@pushchain/core 5.1.17 → 5.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/package.json +1 -1
  2. package/src/lib/constants/index.d.ts +1 -1
  3. package/src/lib/constants/index.js +2 -1
  4. package/src/lib/constants/selectors.d.ts +8 -0
  5. package/src/lib/constants/selectors.js +9 -1
  6. package/src/lib/formatters.d.ts +1 -0
  7. package/src/lib/formatters.js +32 -0
  8. package/src/lib/orchestrator/internals/cascade.d.ts +8 -1
  9. package/src/lib/orchestrator/internals/cascade.js +486 -143
  10. package/src/lib/orchestrator/internals/error-decoder.d.ts +2 -6
  11. package/src/lib/orchestrator/internals/error-decoder.js +10 -10
  12. package/src/lib/orchestrator/internals/errors.d.ts +1 -1
  13. package/src/lib/orchestrator/internals/errors.js +7 -4
  14. package/src/lib/orchestrator/internals/execute-standard.js +7 -6
  15. package/src/lib/orchestrator/internals/gas-calculator.js +78 -11
  16. package/src/lib/orchestrator/internals/helpers.d.ts +2 -1
  17. package/src/lib/orchestrator/internals/helpers.js +13 -11
  18. package/src/lib/orchestrator/internals/outbound-sync.d.ts +1 -0
  19. package/src/lib/orchestrator/internals/outbound-sync.js +93 -37
  20. package/src/lib/orchestrator/internals/preflight.d.ts +2 -16
  21. package/src/lib/orchestrator/internals/preflight.js +2 -36
  22. package/src/lib/orchestrator/internals/response-builder.js +23 -7
  23. package/src/lib/orchestrator/internals/route-handlers.js +34 -49
  24. package/src/lib/orchestrator/orchestrator.d.ts +7 -1
  25. package/src/lib/orchestrator/orchestrator.js +40 -2
  26. package/src/lib/orchestrator/orchestrator.types.d.ts +4 -14
  27. package/src/lib/progress-hook/progress-hook.js +13 -20
  28. package/src/lib/push-chain/push-chain.d.ts +11 -1
  29. package/src/lib/push-chain/push-chain.js +2 -2
  30. package/src/lib/universal-tx-detector/cascade.js +14 -4
  31. package/src/lib/universal-tx-detector/child-inbounds.js +9 -1
  32. package/src/lib/universal-tx-detector/detector.js +9 -3
  33. package/src/lib/universal-tx-detector/normalize.d.ts +42 -0
  34. package/src/lib/universal-tx-detector/normalize.js +127 -0
  35. package/src/lib/utils/external-tx-hash.d.ts +37 -0
  36. package/src/lib/utils/external-tx-hash.js +62 -0
@@ -10,12 +10,8 @@
10
10
  * Unknown selectors fall through with `kind: 'unknown'` so callers can log
11
11
  * them at INFO and grow the table from real reverts.
12
12
  *
13
- * The selector→name mappings below are EMPIRICAL: they were observed in
14
- * production e2e logs and SDK test fixtures. `keccak256` of the obvious
15
- * parameterless signatures (e.g. `keccak256("InsufficientBalance()")` =
16
- * `0x01e1e567`) does NOT reproduce the listed selectors, so the deployed-
17
- * source mapping is still unverified. Names and hints are worded as
18
- * "likely cause" until the bytecode-source trace lands.
13
+ * The selector→name mappings below come from source-verified custom errors
14
+ * where available, with production/e2e observations kept as provenance.
19
15
  */
