kawasekit 0.1.0-beta.4 → 0.1.0-beta.5

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.
Files changed (59) hide show
  1. package/dist/asset-domain-CpJuDkI2.d.cts +102 -0
  2. package/dist/asset-domain-CpJuDkI2.d.ts +102 -0
  3. package/dist/chunk-DYTONQW2.js +76 -0
  4. package/dist/chunk-DYTONQW2.js.map +1 -0
  5. package/dist/{chunk-Y6AJKMAL.js → chunk-E2EG72U2.js} +102 -176
  6. package/dist/chunk-E2EG72U2.js.map +1 -0
  7. package/dist/chunk-E47SIVFY.js +44 -0
  8. package/dist/chunk-E47SIVFY.js.map +1 -0
  9. package/dist/chunk-KT7XDT2T.js +209 -0
  10. package/dist/chunk-KT7XDT2T.js.map +1 -0
  11. package/dist/chunk-MTMJNYOD.js +125 -0
  12. package/dist/chunk-MTMJNYOD.js.map +1 -0
  13. package/dist/{chunk-NRGSI52C.js → chunk-PVUKX6IF.js} +6 -235
  14. package/dist/chunk-PVUKX6IF.js.map +1 -0
  15. package/dist/chunk-UQ7WJY6O.js +43 -0
  16. package/dist/chunk-UQ7WJY6O.js.map +1 -0
  17. package/dist/chunk-VPRR3TNA.js +204 -0
  18. package/dist/chunk-VPRR3TNA.js.map +1 -0
  19. package/dist/chunk-WMVJNPX2.js +41 -0
  20. package/dist/chunk-WMVJNPX2.js.map +1 -0
  21. package/dist/cli/index.cjs +1 -1
  22. package/dist/cli/index.js +11 -5
  23. package/dist/cli/index.js.map +1 -1
  24. package/dist/{index-CJfDUtpx.d.ts → index-BaAOB0xd.d.ts} +86 -83
  25. package/dist/{index-CGO7bOx5.d.cts → index-Z6AL1MR_.d.cts} +86 -83
  26. package/dist/index.cjs +416 -85
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +8 -62
  29. package/dist/index.d.ts +8 -62
  30. package/dist/index.js +10 -4
  31. package/dist/policy/index.cjs +419 -0
  32. package/dist/policy/index.cjs.map +1 -0
  33. package/dist/policy/index.d.cts +66 -0
  34. package/dist/policy/index.d.ts +66 -0
  35. package/dist/policy/index.js +7 -0
  36. package/dist/policy/index.js.map +1 -0
  37. package/dist/signer/index.cjs +360 -0
  38. package/dist/signer/index.cjs.map +1 -0
  39. package/dist/signer/index.d.cts +131 -0
  40. package/dist/signer/index.d.ts +131 -0
  41. package/dist/signer/index.js +9 -0
  42. package/dist/signer/index.js.map +1 -0
  43. package/dist/spending-policy-BnNp_y5d.d.cts +129 -0
  44. package/dist/spending-policy-DiZBTBeN.d.ts +129 -0
  45. package/dist/types-IEl-iOIx.d.cts +148 -0
  46. package/dist/types-IEl-iOIx.d.ts +148 -0
  47. package/dist/x402/hono/index.cjs.map +1 -1
  48. package/dist/x402/hono/index.js +4 -2
  49. package/dist/x402/hono/index.js.map +1 -1
  50. package/dist/x402/index.cjs +205 -73
  51. package/dist/x402/index.cjs.map +1 -1
  52. package/dist/x402/index.d.cts +3 -1
  53. package/dist/x402/index.d.ts +3 -1
  54. package/dist/x402/index.js +6 -3
  55. package/package.json +21 -1
  56. package/dist/chunk-DGWKPDDQ.js +0 -81
  57. package/dist/chunk-DGWKPDDQ.js.map +0 -1
  58. package/dist/chunk-NRGSI52C.js.map +0 -1
  59. package/dist/chunk-Y6AJKMAL.js.map +0 -1
