diff --git a/apps/dapp/.firebase/hosting.LmZpcmViYXNlL3NwYy1kYXBwL2hvc3Rpbmc.cache b/apps/dapp/.firebase/hosting.LmZpcmViYXNlL3NwYy1kYXBwL2hvc3Rpbmc.cache index 948936e..0d0ea81 100644 --- a/apps/dapp/.firebase/hosting.LmZpcmViYXNlL3NwYy1kYXBwL2hvc3Rpbmc.cache +++ b/apps/dapp/.firebase/hosting.LmZpcmViYXNlL3NwYy1kYXBwL2hvc3Rpbmc.cache @@ -1,9 +1,14 @@ -favicon.svg,1710612600596,11f7bbcc36bf2f54c31744264fa1b24a0811ed62e4d26d5b18d3b2dec99040a7 -global.css,1710612600596,42d73ffbdad77a1b36c73186c8ecfedf609c52809da1ae37a2853a0dd10a91a2 -index.html,1710612600596,4f4375b1d8a51aa512086a8597622b47c35c025491a244381d86050a6de93acd -_astro/hoisted.bU3TEY26.js,1710612600597,12298e4f606a273f1d1d5645e995b3f08bf59eb700b3581f4e2978abb27ab38a -_astro/create-payment-button.CE6C2yQc.js,1710612600598,12a2a4c61d23bc3d87b947c3202cb6a457bf9fa0b7b91087f1bf9cc339644c82 -_astro/index.8-_CQqnL.css,1710612600597,e9c06675410edad1a5e1e4185fe3e9c9a0002f94035f81189fe63e262c734447 -_astro/index.NEDEFKed.js,1710612600597,c1250d9adcf7af9f08cbad6c8b34267ac3bd193c676424dc5653db6fc9505e90 -_astro/constants.Bq4ER0LB.js,1710612600598,15319ae0b9cb6cac4168d89ce7618a53261b798b6ae301b81bdb49ae48ec7f75 -_astro/client.DbokQZWz.js,1710612600598,dfc9d946776d09a6ecd38cb440df7115dce93ec392f2272238dc903ac9f14163 +favicon.svg,1710628059222,11f7bbcc36bf2f54c31744264fa1b24a0811ed62e4d26d5b18d3b2dec99040a7 +global.css,1710628059221,42d73ffbdad77a1b36c73186c8ecfedf609c52809da1ae37a2853a0dd10a91a2 +_astro/button.cJ5DMypp.js,1710628059238,701808af954e14b33f962b51f6e71219536ea2f4b20b1ae61e0b928558367598 +index.html,1710628059220,87bd370988cdc70e3b2b51c75edaeeb78445e41a8a7ab17f79d566309f88c728 +_astro/constants.k50eM4pa.js,1710628059236,8fa9491ca1e640ee55957b77b7f3cb56d3b4fcc5cedf90ce245ccb6acecf08ea +_astro/create-payment-button.DS5N7mqO.js,1710628059229,0fd224ff01eb02fb4d86f2a4d0b59a1c150993b1c8a0c4cb689a551d277a47f3 +_astro/hoisted.Cf8LOESL.js,1710628059225,0c5166f31ddce70fa8cd3f0acbf876e43801022e909780dd31a3ceed67dfc527 +_astro/deploy-account-button.C4nwBoNT.js,1710628059225,de0abc549a0542a1f9aa88884a09575627da66f5a42b441711022b24ccb4c9ae +_astro/ccip.k6LiPXKt.js,1710628059238,001401e4836946326c7acfec5536a5decec22a0d79faa562acc13a78ed42003f +_astro/index.B7M7nzP-.css,1710628059224,76d1450f2c130d36cad17f351a69c9da2171b7c163a4e367ee22ced3de72c868 +_astro/index.NEDEFKed.js,1710628059224,c1250d9adcf7af9f08cbad6c8b34267ac3bd193c676424dc5653db6fc9505e90 +_astro/utils.DVs8iIlu.js,1710628059223,d2970d868c60c379893e77a2ee97083d0e04922da4e5ffc08dfd617667c282ad +_astro/client.DbokQZWz.js,1710628059237,dfc9d946776d09a6ecd38cb440df7115dce93ec392f2272238dc903ac9f14163 +_astro/deploy-account-button.BbVFG_Xp.js,1710628059226,8a5b39bd352c3286e80ab2b238f63f41315da2f19e3f4ef6dbe7180ae716d2ff diff --git a/apps/dapp/.firebase/spc-dapp/hosting/index.html b/apps/dapp/.firebase/spc-dapp/hosting/index.html index a53a03e..3c4ab54 100644 --- a/apps/dapp/.firebase/spc-dapp/hosting/index.html +++ b/apps/dapp/.firebase/spc-dapp/hosting/index.html @@ -1 +1 @@ - SPC dApp

