diff --git a/fern/wallets/pages/transactions/cross-chain-swap-tokens/api.mdx b/fern/wallets/pages/transactions/cross-chain-swap-tokens/api.mdx index 508b3e7b6..65e076543 100644 --- a/fern/wallets/pages/transactions/cross-chain-swap-tokens/api.mdx +++ b/fern/wallets/pages/transactions/cross-chain-swap-tokens/api.mdx @@ -2,40 +2,6 @@ You will need to fill in values wrapped in curly braces like `{SIGNER_ADDRESS}`. - - -```bash -curl -X POST https://api.g.alchemy.com/v2/{API_KEY} \ - -H "Content-Type: application/json" \ - -d '{ - "jsonrpc": "2.0", - "id": 1, - "method": "wallet_requestAccount", - "params": [ - { - "signerAddress": "{SIGNER_ADDRESS}" - } - ] - }' -``` - -This returns: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "accountAddress": "ACCOUNT_ADDRESS", - "id": "ACCOUNT_ID" - } -} -``` - -For other potential responses, [check out the API reference!](/docs/wallets/api-reference/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-request-account) - - - @@ -43,7 +9,7 @@ For other potential responses, [check out the API reference!](/docs/wallets/api- additional actions after a cross-chain swap. -Request a cross-chain swap quote by specifying both the source chain (`chainId`) and destination chain (`toChainId`). In addition, just like in [single-chain swaps](/wallets/transactions/swap-tokens) you can specify either a `minimumToAmount` or a `fromAmount`. +Use your signer address directly as the `from` field to enable [EIP-7702](/wallets/transactions/using-eip-7702) by default. Request a cross-chain swap quote by specifying both the source chain (`chainId`) and destination chain (`toChainId`). In addition, just like in [single-chain swaps](/wallets/transactions/swap-tokens) you can specify either a `minimumToAmount` or a `fromAmount`. If you're using an EOA or just want the raw array of calls returned, pass the @@ -59,7 +25,7 @@ curl -X POST https://api.g.alchemy.com/v2/{API_KEY} \ "method": "wallet_requestQuote_v0", "params": [ { - "from": "{ACCOUNT_ADDRESS_FROM_STEP_1}", + "from": "{SIGNER_ADDRESS}", "chainId": "{SOURCE_CHAIN_ID}", "toChainId": "{DESTINATION_CHAIN_ID}", "fromToken": "{FROM_TOKEN}", @@ -110,6 +76,8 @@ This returns: Note the `callId` in the response! You'll use this to track the cross-chain swap status. Also note the `signatureRequest` - this is what you need to sign, and the returned `data` field is what you'll need to send the transaction. +On the first transaction for a new account, the response type will be `array` containing both an EIP-7702 authorization and a user operation. See [Send Transactions](/wallets/transactions/send-transactions) for handling first-time authorization signing. + @@ -124,7 +92,7 @@ Alternatively, you can sign the raw payload with a simple `eth_sign` but this RP -Pass the `callId` from Step 2 to `sendPreparedCalls`. This makes the response return the same `callId` with additional cross-chain status tracking information: +Pass the `callId` from Step 1 to `sendPreparedCalls`. This makes the response return the same `callId` with additional cross-chain status tracking information: ```bash curl -X POST https://api.g.alchemy.com/v2/{API_KEY} \ @@ -134,13 +102,13 @@ curl -X POST https://api.g.alchemy.com/v2/{API_KEY} \ "method": "wallet_sendPreparedCalls", "params": [ { - "callId": "{CALL_ID_FROM_STEP_2}", + "callId": "{CALL_ID_FROM_STEP_1}", "type": "user-operation-v070", - "data": "{DATA_FROM_STEP_2}", + "data": "{DATA_FROM_STEP_1}", "chainId": "{SOURCE_CHAIN_ID}", "signature": { "type": "secp256k1", - "data": "{SIGNATURE_FROM_STEP_3}" + "data": "{SIGNATURE_FROM_STEP_2}" } } ], @@ -178,7 +146,7 @@ curl -X POST https://api.g.alchemy.com/v2/{API_KEY} \ "method": "wallet_getCallsStatus", "params": [ [ - "{CALL_ID_FROM_STEP_2_OR_STEP_4}" + "{CALL_ID_FROM_STEP_1_OR_STEP_3}" ] ], "id": 1 diff --git a/fern/wallets/pages/transactions/cross-chain-swap-tokens/client.mdx b/fern/wallets/pages/transactions/cross-chain-swap-tokens/client.mdx index 9b64d2af2..a88ff1d83 100644 --- a/fern/wallets/pages/transactions/cross-chain-swap-tokens/client.mdx +++ b/fern/wallets/pages/transactions/cross-chain-swap-tokens/client.mdx @@ -14,9 +14,7 @@ You'll need the following env variables: ```ts title="requestCrossChainQuote.ts" import { swapActions } from "@account-kit/wallet-client/experimental"; - import { client } from "./client"; - - const account = await client.requestAccount(); + import { client, signer } from "./client"; // Add the swap actions to the client const swapClient = client.extend(swapActions); @@ -24,7 +22,7 @@ You'll need the following env variables: // Request the cross-chain swap quote // Note: toChainId specifies the destination chain for the swap const { quote, callId, ...calls } = await swapClient.requestQuoteV0({ - from: account.address, + from: await signer.getAddress(), // Your wallet address toChainId: "0x...", // Destination chain ID fromToken: "0x...", toToken: "0x...", @@ -83,24 +81,17 @@ You'll need the following env variables: import { alchemy, sepolia } from "@account-kit/infra"; import { createSmartWalletClient } from "@account-kit/wallet-client"; - const clientParams = { + export const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY! as Hex, + ) + + export const client = createSmartWalletClient({ transport: alchemy({ apiKey: process.env.ALCHEMY_API_KEY!, }), chain: sepolia, - signer: LocalAccountSigner.privateKeyToAccountSigner( - process.env.PRIVATE_KEY! as Hex, - ), + signer, policyId: process.env.ALCHEMY_POLICY_ID!, // Optional: If you're using a gas manager policy - }; - - const clientWithoutAccount = createSmartWalletClient(clientParams); - - const account = await clientWithoutAccount.requestAccount(); - - export const client = createSmartWalletClient({ - ...clientParams, - account: account.address, }); - ``` +``` diff --git a/fern/wallets/pages/transactions/pay-gas-with-any-token/api-postop.mdx b/fern/wallets/pages/transactions/pay-gas-with-any-token/api-postop.mdx index 01bb440e6..1ff6f2ba1 100644 --- a/fern/wallets/pages/transactions/pay-gas-with-any-token/api-postop.mdx +++ b/fern/wallets/pages/transactions/pay-gas-with-any-token/api-postop.mdx @@ -3,28 +3,8 @@ reference](/wallets/api/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/ for full descriptions of the parameters used in the following example. - - If the user does not yet have a smart account, you must create one. -```bash - ACCOUNT_ADDRESS=$(curl --request POST \ - --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ - --header 'accept: application/json' \ - --data ' -{ - "id": 1, - "jsonrpc": "2.0", - "method": "wallet_requestAccount", - "params": [ - { - "signerAddress": "'$SIGNER_ADDRESS'" - } - ] -} -' | jq -r '.result.accountAddress') -``` - - Prepare calls using the `paymasterService` capability. + Prepare calls using the `paymasterService` capability. Use your signer address directly as the `from` field to enable [EIP-7702](/wallets/transactions/using-eip-7702) by default. ```bash curl --request POST \ --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ @@ -55,7 +35,7 @@ curl --request POST \ "to": "0x0000000000000000000000000000000000000000" } ], - "from": "'$ACCOUNT_ADDRESS'", + "from": "'$SIGNER_ADDRESS'", "chainId": "'$CHAIN_ID'" } ] @@ -63,6 +43,6 @@ curl --request POST \ ``` - Sign the returned signature request and send using `wallet_sendPreparedCalls`. See the [send transactions guide](/wallets/transactions/send-transactions) for more info. + Sign the returned signature request and send using `wallet_sendPreparedCalls`. On the first transaction for a new account, the response type will be `array` containing both an EIP-7702 authorization and a user operation. See the [send transactions guide](/wallets/transactions/send-transactions) for a complete example. diff --git a/fern/wallets/pages/transactions/pay-gas-with-any-token/api-preop.mdx b/fern/wallets/pages/transactions/pay-gas-with-any-token/api-preop.mdx index ee4f7ba69..0d0afe2a8 100644 --- a/fern/wallets/pages/transactions/pay-gas-with-any-token/api-preop.mdx +++ b/fern/wallets/pages/transactions/pay-gas-with-any-token/api-preop.mdx @@ -1,28 +1,6 @@ - - If the user does not yet have a smart account, you must create one. - - ```bash - ACCOUNT_ADDRESS=$(curl --request POST \ - --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ - --header 'accept: application/json' \ - --data ' - { - "id": 1, - "jsonrpc": "2.0", - "method": "wallet_requestAccount", - "params": [ - { - "signerAddress": "'$SIGNER_ADDRESS'" - } - ] - } - ' | jq -r '.result.accountAddress') - ``` - - - Prepare calls using the `paymasterService` capability. + Prepare calls using the `paymasterService` capability. Use your signer address directly as the `from` field to enable [EIP-7702](/wallets/transactions/using-eip-7702) by default. ```bash curl --request POST \ @@ -54,7 +32,7 @@ "to": "0x0000000000000000000000000000000000000000" } ], - "from": "'$ACCOUNT_ADDRESS'", + "from": "'$SIGNER_ADDRESS'", "chainId": "'$CHAIN_ID'" } ] @@ -63,7 +41,7 @@ - If the response to step 2 is a type `paymaster-permit`, then the user must sign the signature request and return via a second call to `wallet_prepareCalls`. Else, skip to step 5. + If the response to step 1 is a type `paymaster-permit`, then the user must sign the signature request and return via a second call to `wallet_prepareCalls`. Else, skip to step 4. The `data` field on the `paymaster-permit` response contains a [Permit typed message](https://eips.ethereum.org/EIPS/eip-2612). It is recommended that the user checks the fields of this message prior to calculating its hash. The `signatureRequest` field on the `paymaster-permit` response is a required signature over the calculated hash. This is typically an ERC-712 typed signature envelope with a field for the hash to sign over. @@ -72,7 +50,7 @@ After signing, another call to `wallet_prepareCalls` is needed to encode the permit into the operation. As a convenience, the `paymaster-permit` response type returns a `modifiedRequest` parameter that modifies the initial request with the permit details. The second request is the `modifiedRequest` with an additional `paymasterPermitSignature` field set to the - signature from step 3. The user can also choose to recreate the request and set the corresponding fields in the `paymasterService` capability to the details returned in the permit signature. + signature from step 2. The user can also choose to recreate the request and set the corresponding fields in the `paymasterService` capability to the details returned in the permit signature. For example: ```json @@ -89,13 +67,13 @@ } } } - ... // same request as step 2 + ... // same request as step 1 "paymasterPermitSignature": "0x..." } ``` - Sign and send the last prepared calls result as usual using `wallet_sendPreparedCalls`. See the [send transactions guide](/wallets/transactions/send-transactions) for more info. + Sign and send the last prepared calls result as usual using `wallet_sendPreparedCalls`. On the first transaction for a new account, the response type will be `array` containing both an EIP-7702 authorization and a user operation. See the [send transactions guide](/wallets/transactions/send-transactions) for a complete example. diff --git a/fern/wallets/pages/transactions/pay-gas-with-any-token/client.mdx b/fern/wallets/pages/transactions/pay-gas-with-any-token/client.mdx index 42101a9de..6ce002f22 100644 --- a/fern/wallets/pages/transactions/pay-gas-with-any-token/client.mdx +++ b/fern/wallets/pages/transactions/pay-gas-with-any-token/client.mdx @@ -50,23 +50,16 @@ export const config = { approveAmount: toHex(10000000n), // 10 USDC }; -const clientParams = { +export const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY! as Hex, +); + +export const client = createSmartWalletClient({ transport: alchemy({ apiKey: process.env.ALCHEMY_API_KEY!, }), chain: sepolia, - signer: LocalAccountSigner.privateKeyToAccountSigner( - process.env.PRIVATE_KEY! as Hex, - ), -}; - -const clientWithoutAccount = createSmartWalletClient(clientParams); - -const account = await clientWithoutAccount.requestAccount(); - -export const client = createSmartWalletClient({ - ...clientParams, - account: account.address, + signer, }); ``` diff --git a/fern/wallets/pages/transactions/retry-transactions/api.mdx b/fern/wallets/pages/transactions/retry-transactions/api.mdx index 6c6d6dd35..843b7f1fa 100644 --- a/fern/wallets/pages/transactions/retry-transactions/api.mdx +++ b/fern/wallets/pages/transactions/retry-transactions/api.mdx @@ -2,42 +2,10 @@ You will need to fill in values wrapped in curly braces like `{SIGNER_ADDRESS}`. - - -```bash -curl -X POST https://api.g.alchemy.com/v2/{API_KEY} \ - -H "Content-Type: application/json" \ - -d '{ - "jsonrpc": "2.0", - "id": 1, - "method": "wallet_requestAccount", - "params": [ - { - "signerAddress": "{SIGNER_ADDRESS}" - } - ] - }' -``` - -This returns: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "accountAddress": "ACCOUNT_ADDRESS", - "id": "ACCOUNT_ID" - } -} -``` - -For other potential responses, [check out the API reference!](https://www.alchemy.com/docs/wallets/api-reference/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-request-account) - - - +Use your signer address directly as the `from` field to enable [EIP-7702](/wallets/transactions/using-eip-7702) by default. + ```bash curl -X POST https://api.g.alchemy.com/v2/{API_KEY} \ -H "Content-Type: application/json" \ @@ -54,7 +22,7 @@ curl -X POST https://api.g.alchemy.com/v2/{API_KEY} \ "data": "{DATA}" } ], - "from": "{ACCOUNT_ADDRESS}", + "from": "{SIGNER_ADDRESS}", "chainId": "{CHAIN_ID}", "capabilities": { "paymasterService": { @@ -87,7 +55,7 @@ This returns: } ``` -Sign the `raw` field and send the transaction as usual. See the [sending transactions documentation](/wallets/transactions/send-transactions) for more details. +Sign the `raw` field and send the transaction as usual. On the first transaction for a new account, the response type will be `array` containing both an EIP-7702 authorization and a user operation. See the [sending transactions documentation](/wallets/transactions/send-transactions) for more details. @@ -150,7 +118,7 @@ curl -X POST https://api.g.alchemy.com/v2/{API_KEY} \ "data": "{SAME_DATA}" } ], - "from": "{ACCOUNT_ADDRESS}", + "from": "{SIGNER_ADDRESS}", "chainId": "{CHAIN_ID}", "capabilities": { "paymasterService": { diff --git a/fern/wallets/pages/transactions/retry-transactions/client.mdx b/fern/wallets/pages/transactions/retry-transactions/client.mdx index c8a1d80b6..8fd263d58 100644 --- a/fern/wallets/pages/transactions/retry-transactions/client.mdx +++ b/fern/wallets/pages/transactions/retry-transactions/client.mdx @@ -72,7 +72,7 @@ You'll need the following env variables: ```ts title="client.ts" import "dotenv/config"; - import { type Address, type Hex, toHex } from "viem"; + import type { Hex } from "viem"; import { LocalAccountSigner } from "@aa-sdk/core"; import { alchemy, sepolia } from "@account-kit/infra"; import { createSmartWalletClient } from "@account-kit/wallet-client"; @@ -81,23 +81,16 @@ You'll need the following env variables: policyId: process.env.ALCHEMY_POLICY_ID!, }; - const clientParams = { + export const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY! as Hex, + ); + + export const client = createSmartWalletClient({ transport: alchemy({ apiKey: process.env.ALCHEMY_API_KEY!, }), chain: sepolia, - signer: LocalAccountSigner.privateKeyToAccountSigner( - process.env.PRIVATE_KEY! as Hex, - ), - }; - - const clientWithoutAccount = createSmartWalletClient(clientParams); - - const account = await clientWithoutAccount.requestAccount(); - - export const client = createSmartWalletClient({ - ...clientParams, - account: account.address, + signer, }); ``` diff --git a/fern/wallets/pages/transactions/send-batch-transactions/api.mdx b/fern/wallets/pages/transactions/send-batch-transactions/api.mdx index ce92c16f0..38afdda2b 100644 --- a/fern/wallets/pages/transactions/send-batch-transactions/api.mdx +++ b/fern/wallets/pages/transactions/send-batch-transactions/api.mdx @@ -8,28 +8,8 @@ reference](/wallets/api/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/ for full descriptions of the parameters used in the following example. - - If the user does not yet have a smart account, you must create one. -```bash twoslash - ACCOUNT_ADDRESS=$(curl --request POST \ - --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ - --header 'accept: application/json' \ - --data ' -{ - "id": 1, - "jsonrpc": "2.0", - "method": "wallet_requestAccount", - "params": [ - { - "signerAddress": "'$SIGNER_ADDRESS'" - } - ] -} -' | jq -r '.result.accountAddress') -``` - - Prepare calls with multiple calls specified in the batch. + Prepare calls with multiple calls specified in the batch. Use your signer address directly as the `from` field to enable [EIP-7702](/wallets/transactions/using-eip-7702) by default. ```bash twoslash curl --request POST \ --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ @@ -44,14 +24,14 @@ curl --request POST \ "calls": [ { "to": "0xCFf7C6dA719408113DFcb5e36182c6d5aa491443", - "data": "'$(cast calldata "approve(address,uint256)" 0xB0AEC4c25E8332256A91bBaf169E3C32dfC3C33C $(cast parse-units 5000 6))'" + "data": "'$(cast calldata "approve(address,uint256)" 0xB0AEC4c25E8332256A91bBaf169E3C32dfC3C33C $(cast parse-units 5000 6))'" }, { "to": "0xB0AEC4c25E8332256A91bBaf169E3C32dfC3C33C", "data": "'$(cast calldata "swapUSDCtoWETH(uint256,uint256)" $(cast parse-units 5000 6) $(cast parse-units 1 18))'" - } + } ], - "from": "'$ACCOUNT_ADDRESS'", + "from": "'$SIGNER_ADDRESS'", "chainId": "'$CHAIN_ID_HEX'" } ] @@ -59,6 +39,6 @@ curl --request POST \ ``` - Sign the returned signature request and send using `wallet_sendPreparedCalls`. + Sign the returned signature request and send using `wallet_sendPreparedCalls`. See [Send Transactions](/wallets/transactions/send-transactions) for a complete example including handling first-time 7702 authorization. diff --git a/fern/wallets/pages/transactions/send-batch-transactions/client.mdx b/fern/wallets/pages/transactions/send-batch-transactions/client.mdx index af49a12c3..56b5a2592 100644 --- a/fern/wallets/pages/transactions/send-batch-transactions/client.mdx +++ b/fern/wallets/pages/transactions/send-batch-transactions/client.mdx @@ -49,23 +49,16 @@ import { LocalAccountSigner } from "@aa-sdk/core"; import { alchemy, sepolia } from "@account-kit/infra"; import { createSmartWalletClient } from "@account-kit/wallet-client"; -const clientParams = { +export const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY! as Hex, +); + +export const client = createSmartWalletClient({ transport: alchemy({ apiKey: process.env.ALCHEMY_API_KEY!, }), chain: sepolia, - signer: LocalAccountSigner.privateKeyToAccountSigner( - process.env.PRIVATE_KEY! as Hex, - ), -}; - -const clientWithoutAccount = createSmartWalletClient(clientParams); - -const account = await clientWithoutAccount.requestAccount(); - -export const client = createSmartWalletClient({ - ...clientParams, - account: account.address, + signer, }); ``` diff --git a/fern/wallets/pages/transactions/send-parallel-transactions/api.mdx b/fern/wallets/pages/transactions/send-parallel-transactions/api.mdx index 749613caa..416475259 100644 --- a/fern/wallets/pages/transactions/send-parallel-transactions/api.mdx +++ b/fern/wallets/pages/transactions/send-parallel-transactions/api.mdx @@ -1,40 +1,8 @@ You will need to fill in values wrapped in curly braces like `{SIGNER_ADDRESS}`. - - ```bash - curl -X POST https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ - -H "Content-Type: application/json" \ - -d '{ - "jsonrpc": "2.0", - "id": 1, - "method": "wallet_requestAccount", - "params": [ - { - "signerAddress": "{SIGNER_ADDRESS}" - } - ] - }' - ``` - - This returns: - - ```json - { - "jsonrpc": "2.0", - "id": 1, - "result": { - "accountAddress": "ACCOUNT_ADDRESS", - "id": "ACCOUNT_ID" - } - } - ``` - - For other potential responses, [check out the API reference!](https://www.alchemy.com/docs/wallets/api-reference/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-request-account) - - - To send additional parallel calls, we have to use the `nonceOverride` capability. This allows us to specify a `nonceKey` parameter, a hex value that fits inside a `uint152` and differentiates transactions. + Use your signer address directly as the `from` field to enable [EIP-7702](/wallets/transactions/using-eip-7702) by default. To send parallel calls, use the `nonceOverride` capability. This allows us to specify a `nonceKey` parameter, a hex value that fits inside a `uint152` and differentiates transactions. In production, as long as the nonce key override is nonzero (zero is the default), and different between `prepareCalls` requests, the transactions will be processed in parallel. @@ -57,7 +25,7 @@ You will need to fill in values wrapped in curly braces like `{SIGNER_ADDRESS}`. "data": "0x" } ], - "from": "{ACCOUNT_ADDRESS}", + "from": "{SIGNER_ADDRESS}", "chainId": "{CHAIN_ID}", "capabilities": { "paymasterService": { @@ -89,7 +57,7 @@ You will need to fill in values wrapped in curly braces like `{SIGNER_ADDRESS}`. "data": "0x" } ], - "from": "{ACCOUNT_ADDRESS}", + "from": "{SIGNER_ADDRESS}", "chainId": "{CHAIN_ID}", "capabilities": { "paymasterService": { @@ -122,6 +90,8 @@ You will need to fill in values wrapped in curly braces like `{SIGNER_ADDRESS}`. ``` Note the two `signatureRequest` objects that were returned for each request! Also keep the returned `data` object from each request, you'll need them when we send the parallel transactions! + + On the first transaction for a new account, the response type will be `array` containing both an EIP-7702 authorization and a user operation. See [Send Transactions](/wallets/transactions/send-transactions) for handling first-time authorization signing. @@ -145,20 +115,20 @@ You will need to fill in values wrapped in curly braces like `{SIGNER_ADDRESS}`. "data": [ { "type": "user-operation-v070", - "data": {DATA_ONE_FROM_STEP_2}, + "data": {DATA_ONE_FROM_STEP_1}, "chainId": "{CHAIN_ID}", "signature": { "type": "secp256k1", - "data": "{SIGNATURE_ONE_FROM_STEP_3}" + "data": "{SIGNATURE_ONE_FROM_STEP_2}" } }, { "type": "user-operation-v070", - "data": {DATA_TWO_FROM_STEP_2}, + "data": {DATA_TWO_FROM_STEP_1}, "chainId": "{CHAIN_ID}", "signature": { "type": "secp256k1", - "data": "{SIGNATURE_TWO_FROM_STEP_3}" + "data": "{SIGNATURE_TWO_FROM_STEP_2}" } } ] @@ -196,7 +166,7 @@ You will need to fill in values wrapped in curly braces like `{SIGNER_ADDRESS}`. "method": "wallet_getCallsStatus", "params": [ [ - "{PREPARED_CALL_ID_ONE_OR_TWO_FROM_STEP_4}", + "{PREPARED_CALL_ID_ONE_OR_TWO_FROM_STEP_3}", ] ], "id": 1 @@ -261,36 +231,7 @@ You will need to fill in values wrapped in curly braces like `{SIGNER_ADDRESS}`. API_URL="https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY" echo "Starting parallel user operations flow..." - - # Step 0: Request account address - echo "Requesting account address for signer: $SIGNER_ADDRESS" - ACCOUNT_RESPONSE=$(curl -s --request POST \ - --url "$API_URL" \ - --header 'accept: application/json' \ - --header 'content-type: application/json' \ - --data '{ - "jsonrpc": "2.0", - "id": 1, - "method": "wallet_requestAccount", - "params": [ - { - "signerAddress": "'"$SIGNER_ADDRESS"'" - } - ] - }') - - # Check for errors in account request - if [[ $(echo "$ACCOUNT_RESPONSE" | jq -r '.error') != "null" ]]; then - echo "❌ Error in wallet_requestAccount: $(echo "$ACCOUNT_RESPONSE" | jq -r '.error.message')" - exit 1 - fi - - # Extract account address - SENDER=$(echo "$ACCOUNT_RESPONSE" | jq -r '.result.accountAddress') - ACCOUNT_ID=$(echo "$ACCOUNT_RESPONSE" | jq -r '.result.id') - - echo "Account Address: $SENDER" - echo "Account ID: $ACCOUNT_ID" + echo "Using signer address: $SIGNER_ADDRESS" # Step 1: Prepare first call (nonce key 0x01) echo "Preparing first call (nonce key 0x01)..." @@ -310,7 +251,7 @@ You will need to fill in values wrapped in curly braces like `{SIGNER_ADDRESS}`. "data": "0x" } ], - "from": "'"$SENDER"'", + "from": "'"$SIGNER_ADDRESS"'", "chainId": "'"$CHAIN_ID"'", "capabilities": { "paymasterService": { @@ -342,7 +283,7 @@ You will need to fill in values wrapped in curly braces like `{SIGNER_ADDRESS}`. "data": "0x" } ], - "from": "'"$SENDER"'", + "from": "'"$SIGNER_ADDRESS"'", "chainId": "'"$CHAIN_ID"'", "capabilities": { "paymasterService": { diff --git a/fern/wallets/pages/transactions/send-parallel-transactions/client.mdx b/fern/wallets/pages/transactions/send-parallel-transactions/client.mdx index fac4de96a..023ec271d 100644 --- a/fern/wallets/pages/transactions/send-parallel-transactions/client.mdx +++ b/fern/wallets/pages/transactions/send-parallel-transactions/client.mdx @@ -68,7 +68,7 @@ You'll need the following env variables: ```ts title="client.ts" import "dotenv/config"; - import { type Address, type Hex, toHex } from "viem"; + import type { Hex } from "viem"; import { LocalAccountSigner } from "@aa-sdk/core"; import { alchemy, sepolia } from "@account-kit/infra"; import { createSmartWalletClient } from "@account-kit/wallet-client"; @@ -77,23 +77,16 @@ You'll need the following env variables: policyId: process.env.ALCHEMY_POLICY_ID!, }; - const clientParams = { + export const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY! as Hex, + ); + + export const client = createSmartWalletClient({ transport: alchemy({ apiKey: process.env.ALCHEMY_API_KEY!, }), chain: sepolia, - signer: LocalAccountSigner.privateKeyToAccountSigner( - process.env.PRIVATE_KEY! as Hex, - ), - }; - - const clientWithoutAccount = createSmartWalletClient(clientParams); - - const account = await clientWithoutAccount.requestAccount(); - - export const client = createSmartWalletClient({ - ...clientParams, - account: account.address, + signer, }); ``` diff --git a/fern/wallets/pages/transactions/send-transactions/api.mdx b/fern/wallets/pages/transactions/send-transactions/api.mdx index a3f374321..616a85e5e 100644 --- a/fern/wallets/pages/transactions/send-transactions/api.mdx +++ b/fern/wallets/pages/transactions/send-transactions/api.mdx @@ -21,33 +21,9 @@ SIGNER_PRIVATE_KEY=your-signer-private-key - - -If the user does not yet have a smart account, you must create one. - -```bash twoslash -ACCOUNT_ADDRESS=$(curl --request POST \ - --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ - --header 'accept: application/json' \ - --data ' -{ - "id": 1, - "jsonrpc": "2.0", - "method": "wallet_requestAccount", - "params": [ - { - "signerAddress": "'$SIGNER_ADDRESS'" - } - ] -} -' | jq -r '.result.accountAddress') -``` - - - -First prepare the calls. +Prepare the calls using your signer address as the `from` field to enable [EIP-7702](/wallets/transactions/using-eip-7702) by default. You can use your signer address directly without first calling `wallet_requestAccount`. ```bash twoslash PREPARE_CALLS_RESPONSE=$(curl --request POST \ @@ -67,7 +43,7 @@ PREPARE_CALLS_RESPONSE=$(curl --request POST \ "value": "0x00" } ], - "from": "'$ACCOUNT_ADDRESS'", + "from": "'$SIGNER_ADDRESS'", "chainId": "'$CHAIN_ID'" } ] @@ -80,15 +56,40 @@ PREPARE_CALLS_RESPONSE=$(curl --request POST \ Sign the returned signature request. How you do this will vary depending on your environment. +On the first transaction for a new account, the response type will be `array` containing both an EIP-7702 authorization and a user operation that need to be signed. On subsequent calls, only the user operation signature is needed. + ```bash twoslash # Extract values from prepare calls response CALL_TYPE=$(echo $PREPARE_CALLS_RESPONSE | jq -r .result.type) CALL_DATA=$(echo $PREPARE_CALLS_RESPONSE | jq -r .result.data) -SIGNATURE_PAYLOAD=$(echo $PREPARE_CALLS_RESPONSE | jq -r .result.signatureRequest.data.raw) -# Sign the payload with your private key -SIGNATURE=$(cast wallet sign --private-key "$SIGNER_PRIVATE_KEY" "$SIGNATURE_PAYLOAD") + +if [ "$CALL_TYPE" = "array" ]; then + # First transaction: sign both authorization and user operation + # Sign the 7702 authorization + AUTH_PAYLOAD=$(echo $PREPARE_CALLS_RESPONSE | jq -r '.result.data[0].signatureRequest.rawPayload') + AUTH_SIGNATURE=$(cast wallet sign --no-hash --private-key "$SIGNER_PRIVATE_KEY" "$AUTH_PAYLOAD") + + # Sign the user operation + UO_PAYLOAD=$(echo $PREPARE_CALLS_RESPONSE | jq -r '.result.data[1].signatureRequest.data.raw') + UO_SIGNATURE=$(cast wallet sign --private-key "$SIGNER_PRIVATE_KEY" "$UO_PAYLOAD") + + # Build the signed array data + SIGNED_DATA=$(echo $PREPARE_CALLS_RESPONSE | jq -c --arg auth_sig "$AUTH_SIGNATURE" --arg uo_sig "$UO_SIGNATURE" ' + .result.data | [ + { type: .[0].type, data: .[0].data, chainId: .[0].chainId, signature: { type: "secp256k1", data: $auth_sig } }, + { type: .[1].type, data: .[1].data, chainId: .[1].chainId, signature: { type: "secp256k1", data: $uo_sig } } + ]') +else + # Subsequent transactions: sign only the user operation + SIGNATURE_PAYLOAD=$(echo $PREPARE_CALLS_RESPONSE | jq -r .result.signatureRequest.data.raw) + SIGNATURE=$(cast wallet sign --private-key "$SIGNER_PRIVATE_KEY" "$SIGNATURE_PAYLOAD") +fi ``` + + Using `cast wallet sign --no-hash` for the authorization payload is acceptable for testing but not recommended for production. See [Using EIP-7702](/wallets/transactions/using-eip-7702) for production signing recommendations. + + @@ -96,28 +97,48 @@ SIGNATURE=$(cast wallet sign --private-key "$SIGNER_PRIVATE_KEY" "$SIGNATURE_PAY Send the signed calls using `wallet_sendPreparedCalls`. ```bash twoslash -SEND_CALLS_RESPONSE=$(echo '{}' | jq -n \ - --arg call_type "$CALL_TYPE" \ - --argjson call_data "$CALL_DATA" \ - --arg chain_id "$CHAIN_ID" \ - --arg signature "$SIGNATURE" \ - '{ - "id": 1, - "jsonrpc": "2.0", - "method": "wallet_sendPreparedCalls", - "params": [{ - "type": $call_type, - "data": $call_data, - "chainId": $chain_id, - "signature": { - "type": "secp256k1", - "data": $signature - } - }] - }' | curl --request POST \ - --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ - --header 'accept: application/json' \ - --data @-) +if [ "$CALL_TYPE" = "array" ]; then + # Send the array of signed calls + SEND_CALLS_RESPONSE=$(echo '{}' | jq -n \ + --argjson signed_data "$SIGNED_DATA" \ + --arg chain_id "$CHAIN_ID" \ + '{ + "id": 1, + "jsonrpc": "2.0", + "method": "wallet_sendPreparedCalls", + "params": [{ + "type": "array", + "data": $signed_data + }] + }' | curl --request POST \ + --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ + --header 'accept: application/json' \ + --data @-) +else + # Send the single user operation + SEND_CALLS_RESPONSE=$(echo '{}' | jq -n \ + --arg call_type "$CALL_TYPE" \ + --argjson call_data "$CALL_DATA" \ + --arg chain_id "$CHAIN_ID" \ + --arg signature "$SIGNATURE" \ + '{ + "id": 1, + "jsonrpc": "2.0", + "method": "wallet_sendPreparedCalls", + "params": [{ + "type": $call_type, + "data": $call_data, + "chainId": $chain_id, + "signature": { + "type": "secp256k1", + "data": $signature + } + }] + }' | curl --request POST \ + --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ + --header 'accept: application/json' \ + --data @-) +fi CALL_ID=$(echo $SEND_CALLS_RESPONSE | jq -r '.result.preparedCallIds[0]') ``` @@ -126,7 +147,7 @@ CALL_ID=$(echo $SEND_CALLS_RESPONSE | jq -r '.result.preparedCallIds[0]') -Finally, use `wallet_getCallsStatus` to check the status of the call. A “pending” state (1xx status codes) is expected for some time before the transition to “confirmed,” so this endpoint should be polled while the status is pending. If the call does not progress, refer to the [retry guide](/wallets/transactions/retry-transactions). The [API documentation](/wallets/api-reference/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-get-calls-status#response.body.status) provides details on each status code. +Finally, use `wallet_getCallsStatus` to check the status of the call. A "pending" state (1xx status codes) is expected for some time before the transition to "confirmed," so this endpoint should be polled while the status is pending. If the call does not progress, refer to the [retry guide](/wallets/transactions/retry-transactions). The [API documentation](/wallets/api-reference/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-get-calls-status#response.body.status) provides details on each status code. ```bash twoslash curl --request POST \ diff --git a/fern/wallets/pages/transactions/send-transactions/client.mdx b/fern/wallets/pages/transactions/send-transactions/client.mdx index 12a9b9590..769fd9f53 100644 --- a/fern/wallets/pages/transactions/send-transactions/client.mdx +++ b/fern/wallets/pages/transactions/send-transactions/client.mdx @@ -28,30 +28,21 @@ console.log(result); ``` ```ts title="client.ts" +import type { Hex } from "viem"; import { LocalAccountSigner } from "@aa-sdk/core"; import { alchemy, sepolia } from "@account-kit/infra"; -import { - createSmartWalletClient, - type SmartWalletClientParams, -} from "@account-kit/wallet-client"; +import { createSmartWalletClient } from "@account-kit/wallet-client"; -const clientParams: SmartWalletClientParams = { +export const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY! as Hex, +); + +export const client = createSmartWalletClient({ transport: alchemy({ - apiKey: "your-alchemy-api-key", + apiKey: process.env.ALCHEMY_API_KEY!, }), chain: sepolia, - signer: LocalAccountSigner.privateKeyToAccountSigner( - "0x-your-wallet-private-key", - ), -}; - -const clientWithoutAccount = createSmartWalletClient(clientParams); - -const account = await clientWithoutAccount.requestAccount(); - -export const client = createSmartWalletClient({ - ...clientParams, - account: account.address, + signer, }); ``` diff --git a/fern/wallets/pages/transactions/send-transactions/encoding-function-data/api.mdx b/fern/wallets/pages/transactions/send-transactions/encoding-function-data/api.mdx index 2c9ba52bb..0c378c357 100644 --- a/fern/wallets/pages/transactions/send-transactions/encoding-function-data/api.mdx +++ b/fern/wallets/pages/transactions/send-transactions/encoding-function-data/api.mdx @@ -14,10 +14,10 @@ curl --request POST \ "calls": [ { "to": "0x0000000000000000000000000000000000000000", - "data": "'$(cast calldata "mintTo(address)" $ACCOUNT_ADDRESS)'" + "data": "'$(cast calldata "mintTo(address)" $SIGNER_ADDRESS)'" } ], - "from": "'$ACCOUNT_ADDRESS'", + "from": "'$SIGNER_ADDRESS'", "chainId": "'$CHAIN_ID'" } ] diff --git a/fern/wallets/pages/transactions/send-transactions/encoding-function-data/client.mdx b/fern/wallets/pages/transactions/send-transactions/encoding-function-data/client.mdx index 2d10496d3..3923cafe1 100644 --- a/fern/wallets/pages/transactions/send-transactions/encoding-function-data/client.mdx +++ b/fern/wallets/pages/transactions/send-transactions/encoding-function-data/client.mdx @@ -34,30 +34,21 @@ export const exampleAbi = [ ``` ```ts title="client.ts" +import type { Hex } from "viem"; import { LocalAccountSigner } from "@aa-sdk/core"; import { alchemy, sepolia } from "@account-kit/infra"; -import { - createSmartWalletClient, - type SmartWalletClientParams, -} from "@account-kit/wallet-client"; +import { createSmartWalletClient } from "@account-kit/wallet-client"; -const clientParams: SmartWalletClientParams = { +export const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY! as Hex, +); + +export const client = createSmartWalletClient({ transport: alchemy({ - apiKey: "your-alchemy-api-key", + apiKey: process.env.ALCHEMY_API_KEY!, }), chain: sepolia, - signer: LocalAccountSigner.privateKeyToAccountSigner( - "0x-your-wallet-private-key", - ), -}; - -const clientWithoutAccount = createSmartWalletClient(clientParams); - -const account = await clientWithoutAccount.requestAccount(); - -export const client = createSmartWalletClient({ - ...clientParams, - account: account.address, + signer, }); ``` diff --git a/fern/wallets/pages/transactions/send-transactions/prepare-calls/client.mdx b/fern/wallets/pages/transactions/send-transactions/prepare-calls/client.mdx index a1f2a3345..2c3eb910e 100644 --- a/fern/wallets/pages/transactions/send-transactions/prepare-calls/client.mdx +++ b/fern/wallets/pages/transactions/send-transactions/prepare-calls/client.mdx @@ -28,30 +28,21 @@ console.log({ sentCalls }); ``` ```ts title="client.ts" +import type { Hex } from "viem"; import { LocalAccountSigner } from "@aa-sdk/core"; import { alchemy, sepolia } from "@account-kit/infra"; -import { - createSmartWalletClient, - type SmartWalletClientParams, -} from "@account-kit/wallet-client"; +import { createSmartWalletClient } from "@account-kit/wallet-client"; -const clientParams: SmartWalletClientParams = { +export const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY! as Hex, +); + +export const client = createSmartWalletClient({ transport: alchemy({ - apiKey: "your-alchemy-api-key", + apiKey: process.env.ALCHEMY_API_KEY!, }), chain: sepolia, - signer: LocalAccountSigner.privateKeyToAccountSigner( - "0x-your-wallet-private-key", - ), -}; - -const clientWithoutAccount = createSmartWalletClient(clientParams); - -const account = await clientWithoutAccount.requestAccount(); - -export const client = createSmartWalletClient({ - ...clientParams, - account: account.address, + signer, }); ``` diff --git a/fern/wallets/pages/transactions/signing/sign-messages/client-raw.mdx b/fern/wallets/pages/transactions/signing/sign-messages/client-raw.mdx index a5cd98af2..15a0dd192 100644 --- a/fern/wallets/pages/transactions/signing/sign-messages/client-raw.mdx +++ b/fern/wallets/pages/transactions/signing/sign-messages/client-raw.mdx @@ -26,23 +26,16 @@ import { LocalAccountSigner } from "@aa-sdk/core"; import { alchemy, sepolia } from "@account-kit/infra"; import { createSmartWalletClient } from "@account-kit/wallet-client"; -const clientParams = { +export const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY! as Hex, +); + +export const client = createSmartWalletClient({ transport: alchemy({ apiKey: process.env.ALCHEMY_API_KEY!, }), chain: sepolia, - signer: LocalAccountSigner.privateKeyToAccountSigner( - process.env.PRIVATE_KEY! as Hex, - ), -}; - -const clientWithoutAccount = createSmartWalletClient(clientParams); - -const account = await clientWithoutAccount.requestAccount(); - -export const client = createSmartWalletClient({ - ...clientParams, - account: account.address, + signer, }); ``` diff --git a/fern/wallets/pages/transactions/signing/sign-messages/client-text.mdx b/fern/wallets/pages/transactions/signing/sign-messages/client-text.mdx index 782330524..182325507 100644 --- a/fern/wallets/pages/transactions/signing/sign-messages/client-text.mdx +++ b/fern/wallets/pages/transactions/signing/sign-messages/client-text.mdx @@ -24,23 +24,16 @@ import { LocalAccountSigner } from "@aa-sdk/core"; import { alchemy, sepolia } from "@account-kit/infra"; import { createSmartWalletClient } from "@account-kit/wallet-client"; -const clientParams = { +export const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY! as Hex, +); + +export const client = createSmartWalletClient({ transport: alchemy({ apiKey: process.env.ALCHEMY_API_KEY!, }), chain: sepolia, - signer: LocalAccountSigner.privateKeyToAccountSigner( - process.env.PRIVATE_KEY! as Hex, - ), -}; - -const clientWithoutAccount = createSmartWalletClient(clientParams); - -const account = await clientWithoutAccount.requestAccount(); - -export const client = createSmartWalletClient({ - ...clientParams, - account: account.address, + signer, }); ``` diff --git a/fern/wallets/pages/transactions/signing/sign-typed-data/client.mdx b/fern/wallets/pages/transactions/signing/sign-typed-data/client.mdx index 23ab5d195..92d183b91 100644 --- a/fern/wallets/pages/transactions/signing/sign-typed-data/client.mdx +++ b/fern/wallets/pages/transactions/signing/sign-typed-data/client.mdx @@ -44,23 +44,16 @@ import { LocalAccountSigner } from "@aa-sdk/core"; import { alchemy, sepolia } from "@account-kit/infra"; import { createSmartWalletClient } from "@account-kit/wallet-client"; -const clientParams = { +export const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY! as Hex, +); + +export const client = createSmartWalletClient({ transport: alchemy({ apiKey: process.env.ALCHEMY_API_KEY!, }), chain: sepolia, - signer: LocalAccountSigner.privateKeyToAccountSigner( - process.env.PRIVATE_KEY! as Hex, - ), -}; - -const clientWithoutAccount = createSmartWalletClient(clientParams); - -const account = await clientWithoutAccount.requestAccount(); - -export const client = createSmartWalletClient({ - ...clientParams, - account: account.address, + signer, }); ``` diff --git a/fern/wallets/pages/transactions/sponsor-gas/api.mdx b/fern/wallets/pages/transactions/sponsor-gas/api.mdx index b49e9037a..639ce75cf 100644 --- a/fern/wallets/pages/transactions/sponsor-gas/api.mdx +++ b/fern/wallets/pages/transactions/sponsor-gas/api.mdx @@ -3,28 +3,8 @@ reference](/wallets/api/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/ for full descriptions of the parameters used in the following example. - - If the user does not yet have a smart account, you must create one. -```bash -ACCOUNT_ADDRESS=$(curl --request POST \ - --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ - --header 'accept: application/json' \ - --data ' -{ - "id": 1, - "jsonrpc": "2.0", - "method": "wallet_requestAccount", - "params": [ - { - "signerAddress": "'$SIGNER_ADDRESS'" - } - ] -} -' | jq -r '.result.accountAddress') -``` - - Prepare calls using the `paymasterService` capability. + Prepare calls using the `paymasterService` capability. Use your signer address directly as the `from` field to enable [EIP-7702](/wallets/transactions/using-eip-7702) by default. ```bash curl --request POST \ --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ @@ -46,7 +26,7 @@ curl --request POST \ "to": "0x0000000000000000000000000000000000000000" } ], - "from": "'$ACCOUNT_ADDRESS'", + "from": "'$SIGNER_ADDRESS'", "chainId": "'$CHAIN_ID_HEX'" } ] @@ -54,6 +34,6 @@ curl --request POST \ ``` - Sign the returned signature request and send using `wallet_sendPreparedCalls`. + Sign the returned signature request and send using `wallet_sendPreparedCalls`. See [Send Transactions](/wallets/transactions/send-transactions) for a complete example including handling first-time 7702 authorization. diff --git a/fern/wallets/pages/transactions/sponsor-gas/client.mdx b/fern/wallets/pages/transactions/sponsor-gas/client.mdx index bb0b98325..85ca2dddf 100644 --- a/fern/wallets/pages/transactions/sponsor-gas/client.mdx +++ b/fern/wallets/pages/transactions/sponsor-gas/client.mdx @@ -44,23 +44,16 @@ export const config = { policyId: process.env.ALCHEMY_POLICY_ID!, }; -const clientParams = { +export const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY! as Hex, +); + +export const client = createSmartWalletClient({ transport: alchemy({ apiKey: process.env.ALCHEMY_API_KEY!, }), chain: sepolia, - signer: LocalAccountSigner.privateKeyToAccountSigner( - process.env.PRIVATE_KEY! as Hex, - ), -}; - -const clientWithoutAccount = createSmartWalletClient(clientParams); - -const account = await clientWithoutAccount.requestAccount(); - -export const client = createSmartWalletClient({ - ...clientParams, - account: account.address, + signer, }); ``` diff --git a/fern/wallets/pages/transactions/swap-tokens/api.mdx b/fern/wallets/pages/transactions/swap-tokens/api.mdx index 37c61a02b..b99f58121 100644 --- a/fern/wallets/pages/transactions/swap-tokens/api.mdx +++ b/fern/wallets/pages/transactions/swap-tokens/api.mdx @@ -2,43 +2,9 @@ You will need to fill in values wrapped in curly braces like `{SIGNER_ADDRESS}`. - - -```bash -curl -X POST https://api.g.alchemy.com/v2/{apiKey} \ - -H "Content-Type: application/json" \ - -d '{ - "jsonrpc": "2.0", - "id": 1, - "method": "wallet_requestAccount", - "params": [ - { - "signerAddress": "{SIGNER_ADDRESS}" - } - ] - }' -``` - -This returns: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "accountAddress": "ACCOUNT_ADDRESS", - "id": "ACCOUNT_ID" - } -} -``` - -For other potential responses, [check out the API reference!](/docs/wallets/api-reference/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-request-account) - - - -Note that `postCalls` are optional and allow you to batch an array of calls after the swap. +Use your signer address directly as the `from` field to enable [EIP-7702](/wallets/transactions/using-eip-7702) by default. Note that `postCalls` are optional and allow you to batch an array of calls after the swap. If you're using an EOA or just want the raw array of calls returned, pass the @@ -55,7 +21,7 @@ curl -X POST https://api.g.alchemy.com/v2/{API_KEY} \ "method": "wallet_requestQuote_v0", "params": [ { - "from": "{ACCOUNT_ADDRESS_FROM_STEP_1}", + "from": "{SIGNER_ADDRESS}", "chainId": "{CHAIN_ID}", "fromToken": "{FROM_TOKEN}", "toToken": "{TO_TOKEN}", @@ -107,15 +73,17 @@ This returns: } ``` -Note the `signatureRequest`! This is what you now have to sign, and the returned `data` field is what you will need to send the transaction! +Note the `signatureRequest`! This is what you now have to sign, and the returned `data` field is what you will need to send the transaction. + +On the first transaction for a new account, the response type will be `array` containing both an EIP-7702 authorization and a user operation. See [Send Transactions](/wallets/transactions/send-transactions) for handling first-time authorization signing. To sign the signature request, you should sign the `raw` field (note, this is not a string! You need to pass it to your signer as raw bytes, generally like so: `{ raw: "0x..." }`) with your signer of choice. - + This should use the `personal_sign` RPC method, as noted by the `type` in the `signatureRequest`. - + Alternatively, you can sign the raw payload with a simple `eth_sign` but this RPC method is not favored due to security concerns. @@ -131,11 +99,11 @@ curl -X POST https://api.g.alchemy.com/v2/{apiKey} \ "params": [ { "type": "user-operation-v070", - "data": "{DATA_FROM_STEP_2}", + "data": "{DATA_FROM_STEP_1}", "chainId": "{CHAIN_ID}", "signature": { "type": "secp256k1", - "data": "{SIGNATURE_FROM_STEP_3}" + "data": "{SIGNATURE_FROM_STEP_2}" } } ], @@ -173,7 +141,7 @@ curl -X POST https://api.g.alchemy.com/v2/{apiKey} \ "method": "wallet_getCallsStatus", "params": [ [ - "{PREPARED_CALL_ID_FROM_STEP_4}" + "{PREPARED_CALL_ID_FROM_STEP_3}" ] ], "id": 1 diff --git a/fern/wallets/pages/transactions/swap-tokens/client.mdx b/fern/wallets/pages/transactions/swap-tokens/client.mdx index a7cf1df2d..eb81a07a8 100644 --- a/fern/wallets/pages/transactions/swap-tokens/client.mdx +++ b/fern/wallets/pages/transactions/swap-tokens/client.mdx @@ -9,16 +9,14 @@ You'll need the following env variables: ```ts title="requestQuote.ts" import { swapActions } from "@account-kit/wallet-client/experimental"; - import { client } from "./client"; - - const account = await client.requestAccount(); + import { client, signer } from "./client"; // Add the swap actions to the client const swapClient = client.extend(swapActions); // Request the swap quote const { quote, ...calls } = await swapClient.requestQuoteV0({ - from: account.address, + from: await signer.getAddress(), // Your wallet address fromToken: "0x...", toToken: "0x...", minimumToAmount: "0x...", @@ -69,24 +67,17 @@ You'll need the following env variables: import { alchemy, sepolia } from "@account-kit/infra"; import { createSmartWalletClient } from "@account-kit/wallet-client"; - const clientParams = { + export const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY! as Hex, + ); + + export const client = createSmartWalletClient({ transport: alchemy({ apiKey: process.env.ALCHEMY_API_KEY!, }), chain: sepolia, - signer: LocalAccountSigner.privateKeyToAccountSigner( - process.env.PRIVATE_KEY! as Hex, - ), + signer, policyId: process.env.ALCHEMY_POLICY_ID!, // Optional: If you're using a gas manager policy - }; - - const clientWithoutAccount = createSmartWalletClient(clientParams); - - const account = await clientWithoutAccount.requestAccount(); - - export const client = createSmartWalletClient({ - ...clientParams, - account: account.address, }); ``` diff --git a/fern/wallets/pages/transactions/using-eip-7702/api.mdx b/fern/wallets/pages/transactions/using-eip-7702/api.mdx index ff6f42aae..cf87bdded 100644 --- a/fern/wallets/pages/transactions/using-eip-7702/api.mdx +++ b/fern/wallets/pages/transactions/using-eip-7702/api.mdx @@ -2,9 +2,11 @@ See the [`wallet_prepareCalls` API reference](/wallets/api-reference/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-prepare-calls) for full descriptions of the parameters used in the following example. +EIP-7702 is now the default mode when using your signer address directly with `wallet_prepareCalls`. The API will automatically return an authorization request when delegation is needed. + - Prepare calls using the `eip7702Auth` capability. + Prepare calls using your signer address directly as the `from` field. ```bash curl --request POST \ --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ @@ -19,8 +21,7 @@ curl --request POST \ "capabilities": { "paymasterService": { "policyId": "'$ALCHEMY_POLICY_ID'" - }, - "eip7702Auth": true + } }, "calls": [ { @@ -35,7 +36,8 @@ curl --request POST \ ``` - Sign the returned signature request and send using `wallet_sendPreparedCalls`. - See "Usage with prepare calls" for details on the authorization signature request. + Sign the returned signature request(s) and send using `wallet_sendPreparedCalls`. + + On the first transaction for a new account, the response type will be `array` containing both an EIP-7702 authorization and a user operation. See [Send Transactions](/wallets/transactions/send-transactions) for a complete example including handling the authorization signature. diff --git a/fern/wallets/pages/transactions/using-eip-7702/client.mdx b/fern/wallets/pages/transactions/using-eip-7702/client.mdx index 3ebaa59e4..8070837ce 100644 --- a/fern/wallets/pages/transactions/using-eip-7702/client.mdx +++ b/fern/wallets/pages/transactions/using-eip-7702/client.mdx @@ -1,7 +1,6 @@ Required SDK version: ^v4.61.0 -Use the `eip7702Auth` capability on the smart wallet client `sendCalls` action. `sendCalls` will automatically -sign any required authorization requests to delegate the EOA to Modular Account v2. +EIP-7702 is now the default mode for Smart Wallets. Simply create a client with your signer and use `sendCalls` - the SDK will automatically handle authorization requests to delegate the EOA to Modular Account v2 when needed. If the signing EOA is delegated to a different smart contract, `sendCalls` @@ -24,7 +23,6 @@ try { paymasterService: { policyId: config.policyId, }, - eip7702Auth: true, }, calls: [ { @@ -52,10 +50,9 @@ export const config = { policyId: process.env.ALCHEMY_POLICY_ID!, }; -const signer = LocalAccountSigner.privateKeyToAccountSigner( +export const signer = LocalAccountSigner.privateKeyToAccountSigner( process.env.PRIVATE_KEY! as Hex, ); -const signerAddress = await signer.getAddress(); export const client = createSmartWalletClient({ transport: alchemy({ @@ -63,8 +60,6 @@ export const client = createSmartWalletClient({ }), chain: sepolia, signer, - // hoist the signer address as the account when using 7702 mode - account: signerAddress, }); ``` diff --git a/fern/wallets/pages/transactions/using-eip-7702/index.mdx b/fern/wallets/pages/transactions/using-eip-7702/index.mdx index cc4dd55c0..c9ec873f1 100644 --- a/fern/wallets/pages/transactions/using-eip-7702/index.mdx +++ b/fern/wallets/pages/transactions/using-eip-7702/index.mdx @@ -1,22 +1,22 @@ --- -title: Using EIP-7702 -description: Upgrade to Smart Wallets with EIP-7702 +title: How EIP-7702 Works +description: Understanding how Smart Wallets use EIP-7702 slug: wallets/transactions/using-eip-7702 --- -Upgrade your user's accounts to Smart Wallets using [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702). -This gives users access to all of the capabilities of Smart Wallets including gas sponsorship, batching, and more. +Alchemy Smart Wallets use [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) by default to give users access to all Smart Wallet capabilities including gas sponsorship, batching, and more - while keeping the same address. ## How it works EIP-7702 enables EOAs (Externally Owned Accounts) to delegate control to Smart Wallets that can execute code directly from their addresses. When using Transaction APIs: -* Transaction APIs detect whether a user must first delegate via EIP-7702 +* You can use your signer address directly as the account address - no need to call `wallet_requestAccount` first +* Transaction APIs automatically detect whether a user must first delegate via EIP-7702 * If delegation is required, Transaction APIs prepare the correct authorization payload * Your application prompts the user to sign when required * We combine the delegation and transaction into a single onchain submission -Once delegated, the user’s account behaves as a Smart Wallet while keeping the same address and assets. +Once delegated, the user's account behaves as a Smart Wallet while keeping the same address and assets. Subsequent transactions only require a single user operation signature. ## Prerequisites @@ -102,13 +102,14 @@ Once delegated, the user’s account behaves as a Smart Wallet while keeping the + EIP-7702 delegation is now the default mode for Alchemy Smart Wallets. When you use your signer address directly with `wallet_prepareCalls` or other Transaction APIs, 7702 mode is automatically enabled. + The `eip7702Auth` capability supports the interface defined in [ERC-7902](https://eips.ethereum.org/EIPS/eip-7902). Currently, Wallet APIs only support delegation to the following contract: `0x69007702764179f14F51cdce752f4f775d74E139` (Modular Account v2) All other delegation addresses will be rejected. - To simplify usage, it is recommended to use `eip7702Auth: true`. Once delegated, an account remains delegated until the delegation is replaced or removed. @@ -121,6 +122,72 @@ Once delegated, the user’s account behaves as a Smart Wallet while keeping the + + If you need to use a traditional Smart Contract Account instead of EIP-7702, you can opt out of the default 7702 behavior by calling `wallet_requestAccount` first. + + When you call `wallet_requestAccount` with a signer address, it creates a dedicated Smart Contract Account address. Using this SCA address in subsequent API calls will bypass 7702 mode. + + **SDK Example:** + ```ts + import { createSmartWalletClient } from "@account-kit/wallet-client"; + import { LocalAccountSigner } from "@aa-sdk/core"; + import { alchemy, sepolia } from "@account-kit/infra"; + + const signer = LocalAccountSigner.privateKeyToAccountSigner( + process.env.PRIVATE_KEY!, + ); + + const client = createSmartWalletClient({ + transport: alchemy({ apiKey: process.env.ALCHEMY_API_KEY! }), + chain: sepolia, + signer, + }); + + // Request a Smart Contract Account + const account = await client.requestAccount(); + + // Use the SCA address as the `from` param to bypass 7702 mode + await client.sendCalls({ + from: account.address, + calls: [...], + }); + ``` + + **API Example:** + ```bash + # First, request a Smart Contract Account + ACCOUNT_ADDRESS=$(curl --request POST \ + --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ + --header 'accept: application/json' \ + --data '{ + "id": 1, + "jsonrpc": "2.0", + "method": "wallet_requestAccount", + "params": [{ "signerAddress": "'$SIGNER_ADDRESS'" }] + }' | jq -r '.result.accountAddress') + + # Use the SCA address (not the signer address) in subsequent calls + curl --request POST \ + --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \ + --header 'accept: application/json' \ + --data '{ + "id": 1, + "jsonrpc": "2.0", + "method": "wallet_prepareCalls", + "params": [{ + "calls": [{ "to": "0x...", "data": "0x" }], + "from": "'$ACCOUNT_ADDRESS'", + "chainId": "'$CHAIN_ID'" + }] + }' + ``` + + **When to use SCA mode:** + * When you need backwards compatibility with existing Smart Contract Accounts + * When working with chains that don't yet support EIP-7702 + * When you have specific requirements for smart contract account architecture + + ## Next steps Build more: