@haven_ai/sdk 0.9.0-alpha.0 → 0.11.0-alpha.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.
Files changed (38) hide show
  1. package/README.md +9 -6
  2. package/dist/{base64-BZDPJ8M1.d.ts → base64-D4VZhgUg.d.ts} +11 -3
  3. package/dist/{base64-Cyxhsvqd.d.cts → base64-DR4Gl8cD.d.cts} +11 -3
  4. package/dist/{chunk-VRKWNJ7H.js → chunk-34YJQFCM.js} +3 -3
  5. package/dist/{chunk-VRKWNJ7H.js.map → chunk-34YJQFCM.js.map} +1 -1
  6. package/dist/{chunk-7UTWSJC5.cjs → chunk-DXBAN4SN.cjs} +4 -4
  7. package/dist/{chunk-7UTWSJC5.cjs.map → chunk-DXBAN4SN.cjs.map} +1 -1
  8. package/dist/{chunk-J7N4LUZZ.js → chunk-I7SL4A6X.js} +23 -5
  9. package/dist/chunk-I7SL4A6X.js.map +1 -0
  10. package/dist/{chunk-ZDKNPNI3.cjs → chunk-IKQIIMM6.cjs} +41 -35
  11. package/dist/chunk-IKQIIMM6.cjs.map +1 -0
  12. package/dist/{chunk-4Z6ATE44.cjs → chunk-MZKLAHBK.cjs} +23 -5
  13. package/dist/chunk-MZKLAHBK.cjs.map +1 -0
  14. package/dist/{chunk-424S4QMG.js → chunk-ZDJ55LR7.js} +10 -6
  15. package/dist/chunk-ZDJ55LR7.js.map +1 -0
  16. package/dist/edge.cjs +99 -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 +861 -459
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +88 -27
  23. package/dist/index.d.ts +88 -27
  24. package/dist/index.js +541 -148
  25. package/dist/index.js.map +1 -1
  26. package/dist/{receipt-WkXHZGbu.d.ts → receipt-CbD8L0WL.d.ts} +1 -1
  27. package/dist/{receipt-D4Roey3D.d.cts → receipt-_bWCELEH.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.cts → types-DKmvjXK6.d.cts} +96 -12
  33. package/dist/{types-CrszUJ7Z.d.ts → types-DKmvjXK6.d.ts} +96 -12
  34. package/package.json +1 -1
  35. package/dist/chunk-424S4QMG.js.map +0 -1
  36. package/dist/chunk-4Z6ATE44.cjs.map +0 -1
  37. package/dist/chunk-J7N4LUZZ.js.map +0 -1
  38. package/dist/chunk-ZDKNPNI3.cjs.map +0 -1
package/README.md CHANGED
@@ -98,11 +98,14 @@ shows up in your Haven dashboard activity feed.
98
98
  ## Step-by-Step API
99
99
 
100
100
  Discovery and listing: `discoverTools({ verified?: 'any' | 'verified' | 'operator' })` returns the merged
