@haven_ai/sdk 0.1.25-alpha.0 → 0.1.26-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.
package/dist/index.d.cts CHANGED
@@ -1063,6 +1063,42 @@ declare class X402UnexpectedStatusError extends HavenApiError {
1063
1063
  readonly x402ErrorCode: "unexpected_non_402_status";
1064
1064
  constructor(message: string, statusCode: number);
1065
1065
  }
1066
+ /**
1067
+ * #1521: the idempotency key resolved to a payment that has already settled,
1068
+ * and the delegate can no longer fund a fresh authorization for it.
1069
+ *
1070
+ * This is the typed form of "you already bought this". It exists because the
1071
+ * alternative was indefensible: the SDK used to mint a new EIP-3009
1072
+ * authorization against the spent delegate and hand it back paired with the
1073
+ * ORIGINAL payment's `txHash`, so the caller learned what had happened only
1074
+ * from a merchant-side balance error that reads identically to a broken
1075
+ * payment rail.
1076
+ *
1077
+ * `receipt` is the ORIGINAL payment — a real receipt for real settled funds,
1078
+ * deliberately carrying no `paymentHeader`, because any header minted here
1079
+ * would be exactly the unfundable artifact this error replaces.
1080
+ */
1081
+ declare class X402AlreadySettledError extends HavenApiError {
1082
+ readonly receipt: X402Receipt;
1083
+ /**
1084
+ * `settled` — the delegate was checked on-chain and cannot fund a fresh
1085
+ * authorization, so this payment demonstrably completed.
1086
+ * `unverifiable` — no `chainRpcs` entry for the chain, so fundability
1087
+ * could not be established either way. Same refusal, weaker claim; say
1088
+ * which, rather than assert what was not checked.
1089
+ */
1090
+ readonly basis: 'settled' | 'unverifiable';
1091
+ readonly x402ErrorCode: "already_settled";
1092
+ constructor(message: string, receipt: X402Receipt,
1093
+ /**
1094
+ * `settled` — the delegate was checked on-chain and cannot fund a fresh
1095
+ * authorization, so this payment demonstrably completed.
1096
+ * `unverifiable` — no `chainRpcs` entry for the chain, so fundability
1097
+ * could not be established either way. Same refusal, weaker claim; say
1098
+ * which, rather than assert what was not checked.
1099
+ */
1100
+ basis: 'settled' | 'unverifiable');
1101
+ }
1066
1102
  declare class HavenPaymentStateError extends HavenApiError {
1067
1103
  readonly state: PaymentStatusResult;
1068
1104
  resumeState?: X402ResumeState;
@@ -1825,6 +1861,25 @@ declare class HavenClient {
1825
1861
  * small propagation window as a trade-off for not configuring an RPC URL.
1826
1862
  */
1827
1863
  private waitForFundingTx;
1864
+ /**
1865
+ * Can the delegate EOA still fund an authorization for `amountAtomic`?
1866
+ *
1867
+ * #1521: the only question that separates a legitimate resume (funding
1868
+ * confirmed, merchant never paid — the delegate still holds the money) from
1869
+ * a replayed settled payment (funding confirmed, merchant paid, delegate
1870
+ * spent). The intent's own `status: 'confirmed'` is identical in both.
1871
+ *
1872
+ * The balance is asked of the CHAIN rather than of Haven's bookkeeping on
1873
+ * purpose: the merchant-settlement evidence record is written by this SDK
1874
+ * *after* the merchant call, so a client that dies between the two leaves
1875
+ * the backend believing the merchant was never paid — the exact case the
1876
+ * discriminator has to get right. The chain cannot be behind in that way.
1877
+ *
1878
+ * Returns `null` — never a guess — when `chainRpcs` has no entry for the
1879
+ * chain or the read fails. Callers must treat that as "unverifiable", not
1880
+ * as "funded".
1881
+ */
1882
+ private delegateCanFund;
1828
1883
  private throwIfNonSignableAuthorizationState;
1829
1884
  private throwPaymentStateError;
1830
1885
  private paymentStateFromRaw;
@@ -2469,4 +2524,4 @@ declare function discoverMerchantMcpUrl(inputUrl: string): Promise<string | null
2469
2524
  /** Trailing-slash/percent-case echoes compare equal; unparseable never does. */
2470
2525
  declare function sameUrl(a: string, b: string): boolean;
2471
2526
 
2472
- export { AGENT_PAYMENT_FAILURE_CODE_VALUES, AGENT_PAYMENT_NEXT_ACTION_VALUES, AGENT_PAYMENT_PHASE_VALUES, AGENT_PAYMENT_RAIL_VALUES, type AgentNextStep, type AgentPaymentEnumSchema, AgentPaymentFailureCode, AgentPaymentFailureCodeDescriptions, AgentPaymentFailureCodeSchema, AgentPaymentNextAction, AgentPaymentNextActionDescriptions, AgentPaymentNextActionSchema, AgentPaymentPhase, AgentPaymentPhaseDescriptions, AgentPaymentPhaseSchema, AgentPaymentRail, AgentPaymentRailDescriptions, AgentPaymentRailSchema, type AgentPaymentSummary, type AgentPaymentWarning, AgentPaymentWarningCode, type AgentPurchaseSummary, type ClaudeTool, DISCOVERY_MAX_BYTES, ERC7710_ASSET_TRANSFER_METHOD, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_BODY_MD, HAVEN_SKILL_MD, type HavenAgent, type HavenAgentAllowanceSummary, type HavenAgentReadiness, type HavenAgentSummary, type HavenAllowance, type HavenAllowanceSummary, HavenApiError, type HavenCatalogEntry, HavenClient, type HavenClientConfig, HavenError, type HavenPaymentReceipt, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, type MachinePaymentRail, MerchantTimeoutError, type OpenAITool, type PaymentFee, type PaymentIntent, type PaymentNextAction, type PaymentPhase, type PaymentReceipt, type PaymentRequest, type PaymentResult, type PaymentResumeState, type PaymentStatus, type PaymentStatusResult, type PendingApproval, type PostPurchaseAllowanceSummary, RECEIPT_VERSION, type ReceiptVerification, type ResumeAuthorizedX402Input, type ResumeX402PaymentInput, SIGNER_UPDATE_FALLBACK, SKILL_FOLDER_NAME, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, type SharedToolKey, type SignData, SignerRefusalCode, type SweepAuthorization, type SweepEip712Domain, type SweepEntry, type SweepExpectedAuth, type SweepPreparation, type SweepPrepareResponse, type SweepResult, type SweepSubmitResponse, type SweepSubmitResult, type SweepTypedData, TRANSFER_WITH_AUTHORIZATION_TYPES, type ToolDescription, type UnsupportedNodeVersionMessageOptions, type X402AuthorizationOptions, type X402Erc7710Settlement, type X402ExpectedAuth, type X402ExpectedContext, type X402Intent, type X402McpCallContext, type X402McpTransport, type X402MerchantCallContext, type X402PaymentHeaderContext, X402PaymentHeaderValidationError, type X402PaymentOption, type X402PaymentRequired, type X402Quote, type X402Receipt, type X402RequestSnapshot, type X402ResumeState, type X402SchemeSelection, X402UnexpectedStatusError, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isErc7710Option, isSupportedNodeVersion, isSweepableChain, normalizePaymentRequired, parsePaymentRequired, parsePaymentRequiredResponse, resolveTokenFromAddress, sameUrl, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, signUserOpTypedDataForDelegation, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifyPaymentReceipt, verifySignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses };
2527
+ export { AGENT_PAYMENT_FAILURE_CODE_VALUES, AGENT_PAYMENT_NEXT_ACTION_VALUES, AGENT_PAYMENT_PHASE_VALUES, AGENT_PAYMENT_RAIL_VALUES, type AgentNextStep, type AgentPaymentEnumSchema, AgentPaymentFailureCode, AgentPaymentFailureCodeDescriptions, AgentPaymentFailureCodeSchema, AgentPaymentNextAction, AgentPaymentNextActionDescriptions, AgentPaymentNextActionSchema, AgentPaymentPhase, AgentPaymentPhaseDescriptions, AgentPaymentPhaseSchema, AgentPaymentRail, AgentPaymentRailDescriptions, AgentPaymentRailSchema, type AgentPaymentSummary, type AgentPaymentWarning, AgentPaymentWarningCode, type AgentPurchaseSummary, type ClaudeTool, DISCOVERY_MAX_BYTES, ERC7710_ASSET_TRANSFER_METHOD, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_BODY_MD, HAVEN_SKILL_MD, type HavenAgent, type HavenAgentAllowanceSummary, type HavenAgentReadiness, type HavenAgentSummary, type HavenAllowance, type HavenAllowanceSummary, HavenApiError, type HavenCatalogEntry, HavenClient, type HavenClientConfig, HavenError, type HavenPaymentReceipt, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, type MachinePaymentRail, MerchantTimeoutError, type OpenAITool, type PaymentFee, type PaymentIntent, type PaymentNextAction, type PaymentPhase, type PaymentReceipt, type PaymentRequest, type PaymentResult, type PaymentResumeState, type PaymentStatus, type PaymentStatusResult, type PendingApproval, type PostPurchaseAllowanceSummary, RECEIPT_VERSION, type ReceiptVerification, type ResumeAuthorizedX402Input, type ResumeX402PaymentInput, SIGNER_UPDATE_FALLBACK, SKILL_FOLDER_NAME, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, type SharedToolKey, type SignData, SignerRefusalCode, type SweepAuthorization, type SweepEip712Domain, type SweepEntry, type SweepExpectedAuth, type SweepPreparation, type SweepPrepareResponse, type SweepResult, type SweepSubmitResponse, type SweepSubmitResult, type SweepTypedData, TRANSFER_WITH_AUTHORIZATION_TYPES, type ToolDescription, type UnsupportedNodeVersionMessageOptions, X402AlreadySettledError, type X402AuthorizationOptions, type X402Erc7710Settlement, type X402ExpectedAuth, type X402ExpectedContext, type X402Intent, type X402McpCallContext, type X402McpTransport, type X402MerchantCallContext, type X402PaymentHeaderContext, X402PaymentHeaderValidationError, type X402PaymentOption, type X402PaymentRequired, type X402Quote, type X402Receipt, type X402RequestSnapshot, type X402ResumeState, type X402SchemeSelection, X402UnexpectedStatusError, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isErc7710Option, isSupportedNodeVersion, isSweepableChain, normalizePaymentRequired, parsePaymentRequired, parsePaymentRequiredResponse, resolveTokenFromAddress, sameUrl, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, signUserOpTypedDataForDelegation, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifyPaymentReceipt, verifySignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses };
package/dist/index.d.ts CHANGED
@@ -1063,6 +1063,42 @@ declare class X402UnexpectedStatusError extends HavenApiError {
1063
1063
  readonly x402ErrorCode: "unexpected_non_402_status";
1064
1064
  constructor(message: string, statusCode: number);
1065
1065
  }
1066
+ /**
1067
+ * #1521: the idempotency key resolved to a payment that has already settled,
1068
+ * and the delegate can no longer fund a fresh authorization for it.
1069
+ *
1070
+ * This is the typed form of "you already bought this". It exists because the
1071
+ * alternative was indefensible: the SDK used to mint a new EIP-3009
1072
+ * authorization against the spent delegate and hand it back paired with the
1073
+ * ORIGINAL payment's `txHash`, so the caller learned what had happened only
1074
+ * from a merchant-side balance error that reads identically to a broken
1075
+ * payment rail.
1076
+ *
1077
+ * `receipt` is the ORIGINAL payment — a real receipt for real settled funds,
1078
+ * deliberately carrying no `paymentHeader`, because any header minted here
1079
+ * would be exactly the unfundable artifact this error replaces.
1080
+ */
1081
+ declare class X402AlreadySettledError extends HavenApiError {
1082
+ readonly receipt: X402Receipt;
1083
+ /**
1084
+ * `settled` — the delegate was checked on-chain and cannot fund a fresh
1085
+ * authorization, so this payment demonstrably completed.
1086
+ * `unverifiable` — no `chainRpcs` entry for the chain, so fundability
1087
+ * could not be established either way. Same refusal, weaker claim; say
1088
+ * which, rather than assert what was not checked.
1089
+ */
1090
+ readonly basis: 'settled' | 'unverifiable';
1091
+ readonly x402ErrorCode: "already_settled";
1092
+ constructor(message: string, receipt: X402Receipt,
1093
+ /**
1094
+ * `settled` — the delegate was checked on-chain and cannot fund a fresh
1095
+ * authorization, so this payment demonstrably completed.
1096
+ * `unverifiable` — no `chainRpcs` entry for the chain, so fundability
1097
+ * could not be established either way. Same refusal, weaker claim; say
1098
+ * which, rather than assert what was not checked.
1099
+ */
1100
+ basis: 'settled' | 'unverifiable');
1101
+ }
1066
1102
  declare class HavenPaymentStateError extends HavenApiError {
1067
1103
  readonly state: PaymentStatusResult;
1068
1104
  resumeState?: X402ResumeState;
@@ -1825,6 +1861,25 @@ declare class HavenClient {
1825
1861
  * small propagation window as a trade-off for not configuring an RPC URL.
1826
1862
  */
1827
1863
  private waitForFundingTx;
1864
+ /**
1865
+ * Can the delegate EOA still fund an authorization for `amountAtomic`?
1866
+ *
1867
+ * #1521: the only question that separates a legitimate resume (funding
1868
+ * confirmed, merchant never paid — the delegate still holds the money) from
1869
+ * a replayed settled payment (funding confirmed, merchant paid, delegate
1870
+ * spent). The intent's own `status: 'confirmed'` is identical in both.
1871
+ *
1872
+ * The balance is asked of the CHAIN rather than of Haven's bookkeeping on
1873
+ * purpose: the merchant-settlement evidence record is written by this SDK
1874
+ * *after* the merchant call, so a client that dies between the two leaves
1875
+ * the backend believing the merchant was never paid — the exact case the
1876
+ * discriminator has to get right. The chain cannot be behind in that way.
1877
+ *
1878
+ * Returns `null` — never a guess — when `chainRpcs` has no entry for the
1879
+ * chain or the read fails. Callers must treat that as "unverifiable", not
1880
+ * as "funded".
1881
+ */
1882
+ private delegateCanFund;
1828
1883
  private throwIfNonSignableAuthorizationState;
1829
1884
  private throwPaymentStateError;
1830
1885
  private paymentStateFromRaw;
@@ -2469,4 +2524,4 @@ declare function discoverMerchantMcpUrl(inputUrl: string): Promise<string | null
2469
2524
  /** Trailing-slash/percent-case echoes compare equal; unparseable never does. */
2470
2525
  declare function sameUrl(a: string, b: string): boolean;
2471
2526
 
2472
- export { AGENT_PAYMENT_FAILURE_CODE_VALUES, AGENT_PAYMENT_NEXT_ACTION_VALUES, AGENT_PAYMENT_PHASE_VALUES, AGENT_PAYMENT_RAIL_VALUES, type AgentNextStep, type AgentPaymentEnumSchema, AgentPaymentFailureCode, AgentPaymentFailureCodeDescriptions, AgentPaymentFailureCodeSchema, AgentPaymentNextAction, AgentPaymentNextActionDescriptions, AgentPaymentNextActionSchema, AgentPaymentPhase, AgentPaymentPhaseDescriptions, AgentPaymentPhaseSchema, AgentPaymentRail, AgentPaymentRailDescriptions, AgentPaymentRailSchema, type AgentPaymentSummary, type AgentPaymentWarning, AgentPaymentWarningCode, type AgentPurchaseSummary, type ClaudeTool, DISCOVERY_MAX_BYTES, ERC7710_ASSET_TRANSFER_METHOD, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_BODY_MD, HAVEN_SKILL_MD, type HavenAgent, type HavenAgentAllowanceSummary, type HavenAgentReadiness, type HavenAgentSummary, type HavenAllowance, type HavenAllowanceSummary, HavenApiError, type HavenCatalogEntry, HavenClient, type HavenClientConfig, HavenError, type HavenPaymentReceipt, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, type MachinePaymentRail, MerchantTimeoutError, type OpenAITool, type PaymentFee, type PaymentIntent, type PaymentNextAction, type PaymentPhase, type PaymentReceipt, type PaymentRequest, type PaymentResult, type PaymentResumeState, type PaymentStatus, type PaymentStatusResult, type PendingApproval, type PostPurchaseAllowanceSummary, RECEIPT_VERSION, type ReceiptVerification, type ResumeAuthorizedX402Input, type ResumeX402PaymentInput, SIGNER_UPDATE_FALLBACK, SKILL_FOLDER_NAME, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, type SharedToolKey, type SignData, SignerRefusalCode, type SweepAuthorization, type SweepEip712Domain, type SweepEntry, type SweepExpectedAuth, type SweepPreparation, type SweepPrepareResponse, type SweepResult, type SweepSubmitResponse, type SweepSubmitResult, type SweepTypedData, TRANSFER_WITH_AUTHORIZATION_TYPES, type ToolDescription, type UnsupportedNodeVersionMessageOptions, type X402AuthorizationOptions, type X402Erc7710Settlement, type X402ExpectedAuth, type X402ExpectedContext, type X402Intent, type X402McpCallContext, type X402McpTransport, type X402MerchantCallContext, type X402PaymentHeaderContext, X402PaymentHeaderValidationError, type X402PaymentOption, type X402PaymentRequired, type X402Quote, type X402Receipt, type X402RequestSnapshot, type X402ResumeState, type X402SchemeSelection, X402UnexpectedStatusError, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isErc7710Option, isSupportedNodeVersion, isSweepableChain, normalizePaymentRequired, parsePaymentRequired, parsePaymentRequiredResponse, resolveTokenFromAddress, sameUrl, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, signUserOpTypedDataForDelegation, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifyPaymentReceipt, verifySignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses };
2527
+ export { AGENT_PAYMENT_FAILURE_CODE_VALUES, AGENT_PAYMENT_NEXT_ACTION_VALUES, AGENT_PAYMENT_PHASE_VALUES, AGENT_PAYMENT_RAIL_VALUES, type AgentNextStep, type AgentPaymentEnumSchema, AgentPaymentFailureCode, AgentPaymentFailureCodeDescriptions, AgentPaymentFailureCodeSchema, AgentPaymentNextAction, AgentPaymentNextActionDescriptions, AgentPaymentNextActionSchema, AgentPaymentPhase, AgentPaymentPhaseDescriptions, AgentPaymentPhaseSchema, AgentPaymentRail, AgentPaymentRailDescriptions, AgentPaymentRailSchema, type AgentPaymentSummary, type AgentPaymentWarning, AgentPaymentWarningCode, type AgentPurchaseSummary, type ClaudeTool, DISCOVERY_MAX_BYTES, ERC7710_ASSET_TRANSFER_METHOD, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_BODY_MD, HAVEN_SKILL_MD, type HavenAgent, type HavenAgentAllowanceSummary, type HavenAgentReadiness, type HavenAgentSummary, type HavenAllowance, type HavenAllowanceSummary, HavenApiError, type HavenCatalogEntry, HavenClient, type HavenClientConfig, HavenError, type HavenPaymentReceipt, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, type MachinePaymentRail, MerchantTimeoutError, type OpenAITool, type PaymentFee, type PaymentIntent, type PaymentNextAction, type PaymentPhase, type PaymentReceipt, type PaymentRequest, type PaymentResult, type PaymentResumeState, type PaymentStatus, type PaymentStatusResult, type PendingApproval, type PostPurchaseAllowanceSummary, RECEIPT_VERSION, type ReceiptVerification, type ResumeAuthorizedX402Input, type ResumeX402PaymentInput, SIGNER_UPDATE_FALLBACK, SKILL_FOLDER_NAME, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, type SharedToolKey, type SignData, SignerRefusalCode, type SweepAuthorization, type SweepEip712Domain, type SweepEntry, type SweepExpectedAuth, type SweepPreparation, type SweepPrepareResponse, type SweepResult, type SweepSubmitResponse, type SweepSubmitResult, type SweepTypedData, TRANSFER_WITH_AUTHORIZATION_TYPES, type ToolDescription, type UnsupportedNodeVersionMessageOptions, X402AlreadySettledError, type X402AuthorizationOptions, type X402Erc7710Settlement, type X402ExpectedAuth, type X402ExpectedContext, type X402Intent, type X402McpCallContext, type X402McpTransport, type X402MerchantCallContext, type X402PaymentHeaderContext, X402PaymentHeaderValidationError, type X402PaymentOption, type X402PaymentRequired, type X402Quote, type X402Receipt, type X402RequestSnapshot, type X402ResumeState, type X402SchemeSelection, X402UnexpectedStatusError, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isErc7710Option, isSupportedNodeVersion, isSweepableChain, normalizePaymentRequired, parsePaymentRequired, parsePaymentRequiredResponse, resolveTokenFromAddress, sameUrl, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, signUserOpTypedDataForDelegation, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifyPaymentReceipt, verifySignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses };
package/dist/index.js CHANGED
@@ -275,6 +275,17 @@ var X402UnexpectedStatusError = class extends HavenApiError {
275
275
  this.name = "X402UnexpectedStatusError";
276
276
  }
277
277
  };
278
+ var X402AlreadySettledError = class extends HavenApiError {
279
+ constructor(message, receipt, basis) {
280
+ super(message, 409, void 0, receipt.paymentId);
281
+ this.receipt = receipt;
282
+ this.basis = basis;
283
+ this.name = "X402AlreadySettledError";
284
+ }
285
+ receipt;
286
+ basis;
287
+ x402ErrorCode = "already_settled";
288
+ };
278
289
  var HavenPaymentStateError = class extends HavenApiError {
279
290
  constructor(message, statusCode, state, body) {
280
291
  super(message, statusCode, body, state.paymentId);
@@ -951,8 +962,8 @@ function createJsonRpcProvider(url) {
951
962
  function createWallet(privateKey, provider) {
952
963
  return new ethers.Wallet(privateKey, provider);
953
964
  }
954
- function createErc20Contract(address, abi, signer) {
955
- return new ethers.Contract(address, abi, signer);
965
+ function createErc20Contract(address, abi, runner) {
966
+ return new ethers.Contract(address, abi, runner);
956
967
  }
957
968
 
958
969
  // src/client.ts
@@ -1932,7 +1943,6 @@ var HavenClient = class {
1932
1943
  }
1933
1944
  }
1934
1945
  async authorizeStandardX402(paymentRequired, option, idempotencyKey) {
1935
- const paymentHeader = await this.createStandardX402Header(paymentRequired, option);
1936
1946
  const raw = await this.post("/x402", {
1937
1947
  url: paymentRequired.resource.url,
1938
1948
  payTo: this.delegateAddress,
@@ -1947,12 +1957,30 @@ var HavenClient = class {
1947
1957
  // declaration keeps both writers of the 3009 shape loud-by-default.
1948
1958
  settlementScheme: "eip3009"
1949
1959
  });
1960
+ const state = this.paymentStateFromRaw("x402 payment", raw);
1961
+ const executedReplay = raw.success && raw.tx_hash ? "idempotency-collision" : state?.nextAction === AgentPaymentNextAction.RetryOriginalX402Request ? "approval-resume" : null;
1962
+ if (executedReplay) {
1963
+ const canFund = await this.delegateCanFund(
1964
+ raw.chain_id ?? state?.chainId ?? chainIdFromNetwork(option.network),
1965
+ option.asset,
1966
+ x402AuthorizationAmount(option)
1967
+ );
1968
+ const refuse = executedReplay === "idempotency-collision" ? canFund !== true : canFund === false;
1969
+ if (refuse) {
1970
+ const settledReceipt = state && executedReplay === "approval-resume" ? this.mapX402ReceiptFromStatus(paymentRequired, option, void 0, state) : this.mapX402ReceiptFromAuthorization(paymentRequired, option, void 0, raw);
1971
+ throw new X402AlreadySettledError(
1972
+ canFund === false ? "This x402 payment already settled \u2014 the delegate no longer holds the funds to authorize it again. To buy the same item a second time, pass a distinct `idempotencyKey`; the synthesised key intentionally collapses repeat calls for the same product within a 5-minute window so a retried request cannot pay twice." : "This x402 payment already settled, and whether the delegate can still fund a new authorization could not be verified (no `chainRpcs` entry for this chain). Refusing rather than issue an authorization that may be unfundable. To buy the same item a second time, pass a distinct `idempotencyKey`; to finish an interrupted payment, resume it by `paymentId`.",
1973
+ settledReceipt,
1974
+ canFund === false ? "settled" : "unverifiable"
1975
+ );
1976
+ }
1977
+ }
1978
+ const paymentHeader = await this.createStandardX402Header(paymentRequired, option);
1950
1979
  if (raw.success && raw.tx_hash) {
1951
1980
  const receipt2 = this.mapX402ReceiptFromAuthorization(paymentRequired, option, paymentHeader, raw);
1952
1981
  this.cacheX402Receipt(idempotencyKey, paymentHeader, receipt2);
1953
1982
  return receipt2;
1954
1983
  }
1955
- const state = this.paymentStateFromRaw("x402 payment", raw);
1956
1984
  if (state?.nextAction === AgentPaymentNextAction.RetryOriginalX402Request) {
1957
1985
  const receipt2 = this.mapX402ReceiptFromStatus(paymentRequired, option, paymentHeader, state);
1958
1986
  this.cacheX402Receipt(idempotencyKey, paymentHeader, receipt2);
@@ -2133,6 +2161,18 @@ var HavenClient = class {
2133
2161
  if (cached && cached.expiresAt > Date.now()) return cached.receipt;
2134
2162
  const status = await this.getPaymentStatus(input.paymentId);
2135
2163
  this.assertCanResumeX402(status, input.paymentRequired, option);
2164
+ const canFund = await this.delegateCanFund(
2165
+ status.chainId ?? chainIdFromNetwork(option.network),
2166
+ option.asset,
2167
+ x402AuthorizationAmount(option)
2168
+ );
2169
+ if (canFund === false) {
2170
+ throw new X402AlreadySettledError(
2171
+ `x402 payment ${status.paymentId} has already settled \u2014 the delegate no longer holds the funds to authorize it again, so there is nothing left to resume.`,
2172
+ this.mapX402ReceiptFromStatus(input.paymentRequired, option, void 0, status),
2173
+ "settled"
2174
+ );
2175
+ }
2136
2176
  const paymentHeader = await this.createStandardX402Header(input.paymentRequired, option);
2137
2177
  const receipt = this.mapX402ReceiptFromStatus(input.paymentRequired, option, paymentHeader, status);
2138
2178
  this.cacheX402Receipt(idempotencyKey, paymentHeader, receipt);
@@ -2860,6 +2900,45 @@ var HavenClient = class {
2860
2900
  );
2861
2901
  }
2862
2902
  }
2903
+ /**
2904
+ * Can the delegate EOA still fund an authorization for `amountAtomic`?
2905
+ *
2906
+ * #1521: the only question that separates a legitimate resume (funding
2907
+ * confirmed, merchant never paid — the delegate still holds the money) from
2908
+ * a replayed settled payment (funding confirmed, merchant paid, delegate
2909
+ * spent). The intent's own `status: 'confirmed'` is identical in both.
2910
+ *
2911
+ * The balance is asked of the CHAIN rather than of Haven's bookkeeping on
2912
+ * purpose: the merchant-settlement evidence record is written by this SDK
2913
+ * *after* the merchant call, so a client that dies between the two leaves
2914
+ * the backend believing the merchant was never paid — the exact case the
2915
+ * discriminator has to get right. The chain cannot be behind in that way.
2916
+ *
2917
+ * Returns `null` — never a guess — when `chainRpcs` has no entry for the
2918
+ * chain or the read fails. Callers must treat that as "unverifiable", not
2919
+ * as "funded".
2920
+ */
2921
+ async delegateCanFund(chainId, tokenAddress, amountAtomic, timeoutMs = 1e4) {
2922
+ if (!chainId || !this.delegateAddress) return null;
2923
+ const rpcUrl = this.chainRpcs[chainId];
2924
+ if (!rpcUrl) return null;
2925
+ try {
2926
+ const provider = createJsonRpcProvider(rpcUrl);
2927
+ const token = createErc20Contract(
2928
+ tokenAddress,
2929
+ ["function balanceOf(address) view returns (uint256)"],
2930
+ provider
2931
+ );
2932
+ const balance = await Promise.race([
2933
+ token.balanceOf(this.delegateAddress),
2934
+ new Promise((resolve) => setTimeout(() => resolve(null), timeoutMs).unref?.())
2935
+ ]);
2936
+ if (balance === null) return null;
2937
+ return balance >= BigInt(amountAtomic);
2938
+ } catch {
2939
+ return null;
2940
+ }
2941
+ }
2863
2942
  throwIfNonSignableAuthorizationState(label, raw) {
2864
2943
  if (raw.status === "pending_signature") return;
2865
2944
  this.throwPaymentStateError(label, raw);
@@ -4040,6 +4119,6 @@ function sameUrl(a, b) {
4040
4119
  }
4041
4120
  }
4042
4121
 
4043
- 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, DISCOVERY_MAX_BYTES, ERC7710_ASSET_TRANSFER_METHOD, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_BODY_MD, HAVEN_SKILL_MD, HavenApiError, HavenClient, HavenError, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, MerchantTimeoutError, RECEIPT_VERSION, SIGNER_UPDATE_FALLBACK, SKILL_FOLDER_NAME, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, SignerRefusalCode, TRANSFER_WITH_AUTHORIZATION_TYPES, X402PaymentHeaderValidationError, X402UnexpectedStatusError, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isErc7710Option, isSupportedNodeVersion, isSweepableChain, normalizePaymentRequired, parsePaymentRequired, parsePaymentRequiredResponse, resolveTokenFromAddress, sameUrl, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, signUserOpTypedDataForDelegation, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifyPaymentReceipt, verifySignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses };
4122
+ 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, DISCOVERY_MAX_BYTES, ERC7710_ASSET_TRANSFER_METHOD, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_BODY_MD, HAVEN_SKILL_MD, HavenApiError, HavenClient, HavenError, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, MerchantTimeoutError, RECEIPT_VERSION, SIGNER_UPDATE_FALLBACK, SKILL_FOLDER_NAME, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, SignerRefusalCode, TRANSFER_WITH_AUTHORIZATION_TYPES, X402AlreadySettledError, X402PaymentHeaderValidationError, X402UnexpectedStatusError, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isErc7710Option, isSupportedNodeVersion, isSweepableChain, normalizePaymentRequired, parsePaymentRequired, parsePaymentRequiredResponse, resolveTokenFromAddress, sameUrl, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, signUserOpTypedDataForDelegation, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifyPaymentReceipt, verifySignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses };
4044
4123
  //# sourceMappingURL=index.js.map
4045
4124
  //# sourceMappingURL=index.js.map