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
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/signer/errors.ts","../src/signer/gate.ts","../src/tokens/known-assets.ts","../src/tokens/eip3009.ts","../src/tokens/asset-domain.ts"],"names":["getAddress"],"mappings":"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","file":"chunk-VPRR3TNA.js","sourcesContent":["/**\n * PolicyGatedSigner error types.\n *\n * @packageDocumentation\n */\n\n/**\n * Thrown for a construction-time / configuration error in a PolicyGatedSigner\n * adapter — e.g. a `local` signer constructed without the required\n * `acknowledgeAdvisory: true`, or a non-bypassable signer asserted on an\n * advisory one (`assertNonBypassable`). Policy *denials* are NOT errors — they\n * are returned as a typed {@link PolicyRejection} in {@link SignResult}.\n *\n * @example\n * ```ts\n * import { createLocalPolicyGatedSigner, PolicyGatedSignerConfigError } from \"kawasekit/signer\";\n *\n * try {\n * // @ts-expect-error — acknowledgeAdvisory is required\n * createLocalPolicyGatedSigner({ account, policy, asset });\n * } catch (error) {\n * if (error instanceof PolicyGatedSignerConfigError) {\n * console.error(`${error.field}: ${error.reason}`);\n * }\n * }\n * ```\n */\nexport class PolicyGatedSignerConfigError extends Error {\n\t/** The offending config field. */\n\treadonly field: string;\n\t/** Short machine-readable reason. */\n\treadonly reason: string;\n\n\tconstructor(field: string, reason: string, options?: { cause?: unknown }) {\n\t\tsuper(`Invalid PolicyGatedSigner config (${field}): ${reason}`, options);\n\t\tthis.name = \"PolicyGatedSignerConfigError\";\n\t\tthis.field = field;\n\t\tthis.reason = reason;\n\t}\n}\n","/**\n * The enforcement-level type-gate — the compile-time (and runtime) mechanism\n * that prevents an advisory signer from being substituted for an enforcing one.\n *\n * @packageDocumentation\n */\n\nimport { PolicyGatedSignerConfigError } from \"./errors\";\nimport type { NonBypassableEnforcement, PolicyGatedSigner } from \"./types\";\n\n/**\n * Compile-time gate: accepts only a non-bypassable signer\n * (`cryptographic` | `hardware`). Passing an `advisory` (or `integrator`) signer\n * is a **compile error**, because `PolicyGatedSigner<\"advisory\">` is not\n * assignable to `PolicyGatedSigner<NonBypassableEnforcement>` (covariant `E`).\n *\n * Use it at the boundary of a bounded/regulated flow so wiring an advisory\n * signer into it fails the build, not silently at runtime.\n *\n * @example\n * ```ts\n * function payBounded(signer: PolicyGatedSigner<NonBypassableEnforcement>) { ... }\n *\n * requireNonBypassable(mpc2pSigner); // ✓ ok — cryptographic\n * // requireNonBypassable(localSigner); // ✗ compile error — advisory\n * ```\n */\nexport function requireNonBypassable<E extends NonBypassableEnforcement>(\n\tsigner: PolicyGatedSigner<E>,\n): PolicyGatedSigner<E> {\n\treturn signer;\n}\n\n/**\n * Runtime mirror of {@link requireNonBypassable}, for plain-JS call sites and as\n * defense-in-depth. Throws {@link PolicyGatedSignerConfigError} if the signer is\n * advisory/integrator (i.e. bypassable). On success, narrows the signer type to\n * {@link NonBypassableEnforcement}.\n */\nexport function assertNonBypassable(\n\tsigner: PolicyGatedSigner,\n): asserts signer is PolicyGatedSigner<NonBypassableEnforcement> {\n\tif (signer.enforcement === \"advisory\" || signer.enforcement === \"integrator\") {\n\t\tthrow new PolicyGatedSignerConfigError(\n\t\t\t\"enforcement\",\n\t\t\t`expected a non-bypassable signer (cryptographic | hardware), got \"${signer.enforcement}\" — an ${signer.enforcement} signer's policy can be bypassed by a key-holder`,\n\t\t);\n\t}\n}\n","/**\n * Known-asset registry for {@link createX402PaymentSigner}'s\n * `asset: { kind: \"known\", id }` discriminated-union branch.\n *\n * kawasekit only ships pinned EIP-712 domain definitions for assets it has\n * verified empirically against the deployed contracts. Adding a new entry\n * here requires citing the source-file + line reference for the contract\n * that owns the `name` / `version` (so the next reviewer can spot-check the\n * claim, the same discipline `docs/THREAT_MODEL.md` §0 demands of any ✅\n * verdict that delegates to an out-of-scope component).\n *\n * @packageDocumentation\n */\n\nimport type { Address } from \"viem\";\nimport { getAddress } from \"viem\";\nimport { JPYC_EIP712_DOMAIN_HINT, JPYC_V2_ADDRESS } from \"./jpyc\";\n\n/** Known asset identifiers. New entries must update this union AND the table. */\nexport type KnownAssetId = \"jpyc-v2\";\n\n/** Fully-pinned EIP-712 domain for a known asset. */\nexport interface KnownAssetDomain {\n\treadonly id: KnownAssetId;\n\treadonly name: string;\n\treadonly version: string;\n\treadonly verifyingContract: Address;\n}\n\n/**\n * Canonical table. Lookups go through {@link getKnownAssetDomain}, which\n * returns a frozen copy so callers cannot mutate the registry.\n *\n * `verifyingContract` is the multi-chain canonical address — JPYC v2 is the\n * same address on Ethereum / Polygon (mainnet + Amoy) / Avalanche. The\n * signer cross-checks `requirements.asset` against this value at sign time,\n * so a server advertising a different `asset` is rejected before any\n * signature is produced.\n *\n * JPYC v2 domain: `name = \"JPY Coin\"`, `version = \"1\"`. Source of truth is\n * the deployed contract's `eip712Domain()` view — verified empirically and\n * also cached in `src/tokens/jpyc.ts:JPYC_EIP712_DOMAIN_HINT`.\n */\nconst KNOWN_ASSETS: ReadonlyArray<KnownAssetDomain> = [\n\t{\n\t\tid: \"jpyc-v2\",\n\t\tname: JPYC_EIP712_DOMAIN_HINT.name,\n\t\tversion: JPYC_EIP712_DOMAIN_HINT.version,\n\t\tverifyingContract: getAddress(JPYC_V2_ADDRESS),\n\t},\n];\n\n/**\n * Look up a known asset's pinned EIP-712 domain by id.\n *\n * @returns The domain, or `undefined` if the id is not in the registry.\n *\n * @example\n * ```ts\n * import { getKnownAssetDomain } from \"kawasekit\";\n *\n * const jpyc = getKnownAssetDomain(\"jpyc-v2\");\n * if (jpyc === undefined) throw new Error(\"unreachable\");\n * console.log(jpyc.verifyingContract); // 0xE7C3D8C9a439feDe00D2600032D5dB0Be71C3c29\n * ```\n */\nexport function getKnownAssetDomain(id: KnownAssetId): KnownAssetDomain | undefined {\n\treturn KNOWN_ASSETS.find((entry) => entry.id === id);\n}\n\n/** List every known asset id (for diagnostics / error messages). */\nexport function listKnownAssetIds(): readonly KnownAssetId[] {\n\treturn KNOWN_ASSETS.map((entry) => entry.id);\n}\n","/**\n * EIP-3009 typed-data builders and signing helpers.\n *\n * Token-agnostic: works for any EIP-3009-compliant token (JPYC, USDC, USDP,\n * Centre FiatToken family). Pure off-chain construction — no chain RPC, no\n * submission. Submission is the caller's job (M3 x402 flow, or arbitrary\n * gas-paying relayer).\n *\n * @packageDocumentation\n */\n\nimport {\n\ttype Account,\n\ttype Address,\n\tgetAddress,\n\ttype Hex,\n\tkeccak256,\n\tparseSignature,\n\tstringToHex,\n} from \"viem\";\n\n// ---------------------------------------------------------------------------\n// Domain & typed-data shapes\n// ---------------------------------------------------------------------------\n\n/**\n * EIP-712 domain for an EIP-3009-compliant token.\n *\n * `name` and `version` MUST match the values the token used when computing\n * its `DOMAIN_SEPARATOR`. For JPYC see {@link JPYC_EIP712_DOMAIN_HINT}.\n */\nexport interface Eip3009Domain {\n\treadonly name: string;\n\treadonly version: string;\n\treadonly chainId: number;\n\treadonly verifyingContract: Address;\n}\n\n/** Message body for {@link signTransferWithAuthorization}. */\nexport interface TransferWithAuthorizationMessage {\n\treadonly from: Address;\n\treadonly to: Address;\n\treadonly value: bigint;\n\treadonly validAfter: bigint;\n\treadonly validBefore: bigint;\n\t/** 32-byte random nonce. Generate with {@link generateAuthorizationNonce}. */\n\treadonly nonce: Hex;\n}\n\n/** Message body for {@link signReceiveWithAuthorization}. */\nexport type ReceiveWithAuthorizationMessage = TransferWithAuthorizationMessage;\n\n/** Message body for {@link signCancelAuthorization}. */\nexport interface CancelAuthorizationMessage {\n\treadonly authorizer: Address;\n\treadonly nonce: Hex;\n}\n\n/**\n * A signed EIP-3009 authorization, ready to be passed to the token's\n * `*WithAuthorization` entrypoint as `(v, r, s)`.\n */\nexport interface SignedAuthorization<TMessage> {\n\treadonly signature: Hex;\n\treadonly v: number;\n\treadonly r: Hex;\n\treadonly s: Hex;\n\treadonly domain: Eip3009Domain;\n\treadonly message: TMessage;\n}\n\n// ---------------------------------------------------------------------------\n// EIP-712 type definitions (must match EIP-3009 byte-for-byte)\n// ---------------------------------------------------------------------------\n\nconst transferWithAuthorizationTypes = {\n\tTransferWithAuthorization: [\n\t\t{ name: \"from\", type: \"address\" },\n\t\t{ name: \"to\", type: \"address\" },\n\t\t{ name: \"value\", type: \"uint256\" },\n\t\t{ name: \"validAfter\", type: \"uint256\" },\n\t\t{ name: \"validBefore\", type: \"uint256\" },\n\t\t{ name: \"nonce\", type: \"bytes32\" },\n\t],\n} as const;\n\nconst receiveWithAuthorizationTypes = {\n\tReceiveWithAuthorization: [\n\t\t{ name: \"from\", type: \"address\" },\n\t\t{ name: \"to\", type: \"address\" },\n\t\t{ name: \"value\", type: \"uint256\" },\n\t\t{ name: \"validAfter\", type: \"uint256\" },\n\t\t{ name: \"validBefore\", type: \"uint256\" },\n\t\t{ name: \"nonce\", type: \"bytes32\" },\n\t],\n} as const;\n\nconst cancelAuthorizationTypes = {\n\tCancelAuthorization: [\n\t\t{ name: \"authorizer\", type: \"address\" },\n\t\t{ name: \"nonce\", type: \"bytes32\" },\n\t],\n} as const;\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Generates a cryptographically random 32-byte EIP-3009 nonce.\n *\n * The nonce only needs to be unique per `(authorizer, contract)` — duplicates\n * across different tokens are harmless because the contract scopes them.\n *\n * @example\n * ```ts\n * import { generateAuthorizationNonce } from \"kawasekit\";\n *\n * const nonce = generateAuthorizationNonce();\n * ```\n */\nexport function generateAuthorizationNonce(): Hex {\n\tconst bytes = new Uint8Array(32);\n\tcrypto.getRandomValues(bytes);\n\treturn `0x${Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\")}` as Hex;\n}\n\n/** Domain tag separating the nonce preimage from any other keccak use in the SDK. */\nconst EIP3009_NONCE_DOMAIN_TAG = \"kawasekit/eip3009-nonce/1\";\n\n/**\n * Derives a **deterministic** 32-byte EIP-3009 nonce from a reasoning-step\n * idempotency key, scoped to `(from, verifyingContract, chainId)` so the same\n * key never collides across tokens or chains (M5-1, Half B).\n *\n * `nonce = keccak256(DOMAIN_TAG ‖ idempotencyKey ‖ from ‖ verifyingContract ‖\n * chainId)`. **No shared secret**: determinism across replicas / sub-agents\n * needs only a shared `conversationId` (the source of the key), not secret\n * distribution. A replayed key ⇒ identical nonce ⇒ the token contract's\n * `authorizationState` rejects the second settlement — the on-chain last line of\n * defence against re-signed same-intent duplicate payments. Use in place of\n * {@link generateAuthorizationNonce} only when a key is available.\n *\n * `chainId` is in the preimage, so the same JPYC address on Polygon / Avalanche\n * / Kaia / Ethereum yields distinct nonces (cross-chain replay safety).\n *\n * @example\n * ```ts\n * import { deriveAuthorizationNonce } from \"kawasekit\";\n *\n * const nonce = deriveAuthorizationNonce(\n * { idempotencyKey },\n * { from: account.address, verifyingContract, chainId },\n * );\n * ```\n */\nexport function deriveAuthorizationNonce(\n\tinput: { readonly idempotencyKey: string },\n\tscope: { readonly from: Address; readonly verifyingContract: Address; readonly chainId: number },\n): Hex {\n\tif (input.idempotencyKey === \"\") {\n\t\tthrow new Error(\"deriveAuthorizationNonce: idempotencyKey must be a non-empty string\");\n\t}\n\tconst preimage = JSON.stringify([\n\t\tEIP3009_NONCE_DOMAIN_TAG,\n\t\tinput.idempotencyKey,\n\t\tgetAddress(scope.from),\n\t\tgetAddress(scope.verifyingContract),\n\t\tscope.chainId,\n\t]);\n\treturn keccak256(stringToHex(preimage));\n}\n\n/**\n * Returns a `validBefore` UNIX timestamp `seconds` in the future.\n *\n * @param seconds - Lifetime of the authorization, in seconds.\n * @param nowSec - Optional override of \"now\" (defaults to {@link Date.now}).\n *\n * @example\n * ```ts\n * import { authorizationDeadlineFromNow } from \"kawasekit\";\n *\n * const validBefore = authorizationDeadlineFromNow(60 * 5); // 5 minutes\n * ```\n */\nexport function authorizationDeadlineFromNow(seconds: number, nowSec?: bigint): bigint {\n\tconst now = nowSec ?? BigInt(Math.floor(Date.now() / 1000));\n\treturn now + BigInt(seconds);\n}\n\nfunction requireSignTypedData(account: Account): NonNullable<Account[\"signTypedData\"]> {\n\tif (!account.signTypedData) {\n\t\tthrow new Error(\n\t\t\t`Account ${account.address} cannot sign typed data — pass a LocalAccount or a JsonRpcAccount bound to a WalletClient.`,\n\t\t);\n\t}\n\treturn account.signTypedData.bind(account);\n}\n\nfunction assertSignerMatches(account: Account, expectedFrom: Address, role: string): void {\n\tif (getAddress(account.address) !== getAddress(expectedFrom)) {\n\t\tthrow new Error(\n\t\t\t`EIP-3009 ${role} signature must come from \\`${role === \"cancel\" ? \"authorizer\" : \"from\"}\\`: account is ${account.address}, message says ${expectedFrom}.`,\n\t\t);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Signers\n// ---------------------------------------------------------------------------\n\n/**\n * Signs an EIP-3009 `TransferWithAuthorization` message.\n *\n * The signing account MUST equal `message.from` — EIP-3009 rejects signatures\n * from anyone else (the on-chain check is pure `ecrecover` against `from`).\n *\n * @example\n * ```ts\n * import { privateKeyToAccount } from \"viem/accounts\";\n * import {\n * authorizationDeadlineFromNow,\n * generateAuthorizationNonce,\n * JPYC_EIP712_DOMAIN_HINT,\n * polygon,\n * signTransferWithAuthorization,\n * } from \"kawasekit\";\n *\n * const account = privateKeyToAccount(\"0x...\");\n * const signed = await signTransferWithAuthorization(account, {\n * ...JPYC_EIP712_DOMAIN_HINT,\n * chainId: polygon.id,\n * verifyingContract: \"0xE7C3D8C9a439feDe00D2600032D5dB0Be71C3c29\",\n * }, {\n * from: account.address,\n * to: \"0xBeef...\",\n * value: 100n * 10n ** 18n,\n * validAfter: 0n,\n * validBefore: authorizationDeadlineFromNow(300),\n * nonce: generateAuthorizationNonce(),\n * });\n * // → submit (v, r, s) to token.transferWithAuthorization(...)\n * ```\n */\nexport async function signTransferWithAuthorization(\n\taccount: Account,\n\tdomain: Eip3009Domain,\n\tmessage: TransferWithAuthorizationMessage,\n): Promise<SignedAuthorization<TransferWithAuthorizationMessage>> {\n\tassertSignerMatches(account, message.from, \"transfer\");\n\tconst sign = requireSignTypedData(account);\n\tconst signature = await sign({\n\t\tdomain,\n\t\ttypes: transferWithAuthorizationTypes,\n\t\tprimaryType: \"TransferWithAuthorization\",\n\t\tmessage,\n\t});\n\treturn splitAuthorization(signature, domain, message);\n}\n\n/**\n * Signs an EIP-3009 `ReceiveWithAuthorization` message.\n *\n * Differs from {@link signTransferWithAuthorization} in two ways:\n * 1. Uses the `ReceiveWithAuthorization` EIP-712 type.\n * 2. The contract additionally enforces `msg.sender == to` at submission\n * time, so only `to` (or a relayer impersonating `to` — impossible in\n * practice) can land the tx.\n */\nexport async function signReceiveWithAuthorization(\n\taccount: Account,\n\tdomain: Eip3009Domain,\n\tmessage: ReceiveWithAuthorizationMessage,\n): Promise<SignedAuthorization<ReceiveWithAuthorizationMessage>> {\n\tassertSignerMatches(account, message.from, \"receive\");\n\tconst sign = requireSignTypedData(account);\n\tconst signature = await sign({\n\t\tdomain,\n\t\ttypes: receiveWithAuthorizationTypes,\n\t\tprimaryType: \"ReceiveWithAuthorization\",\n\t\tmessage,\n\t});\n\treturn splitAuthorization(signature, domain, message);\n}\n\n/**\n * Signs an EIP-3009 `CancelAuthorization` message.\n *\n * Cancelling consumes the nonce so a later `transferWithAuthorization` or\n * `receiveWithAuthorization` with the same nonce will revert.\n */\nexport async function signCancelAuthorization(\n\taccount: Account,\n\tdomain: Eip3009Domain,\n\tmessage: CancelAuthorizationMessage,\n): Promise<SignedAuthorization<CancelAuthorizationMessage>> {\n\tassertSignerMatches(account, message.authorizer, \"cancel\");\n\tconst sign = requireSignTypedData(account);\n\tconst signature = await sign({\n\t\tdomain,\n\t\ttypes: cancelAuthorizationTypes,\n\t\tprimaryType: \"CancelAuthorization\",\n\t\tmessage,\n\t});\n\treturn splitAuthorization(signature, domain, message);\n}\n\nfunction splitAuthorization<TMessage>(\n\tsignature: Hex,\n\tdomain: Eip3009Domain,\n\tmessage: TMessage,\n): SignedAuthorization<TMessage> {\n\tconst parsed = parseSignature(signature);\n\t// viem's parseSignature returns yParity ∈ {0, 1} as well as v when present.\n\tconst v = parsed.v !== undefined ? Number(parsed.v) : (parsed.yParity ?? 0) + 27;\n\treturn {\n\t\tsignature,\n\t\tv,\n\t\tr: parsed.r,\n\t\ts: parsed.s,\n\t\tdomain,\n\t\tmessage,\n\t};\n}\n","/**\n * EIP-712 asset-domain resolution for x402 / EIP-3009 signing.\n *\n * Construction-time pinning of the EIP-712 domain (`name` / `version` /\n * `verifyingContract`) a signer will use. The integrator declares an\n * {@link X402AssetParam} — either a kawasekit-maintained `known` asset or a\n * loud `unsafeOverride` — and {@link resolveAssetParam} resolves it to a pinned\n * {@link ResolvedAsset}. The signer then trusts only this pinned domain and\n * refuses to sign for a mismatched advertised asset (Threat 1.4: misadvertised\n * EIP-712 domain).\n *\n * Token-domain concern, reused by both the x402 signer (`src/x402/client.ts`)\n * and the M6 PolicyGatedSigner (`src/signer/`).\n *\n * @packageDocumentation\n */\n\nimport type { Address } from \"viem\";\nimport { getAddress, isAddress } from \"viem\";\nimport { X402InvalidConfigError } from \"../x402/errors\";\nimport {\n\tgetKnownAssetDomain,\n\ttype KnownAssetDomain,\n\ttype KnownAssetId,\n\tlistKnownAssetIds,\n} from \"./known-assets\";\n\n/** EIP-712 token domain `name` / `version` pair. */\nexport interface X402TokenDomain {\n\treadonly name: string;\n\treadonly version: string;\n}\n\n/**\n * Asset binding for {@link createX402PaymentSigner} and the M6 PolicyGatedSigner.\n * Required, discriminated.\n *\n * **Default-on whitelist**: integrators MUST declare which asset they intend\n * to sign for. The `known` branch references a kawasekit-maintained\n * whitelist (see `src/tokens/known-assets.ts`); the `unsafeOverride` branch\n * is the deliberate escape hatch for any other asset and is named loudly so\n * it survives a code review. Either way, the signer pins the EIP-712 domain\n * at construction time and refuses to sign if `paymentRequirements.asset`\n * disagrees with the pinned `verifyingContract`.\n *\n * Closes Threat 1.4 (misadvertised EIP-712 domain): the server's advertised\n * `extra.name` / `extra.version` and `asset` are all ignored for signing\n * purposes — the signer trusts only what the integrator declared here.\n */\nexport type X402AssetParam =\n\t| {\n\t\t\t/** Use a kawasekit-maintained pinned EIP-712 domain. */\n\t\t\treadonly kind: \"known\";\n\t\t\t/** The asset id to pin. See {@link KnownAssetId} for the registry. */\n\t\t\treadonly id: KnownAssetId;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Use a caller-supplied EIP-712 domain for an asset NOT on the\n\t\t\t * kawasekit whitelist. The name is deliberately loud — pick this\n\t\t\t * branch only when you have separately audited the contract and its\n\t\t\t * `eip712Domain()` output.\n\t\t\t */\n\t\t\treadonly kind: \"unsafeOverride\";\n\t\t\treadonly domain: {\n\t\t\t\treadonly name: string;\n\t\t\t\treadonly version: string;\n\t\t\t\treadonly verifyingContract: Address;\n\t\t\t};\n\t };\n\n/** Construction-time resolution of an {@link X402AssetParam} to a pinned domain. */\nexport interface ResolvedAsset {\n\treadonly name: string;\n\treadonly version: string;\n\treadonly verifyingContract: Address;\n}\n\n/**\n * Resolve an {@link X402AssetParam} to a pinned {@link ResolvedAsset}.\n *\n * Throws {@link X402InvalidConfigError} for an unknown `known` id or a malformed\n * `unsafeOverride` domain. Pure / construction-time — no chain RPC.\n */\nexport function resolveAssetParam(asset: X402AssetParam): ResolvedAsset {\n\tif (asset.kind === \"known\") {\n\t\tconst entry: KnownAssetDomain | undefined = getKnownAssetDomain(asset.id);\n\t\tif (entry === undefined) {\n\t\t\tthrow new X402InvalidConfigError(\n\t\t\t\t\"asset.id\",\n\t\t\t\t`unknown asset id ${JSON.stringify(asset.id)}. Supported: ${listKnownAssetIds()\n\t\t\t\t\t.map((id) => JSON.stringify(id))\n\t\t\t\t\t.join(\", \")}.`,\n\t\t\t);\n\t\t}\n\t\treturn {\n\t\t\tname: entry.name,\n\t\t\tversion: entry.version,\n\t\t\tverifyingContract: entry.verifyingContract,\n\t\t};\n\t}\n\tif (asset.kind === \"unsafeOverride\") {\n\t\tconst { domain } = asset;\n\t\tif (typeof domain.name !== \"string\" || domain.name === \"\") {\n\t\t\tthrow new X402InvalidConfigError(\n\t\t\t\t\"asset.domain.name\",\n\t\t\t\t\"`unsafeOverride.domain.name` must be a non-empty string\",\n\t\t\t);\n\t\t}\n\t\tif (typeof domain.version !== \"string\" || domain.version === \"\") {\n\t\t\tthrow new X402InvalidConfigError(\n\t\t\t\t\"asset.domain.version\",\n\t\t\t\t\"`unsafeOverride.domain.version` must be a non-empty string\",\n\t\t\t);\n\t\t}\n\t\tif (!isAddress(domain.verifyingContract, { strict: false })) {\n\t\t\tthrow new X402InvalidConfigError(\n\t\t\t\t\"asset.domain.verifyingContract\",\n\t\t\t\t`\\`unsafeOverride.domain.verifyingContract\\` must be a valid address, got ${JSON.stringify(domain.verifyingContract)}`,\n\t\t\t);\n\t\t}\n\t\treturn {\n\t\t\tname: domain.name,\n\t\t\tversion: domain.version,\n\t\t\tverifyingContract: getAddress(domain.verifyingContract),\n\t\t};\n\t}\n\t// Defensive: TS exhaustiveness guarantees this is unreachable at compile\n\t// time, but a JS consumer could smuggle through an unknown kind.\n\tconst exhaustive = asset as { kind: string };\n\tthrow new X402InvalidConfigError(\n\t\t\"asset.kind\",\n\t\t`unsupported kind ${JSON.stringify(exhaustive.kind)}. Expected \"known\" or \"unsafeOverride\".`,\n\t);\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/policy/spending-policy.ts"],"names":[],"mappings":"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","file":"chunk-YMABXRCK.js","sourcesContent":["/**\n * Spending policy — policy-as-data for the x402 / EIP-3009 PolicyGatedSigner\n * (M6). One declarative {@link SpendingPolicy} (session + expiry, per-token\n * `maxPerSign` + cumulative cap, recipient allowlist, `revoked`) and one pure,\n * deny-closed evaluator {@link evaluateSpendingPolicy}.\n *\n * The same specification is enforced SDK-side (the `local` adapter) and, for the\n * `mpc-2p` adapter, re-implemented backend-side in Go; a shared conformance\n * corpus (`__fixtures__/spending-policy.vectors.json`) keeps the two in lockstep.\n * The evaluator is **check-only** — it reads `SpendState` and never mutates it;\n * the cumulative-cap *commit* (folding a successful spend back in via\n * {@link mergeSpendState}) is the adapter's job, and atomic+authoritative\n * commit is a property of the `cryptographic` adapter only.\n *\n * This is the **x402-EOA** policy path. The smart-account / ZeroDev session-key\n * path is `createJpycDailyLimitPolicies` (`./daily-limit`) — a sibling, not a\n * replacement.\n *\n * @packageDocumentation\n */\n\nimport type { Address } from \"viem\";\nimport { getAddress } from \"viem\";\nimport type { PaymentIntent, PolicyRejection } from \"../signer/types\";\n\n/** Per-token spend limits. A token absent from the policy's `perToken` is NOT allowed. */\nexport interface TokenLimit {\n\treadonly token: Address;\n\t/** Max value per single signature, token base units. Generalizes `maxAmountPerSign` (threat 1.14). */\n\treadonly maxPerSign: bigint;\n\t/** Optional total across the session. `undefined` = uncapped. MUST be `>= maxPerSign`. */\n\treadonly cumulativeCap?: bigint;\n}\n\n/**\n * Policy-as-data evaluated for every {@link PaymentIntent}. Deny-closed\n * throughout: a token not listed in `perToken` is rejected, and\n * `recipientAllowlist` is **required** — `\"any\"` (unrestricted) is a conscious,\n * greppable choice, never a silent default.\n */\nexport interface SpendingPolicy {\n\treadonly version: \"1\";\n\t/** Session id + expiry (unix seconds). An authorization may not outlive the session. */\n\treadonly session: { readonly id: string; readonly notAfter: bigint };\n\treadonly perToken: readonly TokenLimit[];\n\t/**\n\t * Recipient restriction (**required** — no silent allow-open default):\n\t * `\"any\"` = unrestricted, `[]` = deny-all, `[...]` = allowlist. Making\n\t * `\"any\"` explicit keeps the policy deny-closed like `perToken`.\n\t */\n\treadonly recipientAllowlist: readonly Address[] | \"any\";\n\treadonly revoked: boolean;\n}\n\n/**\n * Cross-call cumulative spend, per token. Injected into the evaluator (never a\n * module global). For the `local` adapter this is a single-process, caller-managed\n * **read-only view**; the authoritative ledger lives in the `cryptographic`\n * adapter's backend.\n */\nexport interface SpendState {\n\treadonly spentPerToken: readonly { readonly token: Address; readonly spent: bigint }[];\n}\n\n/** The outcome of {@link evaluateSpendingPolicy}. */\nexport type PolicyDecision =\n\t| { readonly ok: true }\n\t| { readonly ok: false; readonly rejection: PolicyRejection };\n\n/** Thrown by {@link createSpendingPolicy} on a malformed policy. */\nexport class SpendingPolicyConfigError extends Error {\n\treadonly field: string;\n\treadonly reason: string;\n\n\tconstructor(field: string, reason: string, options?: { cause?: unknown }) {\n\t\tsuper(`Invalid SpendingPolicy (${field}): ${reason}`, options);\n\t\tthis.name = \"SpendingPolicyConfigError\";\n\t\tthis.field = field;\n\t\tthis.reason = reason;\n\t}\n}\n\nfunction deny(reason: PolicyRejection[\"reason\"], detail: string): PolicyDecision {\n\treturn { ok: false, rejection: { reason, detail } };\n}\n\n/**\n * Evaluate a {@link SpendingPolicy} against a decoded {@link PaymentIntent}.\n *\n * Pure, deterministic, no I/O. Deny-closed; the first failing check wins. All\n * amount comparisons are `bigint`; all address equality uses `getAddress()` on\n * both sides. **Reads `state`, never mutates it** — see {@link mergeSpendState}.\n * `detail` strings never contain the nonce or any signature.\n *\n * @example\n * ```ts\n * const decision = evaluateSpendingPolicy(policy, intent, state, BigInt(Math.floor(Date.now() / 1000)));\n * if (!decision.ok) console.warn(decision.rejection.reason);\n * ```\n */\nexport function evaluateSpendingPolicy(\n\tpolicy: SpendingPolicy,\n\tintent: PaymentIntent,\n\tstate: SpendState,\n\tnowSeconds: bigint,\n): PolicyDecision {\n\tif (policy.revoked) {\n\t\treturn deny(\"revoked\", \"the spending policy has been revoked\");\n\t}\n\tif (nowSeconds > policy.session.notAfter) {\n\t\treturn deny(\"expired\", `session expired at ${policy.session.notAfter} (now ${nowSeconds})`);\n\t}\n\tif (intent.validBefore > policy.session.notAfter) {\n\t\treturn deny(\n\t\t\t\"expired\",\n\t\t\t`authorization validBefore ${intent.validBefore} outlives the session (notAfter ${policy.session.notAfter})`,\n\t\t);\n\t}\n\n\tconst intentToken = getAddress(intent.token);\n\tconst limit = policy.perToken.find((l) => getAddress(l.token) === intentToken);\n\tif (limit === undefined) {\n\t\treturn deny(\"token_not_allowed\", `token ${intentToken} is not in the policy`);\n\t}\n\n\tif (policy.recipientAllowlist !== \"any\") {\n\t\tconst to = getAddress(intent.to);\n\t\tconst allowed = policy.recipientAllowlist.some((a) => getAddress(a) === to);\n\t\tif (!allowed) {\n\t\t\treturn deny(\"recipient_not_allowed\", `recipient ${to} is not on the allowlist`);\n\t\t}\n\t}\n\n\tif (intent.value > limit.maxPerSign) {\n\t\treturn deny(\n\t\t\t\"amount_exceeds_per_sign\",\n\t\t\t`value ${intent.value} exceeds maxPerSign ${limit.maxPerSign}`,\n\t\t);\n\t}\n\n\tif (limit.cumulativeCap !== undefined) {\n\t\tconst spent = state.spentPerToken.find((s) => getAddress(s.token) === intentToken)?.spent ?? 0n;\n\t\tif (spent + intent.value > limit.cumulativeCap) {\n\t\t\treturn deny(\n\t\t\t\t\"amount_exceeds_cumulative\",\n\t\t\t\t`spent ${spent} + value ${intent.value} exceeds cumulativeCap ${limit.cumulativeCap}`,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn { ok: true };\n}\n\n/** Parameters for {@link createSpendingPolicy}. */\nexport interface CreateSpendingPolicyParams {\n\treadonly session: { readonly id: string; readonly notAfter: bigint };\n\treadonly perToken: readonly TokenLimit[];\n\t/** Required: `\"any\"` (unrestricted), `[]` (deny-all), or an allowlist. No silent default. */\n\treadonly recipientAllowlist: readonly Address[] | \"any\";\n\t/** Defaults to `false`. */\n\treadonly revoked?: boolean;\n}\n\n/**\n * Validate + normalize a {@link SpendingPolicy}. Checksums all addresses\n * (`getAddress`), rejects an empty `perToken` (deny-closed), a non-positive\n * `maxPerSign`/`cumulativeCap`, a `cumulativeCap < maxPerSign`, and duplicate\n * tokens. Throws {@link SpendingPolicyConfigError} on violation.\n *\n * @example\n * ```ts\n * const policy = createSpendingPolicy({\n * session: { id: conversationId, notAfter: BigInt(deadline) },\n * perToken: [{ token: JPYC, maxPerSign: 1_000n, cumulativeCap: 10_000n }],\n * recipientAllowlist: [merchant],\n * });\n * ```\n */\nexport function createSpendingPolicy(params: CreateSpendingPolicyParams): SpendingPolicy {\n\tif (typeof params.session.id !== \"string\" || params.session.id === \"\") {\n\t\tthrow new SpendingPolicyConfigError(\"session.id\", \"must be a non-empty string\");\n\t}\n\tif (params.session.notAfter <= 0n) {\n\t\tthrow new SpendingPolicyConfigError(\n\t\t\t\"session.notAfter\",\n\t\t\t`must be a positive unix-seconds bigint, got ${params.session.notAfter}`,\n\t\t);\n\t}\n\tif (params.perToken.length === 0) {\n\t\tthrow new SpendingPolicyConfigError(\n\t\t\t\"perToken\",\n\t\t\t\"must list at least one token (the policy is deny-closed)\",\n\t\t);\n\t}\n\n\tconst seen = new Set<string>();\n\tconst perToken: readonly TokenLimit[] = params.perToken.map((l) => {\n\t\tconst token = getAddress(l.token);\n\t\tif (seen.has(token)) {\n\t\t\tthrow new SpendingPolicyConfigError(\"perToken\", `duplicate token ${token}`);\n\t\t}\n\t\tseen.add(token);\n\t\tif (l.maxPerSign <= 0n) {\n\t\t\tthrow new SpendingPolicyConfigError(\n\t\t\t\t\"perToken.maxPerSign\",\n\t\t\t\t`must be positive, got ${l.maxPerSign} for ${token}`,\n\t\t\t);\n\t\t}\n\t\tif (l.cumulativeCap !== undefined) {\n\t\t\tif (l.cumulativeCap <= 0n) {\n\t\t\t\tthrow new SpendingPolicyConfigError(\n\t\t\t\t\t\"perToken.cumulativeCap\",\n\t\t\t\t\t`must be positive, got ${l.cumulativeCap} for ${token}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (l.cumulativeCap < l.maxPerSign) {\n\t\t\t\tthrow new SpendingPolicyConfigError(\n\t\t\t\t\t\"perToken.cumulativeCap\",\n\t\t\t\t\t`cumulativeCap (${l.cumulativeCap}) must be >= maxPerSign (${l.maxPerSign}) for ${token}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn { token, maxPerSign: l.maxPerSign, cumulativeCap: l.cumulativeCap };\n\t\t}\n\t\treturn { token, maxPerSign: l.maxPerSign };\n\t});\n\n\tconst recipientAllowlist =\n\t\tparams.recipientAllowlist === \"any\"\n\t\t\t? \"any\"\n\t\t\t: params.recipientAllowlist.map((a) => getAddress(a));\n\n\treturn {\n\t\tversion: \"1\",\n\t\tsession: { id: params.session.id, notAfter: params.session.notAfter },\n\t\tperToken,\n\t\trecipientAllowlist,\n\t\trevoked: params.revoked ?? false,\n\t};\n}\n\n/**\n * Fold a successful spend back into a {@link SpendState} (pure; returns a new\n * state). The caller of the `local` adapter uses this to keep `cumulativeCap`\n * meaningful across calls — `local` does not own an authoritative ledger.\n */\nexport function mergeSpendState(\n\tstate: SpendState,\n\tspend: { readonly token: Address; readonly value: bigint },\n): SpendState {\n\tconst token = getAddress(spend.token);\n\tconst exists = state.spentPerToken.some((s) => getAddress(s.token) === token);\n\tconst spentPerToken = exists\n\t\t? state.spentPerToken.map((s) =>\n\t\t\t\tgetAddress(s.token) === token ? { token, spent: s.spent + spend.value } : s,\n\t\t\t)\n\t\t: [...state.spentPerToken, { token, spent: spend.value }];\n\treturn { spentPerToken };\n}\n"]}
|