diff --git a/.env.local.example b/.env.local.example index c646519..ab0cb02 100644 --- a/.env.local.example +++ b/.env.local.example @@ -1,3 +1,5 @@ +# only include NEXT_PUBLIC_PAYMASTER_POLICY_ID if you require a paymaster policy +NEXT_PUBLIC_PAYMASTER_POLICY_ID= NEXT_PUBLIC_PAYMASTER_API_KEY= NEXT_PUBLIC_BUNDLER_URL= NEXT_PUBLIC_WEB3_CLIENT_ID= diff --git a/README.md b/README.md index c516b34..fa08918 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Hello Gator 🐊 -Easily get up-to-speed with (and integrate) the MetaMask Delegation Toolkit with this demonstration. It includes examples for all the core elements including Delegator Account (ERC-4337) creation, sending User Operations, and the Delegation lifecycle. Example code is provided utilising the DeleGator Core [Viem](https://viem.sh/) client. +Easily get up-to-speed with (and integrate) the MetaMask Delegation Toolkit with this demonstration. It includes examples for all the core elements including Delegator Account (ERC-4337) creation, sending User Operations, and the Delegation lifecycle. Example code is provided utilising the Delegator Smart Account. Note: this template is also designed to complement the [documentation](https://docs.gator.metamask.io). diff --git a/next-env.d.ts b/next-env.d.ts index 4f11a03..40c3d68 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. +// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. diff --git a/package.json b/package.json index 59d8a47..a589e6c 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,12 @@ "lint": "next lint" }, "dependencies": { - "@codefi/delegator-core-viem": "0.1.1", + "@codefi/delegator-core-viem": "0.4.0", "@web3auth/base": "^8.12.2", "@web3auth/ethereum-provider": "^8.12.3", "@web3auth/modal": "^8.12.3", - "next": "13.5.3", + "next": "14.2.10", + "permissionless": "^0.2.10", "react": "^18.2.0", "react-dom": "^18.2.0", "viem": "latest" diff --git a/src/app/examples/index.ts b/src/app/examples/index.ts index a2d0b82..f98fbaf 100644 --- a/src/app/examples/index.ts +++ b/src/app/examples/index.ts @@ -1,24 +1,14 @@ -const examples = [ - // { - // "name": "Delegation Lifecycle", - // "path": "delegations", - // "description": "Create, sign, and redeem delegations." - // }, +const examples = Object.freeze([ { "name": "Custom Signers", "path": "signers", "description": "See the various signer options in action." + }, + { + "name": "Enable and Disable Delegations", + "path": "toggle-delegation", + "description": "Toggle the ability to redeem a delegation." }, - // { - // "name": "Storage API", - // "path": "storage", - // "description": "Use the Delegation Storage client to store and retrieve delegations." - // }, - // { - // "name": "Revoke Delegations", - // "path": "revoke", - // "description": "See how to revoke existing delegations." - // }, -] +]); export default examples; diff --git a/src/app/examples/signers/SignatoryTypes.ts b/src/app/examples/signers/SignatoryTypes.ts index 6633cf4..9f751a2 100644 --- a/src/app/examples/signers/SignatoryTypes.ts +++ b/src/app/examples/signers/SignatoryTypes.ts @@ -1,4 +1,4 @@ -import { Signatory, WalletClientAccount } from "@codefi/delegator-core-viem"; +import { HybridSignatoryConfig } from "@codefi/delegator-core-viem"; import { OPENLOGIN_NETWORK_TYPE } from "@web3auth/base"; import { Address, Chain } from "viem"; @@ -10,7 +10,7 @@ export type SignatoryFactoryConfig = { }; export type SignatoryLoginFunction = () => Promise<{ - signatory: Signatory | WalletClientAccount; + signatory: HybridSignatoryConfig; owner: Address; }>; diff --git a/src/app/examples/signers/burnerSignatoryFactory.tsx b/src/app/examples/signers/burnerSignatoryFactory.tsx index 47b6613..9a5dcee 100644 --- a/src/app/examples/signers/burnerSignatoryFactory.tsx +++ b/src/app/examples/signers/burnerSignatoryFactory.tsx @@ -11,11 +11,11 @@ export const createBurnerSignatoryFactory: SignatoryFactoryConfigurator = ( return { login: async () => { const privateKey = generatePrivateKey(); - const owner = privateKeyToAccount(privateKey); + const account = privateKeyToAccount(privateKey); return { - signatory: owner, - owner: owner.address, + signatory: { account }, + owner: account.address, }; }, canLogout: () => false, diff --git a/src/app/examples/signers/injectedProviderSignatoryFactory.tsx b/src/app/examples/signers/injectedProviderSignatoryFactory.tsx index f972cf9..5a1a783 100644 --- a/src/app/examples/signers/injectedProviderSignatoryFactory.tsx +++ b/src/app/examples/signers/injectedProviderSignatoryFactory.tsx @@ -32,7 +32,7 @@ export const createInjectedProviderSignatoryFactory: SignatoryFactoryConfigurato method: "eth_requestAccounts", })) as Address[]; - const signatory = createWalletClient({ + const walletClient = createWalletClient({ chain, transport: custom(provider), account: owner, @@ -40,7 +40,7 @@ export const createInjectedProviderSignatoryFactory: SignatoryFactoryConfigurato return { owner, - signatory, + signatory: { walletClient}, }; }; diff --git a/src/app/examples/signers/page.tsx b/src/app/examples/signers/page.tsx index 8550472..765195b 100644 --- a/src/app/examples/signers/page.tsx +++ b/src/app/examples/signers/page.tsx @@ -1,110 +1,107 @@ "use client"; import { useEffect, useState } from "react"; -import { http, toHex } from "viem"; +import { + Client, + createPublicClient, + Hex, + http, + toHex, + zeroAddress, +} from "viem"; import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"; import { sepolia as chain } from "viem/chains"; import { Implementation, - createDeleGatorClient, - PimlicoVerifyingPaymasterSponsor, - PimlicoGasFeeResolver, - createBundlerClient, + toMetaMaskSmartAccount, + type MetaMaskSmartAccount, + type DelegationStruct, createRootDelegation, - createAction, - getExplorerAddressLink, + DelegationFramework, + SINGLE_DEFAULT_MODE, getExplorerTransactionLink, - type DeleGatorClient, - type DelegationStruct, - type UserOperationV07, + getExplorerAddressLink, + createExecution, } from "@codefi/delegator-core-viem"; +import { + createBundlerClient, + createPaymasterClient, + UserOperationReceipt, +} from "viem/account-abstraction"; +import { createPimlicoClient } from "permissionless/clients/pimlico"; import { randomBytes } from "crypto"; import { type SignatoryFactoryName, useSelectedSignatory, } from "./useSelectedSignatory"; import { WEB3AUTH_NETWORK_TYPE } from "@web3auth/base"; +import { formatJSON } from "@/app/utils"; - -const PIMLICO_PAYMASTER_KEY = process.env.NEXT_PUBLIC_PAYMASTER_API_KEY!; -const BUNDLER_URL = process.env.NEXT_PUBLIC_BUNDLER_URL!; const WEB3_AUTH_CLIENT_ID = process.env.NEXT_PUBLIC_WEB3_CLIENT_ID!; const WEB3_AUTH_NETWORK = process.env .NEXT_PUBLIC_WEB3_AUTH_NETWORK! as WEB3AUTH_NETWORK_TYPE; +const BUNDLER_URL = process.env.NEXT_PUBLIC_BUNDLER_URL!; const RPC_URL = process.env.NEXT_PUBLIC_RPC_URL!; +// if this is undefined, the API_KEY must be configured to Enable verifying paymaster +const PAYMASTER_POLICY_ID = process.env.NEXT_PUBLIC_PAYMASTER_POLICY_ID; const createSalt = () => toHex(randomBytes(8)); -const createCounterfactualDelegatorClient = () => { +const createSmartAccount = (client: Client) => { const privateKey = generatePrivateKey(); const owner = privateKeyToAccount(privateKey); - const viemClient = createDeleGatorClient({ - transport: http(), - chain, - account: { - implementation: Implementation.Hybrid, - deployParams: [owner.address, [], [], []], - isAccountDeployed: false, - signatory: owner, - deploySalt: createSalt(), - }, + const account = toMetaMaskSmartAccount({ + client, + implementation: Implementation.Hybrid, + deployParams: [owner.address, [], [], []], + signatory: { account: owner }, + deploySalt: createSalt(), }); - return viemClient; + return account; }; -const formatJSON = (value: any) => { - if (value === null || value === undefined) { - return "NA"; - } - - return JSON.stringify( - value, - (_, v) => (typeof v === "bigint" ? `${v.toString()}n` : v), - 2 - ); -}; +type DeploymentStatus = + | "deployed" + | "counterfactual" + | "deployment in progress"; function DeleGatorAccount({ - client, - isDeploying, + account, + deploymentStatus, }: { - client: DeleGatorClient | undefined; - isDeploying: boolean; + account: MetaMaskSmartAccount | undefined; + deploymentStatus: DeploymentStatus; }) { - if (!client) { + if (!account) { return "NA"; } - const status = client.account.isAccountDeployed - ? "deployed" - : isDeploying - ? "deployment in progress" - : "counterfactual"; - const explorerUrl = getExplorerAddressLink(chain.id, client.account.address); + const explorerUrl = getExplorerAddressLink(chain.id, account.address); return ( <> - {client.account.address} -{" "} - {status} + {account.address} - {deploymentStatus} ); } function App() { - const [delegateClient, setDelegateClient] = useState(); - const [delegatorClient, setDelegatorClient] = useState(); - + const [delegateAccount, setDelegateSmartAccount] = + useState>(); + const [delegatorAccount, setDelegatorAccount] = + useState>(); const [delegation, setDelegation] = useState(); - const [userOp, setUserOp] = useState(); - const [userOpExplorerUrl, setUserOpExplorerUrl] = useState(); - const [isDelegatorDeploymentStarted, setIsDelegatorDeploymentStarted] = - useState(false); - const [isDelegateDeploymentStarted, setIsDelegateDeploymentStarted] = - useState(false); + const [userOpReceipt, setUserOpReceipt] = useState(); + const [delegateDeploymentStatus, setDelegateDeploymentStatus] = + useState("counterfactual"); + const [delegatorDeploymentStatus, setDelegatorDeploymentStatus] = + useState("counterfactual"); + const [isRedeemingDelegation, setIsRedeemingDelegation] = + useState(false); const { selectedSignatory, setSelectedSignatoryName, selectedSignatoryName } = useSelectedSignatory({ @@ -114,43 +111,56 @@ function App() { rpcUrl: RPC_URL, }); - const bundler = createBundlerClient(BUNDLER_URL); - const paymaster = PimlicoVerifyingPaymasterSponsor({ - pimlicoAPIKey: PIMLICO_PAYMASTER_KEY, + const client = createPublicClient({ + chain, + transport: http(RPC_URL), }); - const gasFeeResolver = PimlicoGasFeeResolver({ - pimlicoAPIKey: PIMLICO_PAYMASTER_KEY, - inclusionSpeed: "fast", + const paymasterContext = PAYMASTER_POLICY_ID + ? { + sponsorshipPolicyId: PAYMASTER_POLICY_ID, + } + : undefined; + + const pimlicoClient = createPimlicoClient({ + transport: http(BUNDLER_URL), + }); + + const bundlerClient = createBundlerClient({ + transport: http(BUNDLER_URL), + paymaster: createPaymasterClient({ + transport: http(BUNDLER_URL), + }), + chain, + paymasterContext, }); const isValidSignatorySelected = selectedSignatory && !selectedSignatory.isDisabled; const canDeployDelegatorAccount = - delegatorClient && !isDelegatorDeploymentStarted; - const canCreateDelegation = !!(delegateClient && delegatorClient); - const canSignDelegation = !!(delegatorClient && delegation); + delegatorAccount && delegatorDeploymentStatus === "counterfactual"; + const canCreateDelegation = !!(delegateAccount && delegatorAccount); + const canSignDelegation = !!(delegatorAccount && delegation); const canRedeemDelegation = !!( - delegatorClient?.account.isAccountDeployed && - delegateClient && + delegatorDeploymentStatus === "deployed" && + !isRedeemingDelegation && + delegateAccount && delegation?.signature !== undefined && delegation?.signature !== "0x" ); const canLogout = isValidSignatorySelected && selectedSignatory.canLogout(); + // create the delegate account immediately on page load useEffect(() => { - const viemClient = createCounterfactualDelegatorClient(); - setDelegateClient(viemClient); + createSmartAccount(client).then(setDelegateSmartAccount); }, []); const handleSignatoryChange = (ev: any) => { const signatoryName = ev.target.value as SignatoryFactoryName; setSelectedSignatoryName(signatoryName); - setDelegatorClient(undefined); - setIsDelegatorDeploymentStarted(false); - setUserOp(undefined); - setUserOpExplorerUrl(undefined); + setDelegatorAccount(undefined); + setUserOpReceipt(undefined); setDelegation(undefined); }; @@ -160,10 +170,8 @@ function App() { } await selectedSignatory!.logout!(); - setDelegatorClient(undefined); - setIsDelegatorDeploymentStarted(false); - setUserOp(undefined); - setUserOpExplorerUrl(undefined); + setDelegatorAccount(undefined); + setUserOpReceipt(undefined); setDelegation(undefined); }; @@ -173,22 +181,16 @@ function App() { } const { owner, signatory } = await selectedSignatory.login(); - const viemClient = createDeleGatorClient({ - transport: http(), - chain, - account: { - implementation: Implementation.Hybrid, - deployParams: [owner, [], [], []], - isAccountDeployed: false, - signatory, - deploySalt: createSalt(), - }, + const smartAccount = await toMetaMaskSmartAccount({ + client, + implementation: Implementation.Hybrid, + deployParams: [owner, [], [], []], + deploySalt: createSalt(), + signatory, }); - setDelegatorClient(viemClient); - setIsDelegatorDeploymentStarted(false); - setUserOp(undefined); - setUserOpExplorerUrl(undefined); + setDelegatorAccount(smartAccount); + setDelegatorDeploymentStatus("counterfactual"); setDelegation(undefined); }; @@ -197,19 +199,25 @@ function App() { return; } - setIsDelegatorDeploymentStarted(true); + setDelegatorDeploymentStatus("deployment in progress"); - const action = createAction("0x0000000000000000000000000000000000000000"); - const unsponsoredUserOp = await delegatorClient.createExecuteUserOp( - action, - await gasFeeResolver.determineGasFee(chain) - ); + const { fast: fee } = await pimlicoClient.getUserOperationGasPrice(); - await sponsorAndSubmitUserOp(delegatorClient, unsponsoredUserOp); + const userOpHash = await bundlerClient.sendUserOperation({ + account: delegatorAccount, + calls: [ + { + to: zeroAddress, + }, + ], + ...fee, + }); - if (!delegatorClient.account.isAccountDeployed) { - setDelegatorClient(delegatorClient.toDeployedClient()); - } + bundlerClient.waitForUserOperationReceipt({ + hash: userOpHash, + }); + + setDelegatorDeploymentStatus("deployed"); }; const handleCreateDelegation = () => { @@ -218,8 +226,9 @@ function App() { } const newDelegation = createRootDelegation( - delegateClient.account.address, - delegatorClient.account.address + delegateAccount.address, + delegatorAccount.address, + [] ); setDelegation(newDelegation); @@ -230,42 +239,14 @@ function App() { return; } - const signedDelegation = await delegatorClient.signDelegation(delegation); - setDelegation(signedDelegation); - }; - - const sponsorAndSubmitUserOp = async ( - client: DeleGatorClient, - unsponsoredUserOp: UserOperationV07 - ) => { - const sponsorship = await paymaster.getUserOperationSponsorship( - client.account.environment.EntryPoint, - chain, - unsponsoredUserOp - ); - - const unsignedUserOp = { - ...unsponsoredUserOp, - ...sponsorship, - }; - - const userOp = await client.signUserOp(unsignedUserOp); - - const { result: hash } = await bundler.sendUserOp( - userOp, - client.account.environment.EntryPoint - ); - - const { result: userOperationReceipt } = await bundler.pollForReceipt(hash); - - if (!userOperationReceipt.success) { - throw new Error(`UserOperation failed: ${userOperationReceipt.reason}`); - } + const signature = await delegatorAccount.signDelegation({ + delegation, + }); - return { - userOperationReceipt, - userOp, - }; + setDelegation({ + ...delegation, + signature, + }); }; const handleRedeemDelegation = async () => { @@ -273,37 +254,57 @@ function App() { return; } - const action = createAction(delegateClient.account.address); + setIsRedeemingDelegation(true); + + const execution = createExecution(); - const unsponsoredUserOp = await delegateClient.createRedeemDelegationUserOp( - [delegation], - action, - await gasFeeResolver.determineGasFee(chain) + const data = DelegationFramework.encode.redeemDelegations( + [[delegation]], + [SINGLE_DEFAULT_MODE], + [[execution]] ); - setUserOp(unsponsoredUserOp); - if (!delegateClient.account.isAccountDeployed) { - // if the account is already deployed, isDelegateDeploymentStarted is already true anyway - setIsDelegateDeploymentStarted(true); + if (delegateDeploymentStatus === "counterfactual") { + setDelegateDeploymentStatus("deployment in progress"); } - const { userOp, userOperationReceipt } = await sponsorAndSubmitUserOp( - delegateClient, - unsponsoredUserOp - ); + const { fast: fee } = await pimlicoClient.getUserOperationGasPrice(); + + let userOpHash: Hex; + + try { + userOpHash = await bundlerClient.sendUserOperation({ + account: delegateAccount, + calls: [ + { + to: delegateAccount.address, + data, + }, + ], + ...fee, + }); + } catch (error) { + setIsRedeemingDelegation(false); + if (delegateDeploymentStatus === "deployment in progress") { + setDelegateDeploymentStatus("counterfactual"); + } + throw error; + } - setUserOp(userOp); + const userOperationReceipt = + await bundlerClient.waitForUserOperationReceipt({ hash: userOpHash }); - setDelegateClient(delegateClient.toDeployedClient()); + setUserOpReceipt(userOperationReceipt); - const explorerUrl = getExplorerTransactionLink( - chain.id, - userOperationReceipt.receipt.transactionHash - ); + setDelegateDeploymentStatus("deployed"); - setUserOpExplorerUrl(explorerUrl); + setIsRedeemingDelegation(false); }; + const userOpExplorerUrl = + userOpReceipt && + getExplorerTransactionLink(chain.id, userOpReceipt.receipt.transactionHash); + return (

