From a1fe5c2cc7c0799157cf0cfcf2c44284bfe38975 Mon Sep 17 00:00:00 2001 From: Ephyrian <150686927+UMainLove@users.noreply.github.com> Date: Tue, 13 May 2025 14:37:36 +0200 Subject: [PATCH 01/11] added polygon amoy (polygon mumbai deprecated) in ~packages/shared/src/chainUtils.ts, added @account-kit/plugingen in ~/package.json_packageManager_dependencies, fixed ~/packages/nextjs/hooks/scaffold-alchemy/useTransactor.tsx --- package.json | 1 + .../hooks/scaffold-alchemy/useTransactor.tsx | 10 +- .../nextjs/utils/scaffold-alchemy/networks.ts | 6 +- packages/shared/src/chainUtils.ts | 8 +- yarn.lock | 463 +++++++++++++++++- 5 files changed, 478 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 524e11c..7701ef0 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "dependencies": { "@aa-sdk/core": "^4.24.0", "@account-kit/infra": "^4.24.0", + "@account-kit/plugingen": "^4.24.0", "@account-kit/smart-contracts": "^4.24.0", "viem": "2.28.4" }, diff --git a/packages/nextjs/hooks/scaffold-alchemy/useTransactor.tsx b/packages/nextjs/hooks/scaffold-alchemy/useTransactor.tsx index 838040c..78da4e6 100644 --- a/packages/nextjs/hooks/scaffold-alchemy/useTransactor.tsx +++ b/packages/nextjs/hooks/scaffold-alchemy/useTransactor.tsx @@ -90,10 +90,18 @@ export const useTransactor = (): TransactionFunc => { , ); - transactionReceipt = await publicClient.waitForTransactionReceipt({ + const rawReceipt = await publicClient.waitForTransactionReceipt({ hash: transactionHash, confirmations: options?.blockConfirmations, }); + + transactionReceipt = { + ...rawReceipt, + logs: rawReceipt.logs.map(log => ({ + ...log, + blockHash: log.blockHash || "", // Ensure blockHash is not null + })), + } as TransactionReceipt; notification.remove(notificationId); if (transactionReceipt.status === "reverted") throw new Error("Transaction reverted"); diff --git a/packages/nextjs/utils/scaffold-alchemy/networks.ts b/packages/nextjs/utils/scaffold-alchemy/networks.ts index bfbe7ef..92c3d1a 100644 --- a/packages/nextjs/utils/scaffold-alchemy/networks.ts +++ b/packages/nextjs/utils/scaffold-alchemy/networks.ts @@ -20,7 +20,7 @@ export const RPC_CHAIN_NAMES: Record = { [chains.arbitrumNova.id]: "arb-nova", [chains.base.id]: "base-mainnet", [chains.polygonZkEvm.id]: "polygon-zkevm", - [chains.polygon.id]: "polygon-mainnet", + [chains.polygon.id]: "polygon(pos)-mainnet", [chains.optimism.id]: "opt-mainnet", [chains.zora.id]: "zora-mainnet", [chains.worldchain.id]: "worldchain-mainnet", @@ -39,8 +39,8 @@ export const RPC_CHAIN_NAMES: Record = { [chains.optimismSepolia.id]: "opt-sepolia", [chains.baseGoerli.id]: "base-goerli", [chains.baseSepolia.id]: "base-sepolia", - [chains.polygonMumbai.id]: "polygon-mumbai", - [chains.polygonAmoy.id]: "polygon-amoy", + [chains.polygonMumbai.id]: "polygon-mumbai", // deprecated + [chains.polygonAmoy.id]: "polygon(pos)-amoy", [chains.zoraSepolia.id]: "zora-sepolia", [chains.worldchainSepolia.id]: "worldchain-sepolia", [chains.shapeSepolia.id]: "shape-sepolia", diff --git a/packages/shared/src/chainUtils.ts b/packages/shared/src/chainUtils.ts index 352417b..27e9dc3 100644 --- a/packages/shared/src/chainUtils.ts +++ b/packages/shared/src/chainUtils.ts @@ -7,7 +7,8 @@ import { optimism, optimismSepolia, polygon, - polygonMumbai, + polygonMumbai, // deprecated + polygonAmoy, sepolia, worldChain, worldChainSepolia, @@ -36,7 +37,7 @@ export const allChains: ChainInfo[] = [ { chain: arbitrum, name: "arb-mainnet" }, { chain: optimism, name: "opt-mainnet" }, { chain: base, name: "base-mainnet" }, - { chain: polygon, name: "polygon-mainnet" }, + { chain: polygon, name: "polygon(pos)-mainnet" }, { chain: worldChain, name: "worldchain-mainnet" }, { chain: shape, name: "shape-mainnet" }, { chain: unichainMainnet, name: "unichain-mainnet" }, @@ -49,7 +50,8 @@ export const allChains: ChainInfo[] = [ { chain: arbitrumSepolia, name: "arb-sepolia" }, { chain: optimismSepolia, name: "opt-sepolia" }, { chain: baseSepolia, name: "base-sepolia" }, - { chain: polygonMumbai, name: "polygon-mumbai" }, + { chain: polygonMumbai, name: "polygon-mumbai" }, // deprecated + { chain: polygonAmoy, name: "polygon(pos)-amoy" }, { chain: worldChainSepolia, name: "worldchain-sepolia" }, { chain: shapeSepolia, name: "shape-sepolia" }, { chain: unichainSepolia, name: "unichain-sepolia" }, diff --git a/yarn.lock b/yarn.lock index 07f7e66..4e2a067 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18,6 +18,19 @@ __metadata: languageName: node linkType: hard +"@aa-sdk/core@npm:^4.32.0": + version: 4.32.0 + resolution: "@aa-sdk/core@npm:4.32.0" + dependencies: + abitype: ^0.8.3 + eventemitter3: ^5.0.1 + zod: ^3.22.4 + peerDependencies: + viem: ^2.22.6 + checksum: 7704f6605d7dec51958b1c014e64492a27831afb791ab4850de4903870fdcf7b4934b6e5105231a2d4d54bfc35515e5a945073bf8f8884653fdb3b2744e48a56 + languageName: node + linkType: hard + "@account-kit/core@npm:^4.31.0": version: 4.31.0 resolution: "@account-kit/core@npm:4.31.0" @@ -70,6 +83,32 @@ __metadata: languageName: node linkType: hard +"@account-kit/plugingen@npm:^4.24.0": + version: 4.32.0 + resolution: "@account-kit/plugingen@npm:4.32.0" + dependencies: + "@aa-sdk/core": ^4.32.0 + bundle-require: ^4.0.2 + cac: ^6.7.14 + change-case: ^5.4.3 + chokidar: ^3.6.0 + dedent: ^1.5.1 + esbuild: ^0.20.1 + find-up: ^7.0.0 + fs-extra: ^11.2.0 + ora: ^8.0.1 + pathe: ^1.1.2 + picocolors: ^1.0.0 + prettier: ^3.2.5 + zod: ^3.22.4 + peerDependencies: + viem: ^2.22.6 + bin: + plugingen: dist/esm/cli.js + checksum: 1fd6ed2d8bfddc3e64e9b8dd95b70c112f2a447143e42459099331b6d35a08ba907a7cdeb699de15dacec97e4bc29689b25fd4cdf23c3463c336f8b7f5c21b05 + languageName: node + linkType: hard + "@account-kit/react-native-signer@npm:^4.31.0": version: 4.31.0 resolution: "@account-kit/react-native-signer@npm:4.31.0" @@ -1271,6 +1310,167 @@ __metadata: languageName: node linkType: hard +"@esbuild/aix-ppc64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/aix-ppc64@npm:0.20.2" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/android-arm64@npm:0.20.2" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/android-arm@npm:0.20.2" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/android-x64@npm:0.20.2" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/darwin-arm64@npm:0.20.2" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/darwin-x64@npm:0.20.2" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/freebsd-arm64@npm:0.20.2" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/freebsd-x64@npm:0.20.2" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-arm64@npm:0.20.2" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-arm@npm:0.20.2" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-ia32@npm:0.20.2" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-loong64@npm:0.20.2" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-mips64el@npm:0.20.2" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-ppc64@npm:0.20.2" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-riscv64@npm:0.20.2" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-s390x@npm:0.20.2" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-x64@npm:0.20.2" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/netbsd-x64@npm:0.20.2" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/openbsd-x64@npm:0.20.2" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/sunos-x64@npm:0.20.2" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/win32-arm64@npm:0.20.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/win32-ia32@npm:0.20.2" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/win32-x64@npm:0.20.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": version: 4.7.0 resolution: "@eslint-community/eslint-utils@npm:4.7.0" @@ -7906,6 +8106,17 @@ __metadata: languageName: node linkType: hard +"bundle-require@npm:^4.0.2": + version: 4.2.1 + resolution: "bundle-require@npm:4.2.1" + dependencies: + load-tsconfig: ^0.2.3 + peerDependencies: + esbuild: ">=0.17" + checksum: dcf97683772bd9b1461bde9ba83d2dc0f13c5d7aeecfc9d6e3678b21eeb859a03ee815db03ed14af9d7b1311f39e99ce0487d6f67f9244381436eecf478c9a2c + languageName: node + linkType: hard + "burner-connector@npm:0.0.9": version: 0.0.9 resolution: "burner-connector@npm:0.0.9" @@ -7940,6 +8151,13 @@ __metadata: languageName: node linkType: hard +"cac@npm:^6.7.14": + version: 6.7.14 + resolution: "cac@npm:6.7.14" + checksum: 45a2496a9443abbe7f52a49b22fbe51b1905eff46e03fd5e6c98e3f85077be3f8949685a1849b1a9cd2bc3e5567dfebcf64f01ce01847baf918f1b37c839791a + languageName: node + linkType: hard + "cacache@npm:^19.0.1": version: 19.0.1 resolution: "cacache@npm:19.0.1" @@ -8132,6 +8350,13 @@ __metadata: languageName: node linkType: hard +"change-case@npm:^5.4.3": + version: 5.4.4 + resolution: "change-case@npm:5.4.4" + checksum: a22a25a763719658424ffbcd41e931d2d19cc22399cc765dca447fbe1eaf13e179d5e8ab1677af75f2e814dbddf74e42ffdecb526cd5bc906cc859f62aa154b2 + languageName: node + linkType: hard + "charenc@npm:>= 0.0.1": version: 0.0.2 resolution: "charenc@npm:0.0.2" @@ -8276,7 +8501,7 @@ __metadata: languageName: node linkType: hard -"cli-spinners@npm:^2.5.0": +"cli-spinners@npm:^2.5.0, cli-spinners@npm:^2.9.2": version: 2.9.2 resolution: "cli-spinners@npm:2.9.2" checksum: 1bd588289b28432e4676cb5d40505cfe3e53f2e4e10fbe05c8a710a154d6fe0ce7836844b00d6858f740f2ffe67cdc36e0fce9c7b6a8430e80e6388d5aa4956c @@ -8965,6 +9190,18 @@ __metadata: languageName: node linkType: hard +"dedent@npm:^1.5.1": + version: 1.6.0 + resolution: "dedent@npm:1.6.0" + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + checksum: ecaa83968b3db4ffeadf8f679c01280f8679ec79993d7e203c0281d7926e883bb79f42b263ba0df1f78e146e4b0be1b9a5b922b1fe040cb89b09977bc9c25b38 + languageName: node + linkType: hard + "deep-eql@npm:^4.0.1, deep-eql@npm:^4.1.3": version: 4.1.4 resolution: "deep-eql@npm:4.1.4" @@ -9892,6 +10129,86 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:^0.20.1": + version: 0.20.2 + resolution: "esbuild@npm:0.20.2" + dependencies: + "@esbuild/aix-ppc64": 0.20.2 + "@esbuild/android-arm": 0.20.2 + "@esbuild/android-arm64": 0.20.2 + "@esbuild/android-x64": 0.20.2 + "@esbuild/darwin-arm64": 0.20.2 + "@esbuild/darwin-x64": 0.20.2 + "@esbuild/freebsd-arm64": 0.20.2 + "@esbuild/freebsd-x64": 0.20.2 + "@esbuild/linux-arm": 0.20.2 + "@esbuild/linux-arm64": 0.20.2 + "@esbuild/linux-ia32": 0.20.2 + "@esbuild/linux-loong64": 0.20.2 + "@esbuild/linux-mips64el": 0.20.2 + "@esbuild/linux-ppc64": 0.20.2 + "@esbuild/linux-riscv64": 0.20.2 + "@esbuild/linux-s390x": 0.20.2 + "@esbuild/linux-x64": 0.20.2 + "@esbuild/netbsd-x64": 0.20.2 + "@esbuild/openbsd-x64": 0.20.2 + "@esbuild/sunos-x64": 0.20.2 + "@esbuild/win32-arm64": 0.20.2 + "@esbuild/win32-ia32": 0.20.2 + "@esbuild/win32-x64": 0.20.2 + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: bc88050fc1ca5c1bd03648f9979e514bdefb956a63aa3974373bb7b9cbac0b3aac9b9da1b5bdca0b3490e39d6b451c72815dbd6b7d7f978c91fbe9c9e9aa4e4c + languageName: node + linkType: hard + "escalade@npm:^3.1.1, escalade@npm:^3.2.0": version: 3.2.0 resolution: "escalade@npm:3.2.0" @@ -10905,6 +11222,17 @@ __metadata: languageName: node linkType: hard +"find-up@npm:^7.0.0": + version: 7.0.0 + resolution: "find-up@npm:7.0.0" + dependencies: + locate-path: ^7.2.0 + path-exists: ^5.0.0 + unicorn-magic: ^0.1.0 + checksum: e1c63860f9c04355ab2aa19f4be51c1a6e14a7d8cfbd8090e2be6da2a36a76995907cb45337a4b582b19b164388f71d6ab118869dc7bffb2093f2c089ecb95ee + languageName: node + linkType: hard + "flat-cache@npm:^3.0.4": version: 3.2.0 resolution: "flat-cache@npm:3.2.0" @@ -11057,6 +11385,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^11.2.0": + version: 11.3.0 + resolution: "fs-extra@npm:11.3.0" + dependencies: + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: f983c706e0c22b0c0747a8e9c76aed6f391ba2d76734cf2757cd84da13417b402ed68fe25bace65228856c61d36d3b41da198f1ffbf33d0b34283a2f7a62c6e9 + languageName: node + linkType: hard + "fs-extra@npm:^7.0.0, fs-extra@npm:^7.0.1": version: 7.0.1 resolution: "fs-extra@npm:7.0.1" @@ -12321,6 +12660,13 @@ __metadata: languageName: node linkType: hard +"is-interactive@npm:^2.0.0": + version: 2.0.0 + resolution: "is-interactive@npm:2.0.0" + checksum: e8d52ad490bed7ae665032c7675ec07732bbfe25808b0efbc4d5a76b1a1f01c165f332775c63e25e9a03d319ebb6b24f571a9e902669fc1e40b0a60b5be6e26c + languageName: node + linkType: hard + "is-map@npm:^2.0.3": version: 2.0.3 resolution: "is-map@npm:2.0.3" @@ -12454,6 +12800,20 @@ __metadata: languageName: node linkType: hard +"is-unicode-supported@npm:^1.3.0": + version: 1.3.0 + resolution: "is-unicode-supported@npm:1.3.0" + checksum: 20a1fc161afafaf49243551a5ac33b6c4cf0bbcce369fcd8f2951fbdd000c30698ce320de3ee6830497310a8f41880f8066d440aa3eb0a853e2aa4836dd89abc + languageName: node + linkType: hard + +"is-unicode-supported@npm:^2.0.0": + version: 2.1.0 + resolution: "is-unicode-supported@npm:2.1.0" + checksum: f254e3da6b0ab1a57a94f7273a7798dd35d1d45b227759f600d0fa9d5649f9c07fa8d3c8a6360b0e376adf916d151ec24fc9a50c5295c58bae7ca54a76a063f9 + languageName: node + linkType: hard + "is-weakmap@npm:^2.0.2": version: 2.0.2 resolution: "is-weakmap@npm:2.0.2" @@ -13243,6 +13603,13 @@ __metadata: languageName: node linkType: hard +"load-tsconfig@npm:^0.2.3": + version: 0.2.5 + resolution: "load-tsconfig@npm:0.2.5" + checksum: 631740833c4a7157bb7b6eeae6e1afb6a6fac7416b7ba91bd0944d5c5198270af2d68bf8347af3cc2ba821adc4d83ef98f66278bd263bc284c863a09ec441503 + languageName: node + linkType: hard + "locate-path@npm:^3.0.0": version: 3.0.0 resolution: "locate-path@npm:3.0.0" @@ -13271,6 +13638,15 @@ __metadata: languageName: node linkType: hard +"locate-path@npm:^7.2.0": + version: 7.2.0 + resolution: "locate-path@npm:7.2.0" + dependencies: + p-locate: ^6.0.0 + checksum: c1b653bdf29beaecb3d307dfb7c44d98a2a98a02ebe353c9ad055d1ac45d6ed4e1142563d222df9b9efebc2bcb7d4c792b507fad9e7150a04c29530b7db570f8 + languageName: node + linkType: hard + "lodash.camelcase@npm:^4.3.0": version: 4.3.0 resolution: "lodash.camelcase@npm:4.3.0" @@ -13337,6 +13713,16 @@ __metadata: languageName: node linkType: hard +"log-symbols@npm:^6.0.0": + version: 6.0.0 + resolution: "log-symbols@npm:6.0.0" + dependencies: + chalk: ^5.3.0 + is-unicode-supported: ^1.3.0 + checksum: 510cdda36700cbcd87a2a691ea08d310a6c6b449084018f7f2ec4f732ca5e51b301ff1327aadd96f53c08318e616276c65f7fe22f2a16704fb0715d788bc3c33 + languageName: node + linkType: hard + "log-update@npm:^6.1.0": version: 6.1.0 resolution: "log-update@npm:6.1.0" @@ -14890,6 +15276,23 @@ __metadata: languageName: node linkType: hard +"ora@npm:^8.0.1": + version: 8.2.0 + resolution: "ora@npm:8.2.0" + dependencies: + chalk: ^5.3.0 + cli-cursor: ^5.0.0 + cli-spinners: ^2.9.2 + is-interactive: ^2.0.0 + is-unicode-supported: ^2.0.0 + log-symbols: ^6.0.0 + stdin-discarder: ^0.2.2 + string-width: ^7.2.0 + strip-ansi: ^7.1.0 + checksum: 3ef1335ff4d03e83f5715435c6d0c1fc7a1913a37f8df9e7ebbb0dd77b931a5442f6bf1dbe3056bbfddf763390f5e69e7659565dc6b261bee31ac4622a35120f + languageName: node + linkType: hard + "ordinal@npm:^1.0.3": version: 1.0.3 resolution: "ordinal@npm:1.0.3" @@ -14994,6 +15397,15 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^4.0.0": + version: 4.0.0 + resolution: "p-limit@npm:4.0.0" + dependencies: + yocto-queue: ^1.0.0 + checksum: 01d9d70695187788f984226e16c903475ec6a947ee7b21948d6f597bed788e3112cc7ec2e171c1d37125057a5f45f3da21d8653e04a3a793589e12e9e80e756b + languageName: node + linkType: hard + "p-locate@npm:^3.0.0": version: 3.0.0 resolution: "p-locate@npm:3.0.0" @@ -15021,6 +15433,15 @@ __metadata: languageName: node linkType: hard +"p-locate@npm:^6.0.0": + version: 6.0.0 + resolution: "p-locate@npm:6.0.0" + dependencies: + p-limit: ^4.0.0 + checksum: 2bfe5234efa5e7a4e74b30a5479a193fdd9236f8f6b4d2f3f69e3d286d9a7d7ab0c118a2a50142efcf4e41625def635bd9332d6cbf9cc65d85eb0718c579ab38 + languageName: node + linkType: hard + "p-map@npm:^4.0.0": version: 4.0.0 resolution: "p-map@npm:4.0.0" @@ -15105,6 +15526,13 @@ __metadata: languageName: node linkType: hard +"path-exists@npm:^5.0.0": + version: 5.0.0 + resolution: "path-exists@npm:5.0.0" + checksum: 8ca842868cab09423994596eb2c5ec2a971c17d1a3cb36dbf060592c730c725cd524b9067d7d2a1e031fef9ba7bd2ac6dc5ec9fb92aa693265f7be3987045254 + languageName: node + linkType: hard + "path-is-absolute@npm:^1.0.0": version: 1.0.1 resolution: "path-is-absolute@npm:1.0.1" @@ -15190,6 +15618,13 @@ __metadata: languageName: node linkType: hard +"pathe@npm:^1.1.2": + version: 1.1.2 + resolution: "pathe@npm:1.1.2" + checksum: ec5f778d9790e7b9ffc3e4c1df39a5bb1ce94657a4e3ad830c1276491ca9d79f189f47609884671db173400256b005f4955f7952f52a2aeb5834ad5fb4faf134 + languageName: node + linkType: hard + "pathval@npm:^1.1.1": version: 1.1.1 resolution: "pathval@npm:1.1.1" @@ -15491,7 +15926,7 @@ __metadata: languageName: node linkType: hard -"prettier@npm:*, prettier@npm:^3.3.3": +"prettier@npm:*, prettier@npm:^3.2.5, prettier@npm:^3.3.3": version: 3.5.3 resolution: "prettier@npm:3.5.3" bin: @@ -16602,6 +17037,7 @@ __metadata: dependencies: "@aa-sdk/core": ^4.24.0 "@account-kit/infra": ^4.24.0 + "@account-kit/plugingen": ^4.24.0 "@account-kit/smart-contracts": ^4.24.0 husky: ^9.1.6 lint-staged: ^15.2.10 @@ -17233,6 +17669,13 @@ __metadata: languageName: node linkType: hard +"stdin-discarder@npm:^0.2.2": + version: 0.2.2 + resolution: "stdin-discarder@npm:0.2.2" + checksum: 642ffd05bd5b100819d6b24a613d83c6e3857c6de74eb02fc51506fa61dc1b0034665163831873868157c4538d71e31762bcf319be86cea04c3aba5336470478 + languageName: node + linkType: hard + "stream-chain@npm:^2.2.5": version: 2.2.5 resolution: "stream-chain@npm:2.2.5" @@ -17333,7 +17776,7 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^7.0.0": +"string-width@npm:^7.0.0, string-width@npm:^7.2.0": version: 7.2.0 resolution: "string-width@npm:7.2.0" dependencies: @@ -18496,6 +18939,13 @@ __metadata: languageName: node linkType: hard +"unicorn-magic@npm:^0.1.0": + version: 0.1.0 + resolution: "unicorn-magic@npm:0.1.0" + checksum: 48c5882ca3378f380318c0b4eb1d73b7e3c5b728859b060276e0a490051d4180966beeb48962d850fd0c6816543bcdfc28629dcd030bb62a286a2ae2acb5acb6 + languageName: node + linkType: hard + "unique-filename@npm:^4.0.0": version: 4.0.0 resolution: "unique-filename@npm:4.0.0" @@ -19656,6 +20106,13 @@ __metadata: languageName: node linkType: hard +"yocto-queue@npm:^1.0.0": + version: 1.2.1 + resolution: "yocto-queue@npm:1.2.1" + checksum: 0843d6c2c0558e5c06e98edf9c17942f25c769e21b519303a5c2adefd5b738c9b2054204dc856ac0cd9d134b1bc27d928ce84fd23c9e2423b7e013d5a6f50577 + languageName: node + linkType: hard + "yoctocolors-cjs@npm:^2.1.2": version: 2.1.2 resolution: "yoctocolors-cjs@npm:2.1.2" From a7f721384d9d2b042c70322439065e15d1343331 Mon Sep 17 00:00:00 2001 From: Ephyrian <150686927+UMainLove@users.noreply.github.com> Date: Sun, 18 May 2025 01:53:16 +0200 Subject: [PATCH 02/11] Switched client account type from LightAccount to MultiOWnerModularAccount --- .editorconfig | 10 ++++ package.json | 2 +- .../nextjs/contracts/deployedContracts.ts | 55 ++++++++++++++++++- .../hooks/scaffold-alchemy/useClient.ts | 2 +- packages/shared/src/cw3d.config.ts | 18 +++--- yarn.lock | 27 +++------ 6 files changed, 82 insertions(+), 32 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1ed453a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true + +[*.{js,json,yml}] +charset = utf-8 +indent_style = space +indent_size = 2 diff --git a/package.json b/package.json index 7701ef0..cf88379 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "dependencies": { "@aa-sdk/core": "^4.24.0", "@account-kit/infra": "^4.24.0", - "@account-kit/plugingen": "^4.24.0", + "@account-kit/plugingen": "4.24.0", "@account-kit/smart-contracts": "^4.24.0", "viem": "2.28.4" }, diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 9f2b157..cffb977 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -4,6 +4,59 @@ */ import { GenericContractsDeclaration } from "~~/utils/scaffold-alchemy/contract"; -const deployedContracts = {} as const; +const deployedContracts = { + 11155111: { + Counter: { + address: "0xab3f7a562d201a696fb316f39793c3736ff61866", + abi: [ + { + type: "constructor", + stateMutability: "nonpayable", + inputs: [ + { + name: "_x", + type: "uint256", + baseType: "uint256", + components: null, + arrayLength: null, + arrayChildren: null, + }, + ], + }, + { + type: "function", + name: "decrement", + stateMutability: "nonpayable", + inputs: [], + outputs: [], + }, + { + type: "function", + name: "increment", + stateMutability: "nonpayable", + inputs: [], + outputs: [], + }, + { + type: "function", + name: "x", + stateMutability: "view", + inputs: [], + outputs: [ + { + name: "", + type: "uint256", + baseType: "uint256", + components: null, + arrayLength: null, + arrayChildren: null, + }, + ], + }, + ], + inheritedFunctions: {}, + }, + }, +} as const; export default deployedContracts satisfies GenericContractsDeclaration; diff --git a/packages/nextjs/hooks/scaffold-alchemy/useClient.ts b/packages/nextjs/hooks/scaffold-alchemy/useClient.ts index aeff3f3..3f1dd4e 100644 --- a/packages/nextjs/hooks/scaffold-alchemy/useClient.ts +++ b/packages/nextjs/hooks/scaffold-alchemy/useClient.ts @@ -6,7 +6,7 @@ import { RPC_CHAIN_NAMES } from "~~/utils/scaffold-alchemy"; export const useClient = ( config: UseSmartAccountClientProps = { - type: "LightAccount", + type: "MultiOwnerModularAccount", }, ) => { const { client, address } = useSmartAccountClient(config); diff --git a/packages/shared/src/cw3d.config.ts b/packages/shared/src/cw3d.config.ts index f245049..b3c719d 100644 --- a/packages/shared/src/cw3d.config.ts +++ b/packages/shared/src/cw3d.config.ts @@ -1,15 +1,15 @@ // THIS IS AN AUTOGENERATED FILE BY CREATE-WEB3-DAPP export type CW3DConfig = { - mainnetName: string; - mainnetChainId: number; - testnetChainId: number; - testnetChainName: string; + mainnetName: string; + mainnetChainId: number; + testnetChainId: number; + testnetChainName: string; }; export const chainConfig = { - mainnetName: "shape-mainnet", - mainnetChainId: 360, - testnetChainId: 11011, - testnetChainName: "shape-sepolia", -} as const satisfies CW3DConfig; + mainnetName: "eth-mainnet", + mainnetChainId: 1, + testnetChainId: 11155111, + testnetChainName: "eth-sepolia", +} as const satisfies CW3DConfig; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 4e2a067..6b5dccd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18,19 +18,6 @@ __metadata: languageName: node linkType: hard -"@aa-sdk/core@npm:^4.32.0": - version: 4.32.0 - resolution: "@aa-sdk/core@npm:4.32.0" - dependencies: - abitype: ^0.8.3 - eventemitter3: ^5.0.1 - zod: ^3.22.4 - peerDependencies: - viem: ^2.22.6 - checksum: 7704f6605d7dec51958b1c014e64492a27831afb791ab4850de4903870fdcf7b4934b6e5105231a2d4d54bfc35515e5a945073bf8f8884653fdb3b2744e48a56 - languageName: node - linkType: hard - "@account-kit/core@npm:^4.31.0": version: 4.31.0 resolution: "@account-kit/core@npm:4.31.0" @@ -83,11 +70,11 @@ __metadata: languageName: node linkType: hard -"@account-kit/plugingen@npm:^4.24.0": - version: 4.32.0 - resolution: "@account-kit/plugingen@npm:4.32.0" +"@account-kit/plugingen@npm:4.24.0": + version: 4.24.0 + resolution: "@account-kit/plugingen@npm:4.24.0" dependencies: - "@aa-sdk/core": ^4.32.0 + "@aa-sdk/core": ^4.24.0 bundle-require: ^4.0.2 cac: ^6.7.14 change-case: ^5.4.3 @@ -105,7 +92,7 @@ __metadata: viem: ^2.22.6 bin: plugingen: dist/esm/cli.js - checksum: 1fd6ed2d8bfddc3e64e9b8dd95b70c112f2a447143e42459099331b6d35a08ba907a7cdeb699de15dacec97e4bc29689b25fd4cdf23c3463c336f8b7f5c21b05 + checksum: c4e692bf047363cee1a25b94584ab6925d7926ebe9ed055e577b7196566056585fd4318917a1e7e6a5bc8ccd6d6a60039afa7d32d4d1be8437e28a1dd471850c languageName: node linkType: hard @@ -17037,7 +17024,7 @@ __metadata: dependencies: "@aa-sdk/core": ^4.24.0 "@account-kit/infra": ^4.24.0 - "@account-kit/plugingen": ^4.24.0 + "@account-kit/plugingen": 4.24.0 "@account-kit/smart-contracts": ^4.24.0 husky: ^9.1.6 lint-staged: ^15.2.10 @@ -20205,4 +20192,4 @@ __metadata: optional: true checksum: 75f45c00a799c28afdb56f35c9fdcb1c5861113604daaffa1ffe05beff4e506f1a8b332f585076610ef737e14960be64af653eaa0d3022fb2f1ecec6e2bee1dd languageName: node - linkType: hard + linkType: hard \ No newline at end of file From f87776f9b78215b5cbcfe42d14053fff09a9307e Mon Sep 17 00:00:00 2001 From: Ephyrian <150686927+UMainLove@users.noreply.github.com> Date: Fri, 13 Jun 2025 13:57:00 +0200 Subject: [PATCH 03/11] feature: added button to upgrade an EOA to a SCA using EIP-7702 (FRONTEND ONLY) --- .../ConnectButton/AddressInfoDropdown.tsx | 17 ++++- .../nextjs/hooks/scaffold-alchemy/index.ts | 1 + .../hooks/scaffold-alchemy/useAccountType.ts | 72 +++++++++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts diff --git a/packages/nextjs/components/scaffold-alchemy/ConnectButton/AddressInfoDropdown.tsx b/packages/nextjs/components/scaffold-alchemy/ConnectButton/AddressInfoDropdown.tsx index 2115cb0..3302245 100644 --- a/packages/nextjs/components/scaffold-alchemy/ConnectButton/AddressInfoDropdown.tsx +++ b/packages/nextjs/components/scaffold-alchemy/ConnectButton/AddressInfoDropdown.tsx @@ -1,3 +1,5 @@ +/* eslint-disable prettier/prettier */ +/* eslint-disable @typescript-eslint/no-unused-vars */ import { useRef, useState } from "react"; import { NetworkOptions } from "./NetworkOptions"; import { useLogout } from "@account-kit/react"; @@ -12,9 +14,10 @@ import { ChevronDownIcon, DocumentDuplicateIcon, QrCodeIcon, + ShieldCheckIcon, //feature_1 } from "@heroicons/react/24/outline"; import { BlockieAvatar, isENS } from "~~/components/scaffold-alchemy"; -import { useOutsideClick } from "~~/hooks/scaffold-alchemy"; +import { useOutsideClick, useAccountType } from "~~/hooks/scaffold-alchemy"; import { getTargetNetworks } from "~~/utils/scaffold-alchemy"; const allowedNetworks = getTargetNetworks(); @@ -34,6 +37,7 @@ export const AddressInfoDropdown = ({ }: AddressInfoDropdownProps) => { const checkSumAddress = getAddress(address); const { logout } = useLogout(); + const { accountType } = useAccountType(); //Feature_1 const [addressCopied, setAddressCopied] = useState(false); @@ -108,6 +112,17 @@ export const AddressInfoDropdown = ({ +
  • +
    + + + {accountType === "EOA" && "Upgrade to SCA"} + {accountType === "EOA_7702" && "Already a 7702 + EOA"} + {accountType === "SCA_4337" && "Already a 4337 - SCA"} + {accountType === "UNKNOWN" && "Detecting account type..."} + +
    +
  • {allowedNetworks.length > 1 ? (
  • -
    - - - {accountType === "EOA" && "Upgrade to a Smart Wallet"} - {accountType === "EOA_7702" && "This is a Smart Wallet"} - {accountType === "SCA_4337" && "This is a Smart Account"} - {accountType === "UNKNOWN" && "Detecting account type..."} - -
    + {showUpgradeButton ? ( + + ) : ( +
    + + + {getAccountStatusMessage()} + +
    + )}
  • {allowedNetworks.length > 1 ? (
  • @@ -147,6 +217,75 @@ export const AddressInfoDropdown = ({
  • + + {/* Private Key Modal */} + {showPrivateKeyModal && ( +
    +
    +

    + + EIP-7702 Upgrade with Private Key +

    + +
    + +
    +

    Security Warning

    +

    + {"MetaMask doesn't support EIP-7702 yet. You can upgrade using your private key, but this is risky. Never share your private key with anyone!"} +

    +
    +
    + +
    + +
    + setPrivateKey(e.target.value)} + /> + +
    +
    + +
    + + +
    +
    +
    { + setShowPrivateKeyModal(false); + setPrivateKey(""); + setShowPrivateKey(false); + }}>
    +
    + )} ); -}; +}; \ No newline at end of file diff --git a/packages/nextjs/hooks/scaffold-alchemy/index.ts b/packages/nextjs/hooks/scaffold-alchemy/index.ts index 615a4ce..c4a65d1 100644 --- a/packages/nextjs/hooks/scaffold-alchemy/index.ts +++ b/packages/nextjs/hooks/scaffold-alchemy/index.ts @@ -15,3 +15,4 @@ export * from "./useTransactor"; export * from "./useWatchBalance"; export * from "./useSelectedNetwork"; export * from "./useAccountType"; //feature_1 +export * from "./useEOAUpgrade"; //feature_1_part_2 diff --git a/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts b/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts index da72bc6..8ad250a 100644 --- a/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts +++ b/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts @@ -2,8 +2,9 @@ // This code is part of feature_1: "Account Type Detection" import { useEffect, useState } from "react"; -import { useAccount } from "wagmi"; +import { useAccount, usePublicClient } from "wagmi"; //usePublicClient is part of feature_1_part_2 import { useClient } from "./useClient"; +import { useTargetNetwork } from "./useTargetNetwork"; //useTargetNetwork is part of feature_1_part_2 export type AccountType = "EOA" | "EOA_7702" | "SCA_4337" | "UNKNOWN"; @@ -12,6 +13,8 @@ export const useAccountType = () => { const [isLoading, setIsLoading] = useState(true); const { isConnected, connector } = useAccount(); const { client, address } = useClient(); + const publicClient = usePublicClient(); // usePublicClient is part of feature_1_part_2 + const { targetNetwork } = useTargetNetwork(); //useTargetNetwork is part of feature_1_part_2 useEffect(() => { @@ -26,6 +29,21 @@ export const useAccountType = () => { connectorType: connector?.type, connectorName: connector?.name, }); + + // Check if there's bytecode at the address (indicates smart account) - feature_1_part_2 + let hasCode = false; + if (address && publicClient) { + try { + const code = await publicClient.getBytecode({ + address: address as `0x${string}`, + blockTag: 'latest' + }); + hasCode = code !== undefined && code !== "0x"; + console.log("[useAccountType] Bytecode check:", { address, hasCode }); + } catch (error) { + console.error("[useAccountType] Error checking bytecode:", error); + } + } // If we have a client and address, check if it's from external wallet or not if (client && address) { @@ -35,9 +53,13 @@ export const useAccountType = () => { connector?.type === "walletConnect" || connector?.name?.toLowerCase().includes("wallet") || connector?.name?.toLowerCase().includes("metamask"); - - if (isExternalWallet) { - // External wallet with SCA (future: detect 7702) + + //added extended logic for feature_1_part_2 + if (isExternalWallet && hasCode) { + // External wallet with code at address = likely 7702 upgraded + setAccountType("EOA_7702"); + } else if (isExternalWallet) { + // External wallet without code = regular EOA setAccountType("EOA"); } else { // Has SCA but no external wallet = email/social login @@ -45,7 +67,12 @@ export const useAccountType = () => { } } else if (isConnected && !client) { // Connected with external wallet but no SCA client - setAccountType("EOA"); + if (hasCode) { + // Has code but no SCA client = 7702 upgraded EOA + setAccountType("EOA_7702"); + } else { + setAccountType("EOA"); + } } else if (!isConnected && address) { // Has address but not connected via wagmi = likely email/social setAccountType("SCA_4337"); @@ -61,7 +88,8 @@ export const useAccountType = () => { }; detectAccountType(); - }, [isConnected, connector, client, address]); + }, [isConnected, connector, client, address, publicClient, targetNetwork]); + return { accountType, isLoading }; }; diff --git a/packages/nextjs/hooks/scaffold-alchemy/useClient.ts b/packages/nextjs/hooks/scaffold-alchemy/useClient.ts index 3f1dd4e..7497d96 100644 --- a/packages/nextjs/hooks/scaffold-alchemy/useClient.ts +++ b/packages/nextjs/hooks/scaffold-alchemy/useClient.ts @@ -15,7 +15,7 @@ export const useClient = ( network: RPC_CHAIN_NAMES[scaffoldConfig.targetNetworks[0].id] as Network, }); const enhancedApiDecorator = alchemyEnhancedApiActions(alchemy); - return { client: client?.extend(enhancedApiDecorator), origClient: client, address }; + return { client: client?.extend(enhancedApiDecorator as any), origClient: client, address }; }; export type Client = ReturnType["client"]; diff --git a/packages/nextjs/hooks/scaffold-alchemy/useEOAUpgrade.ts b/packages/nextjs/hooks/scaffold-alchemy/useEOAUpgrade.ts new file mode 100644 index 0000000..3908908 --- /dev/null +++ b/packages/nextjs/hooks/scaffold-alchemy/useEOAUpgrade.ts @@ -0,0 +1,475 @@ +/* eslint-disable prettier/prettier */ + +//feature_1_part_2: EOA Upgrade to Smart Account with EIP-7702 + +import { useState, useEffect } from "react"; +import { createModularAccountV2Client, ModularAccountV2Client } from "@account-kit/smart-contracts"; +import { WalletClientSigner } from "@aa-sdk/core"; +import { alchemy, sepolia, mainnet } from "@account-kit/infra"; +import { useAccount, useWalletClient } from "wagmi"; +import { ALCHEMY_CONFIG } from "@scaffold-alchemy/shared"; +import { notification } from "~~/utils/scaffold-alchemy"; +import { useTargetNetwork } from "./useTargetNetwork"; +import { EIP7702_CONFIG } from "~~/utils/scaffold-alchemy/eip7702.config"; +import { zeroAddress, createWalletClient, custom, type Hex } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; + + +export type UpgradeStatus = "idle" | "upgrading" | "success" | "error"; + +interface UpgradeError { + code: string; + message: string; +} + +export const useEOAUpgrade = () => { + const [status, setStatus] = useState("idle"); + const [error, setError] = useState(null); + const [client, setClient] = useState(null); + const { address, connector } = useAccount(); + const { data: walletClient } = useWalletClient(); + const { targetNetwork } = useTargetNetwork(); + + const isEIP7702Supported = () => { + return EIP7702_CONFIG.supportedChains.includes(targetNetwork.id as (1 | 11155111)); + }; + + const isMetaMaskConnected = () => { + return connector?.name?.toLowerCase().includes("metamask") || + connector?.id === "injected"; + }; + + // Initialize the client when wallet is connected + useEffect(() => { + const initializeClient = async () => { + // Check conditions inline to avoid hook dependency issues + const isMetaMask = connector?.name?.toLowerCase().includes("metamask") || connector?.id === "injected"; + const isSupported = EIP7702_CONFIG.supportedChains.includes(targetNetwork.id as (1 | 11155111)); + + if (!walletClient || !address || !isMetaMask || !isSupported) { + return; + } + + try { + console.log("[EOA Upgrade] Initializing client..."); + + // Create a custom wallet client for MetaMask + const customWalletClient = createWalletClient({ + account: address as Hex, + chain: targetNetwork.id === 1 ? mainnet : sepolia, + transport: custom(window.ethereum!), + }); + + // Create the base WalletClientSigner + const baseSigner = new WalletClientSigner(customWalletClient, "metamask"); + + // Create an enhanced signer with EIP-7702 support + const signer = { + ...baseSigner, + signerType: baseSigner.signerType, + inner: baseSigner.inner, + getAddress: baseSigner.getAddress, + signMessage: baseSigner.signMessage, + signTypedData: baseSigner.signTypedData, + signAuthorization: async (unsignedAuth: any): Promise => { + const contractAddress = unsignedAuth.contractAddress ?? unsignedAuth.address; + + try { + console.log("[EOA Upgrade] Signing EIP-7702 authorization for MetaMask..."); + console.log("[EOA Upgrade] Authorization request:", unsignedAuth); + + // For MetaMask, we need to use the wallet_invokeMethod for EIP-7702 + // or fallback to manual typed data signing + try { + // Try the new MetaMask EIP-7702 method first + const signedAuth = await window.ethereum!.request({ + method: 'wallet_invokeMethod', + params: [ + 'eth_signAuthorization', + [{ + chainId: `0x${unsignedAuth.chainId.toString(16)}`, + nonce: `0x${unsignedAuth.nonce.toString(16)}`, + address: contractAddress, + }] + ] + }); + + console.log("[EOA Upgrade] EIP-7702 authorization signed:", signedAuth); + return { + chainId: unsignedAuth.chainId, + nonce: unsignedAuth.nonce, + address: contractAddress!, + ...signedAuth + }; + } catch (methodError) { + console.log("[EOA Upgrade] wallet_invokeMethod not supported, falling back to typed data signing:", methodError); + + // Try EIP-712 typed data signing as a fallback + // Even though this won't produce the correct EIP-7702 format, + // we let the user complete the signing process before showing the private key option + console.log("[EOA Upgrade] Attempting typed data signing (this will likely fail but allows user to complete the flow)"); + + try { + const domain = { + name: "EIP-7702", + version: "1", + chainId: unsignedAuth.chainId, + }; + + const types = { + Authorization: [ + { name: "chainId", type: "uint256" }, + { name: "nonce", type: "uint256" }, + { name: "address", type: "address" }, + ], + }; + + const message = { + chainId: unsignedAuth.chainId, + nonce: unsignedAuth.nonce, + address: contractAddress, + }; + + // Let the user complete the MetaMask signing flow + const signature = await window.ethereum!.request({ + method: 'eth_signTypedData_v4', + params: [address, JSON.stringify({ domain, types, primaryType: 'Authorization', message })], + }); + + // Parse signature components + const sig = signature as string; + const r = `0x${sig.slice(2, 66)}`; + const s = `0x${sig.slice(66, 130)}`; + const v = parseInt(sig.slice(130, 132), 16); + + console.log("[EOA Upgrade] Typed data signature created (but won't work for EIP-7702):", { r, s, v }); + + // Even though we got a signature, it's not in the correct EIP-7702 format + // The bundler will reject this, but at least the user completed the MetaMask flow + return { + chainId: unsignedAuth.chainId, + nonce: unsignedAuth.nonce, + address: contractAddress!, + r: r as Hex, + s: s as Hex, + v: BigInt(v), + yParity: v - 27, + }; + } catch (signError: any) { + // User rejected or error in signing + if (signError?.code === 4001 || signError?.message?.includes("rejected")) { + throw new Error("User rejected the signature request"); + } + + // If typed data signing also fails, then show the private key option + throw new Error( + "MetaMask doesn't support EIP-7702 authorization signing yet. " + + "Please use the private key option to upgrade your account." + ); + } + } + } catch (error) { + console.error("[EOA Upgrade] Failed to sign authorization:", error); + throw error; + } + }, + }; + + // Use the correct chain from @account-kit/infra + const alchemyChain = targetNetwork.id === 1 ? mainnet : sepolia; + + // Get the API key and policy ID from the shared config + const apiKey = ALCHEMY_CONFIG.ALCHEMY_API_KEY; + const policyId = ALCHEMY_CONFIG.ALCHEMY_GAS_POLICY_ID; + + // Create the Modular Account V2 client with EIP-7702 support + const modularClient = await createModularAccountV2Client({ + signer, + chain: alchemyChain, + transport: alchemy({ + apiKey, + }), + policyId, + // This enables EIP-7702 mode + mode: "7702", + }); + + setClient(modularClient); + console.log("[EOA Upgrade] Client initialized successfully"); + } catch (err) { + console.error("[EOA Upgrade] Failed to initialize client:", err); + } + }; + + initializeClient(); + }, [walletClient, address, targetNetwork.id, connector]); + + const upgradeToSmartAccount = async () => { + console.log("[EOA Upgrade] Starting upgrade process..."); + + try { + // Reset state + setStatus("upgrading"); + setError(null); + + // Validation checks + if (!address) { + throw { code: "NO_ADDRESS", message: EIP7702_CONFIG.errors.NO_ADDRESS }; + } + + if (!isMetaMaskConnected()) { + throw { code: "NOT_METAMASK", message: EIP7702_CONFIG.errors.NOT_METAMASK }; + } + + if (!isEIP7702Supported()) { + throw { + code: "UNSUPPORTED_NETWORK", + message: EIP7702_CONFIG.errors.UNSUPPORTED_NETWORK + }; + } + + if (!client) { + throw { code: "NO_CLIENT", message: "Client not initialized. Please try again." }; + } + + notification.info(EIP7702_CONFIG.messages.PREPARING); + + // First, check if MetaMask supports EIP-7702 + // Try to detect if MetaMask has the experimental feature enabled + try { + // Check if the wallet client has experimental methods + const provider = await walletClient?.request({ method: 'eth_accounts' }); + console.log("[EOA Upgrade] Wallet provider check:", provider); + } catch (checkErr) { + console.warn("[EOA Upgrade] Provider check failed:", checkErr); + } + + console.log("[EOA Upgrade] Sending user operation to trigger EIP-7702 delegation..."); + notification.info("Please approve the smart account delegation in MetaMask..."); + + // Send a simple user operation + // The SDK should automatically request EIP-7702 authorization from MetaMask + const uoHash = await client.sendUserOperation({ + uo: { + target: zeroAddress, // Send to self + data: "0x", // Empty data + value: 0n, + }, + }); + + console.log("[EOA Upgrade] User operation sent, hash:", uoHash); + notification.info(EIP7702_CONFIG.messages.UPGRADING); + + // Wait for the user operation to be mined + const txHash = await client.waitForUserOperationTransaction(uoHash); + console.log("[EOA Upgrade] Transaction hash:", txHash); + + if (txHash) { + setStatus("success"); + notification.success(EIP7702_CONFIG.messages.SUCCESS); + console.log("[EOA Upgrade] Upgrade successful!"); + + // Trigger a refresh of account type detection + setTimeout(() => { + window.location.reload(); + }, 2000); + } else { + throw new Error("Transaction failed"); + } + + } catch (err: any) { + console.error("[EOA Upgrade] Upgrade error:", err); + + // Handle specific error cases + if (err.code === "UNSUPPORTED_NETWORK" || err.code === "NOT_METAMASK" || err.code === "NO_ADDRESS" || err.code === "NO_CLIENT") { + setError(err); + notification.error(err.message); + } else if (err.message?.includes("rejected") || err.message?.includes("denied") || err.code === 4001) { + setError({ + code: "USER_REJECTED", + message: EIP7702_CONFIG.errors.USER_REJECTED + }); + notification.error(EIP7702_CONFIG.errors.USER_REJECTED); + } else if (err.message?.includes("AA23") || err.message?.includes("Invalid 7702 Auth signature")) { + // AA23 error or Invalid 7702 Auth signature means the signature format is wrong + setError({ + code: "SIGNATURE_VALIDATION_FAILED", + message: "The signature format is not valid for EIP-7702. MetaMask cannot create the required signature format." + }); + notification.error("Invalid EIP-7702 signature format. Please use the private key option to upgrade."); + } else if (err.message?.includes("MetaMask doesn't support EIP-7702") || + err.message?.includes("Please use the private key option")) { + // MetaMask doesn't support EIP-7702 signing + setError({ + code: "METAMASK_EIP7702_NOT_SUPPORTED", + message: "MetaMask doesn't support EIP-7702 authorization signing. This feature requires a wallet that can sign EIP-7702 authorizations with the specific format (0x05 magic byte + RLP encoding)." + }); + notification.error("MetaMask doesn't support EIP-7702 yet. Please use the private key option."); + } else if (err.message?.includes("AccountTypeNotSupportedError") || err.message?.includes("json-rpc")) { + // Viem doesn't support JSON-RPC accounts for signAuthorization + setError({ + code: "ACCOUNT_TYPE_NOT_SUPPORTED", + message: "EIP-7702 signing failed. MetaMask may not support this feature yet or needs to be updated." + }); + notification.error("EIP-7702 authorization failed. Please ensure MetaMask supports EIP-7702 features."); + } else if (err.message?.includes("eth_signTypedData_v4")) { + // MetaMask doesn't support the signing method + setError({ + code: "METAMASK_NOT_SUPPORTED", + message: "Your MetaMask version doesn't support EIP-7702. Please update to the latest version." + }); + notification.error("MetaMask doesn't support EIP-7702 signing. Please update MetaMask."); + } else if (err.message?.includes("precheck failed") || err.message?.includes("initCode is empty")) { + setError({ + code: "SDK_NOT_READY", + message: EIP7702_CONFIG.errors.SDK_NOT_READY + }); + notification.error(EIP7702_CONFIG.errors.SDK_NOT_READY); + } else { + setError({ + code: "UNKNOWN_ERROR", + message: err.message || EIP7702_CONFIG.errors.UNKNOWN_ERROR + }); + notification.error(err.message || EIP7702_CONFIG.errors.UNKNOWN_ERROR); + } + + setStatus("error"); + } + }; + + const reset = () => { + setStatus("idle"); + setError(null); + }; + + const upgradeWithPrivateKey = async (privateKey: string) => { + console.log("[EOA Upgrade] Starting private key upgrade process..."); + + try { + // Reset state + setStatus("upgrading"); + setError(null); + + // Validation checks + if (!privateKey || !privateKey.startsWith("0x") || privateKey.length !== 66) { + throw { code: "INVALID_PRIVATE_KEY", message: "Invalid private key format. Must be a 0x-prefixed 64 character hex string." }; + } + + if (!isEIP7702Supported()) { + throw { + code: "UNSUPPORTED_NETWORK", + message: EIP7702_CONFIG.errors.UNSUPPORTED_NETWORK + }; + } + + notification.info("Creating account from private key..."); + + // Create account from private key + const account = privateKeyToAccount(privateKey as Hex); + console.log("[EOA Upgrade] Account created from private key:", account.address); + + // Create a simple signer that matches the SmartAccountSigner interface + const signer = { + signerType: "local", + inner: account, + getAddress: async () => account.address, + signMessage: async (message: any) => account.signMessage({ message }), + signTypedData: async (params: any) => account.signTypedData(params), + signAuthorization: async (unsignedAuth: any) => { + console.log("[EOA Upgrade] Signing authorization with private key account:", unsignedAuth); + return account.signAuthorization(unsignedAuth); + } + }; + + // Use the correct chain from @account-kit/infra + const alchemyChain = targetNetwork.id === 1 ? mainnet : sepolia; + + // Get the API key and policy ID from the shared config + const apiKey = ALCHEMY_CONFIG.ALCHEMY_API_KEY; + const policyId = ALCHEMY_CONFIG.ALCHEMY_GAS_POLICY_ID; + + console.log("[EOA Upgrade] Creating client with LocalAccountSigner..."); + + // Create the Modular Account V2 client with EIP-7702 support + const modularClient = await createModularAccountV2Client({ + signer: signer as any, // Type cast needed due to version mismatch between packages + chain: alchemyChain, + transport: alchemy({ + apiKey, + }), + policyId, + // This enables EIP-7702 mode + mode: "7702", + }); + + console.log("[EOA Upgrade] Client created successfully, sending user operation..."); + notification.info("Sending EIP-7702 delegation transaction..."); + + // Send a simple user operation + // The SDK should automatically request EIP-7702 authorization + const uoHash = await modularClient.sendUserOperation({ + uo: { + target: zeroAddress, // Send to zero address + data: "0x", // Empty data + value: 0n, + }, + }); + + console.log("[EOA Upgrade] User operation sent, hash:", uoHash); + notification.info(EIP7702_CONFIG.messages.UPGRADING); + + // Wait for the user operation to be mined + const txHash = await modularClient.waitForUserOperationTransaction(uoHash); + console.log("[EOA Upgrade] Transaction hash:", txHash); + + if (txHash) { + setStatus("success"); + notification.success(EIP7702_CONFIG.messages.SUCCESS); + console.log("[EOA Upgrade] Upgrade successful!"); + + // Clear the private key from memory + privateKey = ""; + + // Trigger a refresh of account type detection + setTimeout(() => { + window.location.reload(); + }, 2000); + } else { + throw new Error("Transaction failed"); + } + + } catch (err: any) { + console.error("[EOA Upgrade] Private key upgrade error:", err); + + // Handle specific error cases + if (err.code === "UNSUPPORTED_NETWORK" || err.code === "INVALID_PRIVATE_KEY") { + setError(err); + notification.error(err.message); + } else if (err.message?.includes("AA23")) { + setError({ + code: "SIGNATURE_VALIDATION_FAILED", + message: "EIP-7702 signature validation failed. Please check your private key." + }); + notification.error("EIP-7702 authorization failed. Please verify your private key is correct."); + } else { + setError({ + code: "UNKNOWN_ERROR", + message: err.message || EIP7702_CONFIG.errors.UNKNOWN_ERROR + }); + notification.error(err.message || EIP7702_CONFIG.errors.UNKNOWN_ERROR); + } + + setStatus("error"); + } + }; + + return { + upgradeToSmartAccount, + upgradeWithPrivateKey, + status, + error, + isEIP7702Supported: isEIP7702Supported(), + isMetaMaskConnected: isMetaMaskConnected(), + reset, + }; +}; \ No newline at end of file diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 3eeccb1..82e04b6 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -14,8 +14,8 @@ "vercel:yolo": "vercel --build-env YARN_ENABLE_IMMUTABLE_INSTALLS=false --build-env ENABLE_EXPERIMENTAL_COREPACK=1 --build-env NEXT_PUBLIC_IGNORE_BUILD_ERROR=true --build-env VERCEL_TELEMETRY_DISABLED=1" }, "dependencies": { - "@account-kit/infra": "^4.24.0", - "@account-kit/react": "^4.24.0", + "@account-kit/infra": "^4.31.0", + "@account-kit/react": "^4.31.0", "@heroicons/react": "^2.1.5", "@scaffold-alchemy/shared": "workspace:*", "@tanstack/react-query": "^5.64.1", diff --git a/packages/nextjs/utils/scaffold-alchemy/index.ts b/packages/nextjs/utils/scaffold-alchemy/index.ts index 6d69193..ca7a151 100644 --- a/packages/nextjs/utils/scaffold-alchemy/index.ts +++ b/packages/nextjs/utils/scaffold-alchemy/index.ts @@ -4,3 +4,4 @@ export * from "./notification"; export * from "./block"; export * from "./decodeTxData"; export * from "./getParsedError"; +export * from "./eip7702.config"; // feature_1_part_2 diff --git a/yarn.lock b/yarn.lock index 6b5dccd..446e924 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,7 +5,7 @@ __metadata: version: 6 cacheKey: 8 -"@aa-sdk/core@npm:^4.12.0, @aa-sdk/core@npm:^4.24.0, @aa-sdk/core@npm:^4.31.0": +"@aa-sdk/core@npm:^4.31.0": version: 4.31.0 resolution: "@aa-sdk/core@npm:4.31.0" dependencies: @@ -18,31 +18,44 @@ __metadata: languageName: node linkType: hard -"@account-kit/core@npm:^4.31.0": - version: 4.31.0 - resolution: "@account-kit/core@npm:4.31.0" +"@aa-sdk/core@npm:^4.43.1, @aa-sdk/core@npm:^4.47.0": + version: 4.47.0 + resolution: "@aa-sdk/core@npm:4.47.0" dependencies: - "@account-kit/infra": ^4.31.0 - "@account-kit/logging": ^4.31.0 - "@account-kit/react-native-signer": ^4.31.0 - "@account-kit/signer": ^4.31.0 - "@account-kit/smart-contracts": ^4.31.0 + abitype: ^0.8.3 + eventemitter3: ^5.0.1 + zod: ^3.22.4 + peerDependencies: + viem: ^2.29.2 + checksum: 2a1bc3e1be6d301a2137da5a3434622be4207159783e57bd97f695b3729c8219629a42094c996de15b7c401a5d2ba2e645453eb177372908a2642680888fbb67 + languageName: node + linkType: hard + +"@account-kit/core@npm:^4.47.0": + version: 4.47.0 + resolution: "@account-kit/core@npm:4.47.0" + dependencies: + "@account-kit/infra": ^4.47.0 + "@account-kit/logging": ^4.47.0 + "@account-kit/react-native-signer": ^4.47.0 + "@account-kit/signer": ^4.47.0 + "@account-kit/smart-contracts": ^4.47.0 "@solana/web3.js": ^1.98.0 alchemy-sdk: ^3.0.0 js-cookie: ^3.0.5 zod: ^3.22.4 zustand: ^5.0.0-rc.2 peerDependencies: - viem: ^2.22.6 + viem: ^2.29.2 wagmi: ^2.12.7 dependenciesMeta: alchemy-sdk: optional: true - checksum: 695dd29c29f7ca3afbb6b59fd3f7266376710de14b837a10ac096df579faea53df440d9cececd0596f8ccbaa5b913676e92319fad9bbee08788305f2b41ecc8b + checksum: 5d6674f28b008e3828aaee84d028b92306825f87b3fe7102b7c5810ec1ed7af95002e38770834376dd24e44ce07aea703f641efac9e115e3f17faa641fbd5cd9 languageName: node linkType: hard -"@account-kit/infra@npm:^4.12.0, @account-kit/infra@npm:^4.24.0, @account-kit/infra@npm:^4.31.0": +"@account-kit/infra@npm:^4.31.0": version: 4.31.0 resolution: "@account-kit/infra@npm:4.31.0" dependencies: @@ -60,6 +73,24 @@ __metadata: languageName: node linkType: hard +"@account-kit/infra@npm:^4.43.1, @account-kit/infra@npm:^4.47.0": + version: 4.47.0 + resolution: "@account-kit/infra@npm:4.47.0" + dependencies: + "@aa-sdk/core": ^4.47.0 + "@account-kit/logging": ^4.47.0 + alchemy-sdk: ^3.0.0 + eventemitter3: ^5.0.1 + zod: ^3.22.4 + peerDependencies: + viem: ^2.29.2 + dependenciesMeta: + alchemy-sdk: + optional: true + checksum: 0311e17b58baf401d675002aa119d9fe027b29a0d44a8c99f9eedbfeae041b563e367a39bb92c5ee53743aa5b38d00f7cc8a615ae28ca132953729bacc2b0999 + languageName: node + linkType: hard + "@account-kit/logging@npm:^4.31.0": version: 4.31.0 resolution: "@account-kit/logging@npm:4.31.0" @@ -70,11 +101,21 @@ __metadata: languageName: node linkType: hard -"@account-kit/plugingen@npm:4.24.0": - version: 4.24.0 - resolution: "@account-kit/plugingen@npm:4.24.0" +"@account-kit/logging@npm:^4.47.0": + version: 4.47.0 + resolution: "@account-kit/logging@npm:4.47.0" dependencies: - "@aa-sdk/core": ^4.24.0 + "@segment/analytics-next": 1.74.0 + uuid: ^11.0.2 + checksum: 94bd933803e5a87a8392b2a9ad978a4bee83aa7ef0f0045b92a61ca0ecf4326704eee2ba55b9adf651db78d8b013df9eb212b4cf3641e5862ce03b726c0d27fd + languageName: node + linkType: hard + +"@account-kit/plugingen@npm:4.31.0": + version: 4.31.0 + resolution: "@account-kit/plugingen@npm:4.31.0" + dependencies: + "@aa-sdk/core": ^4.31.0 bundle-require: ^4.0.2 cac: ^6.7.14 change-case: ^5.4.3 @@ -92,34 +133,38 @@ __metadata: viem: ^2.22.6 bin: plugingen: dist/esm/cli.js - checksum: c4e692bf047363cee1a25b94584ab6925d7926ebe9ed055e577b7196566056585fd4318917a1e7e6a5bc8ccd6d6a60039afa7d32d4d1be8437e28a1dd471850c + checksum: 33327aa277a5e5276d718939de4a0e95ed807576964d7164b81b9eda410d6d4a50d3b965e175b79abcd78e6b8a5d8dad97011cf5c8433de0fee9acb57259415e languageName: node linkType: hard -"@account-kit/react-native-signer@npm:^4.31.0": - version: 4.31.0 - resolution: "@account-kit/react-native-signer@npm:4.31.0" +"@account-kit/react-native-signer@npm:^4.47.0": + version: 4.47.0 + resolution: "@account-kit/react-native-signer@npm:4.47.0" dependencies: - "@aa-sdk/core": ^4.31.0 - "@account-kit/signer": ^4.31.0 - viem: ^2.21.40 + "@aa-sdk/core": ^4.47.0 + "@account-kit/signer": ^4.47.0 + "@turnkey/react-native-passkey-stamper": ^1.0.14 + uuid: ^11.1.0 + viem: 2.29.2 peerDependencies: - react: ">=18.0.0" + react: ">=18.2.0" react-native: ">=0.76.0" + react-native-get-random-values: ^1.11.0 react-native-inappbrowser-reborn: ^3.7.0 react-native-mmkv: ^3.1.0 - checksum: 0fe27ca6bbced22298427b71591f98f7668924f6c63b444eafb8d26c72844cbcba7bd3dd3a2999876f567e796ad690daed5efe44623974b0e9e2637040404862 + react-native-passkey: ^3.1.0 + checksum: 1200e529273354495f11a478f607e294647ffdb6f877bccc5f09380090db450dae31feb58f73ce70f9f97794f1a3e5ca994e1cff1d58b2bc87b1727fc82943ad languageName: node linkType: hard -"@account-kit/react@npm:^4.24.0": - version: 4.31.0 - resolution: "@account-kit/react@npm:4.31.0" +"@account-kit/react@npm:^4.31.0": + version: 4.47.0 + resolution: "@account-kit/react@npm:4.47.0" dependencies: - "@account-kit/core": ^4.31.0 - "@account-kit/infra": ^4.31.0 - "@account-kit/logging": ^4.31.0 - "@account-kit/signer": ^4.31.0 + "@account-kit/core": ^4.47.0 + "@account-kit/infra": ^4.47.0 + "@account-kit/logging": ^4.47.0 + "@account-kit/signer": ^4.47.0 "@solana/web3.js": ^1.98.0 "@tanstack/react-form": ^0.33.0 "@tanstack/zod-form-adapter": ^0.33.0 @@ -132,27 +177,30 @@ __metadata: zustand: ^5.0.0-rc.2 peerDependencies: "@tanstack/react-query": ^5.28.9 - react: ^18.2.0 - react-dom: ^18.2.0 + react: ">=18.2.0" + react-dom: ">=18.2.0" tailwindcss: ^3.4.3 - viem: ^2.22.6 + viem: ^2.29.2 wagmi: ^2.12.7 dependenciesMeta: alchemy-sdk: optional: true - checksum: f92c3802ab39785ce58f242d23815ce378ec23715775d5e37be88722bdd11e58b0ece026f296f2faca9560625a143cab16fd3c880f1fc2fc070b7e7b0fe9c434 + checksum: 2468c57f6189535a5961e0631d62b369397cfda643e08430b68d8abe4af2721d2ab3b260282c3cea2bf7d520540c92594c361a44442623a3b634739816d78dbd languageName: node linkType: hard -"@account-kit/signer@npm:^4.31.0": - version: 4.31.0 - resolution: "@account-kit/signer@npm:4.31.0" +"@account-kit/signer@npm:^4.47.0": + version: 4.47.0 + resolution: "@account-kit/signer@npm:4.47.0" dependencies: - "@aa-sdk/core": ^4.31.0 - "@account-kit/logging": ^4.31.0 + "@aa-sdk/core": ^4.47.0 + "@account-kit/logging": ^4.47.0 + "@noble/curves": ^1.9.2 + "@noble/hashes": 1.7.1 + "@noble/secp256k1": ^2.3.0 "@solana/web3.js": ^1.98.0 - "@turnkey/http": ^2.6.2 - "@turnkey/iframe-stamper": ^1.0.0 + "@turnkey/http": ^3.4.2 + "@turnkey/iframe-stamper": ^2.5.0 "@turnkey/viem": ^0.4.8 "@turnkey/webauthn-stamper": ^0.4.3 bs58: ^6.0.0 @@ -160,12 +208,12 @@ __metadata: zod: ^3.22.4 zustand: ^5.0.0-rc.2 peerDependencies: - viem: ^2.22.6 - checksum: 05ac61a9969d469ab9f2ec2b846a0000b8b7336da7c2d56dedac14e20650337e733687c3d10041e9c3904ac75818e866917cd6bf4e75194f98edbfeef99dff5a + viem: 2.29.2 + checksum: d7de96efc80d14af1018eda6d8415672f43376856c21672c001eaf9c6b7ffb42b8e0cca3628417995abdab944e56db51253f32d178d104a4f3996ab8a441e15a languageName: node linkType: hard -"@account-kit/smart-contracts@npm:^4.12.0, @account-kit/smart-contracts@npm:^4.24.0, @account-kit/smart-contracts@npm:^4.31.0": +"@account-kit/smart-contracts@npm:^4.31.0": version: 4.31.0 resolution: "@account-kit/smart-contracts@npm:4.31.0" dependencies: @@ -177,6 +225,36 @@ __metadata: languageName: node linkType: hard +"@account-kit/smart-contracts@npm:^4.43.1, @account-kit/smart-contracts@npm:^4.47.0": + version: 4.47.0 + resolution: "@account-kit/smart-contracts@npm:4.47.0" + dependencies: + "@aa-sdk/core": ^4.47.0 + "@account-kit/infra": ^4.47.0 + webauthn-p256: ^0.0.10 + peerDependencies: + viem: 2.29.2 + checksum: 663acc10bb36f309b7eefe0f6f6071db24e31142f70b79bb057d28bb40b04c708894311d33c640ecae94eb5692c056d4ffd7190df93bfa81d3386e76e8734677 + languageName: node + linkType: hard + +"@account-kit/wallet-client@npm:0.1.0-alpha.9": + version: 0.1.0-alpha.9 + resolution: "@account-kit/wallet-client@npm:0.1.0-alpha.9" + dependencies: + "@aa-sdk/core": ^4.43.1 + "@account-kit/infra": ^4.43.1 + "@account-kit/smart-contracts": ^4.43.1 + "@sinclair/typebox": ^0.34.33 + deep-equal: ^2.2.3 + ox: ^0.6.12 + viem: 2.29.2 + peerDependencies: + typescript: ^5.8.2 + checksum: 4b633f35ad0915240cd6447515969b17d88357ad014b9fd28de00a20ab4dc0ae17a5c6b5c833fa676fbc2bf253e8312ef4d06737d000686853e2453ca946caba + languageName: node + linkType: hard + "@adraffy/ens-normalize@npm:1.10.0": version: 1.10.0 resolution: "@adraffy/ens-normalize@npm:1.10.0" @@ -3278,6 +3356,15 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:^1.4.0, @noble/curves@npm:^1.9.2": + version: 1.9.2 + resolution: "@noble/curves@npm:1.9.2" + dependencies: + "@noble/hashes": 1.8.0 + checksum: bac582aefe951032cb04ed7627f139c3351ddfefd2625a25fe7f7a8043e7d781be4fad320d4ae75e31fa5d7e05ba643f16139877375130fd3cff86d81512e0f2 + languageName: node + linkType: hard + "@noble/hashes@npm:1.2.0, @noble/hashes@npm:~1.2.0": version: 1.2.0 resolution: "@noble/hashes@npm:1.2.0" @@ -3341,6 +3428,13 @@ __metadata: languageName: node linkType: hard +"@noble/secp256k1@npm:^2.3.0": + version: 2.3.0 + resolution: "@noble/secp256k1@npm:2.3.0" + checksum: 423c7242203fe843f630b48eb3188ca73fffdc81dc29ce8b2579db850c381fb32cda82a8e721623007762241547527c0d5d76d56aa6570bfe077e71dcfbbd583 + languageName: node + linkType: hard + "@noble/secp256k1@npm:~1.7.0": version: 1.7.2 resolution: "@noble/secp256k1@npm:1.7.2" @@ -4446,9 +4540,9 @@ __metadata: version: 0.0.0-use.local resolution: "@se-2/hardhat@workspace:packages/hardhat" dependencies: - "@aa-sdk/core": ^4.12.0 - "@account-kit/infra": ^4.12.0 - "@account-kit/smart-contracts": ^4.12.0 + "@aa-sdk/core": ^4.31.0 + "@account-kit/infra": ^4.31.0 + "@account-kit/smart-contracts": ^4.31.0 "@ethersproject/abi": ^5.7.0 "@ethersproject/providers": ^5.7.2 "@inquirer/password": ^4.0.2 @@ -4493,8 +4587,8 @@ __metadata: version: 0.0.0-use.local resolution: "@se-2/nextjs@workspace:packages/nextjs" dependencies: - "@account-kit/infra": ^4.24.0 - "@account-kit/react": ^4.24.0 + "@account-kit/infra": ^4.31.0 + "@account-kit/react": ^4.31.0 "@heroicons/react": ^2.1.5 "@scaffold-alchemy/shared": "workspace:*" "@tanstack/react-query": ^5.64.1 @@ -4532,6 +4626,18 @@ __metadata: languageName: unknown linkType: soft +"@segment/analytics-core@npm:1.8.0": + version: 1.8.0 + resolution: "@segment/analytics-core@npm:1.8.0" + dependencies: + "@lukeed/uuid": ^2.0.0 + "@segment/analytics-generic-utils": 1.2.0 + dset: ^3.1.4 + tslib: ^2.4.1 + checksum: c8e2a98670658d6400d8e517e141aff6eff581a12a4015ce8ff906185d148cf9dad79cc5bfb5376195794cc0c964a9c9ca79d36f3d4b49affeb7344251dcde1f + languageName: node + linkType: hard + "@segment/analytics-core@npm:1.8.1": version: 1.8.1 resolution: "@segment/analytics-core@npm:1.8.1" @@ -4553,6 +4659,24 @@ __metadata: languageName: node linkType: hard +"@segment/analytics-next@npm:1.74.0": + version: 1.74.0 + resolution: "@segment/analytics-next@npm:1.74.0" + dependencies: + "@lukeed/uuid": ^2.0.0 + "@segment/analytics-core": 1.8.0 + "@segment/analytics-generic-utils": 1.2.0 + "@segment/analytics.js-video-plugins": ^0.2.1 + "@segment/facade": ^3.4.9 + dset: ^3.1.4 + js-cookie: 3.0.1 + node-fetch: ^2.6.7 + tslib: ^2.4.1 + unfetch: ^4.1.0 + checksum: 8677611dbcbb27004700e1bb4aee73b39d3be87b6719f20a28e36d1d76e6dd10c41ffd96fbda4e06da55a95c4453275710fc4dda6705ed97b540cfd3b9180c84 + languageName: node + linkType: hard + "@segment/analytics-next@npm:^1.74.0": version: 1.81.0 resolution: "@segment/analytics-next@npm:1.81.0" @@ -4737,6 +4861,13 @@ __metadata: languageName: node linkType: hard +"@sinclair/typebox@npm:^0.34.33": + version: 0.34.37 + resolution: "@sinclair/typebox@npm:0.34.37" + checksum: dbfef02bb40b286a40a140a94a3ce5b1f176df7ca1109849748a02533d1163bf0b2663cc098578af8f4e183af0c98add180c3e5e0d17c7ebc2a5b2265b4a8ad8 + languageName: node + linkType: hard + "@sinonjs/commons@npm:^3.0.0": version: 3.0.1 resolution: "@sinonjs/commons@npm:3.0.1" @@ -5195,14 +5326,14 @@ __metadata: languageName: node linkType: hard -"@turnkey/api-key-stamper@npm:0.4.4": - version: 0.4.4 - resolution: "@turnkey/api-key-stamper@npm:0.4.4" +"@turnkey/api-key-stamper@npm:0.4.7": + version: 0.4.7 + resolution: "@turnkey/api-key-stamper@npm:0.4.7" dependencies: "@noble/curves": ^1.3.0 - "@turnkey/encoding": 0.4.0 + "@turnkey/encoding": 0.5.0 sha256-uint8array: ^0.10.7 - checksum: aef9dd0dfa6f09a4de49e461d7552a2c4547ea7c0ac32e0d6c965ac25f1377c8232d9449a0ae5eac51926365745588009a17073fa0ae6ada803e51f0e25a096f + checksum: e6f09113f9df6fcc1ebbd3620714f3a7f0e51c4bf55052d1d86be0a707f2312d6704d75b8e1e08671f6227075916f9d0364c01027ddc0b9bdce8b35c47f013ae languageName: node linkType: hard @@ -5230,10 +5361,10 @@ __metadata: languageName: node linkType: hard -"@turnkey/encoding@npm:0.4.0": - version: 0.4.0 - resolution: "@turnkey/encoding@npm:0.4.0" - checksum: c0b8e0f48d790e4715a1eb1b2e213b7f71a5d478cd93994d7310f3c95dd332d9de1e6b7f7330c7d8b4d78029f10feb110b050836a016bf383105cc212d8a2dbd +"@turnkey/encoding@npm:0.5.0": + version: 0.5.0 + resolution: "@turnkey/encoding@npm:0.5.0" + checksum: 4a66f1f18ae0349a8cae3ebf2e5d3f8fed9f68186ad1873cc815e8654f6ce70c8afe48b2aeba5a226a7e1db3a3bb135295c5f518f3627f681652aa763f8afbcd languageName: node linkType: hard @@ -5249,15 +5380,15 @@ __metadata: languageName: node linkType: hard -"@turnkey/http@npm:^2.6.2": - version: 2.22.0 - resolution: "@turnkey/http@npm:2.22.0" +"@turnkey/http@npm:3.5.0, @turnkey/http@npm:^3.4.2": + version: 3.5.0 + resolution: "@turnkey/http@npm:3.5.0" dependencies: - "@turnkey/api-key-stamper": 0.4.4 - "@turnkey/encoding": 0.4.0 - "@turnkey/webauthn-stamper": 0.5.0 + "@turnkey/api-key-stamper": 0.4.7 + "@turnkey/encoding": 0.5.0 + "@turnkey/webauthn-stamper": 0.5.1 cross-fetch: ^3.1.5 - checksum: 35eab37cdd334c81182cff775976b61f2177a1f2930b29fc0ea02427c60e826035b35c38024d7569f03588cd2b1451f9725e31b54aa796ec8bbebd25f69cb3b8 + checksum: 2b980d53e8c7aa85017a46e06b17a557abf504c0fda5cb5d68370834e5fdd4aa30018a9e2cfb7da06e678f2ab915784c60a151c60ebf40f1259ac54f7fd551ad languageName: node linkType: hard @@ -5268,10 +5399,23 @@ __metadata: languageName: node linkType: hard -"@turnkey/iframe-stamper@npm:^1.0.0": - version: 1.2.0 - resolution: "@turnkey/iframe-stamper@npm:1.2.0" - checksum: 347c65fbd4b6945b18db8fe64c1543f7054281f117231c5423b82013f9eb7df43415210354ba9da2c69bacd8d525a27a1c21d744cf32010908506722cdbfabb0 +"@turnkey/iframe-stamper@npm:^2.5.0": + version: 2.5.0 + resolution: "@turnkey/iframe-stamper@npm:2.5.0" + checksum: e69477c13062570a35a02f4c32889a803a626887ea944d7e439e3f4cafd1659d57fd340e3af0aed2cf96bc9ac37c29e9729fc13754cd913fd653a82d88eb2ef5 + languageName: node + linkType: hard + +"@turnkey/react-native-passkey-stamper@npm:^1.0.14": + version: 1.0.17 + resolution: "@turnkey/react-native-passkey-stamper@npm:1.0.17" + dependencies: + "@turnkey/encoding": 0.5.0 + "@turnkey/http": 3.5.0 + buffer: ^6.0.3 + react-native-passkey: ^3.0.0 + sha256-uint8array: ^0.10.7 + checksum: c8c099fe832cae2b34c4823ab658fca8fba6b0768fe02c823961e80e65dccba16d07b248d17f8a1fab9db7c1d65ad5f6804c2f1aa7606c300d502a7134bee887 languageName: node linkType: hard @@ -5332,6 +5476,15 @@ __metadata: languageName: node linkType: hard +"@turnkey/webauthn-stamper@npm:0.5.1": + version: 0.5.1 + resolution: "@turnkey/webauthn-stamper@npm:0.5.1" + dependencies: + sha256-uint8array: ^0.10.7 + checksum: 9e3dfe43ea49ff0ba1902cd70e540c2bd666c90c79d8dd0399f0a31640196f8d55fcd4a08e2530e251aab5bfd262529e34aac683f28d88eca46589c3bb06019d + languageName: node + linkType: hard + "@turnkey/webauthn-stamper@npm:^0.4.3": version: 0.4.3 resolution: "@turnkey/webauthn-stamper@npm:0.4.3" @@ -7404,7 +7557,7 @@ __metadata: languageName: node linkType: hard -"array-buffer-byte-length@npm:^1.0.1, array-buffer-byte-length@npm:^1.0.2": +"array-buffer-byte-length@npm:^1.0.0, array-buffer-byte-length@npm:^1.0.1, array-buffer-byte-length@npm:^1.0.2": version: 1.0.2 resolution: "array-buffer-byte-length@npm:1.0.2" dependencies: @@ -8175,7 +8328,7 @@ __metadata: languageName: node linkType: hard -"call-bind@npm:^1.0.7, call-bind@npm:^1.0.8": +"call-bind@npm:^1.0.2, call-bind@npm:^1.0.5, call-bind@npm:^1.0.7, call-bind@npm:^1.0.8": version: 1.0.8 resolution: "call-bind@npm:1.0.8" dependencies: @@ -9198,6 +9351,32 @@ __metadata: languageName: node linkType: hard +"deep-equal@npm:^2.2.3": + version: 2.2.3 + resolution: "deep-equal@npm:2.2.3" + dependencies: + array-buffer-byte-length: ^1.0.0 + call-bind: ^1.0.5 + es-get-iterator: ^1.1.3 + get-intrinsic: ^1.2.2 + is-arguments: ^1.1.1 + is-array-buffer: ^3.0.2 + is-date-object: ^1.0.5 + is-regex: ^1.1.4 + is-shared-array-buffer: ^1.0.2 + isarray: ^2.0.5 + object-is: ^1.1.5 + object-keys: ^1.1.1 + object.assign: ^4.1.4 + regexp.prototype.flags: ^1.5.1 + side-channel: ^1.0.4 + which-boxed-primitive: ^1.0.2 + which-collection: ^1.0.1 + which-typed-array: ^1.1.13 + checksum: ee8852f23e4d20a5626c13b02f415ba443a1b30b4b3d39eaf366d59c4a85e6545d7ec917db44d476a85ae5a86064f7e5f7af7479f38f113995ba869f3a1ddc53 + languageName: node + linkType: hard + "deep-extend@npm:~0.6.0": version: 0.6.0 resolution: "deep-extend@npm:0.6.0" @@ -9772,6 +9951,23 @@ __metadata: languageName: node linkType: hard +"es-get-iterator@npm:^1.1.3": + version: 1.1.3 + resolution: "es-get-iterator@npm:1.1.3" + dependencies: + call-bind: ^1.0.2 + get-intrinsic: ^1.1.3 + has-symbols: ^1.0.3 + is-arguments: ^1.1.1 + is-map: ^2.0.2 + is-set: ^2.0.2 + is-string: ^1.0.7 + isarray: ^2.0.5 + stop-iteration-iterator: ^1.0.0 + checksum: 8fa118da42667a01a7c7529f8a8cca514feeff243feec1ce0bb73baaa3514560bd09d2b3438873cf8a5aaec5d52da248131de153b28e2638a061b6e4df13267d + languageName: node + linkType: hard + "es-iterator-helpers@npm:^1.2.1": version: 1.2.1 resolution: "es-iterator-helpers@npm:1.2.1" @@ -11513,7 +11709,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0": +"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0": version: 1.3.0 resolution: "get-intrinsic@npm:1.3.0" dependencies: @@ -12435,7 +12631,7 @@ __metadata: languageName: node linkType: hard -"is-arguments@npm:^1.0.4": +"is-arguments@npm:^1.0.4, is-arguments@npm:^1.1.1": version: 1.2.0 resolution: "is-arguments@npm:1.2.0" dependencies: @@ -12445,7 +12641,7 @@ __metadata: languageName: node linkType: hard -"is-array-buffer@npm:^3.0.4, is-array-buffer@npm:^3.0.5": +"is-array-buffer@npm:^3.0.2, is-array-buffer@npm:^3.0.4, is-array-buffer@npm:^3.0.5": version: 3.0.5 resolution: "is-array-buffer@npm:3.0.5" dependencies: @@ -12654,7 +12850,7 @@ __metadata: languageName: node linkType: hard -"is-map@npm:^2.0.3": +"is-map@npm:^2.0.2, is-map@npm:^2.0.3": version: 2.0.3 resolution: "is-map@npm:2.0.3" checksum: e6ce5f6380f32b141b3153e6ba9074892bbbbd655e92e7ba5ff195239777e767a976dcd4e22f864accaf30e53ebf961ab1995424aef91af68788f0591b7396cc @@ -12701,7 +12897,7 @@ __metadata: languageName: node linkType: hard -"is-regex@npm:^1.2.1": +"is-regex@npm:^1.1.4, is-regex@npm:^1.2.1": version: 1.2.1 resolution: "is-regex@npm:1.2.1" dependencies: @@ -12713,14 +12909,14 @@ __metadata: languageName: node linkType: hard -"is-set@npm:^2.0.3": +"is-set@npm:^2.0.2, is-set@npm:^2.0.3": version: 2.0.3 resolution: "is-set@npm:2.0.3" checksum: 36e3f8c44bdbe9496c9689762cc4110f6a6a12b767c5d74c0398176aa2678d4467e3bf07595556f2dba897751bde1422480212b97d973c7b08a343100b0c0dfe languageName: node linkType: hard -"is-shared-array-buffer@npm:^1.0.4": +"is-shared-array-buffer@npm:^1.0.2, is-shared-array-buffer@npm:^1.0.4": version: 1.0.4 resolution: "is-shared-array-buffer@npm:1.0.4" dependencies: @@ -15036,6 +15232,16 @@ __metadata: languageName: node linkType: hard +"object-is@npm:^1.1.5": + version: 1.1.6 + resolution: "object-is@npm:1.1.6" + dependencies: + call-bind: ^1.0.7 + define-properties: ^1.2.1 + checksum: 3ea22759967e6f2380a2cbbd0f737b42dc9ddb2dfefdb159a1b927fea57335e1b058b564bfa94417db8ad58cddab33621a035de6f5e5ad56d89f2dd03e66c6a1 + languageName: node + linkType: hard + "object-keys@npm:^1.1.1": version: 1.1.1 resolution: "object-keys@npm:1.1.1" @@ -15359,6 +15565,26 @@ __metadata: languageName: node linkType: hard +"ox@npm:^0.6.12": + version: 0.6.12 + resolution: "ox@npm:0.6.12" + dependencies: + "@adraffy/ens-normalize": ^1.10.1 + "@noble/curves": ^1.6.0 + "@noble/hashes": ^1.5.0 + "@scure/bip32": ^1.5.0 + "@scure/bip39": ^1.4.0 + abitype: ^1.0.6 + eventemitter3: 5.0.1 + peerDependencies: + typescript: ">=5.4.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 6709e7ef5bc9b74d4a2f84443292cd624891d6f556a53363578d785103610d5623c96fe10c355158ebd50a4d09adaad9b26017e6207574d04be33ca61242c2a4 + languageName: node + linkType: hard + "p-finally@npm:^2.0.0": version: 2.0.1 resolution: "p-finally@npm:2.0.1" @@ -16289,6 +16515,16 @@ __metadata: languageName: node linkType: hard +"react-native-passkey@npm:^3.0.0": + version: 3.1.0 + resolution: "react-native-passkey@npm:3.1.0" + peerDependencies: + react: "*" + react-native: "*" + checksum: 24e39648eae2162bf88c258f421c74a52dea243e9943f5fb89a7a5adc1b201cad61b687d3d0c56c5363fedc8339f6d4e1e160c8076b8a221464514db6b7a2717 + languageName: node + linkType: hard + "react-native-quick-base64@npm:2.1.2": version: 2.1.2 resolution: "react-native-quick-base64@npm:2.1.2" @@ -16606,7 +16842,7 @@ __metadata: languageName: node linkType: hard -"regexp.prototype.flags@npm:^1.5.3": +"regexp.prototype.flags@npm:^1.5.1, regexp.prototype.flags@npm:^1.5.3": version: 1.5.4 resolution: "regexp.prototype.flags@npm:1.5.4" dependencies: @@ -17022,12 +17258,14 @@ __metadata: version: 0.0.0-use.local resolution: "se-2@workspace:." dependencies: - "@aa-sdk/core": ^4.24.0 - "@account-kit/infra": ^4.24.0 - "@account-kit/plugingen": 4.24.0 - "@account-kit/smart-contracts": ^4.24.0 + "@aa-sdk/core": ^4.31.0 + "@account-kit/infra": ^4.31.0 + "@account-kit/plugingen": 4.31.0 + "@account-kit/smart-contracts": ^4.31.0 + "@account-kit/wallet-client": 0.1.0-alpha.9 husky: ^9.1.6 lint-staged: ^15.2.10 + typescript: ^5.8.3 viem: 2.28.4 languageName: unknown linkType: soft @@ -17322,7 +17560,7 @@ __metadata: languageName: node linkType: hard -"side-channel@npm:^1.1.0": +"side-channel@npm:^1.0.4, side-channel@npm:^1.1.0": version: 1.1.0 resolution: "side-channel@npm:1.1.0" dependencies: @@ -17663,6 +17901,16 @@ __metadata: languageName: node linkType: hard +"stop-iteration-iterator@npm:^1.0.0": + version: 1.1.0 + resolution: "stop-iteration-iterator@npm:1.1.0" + dependencies: + es-errors: ^1.3.0 + internal-slot: ^1.1.0 + checksum: be944489d8829fb3bdec1a1cc4a2142c6b6eb317305eeace1ece978d286d6997778afa1ae8cb3bd70e2b274b9aa8c69f93febb1e15b94b1359b11058f9d3c3a1 + languageName: node + linkType: hard + "stream-chain@npm:^2.2.5": version: 2.2.5 resolution: "stream-chain@npm:2.2.5" @@ -18702,7 +18950,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.0.0, typescript@npm:^5.1": +"typescript@npm:^5.0.0, typescript@npm:^5.1, typescript@npm:^5.8.3": version: 5.8.3 resolution: "typescript@npm:5.8.3" bin: @@ -18742,7 +18990,7 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@^5.0.0#~builtin, typescript@patch:typescript@^5.1#~builtin": +"typescript@patch:typescript@^5.0.0#~builtin, typescript@patch:typescript@^5.1#~builtin, typescript@patch:typescript@^5.8.3#~builtin": version: 5.8.3 resolution: "typescript@patch:typescript@npm%3A5.8.3#~builtin::version=5.8.3&hash=a1c5e5" bin: @@ -19241,7 +19489,7 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^11.0.2": +"uuid@npm:^11.0.2, uuid@npm:^11.1.0": version: 11.1.0 resolution: "uuid@npm:11.1.0" bin: @@ -19384,7 +19632,7 @@ __metadata: languageName: node linkType: hard -"viem@npm:2.28.4, viem@npm:>=2.23.11, viem@npm:^2.1.1, viem@npm:^2.21.40, viem@npm:^2.27.0": +"viem@npm:2.28.4, viem@npm:>=2.23.11, viem@npm:^2.1.1, viem@npm:^2.27.0": version: 2.28.4 resolution: "viem@npm:2.28.4" dependencies: @@ -19405,6 +19653,27 @@ __metadata: languageName: node linkType: hard +"viem@npm:2.29.2": + version: 2.29.2 + resolution: "viem@npm:2.29.2" + dependencies: + "@noble/curves": 1.8.2 + "@noble/hashes": 1.7.2 + "@scure/bip32": 1.6.2 + "@scure/bip39": 1.5.4 + abitype: 1.0.8 + isows: 1.0.6 + ox: 0.6.9 + ws: 8.18.1 + peerDependencies: + typescript: ">=5.0.4" + peerDependenciesMeta: + typescript: + optional: true + checksum: c9bb267dd369008b6e49bf5642258984a99495ac51499d3058954c0b109094c46f6b572aaaa2363208ba613849fac48495f47f5cea8b029bf1082276e27c0ff6 + languageName: node + linkType: hard + "viem@npm:^1.1.4": version: 1.21.4 resolution: "viem@npm:1.21.4" @@ -19513,6 +19782,16 @@ __metadata: languageName: node linkType: hard +"webauthn-p256@npm:^0.0.10": + version: 0.0.10 + resolution: "webauthn-p256@npm:0.0.10" + dependencies: + "@noble/curves": ^1.4.0 + "@noble/hashes": ^1.4.0 + checksum: 0648a3d78451bfa7105b5151a34bd685ee60e193be9be1981fe73819ed5a92f410973bdeb72427ef03c8c2a848619f818cf3e66b94012d5127b462cb10c24f5d + languageName: node + linkType: hard + "webextension-polyfill@npm:>=0.10.0 <1.0": version: 0.12.0 resolution: "webextension-polyfill@npm:0.12.0" @@ -19565,7 +19844,7 @@ __metadata: languageName: node linkType: hard -"which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": +"which-boxed-primitive@npm:^1.0.2, which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": version: 1.1.1 resolution: "which-boxed-primitive@npm:1.1.1" dependencies: @@ -19599,7 +19878,7 @@ __metadata: languageName: node linkType: hard -"which-collection@npm:^1.0.2": +"which-collection@npm:^1.0.1, which-collection@npm:^1.0.2": version: 1.0.2 resolution: "which-collection@npm:1.0.2" dependencies: @@ -19618,7 +19897,7 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.18, which-typed-array@npm:^1.1.2": +"which-typed-array@npm:^1.1.13, which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.18, which-typed-array@npm:^1.1.2": version: 1.1.19 resolution: "which-typed-array@npm:1.1.19" dependencies: @@ -20192,4 +20471,4 @@ __metadata: optional: true checksum: 75f45c00a799c28afdb56f35c9fdcb1c5861113604daaffa1ffe05beff4e506f1a8b332f585076610ef737e14960be64af653eaa0d3022fb2f1ecec6e2bee1dd languageName: node - linkType: hard \ No newline at end of file + linkType: hard From c3a3c5794eb0baf5e1e7df6375f2ad412375eaa5 Mon Sep 17 00:00:00 2001 From: Ephyrian <150686927+UMainLove@users.noreply.github.com> Date: Thu, 3 Jul 2025 13:01:43 +0200 Subject: [PATCH 07/11] added custom errors and messages when an EOA is upgraded to a Smart Wallet --- .../utils/scaffold-alchemy/eip7702.config.ts | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 packages/nextjs/utils/scaffold-alchemy/eip7702.config.ts diff --git a/packages/nextjs/utils/scaffold-alchemy/eip7702.config.ts b/packages/nextjs/utils/scaffold-alchemy/eip7702.config.ts new file mode 100644 index 0000000..ddd264f --- /dev/null +++ b/packages/nextjs/utils/scaffold-alchemy/eip7702.config.ts @@ -0,0 +1,42 @@ +/* eslint-disable prettier/prettier */ + +/** + * Configuration for EIP-7702 Smart Account Upgrades + */ + +export const EIP7702_CONFIG = { + // Chains that support EIP-7702 + supportedChains: [1, 11155111] as const, // Mainnet and Sepolia + + // Error messages + errors: { + UNSUPPORTED_NETWORK: "EIP-7702 is not supported on the connected network.", + NOT_METAMASK: "Please connect with MetaMask to upgrade to a Smart Account.", + USER_REJECTED: "Upgrade canceled. Smart Account delegation was not authorized.", + NO_ADDRESS: "No wallet address found. Please connect your wallet.", + NO_WALLET_CLIENT: "Wallet client not available. Please refresh and try again.", + UNKNOWN_ERROR: "Failed to upgrade account. Please try again.", + SIGNATURE_VALIDATION_FAILED: "Failed to validate signature. Please ensure you have enough ETH for gas.", + EIP7702_NOT_READY: "EIP-7702 support is still experimental. Please try again later.", + SDK_NOT_READY: "EIP-7702 upgrade requires MetaMask with experimental features enabled. Please ensure you have the latest MetaMask version.", + }, + + // UI messages + messages: { + PREPARING: "Preparing smart account upgrade...", + UPGRADING: "Upgrading account... Please approve in MetaMask", + SUCCESS: "Account successfully upgraded to Smart Account!", + UPGRADE_BUTTON: "Upgrade to a Smart Wallet", + UPGRADED_EOA: "This is a Smart Wallet", + SMART_ACCOUNT: "This is a Smart Account", + DETECTING: "Detecting account type...", + TOOLTIP_UNSUPPORTED: "EIP-7702 is not supported on this network", + }, + + // Timing configurations + timing: { + reloadDelay: 2000, // ms to wait before reloading page after successful upgrade + }, +} as const; + +export type EIP7702Config = typeof EIP7702_CONFIG; \ No newline at end of file From fa750dcf1fafbab00395ae1cc9f39e7147fae7d0 Mon Sep 17 00:00:00 2001 From: Ephyrian <150686927+UMainLove@users.noreply.github.com> Date: Thu, 3 Jul 2025 14:33:11 +0200 Subject: [PATCH 08/11] fix: public client retrieves the connected address with correct method --- packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts b/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts index 8ad250a..1af0158 100644 --- a/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts +++ b/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts @@ -34,7 +34,7 @@ export const useAccountType = () => { let hasCode = false; if (address && publicClient) { try { - const code = await publicClient.getBytecode({ + const code = await publicClient.getCode({ address: address as `0x${string}`, blockTag: 'latest' }); From 458c37fa7b92fb7e2f133f281086007b220b1c2f Mon Sep 17 00:00:00 2001 From: Ephyrian <150686927+UMainLove@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:25:46 +0200 Subject: [PATCH 09/11] feature: added EOA interactions with in-app smart contracts --- .gitignore | 5 +- .../nextjs/hooks/scaffold-alchemy/index.ts | 2 + .../hooks/scaffold-alchemy/useAccountType.ts | 49 +++++- .../hooks/scaffold-alchemy/useClient.ts | 37 +++++ .../scaffold-alchemy/useSmartWalletClient.ts | 141 ++++++++++++++++++ 5 files changed, 231 insertions(+), 3 deletions(-) create mode 100644 packages/nextjs/hooks/scaffold-alchemy/useSmartWalletClient.ts diff --git a/.gitignore b/.gitignore index 0d4e11d..3aa2d3e 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,7 @@ node_modules # cli dist -.env \ No newline at end of file +.env + +# Claude +CLAUDE.md \ No newline at end of file diff --git a/packages/nextjs/hooks/scaffold-alchemy/index.ts b/packages/nextjs/hooks/scaffold-alchemy/index.ts index c4a65d1..f34f307 100644 --- a/packages/nextjs/hooks/scaffold-alchemy/index.ts +++ b/packages/nextjs/hooks/scaffold-alchemy/index.ts @@ -16,3 +16,5 @@ export * from "./useWatchBalance"; export * from "./useSelectedNetwork"; export * from "./useAccountType"; //feature_1 export * from "./useEOAUpgrade"; //feature_1_part_2 +export * from "./useSmartWalletClient"; //feature_1_part_3 +export * from "./useClient"; //feature_1_part_3 diff --git a/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts b/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts index 1af0158..fe920d0 100644 --- a/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts +++ b/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts @@ -12,7 +12,7 @@ export const useAccountType = () => { const [accountType, setAccountType] = useState("UNKNOWN"); const [isLoading, setIsLoading] = useState(true); const { isConnected, connector } = useAccount(); - const { client, address } = useClient(); + const { client, address, isSmartWallet } = useClient(); // isSmartWallet is part of feature_1_part_3 const publicClient = usePublicClient(); // usePublicClient is part of feature_1_part_2 const { targetNetwork } = useTargetNetwork(); //useTargetNetwork is part of feature_1_part_2 @@ -26,10 +26,11 @@ export const useAccountType = () => { isConnected, hasClient: !!client, hasAddress: !!address, + isSmartWallet, // From useClient (feature_1_part_3) connectorType: connector?.type, connectorName: connector?.name, }); - +/* // Check if there's bytecode at the address (indicates smart account) - feature_1_part_2 let hasCode = false; if (address && publicClient) { @@ -89,6 +90,50 @@ export const useAccountType = () => { detectAccountType(); }, [isConnected, connector, client, address, publicClient, targetNetwork]); +*/ + // If useClient already detected a Smart Wallet, use that + if (isSmartWallet) { + setAccountType("EOA_7702"); + return; + } + + // If we have a client and address, check if it's from external wallet or not + if (client && address) { + // Check if connected via external wallet + const isExternalWallet = + connector?.type === "injected" || + connector?.type === "walletConnect" || + connector?.name?.toLowerCase().includes("wallet") || + connector?.name?.toLowerCase().includes("metamask"); + + if (!isExternalWallet) { + // Has SCA and no external wallet = email/social login + setAccountType("SCA_4337"); + } else { + // This shouldn't happen if isSmartWallet detection works + // But keeping as fallback + setAccountType("EOA"); + } + } else if (isConnected && !client) { + // Connected with external wallet but no client = regular EOA + setAccountType("EOA"); + } else if (!isConnected && address) { + // Has address but not connected via wagmi = likely email/social + setAccountType("SCA_4337"); + } else { + setAccountType("UNKNOWN"); + } + } catch (error) { + console.error("Error detecting account type:", error); + setAccountType("UNKNOWN"); + } finally { + setIsLoading(false); + } + }; + + detectAccountType(); + }, [isConnected, connector, client, address, isSmartWallet, publicClient, targetNetwork]); + return { accountType, isLoading }; diff --git a/packages/nextjs/hooks/scaffold-alchemy/useClient.ts b/packages/nextjs/hooks/scaffold-alchemy/useClient.ts index 7497d96..088c587 100644 --- a/packages/nextjs/hooks/scaffold-alchemy/useClient.ts +++ b/packages/nextjs/hooks/scaffold-alchemy/useClient.ts @@ -1,14 +1,19 @@ +/* eslint-disable prettier/prettier */ + import { alchemyEnhancedApiActions } from "@account-kit/infra"; import { UseSmartAccountClientProps, useSmartAccountClient } from "@account-kit/react"; import { Alchemy, Network } from "alchemy-sdk"; import scaffoldConfig from "~~/scaffold.config"; import { RPC_CHAIN_NAMES } from "~~/utils/scaffold-alchemy"; +import { useSmartWalletClient } from "./useSmartWalletClient"; // feature_1_part_3 export const useClient = ( config: UseSmartAccountClientProps = { type: "MultiOwnerModularAccount", }, ) => { + + /* const { client, address } = useSmartAccountClient(config); const alchemy = new Alchemy({ url: client?.transport.alchemyRpcUrl, @@ -17,5 +22,37 @@ export const useClient = ( const enhancedApiDecorator = alchemyEnhancedApiActions(alchemy); return { client: client?.extend(enhancedApiDecorator as any), origClient: client, address }; }; +*/ + // Get Smart Account client (for social login users) + const { client: smartAccountClient, address: smartAccountAddress } = useSmartAccountClient(config); + + // Get Smart Wallet client (for EIP-7702 upgraded EOAs) + const { client: smartWalletClient, address: smartWalletAddress, isSmartWallet } = useSmartWalletClient(); + + // Determine which client to use + // Priority: Smart Wallet client (if available) > Smart Account client + const client = smartWalletClient || smartAccountClient; + const address = smartWalletClient ? smartWalletAddress : smartAccountAddress; + + // Set up Alchemy enhanced API + let enhancedClient = null; + if (client) { + const alchemy = new Alchemy({ + url: client.transport.alchemyRpcUrl, + network: RPC_CHAIN_NAMES[scaffoldConfig.targetNetworks[0].id] as Network, + }); + const enhancedApiDecorator = alchemyEnhancedApiActions(alchemy); + enhancedClient = client.extend(enhancedApiDecorator as any); + } + + return { + client: enhancedClient, + origClient: client, + address, + // Export isSmartWallet so useAccountType can use it without circular dependency + isSmartWallet, + }; +}; + export type Client = ReturnType["client"]; diff --git a/packages/nextjs/hooks/scaffold-alchemy/useSmartWalletClient.ts b/packages/nextjs/hooks/scaffold-alchemy/useSmartWalletClient.ts new file mode 100644 index 0000000..d09ad4e --- /dev/null +++ b/packages/nextjs/hooks/scaffold-alchemy/useSmartWalletClient.ts @@ -0,0 +1,141 @@ +/* eslint-disable prettier/prettier */ + +// feature_1_part_3: Smart Wallet Client for EIP-7702 upgraded EOAs + +import { useState, useEffect } from "react"; +import { createAlchemySmartAccountClient } from "@account-kit/infra"; +import { createModularAccountV2 } from "@account-kit/smart-contracts"; +import { WalletClientSigner } from "@aa-sdk/core"; +import { alchemy, sepolia, mainnet } from "@account-kit/infra"; +import { useAccount, useWalletClient, usePublicClient } from "wagmi"; +import { ALCHEMY_CONFIG } from "@scaffold-alchemy/shared"; +import { useTargetNetwork } from "./useTargetNetwork"; +import { createWalletClient, custom, type Hex } from "viem"; +import { EIP7702_CONFIG } from "~~/utils/scaffold-alchemy/eip7702.config"; + +export const useSmartWalletClient = () => { + const [client, setClient] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + const [hasCode, setHasCode] = useState(false); + + const { address, connector } = useAccount(); + const { data: walletClient } = useWalletClient(); + const publicClient = usePublicClient(); + const { targetNetwork } = useTargetNetwork(); + + const isMetaMaskConnected = connector?.name?.toLowerCase().includes("metamask") || connector?.id === "injected"; + const isEIP7702Supported = EIP7702_CONFIG.supportedChains.includes(targetNetwork.id as (1 | 11155111)); + + // Check for bytecode at address (indicates upgraded Smart Wallet) + useEffect(() => { + const checkBytecode = async () => { + if (!address || !publicClient) { + setHasCode(false); + return; + } + + try { + const code = await publicClient.getCode({ + address: address as `0x${string}`, + blockTag: 'latest' + }); + const codeExists = code !== undefined && code !== "0x"; + setHasCode(codeExists); + console.log("[Smart Wallet Client] Bytecode check:", { address, hasCode: codeExists }); + } catch (error) { + console.error("[Smart Wallet Client] Error checking bytecode:", error); + setHasCode(false); + } + }; + + checkBytecode(); + }, [address, publicClient]); + + // Determine if this is a Smart Wallet (EOA with bytecode) + const isSmartWallet = hasCode && isMetaMaskConnected; + + useEffect(() => { + const initializeSmartWalletClient = async () => { + // Reset state + setIsLoading(true); + setError(null); + + // Check if we should create a Smart Wallet client + if (!isSmartWallet || !walletClient || !address || !isEIP7702Supported) { + console.log("[Smart Wallet Client] Conditions not met:", { + isSmartWallet, + hasWalletClient: !!walletClient, + hasAddress: !!address, + isEIP7702Supported, + hasCode, + }); + setClient(null); + setIsLoading(false); + return; + } + + try { + console.log("[Smart Wallet Client] Initializing client for upgraded Smart Wallet..."); + + // Create a custom wallet client for MetaMask + const customWalletClient = createWalletClient({ + account: address as Hex, + chain: targetNetwork.id === 1 ? mainnet : sepolia, + transport: custom(window.ethereum!), + }); + + // Create the signer + const signer = new WalletClientSigner(customWalletClient, "metamask"); + + // Use the correct chain from @account-kit/infra + const alchemyChain = targetNetwork.id === 1 ? mainnet : sepolia; + + // Get the API key and policy ID from the shared config + const apiKey = ALCHEMY_CONFIG.ALCHEMY_API_KEY; + const policyId = ALCHEMY_CONFIG.ALCHEMY_GAS_POLICY_ID; + + // Create the transport + const transport = alchemy({ + apiKey, + }); + + // Create the Modular Account V2 in 7702 mode + const account = await createModularAccountV2({ + signer, + chain: alchemyChain, + transport, + mode: "7702", // Key parameter for EIP-7702 + accountAddress: address as Hex, // Use existing address since it's already upgraded + }); + + // Create the Alchemy Smart Account Client + const smartWalletClient = createAlchemySmartAccountClient({ + account, + chain: alchemyChain, + transport, + policyId, + }); + + setClient(smartWalletClient); + console.log("[Smart Wallet Client] Client initialized successfully for address:", address); + } catch (err: any) { + console.error("[Smart Wallet Client] Failed to initialize client:", err); + setError(err.message || "Failed to initialize Smart Wallet client"); + setClient(null); + } finally { + setIsLoading(false); + } + }; + + initializeSmartWalletClient(); + }, [walletClient, address, targetNetwork.id, isSmartWallet, isEIP7702Supported, hasCode]); + + return { + client, + isLoading, + error, + isSmartWallet, + address, + }; +}; \ No newline at end of file From 551dd5526e647d18c40fe0b06114ae5926bba93f Mon Sep 17 00:00:00 2001 From: Ephyrian <150686927+UMainLove@users.noreply.github.com> Date: Tue, 8 Jul 2025 18:42:49 +0200 Subject: [PATCH 10/11] upgrade: replaced EOA direct calls with delegated userOps (eip7702) when a Smart Wallet interacts with in-app smart contracts --- .../contract/WriteOnlyFunctionForm.tsx | 105 ++++++++++--- .../hooks/scaffold-alchemy/useAccountType.ts | 61 -------- .../hooks/scaffold-alchemy/useClient.ts | 11 -- .../useScaffoldWriteContract.ts | 140 ++++++++++++++---- 4 files changed, 195 insertions(+), 122 deletions(-) diff --git a/packages/nextjs/app/debug/_components/contract/WriteOnlyFunctionForm.tsx b/packages/nextjs/app/debug/_components/contract/WriteOnlyFunctionForm.tsx index d5b1104..ce501f6 100644 --- a/packages/nextjs/app/debug/_components/contract/WriteOnlyFunctionForm.tsx +++ b/packages/nextjs/app/debug/_components/contract/WriteOnlyFunctionForm.tsx @@ -1,3 +1,5 @@ +/* eslint-disable prettier/prettier */ + "use client"; import { useEffect, useState } from "react"; @@ -34,43 +36,103 @@ export const WriteOnlyFunctionForm = ({ contractAddress, inheritedFrom, }: WriteOnlyFunctionFormProps) => { - const { client } = useClient(); + const { client, isSmartWallet } = useClient(); // isSmartWallet is part of feature_1_part_3 + + // Only use useSendUserOperation for Smart Accounts cases const { sendUserOperationAsync, isSendingUserOperation } = useSendUserOperation({ - client: client, + client: !isSmartWallet ? client : undefined, // client is not needed for Smart Wallets, 'client: client' is used for Smart Accounts waitForTxn: true, }); const [hash, setHash] = useState(); const [form, setForm] = useState>(() => getInitialFormState(abiFunction)); const [txValue, setTxValue] = useState(""); + const [isSmartWalletSending, setIsSmartWalletSending] = useState(false); // feature_1_part_3: Track Smart Wallet sending state const { chain } = useChain(); const writeTxn = useTransactor(); const { targetNetwork } = useTargetNetwork(); const writeDisabled = !chain || chain?.id !== targetNetwork.id; + const isSending = isSendingUserOperation || isSmartWalletSending; // feature_1_part_3: Track sending state const handleWrite = async () => { - if (sendUserOperationAsync) { - try { - const makeWriteWithParams = async () => { - if (!client) throw Error("You must first login before making an onchain action"); + +// feature_1_part_3: Handle Smart Wallet sending block start ----- + if (!client && !sendUserOperationAsync) { + console.error("No client available for transaction"); + return; + } + + try { + if (isSmartWallet) { + setIsSmartWalletSending(true); + } + + const makeWriteWithParams = async (): Promise => { + const encodedData = encodeFunctionData({ + functionName: abiFunction.name, + abi: abi, + args: getParsedContractFunctionArgs(form), + }); + let txHash: Hex; + + // For Smart Wallets (EIP-7702), use the client directly + if (isSmartWallet && client) { + console.log("[WriteOnlyForm] Using Smart Wallet client for UserOp"); + console.log("[WriteOnlyForm] Target:", contractAddress); + console.log("[WriteOnlyForm] Function:", abiFunction.name); + console.log("[WriteOnlyForm] Value:", BigInt(txValue || "0")); + + try { + const result = await client.sendUserOperation({ + uo: { + target: contractAddress, + data: encodedData, + value: BigInt(txValue || "0"), + }, + }); + + console.log("[WriteOnlyForm] UserOp sent, result:", result); + + // Wait for the transaction if we have a hash + if ('hash' in result && result.hash) { + console.log("[WriteOnlyForm] Waiting for UserOp transaction:", result.hash); + const confirmedHash = await client.waitForUserOperationTransaction({ + hash: result.hash, + }); + txHash = confirmedHash as Hex; + console.log("[WriteOnlyForm] Transaction confirmed:", txHash); + } else { + throw new Error("Failed to get transaction hash from Smart Wallet operation"); + } + } catch (error) { + console.error("[WriteOnlyForm] Smart Wallet operation failed:", error); + throw error; + } + } else if (sendUserOperationAsync) { + // Use the SDK's sendUserOperationAsync for regular smart accounts const { hash } = await sendUserOperationAsync({ uo: { target: contractAddress, - data: encodeFunctionData({ - functionName: abiFunction.name, - abi: abi, - args: getParsedContractFunctionArgs(form), - }), - value: BigInt(txValue), + data: encodedData, + value: BigInt(txValue || "0"), }, }); - setHash(hash); - return hash; - }; - await writeTxn(makeWriteWithParams); - onChange(); - } catch (e: any) { - console.error("⚡️ ~ file: WriteOnlyFunctionForm.tsx:handleWrite ~ error", e); + txHash = hash as Hex; + } else { + throw Error("No method available to send transaction"); + } + + setHash(txHash); + return txHash; + }; + + await writeTxn(makeWriteWithParams); + onChange(); + } catch (e: any) { + console.error("⚡️ ~ file: WriteOnlyFunctionForm.tsx:handleWrite ~ error", e); + } finally { + if (isSmartWallet) { + setIsSmartWalletSending(false); } } }; @@ -82,6 +144,7 @@ export const WriteOnlyFunctionForm = ({ useEffect(() => { setDisplayedTxResult(txResult); }, [txResult]); +// feature_1_part_3: Handle Smart Wallet sending block end ----- // TODO use `useMemo` to optimize also update in ReadOnlyFunctionForm const transformedFunction = transformAbiFunction(abiFunction); @@ -141,10 +204,10 @@ export const WriteOnlyFunctionForm = ({ > diff --git a/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts b/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts index fe920d0..162421f 100644 --- a/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts +++ b/packages/nextjs/hooks/scaffold-alchemy/useAccountType.ts @@ -30,67 +30,6 @@ export const useAccountType = () => { connectorType: connector?.type, connectorName: connector?.name, }); -/* - // Check if there's bytecode at the address (indicates smart account) - feature_1_part_2 - let hasCode = false; - if (address && publicClient) { - try { - const code = await publicClient.getCode({ - address: address as `0x${string}`, - blockTag: 'latest' - }); - hasCode = code !== undefined && code !== "0x"; - console.log("[useAccountType] Bytecode check:", { address, hasCode }); - } catch (error) { - console.error("[useAccountType] Error checking bytecode:", error); - } - } - - // If we have a client and address, check if it's from external wallet or not - if (client && address) { - // Check if connected via external wallet - const isExternalWallet = - connector?.type === "injected" || - connector?.type === "walletConnect" || - connector?.name?.toLowerCase().includes("wallet") || - connector?.name?.toLowerCase().includes("metamask"); - - //added extended logic for feature_1_part_2 - if (isExternalWallet && hasCode) { - // External wallet with code at address = likely 7702 upgraded - setAccountType("EOA_7702"); - } else if (isExternalWallet) { - // External wallet without code = regular EOA - setAccountType("EOA"); - } else { - // Has SCA but no external wallet = email/social login - setAccountType("SCA_4337"); - } - } else if (isConnected && !client) { - // Connected with external wallet but no SCA client - if (hasCode) { - // Has code but no SCA client = 7702 upgraded EOA - setAccountType("EOA_7702"); - } else { - setAccountType("EOA"); - } - } else if (!isConnected && address) { - // Has address but not connected via wagmi = likely email/social - setAccountType("SCA_4337"); - } else { - setAccountType("UNKNOWN"); - } - } catch (error) { - console.error("Error detecting account type:", error); - setAccountType("UNKNOWN"); - } finally { - setIsLoading(false); - } - }; - - detectAccountType(); - }, [isConnected, connector, client, address, publicClient, targetNetwork]); -*/ // If useClient already detected a Smart Wallet, use that if (isSmartWallet) { setAccountType("EOA_7702"); diff --git a/packages/nextjs/hooks/scaffold-alchemy/useClient.ts b/packages/nextjs/hooks/scaffold-alchemy/useClient.ts index 088c587..fb9ec00 100644 --- a/packages/nextjs/hooks/scaffold-alchemy/useClient.ts +++ b/packages/nextjs/hooks/scaffold-alchemy/useClient.ts @@ -12,17 +12,6 @@ export const useClient = ( type: "MultiOwnerModularAccount", }, ) => { - - /* - const { client, address } = useSmartAccountClient(config); - const alchemy = new Alchemy({ - url: client?.transport.alchemyRpcUrl, - network: RPC_CHAIN_NAMES[scaffoldConfig.targetNetworks[0].id] as Network, - }); - const enhancedApiDecorator = alchemyEnhancedApiActions(alchemy); - return { client: client?.extend(enhancedApiDecorator as any), origClient: client, address }; -}; -*/ // Get Smart Account client (for social login users) const { client: smartAccountClient, address: smartAccountAddress } = useSmartAccountClient(config); diff --git a/packages/nextjs/hooks/scaffold-alchemy/useScaffoldWriteContract.ts b/packages/nextjs/hooks/scaffold-alchemy/useScaffoldWriteContract.ts index 7c8f81b..6605c41 100644 --- a/packages/nextjs/hooks/scaffold-alchemy/useScaffoldWriteContract.ts +++ b/packages/nextjs/hooks/scaffold-alchemy/useScaffoldWriteContract.ts @@ -1,8 +1,10 @@ +/* eslint-disable prettier/prettier */ + import { useEffect, useState } from "react"; import { useClient } from "./useClient"; import { useSendUserOperation } from "@account-kit/react"; import { ExtractAbiFunctionNames } from "abitype"; -import { Abi, EncodeFunctionDataParameters, WriteContractReturnType, encodeFunctionData } from "viem"; +import { Abi, EncodeFunctionDataParameters, WriteContractReturnType, encodeFunctionData, Hex } from "viem"; // Hex is part of feature_1_part_3 import { UseWriteContractParameters, useWriteContract } from "wagmi"; import { useSelectedNetwork } from "~~/hooks/scaffold-alchemy"; import { useDeployedContractInfo, useTransactor } from "~~/hooks/scaffold-alchemy"; @@ -70,6 +72,7 @@ export function useScaffoldWriteContract( const writeTx = useTransactor(); const [isMining, setIsMining] = useState(false); + const [isSmartWalletMining, setIsSmartWalletMining] = useState(false); //feature_1_part_3 const wagmiContractWrite = useWriteContract(finalWriteContractParams); @@ -80,10 +83,12 @@ export function useScaffoldWriteContract( chainId: selectedNetwork.id as AllowedChainIds, }); - const { client } = useClient(); + const { client, isSmartWallet } = useClient(); // isSmartWallet is part of feature_1_part_3 + // Only use useSendUserOperation for Smart Accounts cases + // For Smart Wallets, we'll use the client directly to avoid the EOA fallback const { sendUserOperationAsync, sendUserOperation } = useSendUserOperation({ - client, + client: !isSmartWallet ? client : undefined, // feature_1_part_3: client is undefined for Smart Wallets otherwise it falls back to EOA waitForTxn: true, }); @@ -103,23 +108,70 @@ export function useScaffoldWriteContract( return; } +// feature_1_part_3: useScaffoldWriteContract now supports Smart Wallets (EIP-7702) userOps block start ------ try { setIsMining(true); + if (isSmartWallet) { + setIsSmartWalletMining(true); + } + const { blockConfirmations, onBlockConfirmation } = options || {}; - const makeWriteWithParams = async () => { - const { hash } = await sendUserOperationAsync({ - uo: { - target: deployedContractData.address, - data: encodeFunctionData({ - abi: deployedContractData.abi, - functionName: variables.functionName, - args: variables.args || [], - } as EncodeFunctionDataParameters), - value: variables.value, - }, - }); - return hash; + + const makeWriteWithParams = async (): Promise => { + const encodedData = encodeFunctionData({ + abi: deployedContractData.abi, + functionName: variables.functionName, + args: variables.args || [], + } as EncodeFunctionDataParameters); + + // For Smart Wallets (EIP-7702), use the client directly + if (isSmartWallet && client) { + console.log("[ScaffoldWrite] Using Smart Wallet client for UserOp"); + console.log("[ScaffoldWrite] Target:", deployedContractData.address); + console.log("[ScaffoldWrite] Function:", variables.functionName); + console.log("[ScaffoldWrite] Value:", variables.value || 0n); + + try { + const result = await client.sendUserOperation({ + uo: { + target: deployedContractData.address, + data: encodedData, + value: variables.value || 0n, + }, + }); + + console.log("[ScaffoldWrite] UserOp sent, result:", result); + + // Wait for the transaction if we have a hash + if ('hash' in result && result.hash) { + console.log("[ScaffoldWrite] Waiting for UserOp transaction:", result.hash); + const txHash = await client.waitForUserOperationTransaction({ + hash: result.hash, + }); + console.log("[ScaffoldWrite] Transaction confirmed:", txHash); + return txHash as Hex; + } + + throw new Error("Failed to get transaction hash from Smart Wallet operation"); + } catch (error) { + console.error("[ScaffoldWrite] Smart Wallet operation failed:", error); + throw error; + } + } else if (sendUserOperationAsync) { + // Use the SDK's sendUserOperationAsync for regular smart accounts + const { hash } = await sendUserOperationAsync({ + uo: { + target: deployedContractData.address, + data: encodedData, + value: variables.value, + }, + }); + return hash as Hex; + } else { + throw new Error("No method available to send transaction"); + } }; + const writeTxResult = await writeTx(makeWriteWithParams, { blockConfirmations, onBlockConfirmation }); return writeTxResult; @@ -127,9 +179,11 @@ export function useScaffoldWriteContract( throw e; } finally { setIsMining(false); + setIsSmartWalletMining(false); } }; - +// feature_1_part_3: useScaffoldWriteContract now supports Smart Wallets (EIP-7702) userOps block end ------ + const sendContractWriteTx = < TContractName extends ContractName, TFunctionName extends ExtractAbiFunctionNames, "nonpayable" | "payable">, @@ -141,25 +195,53 @@ export function useScaffoldWriteContract( return; } - sendUserOperation({ - uo: { - target: deployedContractData.address, - data: encodeFunctionData({ - abi: deployedContractData.abi, - functionName: variables.functionName, - args: variables.args || [], - } as EncodeFunctionDataParameters), - value: variables.value, - }, - }); +// feature_1_part_3: useScaffoldWriteContract now supports Smart Wallets (EIP-7702) userOps block start ------ + if (!client && !isSmartWallet) { + notification.error(`You must first login before making an onchain action`); + return; + } + + const encodedData = encodeFunctionData({ + abi: deployedContractData.abi, + functionName: variables.functionName, + args: variables.args || [], + } as EncodeFunctionDataParameters); + + // For Smart Wallets (EIP-7702), use the client directly + if (isSmartWallet && client) { + console.log("[ScaffoldWrite] Using Smart Wallet client for UserOp (sync)"); + setIsSmartWalletMining(true); + client.sendUserOperation({ + uo: { + target: deployedContractData.address, + data: encodedData, + value: variables.value || 0n, + }, + }).then(() => { + setIsSmartWalletMining(false); + }).catch((error: any) => { + console.error("Smart Wallet operation failed:", error); + setIsSmartWalletMining(false); + }); + } else if (sendUserOperation) { + // Use the SDK's sendUserOperation for regular smart accounts + sendUserOperation({ + uo: { + target: deployedContractData.address, + data: encodedData, + value: variables.value, + }, + }); + } }; return { ...wagmiContractWrite, - isMining, + isMining: isMining || isSmartWalletMining, // Overwrite wagmi's writeContactAsync writeContractAsync: sendContractWriteAsyncTx, // Overwrite wagmi's writeContract writeContract: sendContractWriteTx, }; } +// feature_1_part_3: useScaffoldWriteContract now supports Smart Wallets (EIP-7702) userOps block end ------ \ No newline at end of file From 4371d65cbc95ceb321047eb221d6af427e039605 Mon Sep 17 00:00:00 2001 From: Ephyrian <150686927+UMainLove@users.noreply.github.com> Date: Sat, 12 Jul 2025 21:41:46 +0200 Subject: [PATCH 11/11] feature: Added explicit Smart Contract Account deployment button --- README.md | 32 ++-- .../ConnectButton/AddressInfoDropdown.tsx | 46 ++++- .../nextjs/hooks/scaffold-alchemy/index.ts | 1 + .../hooks/scaffold-alchemy/useAccountType.ts | 36 +++- .../useSmartAccountDeployment.ts | 167 ++++++++++++++++++ 5 files changed, 262 insertions(+), 20 deletions(-) create mode 100644 packages/nextjs/hooks/scaffold-alchemy/useSmartAccountDeployment.ts diff --git a/README.md b/README.md index f39499a..4cfb502 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# 🏗 Scaffold-Alchemy +# 🏗 Scaffold-Alchemy by UMainLove + +## THIS FORK CONTAINS EIP-7702 SUPPORT WITH METAMASK WALLETS Scaffold-Alchemy is a fork of the popular starter project [Scaffold-Eth 2](https://scaffoldeth.io/). It is everything you need to build dApps on Ethereum. You can get started immediately NextJS, TypeScript, Hardhat, AccountKit, Enhanced APIs and Subgraphs 🤩 @@ -16,34 +18,42 @@ Before you begin, you need to install the following tools: To get started with Scaffold-Alchemy, follow the steps below: -1. Install the latest version of Scaffold-Alchemy +Install the latest version of Scaffold-Alchemy -``` +```bash npx create-web3-dapp ``` -2. In a terminal, deploy the test contract: +In a terminal, deploy the test contract: -``` +```bash yarn deploy ``` This command deploys a test smart contract to a testnet. You can see the default testnet in `packages/hardhat/hardhat/config.ts` -3. In a second terminal, start your NextJS app: +In a second terminal, start your NextJS app: -``` +```bash yarn start ``` -Visit your app on: `http://localhost:3000`. You can interact with your smart contract using the `Debug Contracts` page. You can tweak the app config in `packages/nextjs/scaffold.config.ts`. +Visit your app on: `http://localhost:56900`. You can interact with your smart contract using the `Debug Contracts` page. You can tweak the app config in `packages/nextjs/scaffold.config.ts`. + +## Additional Features + +- Added deployment button for Modular Smart Contract Accounts (erc4337 + erc6900) +- Added eip-7702 upgrade button for connected EOA (Tested with: Metamask Wallets on Ethereum Sepolia testnet, private key required) +- Smart Wallets (EOA + eip7702 + erc4337) interactions fully supported ## Documentation -Visit our [docs](https://docs.alchemy.com/docs/scaffold-alchemy) to learn all the technical details and guides of Scaffold-Alchemy. +Visit [docs](https://docs.alchemy.com/docs/scaffold-alchemy) to learn all the technical details and guides of Scaffold-Alchemy. -## Contributing to Scaffold-Alchemy +Visit [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) to learn more about this Ethereum Improvement Proposal. -We welcome contributions to Scaffold-Alchemy! +Visit [Implementation](https://www.alchemy.com/docs/wallets/react/using-7702) to learn how eip-7702 could be implemented using Alchemy. + +## Contributing to Scaffold-Alchemy Please see [CONTRIBUTING.MD](https://github.com/alchemyplatform/scaffold-alchemy/blob/main/CONTRIBUTING.md) for more information and guidelines for contributing to Scaffold-Alchemy. diff --git a/packages/nextjs/components/scaffold-alchemy/ConnectButton/AddressInfoDropdown.tsx b/packages/nextjs/components/scaffold-alchemy/ConnectButton/AddressInfoDropdown.tsx index 02f5fab..6ac2cce 100644 --- a/packages/nextjs/components/scaffold-alchemy/ConnectButton/AddressInfoDropdown.tsx +++ b/packages/nextjs/components/scaffold-alchemy/ConnectButton/AddressInfoDropdown.tsx @@ -1,4 +1,6 @@ /* eslint-disable prettier/prettier */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { useRef, useState } from "react"; import { NetworkOptions } from "./NetworkOptions"; import { useLogout } from "@account-kit/react"; @@ -15,9 +17,10 @@ import { QrCodeIcon, ShieldCheckIcon, //feature_1 ExclamationTriangleIcon, // feature_1_part_2 + RocketLaunchIcon, // feature_2 } from "@heroicons/react/24/outline"; import { BlockieAvatar, isENS } from "~~/components/scaffold-alchemy"; -import { useOutsideClick, useAccountType, useEOAUpgrade } from "~~/hooks/scaffold-alchemy"; // 'useAccountType' is feature_1 AND 'useEOAUpgrade' is feature_1_part_2 +import { useOutsideClick, useAccountType, useEOAUpgrade, useSmartAccountDeployment } from "~~/hooks/scaffold-alchemy"; // 'useAccountType' is feature_1 AND 'useEOAUpgrade' is feature_1_part_2 AND 'useSmartAccountDeployment' is feature_2 import { getTargetNetworks } from "~~/utils/scaffold-alchemy"; import { EIP7702_CONFIG } from "~~/utils/scaffold-alchemy/eip7702.config"; // feature_1_part_2 @@ -46,6 +49,10 @@ export const AddressInfoDropdown = ({ isMetaMaskConnected, reset: resetUpgrade } = useEOAUpgrade(); // feature_1_part_2 + const { + isDeploying, + deploySmartAccount, + } = useSmartAccountDeployment(); // feature_2 const [addressCopied, setAddressCopied] = useState(false); const [showPrivateKeyModal, setShowPrivateKeyModal] = useState(false); // feature_1_part_2 @@ -67,12 +74,17 @@ export const AddressInfoDropdown = ({ const isUpgradeEnabled = showUpgradeButton && isEIP7702Supported; const isUpgrading = upgradeStatus === "upgrading"; + // feature_2: Determine if deploy button should be shown + const showDeployButton = accountType === "SCA_4337_UNDEPLOYED"; + // Get the appropriate message for the account status const getAccountStatusMessage = () => { if (isUpgrading) return "Upgrading..."; + if (isDeploying) return "Deploying..."; if (accountType === "EOA" && isMetaMaskConnected) return EIP7702_CONFIG.messages.UPGRADE_BUTTON; if (accountType === "EOA_7702") return EIP7702_CONFIG.messages.UPGRADED_EOA; if (accountType === "SCA_4337") return EIP7702_CONFIG.messages.SMART_ACCOUNT; + if (accountType === "SCA_4337_UNDEPLOYED") return "Deploy Smart Account"; if (accountType === "UNKNOWN") return EIP7702_CONFIG.messages.DETECTING; return "This is an EOA"; }; @@ -86,6 +98,14 @@ export const AddressInfoDropdown = ({ } }; + // Handle deploy button click for SCA_4337_UNDEPLOYED accounts + const handleDeployClick = async () => { + if (!isDeploying) { + closeDropdown(); + await deploySmartAccount(); + } + }; + const handlePrivateKeyUpgrade = async () => { if (!privateKey) return; @@ -167,9 +187,23 @@ export const AddressInfoDropdown = ({
  • - {showUpgradeButton ? ( + {showDeployButton ? ( + + ) : showUpgradeButton ? (