@@ -0,0 +1,102 @@
1
+ import { Address } from 'viem';
2
+
3
+ /**
4
+ * Known-asset registry for {@link createX402PaymentSigner}'s
5
+ * `asset: { kind: "known", id }` discriminated-union branch.
6
+ *
7
+ * kawasekit only ships pinned EIP-712 domain definitions for assets it has
8
+ * verified empirically against the deployed contracts. Adding a new entry
9
+ * here requires citing the source-file + line reference for the contract
10
+ * that owns the `name` / `version` (so the next reviewer can spot-check the
11
+ * claim, the same discipline `docs/THREAT_MODEL.md` §0 demands of any ✅
12
+ * verdict that delegates to an out-of-scope component).
13
+ *
14
+ * @packageDocumentation
15
+ */
16
+
17
+ /** Known asset identifiers. New entries must update this union AND the table. */
18
+ type KnownAssetId = "jpyc-v2";
19
+ /** Fully-pinned EIP-712 domain for a known asset. */
20
+ interface KnownAssetDomain {
21
+ readonly id: KnownAssetId;
22
+ readonly name: string;
23
+ readonly version: string;
24
+ readonly verifyingContract: Address;
25
+ }
26
+ /**
27
+ * Look up a known asset's pinned EIP-712 domain by id.
28
+ *
29
+ * @returns The domain, or `undefined` if the id is not in the registry.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { getKnownAssetDomain } from "kawasekit";
34
+ *
35
+ * const jpyc = getKnownAssetDomain("jpyc-v2");
36
+ * if (jpyc === undefined) throw new Error("unreachable");
37
+ * console.log(jpyc.verifyingContract); // 0xE7C3D8C9a439feDe00D2600032D5dB0Be71C3c29
38
+ * ```
39
+ */
40
+ declare function getKnownAssetDomain(id: KnownAssetId): KnownAssetDomain | undefined;
41
+ /** List every known asset id (for diagnostics / error messages). */
42
+ declare function listKnownAssetIds(): readonly KnownAssetId[];
43
+
44
+ /**
45
+ * EIP-712 asset-domain resolution for x402 / EIP-3009 signing.
46
+ *
47
+ * Construction-time pinning of the EIP-712 domain (`name` / `version` /
48
+ * `verifyingContract`) a signer will use. The integrator declares an
49
+ * {@link X402AssetParam} — either a kawasekit-maintained `known` asset or a
50
+ * loud `unsafeOverride` — and {@link resolveAssetParam} resolves it to a pinned
51
+ * {@link ResolvedAsset}. The signer then trusts only this pinned domain and
52
+ * refuses to sign for a mismatched advertised asset (Threat 1.4: misadvertised
53
+ * EIP-712 domain).
54
+ *
55
+ * Token-domain concern, reused by both the x402 signer (`src/x402/client.ts`)
56
+ * and the M6 PolicyGatedSigner (`src/signer/`).
57
+ *
58
+ * @packageDocumentation
59
+ */
60
+
61
+ /** EIP-712 token domain `name` / `version` pair. */
62
+ interface X402TokenDomain {
63
+ readonly name: string;
64
+ readonly version: string;
65
+ }
66
+ /**
67
+ * Asset binding for {@link createX402PaymentSigner} and the M6 PolicyGatedSigner.
68
+ * Required, discriminated.
69
+ *
70
+ * **Default-on whitelist**: integrators MUST declare which asset they intend
71
+ * to sign for. The `known` branch references a kawasekit-maintained
72
+ * whitelist (see `src/tokens/known-assets.ts`); the `unsafeOverride` branch
73
+ * is the deliberate escape hatch for any other asset and is named loudly so
74
+ * it survives a code review. Either way, the signer pins the EIP-712 domain
75
+ * at construction time and refuses to sign if `paymentRequirements.asset`
76
+ * disagrees with the pinned `verifyingContract`.
77
+ *
78
+ * Closes Threat 1.4 (misadvertised EIP-712 domain): the server's advertised
79
+ * `extra.name` / `extra.version` and `asset` are all ignored for signing
80
+ * purposes — the signer trusts only what the integrator declared here.
81
+ */
82
+ type X402AssetParam = {
83
+ /** Use a kawasekit-maintained pinned EIP-712 domain. */
84
+ readonly kind: "known";
85
+ /** The asset id to pin. See {@link KnownAssetId} for the registry. */
86
+ readonly id: KnownAssetId;
87
+ } | {
88
+ /**
89
+ * Use a caller-supplied EIP-712 domain for an asset NOT on the
90
+ * kawasekit whitelist. The name is deliberately loud — pick this
91
+ * branch only when you have separately audited the contract and its
92
+ * `eip712Domain()` output.
93
+ */
94
+ readonly kind: "unsafeOverride";
95
+ readonly domain: {
96
+ readonly name: string;
97
+ readonly version: string;
98
+ readonly verifyingContract: Address;
99
+ };
100
+ };
101
+
102
+ export { type KnownAssetDomain as K, type X402AssetParam as X, type KnownAssetId as a, type X402TokenDomain as b, getKnownAssetDomain as g, listKnownAssetIds as l };
@@ -0,0 +1,102 @@
1
+ import { Address } from 'viem';
2
+
3
+ /**
4
+ * Known-asset registry for {@link createX402PaymentSigner}'s
5
+ * `asset: { kind: "known", id }` discriminated-union branch.
6
+ *
7
+ * kawasekit only ships pinned EIP-712 domain definitions for assets it has
8
+ * verified empirically against the deployed contracts. Adding a new entry
9
+ * here requires citing the source-file + line reference for the contract
10
+ * that owns the `name` / `version` (so the next reviewer can spot-check the
11
+ * claim, the same discipline `docs/THREAT_MODEL.md` §0 demands of any ✅
12
+ * verdict that delegates to an out-of-scope component).
13
+ *
14
+ * @packageDocumentation
15
+ */
16
+
17
+ /** Known asset identifiers. New entries must update this union AND the table. */
18
+ type KnownAssetId = "jpyc-v2";
19
+ /** Fully-pinned EIP-712 domain for a known asset. */
20
+ interface KnownAssetDomain {
21
+ readonly id: KnownAssetId;
22
+ readonly name: string;
23
+ readonly version: string;
24
+ readonly verifyingContract: Address;
25
+ }
26
+ /**
27
+ * Look up a known asset's pinned EIP-712 domain by id.
28
+ *
29
+ * @returns The domain, or `undefined` if the id is not in the registry.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { getKnownAssetDomain } from "kawasekit";
34
+ *
35
+ * const jpyc = getKnownAssetDomain("jpyc-v2");
36
+ * if (jpyc === undefined) throw new Error("unreachable");
37
+ * console.log(jpyc.verifyingContract); // 0xE7C3D8C9a439feDe00D2600032D5dB0Be71C3c29
38
+ * ```
39
+ */
40
+ declare function getKnownAssetDomain(id: KnownAssetId): KnownAssetDomain | undefined;
41
+ /** List every known asset id (for diagnostics / error messages). */
42
+ declare function listKnownAssetIds(): readonly KnownAssetId[];
43
+
44
+ /**
45
+ * EIP-712 asset-domain resolution for x402 / EIP-3009 signing.
46
+ *
47
+ * Construction-time pinning of the EIP-712 domain (`name` / `version` /
48
+ * `verifyingContract`) a signer will use. The integrator declares an
49
+ * {@link X402AssetParam} — either a kawasekit-maintained `known` asset or a
50
+ * loud `unsafeOverride` — and {@link resolveAssetParam} resolves it to a pinned
51
+ * {@link ResolvedAsset}. The signer then trusts only this pinned domain and
52
+ * refuses to sign for a mismatched advertised asset (Threat 1.4: misadvertised
53
+ * EIP-712 domain).
54
+ *
55
+ * Token-domain concern, reused by both the x402 signer (`src/x402/client.ts`)
56
+ * and the M6 PolicyGatedSigner (`src/signer/`).
57
+ *
58
+ * @packageDocumentation
59
+ */
60
+
61
+ /** EIP-712 token domain `name` / `version` pair. */
62
+ interface X402TokenDomain {
63
+ readonly name: string;
64
+ readonly version: string;
65
+ }
66
+ /**
67
+ * Asset binding for {@link createX402PaymentSigner} and the M6 PolicyGatedSigner.
68
+ * Required, discriminated.
69
+ *
70
+ * **Default-on whitelist**: integrators MUST declare which asset they intend
71
+ * to sign for. The `known` branch references a kawasekit-maintained
72
+ * whitelist (see `src/tokens/known-assets.ts`); the `unsafeOverride` branch
73
+ * is the deliberate escape hatch for any other asset and is named loudly so
74
+ * it survives a code review. Either way, the signer pins the EIP-712 domain
75
+ * at construction time and refuses to sign if `paymentRequirements.asset`
76
+ * disagrees with the pinned `verifyingContract`.
77
+ *
78
+ * Closes Threat 1.4 (misadvertised EIP-712 domain): the server's advertised
79
+ * `extra.name` / `extra.version` and `asset` are all ignored for signing
80
+ * purposes — the signer trusts only what the integrator declared here.
81
+ */
82
+ type X402AssetParam = {
83
+ /** Use a kawasekit-maintained pinned EIP-712 domain. */
84
+ readonly kind: "known";
85
+ /** The asset id to pin. See {@link KnownAssetId} for the registry. */
86
+ readonly id: KnownAssetId;
87
+ } | {
88
+ /**
89
+ * Use a caller-supplied EIP-712 domain for an asset NOT on the
90
+ * kawasekit whitelist. The name is deliberately loud — pick this
91
+ * branch only when you have separately audited the contract and its
92
+ * `eip712Domain()` output.
93
+ */
94
+ readonly kind: "unsafeOverride";
95
+ readonly domain: {
96
+ readonly name: string;
97
+ readonly version: string;
98
+ readonly verifyingContract: Address;
99
+ };
100
+ };
101
+
102
+ export { type KnownAssetDomain as K, type X402AssetParam as X, type KnownAssetId as a, type X402TokenDomain as b, getKnownAssetDomain as g, listKnownAssetIds as l };
@@ -0,0 +1,76 @@
1
+ import { PolicyGatedSignerConfigError, resolveAssetParam, signTransferWithAuthorization } from './chunk-VPRR3TNA.js';
2
+ import { evaluateSpendingPolicy } from './chunk-MTMJNYOD.js';
3
+ import { getAddress } from 'viem';
4
+
5
+ function createLocalPolicyGatedSigner(params) {
6
+ if (params.acknowledgeAdvisory !== true) {
7
+ throw new PolicyGatedSignerConfigError(
8
+ "acknowledgeAdvisory",
9
+ "a local signer is advisory (a key-holder can bypass its policy); pass `acknowledgeAdvisory: true` to construct one consciously, or use a cryptographic adapter for bounded/regulated flows"
10
+ );
11
+ }
12
+ const { account, policy, spendState } = params;
13
+ const pinned = resolveAssetParam(params.asset);
14
+ const from = getAddress(account.address);
15
+ return {
16
+ enforcement: "advisory",
17
+ from,
18
+ async sign(intent) {
19
+ if (getAddress(intent.from) !== from) {
20
+ return {
21
+ ok: false,
22
+ rejection: {
23
+ reason: "from_mismatch",
24
+ detail: `intent.from ${getAddress(intent.from)} does not equal signer.from ${from}`
25
+ }
26
+ };
27
+ }
28
+ if (getAddress(intent.token) !== pinned.verifyingContract) {
29
+ return {
30
+ ok: false,
31
+ rejection: {
32
+ reason: "token_not_allowed",
33
+ detail: `intent.token ${getAddress(intent.token)} does not equal the signer's pinned verifyingContract ${pinned.verifyingContract}`
34
+ }
35
+ };
36
+ }
37
+ const state = await spendState?.() ?? { spentPerToken: [] };
38
+ const nowSeconds = BigInt(Math.floor(Date.now() / 1e3));
39
+ const decision = evaluateSpendingPolicy(policy, intent, state, nowSeconds);
40
+ if (!decision.ok) {
41
+ return { ok: false, rejection: decision.rejection };
42
+ }
43
+ const signed = await signTransferWithAuthorization(
44
+ account,
45
+ {
46
+ name: pinned.name,
47
+ version: pinned.version,
48
+ chainId: intent.chainId,
49
+ verifyingContract: pinned.verifyingContract
50
+ },
51
+ {
52
+ from,
53
+ to: intent.to,
54
+ value: intent.value,
55
+ validAfter: intent.validAfter,
56
+ validBefore: intent.validBefore,
57
+ nonce: intent.nonce
58
+ }
59
+ );
60
+ return { ok: true, signature: signed.signature, intent };
61
+ },
62
+ describe() {
63
+ return {
64
+ enforcement: "advisory",
65
+ from,
66
+ policyId: policy.session.id,
67
+ notAfter: policy.session.notAfter,
68
+ revoked: policy.revoked
69
+ };
70
+ }
71
+ };
72
+ }
73
+
74
+ export { createLocalPolicyGatedSigner };
75
+ //# sourceMappingURL=chunk-DYTONQW2.js.map
76
+ //# sourceMappingURL=chunk-DYTONQW2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/signer/local.ts"],"names":[],"mappings":";;;;AAgEO,SAAS,6BACf,MAAA,EACgC;AAChC,EAAA,IAAI,MAAA,CAAO,wBAAwB,IAAA,EAAM;AACxC,IAAA,MAAM,IAAI,4BAAA;AAAA,MACT,qBAAA;AAAA,MACA;AAAA,KACD;AAAA,EACD;AAEA,EAAA,MAAM,EAAE,OAAA,EAAS,MAAA,EAAQ,UAAA,EAAW,GAAI,MAAA;AACxC,EAAA,MAAM,MAAA,GAAS,iBAAA,CAAkB,MAAA,CAAO,KAAK,CAAA;AAC7C,EAAA,MAAM,IAAA,GAAO,UAAA,CAAW,OAAA,CAAQ,OAAO,CAAA;AAEvC,EAAA,OAAO;AAAA,IACN,WAAA,EAAa,UAAA;AAAA,IACb,IAAA;AAAA,IACA,MAAM,KAAK,MAAA,EAA4C;AACtD,MAAA,IAAI,UAAA,CAAW,MAAA,CAAO,IAAI,CAAA,KAAM,IAAA,EAAM;AACrC,QAAA,OAAO;AAAA,UACN,EAAA,EAAI,KAAA;AAAA,UACJ,SAAA,EAAW;AAAA,YACV,MAAA,EAAQ,eAAA;AAAA,YACR,QAAQ,CAAA,YAAA,EAAe,UAAA,CAAW,OAAO,IAAI,CAAC,+BAA+B,IAAI,CAAA;AAAA;AAClF,SACD;AAAA,MACD;AACA,MAAA,IAAI,UAAA,CAAW,MAAA,CAAO,KAAK,CAAA,KAAM,OAAO,iBAAA,EAAmB;AAC1D,QAAA,OAAO;AAAA,UACN,EAAA,EAAI,KAAA;AAAA,UACJ,SAAA,EAAW;AAAA,YACV,MAAA,EAAQ,mBAAA;AAAA,YACR,MAAA,EAAQ,gBAAgB,UAAA,CAAW,MAAA,CAAO,KAAK,CAAC,CAAA,sDAAA,EAAyD,OAAO,iBAAiB,CAAA;AAAA;AAClI,SACD;AAAA,MACD;AAEA,MAAA,MAAM,QAAqB,MAAM,UAAA,QAAmB,EAAE,aAAA,EAAe,EAAC,EAAE;AACxE,MAAA,MAAM,UAAA,GAAa,OAAO,IAAA,CAAK,KAAA,CAAM,KAAK,GAAA,EAAI,GAAI,GAAI,CAAC,CAAA;AACvD,MAAA,MAAM,QAAA,GAAW,sBAAA,CAAuB,MAAA,EAAQ,MAAA,EAAQ,OAAO,UAAU,CAAA;AACzE,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AACjB,QAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,SAAA,EAAW,SAAS,SAAA,EAAU;AAAA,MACnD;AAEA,MAAA,MAAM,SAAS,MAAM,6BAAA;AAAA,QACpB,OAAA;AAAA,QACA;AAAA,UACC,MAAM,MAAA,CAAO,IAAA;AAAA,UACb,SAAS,MAAA,CAAO,OAAA;AAAA,UAChB,SAAS,MAAA,CAAO,OAAA;AAAA,UAChB,mBAAmB,MAAA,CAAO;AAAA,SAC3B;AAAA,QACA;AAAA,UACC,IAAA;AAAA,UACA,IAAI,MAAA,CAAO,EAAA;AAAA,UACX,OAAO,MAAA,CAAO,KAAA;AAAA,UACd,YAAY,MAAA,CAAO,UAAA;AAAA,UACnB,aAAa,MAAA,CAAO,WAAA;AAAA,UACpB,OAAO,MAAA,CAAO;AAAA;AACf,OACD;AACA,MAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,SAAA,EAAW,MAAA,CAAO,WAAW,MAAA,EAAO;AAAA,IACxD,CAAA;AAAA,IACA,QAAA,GAA8B;AAC7B,MAAA,OAAO;AAAA,QACN,WAAA,EAAa,UAAA;AAAA,QACb,IAAA;AAAA,QACA,QAAA,EAAU,OAAO,OAAA,CAAQ,EAAA;AAAA,QACzB,QAAA,EAAU,OAAO,OAAA,CAAQ,QAAA;AAAA,QACzB,SAAS,MAAA,CAAO;AAAA,OACjB;AAAA,IACD;AAAA,GACD;AACD","file":"chunk-DYTONQW2.js","sourcesContent":["/**\n * The `local` PolicyGatedSigner adapter — `enforcement: \"advisory\"`.\n *\n * Wraps a viem {@link Account} + a {@link SpendingPolicy} + a pinned EIP-712\n * domain. `sign(intent)` evaluates the policy SDK-side and, on pass, produces a\n * real EIP-3009 authorization via {@link signTransferWithAuthorization}. It is\n * **advisory** because the wrapped key can still sign anything elsewhere — the\n * gate is only reached if the caller chooses to call *this* `sign()`. Use it for\n * dev, the A1 cross-language fallback, and any flow that is explicitly not\n * bounded/regulated; the type-gate (`requireNonBypassable`) keeps it out of\n * flows that require non-bypassable enforcement.\n *\n * @packageDocumentation\n */\n\nimport type { Account } from \"viem\";\nimport { getAddress } from \"viem\";\nimport type { SpendingPolicy, SpendState } from \"../policy/spending-policy\";\nimport { evaluateSpendingPolicy } from \"../policy/spending-policy\";\nimport type { X402AssetParam } from \"../tokens/asset-domain\";\nimport { resolveAssetParam } from \"../tokens/asset-domain\";\nimport { signTransferWithAuthorization } from \"../tokens/eip3009\";\nimport { PolicyGatedSignerConfigError } from \"./errors\";\nimport type { PaymentIntent, PolicyGatedSigner, SignerDescription, SignResult } from \"./types\";\n\n/** Parameters for {@link createLocalPolicyGatedSigner}. */\nexport interface CreateLocalPolicyGatedSignerParams {\n\t/** EOA / LocalAccount that signs the EIP-3009 authorization. */\n\treadonly account: Account;\n\t/** The spending policy this signer enforces (SDK-side, advisory). */\n\treadonly policy: SpendingPolicy;\n\t/** Asset binding — pins the EIP-712 domain `name`/`version`/`verifyingContract`. */\n\treadonly asset: X402AssetParam;\n\t/**\n\t * Required literal acknowledgement that this signer is **advisory** (a\n\t * key-holder can bypass its policy). Omitting it is a compile error (TS) and\n\t * a construction-time throw (JS) — so constructing an advisory signer is a\n\t * conscious, greppable act. For bounded/regulated flows use a cryptographic\n\t * adapter instead.\n\t */\n\treadonly acknowledgeAdvisory: true;\n\t/**\n\t * Optional cumulative-spend view (read-only) the adapter evaluates\n\t * `cumulativeCap` against. `local` does not own an authoritative ledger; the\n\t * caller folds a successful spend back in (e.g. via `mergeSpendState`) before\n\t * the next call. Default: empty.\n\t */\n\treadonly spendState?: () => SpendState | Promise<SpendState>;\n}\n\n/**\n * Construct a `local` (advisory) PolicyGatedSigner.\n *\n * @example\n * ```ts\n * const signer = createLocalPolicyGatedSigner({\n * account,\n * policy: createSpendingPolicy({ session: { id, notAfter }, perToken: [{ token: JPYC, maxPerSign: 1_000n }] }),\n * asset: { kind: \"known\", id: \"jpyc-v2\" },\n * acknowledgeAdvisory: true,\n * });\n * const result = await signer.sign(intent);\n * ```\n */\nexport function createLocalPolicyGatedSigner(\n\tparams: CreateLocalPolicyGatedSignerParams,\n): PolicyGatedSigner<\"advisory\"> {\n\tif (params.acknowledgeAdvisory !== true) {\n\t\tthrow new PolicyGatedSignerConfigError(\n\t\t\t\"acknowledgeAdvisory\",\n\t\t\t\"a local signer is advisory (a key-holder can bypass its policy); pass `acknowledgeAdvisory: true` to construct one consciously, or use a cryptographic adapter for bounded/regulated flows\",\n\t\t);\n\t}\n\n\tconst { account, policy, spendState } = params;\n\tconst pinned = resolveAssetParam(params.asset);\n\tconst from = getAddress(account.address);\n\n\treturn {\n\t\tenforcement: \"advisory\",\n\t\tfrom,\n\t\tasync sign(intent: PaymentIntent): Promise<SignResult> {\n\t\t\tif (getAddress(intent.from) !== from) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\trejection: {\n\t\t\t\t\t\treason: \"from_mismatch\",\n\t\t\t\t\t\tdetail: `intent.from ${getAddress(intent.from)} does not equal signer.from ${from}`,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (getAddress(intent.token) !== pinned.verifyingContract) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\trejection: {\n\t\t\t\t\t\treason: \"token_not_allowed\",\n\t\t\t\t\t\tdetail: `intent.token ${getAddress(intent.token)} does not equal the signer's pinned verifyingContract ${pinned.verifyingContract}`,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst state: SpendState = (await spendState?.()) ?? { spentPerToken: [] };\n\t\t\tconst nowSeconds = BigInt(Math.floor(Date.now() / 1000));\n\t\t\tconst decision = evaluateSpendingPolicy(policy, intent, state, nowSeconds);\n\t\t\tif (!decision.ok) {\n\t\t\t\treturn { ok: false, rejection: decision.rejection };\n\t\t\t}\n\n\t\t\tconst signed = await signTransferWithAuthorization(\n\t\t\t\taccount,\n\t\t\t\t{\n\t\t\t\t\tname: pinned.name,\n\t\t\t\t\tversion: pinned.version,\n\t\t\t\t\tchainId: intent.chainId,\n\t\t\t\t\tverifyingContract: pinned.verifyingContract,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfrom,\n\t\t\t\t\tto: intent.to,\n\t\t\t\t\tvalue: intent.value,\n\t\t\t\t\tvalidAfter: intent.validAfter,\n\t\t\t\t\tvalidBefore: intent.validBefore,\n\t\t\t\t\tnonce: intent.nonce,\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn { ok: true, signature: signed.signature, intent };\n\t\t},\n\t\tdescribe(): SignerDescription {\n\t\t\treturn {\n\t\t\t\tenforcement: \"advisory\",\n\t\t\t\tfrom,\n\t\t\t\tpolicyId: policy.session.id,\n\t\t\t\tnotAfter: policy.session.notAfter,\n\t\t\t\trevoked: policy.revoked,\n\t\t\t};\n\t\t},\n\t};\n}\n"]}
@@ -1,132 +1,12 @@
1
- import { JPYC_EIP712_DOMAIN_HINT, JPYC_V2_ADDRESS, X402InvalidPayloadError, X402_HEADER_PAYMENT_SIGNATURE, encodePaymentSignatureHeader, X402_HEADER_IDEMPOTENCY_KEY, X402_HEADER_PAYMENT_RESPONSE, decodePaymentResponseHeader, X402InvalidConfigError, X402_HEADER_PAYMENT_REQUIRED, decodePaymentRequiredHeader, jpycAbi } from './chunk-NRGSI52C.js';
1
+ import { X402_HEADER_PAYMENT_SIGNATURE, encodePaymentSignatureHeader, X402_HEADER_IDEMPOTENCY_KEY, X402_HEADER_PAYMENT_RESPONSE, decodePaymentResponseHeader, X402_HEADER_PAYMENT_REQUIRED, decodePaymentRequiredHeader } from './chunk-PVUKX6IF.js';
2
+ import { invokeHookSafely } from './chunk-LEHWRDVS.js';
2
3
  import { X402_VERSION, chainIdToX402Network, x402NetworkToChainId } from './chunk-QHUCU5YX.js';