101
- catalog — operator-curated rows plus self-submitted directory entries (epic #1717), each with `source`,
102
- `domainVerified` and `verifiedPayable`. `verified: 'verified'` (#2978) filters on the badge, not the
103
- source: it returns any entry, from either source, whose endpoint Haven watched answer a live quote
104
- probe (`verifiedPayable === true`); `domainVerified` stays true only for entries that also proved
105
- domain ownership. `verified: 'operator'` filters on provenance alone. `submitCatalogEntry(resourceUrl)`
101
+ catalog from three sources, each entry with `source`, `domainVerified` and `verifiedPayable`:
102
+ operator-curated rows (`source: 'operator'`), self-submitted directory entries (`'ingestion'`, epic
103
+ #1717), and rows the x402 Bazaar discovery cron wrote (`'bazaar'`, #4245; seller-asserted name and
104
+ description, only where a deployment enables discovery). `verified: 'verified'` (#2978) filters on the
105
+ badge, not the source: it returns any entry, from any source, whose endpoint Haven watched answer a
106
+ live quote probe (`verifiedPayable === true`); `domainVerified` stays true only for directory entries,
107
+ which also proved domain ownership. `verified: 'operator'` filters on provenance alone and returns
108
+ operator-curated rows only. `submitCatalogEntry(resourceUrl)`
106
109
  submits a merchant endpoint to the Verified Payable Directory (queue-only; the seller still must prove
107
110
  domain ownership before listing),
108
111
  and `getCatalogSubmissionStatus(id)` returns coarse status plus the ownership-proof instructions while
@@ -454,7 +457,7 @@ Hosted MCP and signer tools also return stable `code` values on recoverable x402
454
457
  | `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
458
  | `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
459
  | `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`. |
460
+ | `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
461
  | `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
462
  | `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
463
  | `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, aM as X402PaymentOption, aL as X402ExpectedContext, X as X402PaymentRequired, I as HavenError, an as HavenSigningError } from './types-DKmvjXK6.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.9.0-alpha.0";
203
+ declare const SDK_VERSION = "0.11.0-alpha.0";
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}. */
@@ -846,6 +846,14 @@ declare function resolveTokenBySymbol(chainId: number, symbol: string): {
846
846
  decimals: number;
847
847
  } | null;
848
848
 
849
+ /** The fixed domain tag. Changing it orphans every settlement not yet detected. */
850
+ declare const X402_PAYMENT_NONCE_TAG = "haven-x402-payment-nonce:";
851
+ /**
852
+ * Derive the EIP-3009 nonce for a Haven payment id. Same input, same output,
853
+ * on every surface that imports this — the signer, the SDK and the backend.
854
+ */
855
+ declare function deriveX402PaymentNonce(paymentId: string): `0x${string}`;
856
+
849
857
  /**
850
858
  * #3271: the integrity check every client runs before signing a direct
851
859
  * delegation-rail payment's typed data.
@@ -1341,4 +1349,4 @@ declare function encodeBase64Json(value: unknown): string;
1341
1349
  */
1342
1350
  declare function decodeBase64Json<T>(value: string, label?: string): T;
1343
1351
 
1344
- export { X402_PAYMENT_HEADER_NAMES_SENT as $, type SweepEip712Domain as A, type SweepExpectedAuth as B, CONNECTOR_PACKAGE_NAME as C, DEFAULT_NEXT_TOOL_BY_ACTION as D, ENTRY_POINT_V07 as E, type SweepPreparation as F, type SweepSubmitResult as G, type HavenClientUpdate as H, type SweepTypedData as I, TRANSFER_WITH_AUTHORIZATION_TYPES as J, TYPED_DATA_NOT_ALLOWED as K, type TaskBudgetCloseExpectation as L, MAX_TASK_BUDGET_TTL_SECONDS as M, NEXT_TOOL_SERVER_NAMES as N, type TaskChildExpectation as O, PACKED_USER_OPERATION_FIELDS as P, type TaskChildTypedData as Q, ROOT_AUTHORITY as R, type SweepPrepareResponse as S, TASK_SIGN_CONTEXT_VERSION as T, type UnsupportedNodeVersionMessageOptions as U, X402PaymentHeaderValidationError as V, type X402SchemeSelection as W, type X402PaymentHeaderContext as X, X402_LEGACY_PAYMENT_HEADER_NAME as Y, X402_MAX_AUTHORIZATION_WINDOW_SECONDS as Z, X402_PAYMENT_HEADER_NAME as _, type SweepAuthorization as a, HYBRID_DELEGATOR_IMPLEMENTATION as a$, X402_PAYMENT_REQUIRED_HEADER_NAME as a0, X402_PAYMENT_RESPONSE_HEADER_NAME as a1, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS as a2, assertBoundDirectPaymentUserOp as a3, assertOwnTaskBudgetCloseUserOp as a4, assertOwnTaskChild as a5, assertUserOpTypedDataBinding as a6, buildSweepAuthorizationMessage as a7, buildSweepTypedData as a8, buildX402ExpectedMessage as a9, renderNextTool as aA, resolveConnectorChannel as aB, resolveTokenBySymbol as aC, resolveTokenFromAddress as aD, selectErc7710PaymentOption as aE, selectPaymentOption as aF, selectStandardPaymentOption as aG, selectX402SettlementScheme as aH, sweepUsdcAddress as aI, sweepUsdcDomain as aJ, toStandardPaymentRequirements as aK, unsupportedNodeVersionMessage as aL, validateStandardX402PaymentHeader as aM, verifySettlementChild as aN, x402AssetTransferMethod as aO, x402AuthorizationAmount as aP, x402FacilitatorAddresses as aQ, x402PaymentHeaderNamesFor as aR, x402RetryHeadersFor as aS, x402V2PaymentEnvelope as aT, type DelegationForHashing as aU, CAVEAT_ENFORCERS as aV, CAVEAT_TYPEHASH as aW, DELEGATION_MANAGER as aX, DELEGATION_TYPEHASH as aY, DIRECT_PAYMENT_CHAIN_IDS as aZ, EXECUTE_ABI as a_, compareNodeVersions as aa, connectorRerunCommand as ab, connectorSpec as ac, connectorUpgradeCommand as ad, createNextStepBuilder as ae, decodeBase64Json as af, decodeBase64Utf8 as ag, defaultNextToolFor as ah, deriveDelegateAccountAddress as ai, encodeBase64Json as aj, encodeBase64Utf8 as ak, encodePaymentProof as al, hashDelegation as am, havenClientIdentity as an, isConnectorChannel as ao, isErc7710Option as ap, isPackedUserOperationTypedData as aq, isSupportedNodeVersion as ar, isSweepableChain as as, isTaskChildTypedData as at, normalizePaymentRequired as au, packedUserOperationHash as av, parseNextTool as aw, parsePaymentRequired as ax, parsePaymentRequiredResponse as ay, readClientUpdate as az, type SweepSubmitResponse as b, MAX_SETTLEMENT_WINDOW_SECONDS as b0, SIMPLE_FACTORY_ADDRESS as b1, type SettlementChildTypedData as b2, assertFundingLegPaysDelegate as b3, assertOwnSettlementChild as b4, chainIdForNetwork as b5, isSettlementChildTypedData as b6, DIRECT_SIGN_CONTEXT_VERSION as c, ERC7710_ASSET_TRANSFER_METHOD as d, HAVEN_CLIENT_HEADER as e, HAVEN_CONNECTOR_CHANNEL as f, HAVEN_MINIMUM_NODE_VERSION as g, HYBRID_DELEGATOR_DOMAIN_NAME as h, HYBRID_DELEGATOR_DOMAIN_VERSION as i, HavenTypedDataRefusedError as j, HavenUserOpBindingError as k, NEXT_TOOL_SERVER_ROLES as l, type NextStep as m, type NextStepArguments as n, type NextStepHandoff as o, type NextStepInput as p, type NextStepTarget as q, type NextStepTargets as r, type NextToolServerRole as s, SDK_CLIENT_IDENTITY as t, SDK_VERSION as u, SWEEP_BASE_CHAIN_ID as v, SWEEP_BASE_SEPOLIA_CHAIN_ID as w, SWEEP_BASE_SEPOLIA_USDC_ADDRESS as x, SWEEP_BASE_USDC_ADDRESS as y, type SettlementChildExpectation as z };
1352
+ export { X402_PAYMENT_HEADER_NAMES_SENT as $, type SweepEip712Domain as A, type SweepExpectedAuth as B, CONNECTOR_PACKAGE_NAME as C, DEFAULT_NEXT_TOOL_BY_ACTION as D, ENTRY_POINT_V07 as E, type SweepPreparation as F, type SweepSubmitResult as G, type HavenClientUpdate as H, type SweepTypedData as I, TRANSFER_WITH_AUTHORIZATION_TYPES as J, TYPED_DATA_NOT_ALLOWED as K, type TaskBudgetCloseExpectation as L, MAX_TASK_BUDGET_TTL_SECONDS as M, NEXT_TOOL_SERVER_NAMES as N, type TaskChildExpectation as O, PACKED_USER_OPERATION_FIELDS as P, type TaskChildTypedData as Q, ROOT_AUTHORITY as R, type SweepPrepareResponse as S, TASK_SIGN_CONTEXT_VERSION as T, type UnsupportedNodeVersionMessageOptions as U, X402PaymentHeaderValidationError as V, type X402SchemeSelection as W, type X402PaymentHeaderContext as X, X402_LEGACY_PAYMENT_HEADER_NAME as Y, X402_MAX_AUTHORIZATION_WINDOW_SECONDS as Z, X402_PAYMENT_HEADER_NAME as _, type SweepAuthorization as a, DIRECT_PAYMENT_CHAIN_IDS as a$, X402_PAYMENT_NONCE_TAG as a0, X402_PAYMENT_REQUIRED_HEADER_NAME as a1, X402_PAYMENT_RESPONSE_HEADER_NAME as a2, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS as a3, assertBoundDirectPaymentUserOp as a4, assertOwnTaskBudgetCloseUserOp as a5, assertOwnTaskChild as a6, assertUserOpTypedDataBinding as a7, buildSweepAuthorizationMessage as a8, buildSweepTypedData as a9, parsePaymentRequiredResponse as aA, readClientUpdate as aB, renderNextTool as aC, resolveConnectorChannel as aD, resolveTokenBySymbol as aE, resolveTokenFromAddress as aF, selectErc7710PaymentOption as aG, selectPaymentOption as aH, selectStandardPaymentOption as aI, selectX402SettlementScheme as aJ, sweepUsdcAddress as aK, sweepUsdcDomain as aL, toStandardPaymentRequirements as aM, unsupportedNodeVersionMessage as aN, validateStandardX402PaymentHeader as aO, verifySettlementChild as aP, x402AssetTransferMethod as aQ, x402AuthorizationAmount as aR, x402FacilitatorAddresses as aS, x402PaymentHeaderNamesFor as aT, x402RetryHeadersFor as aU, x402V2PaymentEnvelope as aV, type DelegationForHashing as aW, CAVEAT_ENFORCERS as aX, CAVEAT_TYPEHASH as aY, DELEGATION_MANAGER as aZ, DELEGATION_TYPEHASH as a_, buildX402ExpectedMessage as aa, compareNodeVersions as ab, connectorRerunCommand as ac, connectorSpec as ad, connectorUpgradeCommand as ae, createNextStepBuilder as af, decodeBase64Json as ag, decodeBase64Utf8 as ah, defaultNextToolFor as ai, deriveDelegateAccountAddress as aj, deriveX402PaymentNonce as ak, encodeBase64Json as al, encodeBase64Utf8 as am, encodePaymentProof as an, hashDelegation as ao, havenClientIdentity as ap, isConnectorChannel as aq, isErc7710Option as ar, isPackedUserOperationTypedData as as, isSupportedNodeVersion as at, isSweepableChain as au, isTaskChildTypedData as av, normalizePaymentRequired as aw, packedUserOperationHash as ax, parseNextTool as ay, parsePaymentRequired as az, type SweepSubmitResponse as b, EXECUTE_ABI as b0, HYBRID_DELEGATOR_IMPLEMENTATION as b1, MAX_SETTLEMENT_WINDOW_SECONDS as b2, SIMPLE_FACTORY_ADDRESS as b3, type SettlementChildTypedData as b4, assertFundingLegPaysDelegate as b5, assertOwnSettlementChild as b6, chainIdForNetwork as b7, isSettlementChildTypedData as b8, DIRECT_SIGN_CONTEXT_VERSION as c, ERC7710_ASSET_TRANSFER_METHOD as d, HAVEN_CLIENT_HEADER as e, HAVEN_CONNECTOR_CHANNEL as f, HAVEN_MINIMUM_NODE_VERSION as g, HYBRID_DELEGATOR_DOMAIN_NAME as h, HYBRID_DELEGATOR_DOMAIN_VERSION as i, HavenTypedDataRefusedError as j, HavenUserOpBindingError as k, NEXT_TOOL_SERVER_ROLES as l, type NextStep as m, type NextStepArguments as n, type NextStepHandoff as o, type NextStepInput as p, type NextStepTarget as q, type NextStepTargets as r, type NextToolServerRole as s, SDK_CLIENT_IDENTITY as t, SDK_VERSION as u, SWEEP_BASE_CHAIN_ID as v, SWEEP_BASE_SEPOLIA_CHAIN_ID as w, SWEEP_BASE_SEPOLIA_USDC_ADDRESS as x, SWEEP_BASE_USDC_ADDRESS as y, type SettlementChildExpectation as z };
@@ -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, aM as X402PaymentOption, aL as X402ExpectedContext, X as X402PaymentRequired, I as HavenError, an as HavenSigningError } from './types-DKmvjXK6.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.9.0-alpha.0";
203
+ declare const SDK_VERSION = "0.11.0-alpha.0";
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}. */
@@ -846,6 +846,14 @@ declare function resolveTokenBySymbol(chainId: number, symbol: string): {
846
846
  decimals: number;
847
847
  } | null;
