kawasekit 0.1.0 → 0.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/asset-domain-4Ioxqn28.d.cts +348 -0
- package/dist/asset-domain-4Ioxqn28.d.ts +348 -0
- package/dist/{chunk-VPRR3TNA.js → chunk-5TTOAVHE.js} +65 -51
- package/dist/chunk-5TTOAVHE.js.map +1 -0
- package/dist/{chunk-YMABXRCK.js → chunk-6CNAYQOL.js} +2 -2
- package/dist/chunk-6CNAYQOL.js.map +1 -0
- package/dist/chunk-EUW7AZ4P.js +276 -0
- package/dist/chunk-EUW7AZ4P.js.map +1 -0
- package/dist/{chunk-E2EG72U2.js → chunk-G3UC6SME.js} +4 -9
- package/dist/chunk-G3UC6SME.js.map +1 -0
- package/dist/{chunk-UQ7WJY6O.js → chunk-RJLDKDWL.js} +2 -2
- package/dist/{chunk-UQ7WJY6O.js.map → chunk-RJLDKDWL.js.map} +1 -1
- package/dist/cli/index.cjs +1 -1
- package/dist/cli/index.js +6 -6
- package/dist/{index-BaAOB0xd.d.ts → index-C9tbaHPF.d.ts} +2 -2
- package/dist/{index-Z6AL1MR_.d.cts → index-CAmTA8xR.d.cts} +2 -2
- package/dist/index.cjs +236 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -172
- package/dist/index.d.ts +7 -172
- package/dist/index.js +5 -5
- package/dist/policy/index.cjs.map +1 -1
- package/dist/policy/index.d.cts +2 -2
- package/dist/policy/index.d.ts +2 -2
- package/dist/policy/index.js +1 -1
- package/dist/signer/index.cjs +227 -6
- package/dist/signer/index.cjs.map +1 -1
- package/dist/signer/index.d.cts +221 -6
- package/dist/signer/index.d.ts +221 -6
- package/dist/signer/index.js +3 -3
- package/dist/{spending-policy-DqBRDUxx.d.cts → spending-policy-BD2Mpm-L.d.ts} +4 -3
- package/dist/{spending-policy-DZSNHqnD.d.ts → spending-policy-CGIaBpg-.d.cts} +4 -3
- 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 +9 -6
- package/dist/x402/index.cjs.map +1 -1
- package/dist/x402/index.d.cts +3 -3
- package/dist/x402/index.d.ts +3 -3
- package/dist/x402/index.js +2 -2
- package/package.json +1 -1
- package/dist/asset-domain-CpJuDkI2.d.cts +0 -102
- package/dist/asset-domain-CpJuDkI2.d.ts +0 -102
- package/dist/chunk-E2EG72U2.js.map +0 -1
- package/dist/chunk-RUWCCP37.js +0 -76
- package/dist/chunk-RUWCCP37.js.map +0 -1
- package/dist/chunk-VPRR3TNA.js.map +0 -1
- package/dist/chunk-YMABXRCK.js.map +0 -1
package/dist/signer/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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-
|
|
5
|
-
import { X as X402AssetParam } from '../asset-domain-
|
|
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
|
+
import { X as X402AssetParam } from '../asset-domain-4Ioxqn28.cjs';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* PolicyGatedSigner error types.
|
|
@@ -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,189 @@ interface CreateLocalPolicyGatedSignerParams {
|
|
|
128
158
|
*/
|
|
129
159
|
declare function createLocalPolicyGatedSigner(params: CreateLocalPolicyGatedSignerParams): PolicyGatedSigner<"advisory">;
|
|
130
160
|
|
|
131
|
-
|
|
161
|
+
/**
|
|
162
|
+
* The `mpc-2p` cross-process **wire** — 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) plus the opaque DKLs round payloads (hex, produced/consumed only
|
|
168
|
+
* by the WASM crypto agent). The shapes here mirror the deployed
|
|
169
|
+
* `kawasekit-mpc-2p` Rust serde **byte-for-byte** (snake_case `wire_version`,
|
|
170
|
+
* `session_id`, `auth_tag`; the string-encoded {@link WireIntent}), so a frame the
|
|
171
|
+
* SDK builds round-trips through the backend's `serde_json`. The richer envelope
|
|
172
|
+
* (ceremonyId / ssid / A3 freshness) is a later slice.
|
|
173
|
+
*
|
|
174
|
+
* `canonicalIntentBytes` is the A3 analog of the EIP-712 digest corpus: it
|
|
175
|
+
* reproduces the backend's `auth::canonical_intent_bytes` exactly, so the
|
|
176
|
+
* injected authenticator's HMAC equals what the co-signer verifies.
|
|
177
|
+
*
|
|
178
|
+
* @packageDocumentation
|
|
179
|
+
*/
|
|
180
|
+
|
|
181
|
+
/** The wire protocol version. A frame whose `wire_version` differs is rejected. */
|
|
182
|
+
declare const WIRE_VERSION: 1;
|
|
183
|
+
/**
|
|
184
|
+
* The string-encoded EIP-3009 intent as it crosses the wire — lowercase `0x`
|
|
185
|
+
* addresses, **decimal** integer strings, `0x` hex nonce. Decoupled from any
|
|
186
|
+
* library's native serde so a stdlib client reproduces it trivially; matches the
|
|
187
|
+
* Rust `WireIntent` field names + encoding exactly.
|
|
188
|
+
*/
|
|
189
|
+
interface WireIntent {
|
|
190
|
+
readonly token: string;
|
|
191
|
+
readonly chain_id: number;
|
|
192
|
+
readonly from: string;
|
|
193
|
+
readonly to: string;
|
|
194
|
+
readonly value: string;
|
|
195
|
+
readonly valid_after: string;
|
|
196
|
+
readonly valid_before: string;
|
|
197
|
+
readonly nonce: string;
|
|
198
|
+
}
|
|
199
|
+
/** Encode a decoded {@link PaymentIntent} for the wire. */
|
|
200
|
+
declare function toWireIntent(intent: PaymentIntent): WireIntent;
|
|
201
|
+
/**
|
|
202
|
+
* A versioned control frame: the only cross-language content of the wire. The
|
|
203
|
+
* DKLs round bytes ride opaque inside `payload`; everything else is the small,
|
|
204
|
+
* pinned envelope. Internally tagged by `kind` (matches the Rust serde).
|
|
205
|
+
*/
|
|
206
|
+
type CoSignFrame = {
|
|
207
|
+
readonly wire_version: typeof WIRE_VERSION;
|
|
208
|
+
} & ({
|
|
209
|
+
readonly kind: "request";
|
|
210
|
+
readonly session_id: string;
|
|
211
|
+
readonly intent: WireIntent;
|
|
212
|
+
/** A3 authenticator over {@link canonicalIntentBytes}, `0x`-hex. */
|
|
213
|
+
readonly auth_tag: Hex;
|
|
214
|
+
} | {
|
|
215
|
+
readonly kind: "round";
|
|
216
|
+
readonly payload: Hex;
|
|
217
|
+
} | {
|
|
218
|
+
readonly kind: "result";
|
|
219
|
+
readonly r: Hex;
|
|
220
|
+
readonly s: Hex;
|
|
221
|
+
readonly v: number;
|
|
222
|
+
} | {
|
|
223
|
+
readonly kind: "rejection";
|
|
224
|
+
readonly reason: string;
|
|
225
|
+
readonly detail: string;
|
|
226
|
+
} | {
|
|
227
|
+
readonly kind: "error";
|
|
228
|
+
readonly message: string;
|
|
229
|
+
});
|
|
230
|
+
/**
|
|
231
|
+
* The A3 canonical encoding of an intent — a byte-exact mirror of the backend's
|
|
232
|
+
* `auth::canonical_intent_bytes` (domain-tag `kawasekit-mpc-2p/cosign-request/v2`,
|
|
233
|
+
* one `key=value\n` line per field, lowercase `0x` addresses, decimal integers,
|
|
234
|
+
* `0x` hex nonce, trailing newline). The injected authenticator HMACs these bytes;
|
|
235
|
+
* because the encoding is shared, the tag equals the co-signer's.
|
|
236
|
+
*/
|
|
237
|
+
declare function canonicalIntentBytes(intent: PaymentIntent): Uint8Array;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* The `mpc-2p` PolicyGatedSigner adapter — `enforcement: "cryptographic"`.
|
|
241
|
+
*
|
|
242
|
+
* A 2-of-2 MPC co-signer: the agent holds ONE DKLs share, the owner backend holds
|
|
243
|
+
* the other + the authoritative policy gate. No valid signature exists without a
|
|
244
|
+
* **policy-passing co-sign**, so — unlike `local` — a single key-holder cannot
|
|
245
|
+
* bypass the policy. That is what earns the non-bypassable `"cryptographic"` label
|
|
246
|
+
* and lets the M6-0 type-gate (`requireNonBypassable`) reject an advisory signer at
|
|
247
|
+
* compile time in bounded flows.
|
|
248
|
+
*
|
|
249
|
+
* **Open-core / thin adapter.** This module is pure orchestration over injected
|
|
250
|
+
* interfaces — it ships in the public SDK with **no crypto, no socket, no key**:
|
|
251
|
+
*
|
|
252
|
+
* - {@link Mpc2pCoSignAgent} — the WASM DKLs share (the private package's compiled
|
|
253
|
+
* `crypto-core`); drives the agent's half of the ceremony round-by-round.
|
|
254
|
+
* - {@link CoSignTransport} — the authenticated, encrypted (wss/mTLS) frame channel
|
|
255
|
+
* to the owner backend (the private package's transport).
|
|
256
|
+
* - {@link CoSignRequestAuthenticator} — the A3 HMAC (the pre-shared key never
|
|
257
|
+
* enters this module).
|
|
258
|
+
*
|
|
259
|
+
* The adapter owns the protocol: it pins the EIP-712 domain, **re-derives the
|
|
260
|
+
* digest from the intent (A4)** via the shared `transferWithAuthorizationTypes`
|
|
261
|
+
* source-of-truth, computes the A3 canonical bytes, frames the versioned
|
|
262
|
+
* {@link CoSignFrame} envelope, pumps the ceremony, and maps the terminal frame to
|
|
263
|
+
* a {@link SignResult}. Crucially it has **no local-signing path**: any
|
|
264
|
+
* transport/availability failure throws {@link CoSignUnavailableError}, never an
|
|
265
|
+
* `{ ok: true }` and never a {@link PolicyRejection} (the no-silent-fallback
|
|
266
|
+
* guarantee, RFC m6-3a constraint 3 / W8).
|
|
267
|
+
*
|
|
268
|
+
* @packageDocumentation
|
|
269
|
+
*/
|
|
270
|
+
|
|
271
|
+
/** The agent's half of the 2-of-2 ceremony (the injected WASM DKLs share). */
|
|
272
|
+
interface Mpc2pCoSignAgent {
|
|
273
|
+
/** The group 2-of-2 EOA this share controls — must equal the signer's `from`. */
|
|
274
|
+
groupEoa(): Address;
|
|
275
|
+
/** Begin signing the 32-byte EIP-712 `digest`; returns the first outbound round (hex). */
|
|
276
|
+
start(digest: Hex): Hex;
|
|
277
|
+
/** Feed one inbound round (hex); returns the next outbound round, or the final signature. */
|
|
278
|
+
step(incoming: Hex): Mpc2pStepOutcome;
|
|
279
|
+
}
|
|
280
|
+
/** The result of one {@link Mpc2pCoSignAgent.step}. */
|
|
281
|
+
type Mpc2pStepOutcome = {
|
|
282
|
+
readonly outbound: Hex;
|
|
283
|
+
} | {
|
|
284
|
+
readonly signature: {
|
|
285
|
+
readonly r: Hex;
|
|
286
|
+
readonly s: Hex;
|
|
287
|
+
readonly v: number;
|
|
288
|
+
};
|
|
289
|
+
};
|
|
290
|
+
/** One authenticated, encrypted ceremony connection to the owner backend. */
|
|
291
|
+
interface CoSignConnection {
|
|
292
|
+
/** Send one control frame. */
|
|
293
|
+
send(frame: CoSignFrame): Promise<void>;
|
|
294
|
+
/** Receive the next control frame (resolves per round). */
|
|
295
|
+
recv(): Promise<CoSignFrame>;
|
|
296
|
+
/** Release the connection (best-effort; errors here are ignored). */
|
|
297
|
+
close(): void | Promise<void>;
|
|
298
|
+
}
|
|
299
|
+
/** Opens a wss/mTLS {@link CoSignConnection} for a single co-sign ceremony. */
|
|
300
|
+
interface CoSignTransport {
|
|
301
|
+
connect(): Promise<CoSignConnection>;
|
|
302
|
+
}
|
|
303
|
+
/** The A3 request authenticator — HMAC (or signature) over the canonical request bytes. */
|
|
304
|
+
interface CoSignRequestAuthenticator {
|
|
305
|
+
/** Authenticator tag over {@link canonicalIntentBytes}; the key stays inside. */
|
|
306
|
+
tag(canonicalRequest: Uint8Array): Hex | Promise<Hex>;
|
|
307
|
+
}
|
|
308
|
+
/** Parameters for {@link createMpc2pPolicyGatedSigner}. */
|
|
309
|
+
interface Mpc2pSignerParams {
|
|
310
|
+
/** The group 2-of-2 EOA; every `intent.from` must equal this (asserted vs the agent). */
|
|
311
|
+
readonly from: Address;
|
|
312
|
+
/** Asset binding — pins the EIP-712 domain `name`/`version`/`verifyingContract` (A4). */
|
|
313
|
+
readonly asset: X402AssetParam;
|
|
314
|
+
/** The bound policy session, for `describe()` (the backend holds the authoritative policy). */
|
|
315
|
+
readonly session: {
|
|
316
|
+
readonly id: string;
|
|
317
|
+
readonly notAfter: bigint;
|
|
318
|
+
};
|
|
319
|
+
/** The injected WASM DKLs share (private package). */
|
|
320
|
+
readonly agent: Mpc2pCoSignAgent;
|
|
321
|
+
/** The injected wss/mTLS frame channel (private package). */
|
|
322
|
+
readonly transport: CoSignTransport;
|
|
323
|
+
/** The injected A3 authenticator (the pre-shared key never enters the SDK). */
|
|
324
|
+
readonly authenticator: CoSignRequestAuthenticator;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Construct an `mpc-2p` (cryptographic) PolicyGatedSigner over injected agent +
|
|
328
|
+
* transport + authenticator.
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* ```ts
|
|
332
|
+
* // The agent, transport and authenticator come from the private `kawasekit-mpc-2p`
|
|
333
|
+
* // package (the WASM share, the wss/mTLS client, the HMAC key) — never bundled here.
|
|
334
|
+
* const signer = createMpc2pPolicyGatedSigner({
|
|
335
|
+
* from: groupEoa,
|
|
336
|
+
* asset: { kind: "known", id: "jpyc-v2" },
|
|
337
|
+
* session: { id: "sess-1", notAfter: 2_000_000_000n },
|
|
338
|
+
* agent, transport, authenticator,
|
|
339
|
+
* });
|
|
340
|
+
* requireNonBypassable(signer); // ✓ "cryptographic" — passes the type-gate
|
|
341
|
+
* const result = await signer.sign(intent);
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
declare function createMpc2pPolicyGatedSigner(params: Mpc2pSignerParams): PolicyGatedSigner<"cryptographic">;
|
|
345
|
+
|
|
346
|
+
export { type CoSignConnection, type CoSignFrame, type CoSignRequestAuthenticator, type CoSignTransport, CoSignUnavailableError, type CreateLocalPolicyGatedSignerParams, type Mpc2pCoSignAgent, type Mpc2pSignerParams, type Mpc2pStepOutcome, NonBypassableEnforcement, PaymentIntent, PolicyGatedSigner, PolicyGatedSignerConfigError, WIRE_VERSION, type WireIntent, assertNonBypassable, canonicalIntentBytes, createLocalPolicyGatedSigner, createMpc2pPolicyGatedSigner, requireNonBypassable, toWireIntent };
|
package/dist/signer/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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-
|
|
5
|
-
import { X as X402AssetParam } from '../asset-domain-
|
|
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
|
+
import { X as X402AssetParam } from '../asset-domain-4Ioxqn28.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* PolicyGatedSigner error types.
|
|
@@ -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,189 @@ interface CreateLocalPolicyGatedSignerParams {
|
|
|
128
158
|
*/
|
|
129
159
|
declare function createLocalPolicyGatedSigner(params: CreateLocalPolicyGatedSignerParams): PolicyGatedSigner<"advisory">;
|
|
130
160
|
|
|
131
|
-
|
|
161
|
+
/**
|
|
162
|
+
* The `mpc-2p` cross-process **wire** — 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) plus the opaque DKLs round payloads (hex, produced/consumed only
|
|
168
|
+
* by the WASM crypto agent). The shapes here mirror the deployed
|
|
169
|
+
* `kawasekit-mpc-2p` Rust serde **byte-for-byte** (snake_case `wire_version`,
|
|
170
|
+
* `session_id`, `auth_tag`; the string-encoded {@link WireIntent}), so a frame the
|
|
171
|
+
* SDK builds round-trips through the backend's `serde_json`. The richer envelope
|
|
172
|
+
* (ceremonyId / ssid / A3 freshness) is a later slice.
|
|
173
|
+
*
|
|
174
|
+
* `canonicalIntentBytes` is the A3 analog of the EIP-712 digest corpus: it
|
|
175
|
+
* reproduces the backend's `auth::canonical_intent_bytes` exactly, so the
|
|
176
|
+
* injected authenticator's HMAC equals what the co-signer verifies.
|
|
177
|
+
*
|
|
178
|
+
* @packageDocumentation
|
|
179
|
+
*/
|
|
180
|
+
|
|
181
|
+
/** The wire protocol version. A frame whose `wire_version` differs is rejected. */
|
|
182
|
+
declare const WIRE_VERSION: 1;
|
|
183
|
+
/**
|
|
184
|
+
* The string-encoded EIP-3009 intent as it crosses the wire — lowercase `0x`
|
|
185
|
+
* addresses, **decimal** integer strings, `0x` hex nonce. Decoupled from any
|
|
186
|
+
* library's native serde so a stdlib client reproduces it trivially; matches the
|
|
187
|
+
* Rust `WireIntent` field names + encoding exactly.
|
|
188
|
+
*/
|
|
189
|
+
interface WireIntent {
|
|
190
|
+
readonly token: string;
|
|
191
|
+
readonly chain_id: number;
|
|
192
|
+
readonly from: string;
|
|
193
|
+
readonly to: string;
|
|
194
|
+
readonly value: string;
|
|
195
|
+
readonly valid_after: string;
|
|
196
|
+
readonly valid_before: string;
|
|
197
|
+
readonly nonce: string;
|
|
198
|
+
}
|
|
199
|
+
/** Encode a decoded {@link PaymentIntent} for the wire. */
|
|
200
|
+
declare function toWireIntent(intent: PaymentIntent): WireIntent;
|
|
201
|
+
/**
|
|
202
|
+
* A versioned control frame: the only cross-language content of the wire. The
|
|
203
|
+
* DKLs round bytes ride opaque inside `payload`; everything else is the small,
|
|
204
|
+
* pinned envelope. Internally tagged by `kind` (matches the Rust serde).
|
|
205
|
+
*/
|
|
206
|
+
type CoSignFrame = {
|
|
207
|
+
readonly wire_version: typeof WIRE_VERSION;
|
|
208
|
+
} & ({
|
|
209
|
+
readonly kind: "request";
|
|
210
|
+
readonly session_id: string;
|
|
211
|
+
readonly intent: WireIntent;
|
|
212
|
+
/** A3 authenticator over {@link canonicalIntentBytes}, `0x`-hex. */
|
|
213
|
+
readonly auth_tag: Hex;
|
|
214
|
+
} | {
|
|
215
|
+
readonly kind: "round";
|
|
216
|
+
readonly payload: Hex;
|
|
217
|
+
} | {
|
|
218
|
+
readonly kind: "result";
|
|
219
|
+
readonly r: Hex;
|
|
220
|
+
readonly s: Hex;
|
|
221
|
+
readonly v: number;
|
|
222
|
+
} | {
|
|
223
|
+
readonly kind: "rejection";
|
|
224
|
+
readonly reason: string;
|
|
225
|
+
readonly detail: string;
|
|
226
|
+
} | {
|
|
227
|
+
readonly kind: "error";
|
|
228
|
+
readonly message: string;
|
|
229
|
+
});
|
|
230
|
+
/**
|
|
231
|
+
* The A3 canonical encoding of an intent — a byte-exact mirror of the backend's
|
|
232
|
+
* `auth::canonical_intent_bytes` (domain-tag `kawasekit-mpc-2p/cosign-request/v2`,
|
|
233
|
+
* one `key=value\n` line per field, lowercase `0x` addresses, decimal integers,
|
|
234
|
+
* `0x` hex nonce, trailing newline). The injected authenticator HMACs these bytes;
|
|
235
|
+
* because the encoding is shared, the tag equals the co-signer's.
|
|
236
|
+
*/
|
|
237
|
+
declare function canonicalIntentBytes(intent: PaymentIntent): Uint8Array;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* The `mpc-2p` PolicyGatedSigner adapter — `enforcement: "cryptographic"`.
|
|
241
|
+
*
|
|
242
|
+
* A 2-of-2 MPC co-signer: the agent holds ONE DKLs share, the owner backend holds
|
|
243
|
+
* the other + the authoritative policy gate. No valid signature exists without a
|
|
244
|
+
* **policy-passing co-sign**, so — unlike `local` — a single key-holder cannot
|
|
245
|
+
* bypass the policy. That is what earns the non-bypassable `"cryptographic"` label
|
|
246
|
+
* and lets the M6-0 type-gate (`requireNonBypassable`) reject an advisory signer at
|
|
247
|
+
* compile time in bounded flows.
|
|
248
|
+
*
|
|
249
|
+
* **Open-core / thin adapter.** This module is pure orchestration over injected
|
|
250
|
+
* interfaces — it ships in the public SDK with **no crypto, no socket, no key**:
|
|
251
|
+
*
|
|
252
|
+
* - {@link Mpc2pCoSignAgent} — the WASM DKLs share (the private package's compiled
|
|
253
|
+
* `crypto-core`); drives the agent's half of the ceremony round-by-round.
|
|
254
|
+
* - {@link CoSignTransport} — the authenticated, encrypted (wss/mTLS) frame channel
|
|
255
|
+
* to the owner backend (the private package's transport).
|
|
256
|
+
* - {@link CoSignRequestAuthenticator} — the A3 HMAC (the pre-shared key never
|
|
257
|
+
* enters this module).
|
|
258
|
+
*
|
|
259
|
+
* The adapter owns the protocol: it pins the EIP-712 domain, **re-derives the
|
|
260
|
+
* digest from the intent (A4)** via the shared `transferWithAuthorizationTypes`
|
|
261
|
+
* source-of-truth, computes the A3 canonical bytes, frames the versioned
|
|
262
|
+
* {@link CoSignFrame} envelope, pumps the ceremony, and maps the terminal frame to
|
|
263
|
+
* a {@link SignResult}. Crucially it has **no local-signing path**: any
|
|
264
|
+
* transport/availability failure throws {@link CoSignUnavailableError}, never an
|
|
265
|
+
* `{ ok: true }` and never a {@link PolicyRejection} (the no-silent-fallback
|
|
266
|
+
* guarantee, RFC m6-3a constraint 3 / W8).
|
|
267
|
+
*
|
|
268
|
+
* @packageDocumentation
|
|
269
|
+
*/
|
|
270
|
+
|
|
271
|
+
/** The agent's half of the 2-of-2 ceremony (the injected WASM DKLs share). */
|
|
272
|
+
interface Mpc2pCoSignAgent {
|
|
273
|
+
/** The group 2-of-2 EOA this share controls — must equal the signer's `from`. */
|
|
274
|
+
groupEoa(): Address;
|
|
275
|
+
/** Begin signing the 32-byte EIP-712 `digest`; returns the first outbound round (hex). */
|
|
276
|
+
start(digest: Hex): Hex;
|
|
277
|
+
/** Feed one inbound round (hex); returns the next outbound round, or the final signature. */
|
|
278
|
+
step(incoming: Hex): Mpc2pStepOutcome;
|
|
279
|
+
}
|
|
280
|
+
/** The result of one {@link Mpc2pCoSignAgent.step}. */
|
|
281
|
+
type Mpc2pStepOutcome = {
|
|
282
|
+
readonly outbound: Hex;
|
|
283
|
+
} | {
|
|
284
|
+
readonly signature: {
|
|
285
|
+
readonly r: Hex;
|
|
286
|
+
readonly s: Hex;
|
|
287
|
+
readonly v: number;
|
|
288
|
+
};
|
|
289
|
+
};
|
|
290
|
+
/** One authenticated, encrypted ceremony connection to the owner backend. */
|
|
291
|
+
interface CoSignConnection {
|
|
292
|
+
/** Send one control frame. */
|
|
293
|
+
send(frame: CoSignFrame): Promise<void>;
|
|
294
|
+
/** Receive the next control frame (resolves per round). */
|
|
295
|
+
recv(): Promise<CoSignFrame>;
|
|
296
|
+
/** Release the connection (best-effort; errors here are ignored). */
|
|
297
|
+
close(): void | Promise<void>;
|
|
298
|
+
}
|
|
299
|
+
/** Opens a wss/mTLS {@link CoSignConnection} for a single co-sign ceremony. */
|
|
300
|
+
interface CoSignTransport {
|
|
301
|
+
connect(): Promise<CoSignConnection>;
|
|
302
|
+
}
|
|
303
|
+
/** The A3 request authenticator — HMAC (or signature) over the canonical request bytes. */
|
|
304
|
+
interface CoSignRequestAuthenticator {
|
|
305
|
+
/** Authenticator tag over {@link canonicalIntentBytes}; the key stays inside. */
|
|
306
|
+
tag(canonicalRequest: Uint8Array): Hex | Promise<Hex>;
|
|
307
|
+
}
|
|
308
|
+
/** Parameters for {@link createMpc2pPolicyGatedSigner}. */
|
|
309
|
+
interface Mpc2pSignerParams {
|
|
310
|
+
/** The group 2-of-2 EOA; every `intent.from` must equal this (asserted vs the agent). */
|
|
311
|
+
readonly from: Address;
|
|
312
|
+
/** Asset binding — pins the EIP-712 domain `name`/`version`/`verifyingContract` (A4). */
|
|
313
|
+
readonly asset: X402AssetParam;
|
|
314
|
+
/** The bound policy session, for `describe()` (the backend holds the authoritative policy). */
|
|
315
|
+
readonly session: {
|
|
316
|
+
readonly id: string;
|
|
317
|
+
readonly notAfter: bigint;
|
|
318
|
+
};
|
|
319
|
+
/** The injected WASM DKLs share (private package). */
|
|
320
|
+
readonly agent: Mpc2pCoSignAgent;
|
|
321
|
+
/** The injected wss/mTLS frame channel (private package). */
|
|
322
|
+
readonly transport: CoSignTransport;
|
|
323
|
+
/** The injected A3 authenticator (the pre-shared key never enters the SDK). */
|
|
324
|
+
readonly authenticator: CoSignRequestAuthenticator;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Construct an `mpc-2p` (cryptographic) PolicyGatedSigner over injected agent +
|
|
328
|
+
* transport + authenticator.
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* ```ts
|
|
332
|
+
* // The agent, transport and authenticator come from the private `kawasekit-mpc-2p`
|
|
333
|
+
* // package (the WASM share, the wss/mTLS client, the HMAC key) — never bundled here.
|
|
334
|
+
* const signer = createMpc2pPolicyGatedSigner({
|
|
335
|
+
* from: groupEoa,
|
|
336
|
+
* asset: { kind: "known", id: "jpyc-v2" },
|
|
337
|
+
* session: { id: "sess-1", notAfter: 2_000_000_000n },
|
|
338
|
+
* agent, transport, authenticator,
|
|
339
|
+
* });
|
|
340
|
+
* requireNonBypassable(signer); // ✓ "cryptographic" — passes the type-gate
|
|
341
|
+
* const result = await signer.sign(intent);
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
declare function createMpc2pPolicyGatedSigner(params: Mpc2pSignerParams): PolicyGatedSigner<"cryptographic">;
|
|
345
|
+
|
|
346
|
+
export { type CoSignConnection, type CoSignFrame, type CoSignRequestAuthenticator, type CoSignTransport, CoSignUnavailableError, type CreateLocalPolicyGatedSignerParams, type Mpc2pCoSignAgent, type Mpc2pSignerParams, type Mpc2pStepOutcome, NonBypassableEnforcement, PaymentIntent, PolicyGatedSigner, PolicyGatedSignerConfigError, WIRE_VERSION, type WireIntent, assertNonBypassable, canonicalIntentBytes, createLocalPolicyGatedSigner, createMpc2pPolicyGatedSigner, requireNonBypassable, toWireIntent };
|
package/dist/signer/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { createLocalPolicyGatedSigner } from '../chunk-
|
|
2
|
-
export { PolicyGatedSignerConfigError, assertNonBypassable, requireNonBypassable } from '../chunk-
|
|
1
|
+
export { WIRE_VERSION, canonicalIntentBytes, createLocalPolicyGatedSigner, createMpc2pPolicyGatedSigner, toWireIntent } from '../chunk-EUW7AZ4P.js';
|
|
2
|
+
export { CoSignUnavailableError, PolicyGatedSignerConfigError, assertNonBypassable, requireNonBypassable } from '../chunk-5TTOAVHE.js';
|
|
3
3
|
import '../chunk-WMVJNPX2.js';
|
|
4
|
-
import '../chunk-
|
|
4
|
+
import '../chunk-6CNAYQOL.js';
|
|
5
5
|
import '../chunk-KT7XDT2T.js';
|
|
6
6
|
import '../chunk-SOTYGX67.js';
|
|
7
7
|
import '../chunk-7D4SUZUM.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
|
|
@@ -8,8 +8,9 @@ import { b as PolicyRejection, P as PaymentIntent } from './types-IEl-iOIx.cjs';
|
|
|
8
8
|
* deny-closed evaluator {@link evaluateSpendingPolicy}.
|
|
9
9
|
*
|
|
10
10
|
* The same specification is enforced SDK-side (the `local` adapter) and, for the
|
|
11
|
-
* `mpc-2p` adapter, re-implemented backend-side in
|
|
12
|
-
*
|
|
11
|
+
* `mpc-2p` adapter, re-implemented backend-side in Rust (the `kawasekit-mpc-2p`
|
|
12
|
+
* co-signer); a shared conformance corpus
|
|
13
|
+
* (`__fixtures__/spending-policy.vectors.json`) keeps the two in lockstep.
|
|
13
14
|
* The evaluator is **check-only** — it reads `SpendState` and never mutates it;
|
|
14
15
|
* the cumulative-cap *commit* (folding a successful spend back in via
|
|
15
16
|
* {@link mergeSpendState}) is the adapter's job, and atomic+authoritative
|
|
@@ -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
|
|
@@ -8,8 +8,9 @@ import { b as PolicyRejection, P as PaymentIntent } from './types-IEl-iOIx.js';
|
|
|
8
8
|
* deny-closed evaluator {@link evaluateSpendingPolicy}.
|
|
9
9
|
*
|
|
10
10
|
* The same specification is enforced SDK-side (the `local` adapter) and, for the
|
|
11
|
-
* `mpc-2p` adapter, re-implemented backend-side in
|
|
12
|
-
*
|
|
11
|
+
* `mpc-2p` adapter, re-implemented backend-side in Rust (the `kawasekit-mpc-2p`
|
|
12
|
+
* co-signer); a shared conformance corpus
|
|
13
|
+
* (`__fixtures__/spending-policy.vectors.json`) keeps the two in lockstep.
|
|
13
14
|
* The evaluator is **check-only** — it reads `SpendState` and never mutates it;
|
|
14
15
|
* the cumulative-cap *commit* (folding a successful spend back in via
|
|
15
16
|
* {@link mergeSpendState}) is the adapter's job, and atomic+authoritative
|
|
@@ -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
|
}
|
package/dist/x402/index.cjs
CHANGED
|
@@ -403,6 +403,14 @@ function resolveAssetParam(asset) {
|
|
|
403
403
|
`unsupported kind ${JSON.stringify(exhaustive.kind)}. Expected "known" or "unsafeOverride".`
|
|
404
404
|
);
|
|
405
405
|
}
|
|
406
|
+
function resolvedAssetToEip3009Domain(asset, chainId) {
|
|
407
|
+
return {
|
|
408
|
+
name: asset.name,
|
|
409
|
+
version: asset.version,
|
|
410
|
+
chainId,
|
|
411
|
+
verifyingContract: asset.verifyingContract
|
|
412
|
+
};
|
|
413
|
+
}
|
|
406
414
|
var transferWithAuthorizationTypes = {
|
|
407
415
|
TransferWithAuthorization: [
|
|
408
416
|
{ name: "from", type: "address" },
|
|
@@ -626,12 +634,7 @@ function createX402PaymentSigner(params) {
|
|
|
626
634
|
) : generateAuthorizationNonce();
|
|
627
635
|
const signed = await signTransferWithAuthorization(
|
|
628
636
|
account,
|
|
629
|
-
|
|
630
|
-
name: pinnedDomain.name,
|
|
631
|
-
version: pinnedDomain.version,
|
|
632
|
-
chainId,
|
|
633
|
-
verifyingContract: pinnedDomain.verifyingContract
|
|
634
|
-
},
|
|
637
|
+
resolvedAssetToEip3009Domain(pinnedDomain, chainId),
|
|
635
638
|
{
|
|
636
639
|
from: account.address,
|
|
637
640
|
to: payTo,
|