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