848
848
 
849
+ /** The fixed domain tag. Changing it orphans every settlement not yet detected. */
850
+ declare const X402_PAYMENT_NONCE_TAG = "haven-x402-payment-nonce:";
851
+ /**
852
+ * Derive the EIP-3009 nonce for a Haven payment id. Same input, same output,
853
+ * on every surface that imports this — the signer, the SDK and the backend.
854
+ */
855
+ declare function deriveX402PaymentNonce(paymentId: string): `0x${string}`;
856
+
849
857
  /**
850
858
  * #3271: the integrity check every client runs before signing a direct
851
859
  * delegation-rail payment's typed data.
@@ -1341,4 +1349,4 @@ declare function encodeBase64Json(value: unknown): string;
1341
1349
  */
1342
1350
  declare function decodeBase64Json<T>(value: string, label?: string): T;
1343
1351
 
1344
- export { X402_PAYMENT_HEADER_NAMES_SENT as $, type SweepEip712Domain as A, type SweepExpectedAuth as B, CONNECTOR_PACKAGE_NAME as C, DEFAULT_NEXT_TOOL_BY_ACTION as D, ENTRY_POINT_V07 as E, type SweepPreparation as F, type SweepSubmitResult as G, type HavenClientUpdate as H, type SweepTypedData as I, TRANSFER_WITH_AUTHORIZATION_TYPES as J, TYPED_DATA_NOT_ALLOWED as K, type TaskBudgetCloseExpectation as L, MAX_TASK_BUDGET_TTL_SECONDS as M, NEXT_TOOL_SERVER_NAMES as N, type TaskChildExpectation as O, PACKED_USER_OPERATION_FIELDS as P, type TaskChildTypedData as Q, ROOT_AUTHORITY as R, type SweepPrepareResponse as S, TASK_SIGN_CONTEXT_VERSION as T, type UnsupportedNodeVersionMessageOptions as U, X402PaymentHeaderValidationError as V, type X402SchemeSelection as W, type X402PaymentHeaderContext as X, X402_LEGACY_PAYMENT_HEADER_NAME as Y, X402_MAX_AUTHORIZATION_WINDOW_SECONDS as Z, X402_PAYMENT_HEADER_NAME as _, type SweepAuthorization as a, HYBRID_DELEGATOR_IMPLEMENTATION as a$, X402_PAYMENT_REQUIRED_HEADER_NAME as a0, X402_PAYMENT_RESPONSE_HEADER_NAME as a1, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS as a2, assertBoundDirectPaymentUserOp as a3, assertOwnTaskBudgetCloseUserOp as a4, assertOwnTaskChild as a5, assertUserOpTypedDataBinding as a6, buildSweepAuthorizationMessage as a7, buildSweepTypedData as a8, buildX402ExpectedMessage as a9, renderNextTool as aA, resolveConnectorChannel as aB, resolveTokenBySymbol as aC, resolveTokenFromAddress as aD, selectErc7710PaymentOption as aE, selectPaymentOption as aF, selectStandardPaymentOption as aG, selectX402SettlementScheme as aH, sweepUsdcAddress as aI, sweepUsdcDomain as aJ, toStandardPaymentRequirements as aK, unsupportedNodeVersionMessage as aL, validateStandardX402PaymentHeader as aM, verifySettlementChild as aN, x402AssetTransferMethod as aO, x402AuthorizationAmount as aP, x402FacilitatorAddresses as aQ, x402PaymentHeaderNamesFor as aR, x402RetryHeadersFor as aS, x402V2PaymentEnvelope as aT, type DelegationForHashing as aU, CAVEAT_ENFORCERS as aV, CAVEAT_TYPEHASH as aW, DELEGATION_MANAGER as aX, DELEGATION_TYPEHASH as aY, DIRECT_PAYMENT_CHAIN_IDS as aZ, EXECUTE_ABI as a_, compareNodeVersions as aa, connectorRerunCommand as ab, connectorSpec as ac, connectorUpgradeCommand as ad, createNextStepBuilder as ae, decodeBase64Json as af, decodeBase64Utf8 as ag, defaultNextToolFor as ah, deriveDelegateAccountAddress as ai, encodeBase64Json as aj, encodeBase64Utf8 as ak, encodePaymentProof as al, hashDelegation as am, havenClientIdentity as an, isConnectorChannel as ao, isErc7710Option as ap, isPackedUserOperationTypedData as aq, isSupportedNodeVersion as ar, isSweepableChain as as, isTaskChildTypedData as at, normalizePaymentRequired as au, packedUserOperationHash as av, parseNextTool as aw, parsePaymentRequired as ax, parsePaymentRequiredResponse as ay, readClientUpdate as az, type SweepSubmitResponse as b, MAX_SETTLEMENT_WINDOW_SECONDS as b0, SIMPLE_FACTORY_ADDRESS as b1, type SettlementChildTypedData as b2, assertFundingLegPaysDelegate as b3, assertOwnSettlementChild as b4, chainIdForNetwork as b5, isSettlementChildTypedData as b6, DIRECT_SIGN_CONTEXT_VERSION as c, ERC7710_ASSET_TRANSFER_METHOD as d, HAVEN_CLIENT_HEADER as e, HAVEN_CONNECTOR_CHANNEL as f, HAVEN_MINIMUM_NODE_VERSION as g, HYBRID_DELEGATOR_DOMAIN_NAME as h, HYBRID_DELEGATOR_DOMAIN_VERSION as i, HavenTypedDataRefusedError as j, HavenUserOpBindingError as k, NEXT_TOOL_SERVER_ROLES as l, type NextStep as m, type NextStepArguments as n, type NextStepHandoff as o, type NextStepInput as p, type NextStepTarget as q, type NextStepTargets as r, type NextToolServerRole as s, SDK_CLIENT_IDENTITY as t, SDK_VERSION as u, SWEEP_BASE_CHAIN_ID as v, SWEEP_BASE_SEPOLIA_CHAIN_ID as w, SWEEP_BASE_SEPOLIA_USDC_ADDRESS as x, SWEEP_BASE_USDC_ADDRESS as y, type SettlementChildExpectation as z };
1352
+ export { X402_PAYMENT_HEADER_NAMES_SENT as $, type SweepEip712Domain as A, type SweepExpectedAuth as B, CONNECTOR_PACKAGE_NAME as C, DEFAULT_NEXT_TOOL_BY_ACTION as D, ENTRY_POINT_V07 as E, type SweepPreparation as F, type SweepSubmitResult as G, type HavenClientUpdate as H, type SweepTypedData as I, TRANSFER_WITH_AUTHORIZATION_TYPES as J, TYPED_DATA_NOT_ALLOWED as K, type TaskBudgetCloseExpectation as L, MAX_TASK_BUDGET_TTL_SECONDS as M, NEXT_TOOL_SERVER_NAMES as N, type TaskChildExpectation as O, PACKED_USER_OPERATION_FIELDS as P, type TaskChildTypedData as Q, ROOT_AUTHORITY as R, type SweepPrepareResponse as S, TASK_SIGN_CONTEXT_VERSION as T, type UnsupportedNodeVersionMessageOptions as U, X402PaymentHeaderValidationError as V, type X402SchemeSelection as W, type X402PaymentHeaderContext as X, X402_LEGACY_PAYMENT_HEADER_NAME as Y, X402_MAX_AUTHORIZATION_WINDOW_SECONDS as Z, X402_PAYMENT_HEADER_NAME as _, type SweepAuthorization as a, DIRECT_PAYMENT_CHAIN_IDS as a$, X402_PAYMENT_NONCE_TAG as a0, X402_PAYMENT_REQUIRED_HEADER_NAME as a1, X402_PAYMENT_RESPONSE_HEADER_NAME as a2, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS as a3, assertBoundDirectPaymentUserOp as a4, assertOwnTaskBudgetCloseUserOp as a5, assertOwnTaskChild as a6, assertUserOpTypedDataBinding as a7, buildSweepAuthorizationMessage as a8, buildSweepTypedData as a9, parsePaymentRequiredResponse as aA, readClientUpdate as aB, renderNextTool as aC, resolveConnectorChannel as aD, resolveTokenBySymbol as aE, resolveTokenFromAddress as aF, selectErc7710PaymentOption as aG, selectPaymentOption as aH, selectStandardPaymentOption as aI, selectX402SettlementScheme as aJ, sweepUsdcAddress as aK, sweepUsdcDomain as aL, toStandardPaymentRequirements as aM, unsupportedNodeVersionMessage as aN, validateStandardX402PaymentHeader as aO, verifySettlementChild as aP, x402AssetTransferMethod as aQ, x402AuthorizationAmount as aR, x402FacilitatorAddresses as aS, x402PaymentHeaderNamesFor as aT, x402RetryHeadersFor as aU, x402V2PaymentEnvelope as aV, type DelegationForHashing as aW, CAVEAT_ENFORCERS as aX, CAVEAT_TYPEHASH as aY, DELEGATION_MANAGER as aZ, DELEGATION_TYPEHASH as a_, buildX402ExpectedMessage as aa, compareNodeVersions as ab, connectorRerunCommand as ac, connectorSpec as ad, connectorUpgradeCommand as ae, createNextStepBuilder as af, decodeBase64Json as ag, decodeBase64Utf8 as ah, defaultNextToolFor as ai, deriveDelegateAccountAddress as aj, deriveX402PaymentNonce as ak, encodeBase64Json as al, encodeBase64Utf8 as am, encodePaymentProof as an, hashDelegation as ao, havenClientIdentity as ap, isConnectorChannel as aq, isErc7710Option as ar, isPackedUserOperationTypedData as as, isSupportedNodeVersion as at, isSweepableChain as au, isTaskChildTypedData as av, normalizePaymentRequired as aw, packedUserOperationHash as ax, parseNextTool as ay, parsePaymentRequired as az, type SweepSubmitResponse as b, EXECUTE_ABI as b0, HYBRID_DELEGATOR_IMPLEMENTATION as b1, MAX_SETTLEMENT_WINDOW_SECONDS as b2, SIMPLE_FACTORY_ADDRESS as b3, type SettlementChildTypedData as b4, assertFundingLegPaysDelegate as b5, assertOwnSettlementChild as b6, chainIdForNetwork as b7, isSettlementChildTypedData as b8, DIRECT_SIGN_CONTEXT_VERSION as c, ERC7710_ASSET_TRANSFER_METHOD as d, HAVEN_CLIENT_HEADER as e, HAVEN_CONNECTOR_CHANNEL as f, HAVEN_MINIMUM_NODE_VERSION as g, HYBRID_DELEGATOR_DOMAIN_NAME as h, HYBRID_DELEGATOR_DOMAIN_VERSION as i, HavenTypedDataRefusedError as j, HavenUserOpBindingError as k, NEXT_TOOL_SERVER_ROLES as l, type NextStep as m, type NextStepArguments as n, type NextStepHandoff as o, type NextStepInput as p, type NextStepTarget as q, type NextStepTargets as r, type NextToolServerRole as s, SDK_CLIENT_IDENTITY as t, SDK_VERSION as u, SWEEP_BASE_CHAIN_ID as v, SWEEP_BASE_SEPOLIA_CHAIN_ID as w, SWEEP_BASE_SEPOLIA_USDC_ADDRESS as x, SWEEP_BASE_USDC_ADDRESS as y, type SettlementChildExpectation as z };
@@ -1,4 +1,4 @@
1
- import { DELEGATION_MANAGER } from './chunk-J7N4LUZZ.js';
1
+ import { DELEGATION_MANAGER } from './chunk-I7SL4A6X.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-VRKWNJ7H.js.map
103
- //# sourceMappingURL=chunk-VRKWNJ7H.js.map
102
+ //# sourceMappingURL=chunk-34YJQFCM.js.map
103
+ //# sourceMappingURL=chunk-34YJQFCM.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/receipt.ts"],"names":[],"mappings":"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","file":"chunk-VRKWNJ7H.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-34YJQFCM.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,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk4Z6ATE44_cjs = require('./chunk-4Z6ATE44.cjs');
3
+ var chunkMZKLAHBK_cjs = require('./chunk-MZKLAHBK.cjs');
4
4
  var ethers = require('ethers');
