@haven_ai/sdk 0.0.0-dev.202610091112.2d759b4 → 0.0.0-dev.202610091605.1bb6937

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 (36) hide show
  1. package/README.md +1 -1
  2. package/dist/{base64-Bt4FfseR.d.ts → base64-BTNPyGx3.d.ts} +2 -2
  3. package/dist/{base64-DTildBvj.d.cts → base64-Y4dQEYtK.d.cts} +2 -2
  4. package/dist/{chunk-IK76AGXX.js → chunk-6HOA45ID.js} +3 -3
  5. package/dist/{chunk-IK76AGXX.js.map → chunk-6HOA45ID.js.map} +1 -1
  6. package/dist/{chunk-AYAVDHWH.cjs → chunk-7IXXN7CR.cjs} +35 -35
  7. package/dist/{chunk-AYAVDHWH.cjs.map → chunk-7IXXN7CR.cjs.map} +1 -1
  8. package/dist/{chunk-XCVI6OFM.cjs → chunk-A3V4HANQ.cjs} +4 -4
  9. package/dist/{chunk-XCVI6OFM.cjs.map → chunk-A3V4HANQ.cjs.map} +1 -1
  10. package/dist/{chunk-H5LK5WVJ.js → chunk-AEUUVGTQ.js} +6 -4
  11. package/dist/chunk-AEUUVGTQ.js.map +1 -0
  12. package/dist/{chunk-G5IJ74QS.cjs → chunk-CETAFCIA.cjs} +6 -4
  13. package/dist/chunk-CETAFCIA.cjs.map +1 -0
  14. package/dist/{chunk-WDXP4U2F.js → chunk-PAYNYIXL.js} +4 -4
  15. package/dist/{chunk-WDXP4U2F.js.map → chunk-PAYNYIXL.js.map} +1 -1
  16. package/dist/edge.cjs +91 -91
  17. package/dist/edge.d.cts +4 -4
  18. package/dist/edge.d.ts +4 -4
  19. package/dist/edge.js +4 -4
  20. package/dist/index.cjs +322 -320
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +7 -7
  23. package/dist/index.d.ts +7 -7
  24. package/dist/index.js +9 -7
  25. package/dist/index.js.map +1 -1
  26. package/dist/{receipt-WkXHZGbu.d.ts → receipt-C9IcbSIJ.d.ts} +1 -1
  27. package/dist/{receipt-D4Roey3D.d.cts → receipt-FPonPn5v.d.cts} +1 -1
  28. package/dist/test-support.cjs +21 -21
  29. package/dist/test-support.d.cts +2 -2
  30. package/dist/test-support.d.ts +2 -2
  31. package/dist/test-support.js +2 -2
  32. package/dist/{types-CrszUJ7Z.d.ts → types-dE4yDw9n.d.cts} +3 -1
  33. package/dist/{types-CrszUJ7Z.d.cts → types-dE4yDw9n.d.ts} +3 -1
  34. package/package.json +1 -1
  35. package/dist/chunk-G5IJ74QS.cjs.map +0 -1
  36. package/dist/chunk-H5LK5WVJ.js.map +0 -1
package/README.md CHANGED
@@ -454,7 +454,7 @@ Hosted MCP and signer tools also return stable `code` values on recoverable x402
454
454
  | `PRICE_EXCEEDS_MAX` | The merchant-authoritative x402 price is above the caller's spending cap. No funding transfer was created. | Tell the user the live price exceeded the cap and retry only after they confirm a higher one. Payloads carry `next_action: stop_and_tell_user` and `retry_with_new_quote: true` — the latter means any retry needs a fresh quote, not that one should be attempted unattended. |
455
455
  | `AMBIGUOUS_MAX_AMOUNT` | Both `max_amount` (atomic units) and `max_amount_human` (whole tokens) were sent for one purchase. Nothing was contacted and nothing was spent. | Re-send with exactly one — `max_amount_human` for a cap the user stated in tokens, `max_amount` for an exact atomic figure. |
456
456
  | `MAX_AMOUNT_UNCONVERTIBLE` | `max_amount_human` could not be converted against this quote's asset — its decimals are unknown to Haven, or the cap has more decimal places than the asset supports. Nothing was spent. | Round the cap to the asset's decimals, or re-send it as an exact atomic `max_amount`. |
457
- | `MERCHANT_NOT_READY` | The merchant answered the quote probe with its own `503 { error: 'merchant_not_ready', reason_code, retry_after_s }` instead of a 402 — it cannot settle right now (e.g. its settlement wallet is out of gas). No payment was created. | Tell the user and retry later (`retry_after_s` in the message when given); do not treat it as a wrong endpoint. Payloads carry `next_action: stop_and_tell_user` and `retry_with_new_quote: true`. |
457
+ | `MERCHANT_NOT_READY` | The merchant answered the quote probe with its own `503 { error: 'merchant_not_ready', reason_code, retry_after_s }` instead of a 402 — it cannot settle right now (e.g. its settlement wallet is out of gas). No payment was created. | Tell the user and retry later (`retry_after_s` in the message when given); do not treat it as a wrong endpoint. An out-of-gas refusal (`reason_code: settlement_wallet_out_of_gas`) needs the merchant's operator to top up its settlement wallet first; retrying before then is refused again. Payloads carry `next_action: stop_and_tell_user` and `retry_with_new_quote: true`. |
458
458
  | `PAYMENT_WINDOW_EXPIRED` | The funding/quote window closed before `haven_x402_sign_header`, `haven_submit`, or `haven_complete_mcp_tool` could finish. | Re-run `haven_pay_mcp_tool` with the same `idempotency_key`, then sign and complete the fresh quote. Payloads include `retry_with_new_quote: true`. |
459
459
  | `MERCHANT_REJECTED_AFTER_FUNDING` | The merchant rejected the paid retry. On eip3009 Haven's funding leg had succeeded; on erc7710 there is no funding leg (#2983). | eip3009: stop retrying the merchant and call `haven_sweep_delegate` so the user can recover stranded delegate USDC. erc7710: nothing to sweep — follow the message (re-quote later if the merchant declined to settle; otherwise check `haven_get_payment_status` after the payment window before re-quoting). |
460
460
  | `MERCHANT_UNRESPONSIVE_AFTER_FUNDING` | The merchant did not answer the paid retry before the timeout — NOT proof of rejection, the merchant may still settle late. On eip3009 Haven's funding leg had succeeded; on erc7710 there is no funding leg (#3000). | eip3009: check `haven_get_payment_status`, retry `haven_complete_mcp_tool` once, and only then call `haven_sweep_delegate` if no settlement appears. erc7710: nothing to sweep and `haven_complete_mcp_tool` has no erc7710 branch — do not retry it; check `haven_get_payment_status` after the payment window and re-quote only if it shows no settlement. |
@@ -1,4 +1,4 @@
1
- import { Q as AgentNextStep, Z as AgentPaymentNextAction, aL as X402PaymentOption, aK as X402ExpectedContext, X as X402PaymentRequired, I as HavenError, am as HavenSigningError } from './types-CrszUJ7Z.js';
1
+ import { Q as AgentNextStep, Z as AgentPaymentNextAction, aL as X402PaymentOption, aK as X402ExpectedContext, X as X402PaymentRequired, I as HavenError, am as HavenSigningError } from './types-dE4yDw9n.js';
2
2
  import { PaymentRequirements } from 'x402/types';
