Skip to content

Commit 974349c

Browse files
Add session keys guide to Engine V3 documentation
Co-authored-by: joaquim.verges <[email protected]>
1 parent 20e323d commit 974349c

File tree

2 files changed

+320
-0
lines changed

2 files changed

+320
-0
lines changed
Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
# Session Keys Guide
2+
3+
Session keys enable secure transaction execution on behalf of smart accounts without requiring direct access to the main account's private key. This guide will walk you through creating and using session keys with the thirdweb TypeScript SDK.
4+
5+
## Prerequisites
6+
7+
Before you begin, ensure you have:
8+
- A thirdweb client configured
9+
- Access to a session key account address
10+
- Vault access token for Engine operations
11+
12+
## Setup
13+
14+
First, let's set up the necessary imports and configuration:
15+
16+
```typescript
17+
import {
18+
generateAccount,
19+
smartWallet,
20+
sendTransaction,
21+
getContract
22+
} from "thirdweb";
23+
import { sepolia } from "thirdweb/chains";
24+
import { getAllActiveSigners } from "thirdweb/extensions/erc4337";
25+
import { Engine } from "thirdweb/engine";
26+
27+
// Configure your client
28+
const client = createThirdwebClient({
29+
clientId: "your-client-id",
30+
secretKey: "your-secret-key" // Only use in server environments
31+
});
32+
33+
// Your session key account address
34+
const sessionKeyAccountAddress = "0x..."; // Replace with your session key address
35+
36+
// Target address for transactions
37+
const targetAddress = "0x..."; // Replace with your target address
38+
```
39+
40+
## Step 1: Create a Personal Account
41+
42+
Generate a personal account that will be used to create the smart wallet:
43+
44+
```typescript
45+
const personalAccount = await generateAccount({
46+
client: client,
47+
});
48+
49+
console.log("Personal account created:", personalAccount.address);
50+
```
51+
52+
## Step 2: Configure Smart Wallet with Session Key
53+
54+
Create a smart wallet configuration with session key permissions:
55+
56+
```typescript
57+
const smart = smartWallet({
58+
chain: sepolia,
59+
sessionKey: {
60+
address: sessionKeyAccountAddress,
61+
permissions: {
62+
// "*" allows all targets, or specify specific contract addresses
63+
approvedTargets: "*",
64+
},
65+
},
66+
sponsorGas: true, // Enable gas sponsorship
67+
});
68+
```
69+
70+
### Session Key Permissions
71+
72+
The `permissions` object allows you to control what the session key can do:
73+
74+
- `approvedTargets`: Specify which contract addresses the session key can interact with
75+
- Use `"*"` for all targets
76+
- Use an array of addresses for specific contracts: `["0x123...", "0x456..."]`
77+
78+
## Step 3: Connect Smart Account
79+
80+
Connect the smart wallet using the personal account:
81+
82+
```typescript
83+
const smartAccount = await smart.connect({
84+
client: client,
85+
personalAccount: personalAccount,
86+
});
87+
88+
console.log("Smart account address:", smartAccount.address);
89+
```
90+
91+
## Step 4: Verify Session Key Registration
92+
93+
Check that the session key is properly registered as an active signer:
94+
95+
```typescript
96+
const signers = await getAllActiveSigners({
97+
contract: getContract({
98+
address: smartAccount.address,
99+
chain: sepolia,
100+
client: client,
101+
}),
102+
});
103+
104+
// Verify the session key is in the list of active signers
105+
const isSessionKeyActive = signers
106+
.map((s) => s.signer)
107+
.includes(sessionKeyAccountAddress);
108+
109+
console.log("Session key is active:", isSessionKeyActive);
110+
console.log("All active signers:", signers.map((s) => s.signer));
111+
```
112+
113+
## Step 5: Create Engine Server Wallet
114+
115+
Set up an Engine server wallet using the session key for transaction execution:
116+
117+
```typescript
118+
const serverWallet = Engine.serverWallet({
119+
address: sessionKeyAccountAddress,
120+
chain: sepolia,
121+
client: client,
122+
executionOptions: {
123+
entrypointVersion: "0.6", // ERC-4337 entrypoint version
124+
signerAddress: sessionKeyAccountAddress,
125+
smartAccountAddress: smartAccount.address,
126+
type: "ERC4337",
127+
},
128+
vaultAccessToken: process.env.VAULT_TOKEN as string, // Your vault access token
129+
});
130+
```
131+
132+
### Execution Options
133+
134+
- `entrypointVersion`: The ERC-4337 entrypoint version to use
135+
- `signerAddress`: The session key address that will sign transactions
136+
- `smartAccountAddress`: The smart account address that will execute transactions
137+
- `type`: The account abstraction type (ERC4337)
138+
139+
## Step 6: Execute Transactions
140+
141+
Now you can execute transactions using the session key:
142+
143+
```typescript
144+
const tx = await sendTransaction({
145+
account: serverWallet,
146+
transaction: {
147+
chain: sepolia,
148+
client: client,
149+
to: targetAddress,
150+
value: 0n, // Amount in wei (0 for no ETH transfer)
151+
// data: "0x...", // Optional: contract call data
152+
},
153+
});
154+
155+
console.log("Transaction sent:", tx.transactionHash);
156+
```
157+
158+
## Complete Example
159+
160+
Here's a complete example putting it all together:
161+
162+
```typescript
163+
import {
164+
generateAccount,
165+
smartWallet,
166+
sendTransaction,
167+
getContract,
168+
createThirdwebClient
169+
} from "thirdweb";
170+
import { sepolia } from "thirdweb/chains";
171+
import { getAllActiveSigners } from "thirdweb/extensions/erc4337";
172+
import { Engine } from "thirdweb/engine";
173+
174+
async function executeTransactionWithSessionKey() {
175+
// Configuration
176+
const client = createThirdwebClient({
177+
clientId: "your-client-id",
178+
secretKey: "your-secret-key"
179+
});
180+
181+
const sessionKeyAccountAddress = "0x..."; // Your session key address
182+
const targetAddress = "0x..."; // Target address for transaction
183+
184+
try {
185+
// Step 1: Create personal account
186+
const personalAccount = await generateAccount({ client });
187+
188+
// Step 2: Configure smart wallet
189+
const smart = smartWallet({
190+
chain: sepolia,
191+
sessionKey: {
192+
address: sessionKeyAccountAddress,
193+
permissions: {
194+
approvedTargets: "*",
195+
},
196+
},
197+
sponsorGas: true,
198+
});
199+
200+
// Step 3: Connect smart account
201+
const smartAccount = await smart.connect({
202+
client,
203+
personalAccount,
204+
});
205+
206+
// Step 4: Verify session key
207+
const signers = await getAllActiveSigners({
208+
contract: getContract({
209+
address: smartAccount.address,
210+
chain: sepolia,
211+
client,
212+
}),
213+
});
214+
215+
const isSessionKeyActive = signers
216+
.map((s) => s.signer)
217+
.includes(sessionKeyAccountAddress);
218+
219+
if (!isSessionKeyActive) {
220+
throw new Error("Session key is not active");
221+
}
222+
223+
// Step 5: Create server wallet
224+
const serverWallet = Engine.serverWallet({
225+
address: sessionKeyAccountAddress,
226+
chain: sepolia,
227+
client,
228+
executionOptions: {
229+
entrypointVersion: "0.6",
230+
signerAddress: sessionKeyAccountAddress,
231+
smartAccountAddress: smartAccount.address,
232+
type: "ERC4337",
233+
},
234+
vaultAccessToken: process.env.VAULT_TOKEN as string,
235+
});
236+
237+
// Step 6: Execute transaction
238+
const tx = await sendTransaction({
239+
account: serverWallet,
240+
transaction: {
241+
chain: sepolia,
242+
client,
243+
to: targetAddress,
244+
value: 0n,
245+
},
246+
});
247+
248+
console.log("Transaction successful:", tx.transactionHash);
249+
return tx;
250+
251+
} catch (error) {
252+
console.error("Error executing transaction:", error);
253+
throw error;
254+
}
255+
}
256+
257+
// Execute the function
258+
executeTransactionWithSessionKey()
259+
.then((tx) => console.log("Done!", tx.transactionHash))
260+
.catch((error) => console.error("Failed:", error));
261+
```
262+
263+
## Security Considerations
264+
265+
- **Session Key Storage**: Store session keys securely, preferably in a vault system
266+
- **Permission Scope**: Limit session key permissions to only necessary targets
267+
- **Key Rotation**: Regularly rotate session keys for enhanced security
268+
- **Monitoring**: Monitor session key usage for suspicious activity
269+
270+
## Troubleshooting
271+
272+
### Common Issues
273+
274+
1. **Session key not active**: Ensure the session key is properly registered with the smart account
275+
2. **Permission denied**: Check that the target address is included in `approvedTargets`
276+
3. **Gas estimation failed**: Verify that gas sponsorship is properly configured
277+
4. **Vault token invalid**: Ensure your vault access token is valid and has proper permissions
278+
279+
### Error Handling
280+
281+
Always wrap your session key operations in try-catch blocks:
282+
283+
```typescript
284+
try {
285+
const tx = await sendTransaction({
286+
account: serverWallet,
287+
transaction: {
288+
chain: sepolia,
289+
client,
290+
to: targetAddress,
291+
value: 0n,
292+
},
293+
});
294+
} catch (error) {
295+
if (error.message.includes("permission")) {
296+
console.error("Session key lacks permission for this operation");
297+
} else if (error.message.includes("gas")) {
298+
console.error("Gas estimation or sponsorship failed");
299+
} else {
300+
console.error("Transaction failed:", error);
301+
}
302+
}
303+
```
304+
305+
## Next Steps
306+
307+
- Learn more about [Smart Wallets](/engine/v3/configure-wallets/server-wallets)
308+
- Explore [Engine API Reference](https://engine.thirdweb.com/reference)
309+
- Check out the [TypeScript SDK](/references/typescript/v5/serverWallet) documentation

apps/portal/src/app/engine/v3/sidebar.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
ShieldQuestionIcon,
1010
WalletIcon,
1111
WrenchIcon,
12+
BookOpenIcon,
1213
} from "lucide-react";
1314
import type { SideBar } from "@/components/Layouts/DocLayout";
1415

@@ -51,6 +52,16 @@ export const sidebar: SideBar = {
5152
],
5253
name: "Configure Wallets",
5354
},
55+
{
56+
icon: <BookOpenIcon />,
57+
links: [
58+
{
59+
href: `${engineV3Slug}/guides/session-keys`,
60+
name: "Session Keys",
61+
},
62+
],
63+
name: "Guides",
64+
},
5465
{
5566
href: "https://engine.thirdweb.com/reference",
5667
icon: <BracesIcon />,

0 commit comments

Comments
 (0)