@atumlabs/payment-gateway-client 3.0.0 → 3.0.1

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.js CHANGED
@@ -1,8 +1,6 @@
1
1
  /*
2
- * Copyright (c) 2026 Atum Labs, Inc. All rights reserved.
3
- * Proprietary and confidential.
4
- * Access and use are governed by the LICENSE file distributed with this package.
5
- * Do not remove, alter, or obscure this notice.
2
+ * Copyright 2026 Atum Labs, Inc.
3
+ * SPDX-License-Identifier: Apache-2.0
6
4
  */
7
5
  "use strict";
8
6
  var __create = Object.create;
@@ -11,11 +9,20 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
11
9
  var __getOwnPropNames = Object.getOwnPropertyNames;
12
10
  var __getProtoOf = Object.getPrototypeOf;
13
11
  var __hasOwnProp = Object.prototype.hasOwnProperty;
14
- var __esm = (fn, res) => function __init() {
15
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
+ var __esm = (fn, res, err) => function __init() {
13
+ if (err) throw err[0];
14
+ try {
15
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
16
+ } catch (e) {
17
+ throw err = [e], e;
18
+ }
16
19
  };
17
20
  var __commonJS = (cb, mod) => function __require() {
18
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
21
+ try {
22
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
23
+ } catch (e) {
24
+ throw mod = 0, e;
25
+ }
19
26
  };
20
27
  var __export = (target, all) => {
21
28
  for (var name in all)
@@ -2105,7 +2112,7 @@ var require_errors2 = __commonJS({
2105
2112
  "../contracts/svm/escrow-encoding/typescript/dist/errors.js"(exports2) {
2106
2113
  "use strict";
2107
2114
  Object.defineProperty(exports2, "__esModule", { value: true });
2108
- exports2.DestinationTooLongError = exports2.EmptyDestinationError = exports2.ZeroSourceAmountError = exports2.ZeroQuoteHashError = exports2.InvalidHexError = exports2.InvalidBase58Error = exports2.InvalidPubkeyLengthError = exports2.ZeroDepositHashError = exports2.ZeroRecipientError = exports2.ZeroReleaserError = exports2.ZeroReserverError = exports2.ZeroAmountError = exports2.ZeroMintError = exports2.ZeroDepositorError = exports2.ZeroDepositRequestHashError = exports2.EncodingError = void 0;
2115
+ exports2.InvalidEscrowDomainError = exports2.DestinationTooLongError = exports2.EmptyDestinationError = exports2.ZeroSourceAmountError = exports2.ZeroQuoteHashError = exports2.InvalidHexError = exports2.InvalidBase58Error = exports2.InvalidPubkeyLengthError = exports2.ZeroDepositHashError = exports2.ZeroRecipientError = exports2.ZeroReleaserError = exports2.ZeroReserverError = exports2.ZeroAmountError = exports2.ZeroMintError = exports2.ZeroDepositorError = exports2.ZeroDepositRequestHashError = exports2.EncodingError = void 0;
2109
2116
  var EncodingError = class extends Error {
2110
2117
  constructor(message) {
2111
2118
  super(message);
@@ -2218,6 +2225,13 @@ var require_errors2 = __commonJS({
2218
2225
  }
2219
2226
  };
2220
2227
  exports2.DestinationTooLongError = DestinationTooLongError;
2228
+ var InvalidEscrowDomainError = class extends EncodingError {
2229
+ constructor(message) {
2230
+ super(message);
2231
+ this.name = "InvalidEscrowDomainError";
2232
+ }
2233
+ };
2234
+ exports2.InvalidEscrowDomainError = InvalidEscrowDomainError;
2221
2235
  }
2222
2236
  });
2223
2237
 
@@ -2926,12 +2940,17 @@ var require_escrow_domain = __commonJS({
2926
2940
  "use strict";
2927
2941
  Object.defineProperty(exports2, "__esModule", { value: true });
2928
2942
  exports2.escrowDomainPrefixBytes = escrowDomainPrefixBytes;
2943
+ exports2.newEscrowDomain = newEscrowDomain;
2944
+ var errors_1 = require_errors2();
2929
2945
  function escrowDomainPrefixBytes(domain) {
2930
2946
  if (domain.clusterId.length !== 32) {
2931
- throw new Error(`EscrowDomain.clusterId must be 32 bytes, got ${domain.clusterId.length}`);
2947
+ throw new errors_1.InvalidEscrowDomainError(`EscrowDomain.clusterId must be 32 bytes, got ${domain.clusterId.length}`);
2948
+ }
2949
+ if (domain.programId.isZero()) {
2950
+ throw new errors_1.InvalidEscrowDomainError("EscrowDomain.programId cannot be zero");
2932
2951
  }
2933
2952
  if (!Number.isInteger(domain.signatureDomainVersion) || domain.signatureDomainVersion < 1 || domain.signatureDomainVersion > 255) {
2934
- throw new Error(`EscrowDomain.signatureDomainVersion must be an integer in 1..=255, got ${domain.signatureDomainVersion}`);
2953
+ throw new errors_1.InvalidEscrowDomainError(`EscrowDomain.signatureDomainVersion must be an integer in 1..=255, got ${domain.signatureDomainVersion}`);
2935
2954
  }
2936
2955
  return [
2937
2956
  new TextEncoder().encode("escrow"),
@@ -2940,6 +2959,25 @@ var require_escrow_domain = __commonJS({
2940
2959
  domain.programId.toBytes()
2941
2960
  ];
2942
2961
  }
2962
+ function newEscrowDomain(clusterName, signatureDomainVersion, programId) {
2963
+ const trimmed = clusterName.trim();
2964
+ if (trimmed.length === 0) {
2965
+ throw new errors_1.InvalidEscrowDomainError("EscrowDomain cluster name cannot be empty");
2966
+ }
2967
+ const encoded = new TextEncoder().encode(trimmed);
2968
+ if (encoded.length > 32) {
2969
+ throw new errors_1.InvalidEscrowDomainError(`EscrowDomain cluster name "${trimmed}" exceeds 32 bytes`);
2970
+ }
2971
+ if (!Number.isInteger(signatureDomainVersion) || signatureDomainVersion < 1 || signatureDomainVersion > 255) {
2972
+ throw new errors_1.InvalidEscrowDomainError(`EscrowDomain.signatureDomainVersion must be an integer in 1..=255, got ${signatureDomainVersion}`);
2973
+ }
2974
+ if (programId.isZero()) {
2975
+ throw new errors_1.InvalidEscrowDomainError("EscrowDomain.programId cannot be zero");
2976
+ }
2977
+ const clusterId = new Uint8Array(32);
2978
+ clusterId.set(encoded);
2979
+ return { clusterId, signatureDomainVersion, programId };
2980
+ }
2943
2981
  }
2944
2982
  });
2945
2983
 
@@ -3138,7 +3176,7 @@ var require_dist4 = __commonJS({
3138
3176
  "../contracts/svm/escrow-encoding/typescript/dist/index.js"(exports2) {
3139
3177
  "use strict";
3140
3178
  Object.defineProperty(exports2, "__esModule", { value: true });
3141
- exports2.DEPOSIT_COMPUTE_UNIT_LIMIT = exports2.REPLAY_BUCKETS = exports2.MAX_VALID_SLOT = exports2.REPLAY_SLOTS = exports2.generateNonce = exports2.computeRefundHashV2 = exports2.computeRefundHash = exports2.computeReleaseHashV2 = exports2.computeReleaseHash = exports2.computeReserveHashV3 = exports2.computeReserveHashV2 = exports2.computeReserveHash = exports2.MAX_DESTINATION_LEN = exports2.computeDestinationHash = exports2.computeDepositHashV2 = exports2.computeDepositHash = exports2.InvalidHexError = exports2.InvalidBase58Error = exports2.InvalidPubkeyLengthError = exports2.ZeroDepositHashError = exports2.ZeroRecipientError = exports2.ZeroReleaserError = exports2.ZeroReserverError = exports2.ZeroAmountError = exports2.ZeroMintError = exports2.ZeroDepositorError = exports2.DestinationTooLongError = exports2.EmptyDestinationError = exports2.ZeroQuoteHashError = exports2.ZeroDepositRequestHashError = exports2.EncodingError = exports2.escrowDomainPrefixBytes = exports2.isZeroBytes32 = exports2.stringToBytes = exports2.keccak256 = exports2.encodeU64LE = exports2.Pubkey = void 0;
3179
+ exports2.DEPOSIT_COMPUTE_UNIT_LIMIT = exports2.REPLAY_BUCKETS = exports2.MAX_VALID_SLOT = exports2.REPLAY_SLOTS = exports2.generateNonce = exports2.computeRefundHashV2 = exports2.computeRefundHash = exports2.computeReleaseHashV2 = exports2.computeReleaseHash = exports2.computeReserveHashV3 = exports2.computeReserveHashV2 = exports2.computeReserveHash = exports2.MAX_DESTINATION_LEN = exports2.computeDestinationHash = exports2.computeDepositHashV2 = exports2.computeDepositHash = exports2.InvalidHexError = exports2.InvalidBase58Error = exports2.InvalidPubkeyLengthError = exports2.InvalidEscrowDomainError = exports2.ZeroSourceAmountError = exports2.ZeroDepositHashError = exports2.ZeroRecipientError = exports2.ZeroReleaserError = exports2.ZeroReserverError = exports2.ZeroAmountError = exports2.ZeroMintError = exports2.ZeroDepositorError = exports2.DestinationTooLongError = exports2.EmptyDestinationError = exports2.ZeroQuoteHashError = exports2.ZeroDepositRequestHashError = exports2.EncodingError = exports2.newEscrowDomain = exports2.escrowDomainPrefixBytes = exports2.isZeroBytes32 = exports2.stringToBytes = exports2.keccak256 = exports2.encodeU64LE = exports2.Pubkey = void 0;
3142
3180
  var pubkey_1 = require_pubkey();
3143
3181
  Object.defineProperty(exports2, "Pubkey", { enumerable: true, get: function() {
3144
3182
  return pubkey_1.Pubkey;
@@ -3160,6 +3198,9 @@ var require_dist4 = __commonJS({
3160
3198
  Object.defineProperty(exports2, "escrowDomainPrefixBytes", { enumerable: true, get: function() {
3161
3199
  return escrow_domain_1.escrowDomainPrefixBytes;
3162
3200
  } });
3201
+ Object.defineProperty(exports2, "newEscrowDomain", { enumerable: true, get: function() {
3202
+ return escrow_domain_1.newEscrowDomain;
3203
+ } });
3163
3204
  var errors_1 = require_errors2();
3164
3205
  Object.defineProperty(exports2, "EncodingError", { enumerable: true, get: function() {
3165
3206
  return errors_1.EncodingError;
@@ -3197,6 +3238,12 @@ var require_dist4 = __commonJS({
3197
3238
  Object.defineProperty(exports2, "ZeroDepositHashError", { enumerable: true, get: function() {
3198
3239
  return errors_1.ZeroDepositHashError;
3199
3240
  } });
3241
+ Object.defineProperty(exports2, "ZeroSourceAmountError", { enumerable: true, get: function() {
3242
+ return errors_1.ZeroSourceAmountError;
3243
+ } });
3244
+ Object.defineProperty(exports2, "InvalidEscrowDomainError", { enumerable: true, get: function() {
3245
+ return errors_1.InvalidEscrowDomainError;
3246
+ } });
3200
3247
  Object.defineProperty(exports2, "InvalidPubkeyLengthError", { enumerable: true, get: function() {
3201
3248
  return errors_1.InvalidPubkeyLengthError;
3202
3249
  } });
@@ -5477,6 +5524,7 @@ var require_policies = __commonJS({
5477
5524
  exports2.buildDenyApproveToNonAllowedSpenderTron = buildDenyApproveToNonAllowedSpenderTron;
5478
5525
  exports2.listPolicies = listPolicies;
5479
5526
  exports2.deletePolicy = deletePolicy;
5527
+ exports2.planPolicyChanges = planPolicyChanges;
5480
5528
  exports2.applyPolicies = applyPolicies;
5481
5529
  function derivePoliciesFromAllowlist(policy, chain, context) {
5482
5530
  const policies = [];
@@ -5664,26 +5712,54 @@ var require_policies = __commonJS({
5664
5712
  policyId
5665
5713
  });
5666
5714
  }
5715
+ function planPolicyChanges(existing, policies) {
5716
+ const existingByName = new Map(existing.map((p) => [p.policyName, p]));
5717
+ const drifted = [];
5718
+ for (const p of policies) {
5719
+ const prev = existingByName.get(p.policyName);
5720
+ if (!prev)
5721
+ continue;
5722
+ const matches = prev.effect === p.effect && prev.condition === p.condition && (prev.consensus ?? "") === (p.consensus ?? "");
5723
+ if (!matches)
5724
+ drifted.push({ name: p.policyName, diff: formatPolicyDiff(prev, p) });
5725
+ }
5726
+ const emittedNames = new Set(policies.map((p) => p.policyName));
5727
+ const stale = existing.filter((p) => !emittedNames.has(p.policyName));
5728
+ const seen = /* @__PURE__ */ new Set();
5729
+ const duplicateNames = [
5730
+ ...new Set(existing.filter((p) => !(seen.size === seen.add(p.policyName).size)).map((p) => p.policyName))
5731
+ ];
5732
+ return { drifted, stale, duplicateNames };
5733
+ }
5667
5734
  async function applyPolicies(client, policies, options) {
5668
5735
  const existing = await listPolicies(client, options.organizationId);
5669
5736
  const existingByName = new Map(existing.map((p) => [p.policyName, p]));
5670
5737
  const created = [];
5671
5738
  const skippedUnchanged = [];
5672
- const drifted = [];
5673
5739
  const replaced = [];
5740
+ const pruned = [];
5741
+ const { drifted, stale } = planPolicyChanges(existing, policies);
5742
+ if (stale.length > 0 && !options.prune) {
5743
+ const detail = stale.map((p) => ` - ${p.policyName} [${p.effect}] (${p.policyId})`).join("\n");
5744
+ throw new Error(`${stale.length} live polic${stale.length === 1 ? "y is" : "ies are"} absent from the emitted set:
5745
+ ${detail}
5746
+
5747
+ A retired ALLOW left live keeps granting what it always granted, so a narrower replacement does not take effect until it is gone. Re-run with --prune to delete them, or reconcile the config if they are policies this set should still emit.`);
5748
+ }
5749
+ if (drifted.length > 0 && !options.update) {
5750
+ const detail = drifted.map((d) => ` - ${d.name}:
5751
+ ${indent(d.diff, " ")}`).join("\n");
5752
+ throw new Error(`Content drift detected on ${drifted.length} polic${drifted.length === 1 ? "y" : "ies"}. Re-run with --update to delete-and-recreate, or fix the existing policy in the Turnkey console.
5753
+ ${detail}`);
5754
+ }
5755
+ const driftedNames = new Set(drifted.map((d) => d.name));
5674
5756
  for (const p of policies) {
5675
5757
  const prev = existingByName.get(p.policyName);
5676
5758
  if (prev) {
5677
- const matches = prev.effect === p.effect && prev.condition === p.condition && (prev.consensus ?? "") === (p.consensus ?? "");
5678
- if (matches) {
5759
+ if (!driftedNames.has(p.policyName)) {
5679
5760
  skippedUnchanged.push(p.policyName);
5680
5761
  continue;
5681
5762
  }
5682
- const diff = formatPolicyDiff(prev, p);
5683
- if (!options.update) {
5684
- drifted.push({ name: p.policyName, diff });
5685
- continue;
5686
- }
5687
5763
  await deletePolicy(client, prev.policyId);
5688
5764
  const newId = await createPolicyRaw(client, p);
5689
5765
  replaced.push({ name: p.policyName, oldPolicyId: prev.policyId, newPolicyId: newId });
@@ -5693,13 +5769,11 @@ var require_policies = __commonJS({
5693
5769
  const id = await createPolicyRaw(client, p);
5694
5770
  created.push(id);
5695
5771
  }
5696
- if (drifted.length > 0) {
5697
- const detail = drifted.map((d) => ` - ${d.name}:
5698
- ${indent(d.diff, " ")}`).join("\n");
5699
- throw new Error(`Content drift detected on ${drifted.length} polic${drifted.length === 1 ? "y" : "ies"}. Re-run with --update to delete-and-recreate, or fix the existing policy in the Turnkey console.
5700
- ${detail}`);
5772
+ for (const p of stale) {
5773
+ await deletePolicy(client, p.policyId);
5774
+ pruned.push({ name: p.policyName, policyId: p.policyId });
5701
5775
  }
5702
- return { created, skippedUnchanged, replaced };
5776
+ return { created, skippedUnchanged, replaced, pruned };
5703
5777
  }
5704
5778
  async function createPolicyRaw(client, p) {
5705
5779
  const result = await client.executeActivity("ACTIVITY_TYPE_CREATE_POLICY_V3", "create_policy", {
@@ -5745,6 +5819,8 @@ var require_sender_policies = __commonJS({
5745
5819
  "use strict";
5746
5820
  Object.defineProperty(exports2, "__esModule", { value: true });
5747
5821
  exports2.TRON_PERMIT2 = exports2.EVM_PERMIT2 = void 0;
5822
+ exports2.tronTip712ChainId = tronTip712ChainId;
5823
+ exports2.toTronEvmHex = toTronEvmHex;
5748
5824
  exports2.buildSenderPolicies = buildSenderPolicies;
5749
5825
  exports2.tronBase58ToEvmHex = tronBase58ToEvmHex;
5750
5826
  var node_crypto_1 = require("crypto");
@@ -5754,6 +5830,57 @@ var require_sender_policies = __commonJS({
5754
5830
  shasta: "TPUqJPASUn1zLvbLBgRZ5pBYrx7WSe5ahp"
5755
5831
  };
5756
5832
  var APPROVE_SELECTOR = "0x095ea7b3";
5833
+ var PERMIT2_PRIMARY_TYPE = "PermitWitnessTransferFrom";
5834
+ var PERMIT2_DOMAIN_NAME = "Permit2";
5835
+ var TRON_TIP712_CHAIN_IDS = {
5836
+ mainnet: 728126428,
5837
+ shasta: 2494104990
5838
+ };
5839
+ function tronTip712ChainId(caip2) {
5840
+ const cluster = caip2.split(":")[1] ?? "";
5841
+ const id = Object.hasOwn(TRON_TIP712_CHAIN_IDS, cluster) ? TRON_TIP712_CHAIN_IDS[cluster] : void 0;
5842
+ if (id === void 0) {
5843
+ throw new Error(`Sender extras: unsupported Tron network "${caip2}". Known clusters: ${Object.keys(TRON_TIP712_CHAIN_IDS).join(", ")}.`);
5844
+ }
5845
+ return (id & 4294967295) >>> 0;
5846
+ }
5847
+ function evmNumericChainId(caip2) {
5848
+ const id = Number.parseInt(caip2.split(":")[1] ?? "", 10);
5849
+ if (!Number.isSafeInteger(id) || id <= 0) {
5850
+ throw new Error(`Sender extras: chain id "${caip2}" is not a usable eip155 CAIP-2 identifier.`);
5851
+ }
5852
+ return id;
5853
+ }
5854
+ var lower = (a) => a.toLowerCase();
5855
+ function assertEvmAddress(address, chainKey) {
5856
+ if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {
5857
+ throw new Error(`Sender extras: ${JSON.stringify(address)} on chain "${chainKey}" is not a 20-byte 0x hex address. A malformed literal matches nothing, which denies every payment on this chain.`);
5858
+ }
5859
+ return address;
5860
+ }
5861
+ function toTronEvmHex(address) {
5862
+ if (address.startsWith("T"))
5863
+ return `0x${tronBase58ToEvmHex(address)}`;
5864
+ if (/^0x[0-9a-fA-F]{40}$/.test(address))
5865
+ return lower(address);
5866
+ throw new Error(`Sender extras: Tron address ${JSON.stringify(address)} is neither a base58 (T\u2026) address nor a 20-byte 0x hex address, so its TIP-712 message form cannot be derived.`);
5867
+ }
5868
+ var quotedLower = (xs) => xs.map((x) => `'${lower(x)}'`).join(", ");
5869
+ function quotedExact(xs, chainKey) {
5870
+ for (const x of xs) {
5871
+ if (x.includes("'") || x.includes("\\")) {
5872
+ throw new Error(`Sender extras: destination ${JSON.stringify(x)} on chain "${chainKey}" contains a quote or backslash, which cannot appear in a policy condition literal.`);
5873
+ }
5874
+ if (x.length === 0 || !x.includes("@")) {
5875
+ throw new Error(`Sender extras: destination ${JSON.stringify(x)} on chain "${chainKey}" is not a composed destination (<caip19-asset>@<account>). Build it with buildEscrowDestination.`);
5876
+ }
5877
+ if (Buffer.byteLength(x, "utf8") > MAX_DESTINATION_BYTES) {
5878
+ throw new Error(`Sender extras: destination ${JSON.stringify(x)} on chain "${chainKey}" is longer than ${MAX_DESTINATION_BYTES} bytes, which the escrow rejects as DestinationTooLong, so no deposit could ever carry it.`);
5879
+ }
5880
+ }
5881
+ return xs.map((x) => `'${x}'`).join(", ");
5882
+ }
5883
+ var MAX_DESTINATION_BYTES = 256;
5757
5884
  var SOLANA_STANDARD_PROGRAMS = [
5758
5885
  "11111111111111111111111111111111",
5759
5886
  // System
@@ -5783,12 +5910,20 @@ var require_sender_policies = __commonJS({
5783
5910
  }
5784
5911
  function buildSenderPolicies(extras, chains) {
5785
5912
  const policies = [];
5786
- policies.push({
5787
- policyName: "allowSignRawPayload",
5788
- effect: "EFFECT_ALLOW",
5789
- condition: `activity.type in ['ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2', 'ACTIVITY_TYPE_SIGN_RAW_PAYLOADS'] && activity.params.hash_function in ['HASH_FUNCTION_KECCAK256', 'HASH_FUNCTION_NOT_APPLICABLE']`,
5790
- notes: "Allows Permit2 EIP-712 (secp256k1 KECCAK256) and Solana inner-signature (ed25519) signing."
5791
- });
5913
+ const permit2Evm = lower(extras.permit2 ?? exports2.EVM_PERMIT2);
5914
+ for (const chain of chains) {
5915
+ if (chain.kind !== "evm" && chain.kind !== "tron")
5916
+ continue;
5917
+ policies.push(permit2TypedDataAllow(chain, extras, permit2Evm));
5918
+ }
5919
+ if (chains.some((c) => c.kind === "solana")) {
5920
+ policies.push({
5921
+ policyName: "allowEd25519RawPayload",
5922
+ effect: "EFFECT_ALLOW",
5923
+ condition: `activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2' && activity.params.encoding in ['PAYLOAD_ENCODING_HEXADECIMAL', 'PAYLOAD_ENCODING_TEXT_UTF8'] && activity.params.hash_function == 'HASH_FUNCTION_NOT_APPLICABLE'`,
5924
+ notes: "Solana deposit inner signature (ed25519 over the deposit digest). Legal on secp256k1 only with EIP712, which the API enforces, so this stays an ed25519-only path."
5925
+ });
5926
+ }
5792
5927
  for (const chain of chains) {
5793
5928
  if (chain.kind === "evm") {
5794
5929
  const evmChainId = parseInt(chain.chainId.split(":")[1], 10);
@@ -5797,7 +5932,7 @@ var require_sender_policies = __commonJS({
5797
5932
  throw new Error(`Sender extras: chain "${chain.key}" has no allowedTokens. Add at least one ERC-20 contract address the sender's wallet is permitted to approve, or remove this chain.`);
5798
5933
  }
5799
5934
  const tokenList = tokens.map((t) => `'${t}'`).join(", ");
5800
- const permit2Lower = exports2.EVM_PERMIT2.replace(/^0x/, "");
5935
+ const permit2Lower = permit2Evm.replace(/^0x/, "");
5801
5936
  policies.push({
5802
5937
  policyName: `allowApproveToPermit2 (${chain.chainId})`,
5803
5938
  effect: "EFFECT_ALLOW",
@@ -5887,13 +6022,70 @@ var require_sender_policies = __commonJS({
5887
6022
  }
5888
6023
  }
5889
6024
  policies.push({
5890
- policyName: "denyNoOpHash",
6025
+ policyName: "denyNonTypedDataHashFunctions",
6026
+ effect: "EFFECT_DENY",
6027
+ condition: `activity.type in ['ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2', 'ACTIVITY_TYPE_SIGN_RAW_PAYLOADS'] && activity.params.hash_function in ['HASH_FUNCTION_NO_OP', 'HASH_FUNCTION_SHA256', 'HASH_FUNCTION_KECCAK256']`,
6028
+ notes: "NO_OP signs a caller-chosen digest as-is; KECCAK256 signs a caller-chosen preimage, which reproduces any EIP-712 digest and bypasses every typed-data condition."
6029
+ });
6030
+ policies.push({
6031
+ policyName: "denyAccountDelegationEncoding",
5891
6032
  effect: "EFFECT_DENY",
5892
- condition: `activity.type in ['ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2', 'ACTIVITY_TYPE_SIGN_RAW_PAYLOADS'] && activity.params.hash_function == 'HASH_FUNCTION_NO_OP'`,
5893
- notes: "Sender never uses NO_OP; NOT_APPLICABLE is the only allowed raw-payload hash mode."
6033
+ condition: `activity.type in ['ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2', 'ACTIVITY_TYPE_SIGN_RAW_PAYLOADS'] && activity.params.encoding == 'PAYLOAD_ENCODING_EIP7702_AUTHORIZATION'`,
6034
+ notes: "One signature would delegate the sender EOA to an attacker contract."
6035
+ });
6036
+ policies.push({
6037
+ policyName: "denyBatchRawPayloads",
6038
+ effect: "EFFECT_DENY",
6039
+ condition: `activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOADS'`,
6040
+ notes: "Message conditions bind one payload of a batch, so a second could ride along unbound."
5894
6041
  });
5895
6042
  return policies;
5896
6043
  }
6044
+ function permit2TypedDataAllow(chain, extras, permit2Evm) {
6045
+ const escrowsRaw = extras.escrows?.[chain.key] ?? [];
6046
+ if (escrowsRaw.length === 0) {
6047
+ throw new Error(`Sender extras: chain "${chain.key}" has no escrows. Permit2 leaves the transfer recipient out of the signed struct, so the escrow named as \`spender\` IS the funds destination \u2014 without it a stolen key can authorize a pull to anywhere. Read it from payment-gw /v1/defaults?chain_id=${chain.chainId} (escrow_contract).`);
6048
+ }
6049
+ const isTron = chain.kind === "tron";
6050
+ const tronCluster = isTron ? chain.chainId.split(":")[1] ?? "" : "";
6051
+ if (isTron) {
6052
+ const expected = extras.network === "mainnet" ? "mainnet" : "shasta";
6053
+ if (tronCluster !== expected) {
6054
+ throw new Error(`Sender extras: network "${extras.network}" selects the ${expected} Permit2 deployment, but chain "${chain.key}" is "${chain.chainId}". The domain would carry one cluster's Permit2 with another's chain id, which matches no signature the runtime produces.`);
6055
+ }
6056
+ }
6057
+ const permit2 = isTron ? `0x${tronBase58ToEvmHex(exports2.TRON_PERMIT2[tronCluster])}` : permit2Evm;
6058
+ const chainIdValue = isTron ? tronTip712ChainId(chain.chainId) : evmNumericChainId(chain.chainId);
6059
+ const addr = (xs) => quotedLower(xs.map((x) => isTron ? toTronEvmHex(x) : assertEvmAddress(x, chain.key)));
6060
+ const tokens = extras.allowedTokens[chain.key] ?? [];
6061
+ if (tokens.length === 0) {
6062
+ throw new Error(`Sender extras: chain "${chain.key}" has no allowedTokens, so the typed-data allow would not bind which token the permit moves.`);
6063
+ }
6064
+ const tokenClause = ` && eth.eip_712.message['permitted']['token'] in [${addr(tokens)}]`;
6065
+ const reservers = extras.reservers?.[chain.key] ?? [];
6066
+ const releasers = extras.releasers?.[chain.key] ?? [];
6067
+ for (const [role, vals, field] of [
6068
+ ["reservers", reservers, "quote_selector"],
6069
+ ["releasers", releasers, "fulfillment_verifier.account"]
6070
+ ]) {
6071
+ if (vals.length === 0) {
6072
+ throw new Error(`Sender extras: chain "${chain.key}" has no ${role}. Either witness role can divert funds at settlement and the payer pins neither client-side, so leaving this unset is a hole this policy set is meant to close. Read it from payment-gw /v1/defaults?chain_id=${chain.chainId} (${field}).`);
6073
+ }
6074
+ }
6075
+ const reserverClause = ` && eth.eip_712.message['witness']['reserver'] in [${addr(reservers)}]`;
6076
+ const releaserClause = ` && eth.eip_712.message['witness']['releaser'] in [${addr(releasers)}]`;
6077
+ const destinations = extras.allowedDestinations?.[chain.key] ?? [];
6078
+ if (destinations.length === 0) {
6079
+ throw new Error(`Sender extras: chain "${chain.key}" has no allowedDestinations. Without them a stolen key can authorize a deposit whose payout instruction names the attacker, which is the hole this policy set exists to close. Compose each entry with buildEscrowDestination, or remove the chain.`);
6080
+ }
6081
+ const destinationClause = ` && eth.eip_712.message['witness']['destination'] in [${quotedExact(destinations, chain.key)}]`;
6082
+ return {
6083
+ policyName: `allowPermit2DepositTypedData (${chain.chainId})`,
6084
+ effect: "EFFECT_ALLOW",
6085
+ condition: `activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2' && activity.params.encoding == 'PAYLOAD_ENCODING_EIP712' && activity.params.hash_function == 'HASH_FUNCTION_NOT_APPLICABLE' && eth.eip_712.primary_type == '${PERMIT2_PRIMARY_TYPE}' && eth.eip_712.domain.name == '${PERMIT2_DOMAIN_NAME}' && eth.eip_712.domain.verifying_contract == '${permit2}' && eth.eip_712.domain.chain_id == ${chainIdValue} && eth.eip_712.message['spender'] in [${addr(escrowsRaw)}]` + tokenClause + reserverClause + releaserClause + destinationClause,
6086
+ notes: "The sender's only fund-moving signature: a Permit2 deposit authorization into an allowlisted escrow, for an allowlisted token, committing to an allowlisted destination."
6087
+ };
6088
+ }
5897
6089
  function tronBase58ToEvmHex(b58) {
5898
6090
  const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
5899
6091
  let bn = 0n;
@@ -6197,7 +6389,7 @@ var require_admin = __commonJS({
6197
6389
  "../key-management/providers/turnkey/typescript/dist/admin/index.js"(exports2) {
6198
6390
  "use strict";
6199
6391
  Object.defineProperty(exports2, "__esModule", { value: true });
6200
- exports2.validateExtras = exports2.buildExtrasPolicies = exports2.tronBase58ToEvmHex = exports2.TRON_PERMIT2 = exports2.EVM_PERMIT2 = exports2.buildSenderPolicies = exports2.listPolicies = exports2.derivePoliciesFromAllowlist = exports2.deletePolicy = exports2.buildDenyApproveToNonAllowedSpenderTron = exports2.buildDenyApproveToNonAllowedSpenderEvm = exports2.buildAllowSignRawPayloadPolicy = exports2.applyPolicies = exports2.createWalletWithChainAccounts = exports2.planRevocation = exports2.listUsers = exports2.isExpiredApiKey = exports2.isDurableApiKey = exports2.getUser = exports2.findApiKeyByPublicKey = exports2.deleteApiKeys = exports2.addApiKeys = exports2.UnsafeRevocationError = exports2.MAX_API_KEYS_PER_USER = exports2.listPendingActivities = exports2.getRootQuorum = exports2.getActivity = exports2.approvedVoterIds = exports2.approveActivity = exports2.provisionAgentUser = exports2.deleteSubOrganization = exports2.listSubOrganizations = exports2.createSubOrganization = void 0;
6392
+ exports2.validateExtras = exports2.buildExtrasPolicies = exports2.tronTip712ChainId = exports2.tronBase58ToEvmHex = exports2.toTronEvmHex = exports2.TRON_PERMIT2 = exports2.EVM_PERMIT2 = exports2.buildSenderPolicies = exports2.planPolicyChanges = exports2.listPolicies = exports2.derivePoliciesFromAllowlist = exports2.deletePolicy = exports2.buildDenyApproveToNonAllowedSpenderTron = exports2.buildDenyApproveToNonAllowedSpenderEvm = exports2.buildAllowSignRawPayloadPolicy = exports2.applyPolicies = exports2.createWalletWithChainAccounts = exports2.planRevocation = exports2.listUsers = exports2.isExpiredApiKey = exports2.isDurableApiKey = exports2.getUser = exports2.findApiKeyByPublicKey = exports2.deleteApiKeys = exports2.addApiKeys = exports2.UnsafeRevocationError = exports2.MAX_API_KEYS_PER_USER = exports2.listPendingActivities = exports2.getRootQuorum = exports2.getActivity = exports2.approvedVoterIds = exports2.approveActivity = exports2.provisionAgentUser = exports2.deleteSubOrganization = exports2.listSubOrganizations = exports2.createSubOrganization = void 0;
6201
6393
  var sub_organizations_1 = require_sub_organizations();
6202
6394
  Object.defineProperty(exports2, "createSubOrganization", { enumerable: true, get: function() {
6203
6395
  return sub_organizations_1.createSubOrganization;
@@ -6287,6 +6479,9 @@ var require_admin = __commonJS({
6287
6479
  Object.defineProperty(exports2, "listPolicies", { enumerable: true, get: function() {
6288
6480
  return policies_1.listPolicies;
6289
6481
  } });
6482
+ Object.defineProperty(exports2, "planPolicyChanges", { enumerable: true, get: function() {
6483
+ return policies_1.planPolicyChanges;
6484
+ } });
6290
6485
  var sender_policies_1 = require_sender_policies();
6291
6486
  Object.defineProperty(exports2, "buildSenderPolicies", { enumerable: true, get: function() {
6292
6487
  return sender_policies_1.buildSenderPolicies;
@@ -6297,9 +6492,15 @@ var require_admin = __commonJS({
6297
6492
  Object.defineProperty(exports2, "TRON_PERMIT2", { enumerable: true, get: function() {
6298
6493
  return sender_policies_1.TRON_PERMIT2;
6299
6494
  } });
6495
+ Object.defineProperty(exports2, "toTronEvmHex", { enumerable: true, get: function() {
6496
+ return sender_policies_1.toTronEvmHex;
6497
+ } });
6300
6498
  Object.defineProperty(exports2, "tronBase58ToEvmHex", { enumerable: true, get: function() {
6301
6499
  return sender_policies_1.tronBase58ToEvmHex;
6302
6500
  } });
6501
+ Object.defineProperty(exports2, "tronTip712ChainId", { enumerable: true, get: function() {
6502
+ return sender_policies_1.tronTip712ChainId;
6503
+ } });
6303
6504
  var extras_policies_1 = require_extras_policies();
6304
6505
  Object.defineProperty(exports2, "buildExtrasPolicies", { enumerable: true, get: function() {
6305
6506
  return extras_policies_1.buildExtrasPolicies;
@@ -6543,11 +6744,14 @@ __export(index_exports, {
6543
6744
  $GetPaymentStatusResponse: () => $GetPaymentStatusResponse,
6544
6745
  $OwnedAsset: () => $OwnedAsset,
6545
6746
  $PaymentBlockchainContext: () => $PaymentBlockchainContext,
6546
- $PaymentError: () => $PaymentError,
6747
+ $PaymentFailure: () => $PaymentFailure,
6547
6748
  $PaymentRequest: () => $PaymentRequest,
6548
6749
  $PaymentResponse: () => $PaymentResponse,
6750
+ $PaymentStatus: () => $PaymentStatus,
6549
6751
  $PaymentSummary: () => $PaymentSummary,
6550
6752
  $PaymentTimelineResponse: () => $PaymentTimelineResponse,
6753
+ $PaymentTransaction: () => $PaymentTransaction,
6754
+ $PaymentTransactions: () => $PaymentTransactions,
6551
6755
  $PreparePaymentRequest: () => $PreparePaymentRequest,
6552
6756
  $PreparePaymentResponse: () => $PreparePaymentResponse,
6553
6757
  $Quote: () => $Quote,
@@ -6558,7 +6762,6 @@ __export(index_exports, {
6558
6762
  $SenderAuth: () => $SenderAuth,
6559
6763
  $SenderAuthMessageScheme: () => $SenderAuthMessageScheme,
6560
6764
  $SignedMessage: () => $SignedMessage,
6561
- $TimelineError: () => $TimelineError,
6562
6765
  $TimelineStep: () => $TimelineStep,
6563
6766
  $VerifiableCredential: () => $VerifiableCredential,
6564
6767
  $VerifiableCredentialAuth: () => $VerifiableCredentialAuth,
@@ -7501,6 +7704,9 @@ var PaymentGatewayClient = class {
7501
7704
  }
7502
7705
  };
7503
7706
 
7707
+ // src/timeout-http-request.ts
7708
+ var import_axios2 = __toESM(require("axios"));
7709
+
7504
7710
  // src/errors.ts
7505
7711
  var GatewayTimeoutError = class extends Error {
7506
7712
  constructor(baseUrl, timeoutMs) {
@@ -7574,6 +7780,12 @@ function isAxiosTimeout(error) {
7574
7780
  if (failure.code === "ECONNABORTED" || failure.code === "ETIMEDOUT") return true;
7575
7781
  return failure.code === "ERR_BAD_RESPONSE" && /stream has been aborted/i.test(failure.message ?? "");
7576
7782
  }
7783
+ function dropPartialResponseOnTimeout(error) {
7784
+ if (isAxiosTimeout(error) && error !== null && typeof error === "object" && "response" in error) {
7785
+ delete error.response;
7786
+ }
7787
+ return error;
7788
+ }
7577
7789
  function translateTimeout(error, baseUrl, fallbackTimeoutMs) {
7578
7790
  if (!isAxiosTimeout(error)) return error;
7579
7791
  const configured = error.config?.timeout;
@@ -7581,6 +7793,11 @@ function translateTimeout(error, baseUrl, fallbackTimeoutMs) {
7581
7793
  }
7582
7794
 
7583
7795
  // src/timeout-http-request.ts
7796
+ var timeoutAxios = import_axios2.default.create();
7797
+ timeoutAxios.interceptors.response.use(
7798
+ void 0,
7799
+ (error) => Promise.reject(dropPartialResponseOnTimeout(error))
7800
+ );
7584
7801
  function withRequestTimeout(config, timeouts) {
7585
7802
  const request2 = new Interceptors();
7586
7803
  for (const fn of config?.interceptors?.request?._fns ?? []) request2.use(fn);
@@ -7596,7 +7813,7 @@ var TimeoutHttpRequest = class extends AxiosHttpRequest {
7596
7813
  }
7597
7814
  request(options) {
7598
7815
  return new CancelablePromise((resolve2, reject, onCancel) => {
7599
- const pending = super.request(options);
7816
+ const pending = request(this.config, options, timeoutAxios);
7600
7817
  onCancel(() => pending.cancel());
7601
7818
  pending.then(resolve2, (error) => {
7602
7819
  const request2 = { method: options.method, url: options.url, wait: options.query?.wait };
@@ -8046,7 +8263,7 @@ a past value is rejected with 400.`,
8046
8263
  type: "string",
8047
8264
  format: "date-time",
8048
8265
  description: `Required. The final deadline for completing the payment. If not completed by this time the
8049
- payment is cancelled and eligible for a refund. The gateway injects no default and validates
8266
+ payment fails and is eligible for a refund. The gateway injects no default and validates
8050
8267
  the value is in the future. The originator must supply it, and a request that omits it or
8051
8268
  supplies a past value is rejected with 400.`,
8052
8269
  example: "2024-12-25T11:00:00Z"
@@ -8394,6 +8611,104 @@ var $VerifiableCredential = {
8394
8611
  }
8395
8612
  }
8396
8613
  };
8614
+ var $PaymentStatus = {
8615
+ type: "string",
8616
+ description: `Where your payment is in its lifecycle. One payment reads the same however you ask
8617
+ about it.
8618
+
8619
+ - \`pending\`: accepted and in progress. Nothing has reached the recipient yet.
8620
+ - \`finalizing\`: the transaction paying your recipient is on chain and is accruing
8621
+ the confirmations its chain requires. NOT FINAL, see below.
8622
+ - \`completed\`: delivered, with the required confirmations behind it.
8623
+ - \`failed\`: did not complete. Any funds held in escrow are returned, and \`error\`
8624
+ describes what went wrong.
8625
+
8626
+ \`completed\` and \`failed\` are final and will not change afterwards. \`pending\` and
8627
+ \`finalizing\` will.
8628
+
8629
+ **Do not treat \`finalizing\` as delivered.** It says the payment has been made on
8630
+ chain but is not yet irreversible, much as a card authorization is not yet a
8631
+ settlement. It normally becomes \`completed\`, and it can still become \`failed\` if
8632
+ the transaction never reaches the confirmation depth its chain requires. Acting on
8633
+ \`finalizing\` \u2014 releasing goods, crediting an account \u2014 means accepting that risk
8634
+ deliberately, at whatever threshold suits you rather than the one we wait for.
8635
+
8636
+ \`finalizing\` is about paying the recipient. While your own funds are still being
8637
+ committed on the source chain the payment is \`pending\`, because nothing has reached
8638
+ the recipient yet.
8639
+ `,
8640
+ enum: ["pending", "finalizing", "completed", "failed"],
8641
+ example: "pending"
8642
+ };
8643
+ var $PaymentTransaction = {
8644
+ type: "object",
8645
+ description: `One on-chain transaction belonging to a payment: which chain, which transaction, and
8646
+ which block it landed in.
8647
+
8648
+ Whether the payment has actually happened is answered by \`status\`, not here. Read this
8649
+ to look the transaction up on chain and to verify it yourself.
8650
+ `,
8651
+ required: ["transaction_hash", "chain_id"],
8652
+ properties: {
8653
+ transaction_hash: {
8654
+ type: "string",
8655
+ description: `The transaction's hash on its chain. Hex hashes carry the \`0x\` prefix, including on
8656
+ Tron, whose own tooling omits it.
8657
+ `,
8658
+ pattern: "^(0x[a-fA-F0-9]{64}|[1-9A-HJ-NP-Za-km-z]{32,88})$",
8659
+ example: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
8660
+ },
8661
+ chain_id: {
8662
+ type: "string",
8663
+ description: "CAIP-2 identifier of the chain the transaction is on.",
8664
+ pattern: "^[a-z0-9]+:[a-zA-Z0-9_-]+$",
8665
+ example: "eip155:42161"
8666
+ },
8667
+ block_number: {
8668
+ type: "integer",
8669
+ description: `The block the transaction landed in. Absent until it has been mined.
8670
+
8671
+ Provisional while \`status\` is \`finalizing\`: on a chain that settles against another,
8672
+ a reorganization there can move the transaction to a different block. Settled once
8673
+ \`status\` is \`completed\` \u2014 keep it as a final record only from then.
8674
+ `,
8675
+ example: 61234567
8676
+ }
8677
+ }
8678
+ };
8679
+ var $PaymentTransactions = {
8680
+ type: "object",
8681
+ description: `The transactions a payment has produced, one entry per stage, added as each becomes
8682
+ known. A stage absent here has produced no transaction yet.
8683
+
8684
+ These are the two movements that decide whether your payment happened: your funds
8685
+ being committed, and your recipient being paid. Present on every outcome, so a
8686
+ payment that did not complete can still be traced on chain.
8687
+ \`fulfillment_confirmation\` is not a substitute: it is written only once a payment
8688
+ completes, and describes the finished delivery rather than progress towards it.
8689
+
8690
+ Where a stage is attempted more than once, the entry describes the attempt that
8691
+ counts \u2014 the one that succeeded, or the last one if none did.
8692
+ `,
8693
+ properties: {
8694
+ deposit: {
8695
+ allOf: [
8696
+ {
8697
+ "$ref": "#/components/schemas/PaymentTransaction"
8698
+ }
8699
+ ],
8700
+ description: "Committing your funds on the source chain."
8701
+ },
8702
+ fulfillment: {
8703
+ allOf: [
8704
+ {
8705
+ "$ref": "#/components/schemas/PaymentTransaction"
8706
+ }
8707
+ ],
8708
+ description: "Paying your recipient on the destination chain."
8709
+ }
8710
+ }
8711
+ };
8397
8712
  var $PaymentResponse = {
8398
8713
  type: "object",
8399
8714
  description: `Response from submitting a payment request. If settlement completes inside the
@@ -8401,9 +8716,9 @@ gateway's synchronous window, the response includes a fulfillment_confirmation w
8401
8716
  full settlement details. Otherwise you receive a payment_id plus the payment's
8402
8717
  current \`status\`, and can poll /v1/payments/{paymentId}/status for updates.
8403
8718
 
8404
- Read \`status\` before deciding what to do next: a \`pending\` payment is in flight and
8405
- must NOT be re-submitted under a new request_id (that would be a second payment),
8406
- whereas a \`failed\` or \`cancelled\` one is terminal \u2014 re-submitting it under the SAME
8719
+ Read \`status\` before deciding what to do next: a \`pending\` or \`finalizing\` payment is
8720
+ in flight and must NOT be re-submitted under a new request_id (that would be a second
8721
+ payment), whereas a \`failed\` one is terminal \u2014 re-submitting it under the SAME
8407
8722
  request_id resolves to the same terminal payment, so a genuine re-attempt needs a
8408
8723
  new request_id.
8409
8724
 
@@ -8413,6 +8728,10 @@ settlement lands inside the window you get \`status: completed\`, a full
8413
8728
  \`quote_id\` and \`fulfillment_quote\`. The fast path therefore needs no follow-up call to
8414
8729
  verify: recompute \`quote_hash\` over the returned quote and compare it against the on-chain
8415
8730
  commitment from this response alone.
8731
+
8732
+ \`status\` is present on every response. \`completed\` is always accompanied by
8733
+ fulfillment_confirmation; \`failed\` is accompanied by \`error\` where a reason has been
8734
+ recorded.
8416
8735
  `,
8417
8736
  required: ["payment_id", "status", "idempotent_replay"],
8418
8737
  properties: {
@@ -8423,19 +8742,10 @@ commitment from this response alone.
8423
8742
  example: "0x761989729fefb4b0cb8b3e6f787301a3878c91e8fba35ed362a079292879f34f"
8424
8743
  },
8425
8744
  status: {
8426
- type: "string",
8427
- enum: ["pending", "completed", "failed", "cancelled"],
8428
- description: `Current status of the payment, with the same meaning as on
8429
- /v1/payments/{paymentId}/status:
8430
- - \`pending\`: accepted and being processed
8431
- - \`completed\`: successfully delivered
8432
- - \`failed\`: failed (funds returned if escrowed)
8433
- - \`cancelled\`: cancelled before completion
8434
-
8435
- Present on every response. \`completed\` is always accompanied by
8436
- fulfillment_confirmation; \`failed\` is accompanied by \`error\` where a reason has
8437
- been recorded.
8438
- `
8745
+ "$ref": "#/components/schemas/PaymentStatus"
8746
+ },
8747
+ transactions: {
8748
+ "$ref": "#/components/schemas/PaymentTransactions"
8439
8749
  },
8440
8750
  idempotent_replay: {
8441
8751
  type: "boolean",
@@ -8498,7 +8808,7 @@ the status endpoint rather than treat the payment as unverified.
8498
8808
  "$ref": "#/components/schemas/FulfillmentConfirmation"
8499
8809
  },
8500
8810
  error: {
8501
- "$ref": "#/components/schemas/PaymentError"
8811
+ "$ref": "#/components/schemas/PaymentFailure"
8502
8812
  }
8503
8813
  }
8504
8814
  };
@@ -8512,14 +8822,10 @@ var $GetPaymentStatusResponse = {
8512
8822
  example: "0x761989729fefb4b0cb8b3e6f787301a3878c91e8fba35ed362a079292879f34f"
8513
8823
  },
8514
8824
  status: {
8515
- type: "string",
8516
- enum: ["pending", "completed", "failed", "cancelled"],
8517
- description: `Current status of your payment:
8518
- - \`pending\`: Payment is being processed
8519
- - \`completed\`: Payment successfully delivered
8520
- - \`failed\`: Payment failed (funds returned if escrowed)
8521
- - \`cancelled\`: Payment was cancelled before completion
8522
- `
8825
+ "$ref": "#/components/schemas/PaymentStatus"
8826
+ },
8827
+ transactions: {
8828
+ "$ref": "#/components/schemas/PaymentTransactions"
8523
8829
  },
8524
8830
  updated_at: {
8525
8831
  type: "string",
@@ -8562,7 +8868,7 @@ JSON passthrough.
8562
8868
  "$ref": "#/components/schemas/FulfillmentConfirmation"
8563
8869
  },
8564
8870
  error: {
8565
- "$ref": "#/components/schemas/PaymentError"
8871
+ "$ref": "#/components/schemas/PaymentFailure"
8566
8872
  },
8567
8873
  requested_count: {
8568
8874
  type: "integer",
@@ -8589,37 +8895,51 @@ As on the quote-request endpoints, the free-form decline detail is never relayed
8589
8895
  }
8590
8896
  }
8591
8897
  };
8592
- var $PaymentError = {
8898
+ var $PaymentFailure = {
8593
8899
  type: "object",
8594
- description: `Error details when payment status is "failed".
8595
- Only present when the payment has failed. Contains a machine-readable
8596
- code for programmatic handling and a human-readable message for debugging.
8900
+ description: `Why a payment failed. Present only when \`status\` is \`failed\`, and identical
8901
+ however you ask about the payment.
8902
+
8903
+ \`code\` is the stable, machine-readable identity of the failure \u2014 branch on it
8904
+ rather than on \`message\`, which is written for a person and may be reworded.
8905
+ \`docs_url\` points at the page describing that code.
8597
8906
  `,
8598
8907
  required: ["code", "message"],
8599
8908
  properties: {
8600
8909
  code: {
8601
8910
  type: "string",
8602
- description: `Public error category in SCREAMING_SNAKE_CASE.
8603
- Common codes:
8604
- - \`SETTLEMENT_FAILED\`: The settlement could not be completed
8605
- - \`NO_QUOTES_RECEIVED\`: No quotes arrived within the auction window
8606
- - \`INTERNAL_ERROR\`: An unexpected error occurred
8911
+ description: `Public error category in SCREAMING_SNAKE_CASE. Common codes:
8912
+ - \`SETTLEMENT_FAILED\`: the settlement could not be completed
8913
+ - \`NO_QUOTES_RECEIVED\`: no quotes arrived within the auction window
8914
+ - \`INTERNAL_ERROR\`: an unexpected error occurred
8607
8915
  `,
8608
8916
  example: "SETTLEMENT_FAILED"
8609
8917
  },
8610
8918
  message: {
8611
8919
  type: "string",
8612
- description: `Human-readable error description with additional context.
8920
+ description: `Human-readable description of the failure, for a person reading it. Do not
8921
+ branch on this text.
8613
8922
  `,
8614
8923
  example: "No quotes received within the auction window"
8615
8924
  },
8616
8925
  domain: {
8617
8926
  type: "string",
8618
- description: `Service domain where the error originated.
8927
+ description: `Which part of the system reported the failure.
8619
8928
  `,
8620
8929
  enum: ["PAYMENT_GATEWAY", "SETTLER_GATEWAY", "SETTLER_AGENT", "WALLET_ORCHESTRATION", "VERIFICATION_SERVICE", "BLOCKCHAIN", "EXTERNAL_SERVICE"],
8621
8930
  example: "PAYMENT_GATEWAY"
8622
8931
  },
8932
+ docs_url: {
8933
+ type: "string",
8934
+ format: "uri",
8935
+ description: "Link to the documentation page for this public code."
8936
+ },
8937
+ retry_classification: {
8938
+ type: "string",
8939
+ description: `What the caller should do next. Absent means the condition has not been classified, which is not the same as safe to retry.
8940
+ Re-sending the same \`request_id\` is an idempotent replay and always safe. This value is about submitting a new one, which starts a new payment. See https://docs.atum.xyz/errors for the value set.`,
8941
+ example: "RECONCILE_THEN_DECIDE"
8942
+ },
8623
8943
  blockchain_context: {
8624
8944
  "$ref": "#/components/schemas/PaymentBlockchainContext"
8625
8945
  }
@@ -8627,46 +8947,46 @@ Common codes:
8627
8947
  };
8628
8948
  var $PaymentBlockchainContext = {
8629
8949
  type: "object",
8630
- description: `Blockchain-specific error context. Only present when the error
8631
- originated from an on-chain operation (e.g., escrow revert,
8632
- fulfillment failure).
8633
- `,
8950
+ description: `Where on chain a failed payment failed. Present only when the failure happened
8951
+ on chain \u2014 an escrow revert, or a fulfillment that could not be delivered \u2014 so a
8952
+ payment that failed before any transaction was sent carries no context here.`,
8634
8953
  properties: {
8635
8954
  chain_id: {
8636
8955
  type: "string",
8637
8956
  description: "CAIP-2 chain identifier",
8638
- example: "eip155:42161"
8957
+ pattern: "^[a-z0-9]+:[a-zA-Z0-9_-]+$"
8639
8958
  },
8640
- tx_hash: {
8959
+ transaction_hash: {
8641
8960
  type: "string",
8642
8961
  description: "Failed transaction hash",
8643
- example: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
8962
+ pattern: "^(0x[a-fA-F0-9]{64}|[1-9A-HJ-NP-Za-km-z]{32,88})$"
8644
8963
  },
8645
8964
  block_number: {
8646
8965
  type: "integer",
8647
- description: "Block number where error occurred",
8648
- example: 12345678
8966
+ description: "Block number where error occurred"
8649
8967
  },
8650
8968
  contract_address: {
8651
8969
  type: "string",
8652
- description: "Contract address involved in the error",
8653
- example: "0x1234567890abcdef1234567890abcdef12345678"
8970
+ description: "Contract that caused the error",
8971
+ pattern: "^(0x[a-fA-F0-9]{40}|[1-9A-HJ-NP-Za-km-z]{32,44})$"
8654
8972
  },
8655
8973
  revert_reason: {
8656
8974
  type: "string",
8657
- description: "Smart contract revert reason",
8658
- example: "Insufficient balance"
8975
+ description: "Smart contract revert reason"
8659
8976
  },
8660
8977
  gas_used: {
8661
8978
  type: "string",
8662
- description: "Gas consumed before failure",
8663
- example: "21000"
8979
+ description: "Gas consumed before failure"
8664
8980
  },
8665
8981
  estimated_gas_needed: {
8666
8982
  type: "string",
8667
- description: "Estimated gas needed for success",
8668
- example: "50000"
8983
+ description: "Estimated gas needed for success"
8669
8984
  }
8985
+ },
8986
+ "x-go-type": "atumerror.BlockchainContext",
8987
+ "x-go-type-import": {
8988
+ name: "atumerror",
8989
+ path: "github.com/atum-labs/protocol/schemas/apis/error/v1/bindings/go"
8670
8990
  }
8671
8991
  };
8672
8992
  var $PreparePaymentRequest = {
@@ -8796,15 +9116,10 @@ structured error describing where and why.
8796
9116
  example: "0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f"
8797
9117
  },
8798
9118
  status: {
8799
- type: "string",
8800
- enum: ["pending", "settling", "completed", "failed", "cancelled"],
8801
- description: `High-level status:
8802
- - \`pending\`: Bidding, awarded, or early in settlement
8803
- - \`settling\`: Settlement in progress (on-chain steps executing)
8804
- - \`completed\`: Payment successfully delivered
8805
- - \`failed\`: Payment failed
8806
- - \`cancelled\`: Payment was cancelled
8807
- `
9119
+ "$ref": "#/components/schemas/PaymentStatus"
9120
+ },
9121
+ transactions: {
9122
+ "$ref": "#/components/schemas/PaymentTransactions"
8808
9123
  },
8809
9124
  created_at: {
8810
9125
  type: "string",
@@ -8823,7 +9138,7 @@ structured error describing where and why.
8823
9138
  "$ref": "#/components/schemas/PaymentSummary"
8824
9139
  },
8825
9140
  error: {
8826
- "$ref": "#/components/schemas/TimelineError"
9141
+ "$ref": "#/components/schemas/PaymentFailure"
8827
9142
  },
8828
9143
  steps: {
8829
9144
  type: "array",
@@ -8877,40 +9192,6 @@ Only set when the source asset's decimals are known via the token registry.
8877
9192
  }
8878
9193
  }
8879
9194
  };
8880
- var $TimelineError = {
8881
- type: "object",
8882
- description: "Structured error details when a payment has failed",
8883
- required: ["code", "message"],
8884
- properties: {
8885
- code: {
8886
- type: "string",
8887
- description: "Machine-readable error code",
8888
- example: "ESCROW_DEPOSIT_FAILED"
8889
- },
8890
- message: {
8891
- type: "string",
8892
- description: "Human-readable error description"
8893
- },
8894
- domain: {
8895
- type: "string",
8896
- description: "Which component reported the error",
8897
- example: "SETTLER_AGENT"
8898
- },
8899
- chain_id: {
8900
- type: "string",
8901
- description: "CAIP-2 chain where the error occurred (if on-chain)",
8902
- example: "eip155:1"
8903
- },
8904
- tx_hash: {
8905
- type: "string",
8906
- description: "Transaction hash of the failed on-chain attempt (if applicable)"
8907
- },
8908
- revert_reason: {
8909
- type: "string",
8910
- description: "Smart-contract revert reason (if the error was an on-chain revert)"
8911
- }
8912
- }
8913
- };
8914
9195
  var $TimelineStep = {
8915
9196
  type: "object",
8916
9197
  required: ["name", "label", "status"],
@@ -8951,7 +9232,7 @@ var $TimelineStep = {
8951
9232
  description: "CAIP-2 chain this step happened on (if on-chain)",
8952
9233
  example: "eip155:1"
8953
9234
  },
8954
- tx_hash: {
9235
+ transaction_hash: {
8955
9236
  type: "string",
8956
9237
  description: "Transaction hash associated with this step (if on-chain)"
8957
9238
  },
@@ -9071,7 +9352,7 @@ the future. Must be strictly earlier than fulfillment_deadline.
9071
9352
  fulfillment_deadline: {
9072
9353
  type: "string",
9073
9354
  format: "date-time",
9074
- description: `Required. Final deadline for completing the payment. Past it the payment is cancelled and
9355
+ description: `Required. Final deadline for completing the payment. Past it the payment fails and
9075
9356
  eligible for refund. The gateway injects no default and never mutates the
9076
9357
  originator-supplied body, so the value is carried through verbatim to the award call. It
9077
9358
  must be supplied and must be in the future. Must be strictly later than quote_deadline.
@@ -9579,9 +9860,9 @@ agent appears under one reason only.
9579
9860
  },
9580
9861
  retry_classification: {
9581
9862
  type: "string",
9582
- description: `What would have to change for a settler giving this reason to bid, drawn from the same
9583
- closed set as the \`retry_classification\` on an error response so a caller reads one
9584
- vocabulary.
9863
+ description: `What would have to change for a settler giving this reason to submit a price quote,
9864
+ drawn from the same closed set as the \`retry_classification\` on an error response so
9865
+ a caller reads one vocabulary.
9585
9866
 
9586
9867
  It describes the decline only. The authoritative instruction for the payment is the
9587
9868
  \`retry_classification\` on its own error response: a payment can fail for a reason no
@@ -9591,6 +9872,14 @@ Optional, and a pattern-constrained string for the same reason \`DeclineReason\`
9591
9872
  `,
9592
9873
  pattern: "^[A-Z][A-Z0-9_]*$",
9593
9874
  example: "RETRY_AFTER_DELAY"
9875
+ },
9876
+ docs_url: {
9877
+ type: "string",
9878
+ format: "uri",
9879
+ description: `Link to the documentation for this reason. Absent rather than empty when no page is
9880
+ published, so a reader never follows a link to the site root.
9881
+ `,
9882
+ example: "https://docs.atum.xyz/decline-reasons#insufficient-liquidity"
9594
9883
  }
9595
9884
  }
9596
9885
  };
@@ -9864,7 +10153,7 @@ var $ChainDefaultsByChain = {
9864
10153
 
9865
10154
  // src/payment-tracking.ts
9866
10155
  function isTerminalStatus(status) {
9867
- return status === "completed" || status === "failed" || status === "cancelled";
10156
+ return status === "completed" || status === "failed";
9868
10157
  }
9869
10158
  var DEFAULT_WAIT_SECONDS = 60;
9870
10159
  var DEFAULT_WAIT_BUDGET_MS = DEFAULT_WAIT_SECONDS * 1e3;
@@ -9983,7 +10272,7 @@ function createSolanaDepositPrehash(paymentId, params) {
9983
10272
  }
9984
10273
  function hashSolanaDeposit(_prehash) {
9985
10274
  throw new Error(
9986
- 'hashSolanaDeposit computes the pre-domain-separation Solana deposit hash (199-byte preimage, no "escrow"/version/cluster_id/program_id prefix and no destination_hash). No deployed escrow program accepts it \u2014 on-chain verification rejects it with InvalidData on every cluster \u2014 so it cannot be used to build a deposit. Use the shared sender_auth adapter instead: getChainAdapter(chainId).buildAuthMessage({ ... }), which picks the preimage that matches the escrow domain version and is what the facilitator verifies against.'
10275
+ 'hashSolanaDeposit computes the pre-domain-separation Solana deposit hash (199-byte preimage, no "escrow"/version/cluster_id/program_id prefix and no destination_hash). No deployed escrow program accepts it \u2014 on-chain verification rejects it with DepositHashMismatch on every cluster \u2014 so it cannot be used to build a deposit. Use the shared sender_auth adapter instead: getChainAdapter(chainId).buildAuthMessage({ ... }), which picks the preimage that matches the escrow domain version and is what the facilitator verifies against.'
9987
10276
  );
9988
10277
  }
9989
10278
  function generateSolanaNonce() {
@@ -10314,8 +10603,8 @@ var PaymentGatewayClient2 = class extends PaymentGatewayClient {
10314
10603
  // reasonable against that type - would otherwise build an EIP-712 domain around a
10315
10604
  // null verifyingContract.
10316
10605
  permit2Contract: data.permit2_contract ?? void 0,
10317
- // Which deposit witness the escrow on this chain pins (CORE-2033). Absent means the
10318
- // four-member CORE-2120 witness — see ChainDefaults.depositWitnessVersion for why
10606
+ // Which deposit witness the escrow on this chain pins. Absent means the
10607
+ // four-member witness — see ChainDefaults.depositWitnessVersion for why
10319
10608
  // absence is the permissive default. EVM/Tron only; Solana uses the svm_* fields below.
10320
10609
  depositWitnessVersion: data.deposit_witness_version ?? void 0,
10321
10610
  // V3 Solana escrow domain separation. Present only for Solana
@@ -10520,11 +10809,14 @@ var PaymentGatewayClient2 = class extends PaymentGatewayClient {
10520
10809
  $GetPaymentStatusResponse,
10521
10810
  $OwnedAsset,
10522
10811
  $PaymentBlockchainContext,
10523
- $PaymentError,
10812
+ $PaymentFailure,
10524
10813
  $PaymentRequest,
10525
10814
  $PaymentResponse,
10815
+ $PaymentStatus,
10526
10816
  $PaymentSummary,
10527
10817
  $PaymentTimelineResponse,
10818
+ $PaymentTransaction,
10819
+ $PaymentTransactions,
10528
10820
  $PreparePaymentRequest,
10529
10821
  $PreparePaymentResponse,
10530
10822
  $Quote,
@@ -10535,7 +10827,6 @@ var PaymentGatewayClient2 = class extends PaymentGatewayClient {
10535
10827
  $SenderAuth,
10536
10828
  $SenderAuthMessageScheme,
10537
10829
  $SignedMessage,
10538
- $TimelineError,
10539
10830
  $TimelineStep,
10540
10831
  $VerifiableCredential,
10541
10832
  $VerifiableCredentialAuth,