3
3
  import { Hex, Address } from 'viem';
4
4
 
@@ -200,7 +200,7 @@ declare function buildSweepAuthorizationMessage(auth: SweepAuthorization): strin
200
200
  * This SDK's own version. Owned by `scripts/release-bump.mjs`, which rewrites
201
201
  * it with the package version on every release — never hand-edit it.
202
202
  */
203
- declare const SDK_VERSION = "0.0.0-dev.202610091112.2d759b4";
203
+ declare const SDK_VERSION = "0.0.0-dev.202610091605.1bb6937";
204
204
  /** The request header every published Haven client sends. */
205
205
  declare const HAVEN_CLIENT_HEADER = "X-Haven-Client";
206
206
  /** `<package>/<version>` — the value of {@link HAVEN_CLIENT_HEADER}. */
@@ -1,4 +1,4 @@
1
- import { Q as AgentNextStep, Z as AgentPaymentNextAction, aL as X402PaymentOption, aK as X402ExpectedContext, X as X402PaymentRequired, I as HavenError, am as HavenSigningError } from './types-CrszUJ7Z.cjs';
1
+ import { Q as AgentNextStep, Z as AgentPaymentNextAction, aL as X402PaymentOption, aK as X402ExpectedContext, X as X402PaymentRequired, I as HavenError, am as HavenSigningError } from './types-dE4yDw9n.cjs';
2
2
  import { PaymentRequirements } from 'x402/types';
3
3
  import { Hex, Address } from 'viem';
4
4
 
@@ -200,7 +200,7 @@ declare function buildSweepAuthorizationMessage(auth: SweepAuthorization): strin
200
200
  * This SDK's own version. Owned by `scripts/release-bump.mjs`, which rewrites
201
201
  * it with the package version on every release — never hand-edit it.
202
202
  */
203
- declare const SDK_VERSION = "0.0.0-dev.202610091112.2d759b4";
203
+ declare const SDK_VERSION = "0.0.0-dev.202610091605.1bb6937";
204
204
  /** The request header every published Haven client sends. */
205
205
  declare const HAVEN_CLIENT_HEADER = "X-Haven-Client";
206
206
  /** `<package>/<version>` — the value of {@link HAVEN_CLIENT_HEADER}. */
@@ -1,4 +1,4 @@
1
- import { DELEGATION_MANAGER } from './chunk-H5LK5WVJ.js';
1
+ import { DELEGATION_MANAGER } from './chunk-AEUUVGTQ.js';
2
2
  import { ethers } from 'ethers';
3
3
  import { keccak256, toBytes, concatHex, encodeAbiParameters } from 'viem';
4
4
 
@@ -99,5 +99,5 @@ function verifyPaymentReceipt(receipt, recover = defaultRecover) {
99
99
  }
100
100
 
101
101
  export { RECEIPT_VERSION, verifyPaymentReceipt };
