@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.
@@ -1,9 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /*
3
- * Copyright (c) 2026 Atum Labs, Inc. All rights reserved.
4
- * Proprietary and confidential.
5
- * Access and use are governed by the LICENSE file distributed with this package.
6
- * Do not remove, alter, or obscure this notice.
3
+ * Copyright 2026 Atum Labs, Inc.
4
+ * SPDX-License-Identifier: Apache-2.0
7
5
  */
8
6
  "use strict";
9
7
  var __create = Object.create;
@@ -12,11 +10,20 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
10
  var __getOwnPropNames = Object.getOwnPropertyNames;
13
11
  var __getProtoOf = Object.getPrototypeOf;
14
12
  var __hasOwnProp = Object.prototype.hasOwnProperty;
15
- var __esm = (fn, res) => function __init() {
16
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
13
+ var __esm = (fn, res, err) => function __init() {
14
+ if (err) throw err[0];
15
+ try {
16
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
17
+ } catch (e) {
18
+ throw err = [e], e;
19
+ }
17
20
  };
18
21
  var __commonJS = (cb, mod) => function __require() {
19
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
22
+ try {
23
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
24
+ } catch (e) {
25
+ throw mod = 0, e;
26
+ }
20
27
  };
21
28
  var __export = (target, all) => {
22
29
  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",
5891
6026
  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."
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",
6032
+ effect: "EFFECT_DENY",
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;
@@ -7404,6 +7605,9 @@ var PaymentGatewayClient = class {
7404
7605
  }
7405
7606
  };
7406
7607
 
7608
+ // src/timeout-http-request.ts
7609
+ var import_axios2 = __toESM(require("axios"));
7610
+
7407
7611
  // src/errors.ts
7408
7612
  var GatewayTimeoutError = class extends Error {
7409
7613
  constructor(baseUrl, timeoutMs) {
@@ -7467,6 +7671,12 @@ function isAxiosTimeout(error) {
7467
7671
  if (failure.code === "ECONNABORTED" || failure.code === "ETIMEDOUT") return true;
7468
7672
  return failure.code === "ERR_BAD_RESPONSE" && /stream has been aborted/i.test(failure.message ?? "");
7469
7673
  }
7674
+ function dropPartialResponseOnTimeout(error) {
7675
+ if (isAxiosTimeout(error) && error !== null && typeof error === "object" && "response" in error) {
7676
+ delete error.response;
7677
+ }
7678
+ return error;
7679
+ }
7470
7680
  function translateTimeout(error, baseUrl, fallbackTimeoutMs) {
7471
7681
  if (!isAxiosTimeout(error)) return error;
7472
7682
  const configured = error.config?.timeout;
@@ -7474,6 +7684,11 @@ function translateTimeout(error, baseUrl, fallbackTimeoutMs) {
7474
7684
  }
7475
7685
 
7476
7686
  // src/timeout-http-request.ts
7687
+ var timeoutAxios = import_axios2.default.create();
7688
+ timeoutAxios.interceptors.response.use(
7689
+ void 0,
7690
+ (error) => Promise.reject(dropPartialResponseOnTimeout(error))
7691
+ );
7477
7692
  function withRequestTimeout(config2, timeouts) {
7478
7693
  const request2 = new Interceptors();
7479
7694
  for (const fn of config2?.interceptors?.request?._fns ?? []) request2.use(fn);
@@ -7489,7 +7704,7 @@ var TimeoutHttpRequest = class extends AxiosHttpRequest {
7489
7704
  }
7490
7705
  request(options) {
7491
7706
  return new CancelablePromise((resolve2, reject, onCancel) => {
7492
- const pending = super.request(options);
7707
+ const pending = request(this.config, options, timeoutAxios);
7493
7708
  onCancel(() => pending.cancel());
7494
7709
  pending.then(resolve2, (error) => {
7495
7710
  const request2 = { method: options.method, url: options.url, wait: options.query?.wait };
@@ -7809,7 +8024,7 @@ var import_chain_address2 = __toESM(require_dist2());
7809
8024
 
7810
8025
  // src/payment-tracking.ts
7811
8026
  function isTerminalStatus(status) {
7812
- return status === "completed" || status === "failed" || status === "cancelled";
8027
+ return status === "completed" || status === "failed";
7813
8028
  }
7814
8029
  var DEFAULT_WAIT_SECONDS = 60;
7815
8030
  var DEFAULT_WAIT_BUDGET_MS = DEFAULT_WAIT_SECONDS * 1e3;
@@ -8169,8 +8384,8 @@ var PaymentGatewayClient2 = class extends PaymentGatewayClient {
8169
8384
  // reasonable against that type - would otherwise build an EIP-712 domain around a
8170
8385
  // null verifyingContract.
8171
8386
  permit2Contract: data.permit2_contract ?? void 0,
8172
- // Which deposit witness the escrow on this chain pins (CORE-2033). Absent means the
8173
- // four-member CORE-2120 witness — see ChainDefaults.depositWitnessVersion for why
8387
+ // Which deposit witness the escrow on this chain pins. Absent means the
8388
+ // four-member witness — see ChainDefaults.depositWitnessVersion for why
8174
8389
  // absence is the permissive default. EVM/Tron only; Solana uses the svm_* fields below.
8175
8390
  depositWitnessVersion: data.deposit_witness_version ?? void 0,
8176
8391
  // V3 Solana escrow domain separation. Present only for Solana
@@ -8385,7 +8600,7 @@ function runCli(program2, ...parseArgs) {
8385
8600
  }
8386
8601
 
8387
8602
  // src/version.ts
8388
- var PACKAGE_VERSION = true ? "3.0.0" : "0.0.0-dev";
8603
+ var PACKAGE_VERSION = true ? "3.0.1" : "0.0.0-dev";
8389
8604
 
8390
8605
  // src/cli/payment-outcome.ts
8391
8606
  var EXIT_COMPLETED = 0;
@@ -8402,7 +8617,7 @@ function describePaymentOutcome(input) {
8402
8617
  summary: `completed: ${payment} settled.${replay}`
8403
8618
  };
8404
8619
  }
8405
- if (status === "failed" || status === "cancelled") {
8620
+ if (status === "failed") {
8406
8621
  const reason = errorCode ? ` (${errorCode})` : "";
8407
8622
  return {
8408
8623
  exitCode: EXIT_TERMINAL_FAILURE,