@pushchain/core 5.1.16 → 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.
- package/package.json +1 -1
- package/src/lib/constants/index.d.ts +1 -1
- package/src/lib/constants/index.js +2 -1
- package/src/lib/constants/selectors.d.ts +8 -0
- package/src/lib/constants/selectors.js +9 -1
- package/src/lib/formatters.d.ts +1 -0
- package/src/lib/formatters.js +32 -0
- package/src/lib/orchestrator/internals/cascade.d.ts +8 -1
- package/src/lib/orchestrator/internals/cascade.js +486 -143
- package/src/lib/orchestrator/internals/error-decoder.d.ts +2 -6
- package/src/lib/orchestrator/internals/error-decoder.js +10 -10
- package/src/lib/orchestrator/internals/errors.d.ts +1 -1
- package/src/lib/orchestrator/internals/errors.js +7 -4
- package/src/lib/orchestrator/internals/execute-standard.js +7 -6
- package/src/lib/orchestrator/internals/gas-calculator.js +78 -11
- package/src/lib/orchestrator/internals/helpers.d.ts +2 -1
- package/src/lib/orchestrator/internals/helpers.js +13 -11
- package/src/lib/orchestrator/internals/outbound-sync.d.ts +1 -0
- package/src/lib/orchestrator/internals/outbound-sync.js +93 -37
- package/src/lib/orchestrator/internals/preflight.d.ts +9 -23
- package/src/lib/orchestrator/internals/preflight.js +22 -48
- package/src/lib/orchestrator/internals/response-builder.js +23 -7
- package/src/lib/orchestrator/internals/route-handlers.js +34 -49
- package/src/lib/orchestrator/internals/tx-transformer.js +2 -1
- package/src/lib/orchestrator/orchestrator.d.ts +7 -1
- package/src/lib/orchestrator/orchestrator.js +40 -2
- package/src/lib/orchestrator/orchestrator.types.d.ts +4 -14
- package/src/lib/progress-hook/progress-hook.js +66 -16
- package/src/lib/progress-hook/progress-hook.types.d.ts +4 -1
- package/src/lib/progress-hook/progress-hook.types.js +8 -0
- package/src/lib/push-chain/push-chain.d.ts +11 -1
- package/src/lib/push-chain/push-chain.js +2 -2
- package/src/lib/universal-tx-detector/cascade.js +14 -4
- package/src/lib/universal-tx-detector/child-inbounds.js +9 -1
- package/src/lib/universal-tx-detector/detector.js +9 -3
- package/src/lib/universal-tx-detector/normalize.d.ts +42 -0
- package/src/lib/universal-tx-detector/normalize.js +127 -0
- package/src/lib/utils/external-tx-hash.d.ts +37 -0
- 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
|
|
14
|
-
* production
|
|
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
|
|
15
|
-
* production
|
|
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:
|
|
40
|
-
'For
|
|
41
|
-
|
|
42
|
-
|
|
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' =
|
|
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
|
|
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 >=${
|
|
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 ${
|
|
59
|
-
`outbound requires ${
|
|
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
|
-
`~${(
|
|
356
|
-
`(UEA balance ${(
|
|
357
|
-
`pool-safe deposit ${(
|
|
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 ~${(
|
|
362
|
-
`but the transaction requires ~${(
|
|
363
|
-
`(shortfall: ~${(
|
|
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
|
-
|
|
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 *
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
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: ${((
|
|
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 ((
|
|
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 ${(
|
|
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 ${(
|
|
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 = (
|
|
247
|
-
const isSvm = ((
|
|
248
|
-
|
|
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
|
|
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/${
|
|
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: ${
|
|
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
|
-
|
|
376
|
-
|
|
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: ${((
|
|
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
|
|
390
|
-
|
|
391
|
-
if (
|
|
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 = (
|
|
396
|
-
const isSvm = ((
|
|
397
|
-
if (isSvm
|
|
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/${
|
|
458
|
+
explorerUrl = explorerBaseUrl ? `${explorerBaseUrl}/tx/${displayTxHash}${cluster}` : '';
|
|
403
459
|
}
|
|
404
460
|
else {
|
|
405
|
-
explorerUrl = explorerBaseUrl ? `${explorerBaseUrl}/tx/${
|
|
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 =
|
|
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: ${
|
|
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:
|
|
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 = (
|
|
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');
|