Skip to content
This repository was archived by the owner on Nov 20, 2025. It is now read-only.

Commit c71e14e

Browse files
authored
Merge pull request #68 from abstraction-hq/67-refactor-welcome-flow-1
67 refactor welcome flow 1
2 parents b9b5b2a + c70681c commit c71e14e

9 files changed

Lines changed: 5075 additions & 22 deletions

File tree

abis/Passkey.json

Lines changed: 4903 additions & 0 deletions
Large diffs are not rendered by default.

account/passkeyAccount.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export default class PasskeyAccount extends BaseAccount {
120120
const challenge = utils.toBase64url(toBytes(message));
121121
const authData = await this.authenticate(challenge, [this.credentialId], {
122122
userVerification: "required",
123-
authenticatorType: "both",
123+
authenticatorType: "auto",
124124
});
125125
const sig = WebAuthnUtils.getMessageSignature(authData.signature);
126126
const clientDataJSON = new TextDecoder().decode(

app/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default function Home() {
1515
return;
1616
}
1717
if (!wallet) {
18-
route.push("/create");
18+
route.push("/welcome");
1919
return;
2020
}
2121
}, [wallet, loading, route]);

constants/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { Address, Hex } from "viem"
22

33
export const ENTRY_POINT: Address = "0xB5BBaa433180574Dd242d166b8ff9cCc7Fa12df0"
44
export const WALLET_FACTORY: Address = "0x5283c995eBD1eaADadccE298ace4d24812ec131f"
5-
export const BOOTSTRAP: Address = "0x568565Ceb52db8Cda129Cbd39673501409787cC4"
6-
export const PASSKEY: Address = "0x6664b53D20b5c164858eB834eAE724a1B93a428E"
5+
export const BOOTSTRAP: Address = "0x11154A2f670F6590876F37314bcfbCa7b6dBCD83"
6+
export const PASSKEY: Address = "0xb586BaC69b148B15a8D7132Af0853DCc800c869D"
77
export const FACTORY: Address = "0xbC82703bDbE098773059957837016b8CA7374992"
88

99
export const ERC1967_CREATION_CODE_HASH: Hex = "0xcfb46bc89e14c165fbbff6cf3d052fa9fb4dccb4478919a5a65ab20364c67071"

stores/walletStore.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export const useWalletStore = create<IWalletStoreState>()(
3939
}),
4040
{
4141
name: "walletStore",
42+
version: 2,
4243
storage: createJSONStorage(() => localStorage),
4344
onRehydrateStorage: (_: IWalletStoreState) => {
4445
return (state: IWalletStoreState | undefined, error: unknown) => {

templates/ConnectPage/index.tsx

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { useWalletStore } from "@/stores/walletStore";
44
import type { NextPage } from "next";
55
import React, { useEffect, useState } from "react";
66
import { useSearchParams } from "next/navigation";
7-
import SignUpHandle from "../CreatePage/SignUpHandle";
87
import Image from "@/components/Image";
98
import Icon from "@/components/Icon";
109
import Tooltip from "@/components/Tooltip";
@@ -29,6 +28,11 @@ const ConnectPage: NextPage = () => {
2928
});
3029
});
3130