4
+ import { resolveAssetParam, authorizationDeadlineFromNow, deriveAuthorizationNonce, generateAuthorizationNonce, signTransferWithAuthorization, assertNonBypassable } from './chunk-VPRR3TNA.js';
5
+ import { X402InvalidPayloadError, X402PolicyRejectedError } from './chunk-WMVJNPX2.js';
6
+ import { jpycAbi, JPYC_V2_ADDRESS, JPYC_EIP712_DOMAIN_HINT } from './chunk-KT7XDT2T.js';
3
7
  import { getChain, isSupportedChainId } from './chunk-SOTYGX67.js';
4
- import { invokeHookSafely } from './chunk-LEHWRDVS.js';
5
- import { getAddress, keccak256, stringToHex, parseSignature, isAddress, recoverTypedDataAddress } from 'viem';
8
+ import { getAddress, recoverTypedDataAddress, parseSignature, isAddress } from 'viem';
6
9
 
7
- var transferWithAuthorizationTypes = {
8
- TransferWithAuthorization: [
9
- { name: "from", type: "address" },
10
- { name: "to", type: "address" },
11
- { name: "value", type: "uint256" },
12
- { name: "validAfter", type: "uint256" },
13
- { name: "validBefore", type: "uint256" },
14
- { name: "nonce", type: "bytes32" }
15
- ]
16
- };
17
- var receiveWithAuthorizationTypes = {
18
- ReceiveWithAuthorization: [
19
- { name: "from", type: "address" },
20
- { name: "to", type: "address" },
21
- { name: "value", type: "uint256" },
22
- { name: "validAfter", type: "uint256" },
23
- { name: "validBefore", type: "uint256" },
24
- { name: "nonce", type: "bytes32" }
25
- ]
26
- };
27
- var cancelAuthorizationTypes = {
28
- CancelAuthorization: [
29
- { name: "authorizer", type: "address" },
30
- { name: "nonce", type: "bytes32" }
31
- ]
32
- };
33
- function generateAuthorizationNonce() {
34
- const bytes = new Uint8Array(32);
35
- crypto.getRandomValues(bytes);
36
- return `0x${Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("")}`;
37
- }
38
- var EIP3009_NONCE_DOMAIN_TAG = "kawasekit/eip3009-nonce/1";
39
- function deriveAuthorizationNonce(input, scope) {
40
- if (input.idempotencyKey === "") {
41
- throw new Error("deriveAuthorizationNonce: idempotencyKey must be a non-empty string");
42
- }
43
- const preimage = JSON.stringify([
44
- EIP3009_NONCE_DOMAIN_TAG,
45
- input.idempotencyKey,
46
- getAddress(scope.from),
47
- getAddress(scope.verifyingContract),
48
- scope.chainId
49
- ]);
50
- return keccak256(stringToHex(preimage));
51
- }
52
- function authorizationDeadlineFromNow(seconds, nowSec) {
53
- const now = nowSec ?? BigInt(Math.floor(Date.now() / 1e3));
54
- return now + BigInt(seconds);
55
- }
56
- function requireSignTypedData(account) {
57
- if (!account.signTypedData) {
58
- throw new Error(
59
- `Account ${account.address} cannot sign typed data \u2014 pass a LocalAccount or a JsonRpcAccount bound to a WalletClient.`
60
- );
61
- }
62
- return account.signTypedData.bind(account);
63
- }
64
- function assertSignerMatches(account, expectedFrom, role) {
65
- if (getAddress(account.address) !== getAddress(expectedFrom)) {
66
- throw new Error(
67
- `EIP-3009 ${role} signature must come from \`${role === "cancel" ? "authorizer" : "from"}\`: account is ${account.address}, message says ${expectedFrom}.`
68
- );
69
- }
70
- }
71
- async function signTransferWithAuthorization(account, domain, message) {
72
- assertSignerMatches(account, message.from, "transfer");
73
- const sign = requireSignTypedData(account);
74
- const signature = await sign({
75
- domain,
76
- types: transferWithAuthorizationTypes,
77
- primaryType: "TransferWithAuthorization",
78
- message
79
- });
80
- return splitAuthorization(signature, domain, message);
81
- }
82
- async function signReceiveWithAuthorization(account, domain, message) {
83
- assertSignerMatches(account, message.from, "receive");
84
- const sign = requireSignTypedData(account);
85
- const signature = await sign({
86
- domain,
87
- types: receiveWithAuthorizationTypes,
88
- primaryType: "ReceiveWithAuthorization",
89
- message
90
- });
91
- return splitAuthorization(signature, domain, message);
92
- }
93
- async function signCancelAuthorization(account, domain, message) {
94
- assertSignerMatches(account, message.authorizer, "cancel");
95
- const sign = requireSignTypedData(account);
96
- const signature = await sign({
97
- domain,
98
- types: cancelAuthorizationTypes,
99
- primaryType: "CancelAuthorization",
100
- message
101
- });
102
- return splitAuthorization(signature, domain, message);
103
- }
104
- function splitAuthorization(signature, domain, message) {
105
- const parsed = parseSignature(signature);
106
- const v = parsed.v !== void 0 ? Number(parsed.v) : (parsed.yParity ?? 0) + 27;
107
- return {
108
- signature,
109
- v,
110
- r: parsed.r,
111
- s: parsed.s,
112
- domain,
113
- message
114
- };
115
- }
116
- var KNOWN_ASSETS = [
117
- {
118
- id: "jpyc-v2",
119
- name: JPYC_EIP712_DOMAIN_HINT.name,
120
- version: JPYC_EIP712_DOMAIN_HINT.version,
121
- verifyingContract: getAddress(JPYC_V2_ADDRESS)
122
- }
123
- ];
124
- function getKnownAssetDomain(id) {
125
- return KNOWN_ASSETS.find((entry) => entry.id === id);
126
- }
127
- function listKnownAssetIds() {
128
- return KNOWN_ASSETS.map((entry) => entry.id);
129
- }
130
10
  var X402_DEFAULT_AUTHORIZATION_LIFETIME_SECONDS = 300;