102
- //# sourceMappingURL=chunk-IK76AGXX.js.map
103
- //# sourceMappingURL=chunk-IK76AGXX.js.map
102
+ //# sourceMappingURL=chunk-6HOA45ID.js.map
103
+ //# sourceMappingURL=chunk-6HOA45ID.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/receipt.ts"],"names":[],"mappings":"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","file":"chunk-IK76AGXX.js","sourcesContent":["import { ethers } from 'ethers'\nimport { concatHex, encodeAbiParameters, keccak256, toBytes, type Hex } from 'viem'\nimport { DELEGATION_MANAGER } from './settlement-child.js'\nimport type { RawPaymentParties } from './types.js'\n\n/**\n * Verifiable payment receipts.\n *\n * A self-contained bundle for a settled Haven payment whose agent\n * authorisation can be checked offline. What `verifyPaymentReceipt` proves is\n * deliberately narrow: the `payment` block (amount, recipient) is\n * Haven-asserted and is NOT bound by the signature, and `verified: true` never\n * proves the payment settled on-chain — settlement stays an explorer check on\n * `onChain.txHash` / `settlementTxHash`.\n *\n * What `verified: true` means, per scheme:\n *\n * - erc7710 (`authorization.signatureScheme: 'eip712_delegation'`): the bundle\n * carries the settlement child's EIP-712 struct hash as `signHash`. The\n * verifier rebuilds the digest the delegate actually signed —\n * `keccak256(0x1901 ‖ domainSeparator(DelegationManager, chainId) ‖ signHash)`\n * — from the DelegationManager address the SDK pins and the bundle's\n * `onChain.chainId`, never from a value the receipt itself vouches for.\n * `verified: true` means the delegate key signed that settlement delegation\n * (`verifiedOver: 'delegation_digest'`).\n * - direct payments and the eip3009 funding leg\n * (`signatureScheme: 'eip712_userop'`) sign an ERC-4337 user operation the\n * bundle does not carry: they return `not_verifiable_offline` rather than a\n * false accusation.\n * - retired-rail bundles (no scheme) carry a raw-signed `signHash`; the\n * verifier recovers over it directly, then over the delegation digest when\n * the chain allows rebuilding it.\n *\n * Anything that is not a signed bundle — including a `haven_list_receipts`\n * history row, which carries no signature at all — returns\n * `not_a_signed_receipt`. Verification never throws.\n *\n * #3723: the response `GET /payments/{id}/receipt` returns —\n * `{ receipt, verification }` — is accepted AS-IS: when the top level carries\n * no `authorization`, the `.receipt` object inside is verified instead (one\n * level, no recursion). The wrapper's `verification` is never read — it is\n * Haven's own self-check, and trusting it would defeat an offline verifier.\n *\n * This lives in the SDK so agents and users can verify receipts client-side.\n */\nexport const RECEIPT_VERSION = 'haven-receipt-1'\n\nexport interface PaymentReceipt {\n version: typeof RECEIPT_VERSION\n paymentId: string\n payment: {\n token: string\n tokenAddress: string\n amount: string\n amountSek: string | null\n recipient: string\n /** The payer's smart-account address. */\n account: string\n /**\n * #2960: one party vocabulary for \"who paid\", additive alongside `account`\n * above (which is `parties.treasury_account` only). Optional: a server\n * from before #2960 emits neither. Ignored by `verifyPaymentReceipt`,\n * which reads only `authorization`.\n */\n parties?: RawPaymentParties\n chainId: number\n settledAt: string | null\n resourceUrl: string | null\n /**\n * #3770: the paying agent's own evidence-only verdict on what the\n * merchant DELIVERED (`ok` / `unusable` / `partial`, plus a bounded\n * note). Additive and OPTIONAL: a server from before #3770 emits\n * neither, and `null` means the agent has not reported. Ignored by\n * `verifyPaymentReceipt`, which reads only `authorization` — the same\n * rule `parties` follows. Evidence only: it never changes what the\n * payment itself is, and `settled`/amounts are untouched by a report.\n */\n deliveryQuality?: {\n quality: 'ok' | 'unusable' | 'partial'\n note: string | null\n reportedAt: string | null\n } | null\n }\n /** The agent's cryptographic authorisation — what makes the receipt verifiable. */\n authorization: {\n delegate: string\n signHash: string\n signature: string | null\n /**\n * #3418: which digest the delegate signed — selects what offline\n * verification rebuilds. `'eip712_delegation'`: the settlement\n * delegation's EIP-712 digest (erc7710). `'eip712_userop'`: an ERC-4337\n * user-operation digest the bundle does not carry (direct payments, the\n * eip3009 funding leg) — not verifiable offline. Absent on retired-rail\n * bundles and on backends older than #3418, whose `signHash` was signed\n * raw. The value is only a selector: a lying one cannot make a forged\n * signature verify, because recovery must still return `delegate`.\n */\n signatureScheme?: 'eip712_delegation' | 'eip712_userop'\n }\n onChain: {\n txHash: string | null\n chainId: number\n }\n}\n\nexport type ReceiptVerification =\n | { verified: true; recoveredSigner: string; verifiedOver: 'sign_hash' | 'delegation_digest' }\n | {\n verified: false\n reason:\n /** #3418: the input is not a haven-receipt-1 bundle (a haven_list_receipts row, null, undefined, a non-object). */\n | 'not_a_signed_receipt'\n /** #3418: eip712_userop bundle; or a delegation bundle on a chain the SDK pins no DelegationManager for. */\n | 'not_verifiable_offline'\n | 'missing_signature'\n | 'bad_signature'\n | 'signer_mismatch'\n recoveredSigner?: string\n }\n\n/** Chains whose DelegationManager the SDK pins (same address on both — rails/delegation-contracts.ts). */\nconst DELEGATION_MANAGER_CHAIN_IDS: ReadonlySet<number> = new Set([8453, 84532])\n\nconst EIP712_DOMAIN_TYPEHASH = keccak256(\n toBytes('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),\n)\n\n/**\n * The EIP-712 domain separator of the DelegationManager on `chainId`, rebuilt\n * from the manager's own constants (name/version, fixed in the contract) and\n * the address the SDK pins — never from a value the receipt vouches for.\n */\nfunction delegationDomainSeparator(chainId: number): Hex {\n return keccak256(\n encodeAbiParameters(\n [{ type: 'bytes32' }, { type: 'bytes32' }, { type: 'bytes32' }, { type: 'uint256' }, { type: 'address' }],\n [\n EIP712_DOMAIN_TYPEHASH,\n keccak256(toBytes('DelegationManager')),\n keccak256(toBytes('1')),\n BigInt(chainId),\n DELEGATION_MANAGER as Hex,\n ],\n ),\n )\n}\n\n/** The EIP-712 digest over a delegation struct hash (what the delegate signs). */\nfunction delegationDigest(structHash: string, chainId: number): Hex {\n return keccak256(concatHex(['0x1901', delegationDomainSeparator(chainId), structHash as Hex]))\n}\n\n/** Default ECDSA recovery (raw ecrecover over the hash, no message prefix). */\nfunction defaultRecover(hash: string, signature: string): string {\n return ethers.recoverAddress(hash, signature)\n}\n\nconst NOT_A_SIGNED_RECEIPT = { verified: false, reason: 'not_a_signed_receipt' } as const\n\ntype RecoverFn = (hash: string, signature: string) => string\n\ntype MatchResult =\n | { ok: true; recoveredSigner: string }\n | { ok: false; reason: 'bad_signature' | 'signer_mismatch'; recoveredSigner?: string }\n\n/** Recover over one candidate hash and compare the signer with the named delegate. */\nfunction match(delegate: string, hash: string, signature: string, recover: RecoverFn): MatchResult {\n let recovered: string\n try {\n recovered = recover(hash, signature)\n } catch {\n return { ok: false, reason: 'bad_signature' }\n }\n if (recovered.toLowerCase() !== delegate.toLowerCase()) {\n return { ok: false, reason: 'signer_mismatch', recoveredSigner: recovered }\n }\n return { ok: true, recoveredSigner: recovered }\n}\n\nfunction finish(result: MatchResult, verifiedOver: 'sign_hash' | 'delegation_digest'): ReceiptVerification {\n if (result.ok) {\n return { verified: true, recoveredSigner: result.recoveredSigner, verifiedOver }\n }\n return result.recoveredSigner !== undefined\n ? { verified: false, reason: result.reason, recoveredSigner: result.recoveredSigner }\n : { verified: false, reason: result.reason }\n}\n\n/**\n * Verify a receipt's agent authorisation offline: recover the signer and\n * confirm it is the agent delegate, over whichever digest the bundle's scheme\n * names (see the module doc for what that proves — and what it does not).\n * Never throws: anything that is not a signed receipt — a\n * `haven_list_receipts` history row, null, undefined, a non-object — returns\n * `not_a_signed_receipt`. The `{ receipt, verification }` wrapper the receipt\n * endpoint returns is accepted as-is: `.receipt` is verified, and the\n * wrapper's `verification` — Haven's own self-check — is never read. Pure —\n * `recover` is injectable but defaults to\n * standard ECDSA recovery, so this runs anywhere (no Haven backend).\n */\nexport function verifyPaymentReceipt(\n receipt: unknown,\n recover: RecoverFn = defaultRecover,\n): ReceiptVerification {\n // #3418 rule 1: a list row (or any non-bundle) has no authorization object\n // holding string delegate/signHash — answer, never throw.\n if (typeof receipt !== 'object' || receipt === null) return NOT_A_SIGNED_RECEIPT\n let source = receipt as {\n authorization?: unknown\n receipt?: unknown\n onChain?: { chainId?: unknown }\n }\n // #3723: accept the endpoint's response as-is. When the top level carries no\n // `authorization` and `.receipt` is a non-null object, verify the bundle\n // inside the `{ receipt, verification }` wrapper (GET\n // /payments/{id}/receipt, and HavenClient.getReceipt's re-wrap). ONE level\n // only — no recursion — and the wrapper's `verification` is NEVER read: it\n // is Haven's own self-check, and trusting it would defeat an offline\n // verifier. A list row wrapped or bare still answers not_a_signed_receipt.\n if (typeof source.authorization !== 'object' || source.authorization === null) {\n if (typeof source.receipt !== 'object' || source.receipt === null) {\n return NOT_A_SIGNED_RECEIPT\n }\n source = source.receipt as typeof source\n }\n if (typeof source.authorization !== 'object' || source.authorization === null) {\n return NOT_A_SIGNED_RECEIPT\n }\n const auth = source.authorization as {\n delegate?: unknown\n signHash?: unknown\n signature?: unknown\n signatureScheme?: unknown\n }\n const { delegate, signHash, signature, signatureScheme } = auth\n if (typeof delegate !== 'string' || delegate === '' || typeof signHash !== 'string' || signHash === '') {\n return NOT_A_SIGNED_RECEIPT\n }\n if (typeof signature !== 'string' || signature === '') {\n return { verified: false, reason: 'missing_signature' }\n }\n\n const chainId =\n typeof source.onChain?.chainId === 'number' ? source.onChain.chainId : undefined\n const digestVerifiable = chainId !== undefined && DELEGATION_MANAGER_CHAIN_IDS.has(chainId)\n\n // #3418 rule 4: a userop digest needs the full UserOperation, which the\n // bundle does not carry. Return not_verifiable_offline — never\n // signer_mismatch, which would accuse a genuine payment.\n if (signatureScheme === 'eip712_userop') {\n return { verified: false, reason: 'not_verifiable_offline' }\n }\n\n // #3418 rule 3: rebuild the delegation digest from the pinned manager and\n // the bundle's chain id, then recover over it.\n if (signatureScheme === 'eip712_delegation') {\n if (!digestVerifiable) {\n return { verified: false, reason: 'not_verifiable_offline' }\n }\n let digest: string\n try {\n digest = delegationDigest(signHash, chainId as number)\n } catch {\n return { verified: false, reason: 'bad_signature' }\n }\n return finish(match(delegate, digest, signature, recover), 'delegation_digest')\n }\n\n // #3418 rule 5: absent or unknown scheme — retired-rail history (signed raw\n // over signHash) or a backend older than this change. Raw recovery first,\n // then the delegation digest when the chain allows rebuilding it. This is\n // the one remaining ambiguous case, limited to old bundles.\n const raw = match(delegate, signHash, signature, recover)\n if (raw.ok) return finish(raw, 'sign_hash')\n if (digestVerifiable) {\n let digest: string\n try {\n digest = delegationDigest(signHash, chainId as number)\n } catch {\n return finish(raw, 'sign_hash')\n }\n const delegated = match(delegate, digest, signature, recover)\n if (delegated.ok) return finish(delegated, 'delegation_digest')\n }\n return finish(raw, 'sign_hash')\n}\n"]}
1
+ {"version":3,"sources":["../src/receipt.ts"],"names":[],"mappings":"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","file":"chunk-6HOA45ID.js","sourcesContent":["import { ethers } from 'ethers'\nimport { concatHex, encodeAbiParameters, keccak256, toBytes, type Hex } from 'viem'\nimport { DELEGATION_MANAGER } from './settlement-child.js'\nimport type { RawPaymentParties } from './types.js'\n\n/**\n * Verifiable payment receipts.\n *\n * A self-contained bundle for a settled Haven payment whose agent\n * authorisation can be checked offline. What `verifyPaymentReceipt` proves is\n * deliberately narrow: the `payment` block (amount, recipient) is\n * Haven-asserted and is NOT bound by the signature, and `verified: true` never\n * proves the payment settled on-chain — settlement stays an explorer check on\n * `onChain.txHash` / `settlementTxHash`.\n *\n * What `verified: true` means, per scheme:\n *\n * - erc7710 (`authorization.signatureScheme: 'eip712_delegation'`): the bundle\n * carries the settlement child's EIP-712 struct hash as `signHash`. The\n * verifier rebuilds the digest the delegate actually signed —\n * `keccak256(0x1901 ‖ domainSeparator(DelegationManager, chainId) ‖ signHash)`\n * — from the DelegationManager address the SDK pins and the bundle's\n * `onChain.chainId`, never from a value the receipt itself vouches for.\n * `verified: true` means the delegate key signed that settlement delegation\n * (`verifiedOver: 'delegation_digest'`).\n * - direct payments and the eip3009 funding leg\n * (`signatureScheme: 'eip712_userop'`) sign an ERC-4337 user operation the\n * bundle does not carry: they return `not_verifiable_offline` rather than a\n * false accusation.\n * - retired-rail bundles (no scheme) carry a raw-signed `signHash`; the\n * verifier recovers over it directly, then over the delegation digest when\n * the chain allows rebuilding it.\n *\n * Anything that is not a signed bundle — including a `haven_list_receipts`\n * history row, which carries no signature at all — returns\n * `not_a_signed_receipt`. Verification never throws.\n *\n * #3723: the response `GET /payments/{id}/receipt` returns —\n * `{ receipt, verification }` — is accepted AS-IS: when the top level carries\n * no `authorization`, the `.receipt` object inside is verified instead (one\n * level, no recursion). The wrapper's `verification` is never read — it is\n * Haven's own self-check, and trusting it would defeat an offline verifier.\n *\n * This lives in the SDK so agents and users can verify receipts client-side.\n */\nexport const RECEIPT_VERSION = 'haven-receipt-1'\n\nexport interface PaymentReceipt {\n version: typeof RECEIPT_VERSION\n paymentId: string\n payment: {\n token: string\n tokenAddress: string\n amount: string\n amountSek: string | null\n recipient: string\n /** The payer's smart-account address. */\n account: string\n /**\n * #2960: one party vocabulary for \"who paid\", additive alongside `account`\n * above (which is `parties.treasury_account` only). Optional: a server\n * from before #2960 emits neither. Ignored by `verifyPaymentReceipt`,\n * which reads only `authorization`.\n */\n parties?: RawPaymentParties\n chainId: number\n settledAt: string | null\n resourceUrl: string | null\n /**\n * #3770: the paying agent's own evidence-only verdict on what the\n * merchant DELIVERED (`ok` / `unusable` / `partial`, plus a bounded\n * note). Additive and OPTIONAL: a server from before #3770 emits\n * neither, and `null` means the agent has not reported. Ignored by\n * `verifyPaymentReceipt`, which reads only `authorization` — the same\n * rule `parties` follows. Evidence only: it never changes what the\n * payment itself is, and `settled`/amounts are untouched by a report.\n */\n deliveryQuality?: {\n quality: 'ok' | 'unusable' | 'partial'\n note: string | null\n reportedAt: string | null\n } | null\n }\n /** The agent's cryptographic authorisation — what makes the receipt verifiable. */\n authorization: {\n delegate: string\n signHash: string\n signature: string | null\n /**\n * #3418: which digest the delegate signed — selects what offline\n * verification rebuilds. `'eip712_delegation'`: the settlement\n * delegation's EIP-712 digest (erc7710). `'eip712_userop'`: an ERC-4337\n * user-operation digest the bundle does not carry (direct payments, the\n * eip3009 funding leg) — not verifiable offline. Absent on retired-rail\n * bundles and on backends older than #3418, whose `signHash` was signed\n * raw. The value is only a selector: a lying one cannot make a forged\n * signature verify, because recovery must still return `delegate`.\n */\n signatureScheme?: 'eip712_delegation' | 'eip712_userop'\n }\n onChain: {\n txHash: string | null\n chainId: number\n }\n}\n\nexport type ReceiptVerification =\n | { verified: true; recoveredSigner: string; verifiedOver: 'sign_hash' | 'delegation_digest' }\n | {\n verified: false\n reason:\n /** #3418: the input is not a haven-receipt-1 bundle (a haven_list_receipts row, null, undefined, a non-object). */\n | 'not_a_signed_receipt'\n /** #3418: eip712_userop bundle; or a delegation bundle on a chain the SDK pins no DelegationManager for. */\n | 'not_verifiable_offline'\n | 'missing_signature'\n | 'bad_signature'\n | 'signer_mismatch'\n recoveredSigner?: string\n }\n\n/** Chains whose DelegationManager the SDK pins (same address on both — rails/delegation-contracts.ts). */\nconst DELEGATION_MANAGER_CHAIN_IDS: ReadonlySet<number> = new Set([8453, 84532])\n\nconst EIP712_DOMAIN_TYPEHASH = keccak256(\n toBytes('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),\n)\n\n/**\n * The EIP-712 domain separator of the DelegationManager on `chainId`, rebuilt\n * from the manager's own constants (name/version, fixed in the contract) and\n * the address the SDK pins — never from a value the receipt vouches for.\n */\nfunction delegationDomainSeparator(chainId: number): Hex {\n return keccak256(\n encodeAbiParameters(\n [{ type: 'bytes32' }, { type: 'bytes32' }, { type: 'bytes32' }, { type: 'uint256' }, { type: 'address' }],\n [\n EIP712_DOMAIN_TYPEHASH,\n keccak256(toBytes('DelegationManager')),\n keccak256(toBytes('1')),\n BigInt(chainId),\n DELEGATION_MANAGER as Hex,\n ],\n ),\n )\n}\n\n/** The EIP-712 digest over a delegation struct hash (what the delegate signs). */\nfunction delegationDigest(structHash: string, chainId: number): Hex {\n return keccak256(concatHex(['0x1901', delegationDomainSeparator(chainId), structHash as Hex]))\n}\n\n/** Default ECDSA recovery (raw ecrecover over the hash, no message prefix). */\nfunction defaultRecover(hash: string, signature: string): string {\n return ethers.recoverAddress(hash, signature)\n}\n\nconst NOT_A_SIGNED_RECEIPT = { verified: false, reason: 'not_a_signed_receipt' } as const\n\ntype RecoverFn = (hash: string, signature: string) => string\n\ntype MatchResult =\n | { ok: true; recoveredSigner: string }\n | { ok: false; reason: 'bad_signature' | 'signer_mismatch'; recoveredSigner?: string }\n\n/** Recover over one candidate hash and compare the signer with the named delegate. */\nfunction match(delegate: string, hash: string, signature: string, recover: RecoverFn): MatchResult {\n let recovered: string\n try {\n recovered = recover(hash, signature)\n } catch {\n return { ok: false, reason: 'bad_signature' }\n }\n if (recovered.toLowerCase() !== delegate.toLowerCase()) {\n return { ok: false, reason: 'signer_mismatch', recoveredSigner: recovered }\n }\n return { ok: true, recoveredSigner: recovered }\n}\n\nfunction finish(result: MatchResult, verifiedOver: 'sign_hash' | 'delegation_digest'): ReceiptVerification {\n if (result.ok) {\n return { verified: true, recoveredSigner: result.recoveredSigner, verifiedOver }\n }\n return result.recoveredSigner !== undefined\n ? { verified: false, reason: result.reason, recoveredSigner: result.recoveredSigner }\n : { verified: false, reason: result.reason }\n}\n\n/**\n * Verify a receipt's agent authorisation offline: recover the signer and\n * confirm it is the agent delegate, over whichever digest the bundle's scheme\n * names (see the module doc for what that proves — and what it does not).\n * Never throws: anything that is not a signed receipt — a\n * `haven_list_receipts` history row, null, undefined, a non-object — returns\n * `not_a_signed_receipt`. The `{ receipt, verification }` wrapper the receipt\n * endpoint returns is accepted as-is: `.receipt` is verified, and the\n * wrapper's `verification` — Haven's own self-check — is never read. Pure —\n * `recover` is injectable but defaults to\n * standard ECDSA recovery, so this runs anywhere (no Haven backend).\n */\nexport function verifyPaymentReceipt(\n receipt: unknown,\n recover: RecoverFn = defaultRecover,\n): ReceiptVerification {\n // #3418 rule 1: a list row (or any non-bundle) has no authorization object\n // holding string delegate/signHash — answer, never throw.\n if (typeof receipt !== 'object' || receipt === null) return NOT_A_SIGNED_RECEIPT\n let source = receipt as {\n authorization?: unknown\n receipt?: unknown\n onChain?: { chainId?: unknown }\n }\n // #3723: accept the endpoint's response as-is. When the top level carries no\n // `authorization` and `.receipt` is a non-null object, verify the bundle\n // inside the `{ receipt, verification }` wrapper (GET\n // /payments/{id}/receipt, and HavenClient.getReceipt's re-wrap). ONE level\n // only — no recursion — and the wrapper's `verification` is NEVER read: it\n // is Haven's own self-check, and trusting it would defeat an offline\n // verifier. A list row wrapped or bare still answers not_a_signed_receipt.\n if (typeof source.authorization !== 'object' || source.authorization === null) {\n if (typeof source.receipt !== 'object' || source.receipt === null) {\n return NOT_A_SIGNED_RECEIPT\n }\n source = source.receipt as typeof source\n }\n if (typeof source.authorization !== 'object' || source.authorization === null) {\n return NOT_A_SIGNED_RECEIPT\n }\n const auth = source.authorization as {\n delegate?: unknown\n signHash?: unknown\n signature?: unknown\n signatureScheme?: unknown\n }\n const { delegate, signHash, signature, signatureScheme } = auth\n if (typeof delegate !== 'string' || delegate === '' || typeof signHash !== 'string' || signHash === '') {\n return NOT_A_SIGNED_RECEIPT\n }\n if (typeof signature !== 'string' || signature === '') {\n return { verified: false, reason: 'missing_signature' }\n }\n\n const chainId =\n typeof source.onChain?.chainId === 'number' ? source.onChain.chainId : undefined\n const digestVerifiable = chainId !== undefined && DELEGATION_MANAGER_CHAIN_IDS.has(chainId)\n\n // #3418 rule 4: a userop digest needs the full UserOperation, which the\n // bundle does not carry. Return not_verifiable_offline — never\n // signer_mismatch, which would accuse a genuine payment.\n if (signatureScheme === 'eip712_userop') {\n return { verified: false, reason: 'not_verifiable_offline' }\n }\n\n // #3418 rule 3: rebuild the delegation digest from the pinned manager and\n // the bundle's chain id, then recover over it.\n if (signatureScheme === 'eip712_delegation') {\n if (!digestVerifiable) {\n return { verified: false, reason: 'not_verifiable_offline' }\n }\n let digest: string\n try {\n digest = delegationDigest(signHash, chainId as number)\n } catch {\n return { verified: false, reason: 'bad_signature' }\n }\n return finish(match(delegate, digest, signature, recover), 'delegation_digest')\n }\n\n // #3418 rule 5: absent or unknown scheme — retired-rail history (signed raw\n // over signHash) or a backend older than this change. Raw recovery first,\n // then the delegation digest when the chain allows rebuilding it. This is\n // the one remaining ambiguous case, limited to old bundles.\n const raw = match(delegate, signHash, signature, recover)\n if (raw.ok) return finish(raw, 'sign_hash')\n if (digestVerifiable) {\n let digest: string\n try {\n digest = delegationDigest(signHash, chainId as number)\n } catch {\n return finish(raw, 'sign_hash')\n }\n const delegated = match(delegate, digest, signature, recover)\n if (delegated.ok) return finish(delegated, 'delegation_digest')\n }\n return finish(raw, 'sign_hash')\n}\n"]}
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var chunkG5IJ74QS_cjs = require('./chunk-G5IJ74QS.cjs');
3
+ var chunkCETAFCIA_cjs = require('./chunk-CETAFCIA.cjs');
4
4
  var viem = require('viem');