31+
const onCreateNewWallet = () => {
32+
window.open(`${window.origin}/welcome`, "_blank");
33+
window.close();
34+
};
35+
3236
const onConnect = () => {
3337
communicator.sendResponseMessage(messageId, [wallet?.senderAddress]);
3438
window.close();
@@ -44,7 +48,25 @@ const ConnectPage: NextPage = () => {
4448
}
4549

4650
if (!wallet) {
47-
return <SignUpHandle allowToggle={false} />;
51+
return (
52+
<div className="flex justify-center items-center min-h-screen">
53+
<div className="max-w-[28.5rem] w-full p-6 text-white">
54+
<div className="mb-4 text-xl text-center font-semibold text-theme-primary">
55+
Don't have wallet
56+
</div>
57+
<div className="border-t border-theme-stroke mt-3 py-3">
58+
<div className="flex justify-center w-full mt-6">
59+
<button
60+
onClick={onCreateNewWallet}
61+
className="btn-secondary mr-2 w-full px-4"
62+
>
63+
Create new ?
64+
</button>
65+
</div>
66+
</div>
67+
</div>
68+
</div>
69+
);
4870
}
4971

5072
return (

templates/SignPage/SendTransaction/index.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ const ContractInteraction = ({
4949
wallet.passkeyCredentialId || "",
5050
0n,
5151
0n,
52-
undefined,
5352
wallet.senderAddress
5453
);
5554

@@ -87,9 +86,6 @@ const ContractInteraction = ({
8786
console.error(error);
8887
}
8988
};
90-
if (!params) {
91-
return <Loading />;
92-
}
9389
return (
9490
<div className="flex justify-center items-center">
9591
<div className="max-w-[28.5rem] w-full p-6 text-white">

templates/SignPage/index.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ import PasskeyAccount from "@/account/passkeyAccount";
33
import { useWalletStore } from "@/stores/walletStore";
44
import React, { useEffect, useState } from "react";
55
import { useSearchParams } from "next/navigation";
6-
import { encodeFunctionData, keccak256, PublicClient, toHex, zeroAddress } from "viem";
6+
import {
7+
encodeFunctionData,
8+
keccak256,
9+
PublicClient,
10+
toHex,
11+
zeroAddress,
12+
} from "viem";
713
import ContractInteraction from "./SendTransaction";
814
import SignMessage from "./SignMessage";
915
import { Communicator } from "@abstraction-hq/wallet-sdk";
@@ -32,7 +38,6 @@ const SignPage = () => {
3238
const [signData, setSignData] = useState<any>(null);
3339
const searchParams = useSearchParams();
3440
const communicator = new Communicator(window.opener, "");
35-
const [loading, setLoading] = useState(false);
3641

3742
useEffect(() => {
3843
communicator.onPopupLoaded(searchParams.get("id") || "");
@@ -42,10 +47,9 @@ const SignPage = () => {
4247
communicator.listenRequestMessage(async (message) => {
4348
setMessageId(message.id);
4449
setSignData({
50+
category: determineMethodCategory(message.payload.method),
4551
method: determineMethodCategory(message.payload.method),
46-
params: {
47-
...message.payload.params,
48-
},
52+
params: message.payload.params,
4953
dappInfo: message.payload.dappInfo,
5054
});
5155
});
@@ -106,9 +110,15 @@ const SignPage = () => {
106110
};
107111

108112
if (walletLoading || !wallet) {
109-
return <Loading />;
113+
return (
114+
<div className="flex items-center justify-center h-screen">
115+
<Loading />
116+
</div>
117+
);
110118
}
111119

120+
console.log("signData", signData);
121+
112122
switch (signData?.category) {
113123
case "signMessage":
114124
return (

templates/WelcomePage/index.tsx

Lines changed: 127 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,141 @@
11
"use client";
2+
import PasskeyAccount from "@/account/passkeyAccount";
3+
import Field from "@/components/Field";
24
import Login from "@/components/Login";
5+
import { ethClient } from "@/config";
6+
import { useWalletStore } from "@/stores/walletStore";
7+
import { submitUserOp } from "@/utils/bundler";
8+
import { getXYCoordinates } from "@/utils/webauthn";
9+
import { client, parsers } from "@passwordless-id/webauthn";
10+
import { RegistrationEncoded } from "@passwordless-id/webauthn/dist/esm/types";
311
import Link from "next/link";
12+
import { useRouter } from "next/navigation";
13+
import { useState } from "react";
14+
import toast from "react-hot-toast";
15+
import { Address, hashMessage, zeroAddress } from "viem";
16+
import Passkey from "@/abis/Passkey.json"
17+
import { PASSKEY } from "@/constants";
418

519
const WelcomePage = () => {
20+
const [passkeyName, setPasskeyName] = useState<string>("");
21+
const createWallet = useWalletStore((state) => state.onCreateWallet);
22+
const wallets = useWalletStore((state) => state.wallets);
23+
const route = useRouter();
24+
25+
const onCreateWallet = async () => {
26+
const randomString = Math.random().toString(36).substring(2, 15);
27+
const regData: RegistrationEncoded = await client.register(
28+
passkeyName,
29+
randomString,
30+
{
31+
authenticatorType: "auto",
32+
userVerification: "required",
33+
}
34+
);
35+
const parsedData = parsers.parseRegistration(regData);
36+
37+
let passkey = getXYCoordinates(parsedData.credential.publicKey);
38+
39+
const account = new PasskeyAccount(
40+
parsedData.credential.id,
41+
passkey[0] as bigint,
42+
passkey[1] as bigint
43+
);
44+
45+
const [userOp, userOpHash] = await account.sendTransactionOperation(
46+
ethClient,
47+
[
48+
{
49+
target: account.getSender(),
50+
value: 0n,
51+
data: "",
52+
},
53+
]
54+
);
55+
const userOpReceipt: any = await toast.promise(submitUserOp(userOp, true), {
56+
loading: "Wallet creating...",
57+
success: (data) => (
58+
<div>
59+
Transaction Success -{" "}
60+
<a href={`https://vicscan.xyz/tx/${userOpHash}`} target="_blank">
61+
Click to view on scan
62+
</a>
63+
</div>
64+
),
65+
error: (err) => (
66+
<div>
67+
Transaction Fail -{" "}
68+
<a href={`https://vicscan.xyz/tx/${userOpHash}`} target="_blank">
69+
Click to view on scan
70+
</a>
71+
</div>
72+
),
73+
});
74+
75+
if (userOpReceipt && userOpReceipt.success) {
76+
createWallet({
77+
id: wallets.length,
78+
name: `Account ${wallets.length}`,
79+
senderAddress: account.getSender(),
80+
passkeyCredentialId: parsedData.credential.id,
81+
});
82+
83+
route.replace("/");
84+
}
85+
};
86+
87+
const onLogin = async () => {
88+
const randomString = Math.random().toString(36).substring(2, 15);
89+
const authData = await client.authenticate([], randomString, {
90+
authenticatorType: "auto",
91+
userVerification: "required",
92+
});
93+
94+
const keyId = hashMessage(authData.credentialId)
95+
96+
97+
const walletAddress = await ethClient.readContract({
98+
abi: Passkey.abi,
99+
address: PASSKEY,
100+
functionName: "getWallet",
101+
args: [keyId],
102+
})
103+
104+
console.log(walletAddress)
105+
106+
if (walletAddress && walletAddress != zeroAddress) {
107+
createWallet({
108+
id: wallets.length,
109+
name: `Account ${wallets.length}`,
110+
senderAddress: walletAddress as Address,
111+
passkeyCredentialId: authData.credentialId,
112+
});
113+
114+
route.replace("/");
115+
}
116+
};
117+
6118
return (
7119
<Login
8120
title="Abstraction Wallet."
9121
description="Your gateway to blockchain world."
10122
image="/images/login-pic-1.png"
11123
>
12-
<button className="btn-primary w-full mb-3">
13-
<Link href="/create">Create new wallet</Link>{" "}
14-
</button>
15-
<button className="btn-secondary w-full mb-3">
16-
<Link href="/login">Login with exited wallet</Link>{" "}
17-
</button>
124+
<Field
125+
className="flex-1 mb-3"
126+
placeholder="Enter your passkey name"
127+
value={passkeyName}
128+
onChange={(e) => setPasskeyName(e.target.value)}
129+
required
130+
/>
131+
<div className="justify-center w-full mt-6 flex md:flex-1">
132+
<button className="btn-primary mb-3 mr-2 w-full md:w-1/2" onClick={onCreateWallet}>
133+
Create new wallet
134+
</button>
135+
<button className="btn-secondary mb-3 w-full md:w-1/2" onClick={onLogin}>
136+
Login with exited wallet
137+
</button>
138+
</div>
18139
<div className="mt-5 text-title-1s text-theme-tertiary md:mt-4 md:text-base-1s">
19140
Lost your wallet?{" "}
20141
<Link

0 commit comments

Comments
 (0)