131
11
  var UINT256_MAX = (1n << 256n) - 1n;
132
12
  var UINT256_DECIMAL = /^(0|[1-9][0-9]*)$/;
@@ -155,53 +35,6 @@ function assertAddress(value, field) {
155
35
  }
156
36
  return value;
157
37
  }
158
- function resolveAssetParam(asset) {
159
- if (asset.kind === "known") {
160
- const entry = getKnownAssetDomain(asset.id);
161
- if (entry === void 0) {
162
- throw new X402InvalidConfigError(
163
- "asset.id",
164
- `unknown asset id ${JSON.stringify(asset.id)}. Supported: ${listKnownAssetIds().map((id) => JSON.stringify(id)).join(", ")}.`
165
- );
166
- }
167
- return {
168
- name: entry.name,
169
- version: entry.version,
170
- verifyingContract: entry.verifyingContract
171
- };
172
- }
173
- if (asset.kind === "unsafeOverride") {
174
- const { domain } = asset;
175
- if (typeof domain.name !== "string" || domain.name === "") {
176
- throw new X402InvalidConfigError(
177
- "asset.domain.name",
178
- "`unsafeOverride.domain.name` must be a non-empty string"
179
- );
180
- }
181
- if (typeof domain.version !== "string" || domain.version === "") {
182
- throw new X402InvalidConfigError(
183
- "asset.domain.version",
184
- "`unsafeOverride.domain.version` must be a non-empty string"
185
- );
186
- }
187
- if (!isAddress(domain.verifyingContract, { strict: false })) {
188
- throw new X402InvalidConfigError(
189
- "asset.domain.verifyingContract",
190
- `\`unsafeOverride.domain.verifyingContract\` must be a valid address, got ${JSON.stringify(domain.verifyingContract)}`
191
- );
192
- }
193
- return {
194
- name: domain.name,
195
- version: domain.version,
196
- verifyingContract: getAddress(domain.verifyingContract)
197
- };
198
- }
199
- const exhaustive = asset;
200
- throw new X402InvalidConfigError(
201
- "asset.kind",
202
- `unsupported kind ${JSON.stringify(exhaustive.kind)}. Expected "known" or "unsafeOverride".`
203
- );
204
- }
205
38
  function validateRequirements(requirements) {
206
39
  if (requirements.scheme !== "exact") {
207
40
  throw new X402InvalidPayloadError(
@@ -231,6 +64,9 @@ function validateRequirements(requirements) {
231
64
  return { chainId, value, asset, payTo };
232
65
  }
233
66
  function createX402PaymentSigner(params) {
67
+ if (params.signer !== void 0) {
68
+ return createSignerBackedX402PaymentSigner(params);
69
+ }
234
70
  const { account, network } = params;
235
71
  const defaultLifetimeSeconds = params.defaultLifetimeSeconds ?? X402_DEFAULT_AUTHORIZATION_LIFETIME_SECONDS;
236
72
  if (defaultLifetimeSeconds <= 0) {
@@ -336,6 +172,96 @@ function createX402PaymentSigner(params) {
336
172
  }
337
173
  };
338
174
  }
175
+ function createSignerBackedX402PaymentSigner(params) {
176
+ const { signer, network } = params;
177
+ const defaultLifetimeSeconds = params.defaultLifetimeSeconds ?? X402_DEFAULT_AUTHORIZATION_LIFETIME_SECONDS;
178
+ if (defaultLifetimeSeconds <= 0) {
179
+ throw new X402InvalidPayloadError(
180
+ "X402PaymentSignerConfig",
181
+ `\`defaultLifetimeSeconds\` must be positive, got ${defaultLifetimeSeconds}`
182
+ );
183
+ }
184
+ if (params.requireEnforcement !== void 0) {
185
+ assertNonBypassable(signer);
186
+ }
187
+ const pinnedDomain = resolveAssetParam(params.asset);
188
+ const from = signer.from;
189
+ return {
190
+ address: from,
191
+ async sign(signParams) {
192
+ const { paymentRequirements } = signParams;
193
+ const { chainId, value, asset, payTo } = validateRequirements(paymentRequirements);
194
+ const chain = getChain(chainId);
195
+ if (network === "mainnet" && chain.isTestnet) {
196
+ throw new X402InvalidPayloadError(
197
+ "PaymentRequirements",
198
+ `signer was configured for network="mainnet" but requirements.network="${paymentRequirements.network}" (chainId ${chainId}) is a testnet`
199
+ );
200
+ }
201
+ if (network === "testnet" && !chain.isTestnet) {
202
+ throw new X402InvalidPayloadError(
203
+ "PaymentRequirements",
204
+ `signer was configured for network="testnet" but requirements.network="${paymentRequirements.network}" (chainId ${chainId}) is a mainnet \u2014 refusing to sign payment for real funds`
205
+ );
206
+ }
207
+ if (getAddress(asset) !== pinnedDomain.verifyingContract) {
208
+ throw new X402InvalidPayloadError(
209
+ "PaymentRequirements",
210
+ `requirements.asset (${getAddress(asset)}) does not match the signer's pinned verifyingContract (${pinnedDomain.verifyingContract}) \u2014 refusing to sign for an asset the signer was not configured to handle`
211
+ );
212
+ }
213
+ const lifetime = Math.min(defaultLifetimeSeconds, paymentRequirements.maxTimeoutSeconds);
214
+ const validAfter = signParams.validAfter ?? 0n;
215
+ const validBefore = signParams.validBefore ?? authorizationDeadlineFromNow(lifetime);
216
+ if (validBefore <= validAfter) {
217
+ throw new X402InvalidPayloadError(
218
+ "PaymentRequirements",
219
+ `\`validBefore\` (${validBefore}) must be greater than \`validAfter\` (${validAfter})`
220
+ );
221
+ }
222
+ const nonce = signParams.idempotencyKey !== void 0 ? deriveAuthorizationNonce(
223
+ { idempotencyKey: signParams.idempotencyKey },
224
+ { from, verifyingContract: pinnedDomain.verifyingContract, chainId }
225
+ ) : generateAuthorizationNonce();
226
+ const intent = {
227
+ token: pinnedDomain.verifyingContract,
228
+ chainId,
229
+ from,
230
+ to: payTo,
231
+ value,
232
+ validAfter,
233
+ validBefore,
234
+ nonce
235
+ };
236
+ const signResult = await signer.sign(intent);
237
+ if (!signResult.ok) {
238
+ throw new X402PolicyRejectedError(signResult.rejection);
239
+ }
240
+ const payload = {
241
+ signature: signResult.signature,
242
+ authorization: {
243
+ from,
244
+ to: payTo,
245
+ value: value.toString(),
246
+ validAfter: validAfter.toString(),
247
+ validBefore: validBefore.toString(),
248
+ nonce
249
+ }
250
+ };
251
+ const result = signParams.resource ? {
252
+ x402Version: X402_VERSION,
253
+ resource: signParams.resource,
254
+ accepted: paymentRequirements,
255
+ payload: { ...payload }
256
+ } : {
257
+ x402Version: X402_VERSION,
258
+ accepted: paymentRequirements,
259
+ payload: { ...payload }
260
+ };
261
+ return result;
262
+ }
263
+ };
264
+ }
339
265
  var X402_FACILITATOR_ERROR_CODES = {
340
266
  insufficient_funds: "insufficient_funds",
341
267
  invalid_exact_evm_payload_authorization_valid_after: "invalid_exact_evm_payload_authorization_valid_after",
@@ -958,6 +884,6 @@ function wrapFetch(params) {
958
884
  };
959
885
  }
960
886
 
961
- export { X402_DEFAULT_AUTHORIZATION_LIFETIME_SECONDS, X402_FACILITATOR_ERROR_CODES, authorizationDeadlineFromNow, createCoinbaseFacilitator, createHttpFacilitator, createSelfFacilitator, createX402PaymentSigner, deriveAuthorizationNonce, deriveReceiptTimeoutMs, generateAuthorizationNonce, getKnownAssetDomain, listKnownAssetIds, signCancelAuthorization, signReceiveWithAuthorization, signTransferWithAuthorization, wrapFetch };
962
- //# sourceMappingURL=chunk-Y6AJKMAL.js.map
963
- //# sourceMappingURL=chunk-Y6AJKMAL.js.map
887
+ export { X402_DEFAULT_AUTHORIZATION_LIFETIME_SECONDS, X402_FACILITATOR_ERROR_CODES, createCoinbaseFacilitator, createHttpFacilitator, createSelfFacilitator, createX402PaymentSigner, deriveReceiptTimeoutMs, wrapFetch };
888
+ //# sourceMappingURL=chunk-E2EG72U2.js.map
889
+ //# sourceMappingURL=chunk-E2EG72U2.js.map