@zerodev/sdk 4.0.26 → 4.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -693
- package/dist/cjs/kernel-zerodev/api/index.d.ts +2 -0
- package/dist/cjs/kernel-zerodev/api/index.js +18 -1
- package/dist/cjs/kernel-zerodev/api/index.js.map +1 -1
- package/dist/cjs/kernel-zerodev/owner/passkey/createPasskeyOwner.js.map +1 -1
- package/dist/cjs/kernel-zerodev/owner/passkey/exceptions.js +1 -1
- package/dist/cjs/kernel-zerodev/owner/passkey/exceptions.js.map +1 -1
- package/dist/cjs/kernel-zerodev/owner/passkey/getAutocompletePasskeyOwner.js +3 -3
- package/dist/cjs/kernel-zerodev/owner/passkey/getAutocompletePasskeyOwner.js.map +1 -1
- package/dist/cjs/kernel-zerodev/owner/passkey/getPasskeyOwner.d.ts +1 -1
- package/dist/cjs/kernel-zerodev/owner/passkey/getPasskeyOwner.js +4 -2
- package/dist/cjs/kernel-zerodev/owner/passkey/getPasskeyOwner.js.map +1 -1
- package/dist/cjs/kernel-zerodev/owner/passkey/index.d.ts +1 -1
- package/dist/cjs/kernel-zerodev/owner/passkey/index.js.map +1 -1
- package/dist/cjs/kernel-zerodev/owner/passkey/utils.js +2 -2
- package/dist/cjs/kernel-zerodev/owner/passkey/utils.js.map +1 -1
- package/dist/cjs/kernel-zerodev/provider.js +2 -2
- package/dist/cjs/kernel-zerodev/provider.js.map +1 -1
- package/dist/cjs/kernel-zerodev/validator/recovery-validator.d.ts +8 -5
- package/dist/cjs/kernel-zerodev/validator/recovery-validator.js +50 -9
- package/dist/cjs/kernel-zerodev/validator/recovery-validator.js.map +1 -1
- package/dist/cjs/kernel-zerodev/validator-provider/recovery-provider.js +20 -32
- package/dist/cjs/kernel-zerodev/validator-provider/recovery-provider.js.map +1 -1
- package/dist/esm/kernel-zerodev/api/index.d.ts +2 -0
- package/dist/esm/kernel-zerodev/api/index.js +16 -0
- package/dist/esm/kernel-zerodev/api/index.js.map +1 -1
- package/dist/esm/kernel-zerodev/owner/passkey/createPasskeyOwner.js.map +1 -1
- package/dist/esm/kernel-zerodev/owner/passkey/exceptions.js +1 -1
- package/dist/esm/kernel-zerodev/owner/passkey/exceptions.js.map +1 -1
- package/dist/esm/kernel-zerodev/owner/passkey/getAutocompletePasskeyOwner.js +3 -3
- package/dist/esm/kernel-zerodev/owner/passkey/getAutocompletePasskeyOwner.js.map +1 -1
- package/dist/esm/kernel-zerodev/owner/passkey/getPasskeyOwner.d.ts +1 -1
- package/dist/esm/kernel-zerodev/owner/passkey/getPasskeyOwner.js +4 -2
- package/dist/esm/kernel-zerodev/owner/passkey/getPasskeyOwner.js.map +1 -1
- package/dist/esm/kernel-zerodev/owner/passkey/index.d.ts +1 -1
- package/dist/esm/kernel-zerodev/owner/passkey/index.js +1 -1
- package/dist/esm/kernel-zerodev/owner/passkey/index.js.map +1 -1
- package/dist/esm/kernel-zerodev/owner/passkey/utils.js +2 -2
- package/dist/esm/kernel-zerodev/owner/passkey/utils.js.map +1 -1
- package/dist/esm/kernel-zerodev/provider.js +2 -2
- package/dist/esm/kernel-zerodev/provider.js.map +1 -1
- package/dist/esm/kernel-zerodev/validator/recovery-validator.d.ts +8 -5
- package/dist/esm/kernel-zerodev/validator/recovery-validator.js +52 -11
- package/dist/esm/kernel-zerodev/validator/recovery-validator.js.map +1 -1
- package/dist/esm/kernel-zerodev/validator-provider/recovery-provider.js +23 -32
- package/dist/esm/kernel-zerodev/validator-provider/recovery-provider.js.map +1 -1
- package/dist/types/kernel-zerodev/api/index.d.ts +2 -0
- package/dist/types/kernel-zerodev/api/index.d.ts.map +1 -1
- package/dist/types/kernel-zerodev/owner/passkey/exceptions.d.ts.map +1 -1
- package/dist/types/kernel-zerodev/owner/passkey/getAutocompletePasskeyOwner.d.ts.map +1 -1
- package/dist/types/kernel-zerodev/owner/passkey/getPasskeyOwner.d.ts +1 -1
- package/dist/types/kernel-zerodev/owner/passkey/getPasskeyOwner.d.ts.map +1 -1
- package/dist/types/kernel-zerodev/owner/passkey/index.d.ts +1 -1
- package/dist/types/kernel-zerodev/owner/passkey/utils.d.ts.map +1 -1
- package/dist/types/kernel-zerodev/validator/recovery-validator.d.ts +8 -5
- package/dist/types/kernel-zerodev/validator/recovery-validator.d.ts.map +1 -1
- package/dist/types/kernel-zerodev/validator-provider/recovery-provider.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/kernel-zerodev/api/index.ts +27 -0
- package/src/kernel-zerodev/owner/passkey/createPasskeyOwner.ts +4 -4
- package/src/kernel-zerodev/owner/passkey/exceptions.ts +2 -2
- package/src/kernel-zerodev/owner/passkey/getAutocompletePasskeyOwner.ts +11 -9
- package/src/kernel-zerodev/owner/passkey/getPasskeyOwner.ts +5 -3
- package/src/kernel-zerodev/owner/passkey/index.ts +1 -1
- package/src/kernel-zerodev/owner/passkey/utils.ts +11 -6
- package/src/kernel-zerodev/provider.ts +2 -2
- package/src/kernel-zerodev/validator/recovery-validator.ts +59 -12
- package/src/kernel-zerodev/validator-provider/recovery-provider.ts +38 -36
package/README.md
CHANGED
|
@@ -2,696 +2,4 @@
|
|
|
2
2
|
|
|
3
3
|
SDK for [ZeroDev](https://docs.zerodev.app/), based on [Kernel](https://github.com/zerodevapp/kernel).
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Follow the instructions below to install the packages.
|
|
8
|
-
|
|
9
|
-
via `yarn`
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
yarn add @zerodev/sdk
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
via `npm`
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
npm i -s @zerodev/sdk
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Example Usage to Interact with [Kernel Accounts](https://github.com/zerodevapp/kernel/blob/main/src/Kernel.sol)
|
|
22
|
-
|
|
23
|
-
### Basic Usage
|
|
24
|
-
|
|
25
|
-
```ts
|
|
26
|
-
import { ECDSAValidator } from "@zerodev/sdk";
|
|
27
|
-
import { LocalAccountSigner } from "@alchemy/aa-core";
|
|
28
|
-
|
|
29
|
-
// 1. define the EOA owner of the Smart Account
|
|
30
|
-
// This is just one exapmle of how to interact with EOAs, feel free to use any other interface
|
|
31
|
-
const owner = LocalAccountSigner.privateKeyToAccountSigner(PRIVATE_KEY);
|
|
32
|
-
|
|
33
|
-
// 2. Create a ZeroDev Provider
|
|
34
|
-
let ecdsaProvider = await ECDSAProvider.init({
|
|
35
|
-
projectId, // zeroDev projectId
|
|
36
|
-
owner,
|
|
37
|
-
// Optional: pass the paymasterConfig to use the verifying paymaster
|
|
38
|
-
// opts: {
|
|
39
|
-
// paymasterConfig: {
|
|
40
|
-
// policy: "VERIFYING_PAYMASTER"
|
|
41
|
-
// }
|
|
42
|
-
// }
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// 3. send a UserOperation
|
|
46
|
-
const { hash } = await ecdsaProvider.sendUserOperation({
|
|
47
|
-
target: "0xTargetAddress",
|
|
48
|
-
data: "0xcallData",
|
|
49
|
-
value: 0n, // value: bigint or undefined
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// 4. Wait for UserOp
|
|
53
|
-
const tx = await ecdsaProvider.waitForUserOperationTransaction(
|
|
54
|
-
result.hash as Hex
|
|
55
|
-
);
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### Batch Transactions
|
|
59
|
-
|
|
60
|
-
```ts
|
|
61
|
-
const { hash } = await ecdsaProvider.sendUserOperation([
|
|
62
|
-
{
|
|
63
|
-
target: "0xTargetAddress1",
|
|
64
|
-
data: "0xcallData1",
|
|
65
|
-
value: 0n, // value: bigint or undefined
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
target: "0xTargetAddress2",
|
|
69
|
-
data: "0xcallData2",
|
|
70
|
-
value: 0n, // value: bigint or undefined
|
|
71
|
-
},
|
|
72
|
-
]);
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### Optional params for ValidatorProvider:
|
|
76
|
-
|
|
77
|
-
| Option | Usage | Type | Default |
|
|
78
|
-
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------- | -------------------------------------------------------------------------------- |
|
|
79
|
-
| bundlerProvider | Bundler Provider | "ALCHEMY", "STACKUP", "PIMLICO" | "STACKUP" |
|
|
80
|
-
| usePaymaster | Use paymaster to send userOps | boolean | true |
|
|
81
|
-
| opts:paymasterConfig:paymasterProvider | Paymaster Provider | "ALCHEMY", "STACKUP", "PIMLICO" | "STACKUP" |
|
|
82
|
-
| opts:paymasterConfig:onlySendSponsoredTransaction | Only send sponsored transaction and revert if somehow paymaster fails | boolean | false |
|
|
83
|
-
| opts:paymasterConfig:policy | Paymaster policy | "TOKEN_PAYMASTER", "VERIFYING_PAYMASTER" | "VERIFYING_PAYMASTER" |
|
|
84
|
-
| opts:paymasterConfig:gasToken | ERC20 token to use for gas fees in case of "TOKEN_PAYMASTER" | "USDC", "PEPE", "TEST_ERC20" | (Required) |
|
|
85
|
-
| opts:providerConfig:rpcUrl | Custom RPC URL for the bundler provider | string | "https://v0-6-meta-bundler.onrender.com" |
|
|
86
|
-
| opts:providerConfig:opts:txMaxRetries | The maximum number of times to try fetching a transaction receipt before giving up | number | 5 |
|
|
87
|
-
| opts:providerConfig:opts:txRetryIntervalMs | The interval in milliseconds to wait between retries while waiting for tx receipts | number | 2000 |
|
|
88
|
-
| opts:providerConfig:opts:minPriorityFeePerBid | used when computing the fees for a user operation | bigint | 100_000_000n, [Chain-wise defaults](/packages/core/src/provider/base.ts#L61-L64) |
|
|
89
|
-
| opts:providerConfig:opts:sendTxMaxRetries | The maximum number of times to try sending a transaction before giving up | number | 3 |
|
|
90
|
-
| opts:providerConfig:opts:sendTxRetryIntervalMs | The interval in milliseconds to wait between retries while sending a transaction | number | 180000 |
|
|
91
|
-
| opts:accountConfig:index | Index variable to be used alongwith with owner address and validator data while calculating counterfactual address | number | 1000 |
|
|
92
|
-
| [TODO] include other options | | | |
|
|
93
|
-
|
|
94
|
-
### Pay gas in ERC20
|
|
95
|
-
|
|
96
|
-
ZeroDev currently supports:
|
|
97
|
-
|
|
98
|
-
- `USDC`
|
|
99
|
-
- `PEPE` (mainnet only)
|
|
100
|
-
- `DAI` (upcoming)
|
|
101
|
-
|
|
102
|
-
Just pass the `paymasterConfig` to `createZeroDevProvider` function while creating the provider.
|
|
103
|
-
|
|
104
|
-
```ts
|
|
105
|
-
let ecdsaProvider = await ECDSAProvider.init({
|
|
106
|
-
projectId, // zeroDev projectId
|
|
107
|
-
owner,
|
|
108
|
-
opts: {
|
|
109
|
-
paymasterConfig: {
|
|
110
|
-
policy: "TOKEN_PAYMASTER",
|
|
111
|
-
gasToken: "TEST_ERC20",
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
});
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Change Kernel Account Owner in ECDSAValidator
|
|
118
|
-
|
|
119
|
-
```ts
|
|
120
|
-
// 1. Create a ECDSAValidatorProvider
|
|
121
|
-
const ecdsaProvider = await ECDSAProvider.init({
|
|
122
|
-
projectId: "c73037ef-8c0b-48be-a581-1f3d161151d3",
|
|
123
|
-
owner,
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// 2. Change the owner of the Kernel Account
|
|
127
|
-
const { hash } = await ecdsaProvider.changeOwner(<NEW_OWNER_ADDRESS>);
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Via `ethers` Signer
|
|
131
|
-
|
|
132
|
-
```ts
|
|
133
|
-
import { Wallet } from "@ethersproject/wallet";
|
|
134
|
-
import {
|
|
135
|
-
ZeroDevEthersProvider,
|
|
136
|
-
convertEthersSignerToAccountSigner,
|
|
137
|
-
} from "@zerodev/sdk";
|
|
138
|
-
|
|
139
|
-
// 1. Create an ethers Wallet
|
|
140
|
-
const owner = Wallet.fromMnemonic(OWNER_MNEMONIC);
|
|
141
|
-
|
|
142
|
-
// 2. Create a ZeroDev ZeroDevEthersProvider passing the ethers Wallet as the signer
|
|
143
|
-
const provider = await ZeroDevEthersProvider.init("ECDSA", {
|
|
144
|
-
projectId, // zeroDev projectId
|
|
145
|
-
owner: convertEthersSignerToAccountSigner(owner),
|
|
146
|
-
opts: {
|
|
147
|
-
paymasterConfig: {
|
|
148
|
-
policy: "VERIFYING_PAYMASTER",
|
|
149
|
-
},
|
|
150
|
-
},
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
// 3. Get the AccountSigner adapter of ethers signer
|
|
154
|
-
const signer = provider.getAccountSigner();
|
|
155
|
-
|
|
156
|
-
// 4. send a UserOperation
|
|
157
|
-
const { hash } = await signer.sendUserOperation({
|
|
158
|
-
target: "0xTargetAddress",
|
|
159
|
-
data: "0xcallData",
|
|
160
|
-
value: 0n, // value: bigint or undefined
|
|
161
|
-
});
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Via `viem` using `custom` transport which supports EIP-1193 providers
|
|
165
|
-
|
|
166
|
-
```ts
|
|
167
|
-
import { createWalletClient, custom } from "viem";
|
|
168
|
-
import { polygonMumbai } from "viem/chains";
|
|
169
|
-
import {
|
|
170
|
-
ECDSAProvider,
|
|
171
|
-
convertWalletClientToAccountSigner,
|
|
172
|
-
} from "@zerodev/sdk";
|
|
173
|
-
|
|
174
|
-
// 1. Create a Viem Wallet Client using the custom transport
|
|
175
|
-
const client = createWalletClient({
|
|
176
|
-
chain: polygonMumbai,
|
|
177
|
-
transport: custom(window.ethereum),
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
// 2. Create a ZeroDev ECDSAProvider passing the Viem Wallet Client as the signer
|
|
181
|
-
let ecdsaProvider = await ECDSAProvider.init({
|
|
182
|
-
projectId, // zeroDev projectId
|
|
183
|
-
owner: convertWalletClientToAccountSigner(client),
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
// 3. send a UserOperation
|
|
187
|
-
const { hash } = await ecdsaProvider.sendUserOperation({
|
|
188
|
-
target: "0xTargetAddress",
|
|
189
|
-
data: "0xcallData",
|
|
190
|
-
value: 0n, // value: bigint or undefined
|
|
191
|
-
});
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### Using [Magic](https://magic.link/)
|
|
195
|
-
|
|
196
|
-
```ts
|
|
197
|
-
import { ECDSAProvider, getRPCProviderOwner } from "@zerodev/sdk";
|
|
198
|
-
import { Magic } from "magic-sdk";
|
|
199
|
-
|
|
200
|
-
const magic = new Magic("MAGIC_API_KEY", {
|
|
201
|
-
// magic config...
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
let ecdsaProvider = await ECDSAProvider.init({
|
|
205
|
-
projectId, // zeroDev projectId
|
|
206
|
-
owner: getRPCProviderOwner(magic.rpcProvider),
|
|
207
|
-
});
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Using [Web3Auth](https://web3auth.io/)
|
|
211
|
-
|
|
212
|
-
```ts
|
|
213
|
-
import { ECDSAProvider, getRPCProviderOwner } from "@zerodev/sdk";
|
|
214
|
-
import { Web3Auth } from "@web3auth/modal";
|
|
215
|
-
|
|
216
|
-
const web3auth = new Web3Auth({
|
|
217
|
-
// web3auth config...
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
await web3auth.initModal();
|
|
221
|
-
|
|
222
|
-
web3auth.connect();
|
|
223
|
-
|
|
224
|
-
let ecdsaProvider = await ECDSAProvider.init({
|
|
225
|
-
projectId, // zeroDev projectId
|
|
226
|
-
owner: getRPCProviderOwner(web3auth.provider),
|
|
227
|
-
});
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
## Using validator plugins
|
|
231
|
-
|
|
232
|
-
### Kill Switch Validator
|
|
233
|
-
|
|
234
|
-
A designated guardian can "turn off" the account and set a new owner.
|
|
235
|
-
|
|
236
|
-
```ts
|
|
237
|
-
import { constants } from "@zerodev/sdk";
|
|
238
|
-
// 1. Get the default ecdsa validator provider
|
|
239
|
-
const ecdsaProvider = await ECDSAProvider.init({
|
|
240
|
-
projectId, // zeroDev projectId
|
|
241
|
-
owner,
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
// 2. Deploy the Kernel account if not already by sending an empty transaction
|
|
245
|
-
let result = await ecdsaProvider.sendUserOperation({
|
|
246
|
-
target: "0xADDRESS",
|
|
247
|
-
data: "0x",
|
|
248
|
-
});
|
|
249
|
-
await ecdsaProvider.waitForUserOperationTransaction(result.hash as Hex);
|
|
250
|
-
|
|
251
|
-
// 3. Initialize required variables
|
|
252
|
-
const accountAddress = await ecdsaProvider.getAccount().getAddress();
|
|
253
|
-
const selector = getFunctionSelector("toggleKillSwitch()");
|
|
254
|
-
|
|
255
|
-
// 4. Initialize KillSwitch Validator Provider
|
|
256
|
-
const blockerKillSwitchProvider = await KillSwitchProvider.init({
|
|
257
|
-
projectId, // zeroDev projectId
|
|
258
|
-
guardian, // Guardian signer
|
|
259
|
-
delaySeconds: 1000, // Delay in seconds
|
|
260
|
-
opts: {
|
|
261
|
-
accountConfig: {
|
|
262
|
-
accountAddress,
|
|
263
|
-
},
|
|
264
|
-
validatorConfig: {
|
|
265
|
-
mode: ValidatorMode.plugin,
|
|
266
|
-
executor: constants.KILL_SWITCH_ACTION, // Address of the executor contract
|
|
267
|
-
selector, // Function selector in the executor contract to toggleKillSwitch()
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
// 5. Get enable signature from default ECDSA validator provider and set it in KillSwitch Validator Provider
|
|
273
|
-
const enableSig = await ecdsaProvider
|
|
274
|
-
.getValidator()
|
|
275
|
-
.approveExecutor(
|
|
276
|
-
accountAddress,
|
|
277
|
-
selector,
|
|
278
|
-
constants.KILL_SWITCH_ACTION,
|
|
279
|
-
0,
|
|
280
|
-
0,
|
|
281
|
-
blockerKillSwitchProvider.getValidator()
|
|
282
|
-
);
|
|
283
|
-
|
|
284
|
-
blockerKillSwitchProvider.getValidator().setEnableSignature(enableSig);
|
|
285
|
-
|
|
286
|
-
// 6. Send the transaction to turn on the KillSwitch
|
|
287
|
-
result = await blockerKillSwitchProvider.sendUserOperation({
|
|
288
|
-
target: accountAddress,
|
|
289
|
-
data: selector,
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
await blockerKillSwitchProvider.waitForUserOperationTransaction(
|
|
293
|
-
result.hash as Hex
|
|
294
|
-
);
|
|
295
|
-
|
|
296
|
-
// 7. Get KillSwitch validator provider instance with SUDO mode
|
|
297
|
-
const sudoModeKillSwitchProvider = await KillSwitchProvider.init({
|
|
298
|
-
projectId, // zeroDev projectId
|
|
299
|
-
guardian,
|
|
300
|
-
delaySeconds: 0,
|
|
301
|
-
opts: {
|
|
302
|
-
accountConfig: {
|
|
303
|
-
accountAddress,
|
|
304
|
-
},
|
|
305
|
-
validatorConfig: {
|
|
306
|
-
mode: ValidatorMode.sudo,
|
|
307
|
-
executor: KILL_SWITCH_ACTION,
|
|
308
|
-
selector,
|
|
309
|
-
},
|
|
310
|
-
},
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
// 8. Send transaction to change the owner address
|
|
314
|
-
const changeOwnerdata = await ecdsaProvider.getEncodedEnableData(
|
|
315
|
-
"0xNEW_OWNER_ADDRESS"
|
|
316
|
-
);
|
|
317
|
-
let result = await sudoModeKillSwitchProvider.sendUserOperation({
|
|
318
|
-
target: accountAddress,
|
|
319
|
-
data: changeOwnerdata,
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
await sudoModeKillSwitchProvider.waitForUserOperationTransaction(
|
|
323
|
-
result.hash as Hex
|
|
324
|
-
);
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
#### Force Unblock
|
|
328
|
-
|
|
329
|
-
```ts
|
|
330
|
-
let result = await sudoModeKillSwitchProvider.sendUserOperation({
|
|
331
|
-
target: accountAddress,
|
|
332
|
-
data: selector,
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
await sudoModeKillSwitchProvider.waitForUserOperationTransaction(
|
|
336
|
-
result.hash as Hash
|
|
337
|
-
);
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
<!--
|
|
341
|
-
### ERC165 Session Key Validator
|
|
342
|
-
|
|
343
|
-
```ts
|
|
344
|
-
// 1. Get the default ecdsa validator provider
|
|
345
|
-
const ecdsaProvider = await ECDSAProvider.init({
|
|
346
|
-
projectId, // zeroDev projectId
|
|
347
|
-
owner,
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
// 2. Deploy the Kernel account if not already by sending an empty transaction
|
|
351
|
-
let result = await ecdsaProvider.sendUserOperation({
|
|
352
|
-
target: "0xADDRESS",
|
|
353
|
-
data: "0x",
|
|
354
|
-
});
|
|
355
|
-
await ecdsaProvider.waitForUserOperationTransaction(result.hash as Hex);
|
|
356
|
-
|
|
357
|
-
// 3. Initialize required variables
|
|
358
|
-
const accountAddress = await ecdsaProvider.getAccount().getAddress();
|
|
359
|
-
const selector = getFunctionSelector(
|
|
360
|
-
"transferERC721Action(address, uint256, address)"
|
|
361
|
-
);
|
|
362
|
-
|
|
363
|
-
// 4. Initialize ERC165SessionKey Validator Provider
|
|
364
|
-
const erc165SessionKeyProvider = await ERC165SessionKeyProvider.init({
|
|
365
|
-
projectId, // ZeroDev projectId
|
|
366
|
-
sessionKey, // Session Key signer
|
|
367
|
-
sessionKeyData: {
|
|
368
|
-
selector, // Function selector in the executor contract to execute
|
|
369
|
-
erc165InterfaceId: "0x80ac58cd", // Supported interfaceId of the contract the executor calls
|
|
370
|
-
validAfter: 0,
|
|
371
|
-
validUntil: 0,
|
|
372
|
-
addressOffset: 16, // Address offest of the contract called by the executor in the calldata
|
|
373
|
-
},
|
|
374
|
-
opts: {
|
|
375
|
-
accountConfig: {
|
|
376
|
-
accountAddress,
|
|
377
|
-
},
|
|
378
|
-
validatorConfig: {
|
|
379
|
-
mode: ValidatorMode.plugin,
|
|
380
|
-
executor: constants.TOKEN_ACTION, // Address of the executor contract
|
|
381
|
-
selector, // Function selector in the executor contract to execute
|
|
382
|
-
},
|
|
383
|
-
},
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
// 5. Get enable signature from default ECDSA validator provider and set it in ERC165SessionKey Validator Provider
|
|
387
|
-
const enableSig = await ecdsaProvider
|
|
388
|
-
.getValidator()
|
|
389
|
-
.approveExecutor(
|
|
390
|
-
accountAddress,
|
|
391
|
-
selector,
|
|
392
|
-
constants.TOKEN_ACTION,
|
|
393
|
-
0,
|
|
394
|
-
0,
|
|
395
|
-
erc165SessionKeyProvider.getValidator()
|
|
396
|
-
);
|
|
397
|
-
|
|
398
|
-
erc165SessionKeyProvider.getValidator().setEnableSignature(enableSig);
|
|
399
|
-
|
|
400
|
-
// 6. Send the transaction
|
|
401
|
-
const { hash } = await erc165SessionKeyProvider.sendUserOperation({
|
|
402
|
-
target: accountAddress,
|
|
403
|
-
data: encodeFunctionData({
|
|
404
|
-
abi: TokenActionsAbi,
|
|
405
|
-
functionName: "transferERC721Action",
|
|
406
|
-
args: ["TOKEN_ADDRESS", "TOKEN_ID", "RECIPIENT_ADDRESS"],
|
|
407
|
-
}),
|
|
408
|
-
});
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
-->
|
|
412
|
-
|
|
413
|
-
### Session Key Validator
|
|
414
|
-
|
|
415
|
-
```ts
|
|
416
|
-
// 1. Get the default ecdsa validator provider
|
|
417
|
-
const ecdsaProvider = await ECDSAProvider.init({
|
|
418
|
-
projectId, // zeroDev projectId
|
|
419
|
-
owner,
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
// 2. Initialize SessionKey Validator Provider
|
|
423
|
-
const sessionKey = LocalAccountSigner.privateKeyToAccountSigner(<SESSION_PRIVATE_KEY>);
|
|
424
|
-
const accountAddress = await ecdsaProvider.getAccount().getAddress();
|
|
425
|
-
const sig = getFunctionSelector(
|
|
426
|
-
"transfer(address, uint256)"
|
|
427
|
-
)
|
|
428
|
-
const permissions = [
|
|
429
|
-
{
|
|
430
|
-
target: <ERC20Address>, // address of the target contract
|
|
431
|
-
valueLimit: 0, // max value the session key can use in tx
|
|
432
|
-
sig, // The function selector of the function that can be called on the target contract
|
|
433
|
-
operation: Operation.Call, // The kind of call session key can make CALL/DELEGATECALL
|
|
434
|
-
rules: [ // Parameter rules
|
|
435
|
-
{
|
|
436
|
-
condition: ParamCondition.LESS_THAN_OR_EQUAL, // The condition to check
|
|
437
|
-
offset: 32, // The offset where the param is in the calldata
|
|
438
|
-
param: pad(toHex(10000), { size: 32 }), // The value to check in condition
|
|
439
|
-
},
|
|
440
|
-
{
|
|
441
|
-
condition: ParamCondition.EQUAL,
|
|
442
|
-
offset: 0,
|
|
443
|
-
param: pad(<SPECIFIC_ADDRESS>, { size: 32 }),
|
|
444
|
-
},
|
|
445
|
-
],
|
|
446
|
-
}
|
|
447
|
-
]
|
|
448
|
-
|
|
449
|
-
const sessionKeyProvider = await SessionKeyProvider.init({
|
|
450
|
-
projectId, //ZeroDevProject
|
|
451
|
-
defaultProvider: ecdsaProvider, // Pass the ECDSAProvider as default provider
|
|
452
|
-
sessionKey, // Session Key Signer
|
|
453
|
-
sessionKeyData: {
|
|
454
|
-
validAfter: 0,
|
|
455
|
-
validUntil: 0,
|
|
456
|
-
permissions,
|
|
457
|
-
paymaster, // Paymaster Address : zeroAddress means accept userOp without paymaster, oneAddress means reject userOp without paymaster, other address means accept userOp with paymaster with the address
|
|
458
|
-
}
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
// 3. Send the transaction
|
|
462
|
-
const { hash } = await sessionKeyProvider.sendUserOperation({
|
|
463
|
-
target: ERC20Address,
|
|
464
|
-
data: encodeFunctionData({
|
|
465
|
-
abi: TEST_ERC20Abi,
|
|
466
|
-
functionName: "transfer",
|
|
467
|
-
args: ["RECIPIENT_ADDRESS", "AMOUNT_TO_TRANSFER"],
|
|
468
|
-
}),
|
|
469
|
-
});
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
#### Creating Session Key on the server and using it on the client side
|
|
473
|
-
|
|
474
|
-
```ts
|
|
475
|
-
// 1. Initilize the session key provider
|
|
476
|
-
const sessionKeyProvider = await SessionKeyProvider.init({
|
|
477
|
-
projectId, //ZeroDevProject
|
|
478
|
-
defaultProvider: ecdsaProvider,
|
|
479
|
-
sessionKey, // Session Key Signer
|
|
480
|
-
sessionKeyData: {
|
|
481
|
-
validAfter: 0,
|
|
482
|
-
validUntil: 0,
|
|
483
|
-
permissions,
|
|
484
|
-
paymaster, // Paymaster Address : zeroAddress means accept userOp without paymaster, oneAddress means reject userOp without paymaster, other address means accept userOp with paymaster with the address
|
|
485
|
-
}
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
// 2. Serialize the session key params with the private key and send it to the client
|
|
489
|
-
const serializedSessionKeyParams = await sessionKeyProvider.serializeSessionKeyParams(<SESSION_PRIVATE_KEY>);
|
|
490
|
-
|
|
491
|
-
// On client side
|
|
492
|
-
// 3. Deserialize the session key params
|
|
493
|
-
const sessionKeyParams = SessionKeyProvider.deserializeSessionKeyParams(serializedSessionKeyParams);
|
|
494
|
-
|
|
495
|
-
// 4 Initialize the SessionKey Provider from the session key params
|
|
496
|
-
const sessionKeyProvider = await SessionKeyProvider.fromSessionKeyParams({
|
|
497
|
-
projectId, //ZeroDevProject
|
|
498
|
-
sessionKeyParams
|
|
499
|
-
});
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
#### Creating Session Key on the client and approving on the server
|
|
503
|
-
|
|
504
|
-
```ts
|
|
505
|
-
// On the server
|
|
506
|
-
// 1. Create an EmptyAccountSigner from the session key address sent from the client and pass to the provider
|
|
507
|
-
const sessionKey = new EmptyAccountSigner(<SESSION_KEY_ADDRESS>);
|
|
508
|
-
|
|
509
|
-
const sessionKeyProvider = await SessionKeyProvider.init({
|
|
510
|
-
projectId, //ZeroDevProject
|
|
511
|
-
defaultProvider: ecdsaProvider,
|
|
512
|
-
sessionKey,
|
|
513
|
-
sessionKeyData: {
|
|
514
|
-
validAfter: 0,
|
|
515
|
-
validUntil: 0,
|
|
516
|
-
permissions,
|
|
517
|
-
paymaster, // Paymaster Address : zeroAddress means accept userOp without paymaster, oneAddress means reject userOp without paymaster, other address means accept userOp with paymaster with the address
|
|
518
|
-
}
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
// 2. Serialize the session key params and send it to the client
|
|
522
|
-
const serializedSessionKeyParams = await sessionKeyProvider.serializeSessionKeyParams();
|
|
523
|
-
|
|
524
|
-
// On client side
|
|
525
|
-
// 3. Deserialize the session key params and pass the session private key to the object
|
|
526
|
-
const sessionKeyParams = {
|
|
527
|
-
...SessionKeyProvider.deserializeSessionKeyParams(serializedSessionKeyParams)
|
|
528
|
-
sessionPrivateKey
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
// 4. Initialize the SessionKey Provider from the session key params
|
|
532
|
-
const sessionKeyProvider = await SessionKeyProvider.fromSessionKeyParams({
|
|
533
|
-
projectId, //ZeroDevProject
|
|
534
|
-
sessionKeyParams
|
|
535
|
-
});
|
|
536
|
-
```
|
|
537
|
-
|
|
538
|
-
### Recovery Key Validator
|
|
539
|
-
|
|
540
|
-
#### Initiate the recovery and retrieve the recoveryId
|
|
541
|
-
|
|
542
|
-
```ts
|
|
543
|
-
// 1. Get the default ecdsa validator provider
|
|
544
|
-
const ecdsaProvider = await ECDSAProvider.init({
|
|
545
|
-
projectId, // zeroDev projectId
|
|
546
|
-
owner,
|
|
547
|
-
});
|
|
548
|
-
|
|
549
|
-
// 2. Initialize the Recovery Provider
|
|
550
|
-
const recoveryData = {
|
|
551
|
-
guardians: { // Guardian addresses with their weights
|
|
552
|
-
[guardianAddress]: 1,
|
|
553
|
-
[guardian2Address]: 1,
|
|
554
|
-
[guardian3Address]: 1,
|
|
555
|
-
},
|
|
556
|
-
threshold: 3,
|
|
557
|
-
delaySeconds: 0,
|
|
558
|
-
};
|
|
559
|
-
|
|
560
|
-
const recoveryProvider = await RecoveryProvider.init({
|
|
561
|
-
projectId,
|
|
562
|
-
defaultProvider: ecdsaProvider,
|
|
563
|
-
opts: {
|
|
564
|
-
validatorConfig: {
|
|
565
|
-
...recoveryData,
|
|
566
|
-
},
|
|
567
|
-
},
|
|
568
|
-
});
|
|
569
|
-
|
|
570
|
-
// 3. Enable the recovery plugin
|
|
571
|
-
const result = await recoveryProvider.enableRecovery();
|
|
572
|
-
await recoveryProvider.waitForUserOperationTransaction(
|
|
573
|
-
result.hash as Hex
|
|
574
|
-
);
|
|
575
|
-
|
|
576
|
-
// 3. Initiate the recovery
|
|
577
|
-
const recoveryId = await recoveryProvider.initiateRecovery(<NewOwnerAddress>);
|
|
578
|
-
```
|
|
579
|
-
|
|
580
|
-
#### Share recoveryId with the guardians to sign recoveryHash
|
|
581
|
-
|
|
582
|
-
```ts
|
|
583
|
-
// 1. Intialize the Recovery Provider for guardian
|
|
584
|
-
const guardian =
|
|
585
|
-
LocalAccountSigner.privateKeyToAccountSigner(<PrivateKey>);
|
|
586
|
-
const recoveryProvider = await RecoveryProvider.init({
|
|
587
|
-
projectId,
|
|
588
|
-
recoveryId,
|
|
589
|
-
opts: {
|
|
590
|
-
validatorConfig: {
|
|
591
|
-
accountSigner: guardian,
|
|
592
|
-
},
|
|
593
|
-
},
|
|
594
|
-
});
|
|
595
|
-
|
|
596
|
-
// 2. Sign the recovery hash
|
|
597
|
-
await recoveryProvider.signRecovery();
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
#### Submit the recovery request
|
|
601
|
-
|
|
602
|
-
| Anybody can submit the recovery request if they have the recoveryId
|
|
603
|
-
|
|
604
|
-
```ts
|
|
605
|
-
// 1. Initialize the recovery provider
|
|
606
|
-
const account = privateKeyToAccount(<PrivateKey>);
|
|
607
|
-
const recoveryProvider = await RecoveryProvider.init({
|
|
608
|
-
projectId,
|
|
609
|
-
recoveryId,
|
|
610
|
-
opts: {
|
|
611
|
-
validatorConfig: {
|
|
612
|
-
guardianAccountOrProvider: account,
|
|
613
|
-
},
|
|
614
|
-
},
|
|
615
|
-
});
|
|
616
|
-
|
|
617
|
-
// 2. Submit the recovery request
|
|
618
|
-
const result = await recoveryProvider.submitRecovery();
|
|
619
|
-
await recoveryProvider.waitForUserOperationTransaction(
|
|
620
|
-
result.hash as Hex
|
|
621
|
-
);
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
#### Cancel the recovery request
|
|
625
|
-
|
|
626
|
-
| Owner of the account can canel the recovery request
|
|
627
|
-
|
|
628
|
-
```ts
|
|
629
|
-
// 1. Get the default ecdsa validator provider
|
|
630
|
-
const ecdsaProvider = await ECDSAProvider.init({
|
|
631
|
-
projectId, // zeroDev projectId
|
|
632
|
-
owner,
|
|
633
|
-
});
|
|
634
|
-
|
|
635
|
-
// 2. Initialize the Recovery Provider
|
|
636
|
-
const recoveryProvider = await RecoveryProvider.init({
|
|
637
|
-
projectId,
|
|
638
|
-
defaultProvider: ecdsaProvider,
|
|
639
|
-
recoveryId,
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
// 3. Cancel the recovery
|
|
643
|
-
const result = await recoveryProvider.cancelRecovery();
|
|
644
|
-
await recoveryProvider.waitForUserOperationTransaction(result.hash as Hex);
|
|
645
|
-
```
|
|
646
|
-
|
|
647
|
-
## Components
|
|
648
|
-
|
|
649
|
-
### Core Components
|
|
650
|
-
|
|
651
|
-
The primary interfaces are the `ZeroDevProvider`, `KernelSmartContractAccount` and `KernelBaseValidator`
|
|
652
|
-
|
|
653
|
-
The `ZeroDevProvider` is an ERC-1193 compliant Provider built on top of Alchemy's `SmartAccountProvider`
|
|
654
|
-
|
|
655
|
-
1. `sendUserOperation` -- this takes in `target`, `callData`, and an optional `value` which then constructs a UserOperation (UO), sends it, and returns the `hash` of the UO. It handles estimating gas, fetching fee data, (optionally) requesting paymasterAndData, and lastly signing. This is done via a middleware stack that runs in a specific order. The middleware order is `getDummyPaymasterData` => `estimateGas` => `getFeeData` => `getPaymasterAndData`. The paymaster fields are set to `0x` by default. They can be changed using `provider.withPaymasterMiddleware`.
|
|
656
|
-
2. `sendTransaction` -- this takes in a traditional Transaction Request object which then gets converted into a UO. Currently, the only data being used from the Transaction Request object is `from`, `to`, `data` and `value`. Support for other fields is coming soon.
|
|
657
|
-
|
|
658
|
-
`KernelSmartContractAccount` is Kernel's implementation of `BaseSmartContractAccount`. 6 main methods are implemented
|
|
659
|
-
|
|
660
|
-
1. `getDummySignature` -- this method should return a signature that will not `revert` during validation. It does not have to pass validation, just not cause the contract to revert. This is required for gas estimation so that the gas estimate are accurate.
|
|
661
|
-
2. `encodeExecute` -- this method should return the abi encoded function data for a call to your contract's `execute` method
|
|
662
|
-
3. `encodeExecuteDelegate` -- this method should return the abi encoded function data for a `delegate` call to your contract's `execute` method
|
|
663
|
-
4. `signMessage` -- this is used to sign UO Hashes
|
|
664
|
-
5. `signWithEip6492` -- this should return an ERC-191 and EIP-6492 compliant message used to personal_sign
|
|
665
|
-
6. `getAccountInitCode` -- this should return the init code that will be used to create an account if one does not exist. Usually this is the concatenation of the account's factory address and the abi encoded function data of the account factory's `createAccount` method.
|
|
666
|
-
|
|
667
|
-
The `KernelBaseValidator` is a plugin that modify how transactions are validated. It allows for extension and implementation of arbitrary validation logic. It implements 3 main methods:
|
|
668
|
-
|
|
669
|
-
1. `getAddress` -- this returns the address of the validator
|
|
670
|
-
2. `getOwner` -- this returns the eligible signer's address for the active smart wallet
|
|
671
|
-
3. `getSignature` -- this method signs the userop hash using signer object and then concats additional params based on validator mode.
|
|
672
|
-
|
|
673
|
-
## Contributing
|
|
674
|
-
|
|
675
|
-
1. clone the repo
|
|
676
|
-
2. run `yarn`
|
|
677
|
-
3. Make changes to packages
|
|
678
|
-
|
|
679
|
-
### Adding new custom validator plugin
|
|
680
|
-
|
|
681
|
-
1. Create a new validator class that extends `KernelBaseValidator` similar to [`ECDSAValidator`](`packages/accounts/src/kernel-zerodev/validator/ecdsa-validator.ts`).
|
|
682
|
-
|
|
683
|
-
2. Make sure to pass the `validatorAddress` of your validator to the `KernelBaseValidator` base class.
|
|
684
|
-
|
|
685
|
-
3. Create a new validator provider that extends `ValidatorProvider` similar to [`ECDSAValidatorProvider`](`packages/accounts/src/kernel-zerodev/validator-provider/ecdsa-provider.ts`).
|
|
686
|
-
|
|
687
|
-
4. Use the newly created validator provider as per above examples.
|
|
688
|
-
|
|
689
|
-
#### `KernelBaseValidator` methods to be implemented in your validator class
|
|
690
|
-
|
|
691
|
-
- `signer()` -- this method should return the signer as per your validator's implementation. For example, for Multi-Signature validator, this method should return one of the owner signer which is connected to the multisig wallet contract and currently using the DAPP.
|
|
692
|
-
- `getOwner()` -- this method should return the address of the signer. For example, for Multi-Signature validator, this method should return the address of the signer which is connected to the multisig wallet contract and currently using the DAPP.
|
|
693
|
-
- `getEnableData()` -- this method should return the bytes data for the `enable` method of your validator contract. For example, in ECDSA validator, this method returns `owner` address as bytes data. This method is used to enable the validator for the first time while creating the account wallet.
|
|
694
|
-
- `encodeEnable(enableData: Hex)` -- this method should return the abi encoded function data for the `enable` method of your validator contract. For example, in ECDSA validator, this method returns the abi encoded function data for the `enable` method with owner address as bytes param.
|
|
695
|
-
- `encodeDisable(disableData: Hex)` -- this method should return the abi encoded function data for the `disable` method of your validator contract. For example, in ECDSA validator, this method returns the abi encoded function data for the `disable` method with empty bytes param since ECDSA Validator doesn't require any param.
|
|
696
|
-
- `signMessage(message: Uint8Array | string | Hex)` -- this method should return the signature of the message using the connected signer.
|
|
697
|
-
- `signUserOp(userOp: UserOperationRequest)` -- this method should return the signature of the userOp hash using the connected signer.
|
|
5
|
+
Documentation available [here](https://github.com/zerodevapp/sdk#zerodev-sdk).
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Hex } from "viem";
|
|
1
2
|
export declare const getChainId: (projectId: string, backendUrl?: string) => Promise<number | undefined>;
|
|
2
3
|
export declare const getRecoveryData: (recoveryId: string) => Promise<any>;
|
|
4
|
+
export declare const postRecoveryData: (enableData: Hex, scwAddress: Hex, recoveryConfig: string) => Promise<string | undefined>;
|
|
3
5
|
export declare const setSignatures: (recoveryId: string, signatures: string) => Promise<any>;
|