|
| 1 | +--- |
| 2 | +description: Follow this tutorial to use a passkey as a backup signer with a Hybrid MetaMask smart account. |
| 3 | +sidebar_position: 1 |
| 4 | +--- |
| 5 | + |
| 6 | +# Use a passkey as a backup signer |
| 7 | + |
| 8 | +This tutorial walks you through using a passkey as a backup signer for your [MetaMask smart account](../concepts/smart-accounts). |
| 9 | + |
| 10 | +## About passkeys |
| 11 | + |
| 12 | +An externally owned account (EOA) uses the secp256k1 elliptic curve to generate key pairs and signatures. |
| 13 | +In contrast, a passkey (WebAuthn credential) uses the secp256r1 (P-256) elliptic curve to generate key pairs and signatures. |
| 14 | +Passkeys eliminate the need for traditional seed phrases that are difficult to remember, enabling a more seamless and secure way for users to access their web3 wallets. |
| 15 | + |
| 16 | +MetaMask Smart Accounts offer a [Hybrid implementation](../concepts/smart-accounts.md#hybrid-smart-account), which supports signature validation for both secp256k1 and secp256r1 curves. |
| 17 | +This allows you to add a passkey as a backup signer for your smart account. |
| 18 | + |
| 19 | +You can add passkeys during smart account creation or after the account has been deployed. |
| 20 | +This tutorial walks you through adding a passkey signer to an already deployed smart account. |
| 21 | + |
| 22 | +## Prerequisites |
| 23 | + |
| 24 | +- [Install and set up the Delegation Toolkit](../get-started/install) in your project. |
| 25 | +- [Install Ox SDK](https://oxlib.sh/#installation). |
| 26 | +- [Configure the Delegation Toolkit](../guides/configure). |
| 27 | +- [Create and deploy a Hybrid smart account,](../guides/smart-accounts/create-smart-account) with a signatory from a private key. |
| 28 | + |
| 29 | +## Steps |
| 30 | + |
| 31 | +### 1. Create a Public Client |
| 32 | + |
| 33 | +Create a [Viem Public Client](https://viem.sh/docs/clients/public) using Viem's `createPublicClient` function. |
| 34 | +You will configure a smart account and Bundler Client with the Public Client, which you can use to query the signer's account state and interact with the blockchain network. |
| 35 | + |
| 36 | +```typescript |
| 37 | +import { createPublicClient, http } from "viem"; |
| 38 | +import { sepolia as chain } from "viem/chains"; |
| 39 | + |
| 40 | +const publicClient = createPublicClient({ |
| 41 | + chain, |
| 42 | + transport: http(), |
| 43 | +}); |
| 44 | +``` |
| 45 | + |
| 46 | +### 2. Create a Bundler Client |
| 47 | + |
| 48 | +Create a [Viem Bundler Client](https://viem.sh/account-abstraction/clients/bundler) using Viem's `createBundlerClient` function. |
| 49 | +You can use the bundler service to estimate gas for user operations and submit transactions to the network. |
| 50 | + |
| 51 | +```typescript |
| 52 | +import { createBundlerClient } from "viem/account-abstraction"; |
| 53 | + |
| 54 | +const bundlerClient = createBundlerClient({ |
| 55 | + client: publicClient, |
| 56 | + transport: http("https://your-bundler-rpc.com"), |
| 57 | +}); |
| 58 | +``` |
| 59 | + |
| 60 | +### 3. Create a Hybrid smart account |
| 61 | + |
| 62 | +Configure the same [Hybrid smart account](../guides/smart-accounts/create-smart-account.md#create-a-hybrid-smart-account) that you created and deployed as a [prerequisite](#prerequisites). |
| 63 | +The Hybrid implementation supports adding additional passkey signers. |
| 64 | + |
| 65 | +```typescript |
| 66 | +import { Implementation, toMetaMaskSmartAccount } from "@metamask/delegation-toolkit"; |
| 67 | +import { privateKeyToAccount } from "viem/accounts"; |
| 68 | + |
| 69 | +const account = privateKeyToAccount("0x..."); |
| 70 | + |
| 71 | +const smartAccount = await toMetaMaskSmartAccount({ |
| 72 | + client: publicClient, |
| 73 | + implementation: Implementation.Hybrid, |
| 74 | + deployParams: [account.address, [], [], []], |
| 75 | + deploySalt: "0x", |
| 76 | + signatory: { account }, |
| 77 | +}); |
| 78 | +``` |
| 79 | + |
| 80 | +### 4. Create a passkey |
| 81 | + |
| 82 | +To add a passkey signer, use Viem's [`createWebAuthnCredential`](https://viem.sh/account-abstraction/accounts/webauthn/createWebAuthnCredential) function to securely register the passkey (WebAuthn credential). |
| 83 | + |
| 84 | +```ts |
| 85 | +import { |
| 86 | + createWebAuthnCredential, |
| 87 | +} from "viem/account-abstraction"; |
| 88 | + |
| 89 | +const credential = await createWebAuthnCredential({ |
| 90 | + name: "MetaMask Smart Account", |
| 91 | +}); |
| 92 | +``` |
| 93 | + |
| 94 | +### 5. Add the passkey as a backup signer |
| 95 | + |
| 96 | +Use the `HybridDeleGator` contract namespace from the Delegation Toolkit to encode the calldata required to add the passkey signer. |
| 97 | +The encoding function needs the X and Y coordinates of the P-256 public key. |
| 98 | +Since WebAuthn credentials store a compressed public key, you need to use the [Ox SDK](https://oxlib.sh/#installation) to deserialize it, and extract the X and Y coordinates. |
| 99 | + |
| 100 | +Once the calldata is prepared, send it to your smart account address to register the passkey as a backup signer. |
| 101 | + |
| 102 | +```ts |
| 103 | +import { PublicKey } from "ox"; |
| 104 | +import { HybridDeleGator, P256Owner } from "@metamask/delegation-toolkit/contracts"; |
| 105 | + |
| 106 | +// Deserialize the compressed public key. |
| 107 | +const publicKey = PublicKey.fromHex(credential.publicKey); |
| 108 | + |
| 109 | +const p256Owner: P256Owner = { |
| 110 | + keyId: credential.id, |
| 111 | + x: publicKey.x, |
| 112 | + y: publicKey.y, |
| 113 | +} |
| 114 | + |
| 115 | +const data = HybridDeleGator.encode.addKey({ |
| 116 | + p256Owner, |
| 117 | +}); |
| 118 | + |
| 119 | +// Appropriate fee per gas must be determined for the specific bundler being used. |
| 120 | +const maxFeePerGas = 1n; |
| 121 | +const maxPriorityFeePerGas = 1n; |
| 122 | + |
| 123 | +const userOperationHash = await bundlerClient.sendUserOperation({ |
| 124 | + account: smartAccount, |
| 125 | + calls: [ |
| 126 | + { |
| 127 | + to: smartAccount.address, |
| 128 | + data, |
| 129 | + }, |
| 130 | + ], |
| 131 | + maxFeePerGas, |
| 132 | + maxPriorityFeePerGas, |
| 133 | +}); |
| 134 | +``` |
| 135 | + |
| 136 | +### 6. (Optional) Use the passkey signer |
| 137 | + |
| 138 | +You can now use the passkey signer to access your smart account and sign transactions. |
| 139 | +If you ever lose your primary signer (private key) used in [Step 3](#3-create-a-hybrid-smart-account), you can use the passkey as a secure backup method to retain access to your smart account. |
| 140 | + |
| 141 | +Use the [Viem WebAuthn Account](https://viem.sh/account-abstraction/accounts/webauthn) to configure your passkey as a MetaMask smart account signer. |
| 142 | + |
| 143 | +```ts |
| 144 | +import { Address } from "ox"; |
| 145 | +import { toWebAuthnAccount } from "viem/account-abstraction"; |
| 146 | +import { toHex } from "viem"; |
| 147 | +import { Implementation, toMetaMaskSmartAccount } from "@metamask/delegation-toolkit"; |
| 148 | + |
| 149 | +// Use the deserialized public key from the previous step. |
| 150 | +const owner = Address.fromPublicKey(publicKey); |
| 151 | + |
| 152 | +// Use the credential from the previous step. |
| 153 | +const webAuthnAccount = toWebAuthnAccount({ credential }); |
| 154 | + |
| 155 | +const smartAccount = await toMetaMaskSmartAccount({ |
| 156 | + client: publicClient, |
| 157 | + implementation: Implementation.Hybrid, |
| 158 | + deployParams: [owner, [credential.id], [publicKey.x], [publicKey.y]], |
| 159 | + deploySalt: "0x", |
| 160 | + signatory: { webAuthnAccount, keyId: toHex(credential.id) }, |
| 161 | +}); |
| 162 | +``` |
| 163 | + |
| 164 | +## Next steps |
| 165 | + |
| 166 | +- See [Create a MetaMask smart account](../guides/smart-accounts/create-smart-account.md) to learn more about smart account implementations. |
| 167 | +- See [Send a gasless transaction](../guides/smart-accounts/send-gasless-transaction.md) to learn how to sponsor gas fees when adding a passkey as a backup signer. |
0 commit comments