diff --git a/fern/docs.yml b/fern/docs.yml
index 3c568ae52..770b37137 100644
--- a/fern/docs.yml
+++ b/fern/docs.yml
@@ -1004,8 +1004,8 @@ navigation:
path: wallets/pages/transactions/send-batch-transactions/index.mdx
- page: Parallel transactions
path: wallets/pages/transactions/send-parallel-transactions/index.mdx
- - page: EIP-7702 transactions
- path: wallets/pages/transactions/using-eip-7702/index.mdx
+ - page: How EIP-7702 works
+ path: wallets/pages/transactions/using-eip-7702/index.mdx
- section: Sponsor gas
path: wallets/pages/transactions/sponsor-gas/overview.mdx
collapsed: true
diff --git a/fern/wallets/pages/smart-wallets/quickstart/api.mdx b/fern/wallets/pages/smart-wallets/quickstart/api.mdx
index 45f35de73..6ffe95069 100644
--- a/fern/wallets/pages/smart-wallets/quickstart/api.mdx
+++ b/fern/wallets/pages/smart-wallets/quickstart/api.mdx
@@ -5,59 +5,21 @@ url: https://www.alchemy.com/docs/wallets/smart-wallet-quickstart/api
slug: wallets/smart-wallet-quickstart/api
---
-We'll demonstrate how to use the [`wallet_requestAccount`](/docs/wallets/api/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-request-account), [`wallet_prepareCalls`](/docs/wallets/api/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-prepare-calls), [`wallet_sendPreparedCalls`](/docs/wallets/api/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-send-prepared-calls), and [`wallet_getCallsStatus`](/docs/wallets/api/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-get-calls-status) endpoints.
+We'll demonstrate how to use the [`wallet_prepareCalls`](/docs/wallets/api/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-prepare-calls), [`wallet_sendPreparedCalls`](/docs/wallets/api/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-send-prepared-calls), and [`wallet_getCallsStatus`](/docs/wallets/api/smart-wallets/wallet-api-endpoints/wallet-api-endpoints/wallet-get-calls-status) endpoints.
+
+
+ For a complete working example with bash scripts using [jq](https://jqlang.org/) and [foundry](https://getfoundry.sh/) for signing, see [Send Transactions](/wallets/transactions/send-transactions).
+
```mermaid
flowchart LR
- A[requestAccount] --> B[prepareCalls]
- B --> C[sendPreparedCalls]
- C --> D[getCallsStatus]
-```
-
-### 1. Request an Account for the Owner Signer
-
-Given an owner address, call `wallet_requestAccount` to return the smart account address for that owner. The [owner](/docs/wallets/signer/what-is-a-signer) address can be any signer (or public key) that has the ability to sign transactions.
-
-* If you want to use social sign up / log in, you can simply use the [SDK](/docs/wallets/react/getting-started) to authenticate user's and retrieve their signer address
-* If instead, you want to generate and control wallets with a custodied owner, you can generate any public private key pair (e.g. any EOA)
-
-This will return the account address associated with the given signer, as well as a uuid you could use to differentiate between accounts for the same signer in the future.
-
-```bash
-curl --request POST \
- --url https://api.g.alchemy.com/v2/API_KEY \
- --header 'accept: application/json' \
- --header 'content-type: application/json' \
- --data '
-{
- "id": 1,
- "jsonrpc": "2.0",
- "method": "wallet_requestAccount",
- "params": [
- {
- "signerAddress": "0xOWNER_ADDRESS"
- }
- ]
-}
-'
+ A[prepareCalls] --> B[sendPreparedCalls]
+ B --> C[getCallsStatus]
```
-This will return the smart account address associated with the given signer:
+### 1. Prepare Calls
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {
- "accountAddress": "0xACCOUNT_ADDRESS",
- "id": "af638-a8..."
- }
-}
-```
-
-### 2. Prepare Calls
-
-Now that we have an account, it's time to prepare some calls!
+Use your signer address directly as the `from` field to enable [EIP-7702](/wallets/transactions/using-eip-7702) by default. The signer can be any Ethereum wallet key.
```bash
curl --request POST \
@@ -73,7 +35,7 @@ curl --request POST \
{
"capabilities": {
"paymasterService": {
- "policyId": GAS_MANAGER_POLICY_ID // put your gas manager policy ID here
+ "policyId": "GAS_MANAGER_POLICY_ID"
}
},
"calls": [
@@ -81,7 +43,7 @@ curl --request POST \
"to": "0x0000000000000000000000000000000000000000"
}
],
- "from": "0xACCOUNT_ADDRESS",
+ "from": "0xSIGNER_ADDRESS",
"chainId": "0xCHAIN_ID"
}
]
@@ -89,7 +51,38 @@ curl --request POST \
'
```
-This will return the userop request (the `data` field) and a signature request, for example:
+If the account hasn't been delegated yet, the response type will be `array` containing both an EIP-7702 authorization and a user operation:
+
+```json
+{
+ "type": "array",
+ "data": [
+ {
+ "type": "eip-7702-authorization",
+ "data": {...authorizationData},
+ "chainId": "0xCHAIN_ID",
+ "signatureRequest": {
+ "type": "eth_signAuthorization",
+ "rawPayload": "0xAUTH_PAYLOAD_TO_SIGN"
+ }
+ },
+ {
+ "type": "user-operation-v070",
+ "data": {...useropRequest},
+ "chainId": "0xCHAIN_ID",
+ "signatureRequest": {
+ "type": "personal_sign",
+ "data": {
+ "raw": "0xHASH_TO_SIGN"
+ },
+ "rawPayload": "0xRAW_PAYLOAD_TO_SIGN"
+ }
+ }
+ ]
+}
+```
+
+On subsequent transactions (after the account is delegated), the response will be a single user operation:
```json
{
@@ -99,27 +92,71 @@ This will return the userop request (the `data` field) and a signature request,
"signatureRequest": {
"type": "personal_sign",
"data": {
- "raw": "0xHASH_TO_SIGN",
+ "raw": "0xHASH_TO_SIGN"
},
"rawPayload": "0xRAW_PAYLOAD_TO_SIGN"
}
}
```
-If using Alchemy's signer service, this is the full raw payload to sign.
-If using a library like Viem, you can instead use `personal_sign` to sign the hash.
+### 2. Sign the Signature Request(s)
-### 3. Sign the userop
+Sign the returned signature request(s) using your signer key.
-With the returned signature request, all you have to do is sign the signature request (returned in step 2). You'll sign this using the account owner (from step 1).
+**If the account isn't delegated yet (array response):** Sign both the EIP-7702 authorization and the user operation. The authorization only needs to be signed once to delegate your account.
+
+**Once delegated:** Sign only the user operation.
If using an Alchemy Signer, you can learn how to stamp the request on the frontend [here](/docs/reference/how-to-stamp-requests). When using the Alchemy Signer, it's easiest to sign the `signatureRequest.rawPayload` directly.
-If you are using a library such as Viem that supports the `personal_sign` method, you should use that to sign the hash (since the `signatureRequest.type` is `"personal_sign"`).
+If you are using a library such as Viem that supports the `personal_sign` method, you should use that to sign the user operation hash (since the `signatureRequest.type` is `"personal_sign"`).
+
+### 3. Send the Prepared Calls!
+
+With the signature(s) from step 2 and the data from step 1, you're good to send the call!
+
+**If the account isn't delegated yet (array response):**
-### 4. Send the Prepared Calls!
+```bash
+curl --request POST \
+ --url https://api.g.alchemy.com/v2/API_KEY \
+ --header 'accept: application/json' \
+ --header 'content-type: application/json' \
+ --data '
+{
+ "id": 1,
+ "jsonrpc": "2.0",
+ "method": "wallet_sendPreparedCalls",
+ "params": [
+ {
+ "type": "array",
+ "data": [
+ {
+ "type": "eip-7702-authorization",
+ "data": {...authorizationData},
+ "chainId": "0xCHAIN_ID",
+ "signature": {
+ "type": "secp256k1",
+ "data": "0xAUTH_SIGNATURE"
+ }
+ },
+ {
+ "type": "user-operation-v070",
+ "data": {...useropRequest},
+ "chainId": "0xCHAIN_ID",
+ "signature": {
+ "type": "secp256k1",
+ "data": "0xUSEROP_SIGNATURE"
+ }
+ }
+ ]
+ }
+ ]
+}
+'
+```
-With the signature from step 3 and the `useropRequest` from step 2, you're good to send the call!
+**Once delegated:**
```bash
curl --request POST \
@@ -135,9 +172,9 @@ curl --request POST \
{
"type": "user-operation-v070",
"data": {...useropRequest},
- "chainId": "0xCHAIN_ID", // E.g. "0x66eee" for Arbitrum Sepolia
+ "chainId": "0xCHAIN_ID",
"signature": {
- "type": "secp256k1"
+ "type": "secp256k1",
"data": "0xUSEROP_SIGNATURE"
}
}
@@ -148,7 +185,7 @@ curl --request POST \
This will return the array of prepared call IDs!
-### 5. Check The Calls Status
+### 4. Check The Calls Status
Now you can simply call `wallet_getCallsStatus` to check the status of the calls. 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).
diff --git a/fern/wallets/pages/smart-wallets/quickstart/sdk.mdx b/fern/wallets/pages/smart-wallets/quickstart/sdk.mdx
index 7fe69a7f8..7040f8856 100644
--- a/fern/wallets/pages/smart-wallets/quickstart/sdk.mdx
+++ b/fern/wallets/pages/smart-wallets/quickstart/sdk.mdx
@@ -46,25 +46,48 @@ const client = createSmartWalletClient({
});
```
-### 3. Request The Account
+### 3. Send A UserOp
-A counterfactual address is the account address associated with the given signer-- but the account contract hasn't been deployed yet.
+Use your signer address directly as the `from` field to enable [EIP-7702](/wallets/transactions/using-eip-7702) by default. This first transaction will delegate your account.
```ts
-const account = await client.requestAccount();
+import { zeroAddress } from "viem";
+
+const signerAddress = await signer.getAddress();
+
+const preparedCalls = await client.prepareCalls({
+ calls: [{ to: zeroAddress, value: "0x0" }], // callData is optional in a "data" parameter
+ from: signerAddress,
+ // "capabilities" is a data structure that hold gas manager data (as seen below) or permission data
+ capabilities: {
+ paymasterService: {
+ policyId: GAS_MANAGER_POLICY_ID, // put your gas manager policy ID here
+ },
+ },
+});
-// get the address
-const address = account.address;
+// Sign the calls (handles both authorization and user operation if account isn't delegated yet)
+const signedCalls = await client.signPreparedCalls(preparedCalls);
+
+// Send the userOp
+const result = await client.sendPreparedCalls(signedCalls);
+
+// Check calls status.
+const status = await client.getCallsStatus(result.preparedCallIds[0]!);
```
### 4. Sign A Message
+Once your account is delegated, you can sign messages.
+
```ts
import { createPublicClient } from "viem";
+const signerAddress = await signer.getAddress();
+
const message = "we are so back";
-const signature = await client.signMessage({ message });
+const signature = await client.signMessage({ message, account: signerAddress });
const publicClient = createPublicClient({
chain: arbitrumSepolia,
@@ -72,7 +95,7 @@ const publicClient = createPublicClient({
});
const isValid = await publicClient.verifyMessage({
- address: account.address, // fetched from await client.requestAccount()
+ address: signerAddress,
message,
signature,
});
@@ -82,39 +105,11 @@ const isValid = await publicClient.verifyMessage({
```ts
// assuming you have a typedData variable
-const signature = await client.signTypedData({ typedData });
+const signature = await client.signTypedData({ typedData, account: signerAddress });
const isValid = await publicClient.verifyTypedData({
- address: account.address, // fetched from await client.requestAccount()
+ address: signerAddress,
...typedData,
signature,
});
```
-
-### 6. Send A UserOp
-
-```ts
-import { zeroAddress } from "viem";
-
-const account = await client.requestAccount();
-
-const preparedCalls = await client.prepareCalls({
- calls: [{ to: zeroAddress, value: "0x0" }], // callData is optional in a "data" parameter
- from: account.address,
- // "capabilities" is a data structure that hold gas manager data (as seen below) or permission data
- capabilities: {
- paymasterService: {
- policyId: GAS_MANAGER_POLICY_ID, // put your gas manager policy ID here
- },
- },
-});
-
-// Sign the calls
-const signedCalls = await client.signPreparedCalls(preparedCalls);
-
-// Send the userOp
-const result = await client.sendPreparedCalls(signedCalls);
-
-// Check calls status.
-const status = await client.getCallsStatus(result.preparedCallIds[0]!);
-```
diff --git a/fern/wallets/pages/smart-wallets/session-keys/api.mdx b/fern/wallets/pages/smart-wallets/session-keys/api.mdx
index d197ffc29..caa0e65e2 100644
--- a/fern/wallets/pages/smart-wallets/session-keys/api.mdx
+++ b/fern/wallets/pages/smart-wallets/session-keys/api.mdx
@@ -5,212 +5,221 @@ url: https://alchemy.com/docs/wallets/reference/wallet-apis-session-keys/api
slug: wallets/reference/wallet-apis-session-keys/api
---
-### 1. Request an Account for the Owner Signer
-
-Given an owner address, call `wallet_requestAccount` to return the smart account address for that owner. The [owner](/docs/wallets/signer/what-is-a-signer) address can be any signer (or public key) that has the ability to sign transactions.
-
-* If you want to use social sign up / log in, you can simply use the [SDK](/docs/wallets/react/getting-started) to authenticate users and retrieve their signer address
-* If instead, you want to generate and control wallets with a custodied owner, you can generate any public private key pair (e.g. any EOA)
-
-This will return the account address associated with the given signer, as well as a uuid you could use to differentiate between accounts for the same signer in the future.
-
-```bash
-curl --request POST \
- --url https://api.g.alchemy.com/v2/API_KEY \
- --header 'accept: application/json' \
- --header 'content-type: application/json' \
- --data '
-{
- "id": 1,
- "jsonrpc": "2.0",
- "method": "wallet_requestAccount",
- "params": [
- {
- "signerAddress": "0xOWNER_ADDRESS"
- }
- ]
-}
-'
-```
-
-This will return the smart account address associated with the given signer:
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {
- "accountAddress": "0xACCOUNT_ADDRESS",
- "id": "af638-a8..."
- }
-}
-```
-
-### 2. Create a Session With the Session Key Signer
-
-
- If you are using an EIP-7702 account, the account must be delegated onchain
- before creating the session. If the account has already sent calls, it will
- already be delegated. If it hasn't sent any calls before creating the session
- key, you can delegate it by sending an empty call as the owner.
-
-
-To create a session key using onchain policies:
-
-* Get the public address of a key you want to use as a session key. This can be any key pair that has the ability to sign (aka a [signer](/docs/wallets/signer/what-is-a-signer) that is either an local [signer](/wallets/reference/aa-sdk/core/classes/LocalAccountSigner) like an EOA or signer generated with a signer provider).
-* Create a session for that key, by passing it as the `publicKey` in a call to `wallet_createSession`. (Note that this must be the public key **address**, not the full public key.)
-
-Note that the expiry is in seconds and represents a UNIX timestamp (e.g. 1776657600 for April 20th, 2077).
-
-```bash
-curl --request POST \
- --url https://api.g.alchemy.com/v2/API_KEY \
- --header 'accept: application/json' \
- --header 'content-type: application/json' \
- --data '
-{
- "jsonrpc": "2.0",
- "id": 1,
- "method": "wallet_createSession",
- "params": [
- {
- "account": "0xACCOUNT_ADDRESS",
- "chainId": "0xCHAIN_ID",
- "expirySec": UNIX_TIMESTAMP_EXPIRY_IN_SECONDS,
- "key": {
- "publicKey": "0xSESSION_KEY_ADDRESS",
- "type": "secp256k1",
- },
- "permissions": [
- {
- "type": "root"
+
+ The examples provided use [jq](https://jqlang.org/) to parse json and
+ [foundry](https://getfoundry.sh/) to sign payloads.
+
+
+
+
+ EIP-7702 accounts must be delegated onchain before creating a session. If the account has already sent calls, it will already be delegated. If it hasn't sent any calls before, delegate it by sending an empty call as the owner. See [Send Transactions](/wallets/transactions/send-transactions) for the complete flow.
+
+ ```bash
+ # Prepare and send a delegation transaction
+ PREPARE_RESPONSE=$(curl -s --request POST \
+ --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --header 'accept: application/json' \
+ --header 'content-type: application/json' \
+ --data '{
+ "id": 1,
+ "jsonrpc": "2.0",
+ "method": "wallet_prepareCalls",
+ "params": [
+ {
+ "calls": [{"to": "0x0000000000000000000000000000000000000000", "data": "0x", "value": "0x0"}],
+ "from": "'$SIGNER_ADDRESS'",
+ "chainId": "'$CHAIN_ID'",
+ "capabilities": {
+ "paymasterService": {"policyId": "'$POLICY_ID'"}
}
- ]
+ }
+ ]
+ }')
+
+ # Sign and send (see Send Transactions for complete signing flow)
+ ```
+
+
+
+ To create a session key:
+
+ * Get the public address of a key you want to use as a session key. This can be any key pair that has the ability to sign (aka a [signer](/docs/wallets/signer/what-is-a-signer) that is either a local [signer](/wallets/reference/aa-sdk/core/classes/LocalAccountSigner) like an EOA or signer generated with a signer provider).
+ * Create a session for that key, by passing it as the `publicKey` in a call to `wallet_createSession`. (Note that this must be the public key **address**, not the full public key.)
+
+ Use your signer address directly as the `account` field to enable [EIP-7702](/wallets/transactions/using-eip-7702) by default.
+
+ Note that the expiry is in seconds and represents a UNIX timestamp (e.g. 1776657600 for April 20th, 2077).
+
+ ```bash
+ curl --request POST \
+ --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --header 'accept: application/json' \
+ --header 'content-type: application/json' \
+ --data '
+ {
+ "jsonrpc": "2.0",
+ "id": 1,
+ "method": "wallet_createSession",
+ "params": [
+ {
+ "account": "'$SIGNER_ADDRESS'",
+ "chainId": "'$CHAIN_ID'",
+ "expirySec": '$EXPIRY_TIMESTAMP',
+ "key": {
+ "publicKey": "'$SESSION_KEY_ADDRESS'",
+ "type": "secp256k1"
+ },
+ "permissions": [
+ {
+ "type": "root"
+ }
+ ]
+ }
+ ]
+ }'
+ ```
+
+ This will return two key elements:
+
+ 1. The session ID
+ 2. The signature request that must be signed by the account owner to authorize the session key
+
+ Keep note of the session ID, you'll need it later!
+
+ ```json
+ {
+ "jsonrpc": "2.0",
+ "id": 1,
+ "result": {
+ "sessionId": "0xSESSION_ID",
+ "signatureRequest": {
+ "type": "eth_signTypedData_v4",
+ "data": {...},
+ "rawPayload": "0xRAW_PAYLOAD_TO_SIGN"
+ }
}
- ]
-}'
-```
-
-This will return two key elements:
-
-1. The session ID
-2. The signature request that must be signed by the account owner to authorize the session key
+ }
+ ```
+
+
+
+ Sign the signature request using the account owner's key, then store the resulting signature.
+
+ The `signatureRequest.type` is `eth_signTypedData_v4`, indicating this is EIP-712 typed data. You can either:
+
+ * Sign the full typed data object using `eth_signTypedData_v4`
+ * Sign the `rawPayload` hash directly (without adding a message prefix)
+
+
+ When using foundry's `cast wallet sign`, use the `--no-hash` flag for the `rawPayload` since it's already an EIP-712 hash that should be signed without the Ethereum signed message prefix.
+
+
+ ```bash
+ # Using foundry cast
+ SESSION_SIGNATURE=$(cast wallet sign --no-hash --private-key "$OWNER_PRIVATE_KEY" "$RAW_PAYLOAD")
+ ```
+
+
+
+ With the session ID received in step 2 and the signature from step 3, we're now ready to prepare some calls!
+
+ ```bash
+ curl --request POST \
+ --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --header 'accept: application/json' \
+ --header 'content-type: application/json' \
+ --data '
+ {
+ "id": 1,
+ "jsonrpc": "2.0",
+ "method": "wallet_prepareCalls",
+ "params": [
+ {
+ "capabilities": {
+ "paymasterService": {
+ "policyId": "'$POLICY_ID'"
+ },
+ "permissions": {
+ "sessionId": "'$SESSION_ID'",
+ "signature": "'$SESSION_SIGNATURE'"
+ }
+ },
+ "calls": [
+ {
+ "to": "0x0000000000000000000000000000000000000000"
+ }
+ ],
+ "from": "'$SIGNER_ADDRESS'",
+ "chainId": "'$CHAIN_ID'"
+ }
+ ]
+ }
+ '
+ ```
-Keep note of the session ID, you'll need it later!
+ This will return the userop request (the `data` field) and a signature request, for example:
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {
- "sessionId": "0xSESSION_ID",
+ ```json
+ {
+ "type": "user-operation-v070",
+ "data": {...useropRequest},
+ "chainId": "0xCHAIN_ID",
"signatureRequest": {
- "type": "eth_signTypedData_v4",
- "data": {...},
+ "type": "personal_sign",
+ "data": {
+ "raw": "0x_HASH_TO_SIGN"
+ },
"rawPayload": "0xRAW_PAYLOAD_TO_SIGN"
}
}
-}
-```
-
-### 3. Sign the Session Key Authorization
-
-Sign the signature request using the account owner's key (used in step 1), then store the resulting signature. If you are using an Alchemy Signer, you can directly sign the `rawPayload`. If you are using a library that supports signing typed data, you can use it to sign the typed data.
-
-### 4. Prepare Calls With the Session Key
-
-With the session ID received in step 2 and the signature from step 3, we're now ready to prepare some calls!
-
-```bash
-curl --request POST \
- --url https://api.g.alchemy.com/v2/API_KEY \
- --header 'accept: application/json' \
- --header 'content-type: application/json' \
- --data '
-{
- "id": 1,
- "jsonrpc": "2.0",
- "method": "wallet_prepareCalls",
- "params": [
- {
- "capabilities": {
- "paymasterService": {
- "policyId": "GAS-MANAGER-POLICY-ID", // put your gas manager policy ID here
+ ```
+
+
+
+ With the returned signature request, sign the userop hash using **the session key** (not the owner). This signature will be valid as long as it is within the permissions the session key has.
+
+ Note that the `type` field in the `signatureRequest` indicates the signature type needed. In this case, we need to `personal_sign` the hash.
+
+ ```bash
+ # Sign with the SESSION key (not owner!)
+ USEROP_SIGNATURE=$(cast wallet sign --private-key "$SESSION_PRIVATE_KEY" "$RAW_HASH")
+ ```
+
+
+
+ With the signature from step 5 and the `useropRequest` from step 4, you're good to go to send the call!
+
+ ```bash
+ curl --request POST \
+ --url https://api.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --header 'accept: application/json' \
+ --header 'content-type: application/json' \
+ --data '
+ {
+ "id": 1,
+ "jsonrpc": "2.0",
+ "method": "wallet_sendPreparedCalls",
+ "params": [
+ {
+ "type": "user-operation-v070",
+ "data": {...useropRequest},
+ "chainId": "'$CHAIN_ID'",
+ "capabilities": {
+ "permissions": {
+ "sessionId": "'$SESSION_ID'",
+ "signature": "'$SESSION_SIGNATURE'"
+ }
},
- "permissions": {
- "sessionId": "0xSESSION_ID",
- "signature": "0xPERMISSION_SIG",
- }
- },
- "calls": [
- {
- "to": "0x0000000000000000000000000000000000000000"
- }
- ],
- "from": "0xACCOUNT_ADDRESS",
- "chainId": "0xCHAIN_ID"
- }
- ]
-}
-'
-```
-
-This will return the userop request (the `data` field) and a signature request, for example:
-
-```json
-{
- "type": "user-operation-v070",
- "data": {...useropRequest},
- "chainId": "0xCHAIN_ID",
- "signatureRequest": {
- "type": "personal_sign",
- "data": {
- "raw": "0x_HASH_TO_SIGN",
- },
- "rawPayload": "0xRAW_PAYLOAD_TO_SIGN"
- }
-}
-```
-
-### 5. Sign the userop
-
-With the returned signature request, all you have to do is sign the userop hash returned in the `signatureRequest` field. This should be signed with the session key. This signature will be valid as long as it is within the permissions the session key has.
-
-Note that the `type` field in the `signatureRequest` indicates the signature type needed. In this case, we need to `personal_sign` the hash, or, if using an Alchemy Signer, you can directly sign the `rawPayload` instead.
-
-### 6. Send the Prepared Calls!
-
-With the signature from step 5 and the `useropRequest` from step 4, you're good to go to send the call!
-
-```bash
-curl --request POST \
- --url https://api.g.alchemy.com/v2/API_KEY \
- --header 'accept: application/json' \
- --header 'content-type: application/json' \
- --data '
-{
- "id": 1,
- "jsonrpc": "2.0",
- "method": "wallet_sendPreparedCalls",
- "params": [
- {
- "type": "user-operation-v070",
- "data": {...useropRequest},
- "chainId": "0xCHAIN_ID", // e.g. "0x66eee" for Arbitrum Sepolia
- "capabilities": {
- "permissions": {
- "sessionId": "0xSESSION_ID",
- "signature": "0xPERMISSION_SIG",
+ "signature": {
+ "type": "secp256k1",
+ "data": "'$USEROP_SIGNATURE'"
}
- },
- "signature": {
- "type": "secp256k1",
- "data": "0xUSEROP_SIGNATURE",
}
- }
- ]
-}
-'
-```
+ ]
+ }
+ '
+ ```
-This will return the array of prepared call IDs!
+ This will return the array of prepared call IDs!
+
+
diff --git a/fern/wallets/pages/smart-wallets/session-keys/index.mdx b/fern/wallets/pages/smart-wallets/session-keys/index.mdx
index 2daef1780..7da2b5580 100644
--- a/fern/wallets/pages/smart-wallets/session-keys/index.mdx
+++ b/fern/wallets/pages/smart-wallets/session-keys/index.mdx
@@ -37,8 +37,10 @@ We'll demonstrate how to create and use session keys [using the SDK client](/doc
To specify permissions during a session key installation, include them in the `permissions` array when calling `client.grantPermission()` via the SDK or `wallet_createSession` via the API.
```ts
+const signerAddress = await signer.getAddress();
+
const permissions = await client.grantPermissions({
- account: account.address,
+ account: signerAddress,
expirySec: Math.floor(Date.now() / 1000) + 60 * 60,
key: {
publicKey: await sessionKey.getAddress(),
diff --git a/fern/wallets/pages/smart-wallets/session-keys/sdk.mdx b/fern/wallets/pages/smart-wallets/session-keys/sdk.mdx
index c88acd114..bec4edcd3 100644
--- a/fern/wallets/pages/smart-wallets/session-keys/sdk.mdx
+++ b/fern/wallets/pages/smart-wallets/session-keys/sdk.mdx
@@ -52,17 +52,19 @@ const client = createSmartWalletClient({
### 3. Create the session key
-
+
-If you are using an EIP-7702 account, the account must be delegated onchain
-before creating the session. If the account has already sent calls, it will
-already be delegated. If it hasn't sent any calls before creating the session
-key, you can delegate it by sending an empty call as the owner:
+EIP-7702 accounts must be delegated onchain before creating a session. If the
+account has already sent calls, it will already be delegated. If it hasn't sent
+any calls before creating the session key, you can delegate it by sending an
+empty call as the owner:
```ts
+const signerAddress = await signer.getAddress();
+
const preparedCalls = await client.prepareCalls({
calls: [], // empty array since you don't want to send any calls
- from: account.address,
+ from: signerAddress,
capabilities: {
paymasterService: {
policyId: GAS_MANAGER_POLICY_ID, // put your gas manager policy ID here
@@ -82,13 +84,13 @@ Now you can continue to create the session key as described below.
```ts
-const account = await client.requestAccount(); // Request an account for the owner signer
+const signerAddress = await signer.getAddress();
// This is where you would use your session key signer!
const sessionKey = LocalAccountSigner.generatePrivateKeySigner();
const permissions = await client.grantPermissions({
- account: account.address,
+ account: signerAddress,
expirySec: Math.floor(Date.now() / 1000) + 60 * 60,
key: {
publicKey: await sessionKey.getAddress(),
@@ -105,7 +107,7 @@ import { signPreparedCalls } from "@account-kit/wallet-client";
const preparedCalls = await client.prepareCalls({
calls: [{ to: "0x0000000000000000000000000000000000000000", value: "0x0" }],
- from: account.address,
+ from: signerAddress,
capabilities: {
paymasterService: {
policyId: GAS_MANAGER_POLICY_ID, // put your gas manager policy ID here
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..46f1512ef 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.
+If the account hasn't been delegated yet, 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 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/cross-chain-swap-tokens/index.mdx b/fern/wallets/pages/transactions/cross-chain-swap-tokens/index.mdx
index 04318ecd8..8dd084c4e 100644
--- a/fern/wallets/pages/transactions/cross-chain-swap-tokens/index.mdx
+++ b/fern/wallets/pages/transactions/cross-chain-swap-tokens/index.mdx
@@ -33,13 +33,15 @@ When requesting a cross-chain swap quote, you can specify either a `fromAmount`
```tsx
// Mode 1: Swap exact input amount
{
+ // Swap exactly 0.01 USDC (10000 in hex, 6 decimals)
fromAmount: "0x2710";
-} // Swap exactly 0.01 USDC (10000 in hex, 6 decimals)
+}
// Mode 2: Get minimum output amount
{
+ // Get at least 0.0001 ETH (18 decimals). The amount you need to spend is calculated to get at least your desired ETH amount.
minimumToAmount: "0x5AF3107A4000";
-} // Get at least 0.0001 ETH (18 decimals). The amount you need to spend is calculated to get at least your desired ETH amount.
+}
```
## Prerequisites
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..bf78eba2d 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`. If the account hasn't been delegated yet, 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..3e400c6f0 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`. If the account hasn't been delegated yet, 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..17fc6e88b 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
@@ -9,9 +9,10 @@ Use the `paymasterService` capability on the smart wallet client `sendCalls` or
```ts title="sendCalls.ts"
-import { client, config } from "./client.ts";
+import { client, config, signer } from "./client.ts";
const { preparedCallIds } = await client.sendCalls({
+ from: await signer.getAddress(),
capabilities: {
paymasterService: {
policyId: config.policyId,
@@ -50,23 +51,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..463997fa4 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. If the account hasn't been delegated yet, 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..9e62d379c 100644
--- a/fern/wallets/pages/transactions/retry-transactions/client.mdx
+++ b/fern/wallets/pages/transactions/retry-transactions/client.mdx
@@ -14,10 +14,11 @@ You'll need the following env variables:
```ts title="retryTransaction.ts"
- import { client, config } from "./client.ts";
+ import { client, config, signer } from "./client.ts";
// Send initial transaction
const { preparedCallIds } = await client.sendCalls({
+ from: await signer.getAddress(),
capabilities: {
paymasterService: {
policyId: config.policyId,
@@ -35,9 +36,7 @@ You'll need the following env variables:
console.log("Initial transaction:", preparedCallIds[0]);
// Check status
- const status = await client.getCallsStatus({
- id: preparedCallIds[0]!,
- });
+ const status = await client.getCallsStatus(preparedCallIds[0]!);
console.log("Transaction status:", status.status);
@@ -47,6 +46,7 @@ You'll need the following env variables:
// Re-send without nonceOverride to replace stuck transaction
const { preparedCallIds: replacementIds } = await client.sendCalls({
+ from: await signer.getAddress(),
capabilities: {
paymasterService: {
policyId: config.policyId,
@@ -64,7 +64,7 @@ You'll need the following env variables:
console.log("Replacement transaction:", replacementIds[0]);
// Wait for replacement to confirm
- const result = await client.waitForCallsStatus(replacementIds[0]!);
+ const result = await client.waitForCallsStatus({ id: replacementIds[0]! });
console.log("Replacement confirmed:", result);
}
@@ -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..5e0897ad9 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`. If the account hasn't been delegated yet, you'll also need to sign the 7702 authorization. See [Send Transactions](/wallets/transactions/send-transactions) for a complete example.
diff --git a/fern/wallets/pages/transactions/send-batch-transactions/client.mdx b/fern/wallets/pages/transactions/send-batch-transactions/client.mdx
index af49a12c3..5ac1bbe7a 100644
--- a/fern/wallets/pages/transactions/send-batch-transactions/client.mdx
+++ b/fern/wallets/pages/transactions/send-batch-transactions/client.mdx
@@ -10,7 +10,7 @@ You can batch transactions using either the smart wallet client `sendCalls` or `
```ts title="sendCalls.ts"
import { type Address, erc20Abi, encodeFunctionData, parseUnits } from "viem";
-import { client } from "./client";
+import { client, signer } from "./client";
import { swapAbi } from "./swapAbi";
const DEMO_USDC_ADDRESS: Address = "0xCFf7C6dA719408113DFcb5e36182c6d5aa491443";
@@ -18,6 +18,7 @@ const DEMO_USDC_ADDRESS: Address = "0xCFf7C6dA719408113DFcb5e36182c6d5aa491443";
const DEMO_SWAP_ADDRESS: Address = "0xB0AEC4c25E8332256A91bBaf169E3C32dfC3C33C";
const { preparedCallIds } = await client.sendCalls({
+ from: await signer.getAddress(),
calls: [
// To batch, simply specify multiple calls in the calls array
{
@@ -49,23 +50,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..98824a22b 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!
+
+ If the account hasn't been delegated yet, 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 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..344d6e695 100644
--- a/fern/wallets/pages/transactions/send-parallel-transactions/client.mdx
+++ b/fern/wallets/pages/transactions/send-parallel-transactions/client.mdx
@@ -14,13 +14,16 @@ You'll need the following env variables:
```ts title="sendParallelCalls.ts"
- import { client, config } from "./client.ts";
+ import { client, config, signer } from "./client.ts";
+
+ const signerAddress = await signer.getAddress();
const [
{ preparedCallIds: preparedCallIdsOne },
{ preparedCallIds: preparedCallIdsTwo },
] = await Promise.all([
client.sendCalls({
+ from: signerAddress,
capabilities: {
paymasterService: {
policyId: config.policyId,
@@ -38,6 +41,7 @@ You'll need the following env variables:
],
}),
client.sendCalls({
+ from: signerAddress,
capabilities: {
paymasterService: {
policyId: config.policyId,
@@ -68,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";
@@ -77,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-transactions/api.mdx b/fern/wallets/pages/transactions/send-transactions/api.mdx
index a3f374321..141ca4639 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.
+If the account hasn't been delegated yet, the response type will be `array` containing both an EIP-7702 authorization and a user operation that need to be signed. Once delegated (after the first successful transaction), subsequent calls will only return a user operation to sign.
+
```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..cc5abecc9 100644
--- a/fern/wallets/pages/transactions/send-transactions/client.mdx
+++ b/fern/wallets/pages/transactions/send-transactions/client.mdx
@@ -8,9 +8,10 @@ You can send transactions using the smart wallet client `sendCalls` action.
```ts title="sendCalls.ts"
import { parseEther, toHex } from "viem";
-import { client } from "./client.ts";
+import { client, signer } from "./client.ts";
const { preparedCallIds } = await client.sendCalls({
+ from: await signer.getAddress(),
calls: [
{
to: "0x0000000000000000000000000000000000000000",
@@ -28,30 +29,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..ff698792f 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
@@ -1,4 +1,4 @@
-You can use [foundry](https://getfoundry.sh/cast/reference/calldata#cast-calldata) to encode function call data.
+You can use [foundry](https://getfoundry.sh/cast/reference/calldata#cast-calldata) to encode function call data. Use your signer address directly as the `from` field to enable [EIP-7702](/wallets/transactions/using-eip-7702) by default.
```bash twoslash focus={14}
curl --request POST \
@@ -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..116d54228 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
@@ -2,19 +2,20 @@ In JavaScript, you can use [Viem](https://viem.sh/docs/contract/encodeFunctionDa
-```ts title="sendCalls.ts" focus={9-13}
+```ts title="sendCalls.ts" focus={9-14}
import { encodeFunctionData } from "viem";
-import { client } from "./client.ts";
+import { client, signer } from "./client.ts";
import { exampleAbi } from "./abi.ts";
await client.sendCalls({
+ from: await signer.getAddress(),
calls: [
{
to: "0x0000000000000000000000000000000000000000",
data: encodeFunctionData({
abi: exampleAbi,
functionName: "mintTo",
- args: [client.account!.address],
+ args: ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"],
}),
},
],
@@ -34,30 +35,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..0db03f96b 100644
--- a/fern/wallets/pages/transactions/send-transactions/prepare-calls/client.mdx
+++ b/fern/wallets/pages/transactions/send-transactions/prepare-calls/client.mdx
@@ -4,11 +4,12 @@ You can use smart wallet client actions to prepare, sign, and send transactions.
-```ts title="sendCalls.ts" focus={4-20}
+```ts title="sendCalls.ts" focus={4-21}
import { parseEther, toHex } from "viem";
-import { client } from "./client.ts";
+import { client, signer } from "./client.ts";
const preparedCalls = await client.prepareCalls({
+ from: await signer.getAddress(),
calls: [
{
to: "0x0000000000000000000000000000000000000000",
@@ -28,30 +29,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..2279e4a1e 100644
--- a/fern/wallets/pages/transactions/signing/sign-messages/client-raw.mdx
+++ b/fern/wallets/pages/transactions/signing/sign-messages/client-raw.mdx
@@ -7,13 +7,14 @@ for full descriptions of the parameters used in the following example.
```ts title="signRawMessage.ts"
-import { client } from "./client";
+import { client, signer } from "./client";
// Sign a raw hex message
const rawSignature = await client.signMessage({
message: {
raw: "0x48656c6c6f2c20776f726c6421", // "Hello, world!" in hex
},
+ account: await signer.getAddress(),
});
console.log("Signature over raw data:", rawSignature);
@@ -26,23 +27,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..75c709874 100644
--- a/fern/wallets/pages/transactions/signing/sign-messages/client-text.mdx
+++ b/fern/wallets/pages/transactions/signing/sign-messages/client-text.mdx
@@ -7,11 +7,12 @@ for full descriptions of the parameters used in the following example.
```ts title="signTextMessage.ts"
-import { client } from "./client";
+import { client, signer } from "./client";
// Sign a simple text message
const textSignature = await client.signMessage({
message: "Hello, world!",
+ account: await signer.getAddress(),
});
console.log("Signature over text:", textSignature);
@@ -24,23 +25,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/index.mdx b/fern/wallets/pages/transactions/signing/sign-messages/index.mdx
index 83b4bbccb..e8d07edba 100644
--- a/fern/wallets/pages/transactions/signing/sign-messages/index.mdx
+++ b/fern/wallets/pages/transactions/signing/sign-messages/index.mdx
@@ -13,6 +13,10 @@ Smart Wallets will generate signatures that can be validated using [ERC-1271](ht
* API key from your [dashboard](https://dashboard.alchemy.com/apps)
* A Smart Wallet with an associated signer
+
+ When using [EIP-7702](/wallets/transactions/using-eip-7702), your account must be delegated before signatures will be valid. Send at least one transaction to delegate your account first.
+
+
## What is message signing?
Message signing allows users to:
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..e25a3f3a8 100644
--- a/fern/wallets/pages/transactions/signing/sign-typed-data/client.mdx
+++ b/fern/wallets/pages/transactions/signing/sign-typed-data/client.mdx
@@ -7,7 +7,9 @@ for full descriptions of the parameters used in the following example.
```ts title="signTypedData.ts"
-import { client } from "./client";
+import { client, signer } from "./client";
+
+const signerAddress = await signer.getAddress();
// Sign typed data
const typedData = {
@@ -26,13 +28,16 @@ const typedData = {
},
primaryType: "Auth",
message: {
- user: "0x...", // wallet address
+ user: signerAddress,
nonce: 12345,
timestamp: Date.now(),
},
} as const;
-const signature = await client.signTypedData(typedData);
+const signature = await client.signTypedData({
+ ...typedData,
+ account: signerAddress,
+});
console.log("Typed data signature:", signature);
```
@@ -44,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/signing/sign-typed-data/index.mdx b/fern/wallets/pages/transactions/signing/sign-typed-data/index.mdx
index be985277f..016bb5db6 100644
--- a/fern/wallets/pages/transactions/signing/sign-typed-data/index.mdx
+++ b/fern/wallets/pages/transactions/signing/sign-typed-data/index.mdx
@@ -11,6 +11,10 @@ This guide will teach you how to sign EIP-712 typed data with your Smart Wallet.
* API key from your [dashboard](https://dashboard.alchemy.com/apps)
* A Smart Wallet with an associated signer
+
+ When using [EIP-7702](/wallets/transactions/using-eip-7702), your account must be delegated before signatures will be valid. Send at least one transaction to delegate your account first.
+
+
## What is typed data signing?
EIP-712 typed data signing allows users to:
diff --git a/fern/wallets/pages/transactions/sponsor-gas/api.mdx b/fern/wallets/pages/transactions/sponsor-gas/api.mdx
index b49e9037a..f3458d2bc 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`. If the account hasn't been delegated yet, you'll also need to sign the 7702 authorization. See [Send Transactions](/wallets/transactions/send-transactions) for a complete example.
diff --git a/fern/wallets/pages/transactions/sponsor-gas/client.mdx b/fern/wallets/pages/transactions/sponsor-gas/client.mdx
index bb0b98325..44ff927e2 100644
--- a/fern/wallets/pages/transactions/sponsor-gas/client.mdx
+++ b/fern/wallets/pages/transactions/sponsor-gas/client.mdx
@@ -9,10 +9,11 @@ Use the `paymasterService` capability on the smart wallet client `sendCalls` or
```ts title="sendCalls.ts"
-import { client, config } from "./client.ts";
+import { client, config, signer } from "./client.ts";
try {
const { preparedCallIds } = await client.sendCalls({
+ from: await signer.getAddress(),
capabilities: {
paymasterService: {
policyId: config.policyId,
@@ -44,23 +45,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..c8219e5fd 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,13 +21,13 @@ 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}",
"fromAmount": "{FROM_AMOUNT_HEXADECIMAL}",
"postCalls": [{
- "to:" "{POSTCALL_TO_ADDRESS}",
+ "to": "{POSTCALL_TO_ADDRESS}",
"data": "{POSTCALL_DATA}",
"value": "{POSTCALL_VALUE}"
}],
@@ -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.
+
+If the account hasn't been delegated yet, 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 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..e1bf630a2 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 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`.
+
+ If the account hasn't been delegated yet, 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..e79be0cfd 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 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`
@@ -16,15 +15,15 @@ for full descriptions of the parameters used in the following example.
```tsx title="sendCalls.ts"
-import { client, config } from "./client.ts";
+import { client, config, signer } from "./client.ts";
try {
const { preparedCallIds } = await client.sendCalls({
+ from: await signer.getAddress(),
capabilities: {
paymasterService: {
policyId: config.policyId,
},
- eip7702Auth: true,
},
calls: [
{
@@ -52,10 +51,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 +61,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..55549862d 100644
--- a/fern/wallets/pages/transactions/using-eip-7702/index.mdx
+++ b/fern/wallets/pages/transactions/using-eip-7702/index.mdx
@@ -1,36 +1,93 @@
---
-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
+For implementation details, see the [Send Transactions](/wallets/transactions/send-transactions) guide.
-* API key from your [dashboard](https://dashboard.alchemy.com/apps)
+## How to use non-7702 mode
-## Implementation
+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 (instead of your signer address) in subsequent API calls will bypass 7702 mode.
+
+**When to use SCA mode:**
+* Backwards compatibility with existing Smart Contract Accounts
+* Using chains that don't yet support EIP-7702
+* Using a signer that doesn't support signing EIP-7702 authorizations
+* Specific requirements for smart contract account architecture
-
-
+
+ ```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: [...],
+ });
+ ```
-
-
+
+ ```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'"
+ }]
+ }'
+ ```
@@ -102,13 +159,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.