5
5
  var crypto = require('crypto');
6
6
  var secp256k1 = require('@noble/curves/secp256k1');
7
7
  var accounts = require('viem/accounts');
8
8
 
9
9
  var TYPED_DATA_NOT_ALLOWED = "TYPED_DATA_NOT_ALLOWED";
10
- var HavenTypedDataRefusedError = class extends chunkG5IJ74QS_cjs.HavenSigningError {
10
+ var HavenTypedDataRefusedError = class extends chunkCETAFCIA_cjs.HavenSigningError {
11
11
  constructor(message) {
12
12
  super(message);
13
13
  this.code = TYPED_DATA_NOT_ALLOWED;
@@ -48,7 +48,7 @@ function assertBoundDirectPaymentUserOp(typedData, delegateAddress) {
48
48
  `This signer only signs direct payments on chains the delegation rail has pinned contracts for (${[...DIRECT_PAYMENT_CHAIN_IDS].join(", ")}); this typed data names chain ${String(domain.chainId)}. Refusing.`
49
49
  );
50
50
  }
51
- const ownAccount = chunkG5IJ74QS_cjs.deriveDelegateAccountAddress(delegateAddress);
51
+ const ownAccount = chunkCETAFCIA_cjs.deriveDelegateAccountAddress(delegateAddress);
52
52
  const sender = typeof message.sender === "string" ? message.sender : "";
53
53
  if (sender.toLowerCase() !== ownAccount.toLowerCase()) {
54
54
  throw new HavenTypedDataRefusedError(
@@ -78,9 +78,9 @@ function assertBoundDirectPaymentUserOp(typedData, delegateAddress) {
78
78
  "This UserOperation's execute() call does not re-encode to the exact callData bytes (trailing or non-canonical bytes). Refusing."
79
79
  );
80
80
  }
81
- if (decoded.target.toLowerCase() !== chunkG5IJ74QS_cjs.DELEGATION_MANAGER.toLowerCase()) {
81
+ if (decoded.target.toLowerCase() !== chunkCETAFCIA_cjs.DELEGATION_MANAGER.toLowerCase()) {
82
82
  throw new HavenTypedDataRefusedError(
83
- `This UserOperation's execute() calls ${decoded.target}, not the DelegationManager (${chunkG5IJ74QS_cjs.DELEGATION_MANAGER}). A direct payment only ever redeems the agent's own budget delegation \u2014 refusing what looks like a self-call (e.g. transferOwnership, updateSigners, upgradeToAndCall) or a call to an unrelated contract.`
83
+ `This UserOperation's execute() calls ${decoded.target}, not the DelegationManager (${chunkCETAFCIA_cjs.DELEGATION_MANAGER}). A direct payment only ever redeems the agent's own budget delegation \u2014 refusing what looks like a self-call (e.g. transferOwnership, updateSigners, upgradeToAndCall) or a call to an unrelated contract.`
84
84
  );
85
85
  }
86
86
  if (decoded.value !== 0n) {
@@ -89,20 +89,20 @@ function assertBoundDirectPaymentUserOp(typedData, delegateAddress) {
89
89
  );
90
90
  }
91
91
  try {
92
- chunkG5IJ74QS_cjs.assertRedeemsOwnBudgetDelegation(decoded.callData, ownAccount);
92
+ chunkCETAFCIA_cjs.assertRedeemsOwnBudgetDelegation(decoded.callData, ownAccount);
93
93
  } catch (err) {
94
94
  throw new HavenTypedDataRefusedError(err instanceof Error ? err.message : String(err));
95
95
  }
96
96
  }
97
97
  function assertOwnSettlementChild(typedData, expectation, delegateAddress) {
98
98
  try {
99
- chunkG5IJ74QS_cjs.verifySettlementChild(typedData, {
99
+ chunkCETAFCIA_cjs.verifySettlementChild(typedData, {
100
100
  ...expectation,
101
- delegatorAccount: chunkG5IJ74QS_cjs.deriveDelegateAccountAddress(delegateAddress)
101
+ delegatorAccount: chunkCETAFCIA_cjs.deriveDelegateAccountAddress(delegateAddress)
102
102
  });
103
103
  } catch (err) {
104
104
  if (err instanceof HavenTypedDataRefusedError) throw err;
105
- if (err instanceof chunkG5IJ74QS_cjs.HavenSigningError) throw new HavenTypedDataRefusedError(err.message);
105
+ if (err instanceof chunkCETAFCIA_cjs.HavenSigningError) throw new HavenTypedDataRefusedError(err.message);
106
106
  throw new HavenTypedDataRefusedError(
107
107
  `Refusing to sign the x402 settlement child: it is malformed (${err instanceof Error ? err.message : String(err)}).`
108
108
  );
@@ -131,7 +131,7 @@ function assertFundingLegPaysDelegate(typedData, expected) {
131
131
  try {
132
132
  const { args: executeArgs } = viem.decodeFunctionData({ abi: EXECUTE_ABI, data: message.callData });
133
133
  const inner = executeArgs[0].callData;
134
- const { args } = viem.decodeFunctionData({ abi: chunkG5IJ74QS_cjs.REDEEM_DELEGATIONS_ABI, data: inner });
134
+ const { args } = viem.decodeFunctionData({ abi: chunkCETAFCIA_cjs.REDEEM_DELEGATIONS_ABI, data: inner });
135
135
  const executions = args[2];
136
136
  executionCallData = executions[0];
137
137
  } catch {
@@ -250,7 +250,7 @@ var TRANSFER_WITH_AUTHORIZATION_TYPES = {
250
250
  function sweepUsdcAddress(chainId) {
251
251
  const address = USDC_ADDRESS_BY_CHAIN[chainId];
252
252
  if (!address) {
253
- throw new chunkG5IJ74QS_cjs.HavenSigningError(
253
+ throw new chunkCETAFCIA_cjs.HavenSigningError(
254
254
  `Sweep is not supported on chain ${chainId}. Supported: ${SWEEPABLE_CHAIN_IDS.join(", ")}.`
255
255
  );
256
256
  }
@@ -259,7 +259,7 @@ function sweepUsdcAddress(chainId) {
259
259
  function sweepUsdcDomain(chainId) {
260
260
  const domain = USDC_EIP712_DOMAIN_BY_CHAIN[chainId];
261
261
  if (!domain) {
262
- throw new chunkG5IJ74QS_cjs.HavenSigningError(
262
+ throw new chunkCETAFCIA_cjs.HavenSigningError(
263
263
  `Sweep is not supported on chain ${chainId}. Supported: ${SWEEPABLE_CHAIN_IDS.join(", ")}.`
264
264
  );
265
265
  }
@@ -272,12 +272,12 @@ function buildSweepTypedData(auth) {
272
272
  const domain = sweepUsdcDomain(auth.chainId);
273
273
  const expectedToken = sweepUsdcAddress(auth.chainId);
274
274
  if (!sameAddress(auth.token, expectedToken)) {
275
- throw new chunkG5IJ74QS_cjs.HavenSigningError(
275
+ throw new chunkCETAFCIA_cjs.HavenSigningError(
276
276
  `Sweep token ${auth.token} is not the canonical USDC contract for chain ${auth.chainId}.`
277
277
  );
278
278
  }
279
279
  if (!/^0x[0-9a-fA-F]{64}$/.test(auth.nonce)) {
280
- throw new chunkG5IJ74QS_cjs.HavenSigningError("Sweep nonce must be a 0x-prefixed 32-byte hex string.");
280
+ throw new chunkCETAFCIA_cjs.HavenSigningError("Sweep nonce must be a 0x-prefixed 32-byte hex string.");
281
281
  }
282
282
  return {
283
283
  domain,
@@ -782,7 +782,7 @@ function stableStringify2(value) {
782
782
  }
783
783
 
784
784
  // src/client-identity.ts
785
- var SDK_VERSION = "0.0.0-dev.202610091112.2d759b4";
785
+ var SDK_VERSION = "0.0.0-dev.202610091605.1bb6937";
786
786
  var HAVEN_CLIENT_HEADER = "X-Haven-Client";
787
787
  function havenClientIdentity(pkg, version) {
788
788
  return `${pkg}/${version}`;
@@ -815,7 +815,7 @@ function addressFromKey(privateKey) {
815
815
  try {
816
816
  return accounts.privateKeyToAddress(`0x${hexBytes(privateKey, 32, "private key")}`);
817
817
  } catch (err) {
818
- throw new chunkG5IJ74QS_cjs.HavenSigningError(
818
+ throw new chunkCETAFCIA_cjs.HavenSigningError(
819
819
  `Invalid private key: ${err instanceof Error ? err.message : String(err)}`
820
820
  );
821
821
  }
@@ -829,7 +829,7 @@ function signHash(privateKey, hash) {
829
829
  yParity: recovery
830
830
  });
831
831
  } catch (err) {
832
- throw new chunkG5IJ74QS_cjs.HavenSigningError(
832
+ throw new chunkCETAFCIA_cjs.HavenSigningError(
833
833
  `Failed to sign hash: ${err instanceof Error ? err.message : String(err)}`
834
834
  );
835
835
  }
@@ -865,7 +865,7 @@ var TAX_DECLARATION_TYPES = {
865
865
  var X_TAX_DECLARATION_HEADER = "X-Tax-Declaration";
866
866
  function validateContent(content) {
867
867
  if (typeof content !== "object" || content === null || Array.isArray(content)) {
868
- throw new chunkG5IJ74QS_cjs.HavenSigningError("Tax declaration content must be an object.");
868
+ throw new chunkCETAFCIA_cjs.HavenSigningError("Tax declaration content must be an object.");
869
869
  }
870
870
  const record = content;
871
871
  for (const field of ["principalId", "principalAttributionHash"]) {
@@ -918,7 +918,7 @@ function taxPrincipalId(network, delegateAddress) {
918
918
  if (network.startsWith("eip155:")) {
919
919
  return `did:pkh:${network}:${delegateAddress}`;
920
920
  }
921
- const chainId = chunkG5IJ74QS_cjs.chainIdForNetwork(network);
921
+ const chainId = chunkCETAFCIA_cjs.chainIdForNetwork(network);
922
922
  if (chainId === void 0) {
923
923
  throw new TaxDeclarationRefusedError(
924
924
  `The accepted payment option's network '${network}' is not a CAIP-2 eip155 chain this SDK can name; refusing to build a tax principal without the settlement network.`
@@ -963,12 +963,12 @@ function addressFromKeyForTax(delegateKey) {
963
963
  try {
964
964
  return addressFromKey(delegateKey);
965
965
  } catch (err) {
966
- throw new chunkG5IJ74QS_cjs.HavenSigningError(
966
+ throw new chunkCETAFCIA_cjs.HavenSigningError(
967
967
  `Invalid delegate key for tax declaration signing: ${err instanceof Error ? err.message : String(err)}`
968
968
  );
969
969
  }
970
970
  }
971
- var TaxDeclarationRefusedError = class extends chunkG5IJ74QS_cjs.HavenSigningError {
971
+ var TaxDeclarationRefusedError = class extends chunkCETAFCIA_cjs.HavenSigningError {
972
972
  code = "TAX_DECLARATION_REFUSED";
973
973
  constructor(message) {
974
974
  super(message);
@@ -1120,10 +1120,10 @@ function assertOwnTaskChild(typedData, expected, delegateAddress, now = Date.now
1120
1120
  if (td?.primaryType !== "Delegation") {
1121
1121
  refuseTaskChild("it is not a Delegation payload", `primaryType was '${String(td?.primaryType)}'.`);
1122
1122
  }
1123
- if (!same(td.domain?.verifyingContract, chunkG5IJ74QS_cjs.DELEGATION_MANAGER)) {
1123
+ if (!same(td.domain?.verifyingContract, chunkCETAFCIA_cjs.DELEGATION_MANAGER)) {
1124
1124
  refuseTaskChild(
1125
1125
  "the EIP-712 domain names an unknown DelegationManager",
1126
- `Expected ${chunkG5IJ74QS_cjs.DELEGATION_MANAGER}, got ${td.domain?.verifyingContract}.`
1126
+ `Expected ${chunkCETAFCIA_cjs.DELEGATION_MANAGER}, got ${td.domain?.verifyingContract}.`
1127
1127
  );
1128
1128
  }
1129
1129
  if (td.domain?.name !== DELEGATION_DOMAIN_NAME || td.domain?.version !== DELEGATION_DOMAIN_VERSION) {
@@ -1151,7 +1151,7 @@ function assertOwnTaskChild(typedData, expected, delegateAddress, now = Date.now
1151
1151
  `Expected chain ${expected.chainId}; the child says ${td.domain?.chainId}.`
1152
1152
  );
1153
1153
  }
1154
- const ownAccount = chunkG5IJ74QS_cjs.deriveDelegateAccountAddress(delegateAddress);
1154
+ const ownAccount = chunkCETAFCIA_cjs.deriveDelegateAccountAddress(delegateAddress);
1155
1155
  const delegator = td.message?.delegator;
1156
1156
  if (typeof delegator !== "string" || !same(delegator, ownAccount)) {
1157
1157
  refuseTaskChild(
@@ -1170,7 +1170,7 @@ function assertOwnTaskChild(typedData, expected, delegateAddress, now = Date.now
1170
1170
  if (typeof authority !== "string" || !/^0x[0-9a-fA-F]{64}$/.test(authority)) {
1171
1171
  refuseTaskChild("its authority is not a 32-byte delegation hash", `Got ${String(authority)}.`);
1172
1172
  }
1173
- if (authority.toLowerCase() === chunkG5IJ74QS_cjs.ROOT_AUTHORITY) {
1173
+ if (authority.toLowerCase() === chunkCETAFCIA_cjs.ROOT_AUTHORITY) {
1174
1174
  refuseTaskChild(
1175
1175
  "it is a ROOT delegation, not a re-delegation of the agent budget",
1176
1176
  "A task budget always chains under the agent budget delegation."
@@ -1183,7 +1183,7 @@ function assertOwnTaskChild(typedData, expected, delegateAddress, now = Date.now
1183
1183
  );
1184
1184
  }
1185
1185
  const caveats = td.message?.caveats ?? [];
1186
- const transfer = findCaveat(caveats, chunkG5IJ74QS_cjs.CAVEAT_ENFORCERS.erc20TransferAmount);
1186
+ const transfer = findCaveat(caveats, chunkCETAFCIA_cjs.CAVEAT_ENFORCERS.erc20TransferAmount);
1187
1187
  if (!transfer) {
1188
1188
  refuseTaskChild(
1189
1189
  "it has no ERC-20 transfer-amount caveat",
@@ -1201,7 +1201,7 @@ function assertOwnTaskChild(typedData, expected, delegateAddress, now = Date.now
1201
1201
  `Expected ${expected.maxAmountAtomic}; the child allows ${amount.toString()}.`
1202
1202
  );
1203
1203
  }
1204
- const timestamp = findCaveat(caveats, chunkG5IJ74QS_cjs.CAVEAT_ENFORCERS.timestamp);
1204
+ const timestamp = findCaveat(caveats, chunkCETAFCIA_cjs.CAVEAT_ENFORCERS.timestamp);
1205
1205
  if (!timestamp) {
1206
1206
  refuseTaskChild("it never expires", "A task-budget child without a timestamp caveat is open-ended.");
1207
1207
  }
@@ -1222,7 +1222,7 @@ function assertOwnTaskChild(typedData, expected, delegateAddress, now = Date.now
1222
1222
  `Expected ${expected.expiresAt}; the child says ${beforeThreshold}.`
1223
1223
  );
1224
1224
  }
1225
- const calldata = findCaveat(caveats, chunkG5IJ74QS_cjs.CAVEAT_ENFORCERS.allowedCalldata);
1225
+ const calldata = findCaveat(caveats, chunkCETAFCIA_cjs.CAVEAT_ENFORCERS.allowedCalldata);
1226
1226
  if (expected.recipientAddress) {
1227
1227
  if (!calldata) {
1228
1228
  refuseTaskChild(
@@ -1259,7 +1259,7 @@ var DISABLE_DELEGATION_ABI = [
1259
1259
  {
1260
1260
  type: "function",
1261
1261
  name: "disableDelegation",
1262
- inputs: [{ name: "delegation", type: "tuple", components: chunkG5IJ74QS_cjs.DELEGATION_TUPLE_COMPONENTS }],
1262
+ inputs: [{ name: "delegation", type: "tuple", components: chunkCETAFCIA_cjs.DELEGATION_TUPLE_COMPONENTS }],
1263
1263
  outputs: [],
1264
1264
  stateMutability: "nonpayable"
1265
1265
  }
@@ -1278,7 +1278,7 @@ function assertOwnTaskBudgetCloseUserOp(typedData, expected, delegateAddress) {
1278
1278
  `This signer only signs a task-budget close on chains the delegation rail has pinned contracts for (${[...DIRECT_PAYMENT_CHAIN_IDS].join(", ")}); this typed data names chain ${String(domain.chainId)}. Refusing.`
1279
1279
  );
1280
1280
  }
1281
- const ownAccount = chunkG5IJ74QS_cjs.deriveDelegateAccountAddress(delegateAddress);
1281
+ const ownAccount = chunkCETAFCIA_cjs.deriveDelegateAccountAddress(delegateAddress);
1282
1282
  const sender = typeof message.sender === "string" ? message.sender : "";
1283
1283
  if (sender.toLowerCase() !== ownAccount.toLowerCase()) {
1284
1284
  throw new HavenTypedDataRefusedError(
@@ -1301,9 +1301,9 @@ function assertOwnTaskBudgetCloseUserOp(typedData, expected, delegateAddress) {
1301
1301
  "This close UserOperation's execute() call does not re-encode to the exact callData bytes (trailing or non-canonical bytes). Refusing."
1302
1302
  );
1303
1303
  }
1304
- if (decoded.target.toLowerCase() !== chunkG5IJ74QS_cjs.DELEGATION_MANAGER.toLowerCase()) {
1304
+ if (decoded.target.toLowerCase() !== chunkCETAFCIA_cjs.DELEGATION_MANAGER.toLowerCase()) {
1305
1305
  throw new HavenTypedDataRefusedError(
1306
- `This close UserOperation's execute() calls ${decoded.target}, not the DelegationManager (${chunkG5IJ74QS_cjs.DELEGATION_MANAGER}). Refusing what looks like a self-call or a call to an unrelated contract.`
1306
+ `This close UserOperation's execute() calls ${decoded.target}, not the DelegationManager (${chunkCETAFCIA_cjs.DELEGATION_MANAGER}). Refusing what looks like a self-call or a call to an unrelated contract.`
1307
1307
  );
1308
1308
  }
1309
1309
  if (decoded.value !== 0n) {
@@ -1340,7 +1340,7 @@ function assertOwnTaskBudgetCloseUserOp(typedData, expected, delegateAddress) {
1340
1340
  `This close UserOperation disables a delegation granted to ${delegation.delegate}, not this signer's own account (${ownAccount}) \u2014 a task-budget child is always self-delegated. Refusing.`
1341
1341
  );
1342
1342
  }
1343
- if (delegation.authority.toLowerCase() === chunkG5IJ74QS_cjs.ROOT_AUTHORITY) {
1343
+ if (delegation.authority.toLowerCase() === chunkCETAFCIA_cjs.ROOT_AUTHORITY) {
1344
1344
  throw new HavenTypedDataRefusedError(
1345
1345
  "This close UserOperation disables a ROOT delegation, not a re-delegation of the agent budget. A task-budget child always chains under the agent budget delegation. Refusing."
1346
1346
  );
@@ -1471,5 +1471,5 @@ exports.x402PaymentHeaderNamesFor = x402PaymentHeaderNamesFor;
1471
1471
  exports.x402PaymentHeaderNamesSent = x402PaymentHeaderNamesSent;
1472
1472
  exports.x402RetryHeadersFor = x402RetryHeadersFor;
1473
1473
  exports.x402V2PaymentEnvelope = x402V2PaymentEnvelope;
1474
- //# sourceMappingURL=chunk-AYAVDHWH.cjs.map
1475
- //# sourceMappingURL=chunk-AYAVDHWH.cjs.map
1474
+ //# sourceMappingURL=chunk-7IXXN7CR.cjs.map
1475
+ //# sourceMappingURL=chunk-7IXXN7CR.cjs.map