SPC dApp

\ No newline at end of file + SPC dApp

SPC dApp

\ No newline at end of file diff --git a/apps/dapp/src/components/deploy-account-button.tsx b/apps/dapp/src/components/deploy-account-button.tsx deleted file mode 100644 index 5d33890..0000000 --- a/apps/dapp/src/components/deploy-account-button.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Button } from "@/components/ui/button"; -import { createSafe4337Account } from "@/lib/safe-account"; - -export function DeployAccountButton() { - return ( - - ); -} diff --git a/apps/dapp/src/lib/permissionless.ts b/apps/dapp/src/lib/permissionless.ts index 21f3161..70089ce 100644 --- a/apps/dapp/src/lib/permissionless.ts +++ b/apps/dapp/src/lib/permissionless.ts @@ -1,70 +1,26 @@ -import { createBundlerClient, createSmartAccountClient } from "permissionless" -import { baseSepolia } from "viem/chains" -import { createPublicClient, createWalletClient, http } from "viem" -import { createPimlicoPaymasterClient } from "permissionless/clients/pimlico"; -import { privateKeyToSimpleSmartAccount, signerToSafeSmartAccount } from "permissionless/accounts"; -import { privateKeyToAccount } from "viem/accounts"; +import { createBundlerClient } from "permissionless"; +import { createPublicClient, http } from "viem"; +import { baseSepolia } from "viem/chains"; // ! Dont do this in prod -const pimlicoApiKey = import.meta.env.PUBLIC_PIMLICO_API_KEY -const privateKey = import.meta.env.PUBLIC_PRIVATE_KEY +const pimlicoApiKey = import.meta.env.PUBLIC_PIMLICO_API_KEY; -const pimlicoTransport = (version: 'v1' | 'v2') => http(`https://api.pimlico.io/${version}/${baseSepolia.id}/rpc?apikey=${pimlicoApiKey}`) +const pimlicoTransport = (version: "v1" | "v2") => + http( + `https://api.pimlico.io/${version}/${baseSepolia.id}/rpc?apikey=${pimlicoApiKey}`, + ); -export const ENTRYPOINT_ADDRESS_V07 = '0x0000000071727De22E5E9d8BAf0edAc6f37da032'; -export const ENTRYPOINT_ADDRESS_V06 = '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'; +export const ENTRYPOINT_ADDRESS_V07 = + "0x0000000071727De22E5E9d8BAf0edAc6f37da032"; // create clients -------------------------------------------- export const publicClient = createPublicClient({ - transport: http(baseSepolia.rpcUrls.default.http[0]) -}); - -export const walletClient = createWalletClient({ - chain: baseSepolia, - transport: http(baseSepolia.rpcUrls.default.http[0]), - account: privateKeyToAccount(privateKey) + transport: http(baseSepolia.rpcUrls.default.http[0]), }); export const bundlerClient = createBundlerClient({ - chain: baseSepolia, - transport: pimlicoTransport('v2'), - entryPoint: ENTRYPOINT_ADDRESS_V07 -}) - -export const paymasterClient = createPimlicoPaymasterClient({ - transport: pimlicoTransport('v2'), - entryPoint: ENTRYPOINT_ADDRESS_V06 + chain: baseSepolia, + transport: pimlicoTransport("v2"), + entryPoint: ENTRYPOINT_ADDRESS_V07, }); - -// create account & account client -------------------------------------------- - -export const simpleAccount = await privateKeyToSimpleSmartAccount(publicClient, { - privateKey: privateKey, - factoryAddress: "0x15Ba39375ee2Ab563E8873C8390be6f2E2F50232", - entryPoint: ENTRYPOINT_ADDRESS_V07 -}); - -export const safeAccount = await signerToSafeSmartAccount(publicClient, { - entryPoint: ENTRYPOINT_ADDRESS_V06, - signer: privateKeyToAccount(privateKey), - saltNonce: 0n, // optional - safeVersion: "1.4.1", - //address: "0x...", // optional, only if you are using an already created account -}) - -export const smartAccountClient = createSmartAccountClient({ - account: simpleAccount, - entryPoint: ENTRYPOINT_ADDRESS_V07, - chain: baseSepolia, - bundlerTransport: pimlicoTransport('v2'), -}); - -export const safeAccountClient = createSmartAccountClient({ - account: safeAccount, - entryPoint: ENTRYPOINT_ADDRESS_V06, - chain: baseSepolia, - bundlerTransport: pimlicoTransport('v2'), -}); - - diff --git a/apps/dapp/src/lib/safe-account.ts b/apps/dapp/src/lib/safe-account.ts deleted file mode 100644 index a7a1112..0000000 --- a/apps/dapp/src/lib/safe-account.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { encodeFunctionData } from "viem" -import { walletClient, publicClient } from './permissionless' - -// abis -------------------------------------------- - -const ONIT_FACTORY_ADDRESS = '0x42ab880ea77fc7a09eb6ba0fe82fbc9901c114b6' - -const createSafe4337Abi = [ - { "type": "function", "name": "createSafe4337", "inputs": [{ "name": "passkeyPublicKey", "type": "uint256[2]", "internalType": "uint256[2]" }, { "name": "nonce", "type": "uint256", "internalType": "uint256" }], "outputs": [{ "name": "onitAccountAddress", "type": "address", "internalType": "address" }], "stateMutability": "nonpayable" } -] - -// formatting calls -------------------------------------------- - -export const createSafe4337Account = async () => { - const { request } = await publicClient.simulateContract({ - account: walletClient.account, - address: ONIT_FACTORY_ADDRESS, - abi: createSafe4337Abi, - functionName: 'createSafe4337', - args: [[1n, 2n], 3n], - }) - console.log({ request }) - - const deployResponse = await walletClient.writeContract(request) - console.log({ deployResponse }) - - return deployResponse -} - -const formatFactoryCreateSafe4337Calldata = (x: bigint, y: bigint, nonce: bigint) => { - const createSafe4337Calldata = encodeFunctionData({ abi: createSafe4337Abi, functionName: "createSafe4337", args: [[x, y], nonce] }) - console.log(createSafe4337Calldata) - return createSafe4337Calldata -} \ No newline at end of file diff --git a/apps/dapp/src/pages/index.astro b/apps/dapp/src/pages/index.astro index 84134a3..10da983 100644 --- a/apps/dapp/src/pages/index.astro +++ b/apps/dapp/src/pages/index.astro @@ -1,7 +1,6 @@ --- import "../../public/global.css"; import { CreatePaymentButton } from "@/components/create-payment-button"; -import { DeployAccountButton } from "@/components/deploy-account-button"; import { getPaymentOrigin } from "@/lib/utils"; const paymentOrigin = getPaymentOrigin(); @@ -22,13 +21,9 @@ import WalletIframeDialog from "@/components/wallet-iframe-dialog.astro";

