kawasekit 0.2.0 → 0.4.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-VXZHS74W.js → chunk-5TTOAVHE.js} +9 -3
- package/dist/chunk-5TTOAVHE.js.map +1 -0
- package/dist/chunk-FD6Q4NB2.js +293 -0
- package/dist/chunk-FD6Q4NB2.js.map +1 -0
- package/dist/{chunk-SMAZUZFO.js → chunk-G3UC6SME.js} +3 -3
- package/dist/{chunk-SMAZUZFO.js.map → chunk-G3UC6SME.js.map} +1 -1
- package/dist/{chunk-XRSZTZVZ.js → chunk-RJLDKDWL.js} +2 -2
- package/dist/{chunk-XRSZTZVZ.js.map → chunk-RJLDKDWL.js.map} +1 -1
- package/dist/cli/index.cjs +1 -1
- package/dist/cli/index.js +5 -5
- package/dist/{index-f-Xg86P9.d.ts → index-C9tbaHPF.d.ts} +1 -1
- package/dist/{index-Cn6kg7KH.d.cts → index-CAmTA8xR.d.cts} +1 -1
- package/dist/index.cjs +239 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/policy/index.d.cts +2 -2
- package/dist/policy/index.d.ts +2 -2
- package/dist/signer/index.cjs +235 -0
- package/dist/signer/index.cjs.map +1 -1
- package/dist/signer/index.d.cts +240 -5
- package/dist/signer/index.d.ts +240 -5
- package/dist/signer/index.js +2 -2
- package/dist/{spending-policy-DKZN3Sg8.d.ts → spending-policy-BD2Mpm-L.d.ts} +1 -1
- package/dist/{spending-policy-DaajDg9B.d.cts → spending-policy-CGIaBpg-.d.cts} +1 -1
- package/dist/{types-IEl-iOIx.d.cts → types-BLJU67HZ.d.cts} +11 -3
- package/dist/{types-IEl-iOIx.d.ts → types-BLJU67HZ.d.ts} +11 -3
- package/dist/x402/index.cjs.map +1 -1
- package/dist/x402/index.d.cts +2 -2
- package/dist/x402/index.d.ts +2 -2
- package/dist/x402/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-THTVJZ2Q.js +0 -71
- package/dist/chunk-THTVJZ2Q.js.map +0 -1
- package/dist/chunk-VXZHS74W.js.map +0 -1
package/dist/signer/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as PolicyGatedSigner, N as NonBypassableEnforcement } from '../types-
|
|
2
|
-
export { E as EnforcementLevel,
|
|
3
|
-
import { Account } from 'viem';
|
|
4
|
-
import { a as SpendingPolicy, S as SpendState } from '../spending-policy-
|
|
1
|
+
import { a as PolicyGatedSigner, N as NonBypassableEnforcement, P as PaymentIntent } from '../types-BLJU67HZ.cjs';
|
|
2
|
+
export { E as EnforcementLevel, b as PolicyRejection, S as SignResult, c as SignerDescription } from '../types-BLJU67HZ.cjs';
|
|
3
|
+
import { Account, Hex, Address } from 'viem';
|
|
4
|
+
import { a as SpendingPolicy, S as SpendState } from '../spending-policy-CGIaBpg-.cjs';
|
|
5
5
|
import { X as X402AssetParam } from '../asset-domain-4Ioxqn28.cjs';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -39,6 +39,36 @@ declare class PolicyGatedSignerConfigError extends Error {
|
|
|
39
39
|
cause?: unknown;
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Thrown by the `mpc-2p` cryptographic adapter when the co-signer is
|
|
44
|
+
* **unreachable or the ceremony could not complete** — endpoint down, TLS
|
|
45
|
+
* failure, connection dropped mid-ceremony, timeout, a malformed/missing
|
|
46
|
+
* terminal frame, or an internal protocol anomaly. It is a transient / internal
|
|
47
|
+
* error on the throws channel (M6-0: throws are reserved for internal/config
|
|
48
|
+
* errors), **distinct from a policy denial**.
|
|
49
|
+
*
|
|
50
|
+
* This is the **no-silent-fallback** guarantee (RFC m6-3a constraint 3 / W8):
|
|
51
|
+
* the adapter has no local-signing path, so an unavailable wire NEVER yields an
|
|
52
|
+
* `{ ok: true }` signature and NEVER a {@link PolicyRejection}. A `rejection`
|
|
53
|
+
* means "the owner decided no" (audit-meaningful); a `CoSignUnavailableError`
|
|
54
|
+
* means "the owner did not decide" — the caller may retry the *same* intent
|
|
55
|
+
* (the backend's idempotency keeps a retry safe).
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* try {
|
|
60
|
+
* const result = await mpc2pSigner.sign(intent);
|
|
61
|
+
* if (!result.ok) handleDenial(result.rejection); // owner said no
|
|
62
|
+
* } catch (error) {
|
|
63
|
+
* if (error instanceof CoSignUnavailableError) retryLater(); // wire was down
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
declare class CoSignUnavailableError extends Error {
|
|
68
|
+
constructor(message: string, options?: {
|
|
69
|
+
cause?: unknown;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
42
72
|
|
|
43
73
|
/**
|
|
44
74
|
* The enforcement-level type-gate — the compile-time (and runtime) mechanism
|
|
@@ -128,4 +158,209 @@ interface CreateLocalPolicyGatedSignerParams {
|
|
|
128
158
|
*/
|
|
129
159
|
declare function createLocalPolicyGatedSigner(params: CreateLocalPolicyGatedSignerParams): PolicyGatedSigner<"advisory">;
|
|
130
160
|
|
|
131
|
-
|
|
161
|
+
/**
|
|
162
|
+
* The `mpc-2p` cross-process **wire** (v2) — the versioned `CoSignFrame` control
|
|
163
|
+
* envelope + the A3 canonical-request encoding, as TypeScript source-of-truth.
|
|
164
|
+
*
|
|
165
|
+
* This is the public, TS-interpreted half of the two-layer wire (RFC m6-3a §4.2):
|
|
166
|
+
* a small, versioned envelope carries the decoded {@link PaymentIntent} (never a
|
|
167
|
+
* digest — A4) + a per-ceremony id + ssid + a freshness element, plus the opaque
|
|
168
|
+
* DKLs round payloads (hex, produced/consumed only by the WASM crypto agent). The
|
|
169
|
+
* shapes here mirror the deployed `kawasekit-mpc-2p` Rust serde **byte-for-byte**
|
|
170
|
+
* (snake_case `wire_version`, `session_id`, `ceremony_id`, `ssid`, `freshness_ts`,
|
|
171
|
+
* `freshness_nonce`, `auth_tag`; the string-encoded {@link WireIntent}), so a frame
|
|
172
|
+
* the SDK builds round-trips through the backend's `serde_json`.
|
|
173
|
+
*
|
|
174
|
+
* `canonicalRequestBytes` is the A3 analog of the EIP-712 digest corpus: it
|
|
175
|
+
* reproduces the backend's `auth::canonical_request_bytes` exactly, so the injected
|
|
176
|
+
* authenticator's HMAC equals what the co-signer verifies (RFC §4.6:
|
|
177
|
+
* `HMAC_k(wireVersion ‖ ceremonyId ‖ ssid ‖ canonical(intent) ‖ freshness)`).
|
|
178
|
+
*
|
|
179
|
+
* @packageDocumentation
|
|
180
|
+
*/
|
|
181
|
+
|
|
182
|
+
/** The wire protocol version. A frame whose `wire_version` differs is rejected. */
|
|
183
|
+
declare const WIRE_VERSION: 2;
|
|
184
|
+
/**
|
|
185
|
+
* The string-encoded EIP-3009 intent as it crosses the wire — lowercase `0x`
|
|
186
|
+
* addresses, **decimal** integer strings, `0x` hex nonce. Decoupled from any
|
|
187
|
+
* library's native serde so a stdlib client reproduces it trivially; matches the
|
|
188
|
+
* Rust `WireIntent` field names + encoding exactly.
|
|
189
|
+
*/
|
|
190
|
+
interface WireIntent {
|
|
191
|
+
readonly token: string;
|
|
192
|
+
readonly chain_id: number;
|
|
193
|
+
readonly from: string;
|
|
194
|
+
readonly to: string;
|
|
195
|
+
readonly value: string;
|
|
196
|
+
readonly valid_after: string;
|
|
197
|
+
readonly valid_before: string;
|
|
198
|
+
readonly nonce: string;
|
|
199
|
+
}
|
|
200
|
+
/** Encode a decoded {@link PaymentIntent} for the wire. */
|
|
201
|
+
declare function toWireIntent(intent: PaymentIntent): WireIntent;
|
|
202
|
+
/**
|
|
203
|
+
* The A3 request envelope the adapter generates per `sign()` and authenticates: a
|
|
204
|
+
* per-ceremony id + ssid (bound into the A3 tag) + the intent + a freshness element
|
|
205
|
+
* (a timestamp + a per-request nonce distinct from the EIP-3009 nonce).
|
|
206
|
+
*/
|
|
207
|
+
interface CoSignRequestEnvelope {
|
|
208
|
+
readonly ceremonyId: string;
|
|
209
|
+
readonly ssid: string;
|
|
210
|
+
readonly intent: PaymentIntent;
|
|
211
|
+
/** Unix seconds; the backend checks it against a clock-skew window. */
|
|
212
|
+
readonly freshnessTs: number;
|
|
213
|
+
/** `0x` hex, distinct from the EIP-3009 nonce — the anti-replay key. */
|
|
214
|
+
readonly freshnessNonce: Hex;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* A versioned control frame: the only cross-language content of the wire. The
|
|
218
|
+
* DKLs round bytes ride opaque inside `payload`; everything else is the small,
|
|
219
|
+
* pinned envelope. Internally tagged by `kind` (matches the Rust serde).
|
|
220
|
+
*/
|
|
221
|
+
type CoSignFrame = {
|
|
222
|
+
readonly wire_version: typeof WIRE_VERSION;
|
|
223
|
+
} & ({
|
|
224
|
+
readonly kind: "request";
|
|
225
|
+
readonly session_id: string;
|
|
226
|
+
readonly ceremony_id: string;
|
|
227
|
+
readonly ssid: string;
|
|
228
|
+
readonly intent: WireIntent;
|
|
229
|
+
readonly freshness_ts: number;
|
|
230
|
+
readonly freshness_nonce: Hex;
|
|
231
|
+
/** A3 authenticator over {@link canonicalRequestBytes}, `0x`-hex. */
|
|
232
|
+
readonly auth_tag: Hex;
|
|
233
|
+
} | {
|
|
234
|
+
readonly kind: "round";
|
|
235
|
+
readonly payload: Hex;
|
|
236
|
+
} | {
|
|
237
|
+
readonly kind: "result";
|
|
238
|
+
readonly r: Hex;
|
|
239
|
+
readonly s: Hex;
|
|
240
|
+
readonly v: number;
|
|
241
|
+
} | {
|
|
242
|
+
readonly kind: "rejection";
|
|
243
|
+
readonly reason: string;
|
|
244
|
+
readonly detail: string;
|
|
245
|
+
} | {
|
|
246
|
+
readonly kind: "error";
|
|
247
|
+
readonly message: string;
|
|
248
|
+
});
|
|
249
|
+
/**
|
|
250
|
+
* The A3 canonical encoding of a request — a byte-exact mirror of the backend's
|
|
251
|
+
* `auth::canonical_request_bytes` (domain-tag `kawasekit-mpc-2p/cosign-request/v3`,
|
|
252
|
+
* one `key=value\n` line per field: `wireVersion ‖ ceremonyId ‖ ssid ‖
|
|
253
|
+
* canonical(intent) ‖ freshness`; lowercase `0x` addresses + freshness nonce,
|
|
254
|
+
* decimal integers, trailing newline). The injected authenticator HMACs these
|
|
255
|
+
* bytes; because the encoding is shared, the tag equals the co-signer's.
|
|
256
|
+
*/
|
|
257
|
+
declare function canonicalRequestBytes(env: CoSignRequestEnvelope): Uint8Array;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* The `mpc-2p` PolicyGatedSigner adapter — `enforcement: "cryptographic"`.
|
|
261
|
+
*
|
|
262
|
+
* A 2-of-2 MPC co-signer: the agent holds ONE DKLs share, the owner backend holds
|
|
263
|
+
* the other + the authoritative policy gate. No valid signature exists without a
|
|
264
|
+
* **policy-passing co-sign**, so — unlike `local` — a single key-holder cannot
|
|
265
|
+
* bypass the policy. That is what earns the non-bypassable `"cryptographic"` label
|
|
266
|
+
* and lets the M6-0 type-gate (`requireNonBypassable`) reject an advisory signer at
|
|
267
|
+
* compile time in bounded flows.
|
|
268
|
+
*
|
|
269
|
+
* **Open-core / thin adapter.** This module is pure orchestration over injected
|
|
270
|
+
* interfaces — it ships in the public SDK with **no crypto, no socket, no key**:
|
|
271
|
+
*
|
|
272
|
+
* - {@link Mpc2pCoSignAgent} — the WASM DKLs share (the private package's compiled
|
|
273
|
+
* `crypto-core`); drives the agent's half of the ceremony round-by-round.
|
|
274
|
+
* - {@link CoSignTransport} — the authenticated, encrypted (wss/mTLS) frame channel
|
|
275
|
+
* to the owner backend (the private package's transport).
|
|
276
|
+
* - {@link CoSignRequestAuthenticator} — the A3 HMAC (the pre-shared key never
|
|
277
|
+
* enters this module).
|
|
278
|
+
*
|
|
279
|
+
* The adapter owns the protocol: it pins the EIP-712 domain, **re-derives the
|
|
280
|
+
* digest from the intent (A4)** via the shared `transferWithAuthorizationTypes`
|
|
281
|
+
* source-of-truth, computes the A3 canonical bytes, frames the versioned
|
|
282
|
+
* {@link CoSignFrame} envelope, pumps the ceremony, and maps the terminal frame to
|
|
283
|
+
* a {@link SignResult}. Crucially it has **no local-signing path**: any
|
|
284
|
+
* transport/availability failure throws {@link CoSignUnavailableError}, never an
|
|
285
|
+
* `{ ok: true }` and never a {@link PolicyRejection} (the no-silent-fallback
|
|
286
|
+
* guarantee, RFC m6-3a constraint 3 / W8).
|
|
287
|
+
*
|
|
288
|
+
* @packageDocumentation
|
|
289
|
+
*/
|
|
290
|
+
|
|
291
|
+
/** The agent's half of the 2-of-2 ceremony (the injected WASM DKLs share). */
|
|
292
|
+
interface Mpc2pCoSignAgent {
|
|
293
|
+
/** The group 2-of-2 EOA this share controls — must equal the signer's `from`. */
|
|
294
|
+
groupEoa(): Address;
|
|
295
|
+
/** Begin signing the 32-byte EIP-712 `digest`; returns the first outbound round (hex). */
|
|
296
|
+
start(digest: Hex): Hex;
|
|
297
|
+
/** Feed one inbound round (hex); returns the next outbound round, or the final signature. */
|
|
298
|
+
step(incoming: Hex): Mpc2pStepOutcome;
|
|
299
|
+
}
|
|
300
|
+
/** The result of one {@link Mpc2pCoSignAgent.step}. */
|
|
301
|
+
type Mpc2pStepOutcome = {
|
|
302
|
+
readonly outbound: Hex;
|
|
303
|
+
} | {
|
|
304
|
+
readonly signature: {
|
|
305
|
+
readonly r: Hex;
|
|
306
|
+
readonly s: Hex;
|
|
307
|
+
readonly v: number;
|
|
308
|
+
};
|
|
309
|
+
};
|
|
310
|
+
/** One authenticated, encrypted ceremony connection to the owner backend. */
|
|
311
|
+
interface CoSignConnection {
|
|
312
|
+
/** Send one control frame. */
|
|
313
|
+
send(frame: CoSignFrame): Promise<void>;
|
|
314
|
+
/** Receive the next control frame (resolves per round). */
|
|
315
|
+
recv(): Promise<CoSignFrame>;
|
|
316
|
+
/** Release the connection (best-effort; errors here are ignored). */
|
|
317
|
+
close(): void | Promise<void>;
|
|
318
|
+
}
|
|
319
|
+
/** Opens a wss/mTLS {@link CoSignConnection} for a single co-sign ceremony. */
|
|
320
|
+
interface CoSignTransport {
|
|
321
|
+
connect(): Promise<CoSignConnection>;
|
|
322
|
+
}
|
|
323
|
+
/** The A3 request authenticator — HMAC (or signature) over the canonical request bytes. */
|
|
324
|
+
interface CoSignRequestAuthenticator {
|
|
325
|
+
/** Authenticator tag over {@link canonicalRequestBytes}; the key stays inside. */
|
|
326
|
+
tag(canonicalRequest: Uint8Array): Hex | Promise<Hex>;
|
|
327
|
+
}
|
|
328
|
+
/** Parameters for {@link createMpc2pPolicyGatedSigner}. */
|
|
329
|
+
interface Mpc2pSignerParams {
|
|
330
|
+
/** The group 2-of-2 EOA; every `intent.from` must equal this (asserted vs the agent). */
|
|
331
|
+
readonly from: Address;
|
|
332
|
+
/** Asset binding — pins the EIP-712 domain `name`/`version`/`verifyingContract` (A4). */
|
|
333
|
+
readonly asset: X402AssetParam;
|
|
334
|
+
/** The bound policy session, for `describe()` (the backend holds the authoritative policy). */
|
|
335
|
+
readonly session: {
|
|
336
|
+
readonly id: string;
|
|
337
|
+
readonly notAfter: bigint;
|
|
338
|
+
};
|
|
339
|
+
/** The injected WASM DKLs share (private package). */
|
|
340
|
+
readonly agent: Mpc2pCoSignAgent;
|
|
341
|
+
/** The injected wss/mTLS frame channel (private package). */
|
|
342
|
+
readonly transport: CoSignTransport;
|
|
343
|
+
/** The injected A3 authenticator (the pre-shared key never enters the SDK). */
|
|
344
|
+
readonly authenticator: CoSignRequestAuthenticator;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Construct an `mpc-2p` (cryptographic) PolicyGatedSigner over injected agent +
|
|
348
|
+
* transport + authenticator.
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```ts
|
|
352
|
+
* // The agent, transport and authenticator come from the private `kawasekit-mpc-2p`
|
|
353
|
+
* // package (the WASM share, the wss/mTLS client, the HMAC key) — never bundled here.
|
|
354
|
+
* const signer = createMpc2pPolicyGatedSigner({
|
|
355
|
+
* from: groupEoa,
|
|
356
|
+
* asset: { kind: "known", id: "jpyc-v2" },
|
|
357
|
+
* session: { id: "sess-1", notAfter: 2_000_000_000n },
|
|
358
|
+
* agent, transport, authenticator,
|
|
359
|
+
* });
|
|
360
|
+
* requireNonBypassable(signer); // ✓ "cryptographic" — passes the type-gate
|
|
361
|
+
* const result = await signer.sign(intent);
|
|
362
|
+
* ```
|
|
363
|
+
*/
|
|
364
|
+
declare function createMpc2pPolicyGatedSigner(params: Mpc2pSignerParams): PolicyGatedSigner<"cryptographic">;
|
|
365
|
+
|
|
366
|
+
export { type CoSignConnection, type CoSignFrame, type CoSignRequestAuthenticator, type CoSignRequestEnvelope, type CoSignTransport, CoSignUnavailableError, type CreateLocalPolicyGatedSignerParams, type Mpc2pCoSignAgent, type Mpc2pSignerParams, type Mpc2pStepOutcome, NonBypassableEnforcement, PaymentIntent, PolicyGatedSigner, PolicyGatedSignerConfigError, WIRE_VERSION, type WireIntent, assertNonBypassable, canonicalRequestBytes, createLocalPolicyGatedSigner, createMpc2pPolicyGatedSigner, requireNonBypassable, toWireIntent };
|
package/dist/signer/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as PolicyGatedSigner, N as NonBypassableEnforcement } from '../types-
|
|
2
|
-
export { E as EnforcementLevel,
|
|
3
|
-
import { Account } from 'viem';
|
|
4
|
-
import { a as SpendingPolicy, S as SpendState } from '../spending-policy-
|
|
1
|
+
import { a as PolicyGatedSigner, N as NonBypassableEnforcement, P as PaymentIntent } from '../types-BLJU67HZ.js';
|
|
2
|
+
export { E as EnforcementLevel, b as PolicyRejection, S as SignResult, c as SignerDescription } from '../types-BLJU67HZ.js';
|
|
3
|
+
import { Account, Hex, Address } from 'viem';
|
|
4
|
+
import { a as SpendingPolicy, S as SpendState } from '../spending-policy-BD2Mpm-L.js';
|
|
5
5
|
import { X as X402AssetParam } from '../asset-domain-4Ioxqn28.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -39,6 +39,36 @@ declare class PolicyGatedSignerConfigError extends Error {
|
|
|
39
39
|
cause?: unknown;
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Thrown by the `mpc-2p` cryptographic adapter when the co-signer is
|
|
44
|
+
* **unreachable or the ceremony could not complete** — endpoint down, TLS
|
|
45
|
+
* failure, connection dropped mid-ceremony, timeout, a malformed/missing
|
|
46
|
+
* terminal frame, or an internal protocol anomaly. It is a transient / internal
|
|
47
|
+
* error on the throws channel (M6-0: throws are reserved for internal/config
|
|
48
|
+
* errors), **distinct from a policy denial**.
|
|
49
|
+
*
|
|
50
|
+
* This is the **no-silent-fallback** guarantee (RFC m6-3a constraint 3 / W8):
|
|
51
|
+
* the adapter has no local-signing path, so an unavailable wire NEVER yields an
|
|
52
|
+
* `{ ok: true }` signature and NEVER a {@link PolicyRejection}. A `rejection`
|
|
53
|
+
* means "the owner decided no" (audit-meaningful); a `CoSignUnavailableError`
|
|
54
|
+
* means "the owner did not decide" — the caller may retry the *same* intent
|
|
55
|
+
* (the backend's idempotency keeps a retry safe).
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* try {
|
|
60
|
+
* const result = await mpc2pSigner.sign(intent);
|
|
61
|
+
* if (!result.ok) handleDenial(result.rejection); // owner said no
|
|
62
|
+
* } catch (error) {
|
|
63
|
+
* if (error instanceof CoSignUnavailableError) retryLater(); // wire was down
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
declare class CoSignUnavailableError extends Error {
|
|
68
|
+
constructor(message: string, options?: {
|
|
69
|
+
cause?: unknown;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
42
72
|
|
|
43
73
|
/**
|
|
44
74
|
* The enforcement-level type-gate — the compile-time (and runtime) mechanism
|
|
@@ -128,4 +158,209 @@ interface CreateLocalPolicyGatedSignerParams {
|
|
|
128
158
|
*/
|
|
129
159
|
declare function createLocalPolicyGatedSigner(params: CreateLocalPolicyGatedSignerParams): PolicyGatedSigner<"advisory">;
|
|
130
160
|
|
|
131
|
-
|
|
161
|
+
/**
|
|
162
|
+
* The `mpc-2p` cross-process **wire** (v2) — the versioned `CoSignFrame` control
|
|
163
|
+
* envelope + the A3 canonical-request encoding, as TypeScript source-of-truth.
|
|
164
|
+
*
|
|
165
|
+
* This is the public, TS-interpreted half of the two-layer wire (RFC m6-3a §4.2):
|
|
166
|
+
* a small, versioned envelope carries the decoded {@link PaymentIntent} (never a
|
|
167
|
+
* digest — A4) + a per-ceremony id + ssid + a freshness element, plus the opaque
|
|
168
|
+
* DKLs round payloads (hex, produced/consumed only by the WASM crypto agent). The
|
|
169
|
+
* shapes here mirror the deployed `kawasekit-mpc-2p` Rust serde **byte-for-byte**
|
|
170
|
+
* (snake_case `wire_version`, `session_id`, `ceremony_id`, `ssid`, `freshness_ts`,
|
|
171
|
+
* `freshness_nonce`, `auth_tag`; the string-encoded {@link WireIntent}), so a frame
|
|
172
|
+
* the SDK builds round-trips through the backend's `serde_json`.
|
|
173
|
+
*
|
|
174
|
+
* `canonicalRequestBytes` is the A3 analog of the EIP-712 digest corpus: it
|
|
175
|
+
* reproduces the backend's `auth::canonical_request_bytes` exactly, so the injected
|
|
176
|
+
* authenticator's HMAC equals what the co-signer verifies (RFC §4.6:
|
|
177
|
+
* `HMAC_k(wireVersion ‖ ceremonyId ‖ ssid ‖ canonical(intent) ‖ freshness)`).
|
|
178
|
+
*
|
|
179
|
+
* @packageDocumentation
|
|
180
|
+
*/
|
|
181
|
+
|
|
182
|
+
/** The wire protocol version. A frame whose `wire_version` differs is rejected. */
|
|
183
|
+
declare const WIRE_VERSION: 2;
|
|
184
|
+
/**
|
|
185
|
+
* The string-encoded EIP-3009 intent as it crosses the wire — lowercase `0x`
|
|
186
|
+
* addresses, **decimal** integer strings, `0x` hex nonce. Decoupled from any
|
|
187
|
+
* library's native serde so a stdlib client reproduces it trivially; matches the
|
|
188
|
+
* Rust `WireIntent` field names + encoding exactly.
|
|
189
|
+
*/
|
|
190
|
+
interface WireIntent {
|
|
191
|
+
readonly token: string;
|
|
192
|
+
readonly chain_id: number;
|
|
193
|
+
readonly from: string;
|
|
194
|
+
readonly to: string;
|
|
195
|
+
readonly value: string;
|
|
196
|
+
readonly valid_after: string;
|
|
197
|
+
readonly valid_before: string;
|
|
198
|
+
readonly nonce: string;
|
|
199
|
+
}
|
|
200
|
+
/** Encode a decoded {@link PaymentIntent} for the wire. */
|
|
201
|
+
declare function toWireIntent(intent: PaymentIntent): WireIntent;
|
|
202
|
+
/**
|
|
203
|
+
* The A3 request envelope the adapter generates per `sign()` and authenticates: a
|
|
204
|
+
* per-ceremony id + ssid (bound into the A3 tag) + the intent + a freshness element
|
|
205
|
+
* (a timestamp + a per-request nonce distinct from the EIP-3009 nonce).
|
|
206
|
+
*/
|
|
207
|
+
interface CoSignRequestEnvelope {
|
|
208
|
+
readonly ceremonyId: string;
|
|
209
|
+
readonly ssid: string;
|
|
210
|
+
readonly intent: PaymentIntent;
|
|
211
|
+
/** Unix seconds; the backend checks it against a clock-skew window. */
|
|
212
|
+
readonly freshnessTs: number;
|
|
213
|
+
/** `0x` hex, distinct from the EIP-3009 nonce — the anti-replay key. */
|
|
214
|
+
readonly freshnessNonce: Hex;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* A versioned control frame: the only cross-language content of the wire. The
|
|
218
|
+
* DKLs round bytes ride opaque inside `payload`; everything else is the small,
|
|
219
|
+
* pinned envelope. Internally tagged by `kind` (matches the Rust serde).
|
|
220
|
+
*/
|
|
221
|
+
type CoSignFrame = {
|
|
222
|
+
readonly wire_version: typeof WIRE_VERSION;
|
|
223
|
+
} & ({
|
|
224
|
+
readonly kind: "request";
|
|
225
|
+
readonly session_id: string;
|
|
226
|
+
readonly ceremony_id: string;
|
|
227
|
+
readonly ssid: string;
|
|
228
|
+
readonly intent: WireIntent;
|
|
229
|
+
readonly freshness_ts: number;
|
|
230
|
+
readonly freshness_nonce: Hex;
|
|
231
|
+
/** A3 authenticator over {@link canonicalRequestBytes}, `0x`-hex. */
|
|
232
|
+
readonly auth_tag: Hex;
|
|
233
|
+
} | {
|
|
234
|
+
readonly kind: "round";
|
|
235
|
+
readonly payload: Hex;
|
|
236
|
+
} | {
|
|
237
|
+
readonly kind: "result";
|
|
238
|
+
readonly r: Hex;
|
|
239
|
+
readonly s: Hex;
|
|
240
|
+
readonly v: number;
|
|
241
|
+
} | {
|
|
242
|
+
readonly kind: "rejection";
|
|
243
|
+
readonly reason: string;
|
|
244
|
+
readonly detail: string;
|
|
245
|
+
} | {
|
|
246
|
+
readonly kind: "error";
|
|
247
|
+
readonly message: string;
|
|
248
|
+
});
|
|
249
|
+
/**
|
|
250
|
+
* The A3 canonical encoding of a request — a byte-exact mirror of the backend's
|
|
251
|
+
* `auth::canonical_request_bytes` (domain-tag `kawasekit-mpc-2p/cosign-request/v3`,
|
|
252
|
+
* one `key=value\n` line per field: `wireVersion ‖ ceremonyId ‖ ssid ‖
|
|
253
|
+
* canonical(intent) ‖ freshness`; lowercase `0x` addresses + freshness nonce,
|
|
254
|
+
* decimal integers, trailing newline). The injected authenticator HMACs these
|
|
255
|
+
* bytes; because the encoding is shared, the tag equals the co-signer's.
|
|
256
|
+
*/
|
|
257
|
+
declare function canonicalRequestBytes(env: CoSignRequestEnvelope): Uint8Array;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* The `mpc-2p` PolicyGatedSigner adapter — `enforcement: "cryptographic"`.
|
|
261
|
+
*
|
|
262
|
+
* A 2-of-2 MPC co-signer: the agent holds ONE DKLs share, the owner backend holds
|
|
263
|
+
* the other + the authoritative policy gate. No valid signature exists without a
|
|
264
|
+
* **policy-passing co-sign**, so — unlike `local` — a single key-holder cannot
|
|
265
|
+
* bypass the policy. That is what earns the non-bypassable `"cryptographic"` label
|
|
266
|
+
* and lets the M6-0 type-gate (`requireNonBypassable`) reject an advisory signer at
|
|
267
|
+
* compile time in bounded flows.
|
|
268
|
+
*
|
|
269
|
+
* **Open-core / thin adapter.** This module is pure orchestration over injected
|
|
270
|
+
* interfaces — it ships in the public SDK with **no crypto, no socket, no key**:
|
|
271
|
+
*
|
|
272
|
+
* - {@link Mpc2pCoSignAgent} — the WASM DKLs share (the private package's compiled
|
|
273
|
+
* `crypto-core`); drives the agent's half of the ceremony round-by-round.
|
|
274
|
+
* - {@link CoSignTransport} — the authenticated, encrypted (wss/mTLS) frame channel
|
|
275
|
+
* to the owner backend (the private package's transport).
|
|
276
|
+
* - {@link CoSignRequestAuthenticator} — the A3 HMAC (the pre-shared key never
|
|
277
|
+
* enters this module).
|
|
278
|
+
*
|
|
279
|
+
* The adapter owns the protocol: it pins the EIP-712 domain, **re-derives the
|
|
280
|
+
* digest from the intent (A4)** via the shared `transferWithAuthorizationTypes`
|
|
281
|
+
* source-of-truth, computes the A3 canonical bytes, frames the versioned
|
|
282
|
+
* {@link CoSignFrame} envelope, pumps the ceremony, and maps the terminal frame to
|
|
283
|
+
* a {@link SignResult}. Crucially it has **no local-signing path**: any
|
|
284
|
+
* transport/availability failure throws {@link CoSignUnavailableError}, never an
|
|
285
|
+
* `{ ok: true }` and never a {@link PolicyRejection} (the no-silent-fallback
|
|
286
|
+
* guarantee, RFC m6-3a constraint 3 / W8).
|
|
287
|
+
*
|
|
288
|
+
* @packageDocumentation
|
|
289
|
+
*/
|
|
290
|
+
|
|
291
|
+
/** The agent's half of the 2-of-2 ceremony (the injected WASM DKLs share). */
|
|
292
|
+
interface Mpc2pCoSignAgent {
|
|
293
|
+
/** The group 2-of-2 EOA this share controls — must equal the signer's `from`. */
|
|
294
|
+
groupEoa(): Address;
|
|
295
|
+
/** Begin signing the 32-byte EIP-712 `digest`; returns the first outbound round (hex). */
|
|
296
|
+
start(digest: Hex): Hex;
|
|
297
|
+
/** Feed one inbound round (hex); returns the next outbound round, or the final signature. */
|
|
298
|
+
step(incoming: Hex): Mpc2pStepOutcome;
|
|
299
|
+
}
|
|
300
|
+
/** The result of one {@link Mpc2pCoSignAgent.step}. */
|
|
301
|
+
type Mpc2pStepOutcome = {
|
|
302
|
+
readonly outbound: Hex;
|
|
303
|
+
} | {
|
|
304
|
+
readonly signature: {
|
|
305
|
+
readonly r: Hex;
|
|
306
|
+
readonly s: Hex;
|
|
307
|
+
readonly v: number;
|
|
308
|
+
};
|
|
309
|
+
};
|
|
310
|
+
/** One authenticated, encrypted ceremony connection to the owner backend. */
|
|
311
|
+
interface CoSignConnection {
|
|
312
|
+
/** Send one control frame. */
|
|
313
|
+
send(frame: CoSignFrame): Promise<void>;
|
|
314
|
+
/** Receive the next control frame (resolves per round). */
|
|
315
|
+
recv(): Promise<CoSignFrame>;
|
|
316
|
+
/** Release the connection (best-effort; errors here are ignored). */
|
|
317
|
+
close(): void | Promise<void>;
|
|
318
|
+
}
|
|
319
|
+
/** Opens a wss/mTLS {@link CoSignConnection} for a single co-sign ceremony. */
|
|
320
|
+
interface CoSignTransport {
|
|
321
|
+
connect(): Promise<CoSignConnection>;
|
|
322
|
+
}
|
|
323
|
+
/** The A3 request authenticator — HMAC (or signature) over the canonical request bytes. */
|
|
324
|
+
interface CoSignRequestAuthenticator {
|
|
325
|
+
/** Authenticator tag over {@link canonicalRequestBytes}; the key stays inside. */
|
|
326
|
+
tag(canonicalRequest: Uint8Array): Hex | Promise<Hex>;
|
|
327
|
+
}
|
|
328
|
+
/** Parameters for {@link createMpc2pPolicyGatedSigner}. */
|
|
329
|
+
interface Mpc2pSignerParams {
|
|
330
|
+
/** The group 2-of-2 EOA; every `intent.from` must equal this (asserted vs the agent). */
|
|
331
|
+
readonly from: Address;
|
|
332
|
+
/** Asset binding — pins the EIP-712 domain `name`/`version`/`verifyingContract` (A4). */
|
|
333
|
+
readonly asset: X402AssetParam;
|
|
334
|
+
/** The bound policy session, for `describe()` (the backend holds the authoritative policy). */
|
|
335
|
+
readonly session: {
|
|
336
|
+
readonly id: string;
|
|
337
|
+
readonly notAfter: bigint;
|
|
338
|
+
};
|
|
339
|
+
/** The injected WASM DKLs share (private package). */
|
|
340
|
+
readonly agent: Mpc2pCoSignAgent;
|
|
341
|
+
/** The injected wss/mTLS frame channel (private package). */
|
|
342
|
+
readonly transport: CoSignTransport;
|
|
343
|
+
/** The injected A3 authenticator (the pre-shared key never enters the SDK). */
|
|
344
|
+
readonly authenticator: CoSignRequestAuthenticator;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Construct an `mpc-2p` (cryptographic) PolicyGatedSigner over injected agent +
|
|
348
|
+
* transport + authenticator.
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```ts
|
|
352
|
+
* // The agent, transport and authenticator come from the private `kawasekit-mpc-2p`
|
|
353
|
+
* // package (the WASM share, the wss/mTLS client, the HMAC key) — never bundled here.
|
|
354
|
+
* const signer = createMpc2pPolicyGatedSigner({
|
|
355
|
+
* from: groupEoa,
|
|
356
|
+
* asset: { kind: "known", id: "jpyc-v2" },
|
|
357
|
+
* session: { id: "sess-1", notAfter: 2_000_000_000n },
|
|
358
|
+
* agent, transport, authenticator,
|
|
359
|
+
* });
|
|
360
|
+
* requireNonBypassable(signer); // ✓ "cryptographic" — passes the type-gate
|
|
361
|
+
* const result = await signer.sign(intent);
|
|
362
|
+
* ```
|
|
363
|
+
*/
|
|
364
|
+
declare function createMpc2pPolicyGatedSigner(params: Mpc2pSignerParams): PolicyGatedSigner<"cryptographic">;
|
|
365
|
+
|
|
366
|
+
export { type CoSignConnection, type CoSignFrame, type CoSignRequestAuthenticator, type CoSignRequestEnvelope, type CoSignTransport, CoSignUnavailableError, type CreateLocalPolicyGatedSignerParams, type Mpc2pCoSignAgent, type Mpc2pSignerParams, type Mpc2pStepOutcome, NonBypassableEnforcement, PaymentIntent, PolicyGatedSigner, PolicyGatedSignerConfigError, WIRE_VERSION, type WireIntent, assertNonBypassable, canonicalRequestBytes, createLocalPolicyGatedSigner, createMpc2pPolicyGatedSigner, requireNonBypassable, toWireIntent };
|
package/dist/signer/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { createLocalPolicyGatedSigner } from '../chunk-
|
|
2
|
-
export { PolicyGatedSignerConfigError, assertNonBypassable, requireNonBypassable } from '../chunk-
|
|
1
|
+
export { WIRE_VERSION, canonicalRequestBytes, createLocalPolicyGatedSigner, createMpc2pPolicyGatedSigner, toWireIntent } from '../chunk-FD6Q4NB2.js';
|
|
2
|
+
export { CoSignUnavailableError, PolicyGatedSignerConfigError, assertNonBypassable, requireNonBypassable } from '../chunk-5TTOAVHE.js';
|
|
3
3
|
import '../chunk-WMVJNPX2.js';
|
|
4
4
|
import '../chunk-6CNAYQOL.js';
|
|
5
5
|
import '../chunk-KT7XDT2T.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Address } from 'viem';
|
|
2
|
-
import { b as PolicyRejection, P as PaymentIntent } from './types-
|
|
2
|
+
import { b as PolicyRejection, P as PaymentIntent } from './types-BLJU67HZ.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Spending policy — policy-as-data for the x402 / EIP-3009 PolicyGatedSigner
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Address } from 'viem';
|
|
2
|
-
import { b as PolicyRejection, P as PaymentIntent } from './types-
|
|
2
|
+
import { b as PolicyRejection, P as PaymentIntent } from './types-BLJU67HZ.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Spending policy — policy-as-data for the x402 / EIP-3009 PolicyGatedSigner
|
|
@@ -77,11 +77,19 @@ interface PaymentIntent {
|
|
|
77
77
|
* The evaluator (`evaluateSpendingPolicy`) emits the `revoked` / `expired` /
|
|
78
78
|
* `token_not_allowed` / `recipient_not_allowed` / `amount_exceeds_*` reasons;
|
|
79
79
|
* the adapter additionally emits `from_mismatch` and (for `mpc-2p`)
|
|
80
|
-
* `intent_digest_mismatch` / `unauthenticated`. The
|
|
81
|
-
* `SignResult` regardless of adapter.
|
|
80
|
+
* `intent_digest_mismatch` / `unauthenticated` / `nonce_reuse_conflict`. The
|
|
81
|
+
* consumer handles one `SignResult` regardless of adapter.
|
|
82
82
|
*/
|
|
83
83
|
interface PolicyRejection {
|
|
84
|
-
readonly reason: "revoked" | "expired" | "token_not_allowed" | "recipient_not_allowed" | "amount_exceeds_per_sign" | "amount_exceeds_cumulative" | "intent_digest_mismatch" | "unauthenticated" | "from_mismatch"
|
|
84
|
+
readonly reason: "revoked" | "expired" | "token_not_allowed" | "recipient_not_allowed" | "amount_exceeds_per_sign" | "amount_exceeds_cumulative" | "intent_digest_mismatch" | "unauthenticated" | "from_mismatch"
|
|
85
|
+
/**
|
|
86
|
+
* (`mpc-2p`) The co-signer was presented a **previously-seen EIP-3009
|
|
87
|
+
* nonce with different intent fields** — the B7 same-nonce/different-fields
|
|
88
|
+
* fund-correctness anomaly. The backend denies + audits it; double-pay
|
|
89
|
+
* protection (same nonce, same fields → cached result) is a separate,
|
|
90
|
+
* non-rejection path (M5 `deriveAuthorizationNonce` + `authorizationState`).
|
|
91
|
+
*/
|
|
92
|
+
| "nonce_reuse_conflict";
|
|
85
93
|
/** Human-readable reason; never contains the nonce or a signature. */
|
|
86
94
|
readonly detail: string;
|
|
87
95
|
}
|
|
@@ -77,11 +77,19 @@ interface PaymentIntent {
|
|
|
77
77
|
* The evaluator (`evaluateSpendingPolicy`) emits the `revoked` / `expired` /
|
|
78
78
|
* `token_not_allowed` / `recipient_not_allowed` / `amount_exceeds_*` reasons;
|
|
79
79
|
* the adapter additionally emits `from_mismatch` and (for `mpc-2p`)
|
|
80
|
-
* `intent_digest_mismatch` / `unauthenticated`. The
|
|
81
|
-
* `SignResult` regardless of adapter.
|
|
80
|
+
* `intent_digest_mismatch` / `unauthenticated` / `nonce_reuse_conflict`. The
|
|
81
|
+
* consumer handles one `SignResult` regardless of adapter.
|
|
82
82
|
*/
|
|
83
83
|
interface PolicyRejection {
|
|
84
|
-
readonly reason: "revoked" | "expired" | "token_not_allowed" | "recipient_not_allowed" | "amount_exceeds_per_sign" | "amount_exceeds_cumulative" | "intent_digest_mismatch" | "unauthenticated" | "from_mismatch"
|
|
84
|
+
readonly reason: "revoked" | "expired" | "token_not_allowed" | "recipient_not_allowed" | "amount_exceeds_per_sign" | "amount_exceeds_cumulative" | "intent_digest_mismatch" | "unauthenticated" | "from_mismatch"
|
|
85
|
+
/**
|
|
86
|
+
* (`mpc-2p`) The co-signer was presented a **previously-seen EIP-3009
|
|
87
|
+
* nonce with different intent fields** — the B7 same-nonce/different-fields
|
|
88
|
+
* fund-correctness anomaly. The backend denies + audits it; double-pay
|
|
89
|
+
* protection (same nonce, same fields → cached result) is a separate,
|
|
90
|
+
* non-rejection path (M5 `deriveAuthorizationNonce` + `authorizationState`).
|
|
91
|
+
*/
|
|
92
|
+
| "nonce_reuse_conflict";
|
|
85
93
|
/** Human-readable reason; never contains the nonce or a signature. */
|
|
86
94
|
readonly detail: string;
|
|
87
95
|
}
|