@keelcodes/sdk 2.3.1 → 2.3.2

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.
@@ -9,6 +9,10 @@ export declare const KEEL_SESSION_VALIDATOR: Address;
9
9
  export declare const KEEL_SESSION_HOOK: Address;
10
10
  /** KeelTokenPaymaster(三链同址;gas 垫付 + 稳定币结算) */
11
11
  export declare const KEEL_TOKEN_PAYMASTER: Address;
12
+ /** Kernel v3 factory(三链同址;首笔 createAccount) */
13
+ export declare const KEEL_KERNEL_FACTORY: Address;
14
+ /** Kernel v3 root validator(ECDSA,三链同址;账户 owner 验签) */
15
+ export declare const KEEL_ROOT_VALIDATOR: Address;
12
16
  export declare const KEEL_CHAIN_IDS: Record<KeelChain, number>;
13
17
  /** 各链 USDC(BSC 为 Binance-Peg USDC,18 位) */
14
18
  export declare const KEEL_USDC: Record<KeelChain, Address>;
@@ -10,7 +10,7 @@
10
10
  // ⚠️ 均为不可变部署;链上重部署须同步本表。
11
11
  // ---------------------------------------------------------------------------
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.KEEL_BUNDLER_URL = exports.KEEL_USDC_DECIMALS = exports.KEEL_USDC = exports.KEEL_CHAIN_IDS = exports.KEEL_TOKEN_PAYMASTER = exports.KEEL_SESSION_HOOK = exports.KEEL_SESSION_VALIDATOR = exports.KEEL_ENTRYPOINT_V07 = void 0;
13
+ exports.KEEL_BUNDLER_URL = exports.KEEL_USDC_DECIMALS = exports.KEEL_USDC = exports.KEEL_CHAIN_IDS = exports.KEEL_ROOT_VALIDATOR = exports.KEEL_KERNEL_FACTORY = exports.KEEL_TOKEN_PAYMASTER = exports.KEEL_SESSION_HOOK = exports.KEEL_SESSION_VALIDATOR = exports.KEEL_ENTRYPOINT_V07 = void 0;
14
14
  exports.keelChainConfig = keelChainConfig;
15
15
  exports.keelPublicClient = keelPublicClient;
16
16
  const viem_1 = require("viem");
@@ -23,6 +23,10 @@ exports.KEEL_SESSION_VALIDATOR = '0x8BCB3F5d855F5b2a1f1398690Daaa7866992bDE7';
23
23
  exports.KEEL_SESSION_HOOK = '0x466b5DC3796D44b0B63FdF2d3bC7a8Ea371a891F';
24
24
  /** KeelTokenPaymaster(三链同址;gas 垫付 + 稳定币结算) */
25
25
  exports.KEEL_TOKEN_PAYMASTER = '0x4500A1FbAe335F5E20Fa85C70Daa98a89faD6415';
26
+ /** Kernel v3 factory(三链同址;首笔 createAccount) */
27
+ exports.KEEL_KERNEL_FACTORY = '0xaac5D4240AF87249B3f71BC8E4A2cae074A3E419';
28
+ /** Kernel v3 root validator(ECDSA,三链同址;账户 owner 验签) */
29
+ exports.KEEL_ROOT_VALIDATOR = '0x845ADb2C711129d4f3966735eD98a9F09fC4cE57';
26
30
  exports.KEEL_CHAIN_IDS = { base: 8453, bsc: 56, ethereum: 1 };
27
31
  /** 各链 USDC(BSC 为 Binance-Peg USDC,18 位) */