Viem Client Quickstart

@@ -329,7 +330,11 @@ function App() { Operation, where it is settled on-chain.

{" "} -
); } diff --git a/src/app/examples/signers/web3AuthSignatoryFactory.tsx b/src/app/examples/signers/web3AuthSignatoryFactory.tsx index 3b90a9c..32de030 100644 --- a/src/app/examples/signers/web3AuthSignatoryFactory.tsx +++ b/src/app/examples/signers/web3AuthSignatoryFactory.tsx @@ -45,7 +45,7 @@ export const createWeb3AuthSignatoryFactory: SignatoryFactoryConfigurator = ( method: "eth_accounts", })) as Address[]; - const signatory = createWalletClient({ + const walletClient = createWalletClient({ chain, transport: custom(provider), account: owner, @@ -53,7 +53,7 @@ export const createWeb3AuthSignatoryFactory: SignatoryFactoryConfigurator = ( return { owner, - signatory, + signatory: { walletClient }, }; }; diff --git a/src/app/examples/toggle-delegation/page.tsx b/src/app/examples/toggle-delegation/page.tsx new file mode 100644 index 0000000..7c4478b --- /dev/null +++ b/src/app/examples/toggle-delegation/page.tsx @@ -0,0 +1,371 @@ +"use client"; + +import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { createPublicClient, getContract, http, toHex } from "viem"; +import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"; +import { sepolia as chain } from "viem/chains"; +import { + Implementation, + toMetaMaskSmartAccount, + createRootDelegation, + type MetaMaskSmartAccount, + type DelegationStruct, + getExplorerAddressLink, + getExplorerTransactionLink, + DelegationManager, + getDelegationHashOffchain, + Call, + DelegationFramework, +} from "@codefi/delegator-core-viem"; +import { + createBundlerClient, + createPaymasterClient, +} from "viem/account-abstraction"; +import { createPimlicoClient } from "permissionless/clients/pimlico"; +import { randomBytes } from "crypto"; +import { formatJSON } from "@/app/utils"; + +const BUNDLER_URL = process.env.NEXT_PUBLIC_BUNDLER_URL!; +const RPC_URL = process.env.NEXT_PUBLIC_RPC_URL!; +const PAYMASTER_POLICY_ID = process.env.NEXT_PUBLIC_PAYMASTER_POLICY_ID; + +const createSalt = () => toHex(randomBytes(8)); + +const createCounterfactualDelegatorAccount = async () => { + const privateKey = generatePrivateKey(); + const owner = privateKeyToAccount(privateKey); + + const client = createPublicClient({ + chain, + transport: http(RPC_URL), + }); + + const smartAccount = await toMetaMaskSmartAccount({ + client, + implementation: Implementation.Hybrid, + deployParams: [owner.address, [], [], []], + deploySalt: createSalt(), + signatory: { account: owner }, + }); + + return smartAccount; +}; + +type DeploymentStatus = + | "deployed" + | "counterfactual" + | "deployment in progress"; + +function DeleGatorAccount({ + account, + deploymentStatus, +}: { + account: MetaMaskSmartAccount | undefined; + deploymentStatus: DeploymentStatus; +}) { + if (!account) { + return "NA"; + } + + const explorerUrl = getExplorerAddressLink(chain.id, account.address); + + return ( + <> + + {account.address} - {deploymentStatus} + + + ); +} + +function App() { + const [delegateAccount, setDelegateAccount] = + useState>(); + const [delegatorAccount, setDelegatorAccount] = + useState>(); + const [delegation, setDelegation] = useState(); + const [userOpExplorerUrlEnable, setUserOpExplorerUrlEnable] = + useState(); + const [userOpExplorerUrlDisable, setUserOpExplorerUrlDisable] = + useState(); + const [delegateDeploymentStatus, setDelegateDeploymentStatus] = + useState("counterfactual"); + const [delegatorDeploymentStatus, setDelegatorDeploymentStatus] = + useState("counterfactual"); + const [delegationStatus, setDelegationStatus] = useState(); + const [isActionLoading, setIsActionLoading] = useState(false); + + const client = createPublicClient({ + chain, + transport: http(RPC_URL), + }); + + const paymasterContext = PAYMASTER_POLICY_ID + ? { + sponsorshipPolicyId: PAYMASTER_POLICY_ID, + } + : undefined; + + const pimlicoClient = createPimlicoClient({ + transport: http(BUNDLER_URL), + }); + + const bundlerClient = createBundlerClient({ + transport: http(BUNDLER_URL), + paymaster: createPaymasterClient({ + transport: http(BUNDLER_URL), + }), + chain, + paymasterContext, + }); + + const canCreateDelegation = !!(delegateAccount && delegatorAccount); + const canSignDelegation = !!(delegatorAccount && delegation); + + useEffect(() => { + createCounterfactualDelegatorAccount().then(setDelegateAccount); + }, []); + + const handleCreateDelegator = async () => { + const account = await createCounterfactualDelegatorAccount(); + + setDelegatorAccount(account); + setDelegateDeploymentStatus("counterfactual"); + setUserOpExplorerUrlDisable(undefined); + setUserOpExplorerUrlEnable(undefined); + setDelegation(undefined); + }; + + const handleDelegationAction = async ( + createCalls: () => Call[], + setExplorerUrl: Dispatch> + ) => { + if (delegatorAccount) { + if (!delegatorAccount.isDeployed) { + setDelegatorDeploymentStatus("deployment in progress"); + } + + setIsActionLoading(true); // Disable the button + try { + const { fast: fees } = await pimlicoClient.getUserOperationGasPrice(); + + const calls = await createCalls(); + + const userOpHash = await bundlerClient.sendUserOperation({ + account: delegatorAccount, + calls, + ...fees, + }); + + const userOperationReceipt = + await bundlerClient.waitForUserOperationReceipt({ + hash: userOpHash, + }); + + const explorerUrl = getExplorerTransactionLink( + chain.id, + userOperationReceipt.receipt.transactionHash + ); + + setTimeout(() => { + handleCheckDelegationStatus(); + }, 2000); + + setDelegatorDeploymentStatus("deployed"); + setExplorerUrl(explorerUrl); + } finally { + setIsActionLoading(false); // Re-enable the button + } + } + }; + + const handleDisableDelegation = async () => { + await handleDelegationAction( + () => [ + { + to: delegatorAccount!.address, + data: DelegationFramework.encode.disableDelegation(delegation!), + }, + ], + setUserOpExplorerUrlDisable + ); + }; + + const handleEnableDelegation = async () => { + await handleDelegationAction( + () => [ + { + to: delegatorAccount!.address, + data: DelegationFramework.encode.enableDelegation(delegation!), + }, + ], + + setUserOpExplorerUrlEnable + ); + }; + + const handleCreateDelegation = async () => { + if (!canCreateDelegation) { + return; + } + + const newDelegation = createRootDelegation( + delegateAccount!.address, + delegatorAccount!.address, + [] + ); + + setDelegation(newDelegation); + await handleCheckDelegationStatusFromInput(newDelegation); + }; + + const handleSignDelegation = async () => { + if (!canSignDelegation) { + return; + } + + const signedDelegation = { + ...delegation, + signature: await delegatorAccount!.signDelegation({ delegation }), + }; + + setDelegation(signedDelegation); + }; + + const handleCheckDelegationStatus = async () => { + handleCheckDelegationStatusFromInput(delegation as DelegationStruct); + }; + + const handleCheckDelegationStatusFromInput = async ( + delegationInput: DelegationStruct + ) => { + try { + if (delegatorAccount) { + const contract = getContract({ + abi: DelegationManager.abi, + address: delegatorAccount.environment.DelegationManager, + client, + }); + const delegationHash = getDelegationHashOffchain(delegationInput); + const isDelegationDisabled = await contract.read.disabledDelegations([ + delegationHash, + ]); + setDelegationStatus(!isDelegationDisabled); + } + } catch (error) { + console.error("Failed to check delegation status", error); + } + }; + + return ( +
+

Enable and Disable Delegations

+

+ In this example, a delegation is created that is enabled by default. Its + status can then be changed using the provided buttons which send the + corresponding User Operation. +

+
+

Note

+

+ A delegation can only be re-enabled if it is currently disabled, and + disabled if it is currently enabled. Attempting to set the status to + its existing state will result in an error." +

+
+ {" "} +

Accounts:

+
+        Delegate:{" "}
+        
+        
+ Delegator:{" "} + +
+
+ {" "} + {delegation && ( + <> + +

Delegation:

+
{formatJSON(delegation)}
+

Delegation Status:

+
+            {`The delegation is ` + (delegationStatus ? "enabled" : "disabled")}
+            .
+          
+
+ {" "} + {/* New button */} + {" "} + +

UserOpDisable:

+ {userOpExplorerUrlDisable && ( + + View transaction + + )} +

UserOpEnable:

+ {userOpExplorerUrlEnable && ( + + View transaction + + )} + + )} +
+ ); +} + +export default App; diff --git a/src/app/page.tsx b/src/app/page.tsx index b297e64..3d7310a 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,101 +1,105 @@ "use client"; import { useState } from "react"; -import { http } from "viem"; +import { createPublicClient, http, zeroAddress } from "viem"; import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"; import { sepolia as chain } from "viem/chains"; import { Implementation, - createDeleGatorClient, - PimlicoVerifyingPaymasterSponsor, - PimlicoGasFeeResolver, - createBundlerClient, - createAction, - type DeleGatorClient, - UserOperationReceiptResponse, - getExplorerAddressLink, - getExplorerTransactionLink, + toMetaMaskSmartAccount, + type MetaMaskSmartAccount, } from "@codefi/delegator-core-viem"; +import { + createBundlerClient, + createPaymasterClient, + UserOperationReceipt, +} from "viem/account-abstraction"; +import { createPimlicoClient } from "permissionless/clients/pimlico"; const BUNDLER_URL = process.env.NEXT_PUBLIC_BUNDLER_URL!; -const PIMLICO_PAYMASTER_KEY = process.env.NEXT_PUBLIC_PAYMASTER_API_KEY!; +const RPC_URL = process.env.NEXT_PUBLIC_RPC_URL!; +// if this is undefined, the API_KEY must be configured to Enable verifying paymaster +const PAYMASTER_POLICY_ID = process.env.NEXT_PUBLIC_PAYMASTER_POLICY_ID; import examples from "@/app/examples"; import Hero from "../components/Hero"; function App() { - const [delegator, setDelegator] = useState(); + const [delegatorSmartAccount, setDelegatorSmartAccount] = + useState>(); const [isDeploying, setIsDeploying] = useState(false); const [userOperationReceipt, setUserOperationReceipt] = - useState(); + useState(); + + const publicClient = createPublicClient({ + chain, + transport: http(RPC_URL), + }); - const gasFeeResolver = PimlicoGasFeeResolver({ - pimlicoAPIKey: PIMLICO_PAYMASTER_KEY, - inclusionSpeed: "fast", + const paymasterContext = PAYMASTER_POLICY_ID + ? { + sponsorshipPolicyId: PAYMASTER_POLICY_ID, + } + : undefined; + + const pimlicoClient = createPimlicoClient({ + transport: http(BUNDLER_URL), + }); + + const paymasterClient = createPaymasterClient({ + transport: http(BUNDLER_URL), }); - const paymaster = PimlicoVerifyingPaymasterSponsor({ - pimlicoAPIKey: PIMLICO_PAYMASTER_KEY, + const bundlerClient = createBundlerClient({ + transport: http(BUNDLER_URL), + paymaster: paymasterClient, + chain, + paymasterContext, }); - function handleCreateDelegator() { + async function handleCreateDelegator() { const privateKey = generatePrivateKey(); const owner = privateKeyToAccount(privateKey); - const delegatorClient = createDeleGatorClient({ - transport: http(), - chain, - account: { - implementation: Implementation.Hybrid, - deployParams: [owner.address, [], [], []], - isAccountDeployed: false, - signatory: owner, - deploySalt: "0x1", - }, + const deploySalt = "0x"; + + const smartaccount = await toMetaMaskSmartAccount({ + client: publicClient, + implementation: Implementation.Hybrid, + deployParams: [owner.address, [], [], []], + deploySalt, + signatory: { account: owner }, }); - setDelegator(delegatorClient); + setDelegatorSmartAccount(smartaccount); } async function handleDeployDelegator() { setIsDeploying(true); - if (!delegator) { + if (!delegatorSmartAccount) { return; } - const bundler = createBundlerClient(BUNDLER_URL); - const action = createAction("0x0000000000000000000000000000000000000000"); - const unsponsoredUserOp = await delegator.createExecuteUserOp( - action, - await gasFeeResolver.determineGasFee(chain) - ); - - const sponsorship = await paymaster.getUserOperationSponsorship( - delegator.account.environment.EntryPoint, - chain, - unsponsoredUserOp - ); - - const unsignedUserOp = { - ...unsponsoredUserOp, - ...sponsorship, - }; - - const userOp = await delegator.signUserOp(unsignedUserOp); - - const { result: hash } = await bundler.sendUserOp( - userOp, - delegator.account.environment.EntryPoint - ); - - const { result } = await bundler.pollForReceipt(hash); + // we use a bespoke pimlico client to get the gas price specified by the bundler, + // as there is no standard way to do this + const { fast: fees } = await pimlicoClient.getUserOperationGasPrice(); + + const userOpHash = await bundlerClient.sendUserOperation({ + account: delegatorSmartAccount, + calls: [ + { + to: zeroAddress, + }, + ], + ...fees, + }); - if (!result.success) { - throw new Error(`UserOperation failed: ${result.reason}`); - } + const receipt = await bundlerClient.waitForUserOperationReceipt({ + hash: userOpHash, + }); setIsDeploying(false); - setUserOperationReceipt(result); + setUserOperationReceipt(receipt); } return ( @@ -127,20 +131,24 @@ function App() {

- {delegator ? ( + {delegatorSmartAccount ? ( - {userOperationReceipt && 🐊} - {delegator.account.address} - {userOperationReceipt && 🐊} + {userOperationReceipt && ( + 🐊 + )} + {delegatorSmartAccount.address} + {userOperationReceipt && ( + 🐊 + )} ) : ( "NA" @@ -153,7 +161,7 @@ function App() { )}

- {delegator && !userOperationReceipt && ( + {delegatorSmartAccount && !userOperationReceipt && (

Nice! You've just created a counterfactual (meaning it's not yet @@ -163,7 +171,7 @@ function App() { @@ -173,10 +181,7 @@ function App() {

Done!{" "} diff --git a/src/app/utils/index.tsx b/src/app/utils/index.tsx new file mode 100644 index 0000000..23e0ba9 --- /dev/null +++ b/src/app/utils/index.tsx @@ -0,0 +1,11 @@ +export const formatJSON = (value: any) => { + if (value === null || value === undefined) { + return "NA"; + } + + return JSON.stringify( + value, + (_, v) => (typeof v === "bigint" ? `${v.toString()}n` : v), + 2 + ); +}; diff --git a/yarn.lock b/yarn.lock index 24ea2f0..0c86ee3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -28,41 +28,42 @@ __metadata: languageName: node linkType: hard -"@codefi/delegation-abis@npm:^0.1.1": - version: 0.1.1 - resolution: "@codefi/delegation-abis@npm:0.1.1" - checksum: 2256aa6ef6fcea8f5ab8d279150050002a0e7d9338528e562e1f314b9bbb448065b46acf062fa627d672de3984d05790ae1e1ebc6cbc3b25388d12af59d58fec +"@codefi/delegation-abis@npm:^0.4.0": + version: 0.4.0 + resolution: "@codefi/delegation-abis@npm:0.4.0" + checksum: d31fe6f83db59e5089e048c982f7f88d59db36abee349f4a7992ae2263bb38aa540d29f0883915650fa2a8f2279f95fd42a7b876f678dca6186ec9aff7cb7f55 languageName: node linkType: hard -"@codefi/delegation-deployments@npm:^0.1.1": - version: 0.1.1 - resolution: "@codefi/delegation-deployments@npm:0.1.1" - checksum: 90c305848cfca42eb53dca816d8226f32dd4c4e852a8c09d767fe21c203a66701b19043baa900e12b7327e5c50830fa332bc333ab8ff676152601b4ac18ce304 +"@codefi/delegation-deployments@npm:^0.4.0": + version: 0.4.0 + resolution: "@codefi/delegation-deployments@npm:0.4.0" + checksum: da94bdedd1e9d3bfe37de2d41e038f8cb30605803b8c351ec27d7649e68360e272856dc1560f2e7f55880d67fe135b364326ef81ec5cd14bd359c86f741d191e languageName: node linkType: hard -"@codefi/delegation-utils@npm:^0.1.1": - version: 0.1.1 - resolution: "@codefi/delegation-utils@npm:0.1.1" +"@codefi/delegation-utils@npm:^0.4.0": + version: 0.4.0 + resolution: "@codefi/delegation-utils@npm:0.4.0" dependencies: - "@codefi/delegation-abis": ^0.1.1 - "@codefi/delegation-deployments": ^0.1.1 - "@peculiar/asn1-ecc": ^2.3.8 - "@peculiar/asn1-schema": ^2.3.8 + "@codefi/delegation-abis": ^0.4.0 + "@codefi/delegation-deployments": ^0.4.0 buffer: ^6.0.3 - viem: ^2.18.2 - checksum: b77b69965dabcba3080b7ed418343744ab0494c7eea3fd7caba8ce0a0842e8e8ed2a928fe9fa0ae891ad464595044b117bb4584861e8037fa957b886c31028eb + peerDependencies: + viem: ">=2.18.2 <3.0.0" + checksum: beec8111c44af2c0b7e9922debf890c79658e40e08799db843b20b49fc34ecef9a37ba820721d029cb9626c80b26f45dd4f0cbf776059092829e7540f9181d21 languageName: node linkType: hard -"@codefi/delegator-core-viem@npm:0.1.1": - version: 0.1.1 - resolution: "@codefi/delegator-core-viem@npm:0.1.1" +"@codefi/delegator-core-viem@npm:0.4.0": + version: 0.4.0 + resolution: "@codefi/delegator-core-viem@npm:0.4.0" dependencies: - "@codefi/delegation-utils": ^0.1.1 - viem: ^2.18.2 - checksum: 42afd05e3c455e58e3dee89721ac600cc90952ff7960e3d5ef34d81d1807ad312aee419f134fc19867edab6f0293d0aa6d9b89b111912c22b99ba92ceb3aeed1 + "@codefi/delegation-utils": ^0.4.0 + webauthn-p256: ^0.0.5 + peerDependencies: + viem: ">=2.18.2 <3.0.0" + checksum: 13e76a12f5db5c0e5f56d0716a9a82cf7ac83b828559fd52a2355e248fde706db6b81783c2d626d92e96b4f5f9737d5627051080c25f44d8dad3b7e0ec67a366 languageName: node linkType: hard @@ -430,72 +431,72 @@ __metadata: languageName: node linkType: hard -"@next/env@npm:13.5.3": - version: 13.5.3 - resolution: "@next/env@npm:13.5.3" - checksum: ebea3bfca114ca66616557a534fbb37d580f1ab91143eb46ba3bdb5803864dc0e72c08814110809f207d625846f0053871adb75b51b68686ec3a9ed76d9d26bf +"@next/env@npm:14.2.10": + version: 14.2.10 + resolution: "@next/env@npm:14.2.10" + checksum: edff4b124b11f9fcea4df239b6feb11c16ef49c97d018e098a2fcfc16f4aba27092569fb7bdec148d8b1113ac9b2d2a6b460940287ef5636ad801ac779ffc08c languageName: node linkType: hard -"@next/swc-darwin-arm64@npm:13.5.3": - version: 13.5.3 - resolution: "@next/swc-darwin-arm64@npm:13.5.3" +"@next/swc-darwin-arm64@npm:14.2.10": + version: 14.2.10 + resolution: "@next/swc-darwin-arm64@npm:14.2.10" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@next/swc-darwin-x64@npm:13.5.3": - version: 13.5.3 - resolution: "@next/swc-darwin-x64@npm:13.5.3" +"@next/swc-darwin-x64@npm:14.2.10": + version: 14.2.10 + resolution: "@next/swc-darwin-x64@npm:14.2.10" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@next/swc-linux-arm64-gnu@npm:13.5.3": - version: 13.5.3 - resolution: "@next/swc-linux-arm64-gnu@npm:13.5.3" +"@next/swc-linux-arm64-gnu@npm:14.2.10": + version: 14.2.10 + resolution: "@next/swc-linux-arm64-gnu@npm:14.2.10" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-arm64-musl@npm:13.5.3": - version: 13.5.3 - resolution: "@next/swc-linux-arm64-musl@npm:13.5.3" +"@next/swc-linux-arm64-musl@npm:14.2.10": + version: 14.2.10 + resolution: "@next/swc-linux-arm64-musl@npm:14.2.10" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@next/swc-linux-x64-gnu@npm:13.5.3": - version: 13.5.3 - resolution: "@next/swc-linux-x64-gnu@npm:13.5.3" +"@next/swc-linux-x64-gnu@npm:14.2.10": + version: 14.2.10 + resolution: "@next/swc-linux-x64-gnu@npm:14.2.10" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-x64-musl@npm:13.5.3": - version: 13.5.3 - resolution: "@next/swc-linux-x64-musl@npm:13.5.3" +"@next/swc-linux-x64-musl@npm:14.2.10": + version: 14.2.10 + resolution: "@next/swc-linux-x64-musl@npm:14.2.10" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@next/swc-win32-arm64-msvc@npm:13.5.3": - version: 13.5.3 - resolution: "@next/swc-win32-arm64-msvc@npm:13.5.3" +"@next/swc-win32-arm64-msvc@npm:14.2.10": + version: 14.2.10 + resolution: "@next/swc-win32-arm64-msvc@npm:14.2.10" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@next/swc-win32-ia32-msvc@npm:13.5.3": - version: 13.5.3 - resolution: "@next/swc-win32-ia32-msvc@npm:13.5.3" +"@next/swc-win32-ia32-msvc@npm:14.2.10": + version: 14.2.10 + resolution: "@next/swc-win32-ia32-msvc@npm:14.2.10" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@next/swc-win32-x64-msvc@npm:13.5.3": - version: 13.5.3 - resolution: "@next/swc-win32-x64-msvc@npm:13.5.3" +"@next/swc-win32-x64-msvc@npm:14.2.10": + version: 14.2.10 + resolution: "@next/swc-win32-x64-msvc@npm:14.2.10" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -583,42 +584,6 @@ __metadata: languageName: node linkType: hard -"@peculiar/asn1-ecc@npm:^2.3.8": - version: 2.3.13 - resolution: "@peculiar/asn1-ecc@npm:2.3.13" - dependencies: - "@peculiar/asn1-schema": ^2.3.13 - "@peculiar/asn1-x509": ^2.3.13 - asn1js: ^3.0.5 - tslib: ^2.6.2 - checksum: 0573e8e2d94675643aef00756db225eb9733187c509e3319192c0941e887b4372fa77e1ff4b7ba65a61a0c2463661c911ece610b58b348c0ec006d9d21649b6a - languageName: node - linkType: hard - -"@peculiar/asn1-schema@npm:^2.3.13, @peculiar/asn1-schema@npm:^2.3.8": - version: 2.3.13 - resolution: "@peculiar/asn1-schema@npm:2.3.13" - dependencies: - asn1js: ^3.0.5 - pvtsutils: ^1.3.5 - tslib: ^2.6.2 - checksum: 245cf398992788fc61c48a4e1263a47803bccd91807e7a419e3fe9ad44ede5e396a5f8d13215b0765774855b634fe10d730b08944e5dc085fc5ee121a7e0139e - languageName: node - linkType: hard - -"@peculiar/asn1-x509@npm:^2.3.13": - version: 2.3.13 - resolution: "@peculiar/asn1-x509@npm:2.3.13" - dependencies: - "@peculiar/asn1-schema": ^2.3.13 - asn1js: ^3.0.5 - ipaddr.js: ^2.1.0 - pvtsutils: ^1.3.5 - tslib: ^2.6.2 - checksum: b8094400138d6e982248d038443520eae00f349d519bbd763b7652dac1b5635bb7c8d952b3a5d060316c8267f09b98676c3e113023215c72f22eb420f6440b13 - languageName: node - linkType: hard - "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -661,12 +626,20 @@ __metadata: languageName: node linkType: hard -"@swc/helpers@npm:0.5.2": - version: 0.5.2 - resolution: "@swc/helpers@npm:0.5.2" +"@swc/counter@npm:^0.1.3": + version: 0.1.3 + resolution: "@swc/counter@npm:0.1.3" + checksum: df8f9cfba9904d3d60f511664c70d23bb323b3a0803ec9890f60133954173047ba9bdeabce28cd70ba89ccd3fd6c71c7b0bd58be85f611e1ffbe5d5c18616598 + languageName: node + linkType: hard + +"@swc/helpers@npm:0.5.5": + version: 0.5.5 + resolution: "@swc/helpers@npm:0.5.5" dependencies: + "@swc/counter": ^0.1.3 tslib: ^2.4.0 - checksum: 51d7e3d8bd56818c49d6bfbd715f0dbeedc13cf723af41166e45c03e37f109336bbcb57a1f2020f4015957721aeb21e1a7fff281233d797ff7d3dd1f447fa258 + checksum: d4f207b191e54b29460804ddf2984ba6ece1d679a0b2f6a9c765dcf27bba92c5769e7965668a4546fb9f1021eaf0ff9be4bf5c235ce12adcd65acdfe77187d11 languageName: node linkType: hard @@ -1187,17 +1160,6 @@ __metadata: languageName: node linkType: hard -"asn1js@npm:^3.0.5": - version: 3.0.5 - resolution: "asn1js@npm:3.0.5" - dependencies: - pvtsutils: ^1.3.2 - pvutils: ^1.1.3 - tslib: ^2.4.0 - checksum: 3b6af1bbadd5762ef8ead5daf2f6bda1bc9e23bc825c4dcc996aa1f9521ad7390a64028565d95d98090d69c8431f004c71cccb866004759169d7c203cf9075eb - languageName: node - linkType: hard - "assert@npm:^2.1.0": version: 2.1.0 resolution: "assert@npm:2.1.0" @@ -1447,10 +1409,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001406": - version: 1.0.30001651 - resolution: "caniuse-lite@npm:1.0.30001651" - checksum: c31a5a01288e70cdbbfb5cd94af3df02f295791673173b8ce6d6a16db4394a6999197d44190be5a6ff06b8c2c7d2047e94dfd5e5eb4c103ab000fca2d370afc7 +"caniuse-lite@npm:^1.0.30001579": + version: 1.0.30001657 + resolution: "caniuse-lite@npm:1.0.30001657" + checksum: daadbe1d4f5f7c58fe2bc7ec1e5f031f09affd87d2d00dacb1811d2c0aee28da259522f7f0350c0bb342d7541d54f76308a5a8bfe753414667ab57bbc74ebf8d languageName: node linkType: hard @@ -2159,13 +2121,6 @@ __metadata: languageName: node linkType: hard -"glob-to-regexp@npm:^0.4.1": - version: 0.4.1 - resolution: "glob-to-regexp@npm:0.4.1" - checksum: e795f4e8f06d2a15e86f76e4d92751cf8bbfcf0157cea5c2f0f35678a8195a750b34096b1256e436f0cebc1883b5ff0888c47348443e69546a5a87f9e1eb1167 - languageName: node - linkType: hard - "glob@npm:^10.2.2, glob@npm:^10.3.10": version: 10.4.5 resolution: "glob@npm:10.4.5" @@ -2191,7 +2146,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6": +"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.6": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 @@ -2253,7 +2208,7 @@ __metadata: version: 0.0.0-use.local resolution: "hello-gator@workspace:." dependencies: - "@codefi/delegator-core-viem": 0.1.1 + "@codefi/delegator-core-viem": 0.4.0 "@types/node": ^20.7.2 "@types/react": ^18.2.22 "@types/react-dom": ^18.2.7 @@ -2265,7 +2220,8 @@ __metadata: bufferutil: ^4.0.7 encoding: ^0.1.13 lokijs: ^1.5.12 - next: 13.5.3 + next: 14.2.10 + permissionless: ^0.2.10 pino-pretty: ^10.2.0 postcss: ^8.4.45 react: ^18.2.0 @@ -2395,13 +2351,6 @@ __metadata: languageName: node linkType: hard -"ipaddr.js@npm:^2.1.0": - version: 2.2.0 - resolution: "ipaddr.js@npm:2.2.0" - checksum: 770ba8451fd9bf78015e8edac0d5abd7a708cbf75f9429ca9147a9d2f3a2d60767cd5de2aab2b1e13ca6e4445bdeff42bf12ef6f151c07a5c6cf8a44328e2859 - languageName: node - linkType: hard - "is-arguments@npm:^1.0.4": version: 1.1.1 resolution: "is-arguments@npm:1.1.1" @@ -2962,7 +2911,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.4, nanoid@npm:^3.3.7": +"nanoid@npm:^3.3.6, nanoid@npm:^3.3.7": version: 3.3.7 resolution: "nanoid@npm:3.3.7" bin: @@ -2978,29 +2927,29 @@ __metadata: languageName: node linkType: hard -"next@npm:13.5.3": - version: 13.5.3 - resolution: "next@npm:13.5.3" +"next@npm:14.2.10": + version: 14.2.10 + resolution: "next@npm:14.2.10" dependencies: - "@next/env": 13.5.3 - "@next/swc-darwin-arm64": 13.5.3 - "@next/swc-darwin-x64": 13.5.3 - "@next/swc-linux-arm64-gnu": 13.5.3 - "@next/swc-linux-arm64-musl": 13.5.3 - "@next/swc-linux-x64-gnu": 13.5.3 - "@next/swc-linux-x64-musl": 13.5.3 - "@next/swc-win32-arm64-msvc": 13.5.3 - "@next/swc-win32-ia32-msvc": 13.5.3 - "@next/swc-win32-x64-msvc": 13.5.3 - "@swc/helpers": 0.5.2 + "@next/env": 14.2.10 + "@next/swc-darwin-arm64": 14.2.10 + "@next/swc-darwin-x64": 14.2.10 + "@next/swc-linux-arm64-gnu": 14.2.10 + "@next/swc-linux-arm64-musl": 14.2.10 + "@next/swc-linux-x64-gnu": 14.2.10 + "@next/swc-linux-x64-musl": 14.2.10 + "@next/swc-win32-arm64-msvc": 14.2.10 + "@next/swc-win32-ia32-msvc": 14.2.10 + "@next/swc-win32-x64-msvc": 14.2.10 + "@swc/helpers": 0.5.5 busboy: 1.6.0 - caniuse-lite: ^1.0.30001406 - postcss: 8.4.14 + caniuse-lite: ^1.0.30001579 + graceful-fs: ^4.2.11 + postcss: 8.4.31 styled-jsx: 5.1.1 - watchpack: 2.4.0 - zod: 3.21.4 peerDependencies: "@opentelemetry/api": ^1.1.0 + "@playwright/test": ^1.41.2 react: ^18.2.0 react-dom: ^18.2.0 sass: ^1.3.0 @@ -3026,11 +2975,13 @@ __metadata: peerDependenciesMeta: "@opentelemetry/api": optional: true + "@playwright/test": + optional: true sass: optional: true bin: next: dist/bin/next - checksum: bdf97002aee33e03859bc00c6b4115956c449e33ad5a8060ff6a6bcd1f32405fc3f0d0464c293ac94a45753f3d6da513af2cb7fe730e37163f7b0dda0567ac12 + checksum: 2d69507cccddc0297ff2e6727d7c0e96653a049c4a0236f6c0cae3e1eb622dabcb576b4f3976046526f31b8252f665f5b98cbb0f66d6e756f4d22b0ccfbd290d languageName: node linkType: hard @@ -3286,6 +3237,15 @@ __metadata: languageName: node linkType: hard +"permissionless@npm:^0.2.10": + version: 0.2.11 + resolution: "permissionless@npm:0.2.11" + peerDependencies: + viem: ^2.21.22 + checksum: 9ca604387f6285684a83bdfdd22b75d8d04778485ab1fc2beba13fc6c702eaa45598e132bbc210a9464390880322e18946a1ddaf2517303a60ea66032ecc1019 + languageName: node + linkType: hard + "picocolors@npm:^1.0.0": version: 1.0.1 resolution: "picocolors@npm:1.0.1" @@ -3446,14 +3406,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:8.4.14": - version: 8.4.14 - resolution: "postcss@npm:8.4.14" +"postcss@npm:8.4.31": + version: 8.4.31 + resolution: "postcss@npm:8.4.31" dependencies: - nanoid: ^3.3.4 + nanoid: ^3.3.6 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: fe58766ff32e4becf65a7d57678995cfd239df6deed2fe0557f038b47c94e4132e7e5f68b5aa820c13adfec32e523b693efaeb65798efb995ce49ccd83953816 + checksum: 1d8611341b073143ad90486fcdfeab49edd243377b1f51834dc4f6d028e82ce5190e4f11bb2633276864503654fb7cab28e67abdc0fbf9d1f88cad4a0ff0beea languageName: node linkType: hard @@ -3511,22 +3471,6 @@ __metadata: languageName: node linkType: hard -"pvtsutils@npm:^1.3.2, pvtsutils@npm:^1.3.5": - version: 1.3.5 - resolution: "pvtsutils@npm:1.3.5" - dependencies: - tslib: ^2.6.1 - checksum: e734516b3cb26086c18bd9c012fefe818928a5073178842ab7e62885a090f1dd7bda9c7bb8cd317167502cb8ec86c0b1b0ccd71dac7ab469382a4518157b0d12 - languageName: node - linkType: hard - -"pvutils@npm:^1.1.3": - version: 1.1.3 - resolution: "pvutils@npm:1.1.3" - checksum: 2ee26a9e5176c348977d6ec00d8ee80bff62f51743b1c5fe8abeeb4c5d29d9959cdfe0ce146707a9e6801bce88190fed3002d720b072dc87d031c692820b44c9 - languageName: node - linkType: hard - "qrcode-generator@npm:^1.4.4": version: 1.4.4 resolution: "qrcode-generator@npm:1.4.4" @@ -4104,7 +4048,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.4.0, tslib@npm:^2.6.1, tslib@npm:^2.6.2": +"tslib@npm:^2.4.0": version: 2.6.3 resolution: "tslib@npm:2.6.3" checksum: 74fce0e100f1ebd95b8995fbbd0e6c91bdd8f4c35c00d4da62e285a3363aaa534de40a80db30ecfd388ed7c313c42d930ee0eaf108e8114214b180eec3dbe6f5 @@ -4230,7 +4174,7 @@ __metadata: languageName: node linkType: hard -"viem@npm:2.x, viem@npm:^2.18.2, viem@npm:latest": +"viem@npm:2.x, viem@npm:latest": version: 2.19.8 resolution: "viem@npm:2.19.8" dependencies: @@ -4259,16 +4203,6 @@ __metadata: languageName: node linkType: hard -"watchpack@npm:2.4.0": - version: 2.4.0 - resolution: "watchpack@npm:2.4.0" - dependencies: - glob-to-regexp: ^0.4.1 - graceful-fs: ^4.1.2 - checksum: 23d4bc58634dbe13b86093e01c6a68d8096028b664ab7139d58f0c37d962d549a940e98f2f201cecdabd6f9c340338dc73ef8bf094a2249ef582f35183d1a131 - languageName: node - linkType: hard - "wcwidth@npm:^1.0.1": version: 1.0.1 resolution: "wcwidth@npm:1.0.1" @@ -4278,7 +4212,7 @@ __metadata: languageName: node linkType: hard -"webauthn-p256@npm:0.0.5": +"webauthn-p256@npm:0.0.5, webauthn-p256@npm:^0.0.5": version: 0.0.5 resolution: "webauthn-p256@npm:0.0.5" dependencies: @@ -4397,13 +4331,6 @@ __metadata: languageName: node linkType: hard -"zod@npm:3.21.4": - version: 3.21.4 - resolution: "zod@npm:3.21.4" - checksum: f185ba87342ff16f7a06686767c2b2a7af41110c7edf7c1974095d8db7a73792696bcb4a00853de0d2edeb34a5b2ea6a55871bc864227dace682a0a28de33e1f - languageName: node - linkType: hard - "zod@npm:^3.22.2": version: 3.23.8 resolution: "zod@npm:3.23.8"