@keelcodes/sdk 2.1.3 → 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 +2 -2
- package/dist/http.js +7 -2
- 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 +78 -0
- package/dist/wallet/wallet-api.d.ts +11 -2
- package/dist/wallet/wallet-api.js +113 -103
- package/package.json +8 -1
package/dist/aa/x402.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// x402 v2 客户端:解 challenge / 选 accept / 组 EIP-712 / 出 PAYMENT-SIGNATURE
|
|
4
|
+
//
|
|
5
|
+
// 与 payments 服务端(`protocol/x402-v2.ts`)逐字段对齐:
|
|
6
|
+
// domain = { name:'x402', version:'2', chainId, verifyingContract: payTo }
|
|
7
|
+
// types = Payment{ scheme, network, amount, asset, payTo, method, url, salt, txHash }
|
|
8
|
+
// header = base64(JSON({ x402Version, resource, accepted, payload:{method,url,salt,txHash}, signature }))
|
|
9
|
+
//
|
|
10
|
+
// 两条用法:
|
|
11
|
+
// 1. 自己已有 txHash(例如用 session key / 任意钱包先发了转账)→ `buildX402Payment` +
|
|
12
|
+
// `buildX402TypedData` + `encodePaymentSignature`
|
|
13
|
+
// 2. 由 SDK 驱动付款(回调里发 tx)→ `payX402`
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.X402_TYPES = exports.X402_DOMAIN_VERSION = exports.X402_DOMAIN_NAME = void 0;
|
|
17
|
+
exports.decodePaymentRequired = decodePaymentRequired;
|
|
18
|
+
exports.selectX402Accept = selectX402Accept;
|
|
19
|
+
exports.buildX402Payment = buildX402Payment;
|
|
20
|
+
exports.buildX402TypedData = buildX402TypedData;
|
|
21
|
+
exports.encodePaymentSignature = encodePaymentSignature;
|
|
22
|
+
exports.buildX402Payload = buildX402Payload;
|
|
23
|
+
exports.payX402 = payX402;
|
|
24
|
+
exports.toX402Salt = toX402Salt;
|
|
25
|
+
exports.toBase64 = toBase64;
|
|
26
|
+
const viem_1 = require("viem");
|
|
27
|
+
const TRANSFER_ABI = [
|
|
28
|
+
{
|
|
29
|
+
type: 'function',
|
|
30
|
+
name: 'transfer',
|
|
31
|
+
stateMutability: 'nonpayable',
|
|
32
|
+
inputs: [
|
|
33
|
+
{ name: 'to', type: 'address' },
|
|
34
|
+
{ name: 'amount', type: 'uint256' },
|
|
35
|
+
],
|
|
36
|
+
outputs: [{ name: '', type: 'bool' }],
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
exports.X402_DOMAIN_NAME = 'x402';
|
|
40
|
+
exports.X402_DOMAIN_VERSION = '2';
|
|
41
|
+
exports.X402_TYPES = {
|
|
42
|
+
Payment: [
|
|
43
|
+
{ name: 'scheme', type: 'string' },
|
|
44
|
+
{ name: 'network', type: 'string' },
|
|
45
|
+
{ name: 'amount', type: 'string' },
|
|
46
|
+
{ name: 'asset', type: 'address' },
|
|
47
|
+
{ name: 'payTo', type: 'address' },
|
|
48
|
+
{ name: 'method', type: 'string' },
|
|
49
|
+
{ name: 'url', type: 'string' },
|
|
50
|
+
{ name: 'salt', type: 'string' },
|
|
51
|
+
{ name: 'txHash', type: 'string' },
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
/** 解 `PAYMENT-REQUIRED` 头(base64 或直接 JSON)。 */
|
|
55
|
+
function decodePaymentRequired(header) {
|
|
56
|
+
const raw = header.trim();
|
|
57
|
+
const text = raw.startsWith('{') ? raw : fromBase64(raw);
|
|
58
|
+
const parsed = JSON.parse(text);
|
|
59
|
+
if (parsed?.x402Version !== 2 || !Array.isArray(parsed.accepts) || parsed.accepts.length === 0) {
|
|
60
|
+
throw new Error('[keel-sdk] PAYMENT-REQUIRED is not a valid x402 v2 challenge');
|
|
61
|
+
}
|
|
62
|
+
return parsed;
|
|
63
|
+
}
|
|
64
|
+
/** 选 accept:优先 exact,其次按传入的 asset / network 过滤。 */
|
|
65
|
+
function selectX402Accept(challenge, opts = {}) {
|
|
66
|
+
const matches = challenge.accepts.filter((a) => (opts.asset === undefined || a.asset.toLowerCase() === opts.asset.toLowerCase()) &&
|
|
67
|
+
(opts.network === undefined || a.network === opts.network));
|
|
68
|
+
const pick = matches.find((a) => a.scheme === 'exact') ?? matches[0];
|
|
69
|
+
if (!pick)
|
|
70
|
+
throw new Error('[keel-sdk] no x402 accept matches the requested asset/network');
|
|
71
|
+
return pick;
|
|
72
|
+
}
|
|
73
|
+
/** 按 accept 组装链上付款参数(native 转账或 ERC20 transfer)。 */
|
|
74
|
+
function buildX402Payment(accept) {
|
|
75
|
+
const amount = BigInt(accept.amount);
|
|
76
|
+
if (amount <= 0n)
|
|
77
|
+
throw new Error('[keel-sdk] x402 amount must be > 0');
|
|
78
|
+
const asset = accept.asset;
|
|
79
|
+
const payTo = accept.payTo;
|
|
80
|
+
const isNative = /^0x0{40}$/i.test(asset);
|
|
81
|
+
if (isNative)
|
|
82
|
+
return { to: payTo, value: amount, data: '0x', asset };
|
|
83
|
+
return {
|
|
84
|
+
to: asset,
|
|
85
|
+
value: 0n,
|
|
86
|
+
data: (0, viem_1.encodeFunctionData)({
|
|
87
|
+
abi: TRANSFER_ABI,
|
|
88
|
+
functionName: 'transfer',
|
|
89
|
+
args: [payTo, amount],
|
|
90
|
+
}),
|
|
91
|
+
asset,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** 构造待签的 EIP-712 结构(必须与 payments 侧逐字段一致)。 */
|
|
95
|
+
function buildX402TypedData(payload) {
|
|
96
|
+
const { accepted } = payload;
|
|
97
|
+
const chainId = Number(accepted.network.replace('eip155:', ''));
|
|
98
|
+
if (!Number.isInteger(chainId) || chainId <= 0) {
|
|
99
|
+
throw new Error(`[keel-sdk] unsupported x402 network: ${accepted.network}`);
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
domain: {
|
|
103
|
+
name: exports.X402_DOMAIN_NAME,
|
|
104
|
+
version: exports.X402_DOMAIN_VERSION,
|
|
105
|
+
chainId,
|
|
106
|
+
verifyingContract: accepted.payTo,
|
|
107
|
+
},
|
|
108
|
+
types: exports.X402_TYPES,
|
|
109
|
+
primaryType: 'Payment',
|
|
110
|
+
message: {
|
|
111
|
+
scheme: accepted.scheme,
|
|
112
|
+
network: accepted.network,
|
|
113
|
+
amount: accepted.amount,
|
|
114
|
+
asset: accepted.asset,
|
|
115
|
+
payTo: accepted.payTo,
|
|
116
|
+
method: payload.payload.method,
|
|
117
|
+
url: payload.payload.url,
|
|
118
|
+
salt: payload.payload.salt,
|
|
119
|
+
txHash: payload.payload.txHash,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* 已有签名时组装 `PAYMENT-SIGNATURE` 头(base64)。
|
|
125
|
+
* 配合 {@link buildX402TypedData} + `wallet.signTypedData` 用于纯 EOA 客户端。
|
|
126
|
+
*/
|
|
127
|
+
function encodePaymentSignature(payload) {
|
|
128
|
+
return toBase64(JSON.stringify(payload));
|
|
129
|
+
}
|
|
130
|
+
/** 由链上付款结果构造未签名的 payload(salt 缺省自动派生)。 */
|
|
131
|
+
function buildX402Payload(args) {
|
|
132
|
+
return {
|
|
133
|
+
x402Version: 2,
|
|
134
|
+
resource: args.challenge.resource,
|
|
135
|
+
accepted: args.accepted,
|
|
136
|
+
payload: {
|
|
137
|
+
method: args.method ?? 'GET',
|
|
138
|
+
url: args.url ?? args.challenge.resource?.url ?? '',
|
|
139
|
+
salt: args.salt ??
|
|
140
|
+
(0, viem_1.keccak256)((0, viem_1.stringToHex)(`${args.txHash}:${Date.now()}:${Math.random().toString(36).slice(2)}`)),
|
|
141
|
+
txHash: args.txHash,
|
|
142
|
+
},
|
|
143
|
+
signature: '0x',
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* 完成一次 x402 付款:发起链上支付 → 等确认 → 构造并签名 PaymentPayload。
|
|
148
|
+
* @returns `header` 可直接写入 `PAYMENT-SIGNATURE`。
|
|
149
|
+
*/
|
|
150
|
+
async function payX402(params) {
|
|
151
|
+
const accept = params.accept ?? selectX402Accept(params.challenge);
|
|
152
|
+
const payment = buildX402Payment(accept);
|
|
153
|
+
const txHash = await params.sendPayment(payment);
|
|
154
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(txHash)) {
|
|
155
|
+
throw new Error(`[keel-sdk] sendPayment must return a tx hash, got ${txHash}`);
|
|
156
|
+
}
|
|
157
|
+
if (params.waitForTransaction)
|
|
158
|
+
await params.waitForTransaction(txHash);
|
|
159
|
+
const unsigned = buildX402Payload({
|
|
160
|
+
challenge: params.challenge,
|
|
161
|
+
accepted: accept,
|
|
162
|
+
txHash,
|
|
163
|
+
method: params.method,
|
|
164
|
+
url: params.url,
|
|
165
|
+
salt: params.salt,
|
|
166
|
+
});
|
|
167
|
+
unsigned.signature = await params.signTypedData(buildX402TypedData(unsigned));
|
|
168
|
+
return { header: encodePaymentSignature(unsigned), payload: unsigned, txHash, payment };
|
|
169
|
+
}
|
|
170
|
+
/** 供调试:把任意 32 字节值转成 x402 salt 形态 */
|
|
171
|
+
function toX402Salt(value) {
|
|
172
|
+
return (0, viem_1.toHex)(BigInt(value), { size: 32 });
|
|
173
|
+
}
|
|
174
|
+
function toBase64(text) {
|
|
175
|
+
const bytes = new TextEncoder().encode(text);
|
|
176
|
+
let binary = '';
|
|
177
|
+
for (const b of bytes)
|
|
178
|
+
binary += String.fromCharCode(b);
|
|
179
|
+
return btoa(binary);
|
|
180
|
+
}
|
|
181
|
+
function fromBase64(encoded) {
|
|
182
|
+
const binary = atob(encoded);
|
|
183
|
+
const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));
|
|
184
|
+
return new TextDecoder().decode(bytes);
|
|
185
|
+
}
|
package/dist/account.js
CHANGED
|
@@ -5,24 +5,25 @@
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.AccountAPI = void 0;
|
|
7
7
|
class AccountAPI {
|
|
8
|
+
http;
|
|
8
9
|
constructor(http) {
|
|
9
10
|
this.http = http;
|
|
10
|
-
this.tenant = {
|
|
11
|
-
create: (p) => this.http.post('/v1/account/tenant', p),
|
|
12
|
-
get: (tenantId) => this.http.get('/v1/account/tenant/' + encodeURIComponent(tenantId)),
|
|
13
|
-
};
|
|
14
|
-
/** 按模块签发 key(用户订阅哪个模块,就为哪个模块签发)。 */
|
|
15
|
-
this.apikey = {
|
|
16
|
-
create: (p) => this.http.post('/v1/account/apikey', p),
|
|
17
|
-
/** 撤销 key;`id` 为 `GET /v1/account/apikey` 返回的 key id(非明文)。 */
|
|
18
|
-
revoke: (id) => this.http.post('/v1/account/apikey/revoke', { id }),
|
|
19
|
-
};
|
|
20
|
-
this.subscription = {
|
|
21
|
-
get: (module) => this.http.get('/v1/account/subscription?module=' + module),
|
|
22
|
-
subscribe: (p) => this.http.post('/v1/account/subscription', p),
|
|
23
|
-
cancel: (module) => this.http.post('/v1/account/subscription/cancel', { module }),
|
|
24
|
-
};
|
|
25
11
|
}
|
|
12
|
+
tenant = {
|
|
13
|
+
create: (p) => this.http.post('/v1/account/tenant', p),
|
|
14
|
+
get: (tenantId) => this.http.get('/v1/account/tenant/' + encodeURIComponent(tenantId)),
|
|
15
|
+
};
|
|
16
|
+
/** 按模块签发 key(用户订阅哪个模块,就为哪个模块签发)。 */
|
|
17
|
+
apikey = {
|
|
18
|
+
create: (p) => this.http.post('/v1/account/apikey', p),
|
|
19
|
+
/** 撤销 key;`id` 为 `GET /v1/account/apikey` 返回的 key id(非明文)。 */
|
|
20
|
+
revoke: (id) => this.http.post('/v1/account/apikey/revoke', { id }),
|
|
21
|
+
};
|
|
22
|
+
subscription = {
|
|
23
|
+
get: (module) => this.http.get('/v1/account/subscription?module=' + module),
|
|
24
|
+
subscribe: (p) => this.http.post('/v1/account/subscription', p),
|
|
25
|
+
cancel: (module) => this.http.post('/v1/account/subscription/cancel', { module }),
|
|
26
|
+
};
|
|
26
27
|
/** 创建提现(钱包签名;启用 TOTP 时需带 `totpCode`)。 */
|
|
27
28
|
withdraw(p) {
|
|
28
29
|
return this.http.post('/v1/account/withdraw', p);
|
package/dist/data.js
CHANGED
|
@@ -5,89 +5,9 @@
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.DataAPI = void 0;
|
|
7
7
|
class DataAPI {
|
|
8
|
+
http;
|
|
8
9
|
constructor(http) {
|
|
9
10
|
this.http = http;
|
|
10
|
-
/** 用户级数据 Key 自助管理(钱包签名;网关另需 `sk_data_*`)。 */
|
|
11
|
-
this.myKeys = {
|
|
12
|
-
/** 列出当前钱包持有的 key(不含明文)。 */
|
|
13
|
-
list: () => this.http.get('/v1/data/my-keys'),
|
|
14
|
-
/** 创建 key:`{label, scope?, rate_limit?}`;明文仅本次返回。 */
|
|
15
|
-
create: (p) => this.http.post('/v1/data/my-keys', p),
|
|
16
|
-
/** 用一次性认领码换取 key 明文(仅一次可见)。 */
|
|
17
|
-
claim: (claimCode) => this.http.post('/v1/data/my-keys/claim', { claim_code: claimCode }),
|
|
18
|
-
/** 轮换 key,返回新的明文。 */
|
|
19
|
-
rotate: (keyId) => this.http.post('/v1/data/my-keys/' + encodeURIComponent(String(keyId)) + '/rotate'),
|
|
20
|
-
/** 删除 key。 */
|
|
21
|
-
remove: (keyId) => this.http.delete('/v1/data/my-keys/' + encodeURIComponent(String(keyId))),
|
|
22
|
-
};
|
|
23
|
-
// ── Market 子域(DEX 行情 / 监控 / 订阅):canonical `/v1/data/market*` ──
|
|
24
|
-
this.market = {
|
|
25
|
-
/** 按名称/符号搜索 DEX 代币(DexScreener)。 */
|
|
26
|
-
search: (p) => {
|
|
27
|
-
const q = new URLSearchParams({ keyword: p.keyword });
|
|
28
|
-
if (p.chainIndex)
|
|
29
|
-
q.set('chainIndex', p.chainIndex);
|
|
30
|
-
if (p.limit)
|
|
31
|
-
q.set('limit', p.limit);
|
|
32
|
-
return this.http.get('/v1/data/market/token-search?' + q.toString());
|
|
33
|
-
},
|
|
34
|
-
/** 热门 DEX 池(GeckoTerminal trending)。 */
|
|
35
|
-
hot: (p = {}) => {
|
|
36
|
-
const q = new URLSearchParams();
|
|
37
|
-
if (p.chainIndex)
|
|
38
|
-
q.set('chainIndex', p.chainIndex);
|
|
39
|
-
if (p.limit)
|
|
40
|
-
q.set('limit', p.limit);
|
|
41
|
-
return this.http.get('/v1/data/market/hot-tokens?' + q.toString());
|
|
42
|
-
},
|
|
43
|
-
/** K 线(OHLCV)。 */
|
|
44
|
-
candles: (p) => {
|
|
45
|
-
const q = new URLSearchParams({ chainIndex: p.chainIndex, tokenAddress: p.tokenAddress });
|
|
46
|
-
if (p.period)
|
|
47
|
-
q.set('period', p.period);
|
|
48
|
-
if (p.limit)
|
|
49
|
-
q.set('limit', p.limit);
|
|
50
|
-
return this.http.get('/v1/data/market/candles?' + q.toString());
|
|
51
|
-
},
|
|
52
|
-
/** 实时 DEX 价。 */
|
|
53
|
-
price: (p) => this.http.get('/v1/data/market/price?' + new URLSearchParams({ chainIndex: p.chainIndex, tokenAddress: p.tokenAddress }).toString()),
|
|
54
|
-
/** 加入监控列表(自动采集 K 线 / 快照)。 */
|
|
55
|
-
trackToken: (p) => this.http.post('/v1/data/market/tracked-tokens', p),
|
|
56
|
-
/** 列出监控中的代币。 */
|
|
57
|
-
listTracked: (chain) => this.http.get('/v1/data/market/tracked-tokens' + (chain ? '?chain=' + encodeURIComponent(chain) : '')),
|
|
58
|
-
/** 注册自定义事件签名(topicHash + eventType,可选 ABI)。 */
|
|
59
|
-
registerEvent: (p) => this.http.post('/v1/data/market/custom-sigs', p),
|
|
60
|
-
/** Market 订阅套餐价目(公开)。 */
|
|
61
|
-
subscriptionPlans: () => this.http.get('/v1/data/market-subscription/plans'),
|
|
62
|
-
/** 发起 Market 订阅支付(免费即时生效;付费返支付意图)。 */
|
|
63
|
-
subscriptionCheckout: (p) => this.http.post('/v1/data/market-subscription/checkout', p),
|
|
64
|
-
/** 轮询 Market 订阅支付状态。 */
|
|
65
|
-
subscriptionPaymentCheck: (p = {}) => this.http.post('/v1/data/market-subscription/payment-check', p),
|
|
66
|
-
/** 确认 Market 订阅的 x402 支付(提交 txHash)。 */
|
|
67
|
-
subscriptionVerify: (p) => this.http.post('/v1/data/market-subscription/verify', p),
|
|
68
|
-
/** 读取 Market 订阅用量。 */
|
|
69
|
-
subscriptionUsage: () => this.http.get('/v1/data/market-subscription/usage'),
|
|
70
|
-
};
|
|
71
|
-
// ── Factor 工厂(因子挖掘):canonical `/v1/data/factor-factory/*`(由 ml-service 承载)──
|
|
72
|
-
this.factorFactory = {
|
|
73
|
-
/** 创建因子挖掘任务(结构化 preferences/constraints/formulas;intent 走 LLM 解析)。返回 job_id。 */
|
|
74
|
-
start: (p = {}) => {
|
|
75
|
-
const body = { preferences: p.preferences ?? {}, constraints: p.constraints ?? {} };
|
|
76
|
-
if (p.formulas?.length)
|
|
77
|
-
body.formulas = p.formulas;
|
|
78
|
-
return p.intent
|
|
79
|
-
? this.http.post('/v1/data/factor-factory/mine', { ...body, intent: p.intent })
|
|
80
|
-
: this.http.post('/v1/data/factor-factory/start', body);
|
|
81
|
-
},
|
|
82
|
-
/** 查询挖掘任务状态(含 stage 细分:pool/eval/select/persist)。 */
|
|
83
|
-
status: (jobId) => this.http.get('/v1/data/factor-factory/status?job_id=' + encodeURIComponent(jobId)),
|
|
84
|
-
/** 查询挖掘任务结果(合格因子列表 + 统计)。 */
|
|
85
|
-
result: (jobId) => this.http.get('/v1/data/factor-factory/result?job_id=' + encodeURIComponent(jobId)),
|
|
86
|
-
/** 最近挖掘任务列表。 */
|
|
87
|
-
list: (limit) => this.http.get('/v1/data/factor-factory/list' + (limit ? '?limit=' + limit : '')),
|
|
88
|
-
/** 取消挖掘任务(排队/运行中可取消)。 */
|
|
89
|
-
cancel: (jobId) => this.http.post('/v1/data/factor-factory/cancel?job_id=' + encodeURIComponent(jobId)),
|
|
90
|
-
};
|
|
91
11
|
}
|
|
92
12
|
bars(params) {
|
|
93
13
|
const q = new URLSearchParams({ symbol: params.symbol });
|
|
@@ -171,6 +91,19 @@ class DataAPI {
|
|
|
171
91
|
}
|
|
172
92
|
return this.http.stream('/v1/data/stream?' + q.toString());
|
|
173
93
|
}
|
|
94
|
+
/** 用户级数据 Key 自助管理(钱包签名;网关另需 `sk_data_*`)。 */
|
|
95
|
+
myKeys = {
|
|
96
|
+
/** 列出当前钱包持有的 key(不含明文)。 */
|
|
97
|
+
list: () => this.http.get('/v1/data/my-keys'),
|
|
98
|
+
/** 创建 key:`{label, scope?, rate_limit?}`;明文仅本次返回。 */
|
|
99
|
+
create: (p) => this.http.post('/v1/data/my-keys', p),
|
|
100
|
+
/** 用一次性认领码换取 key 明文(仅一次可见)。 */
|
|
101
|
+
claim: (claimCode) => this.http.post('/v1/data/my-keys/claim', { claim_code: claimCode }),
|
|
102
|
+
/** 轮换 key,返回新的明文。 */
|
|
103
|
+
rotate: (keyId) => this.http.post('/v1/data/my-keys/' + encodeURIComponent(String(keyId)) + '/rotate'),
|
|
104
|
+
/** 删除 key。 */
|
|
105
|
+
remove: (keyId) => this.http.delete('/v1/data/my-keys/' + encodeURIComponent(String(keyId))),
|
|
106
|
+
};
|
|
174
107
|
// ── 行情 / 符号 / 快照(旧 hub MCP 能力)──
|
|
175
108
|
/** 取单符号最新行情(ticker)。 */
|
|
176
109
|
ticker(symbol) {
|
|
@@ -274,5 +207,73 @@ class DataAPI {
|
|
|
274
207
|
subscriptionUsage(walletAddress) {
|
|
275
208
|
return this.http.get('/v1/data/usage', { 'x-wallet-address': walletAddress });
|
|
276
209
|
}
|
|
210
|
+
// ── Market 子域(DEX 行情 / 监控 / 订阅):canonical `/v1/data/market*` ──
|
|
211
|
+
market = {
|
|
212
|
+
/** 按名称/符号搜索 DEX 代币(DexScreener)。 */
|
|
213
|
+
search: (p) => {
|
|
214
|
+
const q = new URLSearchParams({ keyword: p.keyword });
|
|
215
|
+
if (p.chainIndex)
|
|
216
|
+
q.set('chainIndex', p.chainIndex);
|
|
217
|
+
if (p.limit)
|
|
218
|
+
q.set('limit', p.limit);
|
|
219
|
+
return this.http.get('/v1/data/market/token-search?' + q.toString());
|
|
220
|
+
},
|
|
221
|
+
/** 热门 DEX 池(GeckoTerminal trending)。 */
|
|
222
|
+
hot: (p = {}) => {
|
|
223
|
+
const q = new URLSearchParams();
|
|
224
|
+
if (p.chainIndex)
|
|
225
|
+
q.set('chainIndex', p.chainIndex);
|
|
226
|
+
if (p.limit)
|
|
227
|
+
q.set('limit', p.limit);
|
|
228
|
+
return this.http.get('/v1/data/market/hot-tokens?' + q.toString());
|
|
229
|
+
},
|
|
230
|
+
/** K 线(OHLCV)。 */
|
|
231
|
+
candles: (p) => {
|
|
232
|
+
const q = new URLSearchParams({ chainIndex: p.chainIndex, tokenAddress: p.tokenAddress });
|
|
233
|
+
if (p.period)
|
|
234
|
+
q.set('period', p.period);
|
|
235
|
+
if (p.limit)
|
|
236
|
+
q.set('limit', p.limit);
|
|
237
|
+
return this.http.get('/v1/data/market/candles?' + q.toString());
|
|
238
|
+
},
|
|
239
|
+
/** 实时 DEX 价。 */
|
|
240
|
+
price: (p) => this.http.get('/v1/data/market/price?' + new URLSearchParams({ chainIndex: p.chainIndex, tokenAddress: p.tokenAddress }).toString()),
|
|
241
|
+
/** 加入监控列表(自动采集 K 线 / 快照)。 */
|
|
242
|
+
trackToken: (p) => this.http.post('/v1/data/market/tracked-tokens', p),
|
|
243
|
+
/** 列出监控中的代币。 */
|
|
244
|
+
listTracked: (chain) => this.http.get('/v1/data/market/tracked-tokens' + (chain ? '?chain=' + encodeURIComponent(chain) : '')),
|
|
245
|
+
/** 注册自定义事件签名(topicHash + eventType,可选 ABI)。 */
|
|
246
|
+
registerEvent: (p) => this.http.post('/v1/data/market/custom-sigs', p),
|
|
247
|
+
/** Market 订阅套餐价目(公开)。 */
|
|
248
|
+
subscriptionPlans: () => this.http.get('/v1/data/market-subscription/plans'),
|
|
249
|
+
/** 发起 Market 订阅支付(免费即时生效;付费返支付意图)。 */
|
|
250
|
+
subscriptionCheckout: (p) => this.http.post('/v1/data/market-subscription/checkout', p),
|
|
251
|
+
/** 轮询 Market 订阅支付状态。 */
|
|
252
|
+
subscriptionPaymentCheck: (p = {}) => this.http.post('/v1/data/market-subscription/payment-check', p),
|
|
253
|
+
/** 确认 Market 订阅的 x402 支付(提交 txHash)。 */
|
|
254
|
+
subscriptionVerify: (p) => this.http.post('/v1/data/market-subscription/verify', p),
|
|
255
|
+
/** 读取 Market 订阅用量。 */
|
|
256
|
+
subscriptionUsage: () => this.http.get('/v1/data/market-subscription/usage'),
|
|
257
|
+
};
|
|
258
|
+
// ── Factor 工厂(因子挖掘):canonical `/v1/data/factor-factory/*`(由 ml-service 承载)──
|
|
259
|
+
factorFactory = {
|
|
260
|
+
/** 创建因子挖掘任务(结构化 preferences/constraints/formulas;intent 走 LLM 解析)。返回 job_id。 */
|
|
261
|
+
start: (p = {}) => {
|
|
262
|
+
const body = { preferences: p.preferences ?? {}, constraints: p.constraints ?? {} };
|
|
263
|
+
if (p.formulas?.length)
|
|
264
|
+
body.formulas = p.formulas;
|
|
265
|
+
return p.intent
|
|
266
|
+
? this.http.post('/v1/data/factor-factory/mine', { ...body, intent: p.intent })
|
|
267
|
+
: this.http.post('/v1/data/factor-factory/start', body);
|
|
268
|
+
},
|
|
269
|
+
/** 查询挖掘任务状态(含 stage 细分:pool/eval/select/persist)。 */
|
|
270
|
+
status: (jobId) => this.http.get('/v1/data/factor-factory/status?job_id=' + encodeURIComponent(jobId)),
|
|
271
|
+
/** 查询挖掘任务结果(合格因子列表 + 统计)。 */
|
|
272
|
+
result: (jobId) => this.http.get('/v1/data/factor-factory/result?job_id=' + encodeURIComponent(jobId)),
|
|
273
|
+
/** 最近挖掘任务列表。 */
|
|
274
|
+
list: (limit) => this.http.get('/v1/data/factor-factory/list' + (limit ? '?limit=' + limit : '')),
|
|
275
|
+
/** 取消挖掘任务(排队/运行中可取消)。 */
|
|
276
|
+
cancel: (jobId) => this.http.post('/v1/data/factor-factory/cancel?job_id=' + encodeURIComponent(jobId)),
|
|
277
|
+
};
|
|
277
278
|
}
|
|
278
279
|
exports.DataAPI = DataAPI;
|
package/dist/errors.js
CHANGED
|
@@ -7,6 +7,10 @@ exports.KeelApiError = void 0;
|
|
|
7
7
|
exports.isKeelApiError = isKeelApiError;
|
|
8
8
|
/** 引擎返回非 2xx 时抛出。`status` 为 HTTP 状态码,`code` 为契约错误码。 */
|
|
9
9
|
class KeelApiError extends Error {
|
|
10
|
+
path;
|
|
11
|
+
status;
|
|
12
|
+
code;
|
|
13
|
+
body;
|
|
10
14
|
constructor(path, status, code, body) {
|
|
11
15
|
super(`[keel-sdk] ${path} ${status} (${code}): ${body?.message ?? 'request failed'}`);
|
|
12
16
|
this.path = path;
|
package/dist/http.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { KeelConfig } from './types';
|
|
2
|
-
/** SDK 版本(契约 §5
|
|
3
|
-
export declare const SDK_VERSION = "2.
|
|
2
|
+
/** SDK 版本(契约 §5,随包版本同步)。 */
|
|
3
|
+
export declare const SDK_VERSION = "2.3.0";
|
|
4
4
|
export declare class HttpClient {
|
|
5
5
|
private baseUrl;
|
|
6
6
|
private headers;
|
package/dist/http.js
CHANGED
|
@@ -5,14 +5,19 @@
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.HttpClient = exports.SDK_VERSION = void 0;
|
|
7
7
|
const errors_1 = require("./errors");
|
|
8
|
-
/** SDK 版本(契约 §5
|
|
9
|
-
exports.SDK_VERSION = '2.
|
|
8
|
+
/** SDK 版本(契约 §5,随包版本同步)。 */
|
|
9
|
+
exports.SDK_VERSION = '2.3.0';
|
|
10
10
|
/**
|
|
11
11
|
* 钱包签名的复用时长(ms):首次签名后在该窗口内复用,避免每个请求都触发钱包弹窗。
|
|
12
12
|
* 服务端会话 TTL 为 24h,此处取 1h 留足余量。
|
|
13
13
|
*/
|
|
14
14
|
const WALLET_TOKEN_TTL_MS = 60 * 60 * 1000;
|
|
15
15
|
class HttpClient {
|
|
16
|
+
baseUrl;
|
|
17
|
+
headers;
|
|
18
|
+
timeout;
|
|
19
|
+
wallet;
|
|
20
|
+
walletToken;
|
|
16
21
|
constructor(config = {}) {
|
|
17
22
|
this.baseUrl = (config.baseUrl ?? 'https://keel.codes').replace(/\/+$/, '');
|
|
18
23
|
this.timeout = config.timeout ?? 30000;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { AccountAPI } from './account';
|
|
|
5
5
|
import type { KeelConfig } from './types';
|
|
6
6
|
export { KeelApiError, isKeelApiError } from './errors';
|
|
7
7
|
export type { KeelConfig, KeelModule, KeelErrorBody, KeelWalletAuth, KeelEnvelope } from './types';
|
|
8
|
+
export * from './aa';
|
|
8
9
|
export declare class Keel {
|
|
9
10
|
readonly payment: PaymentAPI;
|
|
10
11
|
readonly wallet: WalletAPI;
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,20 @@
|
|
|
6
6
|
// import { Keel } from '@keelcodes/sdk' // 全家桶
|
|
7
7
|
// import { PaymentAPI } from '@keelcodes/sdk/payment' // 按域 tree-shaking
|
|
8
8
|
// ---------------------------------------------------------------------------
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
21
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
22
|
+
};
|
|
9
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
24
|
exports.Keel = exports.isKeelApiError = exports.KeelApiError = void 0;
|
|
11
25
|
const http_1 = require("./http");
|
|
@@ -16,7 +30,13 @@ const account_1 = require("./account");
|
|
|
16
30
|
var errors_1 = require("./errors");
|
|
17
31
|
Object.defineProperty(exports, "KeelApiError", { enumerable: true, get: function () { return errors_1.KeelApiError; } });
|
|
18
32
|
Object.defineProperty(exports, "isKeelApiError", { enumerable: true, get: function () { return errors_1.isKeelApiError; } });
|
|
33
|
+
__exportStar(require("./aa"), exports);
|
|
19
34
|
class Keel {
|
|
35
|
+
payment;
|
|
36
|
+
wallet;
|
|
37
|
+
data;
|
|
38
|
+
account;
|
|
39
|
+
http;
|
|
20
40
|
constructor(config = {}) {
|
|
21
41
|
this.http = new http_1.HttpClient(config);
|
|
22
42
|
this.payment = new payment_1.PaymentAPI(this.http);
|
package/dist/payment.js
CHANGED
|
@@ -5,30 +5,9 @@
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.PaymentAPI = void 0;
|
|
7
7
|
class PaymentAPI {
|
|
8
|
+
http;
|
|
8
9
|
constructor(http) {
|
|
9
10
|
this.http = http;
|
|
10
|
-
/** 周期订阅扣费(基于已创建的 authorization)。 */
|
|
11
|
-
this.period = {
|
|
12
|
-
/** 扣减一个周期;返回 authorizationId 与扣费结果。 */
|
|
13
|
-
charge: (authorizationId) => this.http.post('/v1/payment/period/charge', { authorizationId }),
|
|
14
|
-
/** 查询周期授权状态(剩余额度 / 周期 / 状态)。 */
|
|
15
|
-
authorization: (authorizationId) => this.http.get('/v1/payment/period/authorization?authorizationId=' + encodeURIComponent(authorizationId)),
|
|
16
|
-
};
|
|
17
|
-
/** 托管(escrow)链上按量计费 / 退款。 */
|
|
18
|
-
this.escrow = {
|
|
19
|
-
/** relayer 代为签名扣费:`{chain, user, amountWei, reference}`。 */
|
|
20
|
-
charge: (p) => this.http.post('/v1/payment/escrow/charge', p),
|
|
21
|
-
/** relayer 代为签名退款:`{chain, user, amountWei, reference}`。 */
|
|
22
|
-
refund: (p) => this.http.post('/v1/payment/escrow/refund', p),
|
|
23
|
-
/** 查询托管余额(未配置链返回 `{configured:false, balanceWei:'0'}`)。 */
|
|
24
|
-
balance: (chain, user) => this.http.get('/v1/payment/escrow/balance?' + new URLSearchParams({ chain, user }).toString()),
|
|
25
|
-
/** 查询链上托管配置(地址 / 限额)。 */
|
|
26
|
-
info: (chain) => this.http.get('/v1/payment/escrow/info?chain=' + encodeURIComponent(chain)),
|
|
27
|
-
/** relayer gas 健康;不传 chain 返回全部已配置链。 */
|
|
28
|
-
relayerStatus: (chain) => this.http.get('/v1/payment/escrow/relayer-status' + (chain ? '?chain=' + encodeURIComponent(chain) : '')),
|
|
29
|
-
/** 核验 Solana 原生 SOL 充值并入账(幂等键 `sol:<signature>`)。 */
|
|
30
|
-
solanaVerify: (p) => this.http.post('/v1/payment/solana/verify', p),
|
|
31
|
-
};
|
|
32
11
|
}
|
|
33
12
|
/** 发起收费(内部路由 x402/a2a/batch/invite)。 */
|
|
34
13
|
charge(params) {
|
|
@@ -178,5 +157,27 @@ class PaymentAPI {
|
|
|
178
157
|
transferCancel(transferId) {
|
|
179
158
|
return this.http.post('/v1/payment/transfers/' + encodeURIComponent(transferId) + '/cancel');
|
|
180
159
|
}
|
|
160
|
+
/** 周期订阅扣费(基于已创建的 authorization)。 */
|
|
161
|
+
period = {
|
|
162
|
+
/** 扣减一个周期;返回 authorizationId 与扣费结果。 */
|
|
163
|
+
charge: (authorizationId) => this.http.post('/v1/payment/period/charge', { authorizationId }),
|
|
164
|
+
/** 查询周期授权状态(剩余额度 / 周期 / 状态)。 */
|
|
165
|
+
authorization: (authorizationId) => this.http.get('/v1/payment/period/authorization?authorizationId=' + encodeURIComponent(authorizationId)),
|
|
166
|
+
};
|
|
167
|
+
/** 托管(escrow)链上按量计费 / 退款。 */
|
|
168
|
+
escrow = {
|
|
169
|
+
/** relayer 代为签名扣费:`{chain, user, amountWei, reference}`。 */
|
|
170
|
+
charge: (p) => this.http.post('/v1/payment/escrow/charge', p),
|
|
171
|
+
/** relayer 代为签名退款:`{chain, user, amountWei, reference}`。 */
|
|
172
|
+
refund: (p) => this.http.post('/v1/payment/escrow/refund', p),
|
|
173
|
+
/** 查询托管余额(未配置链返回 `{configured:false, balanceWei:'0'}`)。 */
|
|
174
|
+
balance: (chain, user) => this.http.get('/v1/payment/escrow/balance?' + new URLSearchParams({ chain, user }).toString()),
|
|
175
|
+
/** 查询链上托管配置(地址 / 限额)。 */
|
|
176
|
+
info: (chain) => this.http.get('/v1/payment/escrow/info?chain=' + encodeURIComponent(chain)),
|
|
177
|
+
/** relayer gas 健康;不传 chain 返回全部已配置链。 */
|
|
178
|
+
relayerStatus: (chain) => this.http.get('/v1/payment/escrow/relayer-status' + (chain ? '?chain=' + encodeURIComponent(chain) : '')),
|
|
179
|
+
/** 核验 Solana 原生 SOL 充值并入账(幂等键 `sol:<signature>`)。 */
|
|
180
|
+
solanaVerify: (p) => this.http.post('/v1/payment/solana/verify', p),
|
|
181
|
+
};
|
|
181
182
|
}
|
|
182
183
|
exports.PaymentAPI = PaymentAPI;
|
package/dist/wallet/index.d.ts
CHANGED
package/dist/wallet/index.js
CHANGED
package/dist/wallet/types.d.ts
CHANGED
|
@@ -48,6 +48,84 @@ export interface ChainResult {
|
|
|
48
48
|
result?: unknown;
|
|
49
49
|
txHash?: string;
|
|
50
50
|
}
|
|
51
|
+
/** session key 托管模式:`client` = 客户自持(relay 不生成、不落库私钥);`relay` = relay 生成并持久化。 */
|
|
52
|
+
export type SessionKeyCustody = 'client' | 'relay';
|
|
53
|
+
export interface SessionCreateParams {
|
|
54
|
+
chain: string;
|
|
55
|
+
/** 智能账户 owner EOA 地址。 */
|
|
56
|
+
owner: string;
|
|
57
|
+
/** 权限声明(由链上 session validator 解释)。 */
|
|
58
|
+
permissions: Array<Record<string, unknown>>;
|
|
59
|
+
/** 生效截止时间(Unix 秒)。 */
|
|
60
|
+
validUntil: number;
|
|
61
|
+
/** 生效起始时间(Unix 秒,缺省 0)。 */
|
|
62
|
+
validAfter?: number;
|
|
63
|
+
/** 客户自持的 session key 地址;传入则 relay 不生成、不落库私钥(`/execute` 不可用)。 */
|
|
64
|
+
signer?: string;
|
|
65
|
+
/** 租户/产品标识,缺省 `default`。 */
|
|
66
|
+
product?: string;
|
|
67
|
+
}
|
|
68
|
+
export interface SessionCreated {
|
|
69
|
+
product: string;
|
|
70
|
+
accountAddress: string;
|
|
71
|
+
isDeployed: boolean;
|
|
72
|
+
isBound: boolean;
|
|
73
|
+
sessionId: string;
|
|
74
|
+
/** session key 地址(自持模式即传入的 `signer`)。 */
|
|
75
|
+
signer: string;
|
|
76
|
+
/** 仅 `keyCustody: 'relay'` 返回私钥;客户自持模式为 `null`。 */
|
|
77
|
+
sessionKey: string | null;
|
|
78
|
+
keyCustody: SessionKeyCustody;
|
|
79
|
+
/** 十进制字符串(Unix 秒)。 */
|
|
80
|
+
validAfter: string;
|
|
81
|
+
/** 十进制字符串(Unix 秒)。 */
|
|
82
|
+
validUntil: string;
|
|
83
|
+
permissions: unknown[];
|
|
84
|
+
/** 链上 validator 副本槽位。 */
|
|
85
|
+
slot: number;
|
|
86
|
+
moduleVersion: string;
|
|
87
|
+
/** owner 侧启用 session 的 calldata。 */
|
|
88
|
+
enableCallData: string;
|
|
89
|
+
}
|
|
90
|
+
/** token paymaster 发现信息(不暴露私钥)。 */
|
|
91
|
+
export interface PaymasterInfo {
|
|
92
|
+
chainId: number;
|
|
93
|
+
paymaster: string;
|
|
94
|
+
/** voucher 签发地址(仅用于核对)。 */
|
|
95
|
+
signer: string;
|
|
96
|
+
voucher: {
|
|
97
|
+
maxCostWei: string;
|
|
98
|
+
ttlSec: number;
|
|
99
|
+
maxTtlSec: number;
|
|
100
|
+
perSenderPerDay: number;
|
|
101
|
+
/** 固定意图:只赞助 `approve(paymaster, amount)`。 */
|
|
102
|
+
intent: string;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** 首笔授权 voucher 申请(无需 native、无需已有 allowance)。 */
|
|
106
|
+
export interface PaymasterVoucherParams {
|
|
107
|
+
sender: string;
|
|
108
|
+
/** 待赞助的 callData(`approve(paymaster, amount)`,直连或包在 execute 里)。 */
|
|
109
|
+
callData: string;
|
|
110
|
+
/** 本笔 op 的最大 gas 成本(wei,十进制字符串)。 */
|
|
111
|
+
maxCost: string | bigint;
|
|
112
|
+
/** Unix 秒;缺省按服务端 TTL。 */
|
|
113
|
+
validUntil?: number;
|
|
114
|
+
chainId?: number;
|
|
115
|
+
}
|
|
116
|
+
export interface PaymasterVoucher {
|
|
117
|
+
chainId: number;
|
|
118
|
+
paymaster: string;
|
|
119
|
+
sender: string;
|
|
120
|
+
nonce: string;
|
|
121
|
+
validUntil: number;
|
|
122
|
+
maxCost: string;
|
|
123
|
+
callDataHash: string;
|
|
124
|
+
digest: string;
|
|
125
|
+
signature: string;
|
|
126
|
+
/** 直接放进 UserOp 的 `paymasterData`。 */
|
|
127
|
+
paymasterData: string;
|
|
128
|
+
}
|
|
51
129
|
export interface WalletBalanceParams {
|
|
52
130
|
address: string;
|
|
53
131
|
chain?: string;
|