28
32
  exports.KEEL_USDC = {
@@ -45,6 +49,8 @@ function keelChainConfig(chain, opts = {}) {
45
49
  entryPoint: exports.KEEL_ENTRYPOINT_V07,
46
50
  rpcUrl: opts.rpcUrl,
47
51
  kernelVersion: '0.3.1',
52
+ kernelFactory: exports.KEEL_KERNEL_FACTORY,
53
+ rootValidator: exports.KEEL_ROOT_VALIDATOR,
48
54
  sessionValidatorCopies: [opts.sessionValidator ?? exports.KEEL_SESSION_VALIDATOR],
49
55
  sessionHookCopies: [opts.sessionHook ?? exports.KEEL_SESSION_HOOK],
50
56
  bundlers: [
@@ -4,6 +4,7 @@ export * from './nonce';
4
4
  export * from './token-paymaster';
5
5
  export * from './signer';
6
6
  export * from './userop';
7
+ export * from './kernel-account';
7
8
  export * from './keel-session';
8
9
  export * from './x402';
9
10
  export * from './x402-session';
package/dist/aa/index.js CHANGED
@@ -23,6 +23,7 @@ __exportStar(require("./nonce"), exports);
23
23
  __exportStar(require("./token-paymaster"), exports);
24
24
  __exportStar(require("./signer"), exports);
25
25
  __exportStar(require("./userop"), exports);
26
+ __exportStar(require("./kernel-account"), exports);
26
27
  __exportStar(require("./keel-session"), exports);
27
28
  __exportStar(require("./x402"), exports);
28
29
  __exportStar(require("./x402-session"), exports);
@@ -24,6 +24,52 @@ export interface KeelTokenLimit {
24
24
  export declare function toKeelRules(policy: SessionPolicy): KeelRule[];
25
25
  /** `policyData = abi.encode(version, validAfter, validUntil, Rule[])` */
26
26
  export declare function encodeKeelPolicyData(policy: SessionPolicy): Hex;
27
+ /** Kernel.execute selector(安装期的 selectorData,必须恰好 4 字节) */
28
+ export declare const KEEL_SELECTOR_DATA: Hex;
29
+ /** hookData flag:仅未初始化时调 onInstall */
30
+ export declare const KEEL_HOOK_FLAG_IF_UNINITIALIZED: Hex;
31
+ /** hookData flag:强制调 onInstall(同账户轮换/换 key 必须用) */
32
+ export declare const KEEL_HOOK_FLAG_FORCE: Hex;
33
+ /** `enableSession(sessionId, sessionKey, policyData)` 完整 calldata(安装期 validatorData) */
34
+ export declare function encodeKeelEnableData(policy: SessionPolicy): Hex;
35
+ /** hookData = flag(1B) ‖ abi.encode(sessionId, policyData)(Kernel 剥掉首字节后交给 hook) */
36
+ export declare function encodeKeelHookData(policy: SessionPolicy, flag?: Hex): Hex;
37
+ /** 解析 slot 对应的 hook 副本;未配置返回 address(1)(= 不挂 hook)。 */
38
+ export declare function resolveKeelHook(chainConfig: ChainAAConfig, slot: number): Address;
39
+ /** 组装 installModule 的 initData(Kernel v3.1 紧凑布局) */
40
+ export declare function encodeKeelValidatorInstallData(params: {
41
+ enableData: Hex;
42
+ hook: Address;
43
+ hookData: Hex;
44
+ selectorData?: Hex;
45
+ }): Hex;
46
+ export interface EncodeKeelEnableSessionCallParams {
47
+ accountAddress: Address;
48
+ policy: SessionPolicy;
49
+ chainConfig: ChainAAConfig;
50
+ /** slot 序号(= validator 副本下标;一 key 一副本) */
51
+ slot: number;
52
+ /** 同账户换 key / 轮换必须传 {@link KEEL_HOOK_FLAG_FORCE} */
53
+ hookFlag?: Hex;
54
+ }
55
+ /**
56
+ * owner 侧「安装/授权」callData:
57
+ * execute( installModule(VALIDATOR, validatorCopy, initData) )
58
+ * 作为 UserOp.callData 由 owner 签名后提交(root nonce;账户未部署时同笔带 factory)。
59
+ */
60
+ export declare function encodeKeelEnableSessionCall(p: EncodeKeelEnableSessionCallParams): Hex;
61
+ export interface EncodeKeelUninstallCallParams {
62
+ accountAddress: Address;
63
+ chainConfig: ChainAAConfig;
64
+ slot: number;
65
+ /** 该 slot 的 sessionId(hook 段 onUninstall 必需) */
66
+ sessionId: string;
67
+ }
68
+ /**
69
+ * owner 侧「撤销」callData(validator + hook 两段批量;无 hook 时单段)。
70
+ * 走 root nonce,owner 裸签 getUserOpHash;**不需要** invalidateNonce。
71
+ */
72
+ export declare function encodeKeelUninstallCall(p: EncodeKeelUninstallCallParams): Hex;
27
73
  /** 解析 slot 对应的 validator 副本地址(缺配置直接抛错,不回退旧模块)。 */
28
74
  export declare function resolveKeelValidator(chainConfig: ChainAAConfig, slot: number): Address;
29
75
  /** agent 侧签名对象:digest = keccak256(userOpHash ‖ keccak256(policyData)) */
@@ -68,3 +114,60 @@ export interface BuildKeelSessionUserOpParams {
68
114
  * 与 aa-sdk 的 `buildKeelSessionUserOp` 逐字节一致(同输入同输出)。
69
115
  */
70
116
  export declare function buildKeelSessionUserOp(p: BuildKeelSessionUserOpParams): Promise<UserOperationV7>;
117
+ export type UserOpGasOverrides = Partial<Pick<UserOperationV7, 'callGasLimit' | 'verificationGasLimit' | 'preVerificationGas' | 'maxFeePerGas' | 'maxPriorityFeePerGas'>>;
118
+ /** owner 侧草稿:op 未签名;owner 对 `userOpHash` 签名后填入 `op.signature`。 */
119
+ export interface OwnerUserOpDraft {
120
+ account: Address;
121
+ op: UserOperationV7;
122
+ /** owner 需签名的摘要(= EntryPoint.getUserOpHash) */
123
+ userOpHash: Hex;
124
+ }
125
+ export interface BuildOwnerEnableUserOpParams {
126
+ /** 未传 nonce(且 deploy 需派生地址)时必须提供 */
127
+ client?: PublicClient;
128
+ chainConfig: ChainAAConfig;
129
+ /** owner EOA(root validator 的 owner) */
130
+ owner: Address;
131
+ /** 账户地址;`deploy` 时可省略(用 factory.getAddress 反事实派生) */
132
+ account?: Address;
133
+ /** relay `POST /v1/wallet/session` 返回的 enableCallData(优先) */
134
+ enableCallData?: Hex;
135
+ /** 或本地由 policy 编码(与 enableCallData 二选一) */
136
+ policy?: SessionPolicy;
137
+ /** validator 副本下标 */
138
+ slot: number;
139
+ /** 同账户换 key / 轮换传 {@link KEEL_HOOK_FLAG_FORCE} */
140
+ hookFlag?: Hex;
141
+ /** 账户未部署时传 true(salt=0)或 `{ salt }`:自动带 factory + factoryData */
142
+ deploy?: boolean | {
143
+ salt?: bigint;
144
+ };
145
+ nonce?: bigint;
146
+ gas?: UserOpGasOverrides;
147
+ }
148
+ /**
149
+ * 首笔 / 后续 owner 授权(enable session)UserOp 构造(未签名):
150
+ * callData = enableCallData ?? execute(installModule(KeelSessionValidator, ...))
151
+ * factory = 仅在 `deploy` 时携带(relay **不会**代部署)
152
+ * nonce = root `getNonce(account, 0)`
153
+ * digest = getUserOpHash(op) → owner 裸签
154
+ */
155
+ export declare function buildOwnerEnableUserOp(p: BuildOwnerEnableUserOpParams): Promise<OwnerUserOpDraft>;
156
+ export interface BuildOwnerRevokeUserOpParams {
157
+ /** 未传 nonce 时必须提供 */
158
+ client?: PublicClient;
159
+ chainConfig: ChainAAConfig;
160
+ account: Address;
161
+ slot: number;
162
+ sessionId: string;
163
+ nonce?: bigint;
164
+ gas?: UserOpGasOverrides;
165
+ }
166
+ /**
167
+ * owner 撤销(revoke)UserOp 构造(未签名):
168
+ * callData = executeBatch[uninstallModule(VALIDATOR), uninstallModule(HOOK, sessionId)]
169
+ * nonce = root `getNonce(account, 0)`
170
+ * digest = getUserOpHash(op) → owner 裸签
171
+ * 上链成功后 policy 随 hook.onUninstall 一并清除,**不需要** invalidateNonce。
172
+ */
173
+ export declare function buildOwnerRevokeUserOp(p: BuildOwnerRevokeUserOpParams): Promise<OwnerUserOpDraft>;
@@ -9,17 +9,26 @@
9
9
  // 链上只存 keccak256(policyData) 作为 commitment,因此这里必须逐字节一致。
10
10
  // ---------------------------------------------------------------------------
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.KEEL_POLICY_VERSION = void 0;
12
+ exports.KEEL_HOOK_FLAG_FORCE = exports.KEEL_HOOK_FLAG_IF_UNINITIALIZED = exports.KEEL_SELECTOR_DATA = exports.KEEL_POLICY_VERSION = void 0;
13
13
  exports.toBytes32 = toBytes32;
14
14
  exports.toKeelRules = toKeelRules;
15
15
  exports.encodeKeelPolicyData = encodeKeelPolicyData;
16
+ exports.encodeKeelEnableData = encodeKeelEnableData;
17
+ exports.encodeKeelHookData = encodeKeelHookData;
18
+ exports.resolveKeelHook = resolveKeelHook;
19
+ exports.encodeKeelValidatorInstallData = encodeKeelValidatorInstallData;
20
+ exports.encodeKeelEnableSessionCall = encodeKeelEnableSessionCall;
21
+ exports.encodeKeelUninstallCall = encodeKeelUninstallCall;
16
22
  exports.resolveKeelValidator = resolveKeelValidator;
17
23
  exports.keelSessionDigest = keelSessionDigest;
18
24
  exports.encodeKeelSessionSignature = encodeKeelSessionSignature;
19
25
  exports.buildKeelSessionUserOp = buildKeelSessionUserOp;
26
+ exports.buildOwnerEnableUserOp = buildOwnerEnableUserOp;
27
+ exports.buildOwnerRevokeUserOp = buildOwnerRevokeUserOp;
20
28
  const viem_1 = require("viem");
21
29
  const userop_1 = require("./userop");
22
30
  const nonce_1 = require("./nonce");
31
+ const kernel_account_1 = require("./kernel-account");
23
32
  exports.KEEL_POLICY_VERSION = 1n;
24
33
  /** bytes32 归一化(已是 0x+64 hex 直接用,否则左对齐补零) */
25
34
  function toBytes32(id) {
@@ -73,6 +82,140 @@ function encodeKeelPolicyData(policy) {
73
82
  { type: 'tuple[]', components: KeelRuleTuple },
74
83
  ], [exports.KEEL_POLICY_VERSION, policy.validAfter, policy.validUntil, toKeelRules(policy)]);
75
84
  }
85
+ // ---------------------------------------------------------------------------
86
+ // owner 侧编码(session 授权安装 / 撤销卸载)
87
+ //
88
+ // 安装 initData(Kernel v3.1 紧凑布局):
89
+ // initData = hook(20B) ‖ abi.encode(bytes validatorData, bytes hookData, bytes selectorData)
90
+ // validatorData = enableSession(sessionId, sessionKey, policyData) 完整 calldata
91
+ // hookData = flag(1B) ‖ abi.encode(bytes32 sessionId, bytes policyData)
92
+ // selectorData = 0xe9ae5c53(Kernel.execute,恰好 4 字节;长度≠4 时内核静默不 set)
93
+ // ⚠️ flag:0x00 = 仅未初始化时调 onInstall;0xff = 强制(同账户换 key 必须用 0xff)。
94
+ //
95
+ // 撤销 = 一次批量 execute:
96
+ // ① uninstallModule(VALIDATOR=1, validatorCopy, '0x')
97
+ // ② uninstallModule(HOOK=4, hookCopy, abi.encode(bytes32 sessionId))
98
+ // 只发①不发②会在 hook 残留 session(union 语义 ⇒ 旧更宽策略仍参与准入)。
99
+ // ---------------------------------------------------------------------------
100
+ /** Kernel.execute selector(安装期的 selectorData,必须恰好 4 字节) */
101
+ exports.KEEL_SELECTOR_DATA = '0xe9ae5c53';
102
+ /** hookData flag:仅未初始化时调 onInstall */
103
+ exports.KEEL_HOOK_FLAG_IF_UNINITIALIZED = '0x00';
104
+ /** hookData flag:强制调 onInstall(同账户轮换/换 key 必须用) */
105
+ exports.KEEL_HOOK_FLAG_FORCE = '0xff';
106
+ const MODULE_TYPE_VALIDATOR = 1n;
107
+ const MODULE_TYPE_HOOK = 4n;
108
+ /** address(1) = Kernel 约定「不挂 hook」 */
109
+ const HOOK_NONE = '0x0000000000000000000000000000000000000001';
110
+ /** KeelSessionValidator.enableSession(bytes32,address,bytes) */
111
+ const KeelSessionValidatorAbi = [
112
+ {
113
+ type: 'function',
114
+ name: 'enableSession',
115
+ inputs: [
116
+ { name: 'sessionId', type: 'bytes32' },
117
+ { name: 'sessionKey', type: 'address' },
118
+ { name: 'policyData', type: 'bytes' },
119
+ ],
120
+ outputs: [],
121
+ stateMutability: 'nonpayable',
122
+ },
123
+ ];
124
+ /** Kernel 账户自身的 ERC-7579 模块管理方法 */
125
+ const KeelModuleManagerAbi = [
126
+ {
127
+ type: 'function',
128
+ name: 'installModule',
129
+ inputs: [
130
+ { name: 'moduleTypeId', type: 'uint256' },
131
+ { name: 'module', type: 'address' },
132
+ { name: 'initData', type: 'bytes' },
133
+ ],
134
+ outputs: [],
135
+ stateMutability: 'nonpayable',
136
+ },
137
+ {
138
+ type: 'function',
139
+ name: 'uninstallModule',
140
+ inputs: [
141
+ { name: 'moduleTypeId', type: 'uint256' },
142
+ { name: 'module', type: 'address' },
143
+ { name: 'deInitData', type: 'bytes' },
144
+ ],
145
+ outputs: [],
146
+ stateMutability: 'nonpayable',
147
+ },
148
+ ];
149
+ /** `enableSession(sessionId, sessionKey, policyData)` 完整 calldata(安装期 validatorData) */
150
+ function encodeKeelEnableData(policy) {
151
+ return (0, viem_1.encodeFunctionData)({
152
+ abi: KeelSessionValidatorAbi,
153
+ functionName: 'enableSession',
154
+ args: [toBytes32(policy.sessionId), policy.signer, encodeKeelPolicyData(policy)],
155
+ });
156
+ }
157
+ /** hookData = flag(1B) ‖ abi.encode(sessionId, policyData)(Kernel 剥掉首字节后交给 hook) */
158
+ function encodeKeelHookData(policy, flag = exports.KEEL_HOOK_FLAG_IF_UNINITIALIZED) {
159
+ return (0, viem_1.concatHex)([
160
+ flag,
161
+ (0, viem_1.encodeAbiParameters)([{ type: 'bytes32' }, { type: 'bytes' }], [toBytes32(policy.sessionId), encodeKeelPolicyData(policy)]),
162
+ ]);
163
+ }
164
+ /** 解析 slot 对应的 hook 副本;未配置返回 address(1)(= 不挂 hook)。 */
165
+ function resolveKeelHook(chainConfig, slot) {
166
+ return chainConfig.sessionHookCopies?.[slot] ?? HOOK_NONE;
167
+ }
168
+ /** 组装 installModule 的 initData(Kernel v3.1 紧凑布局) */
169
+ function encodeKeelValidatorInstallData(params) {
170
+ return (0, viem_1.concatHex)([
171
+ params.hook,
172
+ (0, viem_1.encodeAbiParameters)([{ type: 'bytes' }, { type: 'bytes' }, { type: 'bytes' }], [params.enableData, params.hookData, params.selectorData ?? exports.KEEL_SELECTOR_DATA]),
173
+ ]);
174
+ }
175
+ /**
176
+ * owner 侧「安装/授权」callData:
177
+ * execute( installModule(VALIDATOR, validatorCopy, initData) )
178
+ * 作为 UserOp.callData 由 owner 签名后提交(root nonce;账户未部署时同笔带 factory)。
179
+ */
180
+ function encodeKeelEnableSessionCall(p) {
181
+ const validator = resolveKeelValidator(p.chainConfig, p.slot);
182
+ const hook = resolveKeelHook(p.chainConfig, p.slot);
183
+ const initData = encodeKeelValidatorInstallData({
184
+ enableData: encodeKeelEnableData(p.policy),
185
+ hook,
186
+ hookData: encodeKeelHookData(p.policy, p.hookFlag),
187
+ });
188
+ return (0, userop_1.encodeExecute)(p.accountAddress, 0n, (0, viem_1.encodeFunctionData)({
189
+ abi: KeelModuleManagerAbi,
190
+ functionName: 'installModule',
191
+ args: [MODULE_TYPE_VALIDATOR, validator, initData],
192
+ }));
193
+ }
194
+ /**
195
+ * owner 侧「撤销」callData(validator + hook 两段批量;无 hook 时单段)。
196
+ * 走 root nonce,owner 裸签 getUserOpHash;**不需要** invalidateNonce。
197
+ */
198
+ function encodeKeelUninstallCall(p) {
199
+ const validator = resolveKeelValidator(p.chainConfig, p.slot);
200
+ const hook = resolveKeelHook(p.chainConfig, p.slot);
201
+ const uninstallValidator = (0, viem_1.encodeFunctionData)({
202
+ abi: KeelModuleManagerAbi,
203
+ functionName: 'uninstallModule',
204
+ args: [MODULE_TYPE_VALIDATOR, validator, '0x'],
205
+ });
206
+ if (hook === HOOK_NONE) {
207
+ return (0, userop_1.encodeExecute)(p.accountAddress, 0n, uninstallValidator);
208
+ }
209
+ const uninstallHook = (0, viem_1.encodeFunctionData)({
210
+ abi: KeelModuleManagerAbi,
211
+ functionName: 'uninstallModule',
212
+ args: [MODULE_TYPE_HOOK, hook, (0, viem_1.encodeAbiParameters)([{ type: 'bytes32' }], [toBytes32(p.sessionId)])],
213
+ });
214
+ return (0, userop_1.encodeExecuteBatch)([
215
+ { target: p.accountAddress, data: uninstallValidator },
216
+ { target: p.accountAddress, data: uninstallHook },
217
+ ]);
218
+ }
76
219
  /** 解析 slot 对应的 validator 副本地址(缺配置直接抛错,不回退旧模块)。 */
77
220
  function resolveKeelValidator(chainConfig, slot) {
78
221
  if (!Number.isInteger(slot) || slot < 0) {
@@ -130,3 +273,103 @@ async function buildKeelSessionUserOp(p) {
130
273
  const sig = await p.agentSigner.signUserOp(keelSessionDigest(userOpHash, policyData));
131
274
  return { ...op, signature: encodeKeelSessionSignature({ sessionId: p.policy.sessionId, policyData, sig }) };
132
275
  }
276
+ /** root 通道 nonce:key=0 ⇒ mode=DEFAULT / vType=ROOT。 */
277
+ async function readRootNonce(client, entryPoint, account) {
278
+ return (await client.readContract({
279
+ address: entryPoint,
280
+ abi: ENTRYPOINT_GETNONCE_ABI,
281
+ functionName: 'getNonce',
282
+ args: [account, 0n],
283
+ }));
284
+ }
285
+ /**
286
+ * 首笔 / 后续 owner 授权(enable session)UserOp 构造(未签名):
287
+ * callData = enableCallData ?? execute(installModule(KeelSessionValidator, ...))
288
+ * factory = 仅在 `deploy` 时携带(relay **不会**代部署)
289
+ * nonce = root `getNonce(account, 0)`
290
+ * digest = getUserOpHash(op) → owner 裸签
291
+ */
292
+ async function buildOwnerEnableUserOp(p) {
293
+ if (!p.enableCallData && !p.policy) {
294
+ throw new Error('[keel-sdk] buildOwnerEnableUserOp: enableCallData 与 policy 至少提供一个');
295
+ }
296
+ const deploy = p.deploy === true ? {} : p.deploy;
297
+ let factory;
298
+ let factoryData;
299
+ let account = p.account;
300
+ if (deploy) {
301
+ const built = (0, kernel_account_1.encodeKernelFactoryData)(p.chainConfig, p.owner, deploy.salt ?? 0n);
302
+ factory = built.factory;
303
+ factoryData = built.factoryData;
304
+ if (!account) {
305
+ if (!p.client) {
306
+ throw new Error('[keel-sdk] buildOwnerEnableUserOp: deploy 且未传 account 时必须提供 client(用于反事实地址预测)');
307
+ }
308
+ account = await (0, kernel_account_1.predictAccountAddress)({
309
+ client: p.client,
310
+ chainConfig: p.chainConfig,
311
+ owner: p.owner,
312
+ salt: deploy.salt ?? 0n,
313
+ });
314
+ }
315
+ }
316
+ if (!account) {
317
+ throw new Error('[keel-sdk] buildOwnerEnableUserOp: account 必填(首笔部署请传 deploy: true)');
318
+ }
319
+ const callData = p.enableCallData ??
320
+ encodeKeelEnableSessionCall({
321
+ accountAddress: account,
322
+ policy: p.policy,
323
+ chainConfig: p.chainConfig,
324
+ slot: p.slot,
325
+ hookFlag: p.hookFlag,
326
+ });
327
+ let nonce = p.nonce;
328
+ if (nonce === undefined) {
329
+ if (!p.client) {
330
+ throw new Error('[keel-sdk] buildOwnerEnableUserOp: 未传 nonce 时必须提供 client');
331
+ }
332
+ nonce = await readRootNonce(p.client, p.chainConfig.entryPoint, account);
333
+ }
334
+ const op = (0, userop_1.buildUserOpWithCallData)({
335
+ sender: account,
336
+ nonce,
337
+ callData,
338
+ factory,
339
+ factoryData,
340
+ gas: p.gas,
341
+ });
342
+ return {
343
+ account,
344
+ op,
345
+ userOpHash: (0, userop_1.getUserOpHash)(op, p.chainConfig.entryPoint, p.chainConfig.chainId),
346
+ };
347
+ }
348
+ /**
349
+ * owner 撤销(revoke)UserOp 构造(未签名):
350
+ * callData = executeBatch[uninstallModule(VALIDATOR), uninstallModule(HOOK, sessionId)]
351
+ * nonce = root `getNonce(account, 0)`
352
+ * digest = getUserOpHash(op) → owner 裸签
353
+ * 上链成功后 policy 随 hook.onUninstall 一并清除,**不需要** invalidateNonce。
354
+ */
355
+ async function buildOwnerRevokeUserOp(p) {
356
+ const callData = encodeKeelUninstallCall({
357
+ accountAddress: p.account,
358
+ chainConfig: p.chainConfig,
359
+ slot: p.slot,
360
+ sessionId: p.sessionId,
361
+ });
362
+ let nonce = p.nonce;
363
+ if (nonce === undefined) {
364
+ if (!p.client) {
365
+ throw new Error('[keel-sdk] buildOwnerRevokeUserOp: 未传 nonce 时必须提供 client');
366
+ }
367
+ nonce = await readRootNonce(p.client, p.chainConfig.entryPoint, p.account);
368
+ }
369
+ const op = (0, userop_1.buildUserOpWithCallData)({ sender: p.account, nonce, callData, gas: p.gas });
370
+ return {
371
+ account: p.account,
372
+ op,
373
+ userOpHash: (0, userop_1.getUserOpHash)(op, p.chainConfig.entryPoint, p.chainConfig.chainId),
374
+ };
375
+ }
@@ -0,0 +1,30 @@
1
+ import { type Address, type Hex, type PublicClient } from 'viem';
2
+ import type { ChainAAConfig } from './types';
3
+ /**
4
+ * 编码 Kernel v3.1 `initialize(...)` calldata。
5
+ * rootValidator = 0x01 ‖ rootValidator 地址(21B);validatorData = owner(20B)。
6
+ */
7
+ export declare function encodeKernelInitialize(chainConfig: ChainAAConfig, owner: Address, rootValidator?: Address): Hex;
8
+ /**
9
+ * 首笔部署参数:`factory` + `factoryData = createAccount(initializeData, salt)`。
10
+ * salt 缺省 0(与 relay 的账户派生一致)。
11
+ */
12
+ export declare function encodeKernelFactoryData(chainConfig: ChainAAConfig, owner: Address, salt?: bigint): {
13
+ factory: Address;
14
+ factoryData: Hex;
15
+ };
16
+ /** 从 createAccount 编码中解包 (data, salt) —— 供 factory.getAddress 预测复用。 */
17
+ export declare function unpackFactoryData(factoryData: Hex): {
18
+ data: Hex;
19
+ salt: Hex;
20
+ };
21
+ /**
22
+ * 反事实地址预测:`factory.getAddress(data, salt)` view(纯 CREATE2,无合约创建)。
23
+ * 不依赖 `EntryPoint.getSenderAddress`(部分 RPC 拒绝 eth_call 内的 CREATE2 模拟)。
24
+ */
25
+ export declare function predictAccountAddress(params: {
26
+ client: PublicClient;
27
+ chainConfig: ChainAAConfig;
28
+ owner: Address;
29
+ salt?: bigint;
30
+ }): Promise<Address>;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ // ---------------------------------------------------------------------------
3
+ // Kernel v3 账户:factory initData 编码 / 反事实地址预测
4
+ //
5
+ // 首笔 owner 操作(enable session)之前账户通常尚未部署,UserOp 必须携带
6
+ // factory + factoryData,由 EntryPoint 在验证阶段 CREATE2 部署。
7
+ //
8
+ // initializeData = initialize(
9
+ // rootValidator, // bytes21 = 0x01 ‖ ECDSA validator(20B)
10
+ // hook, // address(0) → Kernel 内部归一为 address(1)(不挂 hook)
11
+ // validatorData, // owner EOA(20B)
12
+ // hookData, // '0x'
13
+ // initConfig // []
14
+ // ) // Kernel v3.1+,selector 0x3c3b752b
15
+ // factoryData = KernelFactory.createAccount(initializeData, bytes32 salt)
16
+ //
17
+ // ⚠️ 仅支持 Kernel v3.1+(0.3.0-beta 的 initialize 为 4 参数,Keel session 路径不支持)。
18
+ // ---------------------------------------------------------------------------
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.encodeKernelInitialize = encodeKernelInitialize;
21
+ exports.encodeKernelFactoryData = encodeKernelFactoryData;
22
+ exports.unpackFactoryData = unpackFactoryData;
23
+ exports.predictAccountAddress = predictAccountAddress;
24
+ const viem_1 = require("viem");
25
+ const chain_defaults_1 = require("./chain-defaults");
26
+ /** ValidationId 前缀:VALIDATOR 类型(0x01) */
27
+ const VALIDATOR_TYPE_VALIDATOR = '0x01';
28
+ /** Kernel v3.1+:initialize(bytes21, address, bytes, bytes, bytes[]) */
29
+ const KernelV3Init5Abi = [
30
+ {
31
+ type: 'function',
32
+ name: 'initialize',
33
+ inputs: [
34
+ { name: '_rootValidator', type: 'bytes21', internalType: 'ValidationId' },
35
+ { name: 'hook', type: 'address', internalType: 'contract IHook' },
36
+ { name: 'validatorData', type: 'bytes', internalType: 'bytes' },
37
+ { name: 'hookData', type: 'bytes', internalType: 'bytes' },
38
+ { name: 'initConfig', type: 'bytes[]', internalType: 'bytes[]' },
39
+ ],
40
+ outputs: [],
41
+ stateMutability: 'nonpayable',
42
+ },
43
+ ];
44
+ /** KernelFactory.createAccount(bytes data, bytes32 salt) */
45
+ const KernelFactoryAbi = [
46
+ {
47
+ type: 'function',
48
+ name: 'createAccount',
49
+ inputs: [
50
+ { name: 'data', type: 'bytes' },
51
+ { name: 'salt', type: 'bytes32' },
52
+ ],
53
+ outputs: [{ name: '', type: 'address' }],
54
+ stateMutability: 'payable',
55
+ },
56
+ ];
57
+ /** KernelFactory.getAddress(bytes data, bytes32 salt)(纯 CREATE2 计算) */
58
+ const KernelFactoryGetAddressAbi = [
59
+ {
60
+ type: 'function',
61
+ name: 'getAddress',
62
+ inputs: [
63
+ { name: 'data', type: 'bytes' },
64
+ { name: 'salt', type: 'bytes32' },
65
+ ],
66
+ outputs: [{ name: '', type: 'address' }],
67
+ stateMutability: 'view',
68
+ },
69
+ ];
70
+ /**
71
+ * 编码 Kernel v3.1 `initialize(...)` calldata。
72
+ * rootValidator = 0x01 ‖ rootValidator 地址(21B);validatorData = owner(20B)。
73
+ */
74
+ function encodeKernelInitialize(chainConfig, owner, rootValidator = chainConfig.rootValidator ?? chain_defaults_1.KEEL_ROOT_VALIDATOR) {
75
+ if (chainConfig.kernelVersion && chainConfig.kernelVersion !== '0.3.1') {
76
+ throw new Error(`[keel-sdk] encodeKernelInitialize 仅支持 Kernel 0.3.1+,got ${chainConfig.kernelVersion}`);
77
+ }
78
+ return (0, viem_1.encodeFunctionData)({
79
+ abi: KernelV3Init5Abi,
80
+ functionName: 'initialize',
81
+ args: [(0, viem_1.concatHex)([VALIDATOR_TYPE_VALIDATOR, rootValidator]), viem_1.zeroAddress, owner, '0x', []],
82
+ });
83
+ }
84
+ /**
85
+ * 首笔部署参数:`factory` + `factoryData = createAccount(initializeData, salt)`。
86
+ * salt 缺省 0(与 relay 的账户派生一致)。
87
+ */
88
+ function encodeKernelFactoryData(chainConfig, owner, salt = 0n) {
89
+ const factory = chainConfig.kernelFactory;
90
+ if (!factory) {
91
+ throw new Error(`[keel-sdk] missing kernelFactory for chain ${chainConfig.chainId}`);
92
+ }
93
+ return {
94
+ factory,
95
+ factoryData: (0, viem_1.encodeFunctionData)({
96
+ abi: KernelFactoryAbi,
97
+ functionName: 'createAccount',
98
+ args: [encodeKernelInitialize(chainConfig, owner), (0, viem_1.toHex)(salt, { size: 32 })],
99
+ }),
100
+ };
101
+ }
102
+ /** 从 createAccount 编码中解包 (data, salt) —— 供 factory.getAddress 预测复用。 */
103
+ function unpackFactoryData(factoryData) {
104
+ const body = factoryData.slice(10);
105
+ const salt = ('0x' + body.slice(64, 128));
106
+ const dataLen = parseInt(body.slice(128, 192), 16);
107
+ return { data: ('0x' + body.slice(192, 192 + dataLen * 2)), salt };
108
+ }
109
+ /**
110
+ * 反事实地址预测:`factory.getAddress(data, salt)` view(纯 CREATE2,无合约创建)。
111
+ * 不依赖 `EntryPoint.getSenderAddress`(部分 RPC 拒绝 eth_call 内的 CREATE2 模拟)。
112
+ */
113
+ async function predictAccountAddress(params) {
114
+ const { factory, factoryData } = encodeKernelFactoryData(params.chainConfig, params.owner, params.salt ?? 0n);
115
+ const { data, salt } = unpackFactoryData(factoryData);
116
+ return (await params.client.readContract({
117
+ address: factory,
118
+ abi: KernelFactoryGetAddressAbi,
119
+ functionName: 'getAddress',
120
+ args: [data, salt],
121
+ }));
122
+ }
@@ -15,6 +15,10 @@ export interface ChainAAConfig {
15
15
  rpcUrl?: string;
16
16
  /** Kernel 版本(缺省 '0.3.1') */
17
17
  kernelVersion?: string;
18
+ /** Kernel v3 factory(首笔部署用;缺省取内置三链默认) */
19
+ kernelFactory?: Address;
20
+ /** Kernel v3 root validator(ECDSA;缺省取内置三链默认) */
21
+ rootValidator?: Address;
18
22
  /** Keel(v1) session validator 副本(slot i → 第 i 个;append-only) */
19
23
  sessionValidatorCopies?: Address[];
20
24
  /** Keel(v1) policy hook 副本(与 validator 成对) */
@@ -7,6 +7,19 @@ export declare function encodeExecute(target: Address, value: bigint, data: Hex)
7
7
  * 挂 KeelPolicyHook 的 session 配置下,Kernel 在验证期强制 callData 以它开头。
8
8
  */
9
9
  export declare const EXECUTE_USER_OP_SELECTOR: Hex;
10
+ /** 批量执行单条(ERC-7579 Execution = (target, value, data)) */
11
+ export interface Execution {
12
+ target: Address;
13
+ value?: bigint;
14
+ data: Hex;
15
+ }
16
+ /**
17
+ * BATCH execMode:CALLTYPE_BATCH(0x01) | EXECTYPE_DEFAULT(0x00) → 高 2 字节 0x0100。
18
+ * 用于 owner 侧撤销(validator + hook 两段一次上链)。
19
+ */
20
+ export declare const BATCH_EXEC_MODE: Hex;
21
+ /** 编码 Kernel v3 批量调用:execute(BATCH_EXEC_MODE, abi.encode(Execution[])) */
22
+ export declare function encodeExecuteBatch(executions: Execution[]): Hex;
10
23
  /** 外层包装:executeUserOp.selector ‖ execute(...)(Route C / 挂真 hook 时必需) */
11
24
  export declare function encodeExecuteUserOp(executeCallData: Hex): Hex;
12
25
  export interface BuildUserOpWithCallDataParams {
package/dist/aa/userop.js CHANGED
@@ -6,8 +6,9 @@
6
6
  // userOpHash = viem getUserOperationHash(v0.7 EIP-712,含 chainId 防跨链重放)
7
7
  // ---------------------------------------------------------------------------
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.EXECUTE_USER_OP_SELECTOR = void 0;
9
+ exports.BATCH_EXEC_MODE = exports.EXECUTE_USER_OP_SELECTOR = void 0;
10
10
  exports.encodeExecute = encodeExecute;
11
+ exports.encodeExecuteBatch = encodeExecuteBatch;
11
12
  exports.encodeExecuteUserOp = encodeExecuteUserOp;
12
13
  exports.buildUserOpWithCallData = buildUserOpWithCallData;
13
14
  exports.getUserOpHash = getUserOpHash;
@@ -42,6 +43,27 @@ function encodeExecute(target, value, data) {
42
43
  * 挂 KeelPolicyHook 的 session 配置下,Kernel 在验证期强制 callData 以它开头。
43
44
  */
44
45
  exports.EXECUTE_USER_OP_SELECTOR = '0x8dd7712f';
46
+ /**
47
+ * BATCH execMode:CALLTYPE_BATCH(0x01) | EXECTYPE_DEFAULT(0x00) → 高 2 字节 0x0100。
48
+ * 用于 owner 侧撤销(validator + hook 两段一次上链)。
49
+ */
50
+ exports.BATCH_EXEC_MODE = '0x0100000000000000000000000000000000000000000000000000000000000000';
51
+ const ExecutionTuple = [
52
+ { name: 'target', type: 'address' },
53
+ { name: 'value', type: 'uint256' },
54
+ { name: 'data', type: 'bytes' },
55
+ ];
56
+ /** 编码 Kernel v3 批量调用:execute(BATCH_EXEC_MODE, abi.encode(Execution[])) */
57
+ function encodeExecuteBatch(executions) {
58
+ return (0, viem_1.encodeFunctionData)({
59
+ abi: KernelV3ExecuteAbi,
60
+ functionName: 'execute',
61
+ args: [
62
+ exports.BATCH_EXEC_MODE,
63
+ (0, viem_1.encodeAbiParameters)([{ name: 'executions', type: 'tuple[]', components: ExecutionTuple }], [executions.map((e) => ({ target: e.target, value: e.value ?? 0n, data: e.data }))]),
64
+ ],
65
+ });
66
+ }
45
67
  /** 外层包装:executeUserOp.selector ‖ execute(...)(Route C / 挂真 hook 时必需) */
46
68
  function encodeExecuteUserOp(executeCallData) {
47
69
  return (0, viem_1.concatHex)([exports.EXECUTE_USER_OP_SELECTOR, executeCallData]);
package/dist/http.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { KeelConfig } from './types';
2
2
  /** SDK 版本(契约 §5,随包版本同步)。 */
3
- export declare const SDK_VERSION = "2.3.1";
3
+ export declare const SDK_VERSION = "2.3.2";
4
4
  export declare class HttpClient {
5
5
  private baseUrl;
6
6
  private headers;
package/dist/http.js CHANGED
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.HttpClient = exports.SDK_VERSION = void 0;
7
7
  const errors_1 = require("./errors");
8
8
  /** SDK 版本(契约 §5,随包版本同步)。 */
9
- exports.SDK_VERSION = '2.3.1';
9
+ exports.SDK_VERSION = '2.3.2';
10
10
  /**
11
11
  * 钱包签名的复用时长(ms):首次签名后在该窗口内复用,避免每个请求都触发钱包弹窗。
12
12
  * 服务端会话 TTL 为 24h,此处取 1h 留足余量。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keelcodes/sdk",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "description": "Keel SDK — unified access to payment / wallet / data / account modules over https://keel.codes",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",