5
5
  var viem = require('viem');
6
6
 
@@ -18,7 +18,7 @@ function delegationDomainSeparator(chainId) {
18
18
  viem.keccak256(viem.toBytes("DelegationManager")),
19
19
  viem.keccak256(viem.toBytes("1")),
20
20
  BigInt(chainId),
21
- chunk4Z6ATE44_cjs.DELEGATION_MANAGER
21
+ chunkMZKLAHBK_cjs.DELEGATION_MANAGER
22
22
  ]
23
23
  )
24
24
  );
@@ -102,5 +102,5 @@ function verifyPaymentReceipt(receipt, recover = defaultRecover) {
102
102
 
103
103
  exports.RECEIPT_VERSION = RECEIPT_VERSION;
104
104
  exports.verifyPaymentReceipt = verifyPaymentReceipt;
105
- //# sourceMappingURL=chunk-7UTWSJC5.cjs.map
106
- //# sourceMappingURL=chunk-7UTWSJC5.cjs.map
105
+ //# sourceMappingURL=chunk-DXBAN4SN.cjs.map
106
+ //# sourceMappingURL=chunk-DXBAN4SN.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/receipt.ts"],"names":["keccak256","toBytes","encodeAbiParameters","DELEGATION_MANAGER","concatHex","ethers"],"mappings":";;;;;;AA6CO,IAAM,eAAA,GAAkB;AA6E/B,IAAM,+CAAoD,IAAI,GAAA,CAAI,CAAC,IAAA,EAAM,KAAK,CAAC,CAAA;AAE/E,IAAM,sBAAA,GAAyBA,cAAA;AAAA,EAC7BC,aAAQ,oFAAoF;AAC9F,CAAA;AAOA,SAAS,0BAA0B,OAAA,EAAsB;AACvD,EAAA,OAAOD,cAAA;AAAA,IACLE,wBAAA;AAAA,MACE,CAAC,EAAE,IAAA,EAAM,SAAA,IAAa,EAAE,IAAA,EAAM,WAAU,EAAG,EAAE,MAAM,SAAA,EAAU,EAAG,EAAE,IAAA,EAAM,SAAA,IAAa,EAAE,IAAA,EAAM,WAAW,CAAA;AAAA,MACxG;AAAA,QACE,sBAAA;AAAA,QACAF,cAAA,CAAUC,YAAA,CAAQ,mBAAmB,CAAC,CAAA;AAAA,QACtCD,cAAA,CAAUC,YAAA,CAAQ,GAAG,CAAC,CAAA;AAAA,QACtB,OAAO,OAAO,CAAA;AAAA,QACdE;AAAA;AACF;AACF,GACF;AACF;AAGA,SAAS,gBAAA,CAAiB,YAAoB,OAAA,EAAsB;AAClE,EAAA,OAAOH,cAAA,CAAUI,eAAU,CAAC,QAAA,EAAU,0BAA0B,OAAO,CAAA,EAAG,UAAiB,CAAC,CAAC,CAAA;AAC/F;AAGA,SAAS,cAAA,CAAe,MAAc,SAAA,EAA2B;AAC/D,EAAA,OAAOC,aAAA,CAAO,cAAA,CAAe,IAAA,EAAM,SAAS,CAAA;AAC9C;AAEA,IAAM,oBAAA,GAAuB,EAAE,QAAA,EAAU,KAAA,EAAO,QAAQ,sBAAA,EAAuB;AAS/E,SAAS,KAAA,CAAM,QAAA,EAAkB,IAAA,EAAc,SAAA,EAAmB,OAAA,EAAiC;AACjG,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI;AACF,IAAA,SAAA,GAAY,OAAA,CAAQ,MAAM,SAAS,CAAA;AAAA,EACrC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,eAAA,EAAgB;AAAA,EAC9C;AACA,EAAA,IAAI,SAAA,CAAU,WAAA,EAAY,KAAM,QAAA,CAAS,aAAY,EAAG;AACtD,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,iBAAA,EAAmB,iBAAiB,SAAA,EAAU;AAAA,EAC5E;AACA,EAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,eAAA,EAAiB,SAAA,EAAU;AAChD;AAEA,SAAS,MAAA,CAAO,QAAqB,YAAA,EAAsE;AACzG,EAAA,IAAI,OAAO,EAAA,EAAI;AACb,IAAA,OAAO,EAAE,QAAA,EAAU,IAAA,EAAM,eAAA,EAAiB,MAAA,CAAO,iBAAiB,YAAA,EAAa;AAAA,EACjF;AACA,EAAA,OAAO,OAAO,eAAA,KAAoB,MAAA,GAC9B,EAAE,QAAA,EAAU,KAAA,EAAO,QAAQ,MAAA,CAAO,MAAA,EAAQ,eAAA,EAAiB,MAAA,CAAO,iBAAgB,GAClF,EAAE,UAAU,KAAA,EAAO,MAAA,EAAQ,OAAO,MAAA,EAAO;AAC/C;AAcO,SAAS,oBAAA,CACd,OAAA,EACA,OAAA,GAAqB,cAAA,EACA;AAGrB,EAAA,IAAI,OAAO,OAAA,KAAY,QAAA,IAAY,OAAA,KAAY,MAAM,OAAO,oBAAA;AAC5D,EAAA,IAAI,MAAA,GAAS,OAAA;AAYb,EAAA,IAAI,OAAO,MAAA,CAAO,aAAA,KAAkB,QAAA,IAAY,MAAA,CAAO,kBAAkB,IAAA,EAAM;AAC7E,IAAA,IAAI,OAAO,MAAA,CAAO,OAAA,KAAY,QAAA,IAAY,MAAA,CAAO,YAAY,IAAA,EAAM;AACjE,MAAA,OAAO,oBAAA;AAAA,IACT;AACA,IAAA,MAAA,GAAS,MAAA,CAAO,OAAA;AAAA,EAClB;AACA,EAAA,IAAI,OAAO,MAAA,CAAO,aAAA,KAAkB,QAAA,IAAY,MAAA,CAAO,kBAAkB,IAAA,EAAM;AAC7E,IAAA,OAAO,oBAAA;AAAA,EACT;AACA,EAAA,MAAM,OAAO,MAAA,CAAO,aAAA;AAMpB,EAAA,MAAM,EAAE,QAAA,EAAU,QAAA,EAAU,SAAA,EAAW,iBAAgB,GAAI,IAAA;AAC3D,EAAA,IAAI,OAAO,aAAa,QAAA,IAAY,QAAA,KAAa,MAAM,OAAO,QAAA,KAAa,QAAA,IAAY,QAAA,KAAa,EAAA,EAAI;AACtG,IAAA,OAAO,oBAAA;AAAA,EACT;AACA,EAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,SAAA,KAAc,EAAA,EAAI;AACrD,IAAA,OAAO,EAAE,QAAA,EAAU,KAAA,EAAO,MAAA,EAAQ,mBAAA,EAAoB;AAAA,EACxD;AAEA,EAAA,MAAM,OAAA,GACJ,OAAO,MAAA,CAAO,OAAA,EAAS,YAAY,QAAA,GAAW,MAAA,CAAO,QAAQ,OAAA,GAAU,MAAA;AACzE,EAAA,MAAM,gBAAA,GAAmB,OAAA,KAAY,MAAA,IAAa,4BAAA,CAA6B,IAAI,OAAO,CAAA;AAK1F,EAAA,IAAI,oBAAoB,eAAA,EAAiB;AACvC,IAAA,OAAO,EAAE,QAAA,EAAU,KAAA,EAAO,MAAA,EAAQ,wBAAA,EAAyB;AAAA,EAC7D;AAIA,EAAA,IAAI,oBAAoB,mBAAA,EAAqB;AAC3C,IAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,MAAA,OAAO,EAAE,QAAA,EAAU,KAAA,EAAO,MAAA,EAAQ,wBAAA,EAAyB;AAAA,IAC7D;AACA,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAA,GAAS,gBAAA,CAAiB,UAAU,OAAiB,CAAA;AAAA,IACvD,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,EAAE,QAAA,EAAU,KAAA,EAAO,MAAA,EAAQ,eAAA,EAAgB;AAAA,IACpD;AACA,IAAA,OAAO,OAAO,KAAA,CAAM,QAAA,EAAU,QAAQ,SAAA,EAAW,OAAO,GAAG,mBAAmB,CAAA;AAAA,EAChF;AAMA,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,QAAA,EAAU,QAAA,EAAU,WAAW,OAAO,CAAA;AACxD,EAAA,IAAI,GAAA,CAAI,EAAA,EAAI,OAAO,MAAA,CAAO,KAAK,WAAW,CAAA;AAC1C,EAAA,IAAI,gBAAA,EAAkB;AACpB,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAA,GAAS,gBAAA,CAAiB,UAAU,OAAiB,CAAA;AAAA,IACvD,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,MAAA,CAAO,KAAK,WAAW,CAAA;AAAA,IAChC;AACA,IAAA,MAAM,SAAA,GAAY,KAAA,CAAM,QAAA,EAAU,MAAA,EAAQ,WAAW,OAAO,CAAA;AAC5D,IAAA,IAAI,SAAA,CAAU,EAAA,EAAI,OAAO,MAAA,CAAO,WAAW,mBAAmB,CAAA;AAAA,EAChE;AACA,EAAA,OAAO,MAAA,CAAO,KAAK,WAAW,CAAA;AAChC","file":"chunk-7UTWSJC5.cjs","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":["keccak256","toBytes","encodeAbiParameters","DELEGATION_MANAGER","concatHex","ethers"],"mappings":"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","file":"chunk-DXBAN4SN.cjs","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"]}
@@ -200,7 +200,9 @@ var AgentPaymentFailureCode = {
200
200
  * challenge — e.g. its settlement wallet is out of gas. No 402 was ever
201
201
  * issued and no payment was created; this is honest and (per
202
202
  * `retry_after_s`, when present) usually transient, unlike a permanent
203
- * endpoint miss.
203
+ * endpoint miss — except out of gas (`reason_code:
204
+ * settlement_wallet_out_of_gas`), which needs the merchant's operator to
205
+ * top up its settlement wallet first (#3834).
204
206
  */
205
207
  MerchantNotReady: "MERCHANT_NOT_READY"
206
208
  };
@@ -262,7 +264,7 @@ var AgentPaymentFailureCodeDescriptions = {
262
264
  [AgentPaymentFailureCode.MerchantCallContextUnavailable]: "merchant_url/tool_name were omitted and no stored merchant call context is available for this payment_id. Re-send merchant_url, tool_name, arguments, and mcp_transport explicitly.",
263
265
  [AgentPaymentFailureCode.AmbiguousMaxAmount]: "Both max_amount (atomic units) and max_amount_human (whole tokens) were supplied 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.",
264
266
  [AgentPaymentFailureCode.MaxAmountUnconvertible]: "max_amount_human could not be converted to atomic units against this quote's asset \u2014 either its decimals are unknown to Haven or the cap has more decimal places than the asset supports. Nothing was spent. Round the cap, or re-send it as an exact atomic max_amount.",
265
- [AgentPaymentFailureCode.MerchantNotReady]: 'The merchant refused the probe with its own "cannot settle right now" signal instead of a 402 challenge. No payment was created. Often transient \u2014 retry later (see retry_after_s in the message, if given) rather than treating this as a broken or wrong endpoint.'
267
+ [AgentPaymentFailureCode.MerchantNotReady]: `The merchant refused the probe with its own "cannot settle right now" signal instead of a 402 challenge. No payment was created. Often transient \u2014 retry later (see retry_after_s in the message, if given) rather than treating this as a broken or wrong endpoint \u2014 except an out-of-gas refusal (reason_code settlement_wallet_out_of_gas), which needs the merchant's operator to top up its settlement wallet before any retry can succeed.`
266
268
  };
267
269
  var AgentPaymentWarningCode = {
268
270
  /** No max_amount cap was supplied — the live quoted price was accepted as-is. */
@@ -310,7 +312,23 @@ var AgentPaymentWarningCode = {
310
312
  * money moved". Carries the intent's `expires_at`: after that instant the
311
313
  * settlement can no longer land at all.
312
314
  */
313
- SettlementUnconfirmed: "SETTLEMENT_UNCONFIRMED"
315
+ SettlementUnconfirmed: "SETTLEMENT_UNCONFIRMED",
316
+ /**
317
+ * #3967: the quote-time budget pre-check decided the quoted amount does NOT
318
+ * fit the agent's remaining delegation budget — the same server-side compare
319
+ * the payment path runs before funding. Travels beside
320
+ * `budget_check.sufficient: false` and, on `haven_quote_x402`,
321
+ * `safe_to_continue: false` with no prefilled cap. The on-chain policy
322
+ * remains the actual gate either way.
323
+ */
324
+ QuoteExceedsRemainingBudget: "QUOTE_EXCEEDS_REMAINING_BUDGET",
325
+ /**
326
+ * #3967: the MERCHANT reported a denial on one of its x402 payment options —
327
+ * a known denial key (starting with `issuanceDenied`) in `accepts[].extra`.
328
+ * Strictly informational: it flips neither `safe_to_continue` nor
329
+ * `expected_settleable`; the agent should surface it to the user.
330
+ */
331
+ MerchantReportedDenial: "MERCHANT_REPORTED_DENIAL"
314
332
  };
315
333
  var AgentPaymentRailDescriptions = {
316
334
  [AgentPaymentRail.Direct]: "Standard Haven payment from the user-controlled account, redeeming the agent's on-chain budget delegation.",
@@ -1016,5 +1034,5 @@ function assertRedeemsOwnBudgetDelegation(redeemCalldata, ownAccount) {
1016
1034
  }
1017
1035
 
1018
1036
  export { AGENT_PAYMENT_FAILURE_CODE_VALUES, AGENT_PAYMENT_NEXT_ACTION_VALUES, AGENT_PAYMENT_PHASE_VALUES, AGENT_PAYMENT_RAIL_VALUES, AgentPaymentFailureCode, AgentPaymentFailureCodeDescriptions, AgentPaymentFailureCodeSchema, AgentPaymentNextAction, AgentPaymentNextActionDescriptions, AgentPaymentNextActionSchema, AgentPaymentPhase, AgentPaymentPhaseDescriptions, AgentPaymentPhaseSchema, AgentPaymentRail, AgentPaymentRailDescriptions, AgentPaymentRailSchema, AgentPaymentWarningCode, CAVEAT_ENFORCERS, CONNECTOR_PACKAGE_NAME, DEFAULT_CONFIRMATION_TIMEOUT_MS, DELEGATION_MANAGER, DELEGATION_TUPLE_COMPONENTS, DIRECT_SIGN_CONTEXT_VERSION, ENTRY_POINT_V07, HAVEN_CONNECTOR_CHANNEL, HYBRID_DELEGATOR_DOMAIN_NAME, HYBRID_DELEGATOR_DOMAIN_VERSION, HYBRID_DELEGATOR_IMPLEMENTATION, HavenApiError, HavenError, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, HavenUserOpBindingError, HavenZeroSettlementHashError, MAX_SETTLEMENT_WINDOW_SECONDS, MerchantTimeoutError, PACKED_USER_OPERATION_FIELDS, REDEEM_DELEGATIONS_ABI, ROOT_AUTHORITY, SIGNER_UPDATE_FALLBACK, SIMPLE_FACTORY_ADDRESS, SINGLE_DEFAULT_MODE, SignerRefusalCode, TASK_SIGN_CONTEXT_VERSION, X402AlreadySettledError, X402Erc7710AlreadySettledError, X402TaskBudgetMismatchError, X402UnexpectedStatusError, assertRedeemsOwnBudgetDelegation, assertUserOpTypedDataBinding, chainIdForNetwork, connectorRerunCommand, connectorSpec, connectorUpgradeCommand, deriveDelegateAccountAddress, isConnectorChannel, isPackedUserOperationTypedData, isSettlementChildTypedData, packedUserOperationHash, resolveConnectorChannel, signerUpdateFallback, verifySettlementChild };
1019
- //# sourceMappingURL=chunk-J7N4LUZZ.js.map
1020
- //# sourceMappingURL=chunk-J7N4LUZZ.js.map
1037
+ //# sourceMappingURL=chunk-I7SL4A6X.js.map
1038
+ //# sourceMappingURL=chunk-I7SL4A6X.js.map