kawasekit 0.3.0 → 0.5.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-G3UC6SME.js → chunk-P5563RGP.js} +3 -3
- package/dist/{chunk-G3UC6SME.js.map → chunk-P5563RGP.js.map} +1 -1
- package/dist/{chunk-EUW7AZ4P.js → chunk-S2ZSX2VS.js} +158 -36
- package/dist/chunk-S2ZSX2VS.js.map +1 -0
- package/dist/{chunk-5TTOAVHE.js → chunk-VJUXTVSW.js} +11 -3
- package/dist/chunk-VJUXTVSW.js.map +1 -0
- package/dist/cli/index.cjs +1 -1
- package/dist/cli/index.js +4 -4
- package/dist/index.cjs +163 -33
- 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 +3 -3
- package/dist/signer/index.cjs +164 -33
- package/dist/signer/index.cjs.map +1 -1
- package/dist/signer/index.d.cts +96 -20
- package/dist/signer/index.d.ts +96 -20
- package/dist/signer/index.js +2 -2
- 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-EUW7AZ4P.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -533,9 +533,17 @@ var PolicyGatedSignerConfigError = class extends Error {
|
|
|
533
533
|
}
|
|
534
534
|
};
|
|
535
535
|
var CoSignUnavailableError = class extends Error {
|
|
536
|
+
/**
|
|
537
|
+
* `true` when the failure is the **transient transport class** (connect failed /
|
|
538
|
+
* connection dropped) — the only class the adapter's bounded retry replays
|
|
539
|
+
* (RFC m6-3a §4.7: never a delivered rejection, never a ban/identifiable-abort,
|
|
540
|
+
* never a protocol anomaly or timeout). Defaults to `false`.
|
|
541
|
+
*/
|
|
542
|
+
transient;
|
|
536
543
|
constructor(message, options) {
|
|
537
|
-
super(message, options);
|
|
544
|
+
super(message, options?.cause === void 0 ? void 0 : { cause: options.cause });
|
|
538
545
|
this.name = "CoSignUnavailableError";
|
|
546
|
+
this.transient = options?.transient ?? false;
|
|
539
547
|
}
|
|
540
548
|
};
|
|
541
549
|
|
|
@@ -836,7 +844,8 @@ function createLocalPolicyGatedSigner(params) {
|
|
|
836
844
|
}
|
|
837
845
|
|
|
838
846
|
// src/signer/mpc-2p-wire.ts
|
|
839
|
-
var WIRE_VERSION =
|
|
847
|
+
var WIRE_VERSION = 2;
|
|
848
|
+
var MAX_FRAME_BYTES = 8 * 1024 * 1024;
|
|
840
849
|
function toWireIntent(intent) {
|
|
841
850
|
return {
|
|
842
851
|
token: intent.token.toLowerCase(),
|
|
@@ -849,17 +858,23 @@ function toWireIntent(intent) {
|
|
|
849
858
|
nonce: intent.nonce.toLowerCase()
|
|
850
859
|
};
|
|
851
860
|
}
|
|
852
|
-
function
|
|
861
|
+
function canonicalRequestBytes(env) {
|
|
862
|
+
const i = env.intent;
|
|
853
863
|
const lines = [
|
|
854
|
-
"kawasekit-mpc-2p/cosign-request/
|
|
855
|
-
|
|
856
|
-
`
|
|
857
|
-
`
|
|
858
|
-
`
|
|
859
|
-
`
|
|
860
|
-
`
|
|
861
|
-
`
|
|
862
|
-
`
|
|
864
|
+
"kawasekit-mpc-2p/cosign-request/v3",
|
|
865
|
+
"wireVersion=2",
|
|
866
|
+
`ceremonyId=${env.ceremonyId}`,
|
|
867
|
+
`ssid=${env.ssid}`,
|
|
868
|
+
`token=${i.token.toLowerCase()}`,
|
|
869
|
+
`chainId=${i.chainId}`,
|
|
870
|
+
`from=${i.from.toLowerCase()}`,
|
|
871
|
+
`to=${i.to.toLowerCase()}`,
|
|
872
|
+
`value=${i.value}`,
|
|
873
|
+
`validAfter=${i.validAfter}`,
|
|
874
|
+
`validBefore=${i.validBefore}`,
|
|
875
|
+
`nonce=${i.nonce.toLowerCase()}`,
|
|
876
|
+
`freshnessTs=${env.freshnessTs}`,
|
|
877
|
+
`freshnessNonce=${env.freshnessNonce.toLowerCase()}`
|
|
863
878
|
];
|
|
864
879
|
return new TextEncoder().encode(lines.map((l) => `${l}
|
|
865
880
|
`).join(""));
|
|
@@ -885,6 +900,12 @@ function createMpc2pPolicyGatedSigner(params) {
|
|
|
885
900
|
const { agent, transport, authenticator, session } = params;
|
|
886
901
|
const pinned = resolveAssetParam(params.asset);
|
|
887
902
|
const from = viem.getAddress(params.from);
|
|
903
|
+
const wire = params.wire ?? {};
|
|
904
|
+
const maxAttempts = Math.max(1, wire.maxAttempts ?? 2);
|
|
905
|
+
const ceremonyTimeoutMs = wire.ceremonyTimeoutMs ?? 3e4;
|
|
906
|
+
const minWindowSecs = wire.minWindowSecs ?? 30;
|
|
907
|
+
const clockSkewBudgetSecs = wire.clockSkewBudgetSecs ?? 30;
|
|
908
|
+
const maxFrameBytes = wire.maxFrameBytes ?? MAX_FRAME_BYTES;
|
|
888
909
|
const agentEoa = viem.getAddress(agent.groupEoa());
|
|
889
910
|
if (agentEoa !== from) {
|
|
890
911
|
throw new PolicyGatedSignerConfigError(
|
|
@@ -921,16 +942,59 @@ function createMpc2pPolicyGatedSigner(params) {
|
|
|
921
942
|
nonce: intent.nonce
|
|
922
943
|
}
|
|
923
944
|
});
|
|
924
|
-
const
|
|
925
|
-
const
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
945
|
+
const validBeforeSecs = Number(intent.validBefore);
|
|
946
|
+
const nowSecs = Math.floor(Date.now() / 1e3);
|
|
947
|
+
if (validBeforeSecs - nowSecs < minWindowSecs + clockSkewBudgetSecs) {
|
|
948
|
+
throw new CoSignUnavailableError(
|
|
949
|
+
`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)`
|
|
950
|
+
);
|
|
951
|
+
}
|
|
952
|
+
const deadlineMs = Math.min(
|
|
953
|
+
Date.now() + ceremonyTimeoutMs,
|
|
954
|
+
(validBeforeSecs - clockSkewBudgetSecs) * 1e3
|
|
955
|
+
);
|
|
956
|
+
let lastTransient;
|
|
957
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
958
|
+
if (Date.now() >= deadlineMs) break;
|
|
959
|
+
const env = {
|
|
960
|
+
ceremonyId: globalThis.crypto.randomUUID(),
|
|
961
|
+
ssid: globalThis.crypto.randomUUID(),
|
|
962
|
+
intent,
|
|
963
|
+
freshnessTs: Math.floor(Date.now() / 1e3),
|
|
964
|
+
freshnessNonce: viem.toHex(globalThis.crypto.getRandomValues(new Uint8Array(16)))
|
|
965
|
+
};
|
|
966
|
+
const authTag = await authenticator.tag(canonicalRequestBytes(env));
|
|
929
967
|
try {
|
|
930
|
-
await
|
|
931
|
-
|
|
968
|
+
const conn = await openConnection(transport);
|
|
969
|
+
try {
|
|
970
|
+
return await runCeremony({
|
|
971
|
+
conn,
|
|
972
|
+
agent,
|
|
973
|
+
sessionId: session.id,
|
|
974
|
+
env,
|
|
975
|
+
digest,
|
|
976
|
+
authTag,
|
|
977
|
+
from,
|
|
978
|
+
deadlineMs,
|
|
979
|
+
maxFrameBytes
|
|
980
|
+
});
|
|
981
|
+
} finally {
|
|
982
|
+
try {
|
|
983
|
+
await conn.close();
|
|
984
|
+
} catch {
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
} catch (error) {
|
|
988
|
+
if (error instanceof CoSignUnavailableError && error.transient && attempt < maxAttempts) {
|
|
989
|
+
lastTransient = error;
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
throw error;
|
|
932
993
|
}
|
|
933
994
|
}
|
|
995
|
+
throw lastTransient ?? new CoSignUnavailableError(
|
|
996
|
+
"co-sign ceremony budget exhausted before validBefore (W11) \u2014 no attempt could start"
|
|
997
|
+
);
|
|
934
998
|
},
|
|
935
999
|
describe() {
|
|
936
1000
|
return {
|
|
@@ -949,23 +1013,32 @@ async function openConnection(transport) {
|
|
|
949
1013
|
try {
|
|
950
1014
|
return await transport.connect();
|
|
951
1015
|
} catch (cause) {
|
|
952
|
-
throw new CoSignUnavailableError("co-signer connection failed", { cause });
|
|
1016
|
+
throw new CoSignUnavailableError("co-signer connection failed", { cause, transient: true });
|
|
953
1017
|
}
|
|
954
1018
|
}
|
|
955
|
-
async function runCeremony(
|
|
1019
|
+
async function runCeremony(ctx) {
|
|
1020
|
+
const { conn, agent, env, digest, from } = ctx;
|
|
956
1021
|
const send = async (frame) => {
|
|
957
1022
|
try {
|
|
958
|
-
await conn.send(frame);
|
|
1023
|
+
await withDeadline(conn.send(frame), ctx.deadlineMs);
|
|
959
1024
|
} catch (cause) {
|
|
960
|
-
|
|
1025
|
+
if (cause instanceof CoSignUnavailableError) throw cause;
|
|
1026
|
+
throw new CoSignUnavailableError("co-sign connection dropped while sending", {
|
|
1027
|
+
cause,
|
|
1028
|
+
transient: true
|
|
1029
|
+
});
|
|
961
1030
|
}
|
|
962
1031
|
};
|
|
963
1032
|
const recv = async () => {
|
|
964
1033
|
let frame;
|
|
965
1034
|
try {
|
|
966
|
-
frame = await conn.recv();
|
|
1035
|
+
frame = await withDeadline(conn.recv(), ctx.deadlineMs);
|
|
967
1036
|
} catch (cause) {
|
|
968
|
-
|
|
1037
|
+
if (cause instanceof CoSignUnavailableError) throw cause;
|
|
1038
|
+
throw new CoSignUnavailableError("co-sign connection dropped mid-ceremony", {
|
|
1039
|
+
cause,
|
|
1040
|
+
transient: true
|
|
1041
|
+
});
|
|
969
1042
|
}
|
|
970
1043
|
if (frame.wire_version !== WIRE_VERSION) {
|
|
971
1044
|
throw new CoSignUnavailableError(
|
|
@@ -977,9 +1050,13 @@ async function runCeremony(conn, agent, sessionId, intent, digest, authTag) {
|
|
|
977
1050
|
await send({
|
|
978
1051
|
wire_version: WIRE_VERSION,
|
|
979
1052
|
kind: "request",
|
|
980
|
-
session_id: sessionId,
|
|
981
|
-
|
|
982
|
-
|
|
1053
|
+
session_id: ctx.sessionId,
|
|
1054
|
+
ceremony_id: env.ceremonyId,
|
|
1055
|
+
ssid: env.ssid,
|
|
1056
|
+
intent: toWireIntent(env.intent),
|
|
1057
|
+
freshness_ts: env.freshnessTs,
|
|
1058
|
+
freshness_nonce: env.freshnessNonce,
|
|
1059
|
+
auth_tag: ctx.authTag
|
|
983
1060
|
});
|
|
984
1061
|
let first;
|
|
985
1062
|
try {
|
|
@@ -993,6 +1070,12 @@ async function runCeremony(conn, agent, sessionId, intent, digest, authTag) {
|
|
|
993
1070
|
const frame = await recv();
|
|
994
1071
|
switch (frame.kind) {
|
|
995
1072
|
case "round": {
|
|
1073
|
+
const payloadBytes = (frame.payload.length - 2) / 2;
|
|
1074
|
+
if (payloadBytes > ctx.maxFrameBytes) {
|
|
1075
|
+
throw new CoSignUnavailableError(
|
|
1076
|
+
`co-signer sent a ${payloadBytes}-byte round frame (bound ${ctx.maxFrameBytes}) \u2014 refused pre-decode`
|
|
1077
|
+
);
|
|
1078
|
+
}
|
|
996
1079
|
let step;
|
|
997
1080
|
try {
|
|
998
1081
|
step = agent.step(frame.payload);
|
|
@@ -1007,15 +1090,16 @@ async function runCeremony(conn, agent, sessionId, intent, digest, authTag) {
|
|
|
1007
1090
|
break;
|
|
1008
1091
|
}
|
|
1009
1092
|
case "result": {
|
|
1093
|
+
const signature = assembleSignature({ r: frame.r, s: frame.s, v: frame.v });
|
|
1010
1094
|
if (agentSig === null) {
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
);
|
|
1095
|
+
await verifyRecovers(digest, signature, frame.s, from, "idempotent-replay");
|
|
1096
|
+
return { ok: true, signature, intent: env.intent };
|
|
1014
1097
|
}
|
|
1015
1098
|
if (frame.r.toLowerCase() !== agentSig.r.toLowerCase() || frame.s.toLowerCase() !== agentSig.s.toLowerCase() || frame.v !== agentSig.v) {
|
|
1016
1099
|
throw new CoSignUnavailableError("the backend and agent derived different signatures");
|
|
1017
1100
|
}
|
|
1018
|
-
|
|
1101
|
+
await verifyRecovers(digest, signature, frame.s, from, "co-signed");
|
|
1102
|
+
return { ok: true, signature, intent: env.intent };
|
|
1019
1103
|
}
|
|
1020
1104
|
case "rejection": {
|
|
1021
1105
|
if (POLICY_REASONS.has(frame.reason)) {
|
|
@@ -1034,6 +1118,52 @@ async function runCeremony(conn, agent, sessionId, intent, digest, authTag) {
|
|
|
1034
1118
|
}
|
|
1035
1119
|
}
|
|
1036
1120
|
}
|
|
1121
|
+
function withDeadline(promise, deadlineMs) {
|
|
1122
|
+
const remaining = deadlineMs - Date.now();
|
|
1123
|
+
if (remaining <= 0) {
|
|
1124
|
+
return Promise.reject(
|
|
1125
|
+
new CoSignUnavailableError(
|
|
1126
|
+
"co-sign ceremony timed out (the deadline fires before validBefore \u2014 W11)"
|
|
1127
|
+
)
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
return new Promise((resolve, reject) => {
|
|
1131
|
+
const timer = setTimeout(() => {
|
|
1132
|
+
reject(
|
|
1133
|
+
new CoSignUnavailableError(
|
|
1134
|
+
"co-sign ceremony timed out (the deadline fires before validBefore \u2014 W11)"
|
|
1135
|
+
)
|
|
1136
|
+
);
|
|
1137
|
+
}, remaining);
|
|
1138
|
+
promise.then(
|
|
1139
|
+
(value) => {
|
|
1140
|
+
clearTimeout(timer);
|
|
1141
|
+
resolve(value);
|
|
1142
|
+
},
|
|
1143
|
+
(cause) => {
|
|
1144
|
+
clearTimeout(timer);
|
|
1145
|
+
reject(cause);
|
|
1146
|
+
}
|
|
1147
|
+
);
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
var SECP256K1_HALF_N = 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0n;
|
|
1151
|
+
async function verifyRecovers(digest, signature, s, from, what) {
|
|
1152
|
+
if (BigInt(s) > SECP256K1_HALF_N) {
|
|
1153
|
+
throw new CoSignUnavailableError(`the ${what} signature is not low-S (EIP-2)`);
|
|
1154
|
+
}
|
|
1155
|
+
let recovered;
|
|
1156
|
+
try {
|
|
1157
|
+
recovered = await viem.recoverAddress({ hash: digest, signature });
|
|
1158
|
+
} catch (cause) {
|
|
1159
|
+
throw new CoSignUnavailableError(`the ${what} signature failed to recover`, { cause });
|
|
1160
|
+
}
|
|
1161
|
+
if (viem.getAddress(recovered) !== from) {
|
|
1162
|
+
throw new CoSignUnavailableError(
|
|
1163
|
+
`the ${what} signature recovers to ${viem.getAddress(recovered)}, not the group EOA ${from}`
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1037
1167
|
function assembleSignature(sig) {
|
|
1038
1168
|
const yParity = sig.v - 27;
|
|
1039
1169
|
if (yParity !== 0 && yParity !== 1) {
|
|
@@ -3075,7 +3205,7 @@ exports.avalancheFuji = avalancheFuji;
|
|
|
3075
3205
|
exports.buildPaymentRequiredResponse = buildPaymentRequiredResponse;
|
|
3076
3206
|
exports.buildPaymentRequirements = buildPaymentRequirements;
|
|
3077
3207
|
exports.cancelAuthorizationTypes = cancelAuthorizationTypes;
|
|
3078
|
-
exports.
|
|
3208
|
+
exports.canonicalRequestBytes = canonicalRequestBytes;
|
|
3079
3209
|
exports.chainIdToX402Network = chainIdToX402Network;
|
|
3080
3210
|
exports.createAgentSmartAccount = createAgentSmartAccount;
|
|
3081
3211
|
exports.createCoinbaseFacilitator = createCoinbaseFacilitator;
|