@zerodev/sdk 4.2.2 → 4.3.0
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/dist/cjs/kernel-zerodev/abis/SessionKeyValidatorAbi.d.ts +58 -4
- package/dist/cjs/kernel-zerodev/abis/SessionKeyValidatorAbi.js +75 -4
- package/dist/cjs/kernel-zerodev/abis/SessionKeyValidatorAbi.js.map +1 -1
- package/dist/cjs/kernel-zerodev/client/create-client.js +1 -0
- package/dist/cjs/kernel-zerodev/client/create-client.js.map +1 -1
- package/dist/cjs/kernel-zerodev/constants.d.ts +1 -1
- package/dist/cjs/kernel-zerodev/constants.js +2 -2
- package/dist/cjs/kernel-zerodev/constants.js.map +1 -1
- package/dist/cjs/kernel-zerodev/middleware/gas-estimator.d.ts +4 -0
- package/dist/cjs/kernel-zerodev/middleware/gas-estimator.js +15 -7
- package/dist/cjs/kernel-zerodev/middleware/gas-estimator.js.map +1 -1
- package/dist/cjs/kernel-zerodev/validator/base.d.ts +1 -1
- package/dist/cjs/kernel-zerodev/validator/base.js +3 -3
- package/dist/cjs/kernel-zerodev/validator/base.js.map +1 -1
- package/dist/cjs/kernel-zerodev/validator/session-key-validator.d.ts +18 -7
- package/dist/cjs/kernel-zerodev/validator/session-key-validator.js +117 -63
- package/dist/cjs/kernel-zerodev/validator/session-key-validator.js.map +1 -1
- package/dist/cjs/kernel-zerodev/validator/types.d.ts +1 -1
- package/dist/cjs/kernel-zerodev/validator/types.js.map +1 -1
- package/dist/cjs/kernel-zerodev/validator-provider/base.js +9 -0
- package/dist/cjs/kernel-zerodev/validator-provider/base.js.map +1 -1
- package/dist/esm/kernel-zerodev/abis/SessionKeyValidatorAbi.d.ts +58 -4
- package/dist/esm/kernel-zerodev/abis/SessionKeyValidatorAbi.js +75 -4
- package/dist/esm/kernel-zerodev/abis/SessionKeyValidatorAbi.js.map +1 -1
- package/dist/esm/kernel-zerodev/client/create-client.js +1 -0
- package/dist/esm/kernel-zerodev/client/create-client.js.map +1 -1
- package/dist/esm/kernel-zerodev/constants.d.ts +1 -1
- package/dist/esm/kernel-zerodev/constants.js +2 -2
- package/dist/esm/kernel-zerodev/constants.js.map +1 -1
- package/dist/esm/kernel-zerodev/middleware/gas-estimator.d.ts +4 -0
- package/dist/esm/kernel-zerodev/middleware/gas-estimator.js +15 -6
- package/dist/esm/kernel-zerodev/middleware/gas-estimator.js.map +1 -1
- package/dist/esm/kernel-zerodev/validator/base.d.ts +1 -1
- package/dist/esm/kernel-zerodev/validator/base.js +3 -3
- package/dist/esm/kernel-zerodev/validator/base.js.map +1 -1
- package/dist/esm/kernel-zerodev/validator/session-key-validator.d.ts +18 -7
- package/dist/esm/kernel-zerodev/validator/session-key-validator.js +118 -64
- package/dist/esm/kernel-zerodev/validator/session-key-validator.js.map +1 -1
- package/dist/esm/kernel-zerodev/validator/types.d.ts +1 -1
- package/dist/esm/kernel-zerodev/validator/types.js.map +1 -1
- package/dist/esm/kernel-zerodev/validator-provider/base.js +9 -0
- package/dist/esm/kernel-zerodev/validator-provider/base.js.map +1 -1
- package/dist/types/kernel-zerodev/abis/SessionKeyValidatorAbi.d.ts +58 -4
- package/dist/types/kernel-zerodev/abis/SessionKeyValidatorAbi.d.ts.map +1 -1
- package/dist/types/kernel-zerodev/client/create-client.d.ts.map +1 -1
- package/dist/types/kernel-zerodev/constants.d.ts +1 -1
- package/dist/types/kernel-zerodev/middleware/gas-estimator.d.ts +4 -0
- package/dist/types/kernel-zerodev/middleware/gas-estimator.d.ts.map +1 -1
- package/dist/types/kernel-zerodev/validator/base.d.ts +1 -1
- package/dist/types/kernel-zerodev/validator/base.d.ts.map +1 -1
- package/dist/types/kernel-zerodev/validator/session-key-validator.d.ts +18 -7
- package/dist/types/kernel-zerodev/validator/session-key-validator.d.ts.map +1 -1
- package/dist/types/kernel-zerodev/validator/types.d.ts +1 -1
- package/dist/types/kernel-zerodev/validator/types.d.ts.map +1 -1
- package/dist/types/kernel-zerodev/validator-provider/base.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/kernel-zerodev/__tests__/config/index.ts +18 -0
- package/src/kernel-zerodev/abis/SessionKeyValidatorAbi.ts +75 -4
- package/src/kernel-zerodev/client/create-client.ts +1 -0
- package/src/kernel-zerodev/constants.ts +2 -2
- package/src/kernel-zerodev/middleware/gas-estimator.ts +21 -7
- package/src/kernel-zerodev/validator/base.ts +4 -4
- package/src/kernel-zerodev/validator/session-key-validator.ts +159 -88
- package/src/kernel-zerodev/validator/types.ts +1 -1
- package/src/kernel-zerodev/validator-provider/base.ts +13 -0
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export const SessionKeyValidatorAbi = [
|
|
2
|
+
{
|
|
3
|
+
inputs: [],
|
|
4
|
+
name: "NotImplemented",
|
|
5
|
+
type: "error",
|
|
6
|
+
},
|
|
2
7
|
{
|
|
3
8
|
inputs: [
|
|
4
9
|
{
|
|
@@ -25,6 +30,72 @@ export const SessionKeyValidatorAbi = [
|
|
|
25
30
|
stateMutability: "payable",
|
|
26
31
|
type: "function",
|
|
27
32
|
},
|
|
33
|
+
{
|
|
34
|
+
inputs: [
|
|
35
|
+
{
|
|
36
|
+
internalType: "bytes32",
|
|
37
|
+
name: "permissionKey",
|
|
38
|
+
type: "bytes32",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
internalType: "address",
|
|
42
|
+
name: "kernel",
|
|
43
|
+
type: "address",
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
name: "executionStatus",
|
|
47
|
+
outputs: [
|
|
48
|
+
{
|
|
49
|
+
internalType: "ValidAfter",
|
|
50
|
+
name: "validAfter",
|
|
51
|
+
type: "uint48",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
internalType: "uint48",
|
|
55
|
+
name: "runs",
|
|
56
|
+
type: "uint48",
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
stateMutability: "view",
|
|
60
|
+
type: "function",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
inputs: [
|
|
64
|
+
{
|
|
65
|
+
internalType: "uint128",
|
|
66
|
+
name: "nonce",
|
|
67
|
+
type: "uint128",
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
name: "invalidateNonce",
|
|
71
|
+
outputs: [],
|
|
72
|
+
stateMutability: "nonpayable",
|
|
73
|
+
type: "function",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
inputs: [
|
|
77
|
+
{
|
|
78
|
+
internalType: "address",
|
|
79
|
+
name: "kernel",
|
|
80
|
+
type: "address",
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
name: "nonces",
|
|
84
|
+
outputs: [
|
|
85
|
+
{
|
|
86
|
+
internalType: "uint128",
|
|
87
|
+
name: "lastNonce",
|
|
88
|
+
type: "uint128",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
internalType: "uint128",
|
|
92
|
+
name: "invalidNonce",
|
|
93
|
+
type: "uint128",
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
stateMutability: "view",
|
|
97
|
+
type: "function",
|
|
98
|
+
},
|
|
28
99
|
{
|
|
29
100
|
inputs: [
|
|
30
101
|
{
|
|
@@ -61,9 +132,9 @@ export const SessionKeyValidatorAbi = [
|
|
|
61
132
|
type: "address",
|
|
62
133
|
},
|
|
63
134
|
{
|
|
64
|
-
internalType: "
|
|
65
|
-
name: "
|
|
66
|
-
type: "
|
|
135
|
+
internalType: "uint256",
|
|
136
|
+
name: "nonce",
|
|
137
|
+
type: "uint256",
|
|
67
138
|
},
|
|
68
139
|
],
|
|
69
140
|
stateMutability: "view",
|
|
@@ -183,7 +254,7 @@ export const SessionKeyValidatorAbi = [
|
|
|
183
254
|
},
|
|
184
255
|
{
|
|
185
256
|
internalType: "bytes32",
|
|
186
|
-
name: "
|
|
257
|
+
name: "",
|
|
187
258
|
type: "bytes32",
|
|
188
259
|
},
|
|
189
260
|
{
|
|
@@ -26,7 +26,7 @@ export const ERC165_SESSION_KEY_VALIDATOR_ADDRESS =
|
|
|
26
26
|
"0xe149290800De29D4b0BF9dB82c508255D81902E6";
|
|
27
27
|
export const TOKEN_ACTION = "0x2087C7FfD0d0DAE80a00EE74325aBF3449e0eaf1";
|
|
28
28
|
export const SESSION_KEY_VALIDATOR_ADDRESS =
|
|
29
|
-
"
|
|
29
|
+
"0xB8E3c4bEaACAd06f6092793012DA4a8cB23D6123";
|
|
30
30
|
export const RECOVERY_VALIDATOR_ADDRESS =
|
|
31
31
|
"0x4fd47D861c349bD49DC61341a922cb72F9dF7E8d";
|
|
32
32
|
export const RECOVERY_ACTION = "0x2f65dB8039fe5CAEE0a8680D2879deB800F31Ae1";
|
|
@@ -102,6 +102,6 @@ export const CHAIN_ID_TO_NODE: { [key: number]: string } = {
|
|
|
102
102
|
10200: "https://nd-810-853-201.p2pify.com/e828b09f0d43591de96c297b3f36fffd",
|
|
103
103
|
59144: `https://linea-mainnet.infura.io/v3/${INFURA_API_KEY}`,
|
|
104
104
|
59140: `https://linea-goerli.infura.io/v3/${INFURA_API_KEY}`,
|
|
105
|
-
204:
|
|
105
|
+
204: "https://opbnb.rpc.thirdweb.com/eed98c1f30120c0508f17c1f01d3102b",
|
|
106
106
|
// 5611: 'opBnb-testnet',
|
|
107
107
|
};
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "@alchemy/aa-core";
|
|
10
10
|
import { ENTRYPOINT_ADDRESS } from "../constants.js";
|
|
11
11
|
import { calcPreVerificationGas } from "../utils/calc-pre-verification-gas.js";
|
|
12
|
+
import { type PaymasterAndBundlerProviders } from "../paymaster/types.js";
|
|
12
13
|
|
|
13
14
|
export const withZeroDevGasEstimator = (
|
|
14
15
|
provider: ZeroDevProvider
|
|
@@ -121,17 +122,30 @@ export const getPreVerificationGas = async (
|
|
|
121
122
|
return calcPreVerificationGas(p);
|
|
122
123
|
};
|
|
123
124
|
|
|
125
|
+
export const GAS_PRICE_RPC_METHODS_BY_BUNDLER: {
|
|
126
|
+
[K in PaymasterAndBundlerProviders]: string;
|
|
127
|
+
} = {
|
|
128
|
+
STACKUP: "eth_maxPriorityFeePerGas",
|
|
129
|
+
ALCHEMY: "rundler_maxPriorityFeePerGas",
|
|
130
|
+
PIMLICO: "pimlico_getUserOperationGasPrice",
|
|
131
|
+
};
|
|
132
|
+
|
|
124
133
|
export const eip1559GasPrice = async (provider: ZeroDevProvider) => {
|
|
125
|
-
|
|
126
|
-
provider.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
:
|
|
134
|
+
let [fee, block] = await Promise.all([
|
|
135
|
+
provider.rpcClient.request({
|
|
136
|
+
method:
|
|
137
|
+
// @ts-expect-error
|
|
138
|
+
GAS_PRICE_RPC_METHODS_BY_BUNDLER[provider.bundlerProvider] ??
|
|
139
|
+
"eth_maxPriorityFeePerGas",
|
|
140
|
+
params: [],
|
|
141
|
+
}) as any,
|
|
132
142
|
provider.rpcClient.getBlock({ blockTag: "latest" }),
|
|
133
143
|
]);
|
|
134
144
|
|
|
145
|
+
if (provider.bundlerProvider === "PIMLICO") {
|
|
146
|
+
fee = fee.standard.maxPriorityFeePerGas;
|
|
147
|
+
}
|
|
148
|
+
|
|
135
149
|
const tip = BigInt(fee);
|
|
136
150
|
const buffer = (tip / 100n) * 13n;
|
|
137
151
|
let maxPriorityFeePerGas = tip + buffer;
|
|
@@ -93,7 +93,7 @@ export abstract class KernelBaseValidator {
|
|
|
93
93
|
|
|
94
94
|
abstract encodeDisable(enableData: Hex): Hex;
|
|
95
95
|
|
|
96
|
-
abstract getEnableData(): Promise<Hex>;
|
|
96
|
+
abstract getEnableData(kernelAccountAddress?: Address): Promise<Hex>;
|
|
97
97
|
|
|
98
98
|
abstract signMessage(message: Uint8Array | string | Hex): Promise<Hex>;
|
|
99
99
|
|
|
@@ -141,7 +141,7 @@ export abstract class KernelBaseValidator {
|
|
|
141
141
|
calldata
|
|
142
142
|
);
|
|
143
143
|
if (validatorMode === ValidatorMode.enable) {
|
|
144
|
-
const enableData = await this.getEnableData();
|
|
144
|
+
const enableData = await this.getEnableData(kernelAccountAddress);
|
|
145
145
|
const enableDataLength = enableData.length / 2 - 1;
|
|
146
146
|
const enableSigLength = 65;
|
|
147
147
|
const staticDummySig = concatHex([
|
|
@@ -241,7 +241,7 @@ export abstract class KernelBaseValidator {
|
|
|
241
241
|
{ size: 32 }
|
|
242
242
|
),
|
|
243
243
|
executor: executor as Address,
|
|
244
|
-
enableData: await validator.getEnableData(),
|
|
244
|
+
enableData: await validator.getEnableData(kernel),
|
|
245
245
|
},
|
|
246
246
|
primaryType: "ValidatorApproved",
|
|
247
247
|
});
|
|
@@ -297,7 +297,7 @@ export abstract class KernelBaseValidator {
|
|
|
297
297
|
if (mode === ValidatorMode.sudo || mode === ValidatorMode.plugin) {
|
|
298
298
|
return concatHex([this.mode, await this.signUserOp(userOp)]);
|
|
299
299
|
} else {
|
|
300
|
-
const enableData = await this.getEnableData();
|
|
300
|
+
const enableData = await this.getEnableData(userOp.sender);
|
|
301
301
|
const enableDataLength = enableData.length / 2 - 1;
|
|
302
302
|
const enableSignature = this.getEnableSignature();
|
|
303
303
|
if (!enableSignature) {
|
|
@@ -20,7 +20,6 @@ import {
|
|
|
20
20
|
concat,
|
|
21
21
|
pad,
|
|
22
22
|
toHex,
|
|
23
|
-
keccak256,
|
|
24
23
|
encodeAbiParameters,
|
|
25
24
|
concatHex,
|
|
26
25
|
zeroAddress,
|
|
@@ -28,13 +27,13 @@ import {
|
|
|
28
27
|
isHex,
|
|
29
28
|
getFunctionSelector,
|
|
30
29
|
type GetAbiItemParameters,
|
|
30
|
+
keccak256,
|
|
31
31
|
} from "viem";
|
|
32
32
|
import { formatAbiItem } from "viem/utils";
|
|
33
33
|
import { SessionKeyValidatorAbi } from "../abis/SessionKeyValidatorAbi.js";
|
|
34
34
|
import { DUMMY_ECDSA_SIG } from "../constants.js";
|
|
35
35
|
import { KernelAccountAbi } from "../abis/KernelAccountAbi.js";
|
|
36
36
|
import { MerkleTree } from "merkletreejs";
|
|
37
|
-
import { Operation } from "../provider.js";
|
|
38
37
|
import { getChainId } from "../api/index.js";
|
|
39
38
|
import { fixSignedData } from "../utils.js";
|
|
40
39
|
import type { GetAbiItemReturnType } from "viem/dist/types/utils/abi/getAbiItem.js";
|
|
@@ -75,6 +74,16 @@ export enum ParamOperator {
|
|
|
75
74
|
NOT_EQUAL = 5,
|
|
76
75
|
}
|
|
77
76
|
|
|
77
|
+
export type SessionNonces = {
|
|
78
|
+
lastNonce: bigint;
|
|
79
|
+
invalidNonce: bigint;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export type ExecutionRule = {
|
|
83
|
+
validAfter: number; // 48 bits
|
|
84
|
+
interval: number; // 48 bits
|
|
85
|
+
runs: number; // 48 bits
|
|
86
|
+
};
|
|
78
87
|
export interface ParamRules {
|
|
79
88
|
offset: number;
|
|
80
89
|
condition: ParamOperator;
|
|
@@ -83,10 +92,11 @@ export interface ParamRules {
|
|
|
83
92
|
|
|
84
93
|
export type Permission = {
|
|
85
94
|
target: Address;
|
|
95
|
+
index?: number;
|
|
86
96
|
rules?: ParamRules[];
|
|
87
97
|
sig?: Hex;
|
|
88
98
|
valueLimit?: bigint;
|
|
89
|
-
|
|
99
|
+
executionRule?: ExecutionRule;
|
|
90
100
|
};
|
|
91
101
|
|
|
92
102
|
export interface SessionKeyData {
|
|
@@ -141,7 +151,6 @@ export function getPermissionFromABI<
|
|
|
141
151
|
target,
|
|
142
152
|
args,
|
|
143
153
|
functionName,
|
|
144
|
-
operation,
|
|
145
154
|
valueLimit,
|
|
146
155
|
}: GeneratePermissionFromArgsParameters<TAbi, TFunctionName>): Permission {
|
|
147
156
|
const abiItem = getAbiItem({
|
|
@@ -175,7 +184,6 @@ export function getPermissionFromABI<
|
|
|
175
184
|
sig: functionSelector,
|
|
176
185
|
rules: paramRules,
|
|
177
186
|
target,
|
|
178
|
-
operation: operation ?? Operation.Call,
|
|
179
187
|
valueLimit: valueLimit ?? 0n,
|
|
180
188
|
};
|
|
181
189
|
}
|
|
@@ -195,18 +203,20 @@ export class SessionKeyValidator extends KernelBaseValidator {
|
|
|
195
203
|
paymaster: params.sessionKeyData.paymaster ?? zeroAddress,
|
|
196
204
|
};
|
|
197
205
|
this.sessionKeyData.permissions = this.sessionKeyData.permissions?.map(
|
|
198
|
-
(perm) => ({
|
|
206
|
+
(perm, index) => ({
|
|
199
207
|
...perm,
|
|
200
|
-
operation: perm.operation ?? Operation.Call,
|
|
201
208
|
valueLimit: perm.valueLimit ?? 0n,
|
|
202
209
|
sig: perm.sig ?? pad("0x", { size: 4 }),
|
|
203
210
|
rules: perm.rules ?? [],
|
|
211
|
+
index,
|
|
212
|
+
executionRule: perm.executionRule ?? {
|
|
213
|
+
validAfter: 0,
|
|
214
|
+
interval: 0,
|
|
215
|
+
runs: 0,
|
|
216
|
+
},
|
|
204
217
|
})
|
|
205
218
|
);
|
|
206
219
|
this.merkleTree = this.getMerkleTree();
|
|
207
|
-
if (this.shouldDelegateViaFallback()) {
|
|
208
|
-
throw Error("Session key permissions not set");
|
|
209
|
-
}
|
|
210
220
|
this.selector =
|
|
211
221
|
params.selector ??
|
|
212
222
|
getFunctionSelector("execute(address, uint256, bytes, uint8)");
|
|
@@ -230,19 +240,54 @@ export class SessionKeyValidator extends KernelBaseValidator {
|
|
|
230
240
|
return this.merkleTree.getHexRoot() === pad("0x00", { size: 32 });
|
|
231
241
|
}
|
|
232
242
|
|
|
233
|
-
|
|
243
|
+
findMatchingPermissions(
|
|
244
|
+
callData: Hex
|
|
245
|
+
): Permission | Permission[] | undefined {
|
|
234
246
|
try {
|
|
235
247
|
const { functionName, args } = decodeFunctionData({
|
|
236
248
|
abi: KernelAccountAbi,
|
|
237
249
|
data: callData,
|
|
238
250
|
});
|
|
239
251
|
|
|
240
|
-
if (functionName !== "execute"
|
|
252
|
+
if (functionName !== "execute" && functionName !== "executeBatch")
|
|
253
|
+
return undefined;
|
|
254
|
+
if (functionName === "execute") {
|
|
255
|
+
const [to, value, data] = args;
|
|
256
|
+
return this.filterPermissions([to], [data], [value])?.[0];
|
|
257
|
+
} else if (functionName === "executeBatch") {
|
|
258
|
+
let targets: Hex[] = [],
|
|
259
|
+
values: bigint[] = [],
|
|
260
|
+
dataArray: Hex[] = [];
|
|
261
|
+
args[0].forEach((arg) => {
|
|
262
|
+
targets.push(arg.to);
|
|
263
|
+
values.push(arg.value);
|
|
264
|
+
dataArray.push(arg.data);
|
|
265
|
+
});
|
|
266
|
+
return this.filterPermissions(targets, dataArray, values);
|
|
267
|
+
} else {
|
|
268
|
+
throw Error("Invalid function");
|
|
269
|
+
}
|
|
270
|
+
} catch (error) {
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
241
274
|
|
|
275
|
+
private filterPermissions(
|
|
276
|
+
targets: Address[],
|
|
277
|
+
dataArray: Hex[],
|
|
278
|
+
values: bigint[]
|
|
279
|
+
): Permission[] | undefined {
|
|
280
|
+
if (
|
|
281
|
+
targets.length !== dataArray.length ||
|
|
282
|
+
targets.length !== values.length
|
|
283
|
+
) {
|
|
284
|
+
throw Error("Invalid arguments");
|
|
285
|
+
}
|
|
286
|
+
const filteredPermissions = targets.map((target, index) => {
|
|
242
287
|
const permissionsList = this.sessionKeyData.permissions;
|
|
243
288
|
if (!permissionsList || !permissionsList.length) return undefined;
|
|
244
289
|
|
|
245
|
-
const targetToMatch =
|
|
290
|
+
const targetToMatch = target.toLowerCase();
|
|
246
291
|
|
|
247
292
|
// Filter permissions by target
|
|
248
293
|
let targetPermissions = permissionsList.filter(
|
|
@@ -259,20 +304,13 @@ export class SessionKeyValidator extends KernelBaseValidator {
|
|
|
259
304
|
|
|
260
305
|
if (!targetPermissions.length) return undefined;
|
|
261
306
|
|
|
262
|
-
const operationPermissions = this.filterByOperation(
|
|
263
|
-
targetPermissions,
|
|
264
|
-
args[3]
|
|
265
|
-
);
|
|
266
|
-
|
|
267
|
-
if (!operationPermissions.length) return undefined;
|
|
268
|
-
|
|
269
307
|
const signaturePermissions = this.filterBySignature(
|
|
270
|
-
|
|
271
|
-
|
|
308
|
+
targetPermissions,
|
|
309
|
+
dataArray[index].slice(0, 10).toLowerCase()
|
|
272
310
|
);
|
|
273
311
|
|
|
274
312
|
const valueLimitPermissions = signaturePermissions.filter(
|
|
275
|
-
(permission) => (permission.valueLimit ?? 0n) >=
|
|
313
|
+
(permission) => (permission.valueLimit ?? 0n) >= values[index]
|
|
276
314
|
);
|
|
277
315
|
|
|
278
316
|
if (!valueLimitPermissions.length) return undefined;
|
|
@@ -287,20 +325,11 @@ export class SessionKeyValidator extends KernelBaseValidator {
|
|
|
287
325
|
}
|
|
288
326
|
});
|
|
289
327
|
|
|
290
|
-
return this.findPermissionByRule(sortedPermissions,
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
private filterByOperation(
|
|
297
|
-
permissions: Permission[],
|
|
298
|
-
operation: Operation
|
|
299
|
-
): Permission[] {
|
|
300
|
-
return permissions.filter(
|
|
301
|
-
(permission) =>
|
|
302
|
-
permission.operation === operation || Operation.Call === operation
|
|
303
|
-
);
|
|
328
|
+
return this.findPermissionByRule(sortedPermissions, dataArray[index]);
|
|
329
|
+
});
|
|
330
|
+
return filteredPermissions.every((permission) => permission !== undefined)
|
|
331
|
+
? (filteredPermissions as Permission[])
|
|
332
|
+
: undefined;
|
|
304
333
|
}
|
|
305
334
|
|
|
306
335
|
private filterBySignature(
|
|
@@ -368,34 +397,43 @@ export class SessionKeyValidator extends KernelBaseValidator {
|
|
|
368
397
|
|
|
369
398
|
// Having one leaf returns empty array in getProof(). To hack it we push the leaf twice
|
|
370
399
|
// issue - https://github.com/merkletreejs/merkletreejs/issues/58
|
|
371
|
-
if (permissionPacked
|
|
400
|
+
if (permissionPacked && permissionPacked.length === 1)
|
|
372
401
|
permissionPacked.push(permissionPacked[0]);
|
|
373
402
|
|
|
374
403
|
return permissionPacked && permissionPacked.length !== 0
|
|
375
404
|
? new MerkleTree(permissionPacked, keccak256, {
|
|
376
|
-
sortPairs: true,
|
|
377
405
|
hashLeaves: true,
|
|
406
|
+
complete: true,
|
|
407
|
+
sort: true,
|
|
378
408
|
})
|
|
379
409
|
: new MerkleTree([pad("0x00", { size: 32 })], keccak256, {
|
|
380
410
|
hashLeaves: false,
|
|
411
|
+
complete: true,
|
|
381
412
|
});
|
|
382
413
|
}
|
|
383
414
|
|
|
384
|
-
encodePermissionData(
|
|
415
|
+
encodePermissionData(
|
|
416
|
+
permission: Permission | Permission[],
|
|
417
|
+
merkleProof?: string[] | string[][]
|
|
418
|
+
): Hex {
|
|
385
419
|
let permissionParam = {
|
|
386
420
|
components: [
|
|
387
421
|
{
|
|
388
|
-
name: "
|
|
389
|
-
type: "
|
|
422
|
+
name: "index",
|
|
423
|
+
type: "uint32",
|
|
390
424
|
},
|
|
391
425
|
{
|
|
392
|
-
name: "
|
|
393
|
-
type: "
|
|
426
|
+
name: "target",
|
|
427
|
+
type: "address",
|
|
394
428
|
},
|
|
395
429
|
{
|
|
396
430
|
name: "sig",
|
|
397
431
|
type: "bytes4",
|
|
398
432
|
},
|
|
433
|
+
{
|
|
434
|
+
name: "valueLimit",
|
|
435
|
+
type: "uint256",
|
|
436
|
+
},
|
|
399
437
|
{
|
|
400
438
|
components: [
|
|
401
439
|
{
|
|
@@ -416,13 +454,27 @@ export class SessionKeyValidator extends KernelBaseValidator {
|
|
|
416
454
|
type: "tuple[]",
|
|
417
455
|
},
|
|
418
456
|
{
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
457
|
+
components: [
|
|
458
|
+
{
|
|
459
|
+
name: "interval",
|
|
460
|
+
type: "uint48",
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
name: "runs",
|
|
464
|
+
type: "uint48",
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
internalType: "ValidAfter",
|
|
468
|
+
name: "validAfter",
|
|
469
|
+
type: "uint48",
|
|
470
|
+
},
|
|
471
|
+
],
|
|
472
|
+
name: "executionRule",
|
|
473
|
+
type: "tuple",
|
|
422
474
|
},
|
|
423
475
|
],
|
|
424
476
|
name: "permission",
|
|
425
|
-
type: "tuple",
|
|
477
|
+
type: Array.isArray(permission) ? "tuple[]" : "tuple",
|
|
426
478
|
};
|
|
427
479
|
let params;
|
|
428
480
|
let values;
|
|
@@ -431,7 +483,7 @@ export class SessionKeyValidator extends KernelBaseValidator {
|
|
|
431
483
|
permissionParam,
|
|
432
484
|
{
|
|
433
485
|
name: "merkleProof",
|
|
434
|
-
type: "bytes32[]",
|
|
486
|
+
type: Array.isArray(merkleProof[0]) ? "bytes32[][]" : "bytes32[]",
|
|
435
487
|
},
|
|
436
488
|
];
|
|
437
489
|
values = [permission, merkleProof];
|
|
@@ -460,16 +512,41 @@ export class SessionKeyValidator extends KernelBaseValidator {
|
|
|
460
512
|
return await Promise.resolve(this.sessionKey);
|
|
461
513
|
}
|
|
462
514
|
|
|
463
|
-
async
|
|
515
|
+
async getSessionNonces(
|
|
516
|
+
kernelAccountAddress: Address
|
|
517
|
+
): Promise<SessionNonces> {
|
|
518
|
+
if (!this.publicClient) {
|
|
519
|
+
throw new Error("Validator uninitialized: PublicClient missing");
|
|
520
|
+
}
|
|
521
|
+
const nonce = await this.publicClient.readContract({
|
|
522
|
+
abi: SessionKeyValidatorAbi,
|
|
523
|
+
address: this.validatorAddress,
|
|
524
|
+
functionName: "nonces",
|
|
525
|
+
args: [kernelAccountAddress],
|
|
526
|
+
});
|
|
527
|
+
return { lastNonce: nonce[0], invalidNonce: nonce[1] };
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
async getEnableData(
|
|
531
|
+
kernelAccountAddress?: Address,
|
|
532
|
+
enabledLastNonce?: bigint
|
|
533
|
+
): Promise<Hex> {
|
|
464
534
|
if (!this.merkleTree) {
|
|
465
535
|
throw Error("SessionKeyValidator: MerkleTree not generated");
|
|
466
536
|
}
|
|
537
|
+
if (!kernelAccountAddress) {
|
|
538
|
+
throw Error("SessionKeyValidator: Kernel account address not provided");
|
|
539
|
+
}
|
|
540
|
+
const lastNonce =
|
|
541
|
+
enabledLastNonce ??
|
|
542
|
+
(await this.getSessionNonces(kernelAccountAddress)).lastNonce + 1n;
|
|
467
543
|
return concat([
|
|
468
544
|
await this.sessionKey.getAddress(),
|
|
469
545
|
pad(this.merkleTree.getHexRoot() as Hex, { size: 32 }),
|
|
470
546
|
pad(toHex(this.sessionKeyData.validAfter), { size: 6 }),
|
|
471
547
|
pad(toHex(this.sessionKeyData.validUntil), { size: 6 }),
|
|
472
548
|
this.sessionKeyData.paymaster!,
|
|
549
|
+
pad(toHex(lastNonce), { size: 32 }),
|
|
473
550
|
]);
|
|
474
551
|
}
|
|
475
552
|
|
|
@@ -494,21 +571,32 @@ export class SessionKeyValidator extends KernelBaseValidator {
|
|
|
494
571
|
});
|
|
495
572
|
const enableDataHex = concatHex([
|
|
496
573
|
await this.sessionKey.getAddress(),
|
|
497
|
-
pad(enableData[0], { size:
|
|
574
|
+
pad(enableData[0], { size: 32 }),
|
|
498
575
|
pad(toHex(enableData[1]), { size: 6 }),
|
|
499
576
|
pad(toHex(enableData[2]), { size: 6 }),
|
|
500
577
|
enableData[3],
|
|
578
|
+
pad(toHex(enableData[4]), { size: 32 }),
|
|
501
579
|
]);
|
|
502
580
|
return (
|
|
503
581
|
execDetail.validator.toLowerCase() ===
|
|
504
582
|
this.validatorAddress.toLowerCase() &&
|
|
505
|
-
|
|
506
|
-
|
|
583
|
+
enableDataHex.toLowerCase() ===
|
|
584
|
+
(
|
|
585
|
+
await this.getEnableData(kernelAccountAddress, enableData[4])
|
|
586
|
+
).toLowerCase()
|
|
507
587
|
);
|
|
508
588
|
}
|
|
509
589
|
|
|
510
590
|
async getDummyUserOpSignature(callData: Hex): Promise<Hex> {
|
|
511
|
-
|
|
591
|
+
return concatHex([
|
|
592
|
+
await this.sessionKey.getAddress(),
|
|
593
|
+
DUMMY_ECDSA_SIG,
|
|
594
|
+
this.getEncodedPermissionProofData(callData),
|
|
595
|
+
]);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
private getEncodedPermissionProofData(callData: Hex): Hex {
|
|
599
|
+
const matchingPermission = this.findMatchingPermissions(callData);
|
|
512
600
|
if (!matchingPermission && !this.shouldDelegateViaFallback()) {
|
|
513
601
|
throw Error(
|
|
514
602
|
"SessionKeyValidator: No matching permission found for the userOp"
|
|
@@ -520,20 +608,24 @@ export class SessionKeyValidator extends KernelBaseValidator {
|
|
|
520
608
|
matchingPermission
|
|
521
609
|
? this.encodePermissionData(matchingPermission)
|
|
522
610
|
: "0x";
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
611
|
+
let merkleProof: string[] | string[][] = [];
|
|
612
|
+
if (Array.isArray(matchingPermission)) {
|
|
613
|
+
let encodedPerms = matchingPermission.map((permission) =>
|
|
614
|
+
keccak256(this.encodePermissionData(permission))
|
|
615
|
+
);
|
|
616
|
+
merkleProof = encodedPerms.map((perm) =>
|
|
617
|
+
this.merkleTree.getHexProof(perm)
|
|
618
|
+
);
|
|
619
|
+
} else if (matchingPermission) {
|
|
620
|
+
merkleProof = this.merkleTree.getHexProof(
|
|
621
|
+
keccak256(encodedPermissionData)
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
return this.sessionKeyData.permissions &&
|
|
528
625
|
this.sessionKeyData.permissions.length !== 0 &&
|
|
529
626
|
matchingPermission
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
return concatHex([
|
|
533
|
-
await this.sessionKey.getAddress(),
|
|
534
|
-
DUMMY_ECDSA_SIG,
|
|
535
|
-
encodedData,
|
|
536
|
-
]);
|
|
627
|
+
? this.encodePermissionData(matchingPermission, merkleProof)
|
|
628
|
+
: "0x";
|
|
537
629
|
}
|
|
538
630
|
|
|
539
631
|
encodeEnable(sessionKeyEnableData: Hex): Hex {
|
|
@@ -574,31 +666,10 @@ export class SessionKeyValidator extends KernelBaseValidator {
|
|
|
574
666
|
);
|
|
575
667
|
const formattedMessage = typeof hash === "string" ? toBytes(hash) : hash;
|
|
576
668
|
|
|
577
|
-
const matchingPermission = this.findMatchingPermission(userOp.callData);
|
|
578
|
-
if (!matchingPermission && !this.shouldDelegateViaFallback()) {
|
|
579
|
-
throw Error(
|
|
580
|
-
"SessionKeyValidator: No matching permission found for the userOp"
|
|
581
|
-
);
|
|
582
|
-
}
|
|
583
|
-
const encodedPermissionData =
|
|
584
|
-
this.sessionKeyData.permissions &&
|
|
585
|
-
this.sessionKeyData.permissions.length !== 0 &&
|
|
586
|
-
matchingPermission
|
|
587
|
-
? this.encodePermissionData(matchingPermission)
|
|
588
|
-
: "0x";
|
|
589
|
-
const merkleProof = this.merkleTree.getHexProof(
|
|
590
|
-
keccak256(encodedPermissionData)
|
|
591
|
-
);
|
|
592
|
-
const encodedData =
|
|
593
|
-
this.sessionKeyData.permissions &&
|
|
594
|
-
this.sessionKeyData.permissions.length !== 0 &&
|
|
595
|
-
matchingPermission
|
|
596
|
-
? this.encodePermissionData(matchingPermission, merkleProof)
|
|
597
|
-
: "0x";
|
|
598
669
|
const signature = concat([
|
|
599
670
|
await this.sessionKey.getAddress(),
|
|
600
671
|
await this.sessionKey.signMessage(formattedMessage),
|
|
601
|
-
|
|
672
|
+
this.getEncodedPermissionProofData(userOp.callData),
|
|
602
673
|
]);
|
|
603
674
|
return signature;
|
|
604
675
|
}
|
|
@@ -120,7 +120,7 @@ export type GeneratePermissionFromArgsParameters<
|
|
|
120
120
|
_FunctionName = TAbi extends Abi
|
|
121
121
|
? InferFunctionName<TAbi, TFunctionName>
|
|
122
122
|
: never
|
|
123
|
-
> = Pick<Permission, "
|
|
123
|
+
> = Pick<Permission, "target" | "valueLimit"> & {
|
|
124
124
|
functionName?: _FunctionName;
|
|
125
125
|
} & (TFunctionName extends string
|
|
126
126
|
? { abi: Narrow<TAbi> } & GetFunctionArgs<TAbi, TFunctionName>
|
|
@@ -75,6 +75,19 @@ export abstract class ValidatorProvider<
|
|
|
75
75
|
bundlerProvider,
|
|
76
76
|
});
|
|
77
77
|
this.defaultProvider = params.defaultProvider;
|
|
78
|
+
if (
|
|
79
|
+
(typeof params.opts?.providerConfig?.chain === "number" &&
|
|
80
|
+
typeof params.defaultProvider?.chain === "number" &&
|
|
81
|
+
params.opts?.providerConfig?.chain !== params.defaultProvider?.chain) ||
|
|
82
|
+
(typeof params.opts?.providerConfig?.chain === "object" &&
|
|
83
|
+
typeof params.defaultProvider?.chain === "object" &&
|
|
84
|
+
params.opts?.providerConfig?.chain.id !==
|
|
85
|
+
params.defaultProvider?.chain.id)
|
|
86
|
+
) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
"chainId mismatch between default provider and current provider - check projectIds"
|
|
89
|
+
);
|
|
90
|
+
}
|
|
78
91
|
this.connect(
|
|
79
92
|
() =>
|
|
80
93
|
new KernelSmartContractAccount({
|