20
16
  export interface KnownErrorSelector {
21
17
  /** Best-effort error name. Worded as a likely cause until source-traced. */
@@ -11,12 +11,8 @@
11
11
  * Unknown selectors fall through with `kind: 'unknown'` so callers can log
12
12
  * them at INFO and grow the table from real reverts.
13
13
  *
14
- * The selector→name mappings below are EMPIRICAL: they were observed in
15
- * production e2e logs and SDK test fixtures. `keccak256` of the obvious
16
- * parameterless signatures (e.g. `keccak256("InsufficientBalance()")` =
17
- * `0x01e1e567`) does NOT reproduce the listed selectors, so the deployed-
18
- * source mapping is still unverified. Names and hints are worded as
19
- * "likely cause" until the bytecode-source trace lands.
14
+ * The selector→name mappings below come from source-verified custom errors
15
+ * where available, with production/e2e observations kept as provenance.
20
16
  */
21
17
  Object.defineProperty(exports, "__esModule", { value: true });
22
18
  exports.ERROR_STRING_SELECTOR = exports.KNOWN_ERROR_SELECTORS = void 0;
@@ -36,10 +32,14 @@ exports.KNOWN_ERROR_SELECTORS = {
36
32
  },
37
33
  '0xf4d678b8': {
38
34
  name: 'InsufficientBalance',
39
- hint: 'Likely cause: UEA does not hold enough of the burn token (PRC-20 mapped from the outbound `funds.token`). ' +
40
- 'For Solana SPL outbounds, ensure UEA holds the corresponding pUSDT.sol / pUSDC.sol mint before retrying. ' +
41
- 'Same selector may also surface from other balance-check reverters; verify burn-token balance first.',
42
- provenance: 'Production e2e: e2e-2026-04-16T16-27-58-082Z.log:342 (R2 SPL fresh-UEA, no pUSDT.sol)',
35
+ hint: 'Likely cause: the executing account does not hold enough of the token being moved. ' +
36
+ 'For Push outbounds, verify the UEA PRC-20 burn-token balance. For CEA→Push routes, verify the source-chain CEA balance.',
37
+ provenance: 'CommonErrors/CEAErrors.InsufficientBalance(); production e2e: e2e-2026-04-16T16-27-58-082Z.log:342',
38
+ },
39
+ '0xb4fa3fb3': {
40
+ name: 'InvalidInput',
41
+ hint: 'Likely cause: contract-level input validation failed. For CEA self-calls, the multicall entry must use value=0 and the encoded sendUniversalTxToUEA amount/revertRecipient must be valid.',
42
+ provenance: 'CommonErrors/CEAErrors.InvalidInput(); observed while replaying failed Route 3 CEA self-call tx 0x6fc0635d76edae0659ff131fd4bbf3349e01946708ce56dc2668d878f34a6077',
43
43
  },
44
44
  '0x66f9d09e': {
45
45
  name: 'GasLimitBelowBase',
@@ -52,7 +52,7 @@ export interface InsufficientUEABalanceErrorOpts {
52
52
  shortfall: bigint;
53
53
  ueaAddress: `0x${string}`;
54
54
  pathTag: PreflightPathTag;
55
- /** 'NATIVE' = UPC shortfall; 'PRC20' = burn-token shortfall. */
55
+ /** 'NATIVE' = native PC shortfall; 'PRC20' = burn-token shortfall. */
56
56
  reason?: PreflightShortfallReason;
57
57
  /** Burn token address (only set when reason === 'PRC20'). */
58
58
  burnToken?: `0x${string}`;
@@ -11,6 +11,7 @@
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.InsufficientUEABalanceError = exports.PushChainExecutionError = void 0;
14
+ const formatters_1 = require("../../formatters");
14
15
  /**
15
16
  * Typed error for Route 1 Push Chain tx failures. Thrown by
16
17
  * `extractPcTxAndTransform` when the final pcTx commits with `status === 'FAILED'`,
@@ -50,13 +51,15 @@ class InsufficientUEABalanceError extends PushChainExecutionError {
50
51
  const tokenSuffix = reason === 'PRC20' && opts.burnToken
51
52
  ? ` of token ${opts.burnToken}`
52
53
  : '';
53
- const currencyLabel = reason === 'PRC20' ? 'units' : 'wei UPC';
54
+ const availableLabel = reason === 'PRC20' ? `${opts.available} units` : (0, formatters_1.formatPc)(opts.available);
55
+ const requiredLabel = reason === 'PRC20' ? `${opts.required} units` : (0, formatters_1.formatPc)(opts.required);
56
+ const shortfallLabel = reason === 'PRC20' ? `${opts.shortfall} units` : (0, formatters_1.formatPc)(opts.shortfall);
54
57
  const remediation = reason === 'PRC20'
55
58
  ? `Bridge the burn token to UEA on Push Chain before retrying.`
56
- : `Bridge >=${opts.shortfall} wei UPC to the UEA on Push Chain before retrying.`;
59
+ : `Bridge >=${shortfallLabel} to the UEA on Push Chain before retrying.`;
57
60
  const message = `InsufficientUEABalance [${opts.pathTag}${segLabel}:${reason}]: ` +
58
- `UEA ${opts.ueaAddress} has ${opts.available} ${currencyLabel}${tokenSuffix}; ` +
59
- `outbound requires ${opts.required} ${currencyLabel}; shortfall ${opts.shortfall} ${currencyLabel}. ` +
61
+ `UEA ${opts.ueaAddress} has ${availableLabel}${tokenSuffix}; ` +
62
+ `outbound requires ${requiredLabel}; shortfall ${shortfallLabel}. ` +
60
63
  remediation;
61
64
  // Lift the structured info into the parent's decodedError so the
62
65
  // orchestrator's outer catch can pass it straight through to the
@@ -16,6 +16,7 @@ const chain_1 = require("../../constants/chain");
16
16
  const enums_1 = require("../../constants/enums");
17
17
  const tx_1 = require("../../generated/v1/tx");
18
18
  const progress_hook_types_1 = require("../../progress-hook/progress-hook.types");
19
+ const formatters_1 = require("../../formatters");
19
20
  const utils_1 = require("../../utils");
20
21
  const evm_client_1 = require("../../vm-client/evm-client");
21
22
  const payload_builders_1 = require("../payload-builders");
@@ -352,15 +353,15 @@ function executeStandardPayload(ctx, execute, eventBuffer, getResponseCallbacks)
352
353
  const maxTransferable = funds + maxFromDeposit;
353
354
  maxTransferableNote =
354
355
  `Max transferable right now (at $1000 cap, pool-limited): ` +
355
- `~${(Number(maxTransferable) / 1e18).toFixed(4)} $PC ` +
356
- `(UEA balance ${(Number(funds) / 1e18).toFixed(4)} + ` +
357
- `pool-safe deposit ${(Number(maxFromDeposit) / 1e18).toFixed(4)} − gas).`;
356
+ `~${(0, formatters_1.formatPc)(maxTransferable, 4)} ` +
357
+ `(UEA balance ${(0, formatters_1.formatPc)(funds, 4)} + ` +
358
+ `pool-safe deposit ${(0, formatters_1.formatPc)(maxFromDeposit, 4)} - gas).`;
358
359
  (0, context_1.printLog)(ctx, `Fee-lock capacity: ${maxTransferableNote}`);
359
360
  }
360
361
  }
361
- throw new Error(`Insufficient deposit: the fee-lock will deposit ~${(Number(safeUPC) / 1e18).toFixed(4)} $PC ` +
362
- `but the transaction requires ~${(Number(requiredFunds) / 1e18).toFixed(4)} $PC ` +
363
- `(shortfall: ~${(Number(shortfall) / 1e18).toFixed(4)} $PC). ` +
362
+ throw new Error(`Insufficient deposit: the fee-lock will deposit ~${(0, formatters_1.formatPc)(safeUPC, 4)} ` +
363
+ `but the transaction requires ~${(0, formatters_1.formatPc)(requiredFunds, 4)} ` +
364
+ `(shortfall: ~${(0, formatters_1.formatPc)(shortfall, 4)}). ` +
364
365
  `The fee-lock deposit is capped at $1000 USD. ` +
365
366
  (maxTransferableNote ? maxTransferableNote + ' ' : '') +
366
367
  `Reduce the transfer value or pre-fund the UEA (${UEA}) on Push Chain.`);
@@ -64,6 +64,31 @@ const UNISWAP_V3_FACTORY_ABI = [
64
64
  stateMutability: 'view',
65
65
  },
66
66
  ];
67
+ const UNISWAP_V3_QUOTER_EXACT_OUTPUT_ABI = [
68
+ {
69
+ type: 'function',
70
+ name: 'quoteExactOutputSingle',
71
+ inputs: [
72
+ {
73
+ type: 'tuple',
74
+ components: [
75
+ { name: 'tokenIn', type: 'address' },
76
+ { name: 'tokenOut', type: 'address' },
77
+ { name: 'amount', type: 'uint256' },
78
+ { name: 'fee', type: 'uint24' },
79
+ { name: 'sqrtPriceLimitX96', type: 'uint160' },
80
+ ],
81
+ },
82
+ ],
83
+ outputs: [
84
+ { name: 'amountIn', type: 'uint256' },
85
+ { name: 'sqrtPriceX96After', type: 'uint160' },
86
+ { name: 'initializedTicksCrossed', type: 'uint32' },
87
+ { name: 'gasEstimate', type: 'uint256' },
88
+ ],
89
+ stateMutability: 'view',
90
+ },
91
+ ];
67
92
  const UNIVERSAL_CORE_SWAP_HELPERS_ABI = [
68
93
  { type: 'function', name: 'WPC', inputs: [], outputs: [{ name: '', type: 'address', internalType: 'address' }], stateMutability: 'view' },
69
94
  { type: 'function', name: 'uniswapV3Factory', inputs: [], outputs: [{ name: '', type: 'address', internalType: 'address' }], stateMutability: 'view' },
@@ -219,7 +244,19 @@ function queryOutboundGasFee(ctx, prc20Token, gasLimit, destinationChain) {
219
244
  */
220
245
  function estimateNativeValueForSwap(ctx, universalCoreAddress, gasToken, gasFee, accountBalance) {
221
246
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
222
- const SWAP_BUFFER = BigInt(2); // 2x safety buffer; excess is refunded by swapAndBurnGas
247
+ var _a, _b;
248
+ // 2.2x safety buffer applied to the pool quote; excess is refunded by
249
+ // swapAndBurnGas. Composed of a 2x pool-slippage cushion plus 10%
250
+ // headroom that used to live in the R2 route-handler callers (×110/100
251
+ // after this function returned). Folded into one place here so the cap
252
+ // branch below correctly bounds the FINAL inflated value — the previous
253
+ // arrangement (outer ×1.10 on top of an inner cap that returned
254
+ // `balance - GAS_RESERVE`) caused a deterministic preflight failure
255
+ // whenever the cap fired: required = 1.10 × (balance − 3 PC) + 3 PC ≈
256
+ // balance × 1.10 − 0.3 PC > balance for any non-trivial balance. See
257
+ // preflight.ts:215.
258
+ const SWAP_BUFFER_NUM = BigInt(22);
259
+ const SWAP_BUFFER_DEN = BigInt(10);
223
260
  const BALANCE_FALLBACK_DIVISOR = BigInt(10); // 10% of balance as fallback
224
261
  const GAS_RESERVE = BigInt(3e18); // 3 UPC reserve for tx overhead
225
262
  try {
@@ -248,6 +285,34 @@ function estimateNativeValueForSwap(ctx, universalCoreAddress, gasToken, gasFee,
248
285
  (0, context_1.printLog)(ctx, `estimateNativeValueForSwap — no fee tier for gasToken, using balance fallback`);
249
286
  return balanceFallback(accountBalance, BALANCE_FALLBACK_DIVISOR, GAS_RESERVE);
250
287
  }
288
+ const pushChain = (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork);
289
+ const quoterAddress = (_b = (_a = chain_1.CHAIN_INFO[pushChain]) === null || _a === void 0 ? void 0 : _a.dex) === null || _b === void 0 ? void 0 : _b.uniV3QuoterV2;
290
+ if (quoterAddress && !quoterAddress.startsWith('0xTBD')) {
291
+ try {
292
+ const quote = yield ctx.pushClient.readContract({
293
+ address: quoterAddress,
294
+ abi: UNISWAP_V3_QUOTER_EXACT_OUTPUT_ABI,
295
+ functionName: 'quoteExactOutputSingle',
296
+ args: [
297
+ {
298
+ tokenIn: wpcAddress,
299
+ tokenOut: gasToken,
300
+ amount: gasFee,
301
+ fee: feeTier,
302
+ sqrtPriceLimitX96: BigInt(0),
303
+ },
304
+ ],
305
+ });
306
+ const exactWpcNeeded = quote[0];
307
+ const result = (exactWpcNeeded * SWAP_BUFFER_NUM) / SWAP_BUFFER_DEN;
308
+ (0, context_1.printLog)(ctx, `estimateNativeValueForSwap — exactOutput quoter=${quoterAddress}, ` +
309
+ `wpcNeeded=${exactWpcNeeded}, withBuffer(2.2x)=${result}`);
310
+ return capSwapEstimate(result, accountBalance, GAS_RESERVE);
311
+ }
312
+ catch (quoteErr) {
313
+ (0, context_1.printLog)(ctx, `estimateNativeValueForSwap — exactOutput quote failed: ${quoteErr instanceof Error ? quoteErr.message : String(quoteErr)}, falling back to slot0 price`);
314
+ }
315
+ }
251
316
  // Get pool address from factory
252
317
  const poolAddress = yield ctx.pushClient.readContract({
253
318
  address: factoryAddress,
@@ -285,17 +350,10 @@ function estimateNativeValueForSwap(ctx, universalCoreAddress, gasToken, gasFee,
285
350
  // price = gasToken_per_WPC → wpcNeeded = gasFee / price
286
351
  wpcNeeded = (gasFee * Q192) / priceNum;
287
352
  }
288
- const result = wpcNeeded * SWAP_BUFFER;
353
+ const result = (wpcNeeded * SWAP_BUFFER_NUM) / SWAP_BUFFER_DEN;
289
354
  (0, context_1.printLog)(ctx, `estimateNativeValueForSwap — pool=${poolAddress}, sqrtPriceX96=${sqrtPriceX96}, ` +
290
- `wpcNeeded=${wpcNeeded}, withBuffer(2x)=${result}`);
291
- // Cap at (balance - reserve)
292
- if (accountBalance > result + GAS_RESERVE) {
293
- return result;
294
- }
295
- else if (accountBalance > GAS_RESERVE) {
296
- return accountBalance - GAS_RESERVE;
297
- }
298
- return result; // let caller decide if balance is too low
355
+ `wpcNeeded=${wpcNeeded}, withBuffer(2.2x)=${result}`);
356
+ return capSwapEstimate(result, accountBalance, GAS_RESERVE);
299
357
  }
300
358
  catch (err) {
301
359
  (0, context_1.printLog)(ctx, `estimateNativeValueForSwap — failed: ${err instanceof Error ? err.message : String(err)}, using balance fallback`);
@@ -303,6 +361,15 @@ function estimateNativeValueForSwap(ctx, universalCoreAddress, gasToken, gasFee,
303
361
  }
304
362
  });
305
363
  }
364
+ function capSwapEstimate(result, accountBalance, reserve) {
365
+ if (accountBalance > result + reserve) {
366
+ return result;
367
+ }
368
+ if (accountBalance > reserve) {
369
+ return accountBalance - reserve;
370
+ }
371
+ return result; // let caller decide if balance is too low
372
+ }
306
373
  function balanceFallback(balance, divisor, reserve) {
307
374
  const fraction = balance / divisor;
308
375
  if (balance > fraction + reserve)
@@ -9,9 +9,10 @@ import type { OrchestratorContext } from './context';
9
9
  /** Chains that support gateway operations (multicall, funds bridging, etc.) */
10
10
  export declare const SUPPORTED_GATEWAY_CHAINS: CHAIN[];
11
11
  export declare function isPushChain(chain: CHAIN): boolean;
12
+ export { toExternalTxHashDisplay } from '../../utils/external-tx-hash';
12
13
  export declare function getPushChainForNetwork(pushNetwork: PUSH_NETWORK): CHAIN;
13
14
  export declare function getChainNamespace(chain: CHAIN): string;
14
- export declare function chainFromNamespace(namespace: string): CHAIN | null;
15
+ export { chainFromNamespace } from '../../utils/external-tx-hash';
15
16
  export declare function getNativePRC20ForChain(targetChain: CHAIN, pushNetwork: PUSH_NETWORK): `0x${string}`;
16
17
  export declare function getUniversalGatewayPCAddress(): `0x${string}`;
17
18
  /**
@@ -5,11 +5,10 @@
5
5
  * These have minimal dependencies and are used across multiple submodules.
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.SUPPORTED_GATEWAY_CHAINS = void 0;
8
+ exports.chainFromNamespace = exports.toExternalTxHashDisplay = exports.SUPPORTED_GATEWAY_CHAINS = void 0;
9
9
  exports.isPushChain = isPushChain;
10
10
  exports.getPushChainForNetwork = getPushChainForNetwork;
11
11
  exports.getChainNamespace = getChainNamespace;
12
- exports.chainFromNamespace = chainFromNamespace;
13
12
  exports.getNativePRC20ForChain = getNativePRC20ForChain;
14
13
  exports.getUniversalGatewayPCAddress = getUniversalGatewayPCAddress;
15
14
  exports.validateFeeLockTxHash = validateFeeLockTxHash;
@@ -38,6 +37,14 @@ function isPushChain(chain) {
38
37
  chain === enums_1.CHAIN.PUSH_TESTNET_DONUT ||
39
38
  chain === enums_1.CHAIN.PUSH_LOCALNET);
40
39
  }
40
+ // `toExternalTxHashDisplay` moved to ../../utils/external-tx-hash so the
41
+ // detector module can use it without back-importing from orchestrator/internals
42
+ // (inbound-tracker.ts already imports universal-tx-detector — a back-import
43
+ // from detector would create a cross-layer tangle). Re-exported here so
44
+ // existing call sites (outbound-sync.ts / response-builder.ts / cascade.ts)
45
+ // keep their current import path unchanged.
46
+ var external_tx_hash_1 = require("../../utils/external-tx-hash");
47
+ Object.defineProperty(exports, "toExternalTxHashDisplay", { enumerable: true, get: function () { return external_tx_hash_1.toExternalTxHashDisplay; } });
41
48
  function getPushChainForNetwork(pushNetwork) {
42
49
  if (pushNetwork === enums_1.PUSH_NETWORK.MAINNET) {
43
50
  return enums_1.CHAIN.PUSH_MAINNET;
@@ -55,15 +62,10 @@ function getChainNamespace(chain) {
55
62
  const namespace = chain_1.VM_NAMESPACE[vm];
56
63
  return `${namespace}:${chainId}`;
57
64
  }
58
- function chainFromNamespace(namespace) {
59
- for (const [chainKey, info] of Object.entries(chain_1.CHAIN_INFO)) {
60
- const expected = `${chain_1.VM_NAMESPACE[info.vm]}:${info.chainId}`;
61
- if (expected === namespace) {
62
- return chainKey;
63
- }
64
- }
65
- return null;
66
- }
65
+ // Moved to ../../utils/external-tx-hash alongside `toExternalTxHashDisplay`
66
+ // so both the orchestrator and the detector module share one implementation.
67
+ var external_tx_hash_2 = require("../../utils/external-tx-hash");
68
+ Object.defineProperty(exports, "chainFromNamespace", { enumerable: true, get: function () { return external_tx_hash_2.chainFromNamespace; } });
67
69
  function getNativePRC20ForChain(targetChain, pushNetwork) {
68
70
  const synthetics = chain_1.SYNTHETIC_PUSH_ERC20[pushNetwork];
69
71
  switch (targetChain) {
@@ -67,6 +67,7 @@ export declare function waitForAllOutboundTxsV2(ctx: OrchestratorContext, pushCh
67
67
  initialWaitMs: number;
68
68
  pollingIntervalMs: number;
69
69
  timeout: number;
70
+ _resolvedSubTxId?: string;
70
71
  progressHook?: (event: {
71
72
  hopIndex: number;
72
73
  route: TransactionRouteType;
@@ -11,7 +11,6 @@ exports.waitForOutboundTx = waitForOutboundTx;
11
11
  exports.waitForAllOutboundTxsV2 = waitForAllOutboundTxsV2;
12
12
  const tslib_1 = require("tslib");
13
13
  const viem_1 = require("viem");
14
- const bs58_1 = require("../../internal/bs58");
15
14
  const chain_1 = require("../../constants/chain");
16
15
  const enums_1 = require("../../constants/enums");
17
16
  const types_1 = require("../../generated/uexecutor/v1/types");
@@ -142,7 +141,7 @@ function verifyExternalEvmReceipt(ctx, destinationChain, externalTxHash) {
142
141
  */
143
142
  function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
144
143
  return tslib_1.__awaiter(this, arguments, void 0, function* (ctx, pushChainTxHash, options = {}) {
145
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
144
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
146
145
  const { initialWaitMs = exports.OUTBOUND_INITIAL_WAIT_MS, pollingIntervalMs = exports.OUTBOUND_POLL_INTERVAL_MS, timeout = exports.OUTBOUND_MAX_TIMEOUT_MS, progressHook, _resolvedSubTxId, _expectedDestinationChain, } = options;
147
146
  // Terminal failure states — fail fast instead of polling until timeout
148
147
  const TERMINAL_FAILURE_STATES = new Set([
@@ -195,20 +194,37 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
195
194
  const statusNum = (_b = utxResponse === null || utxResponse === void 0 ? void 0 : utxResponse.universalTx) === null || _b === void 0 ? void 0 : _b.universalStatus;
196
195
  const statusName = (_c = types_1.UniversalTxStatus[statusNum]) !== null && _c !== void 0 ? _c : statusNum;
197
196
  const outbounds = ((_d = utxResponse === null || utxResponse === void 0 ? void 0 : utxResponse.universalTx) === null || _d === void 0 ? void 0 : _d.outboundTx) || [];
198
- (0, context_1.printLog)(ctx, `[waitForOutboundTx] Poll #${pollCount} | status: ${statusNum} (${statusName}) | outboundTx count: ${outbounds.length} | first txHash: '${((_f = (_e = outbounds[0]) === null || _e === void 0 ? void 0 : _e.observedTx) === null || _f === void 0 ? void 0 : _f.txHash) || ''}' | first dest: '${((_g = outbounds[0]) === null || _g === void 0 ? void 0 : _g.destinationChain) || ''}'`);
197
+ const firstOutbound = outbounds[0];
198
+ const firstOutboundChain = (firstOutbound === null || firstOutbound === void 0 ? void 0 : firstOutbound.destinationChain)
199
+ ? (0, helpers_1.chainFromNamespace)(firstOutbound.destinationChain)
200
+ : undefined;
201
+ const firstDisplayTxHash = (_h = (_f = (0, helpers_1.toExternalTxHashDisplay)(firstOutboundChain !== null && firstOutboundChain !== void 0 ? firstOutboundChain : undefined, (_e = firstOutbound === null || firstOutbound === void 0 ? void 0 : firstOutbound.observedTx) === null || _e === void 0 ? void 0 : _e.txHash)) !== null && _f !== void 0 ? _f : (_g = firstOutbound === null || firstOutbound === void 0 ? void 0 : firstOutbound.observedTx) === null || _g === void 0 ? void 0 : _g.txHash) !== null && _h !== void 0 ? _h : '';
202
+ (0, context_1.printLog)(ctx, `[waitForOutboundTx] Poll #${pollCount} | status: ${statusNum} (${statusName}) | outboundTx count: ${outbounds.length} | first txHash: '${firstDisplayTxHash}' | first dest: '${(firstOutbound === null || firstOutbound === void 0 ? void 0 : firstOutbound.destinationChain) || ''}'`);
199
203
  // Check for terminal failure states — fail fast
200
204
  if (TERMINAL_FAILURE_STATES.has(statusNum)) {
201
205
  (0, context_1.printLog)(ctx, `[waitForOutboundTx] Terminal failure state: ${statusName}`);
202
206
  progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'failed', elapsed: Date.now() - startTime });
203
207
  throw new OutboundFailedError(`Outbound transaction failed with status ${statusName}. Push Chain TX: ${pushChainTxHash}.`, pushChainTxHash);
204
208
  }
209
+ const pcTxs = ((_j = utxResponse === null || utxResponse === void 0 ? void 0 : utxResponse.universalTx) === null || _j === void 0 ? void 0 : _j.pcTx) || [];
210
+ const failedPcTx = pcTxs.find((pcTx) => {
211
+ const status = String(pcTx.status || '').toUpperCase();
212
+ return status === 'FAILED' || Boolean(pcTx.errorMsg);
213
+ });
214
+ if (failedPcTx) {
215
+ const failedTxHash = failedPcTx.txHash || pushChainTxHash;
216
+ const reason = failedPcTx.errorMsg || 'Push Chain execution failed';
217
+ (0, context_1.printLog)(ctx, `[waitForOutboundTx] Push Chain execution failed before outbound emission: ${reason}`);
218
+ progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'failed', elapsed: Date.now() - startTime });
219
+ throw new OutboundFailedError(`Push Chain execution failed before outbound emission: ${reason}. Push Chain TX: ${failedTxHash}.`, pushChainTxHash, undefined, failedPcTx.txHash || undefined);
220
+ }
205
221
  // Iterate V2 outbound array
206
222
  for (const ob of outbounds) {
207
223
  // Fail fast on per-outbound REVERTED status
208
224
  if (ob.outboundStatus === types_2.OutboundStatus.REVERTED) {
209
225
  (0, context_1.printLog)(ctx, `[waitForOutboundTx] Outbound to ${ob.destinationChain} REVERTED`);
210
226
  progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'failed', elapsed: Date.now() - startTime });
211
- throw new OutboundFailedError(`Outbound to ${ob.destinationChain} reverted: ${((_h = ob.observedTx) === null || _h === void 0 ? void 0 : _h.errorMsg) || 'Unknown'}. Push Chain TX: ${pushChainTxHash}.`, pushChainTxHash, ob.destinationChain, (_j = ob.observedTx) === null || _j === void 0 ? void 0 : _j.txHash);
227
+ throw new OutboundFailedError(`Outbound to ${ob.destinationChain} reverted: ${((_k = ob.observedTx) === null || _k === void 0 ? void 0 : _k.errorMsg) || 'Unknown'}. Push Chain TX: ${pushChainTxHash}.`, pushChainTxHash, ob.destinationChain, (_l = ob.observedTx) === null || _l === void 0 ? void 0 : _l.txHash);
212
228
  }
213
229
  // FOUND gating logic:
214
230
  // 1. Primary path — cosmos has transitioned to OBSERVED (the
@@ -218,7 +234,7 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
218
234
  // destination chain's own RPC: if its receipt is success,
219
235
  // treat as FOUND; if reverted, throw OutboundFailedError.
220
236
  // Pending receipts keep polling.
221
- if ((_k = ob.observedTx) === null || _k === void 0 ? void 0 : _k.txHash) {
237
+ if ((_m = ob.observedTx) === null || _m === void 0 ? void 0 : _m.txHash) {
222
238
  // If a destination chain filter is set, skip outbound entries that don't match
223
239
  if (_expectedDestinationChain && ob.destinationChain !== _expectedDestinationChain) {
224
240
  (0, context_1.printLog)(ctx, `[waitForOutboundTx] Poll #${pollCount} | outbound chain '${ob.destinationChain}' does not match expected '${_expectedDestinationChain}', skipping`);
@@ -232,7 +248,7 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
232
248
  // Tiebreaker: ask the destination-chain RPC directly.
233
249
  const verdict = yield verifyExternalEvmReceipt(ctx, chain, ob.observedTx.txHash);
234
250
  if (verdict === 'reverted') {
235
- (0, context_1.printLog)(ctx, `[waitForOutboundTx] Source-chain RPC reports REVERTED for ${ob.destinationChain} tx ${ob.observedTx.txHash} (cosmos still ${(_l = types_1.UniversalTxStatus[statusNum]) !== null && _l !== void 0 ? _l : statusNum})`);
251
+ (0, context_1.printLog)(ctx, `[waitForOutboundTx] Source-chain RPC reports REVERTED for ${ob.destinationChain} tx ${ob.observedTx.txHash} (cosmos still ${(_o = types_1.UniversalTxStatus[statusNum]) !== null && _o !== void 0 ? _o : statusNum})`);
236
252
  progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'failed', elapsed: Date.now() - startTime });
237
253
  throw new OutboundFailedError(`Outbound to ${ob.destinationChain} reverted on source-chain RPC (tx: ${ob.observedTx.txHash}). Push Chain TX: ${pushChainTxHash}.`, pushChainTxHash, ob.destinationChain, ob.observedTx.txHash);
238
254
  }
@@ -240,24 +256,26 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
240
256
  // 'pending' or 'unsupported' — keep polling, cosmos will catch up.
241
257
  continue;
242
258
  }
243
- (0, context_1.printLog)(ctx, `[waitForOutboundTx] Source-chain RPC tiebreaker: ${chain} tx ${ob.observedTx.txHash} succeeded; treating as FOUND despite cosmos status ${(_m = types_1.UniversalTxStatus[statusNum]) !== null && _m !== void 0 ? _m : statusNum}`);
259
+ (0, context_1.printLog)(ctx, `[waitForOutboundTx] Source-chain RPC tiebreaker: ${chain} tx ${ob.observedTx.txHash} succeeded; treating as FOUND despite cosmos status ${(_p = types_1.UniversalTxStatus[statusNum]) !== null && _p !== void 0 ? _p : statusNum}`);
244
260
  }
245
261
  {
246
- const explorerBaseUrl = (_o = chain_1.CHAIN_INFO[chain]) === null || _o === void 0 ? void 0 : _o.explorerUrl;
247
- const isSvm = ((_p = chain_1.CHAIN_INFO[chain]) === null || _p === void 0 ? void 0 : _p.vm) === enums_1.VM.SVM;
248
- // For SVM chains, convert hex txHash to base58 and append cluster param
249
- let displayTxHash = ob.observedTx.txHash;
262
+ const explorerBaseUrl = (_q = chain_1.CHAIN_INFO[chain]) === null || _q === void 0 ? void 0 : _q.explorerUrl;
263
+ const isSvm = ((_r = chain_1.CHAIN_INFO[chain]) === null || _r === void 0 ? void 0 : _r.vm) === enums_1.VM.SVM;
264
+ const displayTxHash = (_s = (0, helpers_1.toExternalTxHashDisplay)(chain, ob.observedTx.txHash)) !== null && _s !== void 0 ? _s : ob.observedTx.txHash;
250
265
  let explorerUrl = '';
251
- if (isSvm && ob.observedTx.txHash.startsWith('0x')) {
252
- const bytes = new Uint8Array(Buffer.from(ob.observedTx.txHash.slice(2), 'hex'));
253
- displayTxHash = bs58_1.bs58.encode(Buffer.from(bytes));
266
+ if (isSvm) {
254
267
  const cluster = chain === enums_1.CHAIN.SOLANA_DEVNET ? '?cluster=devnet'
255
268
  : chain === enums_1.CHAIN.SOLANA_TESTNET ? '?cluster=testnet' : '';
256
269
  explorerUrl = explorerBaseUrl ? `${explorerBaseUrl}/tx/${displayTxHash}${cluster}` : '';
257
270
  }
258
271
  else {
259
- explorerUrl = explorerBaseUrl ? `${explorerBaseUrl}/tx/${ob.observedTx.txHash}` : '';
272
+ explorerUrl = explorerBaseUrl ? `${explorerBaseUrl}/tx/${displayTxHash}` : '';
260
273
  }
274
+ // OutboundTxDetails carries the raw `0x`-hex form so internal
275
+ // consumers (R3 inbound tracker in response-builder.ts:786 →
276
+ // findChildUtxIdFromExternalTx → Cosmos query) keep working.
277
+ // The base58 display form is applied at every user-facing
278
+ // boundary via `toExternalTxHashDisplay` (helpers.ts).
261
279
  const details = {
262
280
  externalTxHash: ob.observedTx.txHash,
263
281
  destinationChain: chain,
@@ -266,7 +284,7 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
266
284
  amount: ob.amount,
267
285
  assetAddr: ob.externalAssetAddr,
268
286
  };
269
- (0, context_1.printLog)(ctx, `[waitForOutboundTx] FOUND on poll #${pollCount} | elapsed: ${Date.now() - startTime}ms | externalTxHash: ${details.externalTxHash}`);
287
+ (0, context_1.printLog)(ctx, `[waitForOutboundTx] FOUND on poll #${pollCount} | elapsed: ${Date.now() - startTime}ms | externalTxHash: ${displayTxHash}`);
270
288
  progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'found', elapsed: Date.now() - startTime });
271
289
  return details;
272
290
  }
@@ -302,8 +320,8 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
302
320
  */
303
321
  function waitForAllOutboundTxsV2(ctx, pushChainTxHash, outboundHops, options) {
304
322
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
305
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
306
- const { initialWaitMs, pollingIntervalMs, timeout, progressHook } = options;
323
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
324
+ const { initialWaitMs, pollingIntervalMs, timeout, progressHook, _resolvedSubTxId, } = options;
307
325
  const startTime = Date.now();
308
326
  // Build a map: CAIP-2 namespace -> hop(s) for matching outbound entries
309
327
  const chainToHops = new Map();
@@ -341,7 +359,11 @@ function waitForAllOutboundTxsV2(ctx, pushChainTxHash, outboundHops, options) {
341
359
  });
342
360
  }