SPC dApp

- - - diff --git a/apps/wallet/package.json b/apps/wallet/package.json index 22f4d60..d952c91 100644 --- a/apps/wallet/package.json +++ b/apps/wallet/package.json @@ -28,6 +28,7 @@ "firebase-tools": "^13.5.1", "helpers": "workspace:*", "lucide-react": "^0.358.0", + "permissionless": "^0.1.10", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.51.0", @@ -35,6 +36,7 @@ "tailwindcss": "^3.4.1", "tailwindcss-animate": "^1.0.7", "typescript": "^5.4.2", + "viem": "^2.8.10", "zod": "^3.22.4" } } \ No newline at end of file diff --git a/apps/wallet/src/components/forms/username.tsx b/apps/wallet/src/components/forms/username.tsx index 5761b23..18fee0e 100644 --- a/apps/wallet/src/components/forms/username.tsx +++ b/apps/wallet/src/components/forms/username.tsx @@ -38,10 +38,30 @@ export function UsernameForm() { } } - await registerSpcCredential({ + const registrationResponse = await registerSpcCredential({ username, challenge: "challenge", }); + + if (!registrationResponse.ok) { + console.error("Failed to register credential", registrationResponse); + return; + } + + // TODO: @jamesmccomish please add a description for this route handler ... why we need to deploy from a relay instead of + // TODO: using init code + const deployResponse = await fetch("/relay/deploy", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ username }), + }); + + const { txHash, address } = (await deployResponse.json()) ?? {}; + + console.log("deployResponse", { txHash, address }); + + if (txHash) localStorage.setItem("deployTxHash", txHash); + if (address) localStorage.setItem("address", address); } return ( diff --git a/apps/wallet/src/pages/relay/deploy.ts b/apps/wallet/src/pages/relay/deploy.ts new file mode 100644 index 0000000..60d17e5 --- /dev/null +++ b/apps/wallet/src/pages/relay/deploy.ts @@ -0,0 +1,114 @@ +import type { APIRoute } from "astro"; +import { Credential, db, sql } from "astro:db"; +import { getXandY, importPublicKeyAsCryptoKey } from "helpers"; +import { z } from "zod"; + +const deploySchema = z.object({ + username: z.string().optional(), + publicKey: z.string().optional(), +}); + +/** + * TODO: @jamesmccomish please add a description for this route handler ... why we need to deploy from a relay instead of + * TODO: using init code + */ + +export const POST: APIRoute = async (ctx) => { + try { + const { username, publicKey } = deploySchema.parse( + await ctx.request.json(), + ); + + if (!username || !publicKey) + return new Response("Invalid input", { status: 400 }); + + const [credential] = + (await db + .select() + .from(Credential) + .where( + username + ? sql`${Credential.username}= ${username}` + : sql`${Credential.publicKey}= ${publicKey}`, + ) + .limit(1)) ?? []; + + if (!credential) return new Response("Account not found", { status: 404 }); + + const publicKeyBuffer = Buffer.from(credential.publicKey, "base64url"); + + const pk = await importPublicKeyAsCryptoKey( + new Uint8Array(publicKeyBuffer), + ); + + if (!pk) return new Response("Invalid public key", { status: 400 }); + + const { x, y } = await getXandY(pk); + + const { txHash, result: deployAddress } = await relaySafeDeploy({ + publicKey: [BigInt(x), BigInt(y)], + }); + + return new Response(JSON.stringify({ address: deployAddress, txHash }), { + status: 204, + }); + } catch (e) { + console.log("error", e); + + return new Response((e as Error).message, { status: 500 }); + } +}; + +const relaySafeDeploy = async ({ + publicKey, +}: { publicKey: [bigint, bigint] }) => { + const { baseSepolia } = await import("viem/chains"); + const { createPublicClient, createWalletClient, http } = await import("viem"); + const { privateKeyToAccount } = await import("viem/accounts"); + + const publicClient = createPublicClient({ + transport: http(baseSepolia.rpcUrls.default.http[0]), + }); + + const walletClient = createWalletClient({ + chain: baseSepolia, + transport: http(baseSepolia.rpcUrls.default.http[0]), + account: privateKeyToAccount(import.meta.env.PRIVATE_KEY), + }); + + const { request, result } = await publicClient.simulateContract({ + account: walletClient.account, + address: ONIT_FACTORY_ADDRESS, + abi: createSafe4337Abi, + functionName: "createSafe4337", + args: [publicKey, 0n], + }); + + const txHash = await walletClient.writeContract(request); + + return { txHash, result }; +}; + +// abis -------------------------------------------- + +const ONIT_FACTORY_ADDRESS = + "0x42ab880ea77fc7a09eb6ba0fe82fbc9901c114b6" as const; + +const createSafe4337Abi = [ + { + type: "function", + name: "createSafe4337", + inputs: [ + { + name: "passkeyPublicKey", + type: "uint256[2]", + internalType: "uint256[2]", + }, + { name: "nonce", type: "uint256", internalType: "uint256" }, + ], + outputs: [ + { name: "onitAccountAddress", type: "address", internalType: "address" }, + ], + stateMutability: "nonpayable", + }, +] as const; diff --git a/packages/helpers/index.ts b/packages/helpers/index.ts index 2e9a164..dadc488 100644 --- a/packages/helpers/index.ts +++ b/packages/helpers/index.ts @@ -2,3 +2,4 @@ export * from "./base64url"; export * from "./domains"; export * from "./is-spc-available"; export * from "./validators"; +export * from "./webauthn"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d0007c2..0ca19ea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -134,6 +134,9 @@ importers: lucide-react: specifier: ^0.358.0 version: 0.358.0(react@18.2.0) + permissionless: + specifier: ^0.1.10 + version: 0.1.10(viem@2.8.10) react: specifier: ^18.2.0 version: 18.2.0 @@ -155,6 +158,9 @@ importers: typescript: specifier: ^5.4.2 version: 5.4.2 + viem: + specifier: ^2.8.10 + version: 2.8.10(typescript@5.4.2)(zod@3.22.4) zod: specifier: ^3.22.4 version: 3.22.4