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/signer/index.cjs
CHANGED
|
@@ -17,9 +17,17 @@ var PolicyGatedSignerConfigError = class extends Error {
|
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
19
|
var CoSignUnavailableError = class extends Error {
|
|
20
|
+
/**
|
|
21
|
+
* `true` when the failure is the **transient transport class** (connect failed /
|
|
22
|
+
* connection dropped) — the only class the adapter's bounded retry replays
|
|
23
|
+
* (RFC m6-3a §4.7: never a delivered rejection, never a ban/identifiable-abort,
|
|
24
|
+
* never a protocol anomaly or timeout). Defaults to `false`.
|
|
25
|
+
*/
|
|
26
|
+
transient;
|
|
20
27
|
constructor(message, options) {
|
|
21
|
-
super(message, options);
|
|
28
|
+
super(message, options?.cause === void 0 ? void 0 : { cause: options.cause });
|
|
22
29
|
this.name = "CoSignUnavailableError";
|
|
30
|
+
this.transient = options?.transient ?? false;
|
|
23
31
|
}
|
|
24
32
|
};
|
|
25
33
|
|
|
@@ -363,6 +371,7 @@ function createLocalPolicyGatedSigner(params) {
|
|
|
363
371
|
|
|
364
372
|
// src/signer/mpc-2p-wire.ts
|
|
365
373
|
var WIRE_VERSION = 2;
|
|
374
|
+
var MAX_FRAME_BYTES = 8 * 1024 * 1024;
|
|
366
375
|
function toWireIntent(intent) {
|
|
367
376
|
return {
|
|
368
377
|
token: intent.token.toLowerCase(),
|
|
@@ -417,6 +426,12 @@ function createMpc2pPolicyGatedSigner(params) {
|
|
|
417
426
|
const { agent, transport, authenticator, session } = params;
|
|
418
427
|
const pinned = resolveAssetParam(params.asset);
|
|
419
428
|
const from = viem.getAddress(params.from);
|
|
429
|
+
const wire = params.wire ?? {};
|
|
430
|
+
const maxAttempts = Math.max(1, wire.maxAttempts ?? 2);
|
|
431
|
+
const ceremonyTimeoutMs = wire.ceremonyTimeoutMs ?? 3e4;
|
|
432
|
+
const minWindowSecs = wire.minWindowSecs ?? 30;
|
|
433
|
+
const clockSkewBudgetSecs = wire.clockSkewBudgetSecs ?? 30;
|
|
434
|
+
const maxFrameBytes = wire.maxFrameBytes ?? MAX_FRAME_BYTES;
|
|
420
435
|
const agentEoa = viem.getAddress(agent.groupEoa());
|
|
421
436
|
if (agentEoa !== from) {
|
|
422
437
|
throw new PolicyGatedSignerConfigError(
|
|
@@ -453,23 +468,59 @@ function createMpc2pPolicyGatedSigner(params) {
|
|
|
453
468
|
nonce: intent.nonce
|
|
454
469
|
}
|
|
455
470
|
});
|
|
456
|
-
const
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
}
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
471
|
+
const validBeforeSecs = Number(intent.validBefore);
|
|
472
|
+
const nowSecs = Math.floor(Date.now() / 1e3);
|
|
473
|
+
if (validBeforeSecs - nowSecs < minWindowSecs + clockSkewBudgetSecs) {
|
|
474
|
+
throw new CoSignUnavailableError(
|
|
475
|
+
`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)`
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
const deadlineMs = Math.min(
|
|
479
|
+
Date.now() + ceremonyTimeoutMs,
|
|
480
|
+
(validBeforeSecs - clockSkewBudgetSecs) * 1e3
|
|
481
|
+
);
|
|
482
|
+
let lastTransient;
|
|
483
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
484
|
+
if (Date.now() >= deadlineMs) break;
|
|
485
|
+
const env = {
|
|
486
|
+
ceremonyId: globalThis.crypto.randomUUID(),
|
|
487
|
+
ssid: globalThis.crypto.randomUUID(),
|
|
488
|
+
intent,
|
|
489
|
+
freshnessTs: Math.floor(Date.now() / 1e3),
|
|
490
|
+
freshnessNonce: viem.toHex(globalThis.crypto.getRandomValues(new Uint8Array(16)))
|
|
491
|
+
};
|
|
492
|
+
const authTag = await authenticator.tag(canonicalRequestBytes(env));
|
|
468
493
|
try {
|
|
469
|
-
await
|
|
470
|
-
|
|
494
|
+
const conn = await openConnection(transport);
|
|
495
|
+
try {
|
|
496
|
+
return await runCeremony({
|
|
497
|
+
conn,
|
|
498
|
+
agent,
|
|
499
|
+
sessionId: session.id,
|
|
500
|
+
env,
|
|
501
|
+
digest,
|
|
502
|
+
authTag,
|
|
503
|
+
from,
|
|
504
|
+
deadlineMs,
|
|
505
|
+
maxFrameBytes
|
|
506
|
+
});
|
|
507
|
+
} finally {
|
|
508
|
+
try {
|
|
509
|
+
await conn.close();
|
|
510
|
+
} catch {
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
} catch (error) {
|
|
514
|
+
if (error instanceof CoSignUnavailableError && error.transient && attempt < maxAttempts) {
|
|
515
|
+
lastTransient = error;
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
throw error;
|
|
471
519
|
}
|
|
472
520
|
}
|
|
521
|
+
throw lastTransient ?? new CoSignUnavailableError(
|
|
522
|
+
"co-sign ceremony budget exhausted before validBefore (W11) \u2014 no attempt could start"
|
|
523
|
+
);
|
|
473
524
|
},
|
|
474
525
|
describe() {
|
|
475
526
|
return {
|
|
@@ -488,23 +539,32 @@ async function openConnection(transport) {
|
|
|
488
539
|
try {
|
|
489
540
|
return await transport.connect();
|
|
490
541
|
} catch (cause) {
|
|
491
|
-
throw new CoSignUnavailableError("co-signer connection failed", { cause });
|
|
542
|
+
throw new CoSignUnavailableError("co-signer connection failed", { cause, transient: true });
|
|
492
543
|
}
|
|
493
544
|
}
|
|
494
|
-
async function runCeremony(
|
|
545
|
+
async function runCeremony(ctx) {
|
|
546
|
+
const { conn, agent, env, digest, from } = ctx;
|
|
495
547
|
const send = async (frame) => {
|
|
496
548
|
try {
|
|
497
|
-
await conn.send(frame);
|
|
549
|
+
await withDeadline(conn.send(frame), ctx.deadlineMs);
|
|
498
550
|
} catch (cause) {
|
|
499
|
-
|
|
551
|
+
if (cause instanceof CoSignUnavailableError) throw cause;
|
|
552
|
+
throw new CoSignUnavailableError("co-sign connection dropped while sending", {
|
|
553
|
+
cause,
|
|
554
|
+
transient: true
|
|
555
|
+
});
|
|
500
556
|
}
|
|
501
557
|
};
|
|
502
558
|
const recv = async () => {
|
|
503
559
|
let frame;
|
|
504
560
|
try {
|
|
505
|
-
frame = await conn.recv();
|
|
561
|
+
frame = await withDeadline(conn.recv(), ctx.deadlineMs);
|
|
506
562
|
} catch (cause) {
|
|
507
|
-
|
|
563
|
+
if (cause instanceof CoSignUnavailableError) throw cause;
|
|
564
|
+
throw new CoSignUnavailableError("co-sign connection dropped mid-ceremony", {
|
|
565
|
+
cause,
|
|
566
|
+
transient: true
|
|
567
|
+
});
|
|
508
568
|
}
|
|
509
569
|
if (frame.wire_version !== WIRE_VERSION) {
|
|
510
570
|
throw new CoSignUnavailableError(
|
|
@@ -516,13 +576,13 @@ async function runCeremony(conn, agent, sessionId, env, digest, authTag) {
|
|
|
516
576
|
await send({
|
|
517
577
|
wire_version: WIRE_VERSION,
|
|
518
578
|
kind: "request",
|
|
519
|
-
session_id: sessionId,
|
|
579
|
+
session_id: ctx.sessionId,
|
|
520
580
|
ceremony_id: env.ceremonyId,
|
|
521
581
|
ssid: env.ssid,
|
|
522
582
|
intent: toWireIntent(env.intent),
|
|
523
583
|
freshness_ts: env.freshnessTs,
|
|
524
584
|
freshness_nonce: env.freshnessNonce,
|
|
525
|
-
auth_tag: authTag
|
|
585
|
+
auth_tag: ctx.authTag
|
|
526
586
|
});
|
|
527
587
|
let first;
|
|
528
588
|
try {
|
|
@@ -536,6 +596,12 @@ async function runCeremony(conn, agent, sessionId, env, digest, authTag) {
|
|
|
536
596
|
const frame = await recv();
|
|
537
597
|
switch (frame.kind) {
|
|
538
598
|
case "round": {
|
|
599
|
+
const payloadBytes = (frame.payload.length - 2) / 2;
|
|
600
|
+
if (payloadBytes > ctx.maxFrameBytes) {
|
|
601
|
+
throw new CoSignUnavailableError(
|
|
602
|
+
`co-signer sent a ${payloadBytes}-byte round frame (bound ${ctx.maxFrameBytes}) \u2014 refused pre-decode`
|
|
603
|
+
);
|
|
604
|
+
}
|
|
539
605
|
let step;
|
|
540
606
|
try {
|
|
541
607
|
step = agent.step(frame.payload);
|
|
@@ -550,15 +616,16 @@ async function runCeremony(conn, agent, sessionId, env, digest, authTag) {
|
|
|
550
616
|
break;
|
|
551
617
|
}
|
|
552
618
|
case "result": {
|
|
619
|
+
const signature = assembleSignature({ r: frame.r, s: frame.s, v: frame.v });
|
|
553
620
|
if (agentSig === null) {
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
);
|
|
621
|
+
await verifyRecovers(digest, signature, frame.s, from, "idempotent-replay");
|
|
622
|
+
return { ok: true, signature, intent: env.intent };
|
|
557
623
|
}
|
|
558
624
|
if (frame.r.toLowerCase() !== agentSig.r.toLowerCase() || frame.s.toLowerCase() !== agentSig.s.toLowerCase() || frame.v !== agentSig.v) {
|
|
559
625
|
throw new CoSignUnavailableError("the backend and agent derived different signatures");
|
|
560
626
|
}
|
|
561
|
-
|
|
627
|
+
await verifyRecovers(digest, signature, frame.s, from, "co-signed");
|
|
628
|
+
return { ok: true, signature, intent: env.intent };
|
|
562
629
|
}
|
|
563
630
|
case "rejection": {
|
|
564
631
|
if (POLICY_REASONS.has(frame.reason)) {
|
|
@@ -577,6 +644,52 @@ async function runCeremony(conn, agent, sessionId, env, digest, authTag) {
|
|
|
577
644
|
}
|
|
578
645
|
}
|
|
579
646
|
}
|
|
647
|
+
function withDeadline(promise, deadlineMs) {
|
|
648
|
+
const remaining = deadlineMs - Date.now();
|
|
649
|
+
if (remaining <= 0) {
|
|
650
|
+
return Promise.reject(
|
|
651
|
+
new CoSignUnavailableError(
|
|
652
|
+
"co-sign ceremony timed out (the deadline fires before validBefore \u2014 W11)"
|
|
653
|
+
)
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
return new Promise((resolve, reject) => {
|
|
657
|
+
const timer = setTimeout(() => {
|
|
658
|
+
reject(
|
|
659
|
+
new CoSignUnavailableError(
|
|
660
|
+
"co-sign ceremony timed out (the deadline fires before validBefore \u2014 W11)"
|
|
661
|
+
)
|
|
662
|
+
);
|
|
663
|
+
}, remaining);
|
|
664
|
+
promise.then(
|
|
665
|
+
(value) => {
|
|
666
|
+
clearTimeout(timer);
|
|
667
|
+
resolve(value);
|
|
668
|
+
},
|
|
669
|
+
(cause) => {
|
|
670
|
+
clearTimeout(timer);
|
|
671
|
+
reject(cause);
|
|
672
|
+
}
|
|
673
|
+
);
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
var SECP256K1_HALF_N = 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0n;
|
|
677
|
+
async function verifyRecovers(digest, signature, s, from, what) {
|
|
678
|
+
if (BigInt(s) > SECP256K1_HALF_N) {
|
|
679
|
+
throw new CoSignUnavailableError(`the ${what} signature is not low-S (EIP-2)`);
|
|
680
|
+
}
|
|
681
|
+
let recovered;
|
|
682
|
+
try {
|
|
683
|
+
recovered = await viem.recoverAddress({ hash: digest, signature });
|
|
684
|
+
} catch (cause) {
|
|
685
|
+
throw new CoSignUnavailableError(`the ${what} signature failed to recover`, { cause });
|
|
686
|
+
}
|
|
687
|
+
if (viem.getAddress(recovered) !== from) {
|
|
688
|
+
throw new CoSignUnavailableError(
|
|
689
|
+
`the ${what} signature recovers to ${viem.getAddress(recovered)}, not the group EOA ${from}`
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
580
693
|
function assembleSignature(sig) {
|
|
581
694
|
const yParity = sig.v - 27;
|
|
582
695
|
if (yParity !== 0 && yParity !== 1) {
|
|
@@ -586,6 +699,7 @@ function assembleSignature(sig) {
|
|
|
586
699
|
}
|
|
587
700
|
|
|
588
701
|
exports.CoSignUnavailableError = CoSignUnavailableError;
|
|
702
|
+
exports.MAX_FRAME_BYTES = MAX_FRAME_BYTES;
|
|
589
703
|
exports.PolicyGatedSignerConfigError = PolicyGatedSignerConfigError;
|
|
590
704
|
exports.WIRE_VERSION = WIRE_VERSION;
|
|
591
705
|
exports.assertNonBypassable = assertNonBypassable;
|