343
361
  // Extract sub-tx ID for V2 query
344
- let cachedQueryId;
362
+ let cachedQueryId = _resolvedSubTxId
363
+ ? _resolvedSubTxId.startsWith('0x')
364
+ ? _resolvedSubTxId.slice(2)
365
+ : _resolvedSubTxId
366
+ : undefined;
345
367
  let pollCount = 0;
346
368
  let consecutiveErrors = 0;
347
369
  const MAX_CONSECUTIVE_ERRORS = 10;
@@ -372,11 +394,18 @@ function waitForAllOutboundTxsV2(ctx, pushChainTxHash, outboundHops, options) {
372
394
  const unconfirmedForChain = hopsForChain.filter((h) => h.status !== 'confirmed' && h.status !== 'failed');
373
395
  if (unconfirmedForChain.length === 0)
374
396
  continue;
375
- // Fail fast on per-outbound REVERTED
376
- if (ob.outboundStatus === types_2.OutboundStatus.REVERTED) {
397
+ const externalTxHash = (_e = ob.observedTx) === null || _e === void 0 ? void 0 : _e.txHash;
398
+ const hasObservedTxHash = !!externalTxHash && externalTxHash !== 'EMPTY';
399
+ const observedFailure = hasObservedTxHash &&
400
+ ((_f = ob.observedTx) === null || _f === void 0 ? void 0 : _f.success) === false &&
401
+ Boolean(((_g = ob.observedTx) === null || _g === void 0 ? void 0 : _g.errorMsg) ||
402
+ ob.abortReason ||
403
+ ob.outboundStatus >= types_2.OutboundStatus.REVERTED);
404
+ // Fail fast on per-outbound REVERTED or observed destination failure.
405
+ if (ob.outboundStatus === types_2.OutboundStatus.REVERTED || observedFailure) {
377
406
  for (const hop of unconfirmedForChain) {
378
407
  hop.status = 'failed';
379
- (0, context_1.printLog)(ctx, `[waitForAllOutboundTxsV2] Outbound to ${destChain} REVERTED | hop ${hop.hopIndex} | error: ${((_e = ob.observedTx) === null || _e === void 0 ? void 0 : _e.errorMsg) || 'Unknown'}`);
408
+ (0, context_1.printLog)(ctx, `[waitForAllOutboundTxsV2] Outbound to ${destChain} REVERTED | hop ${hop.hopIndex} | error: ${ob.abortReason || ((_h = ob.observedTx) === null || _h === void 0 ? void 0 : _h.errorMsg) || 'Unknown'}`);
380
409
  progressHook === null || progressHook === void 0 ? void 0 : progressHook({
381
410
  hopIndex: hop.hopIndex,
382
411
  route: hop.route,
@@ -386,43 +415,70 @@ function waitForAllOutboundTxsV2(ctx, pushChainTxHash, outboundHops, options) {
386
415
  }
387
416
  return { success: false, failedAt: unconfirmedForChain[0].hopIndex };
388
417
  }
389
- // Check for OBSERVED with txHash
390
- const externalTxHash = (_f = ob.observedTx) === null || _f === void 0 ? void 0 : _f.txHash;
391
- if (externalTxHash && (ob.outboundStatus === types_2.OutboundStatus.OBSERVED || ob.outboundStatus === 0)) {
418
+ // Check for observed tx hash. Cosmos may lag the status transition,
419
+ // so EVM destinations are verified against the destination receipt.
420
+ if (hasObservedTxHash && externalTxHash) {
392
421
  const chain = (0, helpers_1.chainFromNamespace)(destChain);
422
+ if (!chain)
423
+ continue;
424
+ const isCosmosObserved = ob.outboundStatus === types_2.OutboundStatus.OBSERVED;
425
+ if (!isCosmosObserved) {
426
+ const verdict = yield verifyExternalEvmReceipt(ctx, chain, externalTxHash);
427
+ if (verdict === 'reverted') {
428
+ for (const hop of unconfirmedForChain) {
429
+ hop.status = 'failed';
430
+ (0, context_1.printLog)(ctx, `[waitForAllOutboundTxsV2] Source-chain RPC reports REVERTED for ${destChain} tx ${externalTxHash} | hop ${hop.hopIndex}`);
431
+ progressHook === null || progressHook === void 0 ? void 0 : progressHook({
432
+ hopIndex: hop.hopIndex,
433
+ route: hop.route,
434
+ chain: hop.executionChain,
435
+ status: 'failed',
436
+ });
437
+ }
438
+ return { success: false, failedAt: unconfirmedForChain[0].hopIndex };
439
+ }
440
+ if (verdict !== 'success') {
441
+ continue;
442
+ }
443
+ }
444
+ // Build the display form for SVM (base58) used in `hop.txHash` /
445
+ // `hop.outboundDetails.externalTxHash` / the progressHook event —
446
+ // these are USER-FACING. The internal raw-hex form stays only
447
+ // inside this function; it's not exposed to consumers from the
448
+ // cascade path (cascade.ts doesn't call findChildUtxIdFromExternalTx
449
+ // for the cascade outbound hash).
450
+ const displayTxHash = (_j = (0, helpers_1.toExternalTxHashDisplay)(chain !== null && chain !== void 0 ? chain : undefined, externalTxHash)) !== null && _j !== void 0 ? _j : externalTxHash;
393
451
  let explorerUrl = '';
394
452
  if (chain && externalTxHash) {
395
- const explorerBaseUrl = (_g = chain_1.CHAIN_INFO[chain]) === null || _g === void 0 ? void 0 : _g.explorerUrl;
396
- const isSvm = ((_h = chain_1.CHAIN_INFO[chain]) === null || _h === void 0 ? void 0 : _h.vm) === enums_1.VM.SVM;
397
- if (isSvm && externalTxHash.startsWith('0x')) {
398
- const bytes = new Uint8Array(Buffer.from(externalTxHash.slice(2), 'hex'));
399
- const base58Hash = bs58_1.bs58.encode(Buffer.from(bytes));
453
+ const explorerBaseUrl = (_k = chain_1.CHAIN_INFO[chain]) === null || _k === void 0 ? void 0 : _k.explorerUrl;
454
+ const isSvm = ((_l = chain_1.CHAIN_INFO[chain]) === null || _l === void 0 ? void 0 : _l.vm) === enums_1.VM.SVM;
455
+ if (isSvm) {
400
456
  const cluster = chain === enums_1.CHAIN.SOLANA_DEVNET ? '?cluster=devnet'
401
457
  : chain === enums_1.CHAIN.SOLANA_TESTNET ? '?cluster=testnet' : '';
402
- explorerUrl = explorerBaseUrl ? `${explorerBaseUrl}/tx/${base58Hash}${cluster}` : '';
458
+ explorerUrl = explorerBaseUrl ? `${explorerBaseUrl}/tx/${displayTxHash}${cluster}` : '';
403
459
  }
404
460
  else {
405
- explorerUrl = explorerBaseUrl ? `${explorerBaseUrl}/tx/${externalTxHash}` : '';
461
+ explorerUrl = explorerBaseUrl ? `${explorerBaseUrl}/tx/${displayTxHash}` : '';
406
462
  }
407
463
  }
408
464
  for (const hop of unconfirmedForChain) {
409
465
  hop.status = 'confirmed';
410
- hop.txHash = externalTxHash;
466
+ hop.txHash = displayTxHash;
411
467
  hop.outboundDetails = {
412
- externalTxHash,
468
+ externalTxHash: displayTxHash,
413
469
  destinationChain: chain || hop.executionChain,
414
470
  explorerUrl,
415
471
  recipient: ob.recipient,
416
472
  amount: ob.amount,
417
473
  assetAddr: ob.externalAssetAddr,
418
474
  };
419
- (0, context_1.printLog)(ctx, `[waitForAllOutboundTxsV2] FOUND outbound for ${destChain} | hop ${hop.hopIndex} | externalTxHash: ${externalTxHash}`);
475
+ (0, context_1.printLog)(ctx, `[waitForAllOutboundTxsV2] FOUND outbound for ${destChain} | hop ${hop.hopIndex} | externalTxHash: ${displayTxHash}`);
420
476
  progressHook === null || progressHook === void 0 ? void 0 : progressHook({
421
477
  hopIndex: hop.hopIndex,
422
478
  route: hop.route,
423
479
  chain: hop.executionChain,
424
480
  status: 'confirmed',
425
- txHash: externalTxHash,
481
+ txHash: displayTxHash,
426
482
  });
427
483
  }
428
484
  }
@@ -439,7 +495,7 @@ function waitForAllOutboundTxsV2(ctx, pushChainTxHash, outboundHops, options) {
439
495
  if (statusNum === types_1.UniversalTxStatus.PC_EXECUTED_SUCCESS) {
440
496
  const stillUnresolved = outboundHops.filter((h) => h.status !== 'confirmed');
441
497
  if (stillUnresolved.length > 0) {
442
- const hasPendingOutbound = (_j = utx === null || utx === void 0 ? void 0 : utx.outboundTx) === null || _j === void 0 ? void 0 : _j.some((ob) => {
498
+ const hasPendingOutbound = (_m = utx === null || utx === void 0 ? void 0 : utx.outboundTx) === null || _m === void 0 ? void 0 : _m.some((ob) => {
443
499
  var _a;
444
500
  return ob.outboundStatus === types_2.OutboundStatus.PENDING &&
445
501
  (!((_a = ob.observedTx) === null || _a === void 0 ? void 0 : _a.txHash) || ob.observedTx.txHash === 'EMPTY');
@@ -23,7 +23,7 @@ import { type PreflightPathTag } from './errors';
23
23
  export interface RunPreflightOpts {
24
24
  ctx: OrchestratorContext;
25
25
  ueaAddress: `0x${string}`;
26
- /** Effective UEA balance in wei UPC (already includes fresh-wallet prediction). */
26
+ /** Effective UEA balance in native PC wei (already includes fresh-wallet prediction). */
27
27
  ueaBalance: bigint;
28
28
  /** Buffered pool quote (pre-clamp) — what the SDK would actually attempt. */
29
29
  requiredValue: bigint;
@@ -36,30 +36,16 @@ export interface RunPreflightOpts {
36
36
  prc20Balance?: bigint;
37
37
  /** Cascade-only: identifies which segment failed. */
38
38
  segmentIndex?: number;
39
- /**
40
- * Per-call opt-out (`params.options.allowUnderfundedSwap`). When `true`,
41
- * pre-flight logs the shortfall but does NOT fire 203-04 or throw —
42
- * caller can fall back to the legacy clamp-and-refund branch.
43
- */
44
- allowUnderfundedSwap?: boolean;
45
39
  }
46
40
  export type PreflightResult = {
47
41
  ok: true;
48
42
  /** What `nativeValueForGas` should be (== requiredValue when sufficient). */
49
43
  adjustedValue: bigint;
50
- } | {
51
- ok: false;
52
- /** Set when allowUnderfundedSwap=true: the legacy clamped value. */
53
- legacyClampedValue: bigint;
54
44
  };
55
45
  /**
56
46
  * Pre-flight check. PRC-20 balance is checked before the native check —
57
47
  * a missing burn token fails before the gas-balance check, so the user
58
- * sees the actionable PRC-20 shortfall instead of a stale UPC error.
59
- *
60
- * Returns a result object instead of throwing for the legacy opt-out
61
- * path. The throw happens here (not in the caller) for the default
62
- * `allowUnderfundedSwap=false` case so all 6 paths share one throw site.
48
+ * sees the actionable PRC-20 shortfall instead of a stale native PC error.
63
49
  */
64
50
  export declare function runPreflight(opts: RunPreflightOpts): PreflightResult;
65
51
  /**