@keelcodes/sdk 2.2.0 → 2.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/aa/bundler.d.ts +28 -0
- package/dist/aa/bundler.js +95 -0
- package/dist/aa/chain-defaults.d.ts +30 -0
- package/dist/aa/chain-defaults.js +63 -0
- package/dist/aa/index.d.ts +10 -0
- package/dist/aa/index.js +29 -0
- package/dist/aa/keel-session.d.ts +37 -0
- package/dist/aa/keel-session.js +90 -0
- package/dist/aa/nonce.d.ts +8 -0
- package/dist/aa/nonce.js +22 -0
- package/dist/aa/signer.d.ts +3 -0
- package/dist/aa/signer.js +16 -0
- package/dist/aa/token-paymaster.d.ts +9 -0
- package/dist/aa/token-paymaster.js +18 -0
- package/dist/aa/types.d.ts +92 -0
- package/dist/aa/types.js +8 -0
- package/dist/aa/userop.d.ts +26 -0
- package/dist/aa/userop.js +100 -0
- package/dist/aa/x402-session.d.ts +96 -0
- package/dist/aa/x402-session.js +203 -0
- package/dist/aa/x402.d.ts +144 -0
- package/dist/aa/x402.js +185 -0
- package/dist/account.js +16 -15
- package/dist/data.js +82 -81
- package/dist/errors.js +4 -0
- package/dist/http.d.ts +1 -1
- package/dist/http.js +6 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +20 -0
- package/dist/payment.js +23 -22
- package/dist/wallet/index.d.ts +1 -0
- package/dist/wallet/index.js +1 -0
- package/dist/wallet/types.d.ts +39 -0
- package/dist/wallet/wallet-api.d.ts +9 -1
- package/dist/wallet/wallet-api.js +113 -104
- package/package.json +8 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Address, Hex } from 'viem';
|
|
2
|
+
import type { BundlerLike, UserOpReceipt, UserOpResult, UserOperationV7 } from './types';
|
|
3
|
+
export interface BundlerClientOptions {
|
|
4
|
+
url: string;
|
|
5
|
+
entryPoint: Address;
|
|
6
|
+
headers?: Record<string, string>;
|
|
7
|
+
/** 单次 HTTP 超时(ms),默认 30s */
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
/** 收据轮询间隔(ms),默认 1s */
|
|
10
|
+
pollIntervalMs?: number;
|
|
11
|
+
/** 等收据总超时(ms),默认 120s */
|
|
12
|
+
waitTimeoutMs?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare class BundlerClient implements BundlerLike {
|
|
15
|
+
private readonly url;
|
|
16
|
+
private readonly entryPoint;
|
|
17
|
+
private readonly headers;
|
|
18
|
+
private readonly timeoutMs;
|
|
19
|
+
private readonly pollIntervalMs;
|
|
20
|
+
private readonly waitTimeoutMs;
|
|
21
|
+
private nextId;
|
|
22
|
+
constructor(opts: BundlerClientOptions);
|
|
23
|
+
estimateUserOperationGas(op: UserOperationV7): Promise<Partial<Pick<UserOperationV7, 'callGasLimit' | 'verificationGasLimit' | 'preVerificationGas'>>>;
|
|
24
|
+
sendUserOperation(op: UserOperationV7): Promise<UserOpResult>;
|
|
25
|
+
/** 轮询 `eth_getUserOperationReceipt`;超时抛错(不静默返回未确认)。 */
|
|
26
|
+
waitForReceipt(userOpHash: Hex): Promise<UserOpReceipt>;
|
|
27
|
+
private rpc;
|
|
28
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// 最小 ERC-4337 bundler 客户端(JSON-RPC over HTTP)
|
|
4
|
+
//
|
|
5
|
+
// 只覆盖 session 付款需要的三件事:
|
|
6
|
+
// eth_estimateUserOperationGas / eth_sendUserOperation / eth_getUserOperationReceipt
|
|
7
|
+
// Keel 托管端点:`https://keel.codes/v1/bundler/{chain}`(可自定义 headers 带鉴权)。
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.BundlerClient = void 0;
|
|
11
|
+
const userop_1 = require("./userop");
|
|
12
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
13
|
+
class BundlerClient {
|
|
14
|
+
url;
|
|
15
|
+
entryPoint;
|
|
16
|
+
headers;
|
|
17
|
+
timeoutMs;
|
|
18
|
+
pollIntervalMs;
|
|
19
|
+
waitTimeoutMs;
|
|
20
|
+
nextId = 1;
|
|
21
|
+
constructor(opts) {
|
|
22
|
+
this.url = opts.url;
|
|
23
|
+
this.entryPoint = opts.entryPoint;
|
|
24
|
+
this.headers = { 'Content-Type': 'application/json', ...(opts.headers ?? {}) };
|
|
25
|
+
this.timeoutMs = opts.timeoutMs ?? 30_000;
|
|
26
|
+
this.pollIntervalMs = opts.pollIntervalMs ?? 1_000;
|
|
27
|
+
this.waitTimeoutMs = opts.waitTimeoutMs ?? 120_000;
|
|
28
|
+
}
|
|
29
|
+
async estimateUserOperationGas(op) {
|
|
30
|
+
const r = await this.rpc('eth_estimateUserOperationGas', [(0, userop_1.userOpToRpc)(op), this.entryPoint]);
|
|
31
|
+
return {
|
|
32
|
+
callGasLimit: BigInt(r.callGasLimit),
|
|
33
|
+
verificationGasLimit: BigInt(r.verificationGasLimit),
|
|
34
|
+
preVerificationGas: BigInt(r.preVerificationGas),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async sendUserOperation(op) {
|
|
38
|
+
const userOpHash = await this.rpc('eth_sendUserOperation', [
|
|
39
|
+
(0, userop_1.userOpToRpc)(op),
|
|
40
|
+
this.entryPoint,
|
|
41
|
+
]);
|
|
42
|
+
const receipt = await this.waitForReceipt(userOpHash);
|
|
43
|
+
return { userOpHash, bundlerUrl: this.url, receipt };
|
|
44
|
+
}
|
|
45
|
+
/** 轮询 `eth_getUserOperationReceipt`;超时抛错(不静默返回未确认)。 */
|
|
46
|
+
async waitForReceipt(userOpHash) {
|
|
47
|
+
const deadline = Date.now() + this.waitTimeoutMs;
|
|
48
|
+
let lastErr;
|
|
49
|
+
while (Date.now() < deadline) {
|
|
50
|
+
try {
|
|
51
|
+
const r = await this.rpc('eth_getUserOperationReceipt', [userOpHash]);
|
|
52
|
+
if (r) {
|
|
53
|
+
return {
|
|
54
|
+
txHash: r.transactionHash ?? r.receipt?.transactionHash,
|
|
55
|
+
success: r.success,
|
|
56
|
+
actualGasCost: BigInt(r.actualGasCost),
|
|
57
|
+
actualGasUsed: BigInt(r.actualGasUsed),
|
|
58
|
+
logs: r.logs ?? [],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
// 轮询期 RPC 抖动不致命
|
|
64
|
+
lastErr = e;
|
|
65
|
+
}
|
|
66
|
+
await sleep(this.pollIntervalMs);
|
|
67
|
+
}
|
|
68
|
+
throw new Error(`[keel-sdk] userOp receipt timeout after ${this.waitTimeoutMs}ms (${userOpHash})` +
|
|
69
|
+
(lastErr instanceof Error ? `: ${lastErr.message}` : ''));
|
|
70
|
+
}
|
|
71
|
+
async rpc(method, params) {
|
|
72
|
+
const controller = new AbortController();
|
|
73
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
74
|
+
let res;
|
|
75
|
+
try {
|
|
76
|
+
res = await fetch(this.url, {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
headers: this.headers,
|
|
79
|
+
body: JSON.stringify({ jsonrpc: '2.0', id: this.nextId++, method, params }),
|
|
80
|
+
signal: controller.signal,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
clearTimeout(timer);
|
|
85
|
+
}
|
|
86
|
+
const json = (await res.json().catch(() => null));
|
|
87
|
+
if (!res.ok || !json || json.error) {
|
|
88
|
+
const msg = json?.error?.message ?? `HTTP ${res.status}`;
|
|
89
|
+
const data = json?.error?.data ? ` ${JSON.stringify(json.error.data).slice(0, 300)}` : '';
|
|
90
|
+
throw new Error(`[keel-sdk] bundler ${method} failed: ${msg}${data}`);
|
|
91
|
+
}
|
|
92
|
+
return json.result;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.BundlerClient = BundlerClient;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Address, type PublicClient } from 'viem';
|
|
2
|
+
import type { ChainAAConfig } from './types';
|
|
3
|
+
export type KeelChain = 'base' | 'bsc' | 'ethereum';
|
|
4
|
+
/** EntryPoint v0.7(三链同址) */
|
|
5
|
+
export declare const KEEL_ENTRYPOINT_V07: Address;
|
|
6
|
+
/** KeelSessionValidator 副本(slot 0,三链同址) */
|
|
7
|
+
export declare const KEEL_SESSION_VALIDATOR: Address;
|
|
8
|
+
/** KeelPolicyHook 副本(slot 0,与 validator 成对,三链同址) */
|
|
9
|
+
export declare const KEEL_SESSION_HOOK: Address;
|
|
10
|
+
/** KeelTokenPaymaster(三链同址;gas 垫付 + 稳定币结算) */
|
|
11
|
+
export declare const KEEL_TOKEN_PAYMASTER: Address;
|
|
12
|
+
export declare const KEEL_CHAIN_IDS: Record<KeelChain, number>;
|
|
13
|
+
/** 各链 USDC(BSC 为 Binance-Peg USDC,18 位) */
|
|
14
|
+
export declare const KEEL_USDC: Record<KeelChain, Address>;
|
|
15
|
+
export declare const KEEL_USDC_DECIMALS: Record<KeelChain, number>;
|
|
16
|
+
/** Keel 托管 bundler(ERC-4337 JSON-RPC,路径即链别名) */
|
|
17
|
+
export declare const KEEL_BUNDLER_URL: Record<KeelChain, string>;
|
|
18
|
+
export interface KeelChainOptions {
|
|
19
|
+
rpcUrl?: string;
|
|
20
|
+
/** 覆盖 bundler(缺省 `KEEL_BUNDLER_URL[chain]`) */
|
|
21
|
+
bundlerUrl?: string;
|
|
22
|
+
bundlerHeaders?: Record<string, string>;
|
|
23
|
+
/** 覆盖 validator/hook 副本(仅重部署后需要) */
|
|
24
|
+
sessionValidator?: Address;
|
|
25
|
+
sessionHook?: Address;
|
|
26
|
+
}
|
|
27
|
+
/** 取某条链的 ChainAAConfig(内置默认 + 可选覆盖)。 */
|
|
28
|
+
export declare function keelChainConfig(chain: KeelChain, opts?: KeelChainOptions): ChainAAConfig;
|
|
29
|
+
/** 便捷:创建该链的只读 PublicClient(用于读 EntryPoint nonce 等)。 */
|
|
30
|
+
export declare function keelPublicClient(chain: KeelChain, rpcUrl?: string): PublicClient;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// @keelcodes/sdk — 内置三链 AA 栈地址(B 端零配置起步)
|
|
4
|
+
//
|
|
5
|
+
// 来源:infraX 生产部署(2026-10 三链同址核验)。
|
|
6
|
+
// - EntryPoint v0.7 / Kernel 官方栈:三链同址(ZeroDev 确定性部署)
|
|
7
|
+
// - KeelSessionValidator 副本 / KeelPolicyHook / KeelTokenPaymaster:三链同址
|
|
8
|
+
// - USDC:三链异址,且 **BSC 为 18 位精度**(其余 6 位)
|
|
9
|
+
//
|
|
10
|
+
// ⚠️ 均为不可变部署;链上重部署须同步本表。
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
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;
|
|
14
|
+
exports.keelChainConfig = keelChainConfig;
|
|
15
|
+
exports.keelPublicClient = keelPublicClient;
|
|
16
|
+
const viem_1 = require("viem");
|
|
17
|
+
const chains_1 = require("viem/chains");
|
|
18
|
+
/** EntryPoint v0.7(三链同址) */
|
|
19
|
+
exports.KEEL_ENTRYPOINT_V07 = '0x0000000071727De22E5E9d8BAf0edAc6f37da032';
|
|
20
|
+
/** KeelSessionValidator 副本(slot 0,三链同址) */
|
|
21
|
+
exports.KEEL_SESSION_VALIDATOR = '0x8BCB3F5d855F5b2a1f1398690Daaa7866992bDE7';
|
|
22
|
+
/** KeelPolicyHook 副本(slot 0,与 validator 成对,三链同址) */
|
|
23
|
+
exports.KEEL_SESSION_HOOK = '0x466b5DC3796D44b0B63FdF2d3bC7a8Ea371a891F';
|
|
24
|
+
/** KeelTokenPaymaster(三链同址;gas 垫付 + 稳定币结算) */
|
|
25
|
+
exports.KEEL_TOKEN_PAYMASTER = '0x4500A1FbAe335F5E20Fa85C70Daa98a89faD6415';
|
|
26
|
+
exports.KEEL_CHAIN_IDS = { base: 8453, bsc: 56, ethereum: 1 };
|
|
27
|
+
/** 各链 USDC(BSC 为 Binance-Peg USDC,18 位) */
|
|
28
|
+
exports.KEEL_USDC = {
|
|
29
|
+
base: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
30
|
+
bsc: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',
|
|
31
|
+
ethereum: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
32
|
+
};
|
|
33
|
+
exports.KEEL_USDC_DECIMALS = { base: 6, bsc: 18, ethereum: 6 };
|
|
34
|
+
/** Keel 托管 bundler(ERC-4337 JSON-RPC,路径即链别名) */
|
|
35
|
+
exports.KEEL_BUNDLER_URL = {
|
|
36
|
+
base: 'https://keel.codes/v1/bundler/base',
|
|
37
|
+
bsc: 'https://keel.codes/v1/bundler/bsc',
|
|
38
|
+
ethereum: 'https://keel.codes/v1/bundler/ethereum',
|
|
39
|
+
};
|
|
40
|
+
const VIEM_CHAIN = { base: chains_1.base, bsc: chains_1.bsc, ethereum: chains_1.mainnet };
|
|
41
|
+
/** 取某条链的 ChainAAConfig(内置默认 + 可选覆盖)。 */
|
|
42
|
+
function keelChainConfig(chain, opts = {}) {
|
|
43
|
+
return {
|
|
44
|
+
chainId: exports.KEEL_CHAIN_IDS[chain],
|
|
45
|
+
entryPoint: exports.KEEL_ENTRYPOINT_V07,
|
|
46
|
+
rpcUrl: opts.rpcUrl,
|
|
47
|
+
kernelVersion: '0.3.1',
|
|
48
|
+
sessionValidatorCopies: [opts.sessionValidator ?? exports.KEEL_SESSION_VALIDATOR],
|
|
49
|
+
sessionHookCopies: [opts.sessionHook ?? exports.KEEL_SESSION_HOOK],
|
|
50
|
+
bundlers: [
|
|
51
|
+
{
|
|
52
|
+
url: opts.bundlerUrl ?? exports.KEEL_BUNDLER_URL[chain],
|
|
53
|
+
priority: 0,
|
|
54
|
+
...(opts.bundlerHeaders ? { headers: opts.bundlerHeaders } : {}),
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** 便捷:创建该链的只读 PublicClient(用于读 EntryPoint nonce 等)。 */
|
|
60
|
+
function keelPublicClient(chain, rpcUrl) {
|
|
61
|
+
const transport = rpcUrl ? (0, viem_1.http)(rpcUrl) : (0, viem_1.http)();
|
|
62
|
+
return (0, viem_1.createPublicClient)({ chain: VIEM_CHAIN[chain], transport });
|
|
63
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './types';
|
|
2
|
+
export * from './chain-defaults';
|
|
3
|
+
export * from './nonce';
|
|
4
|
+
export * from './token-paymaster';
|
|
5
|
+
export * from './signer';
|
|
6
|
+
export * from './userop';
|
|
7
|
+
export * from './keel-session';
|
|
8
|
+
export * from './x402';
|
|
9
|
+
export * from './x402-session';
|
|
10
|
+
export * from './bundler';
|
package/dist/aa/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// @keelcodes/sdk — AA / x402 客户端入口
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
17
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
__exportStar(require("./types"), exports);
|
|
21
|
+
__exportStar(require("./chain-defaults"), exports);
|
|
22
|
+
__exportStar(require("./nonce"), exports);
|
|
23
|
+
__exportStar(require("./token-paymaster"), exports);
|
|
24
|
+
__exportStar(require("./signer"), exports);
|
|
25
|
+
__exportStar(require("./userop"), exports);
|
|
26
|
+
__exportStar(require("./keel-session"), exports);
|
|
27
|
+
__exportStar(require("./x402"), exports);
|
|
28
|
+
__exportStar(require("./x402-session"), exports);
|
|
29
|
+
__exportStar(require("./bundler"), exports);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Address, type Hex } from 'viem';
|
|
2
|
+
import type { SessionPolicy } from './types';
|
|
3
|
+
import type { ChainAAConfig } from './types';
|
|
4
|
+
export declare const KEEL_POLICY_VERSION = 1n;
|
|
5
|
+
/** bytes32 归一化(已是 0x+64 hex 直接用,否则左对齐补零) */
|
|
6
|
+
export declare function toBytes32(id: string): Hex;
|
|
7
|
+
/** 链上 Rule(字段顺序即 ABI 顺序,不可调换) */
|
|
8
|
+
export interface KeelRule {
|
|
9
|
+
target: Address;
|
|
10
|
+
selectors: Hex[];
|
|
11
|
+
maxPerTx: bigint;
|
|
12
|
+
maxDaily: bigint;
|
|
13
|
+
maxCalls: bigint;
|
|
14
|
+
tokenLimits: KeelTokenLimit[];
|
|
15
|
+
}
|
|
16
|
+
export interface KeelTokenLimit {
|
|
17
|
+
token: Address;
|
|
18
|
+
maxPerTx: bigint;
|
|
19
|
+
maxDaily: bigint;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* SessionPermission[] → 链上 Rule[](每条 target 一个 Rule)。
|
|
23
|
+
* tokenLimits 只挂到 `token == target` 的那条 Rule(链上强制同址)。
|
|
24
|
+
*/
|
|
25
|
+
export declare function toKeelRules(policy: SessionPolicy): KeelRule[];
|
|
26
|
+
/** `policyData = abi.encode(version, validAfter, validUntil, Rule[])` */
|
|
27
|
+
export declare function encodeKeelPolicyData(policy: SessionPolicy): Hex;
|
|
28
|
+
/** 解析 slot 对应的 validator 副本地址(缺配置直接抛错,不回退旧模块)。 */
|
|
29
|
+
export declare function resolveKeelValidator(chainConfig: ChainAAConfig, slot: number): Address;
|
|
30
|
+
/** agent 侧签名对象:digest = keccak256(userOpHash ‖ keccak256(policyData)) */
|
|
31
|
+
export declare function keelSessionDigest(userOpHash: Hex, policyData: Hex): Hex;
|
|
32
|
+
/** agent 侧 userOp.signature 组装:sessionId(32B) ‖ policyData ‖ sessionKeySig(65B)。 */
|
|
33
|
+
export declare function encodeKeelSessionSignature(p: {
|
|
34
|
+
sessionId: string;
|
|
35
|
+
policyData: Hex;
|
|
36
|
+
sig: Hex;
|
|
37
|
+
}): Hex;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Keel(v1) session 编码:policyData / 摘要 / 签名布局
|
|
4
|
+
//
|
|
5
|
+
// 链上契约(KeelSessionValidator + KeelPolicyHook 共用同一份 policyData):
|
|
6
|
+
// policyData = abi.encode(version=1, validAfter, validUntil, Rule[])
|
|
7
|
+
// UserOp 摘要 = keccak256(userOpHash ‖ keccak256(policyData))
|
|
8
|
+
// signature = sessionId(32B) ‖ policyData ‖ sessionKeySig(65B)
|
|
9
|
+
// 链上只存 keccak256(policyData) 作为 commitment,因此这里必须逐字节一致。
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.KEEL_POLICY_VERSION = void 0;
|
|
13
|
+
exports.toBytes32 = toBytes32;
|
|
14
|
+
exports.toKeelRules = toKeelRules;
|
|
15
|
+
exports.encodeKeelPolicyData = encodeKeelPolicyData;
|
|
16
|
+
exports.resolveKeelValidator = resolveKeelValidator;
|
|
17
|
+
exports.keelSessionDigest = keelSessionDigest;
|
|
18
|
+
exports.encodeKeelSessionSignature = encodeKeelSessionSignature;
|
|
19
|
+
const viem_1 = require("viem");
|
|
20
|
+
exports.KEEL_POLICY_VERSION = 1n;
|
|
21
|
+
/** bytes32 归一化(已是 0x+64 hex 直接用,否则左对齐补零) */
|
|
22
|
+
function toBytes32(id) {
|
|
23
|
+
return ((0, viem_1.isHex)(id) && id.length === 66 ? id : (0, viem_1.toHex)(id, { size: 32 }));
|
|
24
|
+
}
|
|
25
|
+
const KeelTokenLimitTuple = [
|
|
26
|
+
{ name: 'token', type: 'address' },
|
|
27
|
+
{ name: 'maxPerTx', type: 'uint256' },
|
|
28
|
+
{ name: 'maxDaily', type: 'uint256' },
|
|
29
|
+
];
|
|
30
|
+
const KeelRuleTuple = [
|
|
31
|
+
{ name: 'target', type: 'address' },
|
|
32
|
+
{ name: 'selectors', type: 'bytes4[]' },
|
|
33
|
+
{ name: 'maxPerTx', type: 'uint256' },
|
|
34
|
+
{ name: 'maxDaily', type: 'uint256' },
|
|
35
|
+
{ name: 'maxCalls', type: 'uint256' },
|
|
36
|
+
{ name: 'tokenLimits', type: 'tuple[]', components: KeelTokenLimitTuple },
|
|
37
|
+
];
|
|
38
|
+
/**
|
|
39
|
+
* SessionPermission[] → 链上 Rule[](每条 target 一个 Rule)。
|
|
40
|
+
* tokenLimits 只挂到 `token == target` 的那条 Rule(链上强制同址)。
|
|
41
|
+
*/
|
|
42
|
+
function toKeelRules(policy) {
|
|
43
|
+
const rules = [];
|
|
44
|
+
for (const p of policy.permissions) {
|
|
45
|
+
const limits = p.tokenLimits ?? [];
|
|
46
|
+
for (const target of p.targets) {
|
|
47
|
+
rules.push({
|
|
48
|
+
target,
|
|
49
|
+
selectors: [...(p.selectors ?? [])],
|
|
50
|
+
maxPerTx: p.valueLimit ?? 0n,
|
|
51
|
+
maxDaily: p.dailyLimit ?? 0n,
|
|
52
|
+
maxCalls: BigInt(p.countLimit ?? 0),
|
|
53
|
+
tokenLimits: limits
|
|
54
|
+
.filter((t) => t.token.toLowerCase() === target.toLowerCase())
|
|
55
|
+
.map((t) => ({ token: t.token, maxPerTx: t.maxPerTx, maxDaily: t.maxDaily })),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (rules.length === 0) {
|
|
60
|
+
throw new Error('[keel-sdk] session policy needs at least one target');
|
|
61
|
+
}
|
|
62
|
+
return rules;
|
|
63
|
+
}
|
|
64
|
+
/** `policyData = abi.encode(version, validAfter, validUntil, Rule[])` */
|
|
65
|
+
function encodeKeelPolicyData(policy) {
|
|
66
|
+
return (0, viem_1.encodeAbiParameters)([
|
|
67
|
+
{ type: 'uint256' },
|
|
68
|
+
{ type: 'uint256' },
|
|
69
|
+
{ type: 'uint256' },
|
|
70
|
+
{ type: 'tuple[]', components: KeelRuleTuple },
|
|
71
|
+
], [exports.KEEL_POLICY_VERSION, policy.validAfter, policy.validUntil, toKeelRules(policy)]);
|
|
72
|
+
}
|
|
73
|
+
/** 解析 slot 对应的 validator 副本地址(缺配置直接抛错,不回退旧模块)。 */
|
|
74
|
+
function resolveKeelValidator(chainConfig, slot) {
|
|
75
|
+
if (!Number.isInteger(slot) || slot < 0) {
|
|
76
|
+
throw new Error(`[keel-sdk] invalid slot: ${slot}`);
|
|
77
|
+
}
|
|
78
|
+
const copy = chainConfig.sessionValidatorCopies?.[slot];
|
|
79
|
+
if (copy)
|
|
80
|
+
return copy;
|
|
81
|
+
throw new Error(`[keel-sdk] no keel session validator for slot ${slot}`);
|
|
82
|
+
}
|
|
83
|
+
/** agent 侧签名对象:digest = keccak256(userOpHash ‖ keccak256(policyData)) */
|
|
84
|
+
function keelSessionDigest(userOpHash, policyData) {
|
|
85
|
+
return (0, viem_1.keccak256)((0, viem_1.concatHex)([userOpHash, (0, viem_1.keccak256)(policyData)]));
|
|
86
|
+
}
|
|
87
|
+
/** agent 侧 userOp.signature 组装:sessionId(32B) ‖ policyData ‖ sessionKeySig(65B)。 */
|
|
88
|
+
function encodeKeelSessionSignature(p) {
|
|
89
|
+
return (0, viem_1.concatHex)([toBytes32(p.sessionId), p.policyData, p.sig]);
|
|
90
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Address } from 'viem';
|
|
2
|
+
export declare const VALIDATION_MODE_DEFAULT = 0;
|
|
3
|
+
export declare const VALIDATION_MODE_ENABLE = 1;
|
|
4
|
+
export declare const VALIDATION_TYPE_ROOT = 0;
|
|
5
|
+
export declare const VALIDATION_TYPE_VALIDATOR = 1;
|
|
6
|
+
export declare function encodeAsNonceKey(mode: number, vType: number, validator: Address, nonceKey?: number | bigint): bigint;
|
|
7
|
+
/** 已安装 validator 的常规 UserOp(agent session key 走此通道)。 */
|
|
8
|
+
export declare function validatorNonceKey(validator: Address, nonceKey?: number | bigint): bigint;
|
package/dist/aa/nonce.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Kernel v3 nonce key 编码(ValidatorLib.encodeAsNonceKey)
|
|
4
|
+
//
|
|
5
|
+
// EntryPoint nonce = nonceKey << 64 | sequence;Kernel 用 nonceKey 路由到
|
|
6
|
+
// 具体 validator:key = (mode << 184) | (vType << 176) | (validator << 16) | nonceKey
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.VALIDATION_TYPE_VALIDATOR = exports.VALIDATION_TYPE_ROOT = exports.VALIDATION_MODE_ENABLE = exports.VALIDATION_MODE_DEFAULT = void 0;
|
|
10
|
+
exports.encodeAsNonceKey = encodeAsNonceKey;
|
|
11
|
+
exports.validatorNonceKey = validatorNonceKey;
|
|
12
|
+
exports.VALIDATION_MODE_DEFAULT = 0;
|
|
13
|
+
exports.VALIDATION_MODE_ENABLE = 1;
|
|
14
|
+
exports.VALIDATION_TYPE_ROOT = 0;
|
|
15
|
+
exports.VALIDATION_TYPE_VALIDATOR = 1;
|
|
16
|
+
function encodeAsNonceKey(mode, vType, validator, nonceKey = 0) {
|
|
17
|
+
return (BigInt(mode) << 184n) | (BigInt(vType) << 176n) | (BigInt(validator) << 16n) | BigInt(nonceKey);
|
|
18
|
+
}
|
|
19
|
+
/** 已安装 validator 的常规 UserOp(agent session key 走此通道)。 */
|
|
20
|
+
function validatorNonceKey(validator, nonceKey = 0) {
|
|
21
|
+
return encodeAsNonceKey(exports.VALIDATION_MODE_DEFAULT, exports.VALIDATION_TYPE_VALIDATOR, validator, nonceKey);
|
|
22
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// 自持私钥签名器(最简单接入形态;MPC / 外部钱包请自行实现 Signer)
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.privateKeySigner = privateKeySigner;
|
|
7
|
+
const accounts_1 = require("viem/accounts");
|
|
8
|
+
function privateKeySigner(privateKey) {
|
|
9
|
+
const account = (0, accounts_1.privateKeyToAccount)(privateKey);
|
|
10
|
+
return {
|
|
11
|
+
type: 'private-key',
|
|
12
|
+
address: account.address,
|
|
13
|
+
signUserOp: (hash) => account.sign({ hash }),
|
|
14
|
+
signMessage: (message) => account.signMessage({ message: { raw: message } }),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Address, type Hex } from 'viem';
|
|
2
|
+
/**
|
|
3
|
+
* token 计费分支的 `paymasterData`:`tokenAddress`(可选再追 32B 客户端报价)。
|
|
4
|
+
* 客户端报价只有比链上价更保守时才会被采用(不会多扣)。
|
|
5
|
+
*/
|
|
6
|
+
export declare function buildTokenPaymasterData(args: {
|
|
7
|
+
token: Address;
|
|
8
|
+
clientPrice?: bigint;
|
|
9
|
+
}): Hex;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// KeelTokenPaymaster 客户端数据编码
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.buildTokenPaymasterData = buildTokenPaymasterData;
|
|
7
|
+
const viem_1 = require("viem");
|
|
8
|
+
/**
|
|
9
|
+
* token 计费分支的 `paymasterData`:`tokenAddress`(可选再追 32B 客户端报价)。
|
|
10
|
+
* 客户端报价只有比链上价更保守时才会被采用(不会多扣)。
|
|
11
|
+
*/
|
|
12
|
+
function buildTokenPaymasterData(args) {
|
|
13
|
+
if (args.clientPrice == null)
|
|
14
|
+
return args.token;
|
|
15
|
+
if (args.clientPrice <= 0n)
|
|
16
|
+
throw new Error('[keel-sdk] clientPrice must be > 0');
|
|
17
|
+
return (0, viem_1.concatHex)([args.token, (0, viem_1.toHex)(args.clientPrice, { size: 32 })]);
|
|
18
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { Address, Hex } from 'viem';
|
|
2
|
+
export type EvmNetwork = 'evm';
|
|
3
|
+
export interface BundlerConfig {
|
|
4
|
+
url: string;
|
|
5
|
+
/** 0 = 主端点(缺省) */
|
|
6
|
+
priority?: number;
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
}
|
|
10
|
+
/** 链配置:B 端可用 `keelChainConfig()` 取内置三链默认,再按需覆盖。 */
|
|
11
|
+
export interface ChainAAConfig {
|
|
12
|
+
chainId: number;
|
|
13
|
+
/** EntryPoint v0.7 */
|
|
14
|
+
entryPoint: Address;
|
|
15
|
+
rpcUrl?: string;
|
|
16
|
+
/** Kernel 版本(缺省 '0.3.1') */
|
|
17
|
+
kernelVersion?: string;
|
|
18
|
+
/** Keel(v1) session validator 副本(slot i → 第 i 个;append-only) */
|
|
19
|
+
sessionValidatorCopies?: Address[];
|
|
20
|
+
/** Keel(v1) policy hook 副本(与 validator 成对) */
|
|
21
|
+
sessionHookCopies?: Address[];
|
|
22
|
+
bundlers?: BundlerConfig[];
|
|
23
|
+
}
|
|
24
|
+
/** 统一签名器(自持私钥 / MPC / 外部钱包)。 */
|
|
25
|
+
export interface Signer {
|
|
26
|
+
readonly type: 'private-key' | 'mpc' | 'external-wallet';
|
|
27
|
+
readonly address: Address;
|
|
28
|
+
/** 对 UserOp hash(或等价的 EIP-712 摘要)签名,返回 65 字节 ECDSA */
|
|
29
|
+
signUserOp(hash: Hex): Promise<Hex>;
|
|
30
|
+
/** 对任意消息签名(EIP-191) */
|
|
31
|
+
signMessage(message: Hex): Promise<Hex>;
|
|
32
|
+
}
|
|
33
|
+
/** ERC-20 金额级限额(单笔 / 日累计;0 = 不限) */
|
|
34
|
+
export interface TokenLimit {
|
|
35
|
+
token: Address;
|
|
36
|
+
maxPerTx: bigint;
|
|
37
|
+
maxDaily: bigint;
|
|
38
|
+
}
|
|
39
|
+
/** 单条策略(target 维度) */
|
|
40
|
+
export interface SessionPermission {
|
|
41
|
+
targets: Address[];
|
|
42
|
+
selectors?: Hex[];
|
|
43
|
+
valueLimit?: bigint;
|
|
44
|
+
countLimit?: number;
|
|
45
|
+
dailyLimit?: bigint;
|
|
46
|
+
tokenLimits?: TokenLimit[];
|
|
47
|
+
}
|
|
48
|
+
/** session 策略:链上 `policyData` 的唯一来源(须与 enable 时逐字节一致)。 */
|
|
49
|
+
export interface SessionPolicy {
|
|
50
|
+
network?: EvmNetwork;
|
|
51
|
+
sessionId: string;
|
|
52
|
+
signer: Address;
|
|
53
|
+
validUntil: bigint;
|
|
54
|
+
validAfter: bigint;
|
|
55
|
+
permissions: SessionPermission[];
|
|
56
|
+
}
|
|
57
|
+
/** ERC-4337 v0.7 UserOperation(非打包形态,bundler RPC 字段) */
|
|
58
|
+
export interface UserOperationV7 {
|
|
59
|
+
sender: Address;
|
|
60
|
+
nonce: bigint;
|
|
61
|
+
factory?: Address;
|
|
62
|
+
factoryData?: Hex;
|
|
63
|
+
callData: Hex;
|
|
64
|
+
callGasLimit: bigint;
|
|
65
|
+
verificationGasLimit: bigint;
|
|
66
|
+
preVerificationGas: bigint;
|
|
67
|
+
maxFeePerGas: bigint;
|
|
68
|
+
maxPriorityFeePerGas: bigint;
|
|
69
|
+
paymaster?: Address;
|
|
70
|
+
paymasterVerificationGasLimit?: bigint;
|
|
71
|
+
paymasterPostOpGasLimit?: bigint;
|
|
72
|
+
paymasterData?: Hex;
|
|
73
|
+
signature: Hex;
|
|
74
|
+
}
|
|
75
|
+
export interface UserOpReceipt {
|
|
76
|
+
txHash?: Hex;
|
|
77
|
+
success: boolean;
|
|
78
|
+
actualGasCost: bigint;
|
|
79
|
+
actualGasUsed: bigint;
|
|
80
|
+
logs: unknown[];
|
|
81
|
+
}
|
|
82
|
+
export interface UserOpResult {
|
|
83
|
+
userOpHash: Hex;
|
|
84
|
+
bundlerUrl: string;
|
|
85
|
+
/** 轮询到的收据(可能为 null = 未确认) */
|
|
86
|
+
receipt?: UserOpReceipt;
|
|
87
|
+
}
|
|
88
|
+
/** payX402WithSession 所需的最小 bundler 能力(HTTP 实现见 ./bundler)。 */
|
|
89
|
+
export interface BundlerLike {
|
|
90
|
+
estimateUserOperationGas(op: UserOperationV7): Promise<Partial<Pick<UserOperationV7, 'callGasLimit' | 'verificationGasLimit' | 'preVerificationGas'>>>;
|
|
91
|
+
sendUserOperation(op: UserOperationV7): Promise<UserOpResult>;
|
|
92
|
+
}
|
package/dist/aa/types.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// @keelcodes/sdk — AA 客户端共享类型(EVM / Kernel v3 / ERC-4337 v0.7)
|
|
4
|
+
//
|
|
5
|
+
// 这里只保留「客户端自己签 UserOp + 自己组 x402 凭证」所需的最小形状,
|
|
6
|
+
// 与 @0xinfrax/aa-sdk 的 ChainAAConfig / SessionPolicy 逐字节兼容。
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type Address, type Hex } from 'viem';
|
|
2
|
+
import type { UserOperationV7 } from './types';
|
|
3
|
+
/** 编码 Kernel v3 单调用 callData:executionCalldata = target ‖ value(32B) ‖ data */
|
|
4
|
+
export declare function encodeExecute(target: Address, value: bigint, data: Hex): Hex;
|
|
5
|
+
/**
|
|
6
|
+
* IAccountExecute.executeUserOp selector(ERC-4337 v0.7)。
|
|
7
|
+
* 挂 KeelPolicyHook 的 session 配置下,Kernel 在验证期强制 callData 以它开头。
|
|
8
|
+
*/
|
|
9
|
+
export declare const EXECUTE_USER_OP_SELECTOR: Hex;
|
|
10
|
+
/** 外层包装:executeUserOp.selector ‖ execute(...)(Route C / 挂真 hook 时必需) */
|
|
11
|
+
export declare function encodeExecuteUserOp(executeCallData: Hex): Hex;
|
|
12
|
+
export interface BuildUserOpWithCallDataParams {
|
|
13
|
+
sender: Address;
|
|
14
|
+
nonce: bigint;
|
|
15
|
+
/** 已编码的 callData(自定外层,如 {@link encodeExecuteUserOp} 包裹) */
|
|
16
|
+
callData: Hex;
|
|
17
|
+
factory?: Address;
|
|
18
|
+
factoryData?: Hex;
|
|
19
|
+
gas?: Partial<Pick<UserOperationV7, 'callGasLimit' | 'verificationGasLimit' | 'preVerificationGas' | 'maxFeePerGas' | 'maxPriorityFeePerGas'>>;
|
|
20
|
+
}
|
|
21
|
+
/** 以已编码 callData 构建 UserOp v0.7(未签名)。 */
|
|
22
|
+
export declare function buildUserOpWithCallData(params: BuildUserOpWithCallDataParams): UserOperationV7;
|
|
23
|
+
/** EIP-712 userOpHash(v0.7 标准,含 chainId)。 */
|
|
24
|
+
export declare function getUserOpHash(op: UserOperationV7, entryPoint: Address, chainId: number): Hex;
|
|
25
|
+
/** UserOp v0.7 → bundler RPC 参数(bigint → hex;paymaster 字段缺省剔除)。 */
|
|
26
|
+
export declare function userOpToRpc(op: UserOperationV7): Record<string, unknown>;
|