kawasekit 0.4.0 → 0.6.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/{chunk-6CNAYQOL.js → chunk-7YKRKV6D.js} +18 -4
- package/dist/chunk-7YKRKV6D.js.map +1 -0
- package/dist/{chunk-FD6Q4NB2.js → chunk-NY6VLXQB.js} +137 -32
- package/dist/chunk-NY6VLXQB.js.map +1 -0
- package/dist/{chunk-G3UC6SME.js → chunk-P5563RGP.js} +3 -3
- package/dist/{chunk-G3UC6SME.js.map → chunk-P5563RGP.js.map} +1 -1
- package/dist/{chunk-5TTOAVHE.js → chunk-VJUXTVSW.js} +11 -3
- package/dist/chunk-VJUXTVSW.js.map +1 -0
- package/dist/{chunk-E47SIVFY.js → chunk-X54U6GU4.js} +18 -5
- package/dist/chunk-X54U6GU4.js.map +1 -0
- package/dist/cli/index.cjs +29 -3
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +6 -6
- package/dist/index.cjs +169 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/policy/index.cjs +27 -3
- package/dist/policy/index.cjs.map +1 -1
- package/dist/policy/index.d.cts +41 -3
- package/dist/policy/index.d.ts +41 -3
- package/dist/policy/index.js +2 -2
- package/dist/signer/index.cjs +141 -27
- package/dist/signer/index.cjs.map +1 -1
- package/dist/signer/index.d.cts +58 -2
- package/dist/signer/index.d.ts +58 -2
- package/dist/signer/index.js +3 -3
- package/dist/{spending-policy-BD2Mpm-L.d.ts → spending-policy-BBgXDrVD.d.ts} +10 -3
- package/dist/{spending-policy-CGIaBpg-.d.cts → spending-policy-CwXcTFD_.d.cts} +10 -3
- package/dist/x402/index.cjs.map +1 -1
- package/dist/x402/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-5TTOAVHE.js.map +0 -1
- package/dist/chunk-6CNAYQOL.js.map +0 -1
- package/dist/chunk-E47SIVFY.js.map +0 -1
- package/dist/chunk-FD6Q4NB2.js.map +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { transferJpyc } from '../chunk-RJLDKDWL.js';
|
|
3
|
-
import '../chunk-
|
|
3
|
+
import '../chunk-P5563RGP.js';
|
|
4
4
|
import '../chunk-PVUKX6IF.js';
|
|
5
5
|
import '../chunk-LEHWRDVS.js';
|
|
6
6
|
import '../chunk-TTX3RBIZ.js';
|
|
7
7
|
import '../chunk-QHUCU5YX.js';
|
|
8
8
|
import { issueSessionKey, serializeSessionEnvelope, restoreSessionAccount, revokeSessionKey, rotateSessionKey, parseSessionEnvelope } from '../chunk-N3CVLISJ.js';
|
|
9
|
-
import '../chunk-
|
|
10
|
-
import '../chunk-
|
|
9
|
+
import '../chunk-NY6VLXQB.js';
|
|
10
|
+
import '../chunk-VJUXTVSW.js';
|
|
11
11
|
import '../chunk-WMVJNPX2.js';
|
|
12
|
-
import { createJpycDailyLimitPolicies } from '../chunk-
|
|
13
|
-
import '../chunk-
|
|
12
|
+
import { createJpycDailyLimitPolicies } from '../chunk-X54U6GU4.js';
|
|
13
|
+
import '../chunk-7YKRKV6D.js';
|
|
14
14
|
import { JPYC_DECIMALS, getJpycAddress, jpycAbi } from '../chunk-KT7XDT2T.js';
|
|
15
15
|
import { zerodevRpcUrl, polygon, polygonAmoy } from '../chunk-SOTYGX67.js';
|
|
16
16
|
import { __commonJS, __require, __toESM } from '../chunk-7D4SUZUM.js';
|
|
@@ -980,7 +980,7 @@ function registerTransferCommand(program2) {
|
|
|
980
980
|
}
|
|
981
981
|
|
|
982
982
|
// cli/index.ts
|
|
983
|
-
var CLI_VERSION = "0.
|
|
983
|
+
var CLI_VERSION = "0.6.0" ;
|
|
984
984
|
var program = new Command();
|
|
985
985
|
program.name("kawasekit").description(
|
|
986
986
|
"kawasekit \u2014 CLI for the kawasekit SDK (AI-agent stablecoin payments, Japan-first, JPYC-native)."
|
package/dist/index.cjs
CHANGED
|
@@ -363,6 +363,20 @@ async function transferJpyc(kernelClient, params) {
|
|
|
363
363
|
success: receipt.success
|
|
364
364
|
};
|
|
365
365
|
}
|
|
366
|
+
function normalizeRecipientAllowlist(allowlist) {
|
|
367
|
+
const seen = /* @__PURE__ */ new Set();
|
|
368
|
+
const normalized = [];
|
|
369
|
+
for (const entry of allowlist) {
|
|
370
|
+
const checksummed = viem.getAddress(entry);
|
|
371
|
+
if (!seen.has(checksummed)) {
|
|
372
|
+
seen.add(checksummed);
|
|
373
|
+
normalized.push(checksummed);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return normalized;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// src/policy/daily-limit.ts
|
|
366
380
|
var ONE_DAY_SECONDS = 86400;
|
|
367
381
|
function createJpycDailyLimitPolicies(params) {
|
|
368
382
|
if (params.maxPerTransfer <= 0n) {
|
|
@@ -375,6 +389,17 @@ function createJpycDailyLimitPolicies(params) {
|
|
|
375
389
|
`createJpycDailyLimitPolicies: maxTransfersPerDay must be a positive integer, got ${params.maxTransfersPerDay}.`
|
|
376
390
|
);
|
|
377
391
|
}
|
|
392
|
+
const recipients = params.recipientAllowlist === void 0 || params.recipientAllowlist === "any" ? null : normalizeRecipientAllowlist(params.recipientAllowlist);
|
|
393
|
+
if (recipients !== null && recipients.length === 0) {
|
|
394
|
+
throw new Error(
|
|
395
|
+
'createJpycDailyLimitPolicies: recipientAllowlist must not be empty \u2014 omit it or pass "any" to allow any recipient.'
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
if (recipients !== null && params.callPolicyVersion === policies.CallPolicyVersion.V0_0_1) {
|
|
399
|
+
throw new Error(
|
|
400
|
+
"createJpycDailyLimitPolicies: recipientAllowlist requires callPolicyVersion V0_0_2 or later (the ONE_OF condition is unsupported on V0_0_1)."
|
|
401
|
+
);
|
|
402
|
+
}
|
|
378
403
|
const callPolicy = policies.toCallPolicy({
|
|
379
404
|
policyVersion: params.callPolicyVersion ?? policies.CallPolicyVersion.V0_0_4,
|
|
380
405
|
permissions: [
|
|
@@ -383,8 +408,9 @@ function createJpycDailyLimitPolicies(params) {
|
|
|
383
408
|
abi: jpycAbi,
|
|
384
409
|
functionName: "transfer",
|
|
385
410
|
args: [
|
|
386
|
-
// Recipient:
|
|
387
|
-
|
|
411
|
+
// Recipient (`to`): unrestricted (`null`) unless an allowlist resolved
|
|
412
|
+
// above, in which case it is constrained via the ONE_OF condition.
|
|
413
|
+
recipients === null ? null : { condition: policies.ParamCondition.ONE_OF, value: recipients },
|
|
388
414
|
// value: must be ≤ maxPerTransfer.
|
|
389
415
|
{
|
|
390
416
|
condition: policies.ParamCondition.LESS_THAN_OR_EQUAL,
|
|
@@ -501,7 +527,7 @@ function createSpendingPolicy(params) {
|
|
|
501
527
|
}
|
|
502
528
|
return { token, maxPerSign: l.maxPerSign };
|
|
503
529
|
});
|
|
504
|
-
const recipientAllowlist = params.recipientAllowlist === "any" ? "any" : params.recipientAllowlist
|
|
530
|
+
const recipientAllowlist = params.recipientAllowlist === "any" ? "any" : normalizeRecipientAllowlist(params.recipientAllowlist);
|
|
505
531
|
return {
|
|
506
532
|
version: "1",
|
|
507
533
|
session: { id: params.session.id, notAfter: params.session.notAfter },
|
|
@@ -533,9 +559,17 @@ var PolicyGatedSignerConfigError = class extends Error {
|
|
|
533
559
|
}
|
|
534
560
|
};
|
|
535
561
|
var CoSignUnavailableError = class extends Error {
|
|
562
|
+
/**
|
|
563
|
+
* `true` when the failure is the **transient transport class** (connect failed /
|
|
564
|
+
* connection dropped) — the only class the adapter's bounded retry replays
|
|
565
|
+
* (RFC m6-3a §4.7: never a delivered rejection, never a ban/identifiable-abort,
|
|
566
|
+
* never a protocol anomaly or timeout). Defaults to `false`.
|
|
567
|
+
*/
|
|
568
|
+
transient;
|
|
536
569
|
constructor(message, options) {
|
|
537
|
-
super(message, options);
|
|
570
|
+
super(message, options?.cause === void 0 ? void 0 : { cause: options.cause });
|
|
538
571
|
this.name = "CoSignUnavailableError";
|
|
572
|
+
this.transient = options?.transient ?? false;
|
|
539
573
|
}
|
|
540
574
|
};
|
|
541
575
|
|
|
@@ -837,6 +871,7 @@ function createLocalPolicyGatedSigner(params) {
|
|
|
837
871
|
|
|
838
872
|
// src/signer/mpc-2p-wire.ts
|
|
839
873
|
var WIRE_VERSION = 2;
|
|
874
|
+
var MAX_FRAME_BYTES = 8 * 1024 * 1024;
|
|
840
875
|
function toWireIntent(intent) {
|
|
841
876
|
return {
|
|
842
877
|
token: intent.token.toLowerCase(),
|
|
@@ -891,6 +926,12 @@ function createMpc2pPolicyGatedSigner(params) {
|
|
|
891
926
|
const { agent, transport, authenticator, session } = params;
|
|
892
927
|
const pinned = resolveAssetParam(params.asset);
|
|
893
928
|
const from = viem.getAddress(params.from);
|
|
929
|
+
const wire = params.wire ?? {};
|
|
930
|
+
const maxAttempts = Math.max(1, wire.maxAttempts ?? 2);
|
|
931
|
+
const ceremonyTimeoutMs = wire.ceremonyTimeoutMs ?? 3e4;
|
|
932
|
+
const minWindowSecs = wire.minWindowSecs ?? 30;
|
|
933
|
+
const clockSkewBudgetSecs = wire.clockSkewBudgetSecs ?? 30;
|
|
934
|
+
const maxFrameBytes = wire.maxFrameBytes ?? MAX_FRAME_BYTES;
|
|
894
935
|
const agentEoa = viem.getAddress(agent.groupEoa());
|
|
895
936
|
if (agentEoa !== from) {
|
|
896
937
|
throw new PolicyGatedSignerConfigError(
|
|
@@ -927,23 +968,59 @@ function createMpc2pPolicyGatedSigner(params) {
|
|
|
927
968
|
nonce: intent.nonce
|
|
928
969
|
}
|
|
929
970
|
});
|
|
930
|
-
const
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
}
|
|
937
|
-
const
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
971
|
+
const validBeforeSecs = Number(intent.validBefore);
|
|
972
|
+
const nowSecs = Math.floor(Date.now() / 1e3);
|
|
973
|
+
if (validBeforeSecs - nowSecs < minWindowSecs + clockSkewBudgetSecs) {
|
|
974
|
+
throw new CoSignUnavailableError(
|
|
975
|
+
`intent.validBefore (${validBeforeSecs}) leaves under the minimum ceremony window (${minWindowSecs}s + ${clockSkewBudgetSecs}s clock-skew budget) \u2014 refusing a co-sign that risks being born expired (W11)`
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
const deadlineMs = Math.min(
|
|
979
|
+
Date.now() + ceremonyTimeoutMs,
|
|
980
|
+
(validBeforeSecs - clockSkewBudgetSecs) * 1e3
|
|
981
|
+
);
|
|
982
|
+
let lastTransient;
|
|
983
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
984
|
+
if (Date.now() >= deadlineMs) break;
|
|
985
|
+
const env = {
|
|
986
|
+
ceremonyId: globalThis.crypto.randomUUID(),
|
|
987
|
+
ssid: globalThis.crypto.randomUUID(),
|
|
988
|
+
intent,
|
|
989
|
+
freshnessTs: Math.floor(Date.now() / 1e3),
|
|
990
|
+
freshnessNonce: viem.toHex(globalThis.crypto.getRandomValues(new Uint8Array(16)))
|
|
991
|
+
};
|
|
992
|
+
const authTag = await authenticator.tag(canonicalRequestBytes(env));
|
|
942
993
|
try {
|
|
943
|
-
await
|
|
944
|
-
|
|
994
|
+
const conn = await openConnection(transport);
|
|
995
|
+
try {
|
|
996
|
+
return await runCeremony({
|
|
997
|
+
conn,
|
|
998
|
+
agent,
|
|
999
|
+
sessionId: session.id,
|
|
1000
|
+
env,
|
|
1001
|
+
digest,
|
|
1002
|
+
authTag,
|
|
1003
|
+
from,
|
|
1004
|
+
deadlineMs,
|
|
1005
|
+
maxFrameBytes
|
|
1006
|
+
});
|
|
1007
|
+
} finally {
|
|
1008
|
+
try {
|
|
1009
|
+
await conn.close();
|
|
1010
|
+
} catch {
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
} catch (error) {
|
|
1014
|
+
if (error instanceof CoSignUnavailableError && error.transient && attempt < maxAttempts) {
|
|
1015
|
+
lastTransient = error;
|
|
1016
|
+
continue;
|
|
1017
|
+
}
|
|
1018
|
+
throw error;
|
|
945
1019
|
}
|
|
946
1020
|
}
|
|
1021
|
+
throw lastTransient ?? new CoSignUnavailableError(
|
|
1022
|
+
"co-sign ceremony budget exhausted before validBefore (W11) \u2014 no attempt could start"
|
|
1023
|
+
);
|
|
947
1024
|
},
|
|
948
1025
|
describe() {
|
|
949
1026
|
return {
|
|
@@ -962,23 +1039,32 @@ async function openConnection(transport) {
|
|
|
962
1039
|
try {
|
|
963
1040
|
return await transport.connect();
|
|
964
1041
|
} catch (cause) {
|
|
965
|
-
throw new CoSignUnavailableError("co-signer connection failed", { cause });
|
|
1042
|
+
throw new CoSignUnavailableError("co-signer connection failed", { cause, transient: true });
|
|
966
1043
|
}
|
|
967
1044
|
}
|
|
968
|
-
async function runCeremony(
|
|
1045
|
+
async function runCeremony(ctx) {
|
|
1046
|
+
const { conn, agent, env, digest, from } = ctx;
|
|
969
1047
|
const send = async (frame) => {
|
|
970
1048
|
try {
|
|
971
|
-
await conn.send(frame);
|
|
1049
|
+
await withDeadline(conn.send(frame), ctx.deadlineMs);
|
|
972
1050
|
} catch (cause) {
|
|
973
|
-
|
|
1051
|
+
if (cause instanceof CoSignUnavailableError) throw cause;
|
|
1052
|
+
throw new CoSignUnavailableError("co-sign connection dropped while sending", {
|
|
1053
|
+
cause,
|
|
1054
|
+
transient: true
|
|
1055
|
+
});
|
|
974
1056
|
}
|
|
975
1057
|
};
|
|
976
1058
|
const recv = async () => {
|
|
977
1059
|
let frame;
|
|
978
1060
|
try {
|
|
979
|
-
frame = await conn.recv();
|
|
1061
|
+
frame = await withDeadline(conn.recv(), ctx.deadlineMs);
|
|
980
1062
|
} catch (cause) {
|
|
981
|
-
|
|
1063
|
+
if (cause instanceof CoSignUnavailableError) throw cause;
|
|
1064
|
+
throw new CoSignUnavailableError("co-sign connection dropped mid-ceremony", {
|
|
1065
|
+
cause,
|
|
1066
|
+
transient: true
|
|
1067
|
+
});
|
|
982
1068
|
}
|
|
983
1069
|
if (frame.wire_version !== WIRE_VERSION) {
|
|
984
1070
|
throw new CoSignUnavailableError(
|
|
@@ -990,13 +1076,13 @@ async function runCeremony(conn, agent, sessionId, env, digest, authTag) {
|
|
|
990
1076
|
await send({
|
|
991
1077
|
wire_version: WIRE_VERSION,
|
|
992
1078
|
kind: "request",
|
|
993
|
-
session_id: sessionId,
|
|
1079
|
+
session_id: ctx.sessionId,
|
|
994
1080
|
ceremony_id: env.ceremonyId,
|
|
995
1081
|
ssid: env.ssid,
|
|
996
1082
|
intent: toWireIntent(env.intent),
|
|
997
1083
|
freshness_ts: env.freshnessTs,
|
|
998
1084
|
freshness_nonce: env.freshnessNonce,
|
|
999
|
-
auth_tag: authTag
|
|
1085
|
+
auth_tag: ctx.authTag
|
|
1000
1086
|
});
|
|
1001
1087
|
let first;
|
|
1002
1088
|
try {
|
|
@@ -1010,6 +1096,12 @@ async function runCeremony(conn, agent, sessionId, env, digest, authTag) {
|
|
|
1010
1096
|
const frame = await recv();
|
|
1011
1097
|
switch (frame.kind) {
|
|
1012
1098
|
case "round": {
|
|
1099
|
+
const payloadBytes = (frame.payload.length - 2) / 2;
|
|
1100
|
+
if (payloadBytes > ctx.maxFrameBytes) {
|
|
1101
|
+
throw new CoSignUnavailableError(
|
|
1102
|
+
`co-signer sent a ${payloadBytes}-byte round frame (bound ${ctx.maxFrameBytes}) \u2014 refused pre-decode`
|
|
1103
|
+
);
|
|
1104
|
+
}
|
|
1013
1105
|
let step;
|
|
1014
1106
|
try {
|
|
1015
1107
|
step = agent.step(frame.payload);
|
|
@@ -1024,15 +1116,16 @@ async function runCeremony(conn, agent, sessionId, env, digest, authTag) {
|
|
|
1024
1116
|
break;
|
|
1025
1117
|
}
|
|
1026
1118
|
case "result": {
|
|
1119
|
+
const signature = assembleSignature({ r: frame.r, s: frame.s, v: frame.v });
|
|
1027
1120
|
if (agentSig === null) {
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
);
|
|
1121
|
+
await verifyRecovers(digest, signature, frame.s, from, "idempotent-replay");
|
|
1122
|
+
return { ok: true, signature, intent: env.intent };
|
|
1031
1123
|
}
|
|
1032
1124
|
if (frame.r.toLowerCase() !== agentSig.r.toLowerCase() || frame.s.toLowerCase() !== agentSig.s.toLowerCase() || frame.v !== agentSig.v) {
|
|
1033
1125
|
throw new CoSignUnavailableError("the backend and agent derived different signatures");
|
|
1034
1126
|
}
|
|
1035
|
-
|
|
1127
|
+
await verifyRecovers(digest, signature, frame.s, from, "co-signed");
|
|
1128
|
+
return { ok: true, signature, intent: env.intent };
|
|
1036
1129
|
}
|
|
1037
1130
|
case "rejection": {
|
|
1038
1131
|
if (POLICY_REASONS.has(frame.reason)) {
|
|
@@ -1051,6 +1144,52 @@ async function runCeremony(conn, agent, sessionId, env, digest, authTag) {
|
|
|
1051
1144
|
}
|
|
1052
1145
|
}
|
|
1053
1146
|
}
|
|
1147
|
+
function withDeadline(promise, deadlineMs) {
|
|
1148
|
+
const remaining = deadlineMs - Date.now();
|
|
1149
|
+
if (remaining <= 0) {
|
|
1150
|
+
return Promise.reject(
|
|
1151
|
+
new CoSignUnavailableError(
|
|
1152
|
+
"co-sign ceremony timed out (the deadline fires before validBefore \u2014 W11)"
|
|
1153
|
+
)
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
1156
|
+
return new Promise((resolve, reject) => {
|
|
1157
|
+
const timer = setTimeout(() => {
|
|
1158
|
+
reject(
|
|
1159
|
+
new CoSignUnavailableError(
|
|
1160
|
+
"co-sign ceremony timed out (the deadline fires before validBefore \u2014 W11)"
|
|
1161
|
+
)
|
|
1162
|
+
);
|
|
1163
|
+
}, remaining);
|
|
1164
|
+
promise.then(
|
|
1165
|
+
(value) => {
|
|
1166
|
+
clearTimeout(timer);
|
|
1167
|
+
resolve(value);
|
|
1168
|
+
},
|
|
1169
|
+
(cause) => {
|
|
1170
|
+
clearTimeout(timer);
|
|
1171
|
+
reject(cause);
|
|
1172
|
+
}
|
|
1173
|
+
);
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
var SECP256K1_HALF_N = 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0n;
|
|
1177
|
+
async function verifyRecovers(digest, signature, s, from, what) {
|
|
1178
|
+
if (BigInt(s) > SECP256K1_HALF_N) {
|
|
1179
|
+
throw new CoSignUnavailableError(`the ${what} signature is not low-S (EIP-2)`);
|
|
1180
|
+
}
|
|
1181
|
+
let recovered;
|
|
1182
|
+
try {
|
|
1183
|
+
recovered = await viem.recoverAddress({ hash: digest, signature });
|
|
1184
|
+
} catch (cause) {
|
|
1185
|
+
throw new CoSignUnavailableError(`the ${what} signature failed to recover`, { cause });
|
|
1186
|
+
}
|
|
1187
|
+
if (viem.getAddress(recovered) !== from) {
|
|
1188
|
+
throw new CoSignUnavailableError(
|
|
1189
|
+
`the ${what} signature recovers to ${viem.getAddress(recovered)}, not the group EOA ${from}`
|
|
1190
|
+
);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1054
1193
|
function assembleSignature(sig) {
|
|
1055
1194
|
const yParity = sig.v - 27;
|
|
1056
1195
|
if (yParity !== 0 && yParity !== 1) {
|