@pushchain/core 6.0.14 → 6.0.16
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/orchestrator/internals/cascade.d.ts +2 -2
- package/src/lib/orchestrator/internals/cascade.js +176 -92
- package/src/lib/orchestrator/internals/confirmation.js +35 -6
- package/src/lib/orchestrator/internals/execute-funds-only.js +43 -1
- package/src/lib/orchestrator/internals/execute-standard.d.ts +1 -0
- package/src/lib/orchestrator/internals/execute-standard.js +8 -1
- package/src/lib/orchestrator/internals/gas-calculator.d.ts +3 -1
- package/src/lib/orchestrator/internals/gas-calculator.js +9 -2
- package/src/lib/orchestrator/internals/outbound-sync.d.ts +1 -0
- package/src/lib/orchestrator/internals/outbound-sync.js +117 -74
- package/src/lib/orchestrator/internals/response-builder.js +32 -5
- package/src/lib/orchestrator/internals/route-handlers.d.ts +7 -0
- package/src/lib/orchestrator/internals/route-handlers.js +47 -5
- package/src/lib/orchestrator/internals/signing.js +12 -2
- package/src/lib/orchestrator/orchestrator.js +5 -2
- package/src/lib/orchestrator/orchestrator.types.d.ts +25 -2
- package/src/lib/orchestrator/payload-builders.d.ts +8 -0
- package/src/lib/orchestrator/payload-builders.js +21 -1
- package/src/lib/orchestrator/svm-idl/build-payload.js +30 -6
- package/src/lib/push-chain/push-chain.d.ts +4 -0
- package/src/lib/push-client/push-client.js +27 -3
- package/src/lib/vm-client/evm-client.js +4 -1
|
@@ -15,6 +15,39 @@ const enums_1 = require("../../constants/enums");
|
|
|
15
15
|
const progress_hook_types_1 = require("../../progress-hook/progress-hook.types");
|
|
16
16
|
const svm_client_1 = require("../../vm-client/svm-client");
|
|
17
17
|
const context_2 = require("./context");
|
|
18
|
+
const EVM_RECEIPT_POLL_MS = 3000;
|
|
19
|
+
const EVM_RECEIPT_NOT_FOUND_RE = /not found|TransactionNotFound|TransactionReceiptNotFound|could not be found|No transaction found/i;
|
|
20
|
+
function getErrorMessage(err) {
|
|
21
|
+
var _a, _b;
|
|
22
|
+
if (err instanceof Error)
|
|
23
|
+
return err.message;
|
|
24
|
+
if (typeof err === 'object' && err !== null) {
|
|
25
|
+
const maybe = err;
|
|
26
|
+
return String((_b = (_a = maybe.shortMessage) !== null && _a !== void 0 ? _a : maybe.message) !== null && _b !== void 0 ? _b : err);
|
|
27
|
+
}
|
|
28
|
+
return String(err);
|
|
29
|
+
}
|
|
30
|
+
function waitForEvmReceipt(evmClient, txHash, timeoutMs) {
|
|
31
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
32
|
+
const start = Date.now();
|
|
33
|
+
// eslint-disable-next-line no-constant-condition
|
|
34
|
+
while (true) {
|
|
35
|
+
try {
|
|
36
|
+
return yield evmClient.publicClient.getTransactionReceipt({
|
|
37
|
+
hash: txHash,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
const msg = getErrorMessage(err);
|
|
42
|
+
const retryable = EVM_RECEIPT_NOT_FOUND_RE.test(msg);
|
|
43
|
+
if (!retryable || Date.now() - start > timeoutMs) {
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
yield new Promise((r) => setTimeout(r, EVM_RECEIPT_POLL_MS));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
18
51
|
function waitForEvmConfirmationsWithCountdown(ctx, evmClient, txHash, confirmations, timeoutMs) {
|
|
19
52
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
20
53
|
if (confirmations <= 0) {
|
|
@@ -23,9 +56,7 @@ function waitForEvmConfirmationsWithCountdown(ctx, evmClient, txHash, confirmati
|
|
|
23
56
|
}
|
|
24
57
|
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_03, confirmations);
|
|
25
58
|
const start = Date.now();
|
|
26
|
-
const receipt = yield evmClient
|
|
27
|
-
hash: txHash,
|
|
28
|
-
});
|
|
59
|
+
const receipt = yield waitForEvmReceipt(evmClient, txHash, timeoutMs);
|
|
29
60
|
const targetBlock = receipt.blockNumber + BigInt(confirmations);
|
|
30
61
|
let lastEmitted = 0;
|
|
31
62
|
// eslint-disable-next-line no-constant-condition
|
|
@@ -112,9 +143,7 @@ function waitForLockerFeeConfirmation(ctx, txHashBytes) {
|
|
|
112
143
|
case enums_1.VM.EVM: {
|
|
113
144
|
const evmClient = (0, context_1.getOriginEvmClient)(ctx);
|
|
114
145
|
const txHash = (0, viem_1.bytesToHex)(txHashBytes);
|
|
115
|
-
const receipt = yield evmClient
|
|
116
|
-
hash: txHash,
|
|
117
|
-
});
|
|
146
|
+
const receipt = yield waitForEvmReceipt(evmClient, txHash, timeout);
|
|
118
147
|
if (fastConfirmations <= 1)
|
|
119
148
|
return;
|
|
120
149
|
const targetBlock = receipt.blockNumber + BigInt(fastConfirmations);
|
|
@@ -20,6 +20,9 @@ const svm_client_1 = require("../../vm-client/svm-client");
|
|
|
20
20
|
const context_2 = require("./context");
|
|
21
21
|
const gas_calculator_1 = require("./gas-calculator");
|
|
22
22
|
const gateway_client_1 = require("./gateway-client");
|
|
23
|
+
const gas_usd_sizer_1 = require("./gas-usd-sizer");
|
|
24
|
+
const price_fetch_1 = require("../../price-fetch/price-fetch");
|
|
25
|
+
const utils_1 = require("../../utils");
|
|
23
26
|
const helpers_1 = require("./helpers");
|
|
24
27
|
const payload_builder_1 = require("./payload-builder");
|
|
25
28
|
const uea_manager_1 = require("./uea-manager");
|
|
@@ -100,7 +103,11 @@ function executeFundsOnlyEvm(ctx, execute, eventBuffer, transformFn, chain, rpcU
|
|
|
100
103
|
const gasPrice = yield ctx.pushClient.getGasPrice();
|
|
101
104
|
const requiredGasFee = gasEstimate * gasPrice;
|
|
102
105
|
const requiredFunds = requiredGasFee + ((_c = execute.value) !== null && _c !== void 0 ? _c : BigInt(0));
|
|
103
|
-
let nativeAmount = yield (0, gas_calculator_1.calculateNativeAmountForDeposit)(ctx, chain, requiredFunds, ueaBalanceForGas
|
|
106
|
+
let nativeAmount = yield (0, gas_calculator_1.calculateNativeAmountForDeposit)(ctx, chain, requiredFunds, ueaBalanceForGas,
|
|
107
|
+
// Defer the 103-03-04 ("Prepaid Deposit Estimated") hook — we emit the full
|
|
108
|
+
// 103-03 sizing sequence below, after 103-01/103-02 (UEA resolution), to
|
|
109
|
+
// match the funds-payload path ordering.
|
|
110
|
+
{ emitDepositEstimated: false });
|
|
104
111
|
// For EVM fee-locking, fixed-rate PC→USD sizing can underfund when the
|
|
105
112
|
// live WPC/native pool prices PC above the SDK's fallback price. Size the
|
|
106
113
|
// native deposit against the same Push Chain pool used by the gateway.
|
|
@@ -121,6 +128,41 @@ function executeFundsOnlyEvm(ctx, execute, eventBuffer, transformFn, chain, rpcU
|
|
|
121
128
|
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_01);
|
|
122
129
|
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_02, ueaAddress, deployed);
|
|
123
130
|
(0, context_2.printLog)(ctx, `UEA resolved: ${ueaAddress}, deployed: ${deployed}`);
|
|
131
|
+
// SDK 5.2 R1 deposit-sizing progress (parent + Case A/B/C + terminal),
|
|
132
|
+
// emitted here — after UEA resolution — to match the funds-payload path's
|
|
133
|
+
// ordering. The terminal 103-03-04 hook was suppressed inside
|
|
134
|
+
// calculateNativeAmountForDeposit above so it lands in this position instead
|
|
135
|
+
// of before 103-01/103-02. Purely cosmetic: a pool/price read failure here
|
|
136
|
+
// must never block the bridge, so we fall back to the terminal hook alone.
|
|
137
|
+
try {
|
|
138
|
+
const r1Sizing = yield (0, gas_usd_sizer_1.sizeR1PushGas)(ctx, {
|
|
139
|
+
pushGasFeeWei: requiredGasFee,
|
|
140
|
+
originChain: chain,
|
|
141
|
+
});
|
|
142
|
+
const nativeTokenUsdPrice = yield new price_fetch_1.PriceFetch(ctx.rpcUrls).getPrice(chain);
|
|
143
|
+
const nativeDecimals = chain_1.CHAIN_INFO[chain].vm === enums_1.VM.SVM ? 9 : 18;
|
|
144
|
+
const oneNativeUnit = utils_1.Utils.helpers.parseUnits('1', nativeDecimals);
|
|
145
|
+
const plannedPCDeposit = nativeTokenUsdPrice === BigInt(0)
|
|
146
|
+
? BigInt(0)
|
|
147
|
+
: (r1Sizing.paddedDepositUsd * oneNativeUnit +
|
|
148
|
+
(nativeTokenUsdPrice - BigInt(1))) /
|
|
149
|
+
nativeTokenUsdPrice +
|
|
150
|
+
BigInt(1);
|
|
151
|
+
const extraDepositPC = plannedPCDeposit > requiredGasFee
|
|
152
|
+
? plannedPCDeposit - requiredGasFee
|
|
153
|
+
: BigInt(0);
|
|
154
|
+
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_03, chain, r1Sizing.paddedDepositUsd);
|
|
155
|
+
const r1SizingHookId = {
|
|
156
|
+
A: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_03_01,
|
|
157
|
+
B: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_03_02,
|
|
158
|
+
C: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_03_03,
|
|
159
|
+
}[r1Sizing.category];
|
|
160
|
+
(0, context_2.fireProgressHook)(ctx, r1SizingHookId, chain, requiredGasFee, extraDepositPC, r1Sizing.paddedDepositUsd);
|
|
161
|
+
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_03_04, nativeAmount, r1Sizing.paddedDepositUsd, chain);
|
|
162
|
+
}
|
|
163
|
+
catch (_d) {
|
|
164
|
+
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_03_04, nativeAmount, BigInt(0), chain);
|
|
165
|
+
}
|
|
124
166
|
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_01, execute.funds.amount, execute.funds.token.decimals, symbol);
|
|
125
167
|
// Approve gateway to pull tokens if ERC-20
|
|
126
168
|
if (execute.funds.token.mechanism === 'approve') {
|
|
@@ -10,4 +10,5 @@ import { ProgressEvent } from '../../progress-hook/progress-hook.types';
|
|
|
10
10
|
import type { ExecuteParams, UniversalTxResponse } from '../orchestrator.types';
|
|
11
11
|
import type { OrchestratorContext } from './context';
|
|
12
12
|
import { type ResponseBuilderCallbacks } from './response-builder';
|
|
13
|
+
export declare function resolveRequiredFunds(requiredGasFee: bigint, executeValue: bigint, requiredFundsOverride?: bigint): bigint;
|
|
13
14
|
export declare function executeStandardPayload(ctx: OrchestratorContext, execute: ExecuteParams, eventBuffer: ProgressEvent[], getResponseCallbacks: () => ResponseBuilderCallbacks): Promise<UniversalTxResponse>;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* - Signed verification path for deployed UEA with funds
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.resolveRequiredFunds = resolveRequiredFunds;
|
|
11
12
|
exports.executeStandardPayload = executeStandardPayload;
|
|
12
13
|
const tslib_1 = require("tslib");
|
|
13
14
|
const bs58_1 = require("../../internal/bs58");
|
|
@@ -76,6 +77,12 @@ function encodePayloadForOriginIfNeeded(ctx, payload, feeLockingRequired) {
|
|
|
76
77
|
}
|
|
77
78
|
return encodePayloadForOrigin(ctx, payload);
|
|
78
79
|
}
|
|
80
|
+
function resolveRequiredFunds(requiredGasFee, executeValue, requiredFundsOverride) {
|
|
81
|
+
const baseRequiredFunds = requiredGasFee + executeValue;
|
|
82
|
+
return requiredFundsOverride && requiredFundsOverride > baseRequiredFunds
|
|
83
|
+
? requiredFundsOverride
|
|
84
|
+
: baseRequiredFunds;
|
|
85
|
+
}
|
|
79
86
|
function executeStandardPayload(ctx, execute, eventBuffer, getResponseCallbacks) {
|
|
80
87
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
81
88
|
var _a, _b, _c;
|
|
@@ -122,7 +129,7 @@ function executeStandardPayload(ctx, execute, eventBuffer, getResponseCallbacks)
|
|
|
122
129
|
const gasEstimate = execute.gasLimit || BigInt(1e7);
|
|
123
130
|
const gasPrice = yield ctx.pushClient.getGasPrice();
|
|
124
131
|
const requiredGasFee = gasEstimate * gasPrice;
|
|
125
|
-
const requiredFunds = requiredGasFee
|
|
132
|
+
const requiredFunds = resolveRequiredFunds(requiredGasFee, execute.value, execute._requiredFundsOverride);
|
|
126
133
|
// Fetch UEA Details (or use pre-fetched status if available)
|
|
127
134
|
const UEA = (0, uea_manager_1.computeUEAOffchain)(ctx);
|
|
128
135
|
let isUEADeployed;
|
|
@@ -33,7 +33,9 @@ export declare function queryRescueGasFee(ctx: OrchestratorContext, prc20Token:
|
|
|
33
33
|
nativeValueForGas: bigint;
|
|
34
34
|
sizing?: GasSizingDecision;
|
|
35
35
|
}>;
|
|
36
|
-
export declare function calculateNativeAmountForDeposit(ctx: OrchestratorContext, chain: CHAIN, requiredFunds: bigint, ueaBalance: bigint
|
|
36
|
+
export declare function calculateNativeAmountForDeposit(ctx: OrchestratorContext, chain: CHAIN, requiredFunds: bigint, ueaBalance: bigint, opts?: {
|
|
37
|
+
emitDepositEstimated?: boolean;
|
|
38
|
+
}): Promise<bigint>;
|
|
37
39
|
export declare function calculateGasAmountFromAmountOutMinETH(ctx: OrchestratorContext, gasTokenAddress: `0x${string}`, amountOutMinETH: bigint | string, quoteExactOutputFn: (amountOut: bigint, opts: {
|
|
38
40
|
from: PayableToken | undefined;
|
|
39
41
|
to: MoveableToken | undefined;
|
|
@@ -449,7 +449,12 @@ function queryRescueGasFee(ctx, prc20Token, destinationChain) {
|
|
|
449
449
|
// ============================================================================
|
|
450
450
|
// Native Amount Calculation for Deposit
|
|
451
451
|
// ============================================================================
|
|
452
|
-
function calculateNativeAmountForDeposit(ctx, chain, requiredFunds, ueaBalance
|
|
452
|
+
function calculateNativeAmountForDeposit(ctx, chain, requiredFunds, ueaBalance,
|
|
453
|
+
// When false, suppress the SEND-TX-103-03-04 ("Prepaid Deposit Estimated")
|
|
454
|
+
// progress hook so the caller can emit the full 103-03 sizing sequence
|
|
455
|
+
// (parent + Case A/B/C + terminal) AFTER 103-01/103-02, matching the
|
|
456
|
+
// funds-payload path ordering. The deposit math is unaffected.
|
|
457
|
+
opts) {
|
|
453
458
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
454
459
|
var _a, _b;
|
|
455
460
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_102_01);
|
|
@@ -497,7 +502,9 @@ function calculateNativeAmountForDeposit(ctx, chain, requiredFunds, ueaBalance)
|
|
|
497
502
|
let nativeAmount = (depositUsd * oneNativeUnit + (nativeTokenUsdPrice - BigInt(1))) /
|
|
498
503
|
nativeTokenUsdPrice;
|
|
499
504
|
nativeAmount = nativeAmount + BigInt(1);
|
|
500
|
-
(0
|
|
505
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.emitDepositEstimated) !== false) {
|
|
506
|
+
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_03_04, nativeAmount, depositUsd, chain);
|
|
507
|
+
}
|
|
501
508
|
return nativeAmount;
|
|
502
509
|
});
|
|
503
510
|
}
|
|
@@ -68,6 +68,7 @@ export declare function waitForAllOutboundTxsV2(ctx: OrchestratorContext, pushCh
|
|
|
68
68
|
pollingIntervalMs: number;
|
|
69
69
|
timeout: number;
|
|
70
70
|
_resolvedSubTxId?: string;
|
|
71
|
+
_outboundIndexByHop?: Map<number, number>;
|
|
71
72
|
progressHook?: (event: {
|
|
72
73
|
hopIndex: number;
|
|
73
74
|
route: TransactionRouteType;
|
|
@@ -180,7 +180,8 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
|
|
|
180
180
|
const pollStart = Date.now();
|
|
181
181
|
(0, context_1.printLog)(ctx, `[waitForOutboundTx] Poll #${pollCount} | Elapsed: ${pollStart - startTime}ms / ${timeout}ms`);
|
|
182
182
|
if (!cachedUniversalSubTxId) {
|
|
183
|
-
cachedUniversalSubTxId =
|
|
183
|
+
cachedUniversalSubTxId =
|
|
184
|
+
(_a = (yield (0, outbound_tracker_1.extractUniversalSubTxIdFromTx)(ctx, pushChainTxHash))) !== null && _a !== void 0 ? _a : undefined;
|
|
184
185
|
if (!cachedUniversalSubTxId) {
|
|
185
186
|
cachedUniversalSubTxId = (0, outbound_tracker_1.computeUniversalTxId)(ctx.pushNetwork, pushChainTxHash);
|
|
186
187
|
}
|
|
@@ -228,13 +229,15 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
|
|
|
228
229
|
let matchingOutboundIndex = 0;
|
|
229
230
|
for (const ob of outbounds) {
|
|
230
231
|
// If a destination chain filter is set, skip outbound entries that don't match.
|
|
231
|
-
if (_expectedDestinationChain &&
|
|
232
|
+
if (_expectedDestinationChain &&
|
|
233
|
+
ob.destinationChain !== _expectedDestinationChain) {
|
|
232
234
|
(0, context_1.printLog)(ctx, `[waitForOutboundTx] Poll #${pollCount} | outbound chain '${ob.destinationChain}' does not match expected '${_expectedDestinationChain}', skipping`);
|
|
233
235
|
continue;
|
|
234
236
|
}
|
|
235
237
|
const currentOutboundIndex = matchingOutboundIndex;
|
|
236
238
|
matchingOutboundIndex += 1;
|
|
237
|
-
if (_outboundIndex !== undefined &&
|
|
239
|
+
if (_outboundIndex !== undefined &&
|
|
240
|
+
currentOutboundIndex !== _outboundIndex) {
|
|
238
241
|
(0, context_1.printLog)(ctx, `[waitForOutboundTx] Poll #${pollCount} | outbound index ${currentOutboundIndex} for '${ob.destinationChain}' does not match expected index ${_outboundIndex}, skipping`);
|
|
239
242
|
continue;
|
|
240
243
|
}
|
|
@@ -262,7 +265,10 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
|
|
|
262
265
|
const verdict = yield verifyExternalEvmReceipt(ctx, chain, ob.observedTx.txHash);
|
|
263
266
|
if (verdict === 'reverted') {
|
|
264
267
|
(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})`);
|
|
265
|
-
progressHook === null || progressHook === void 0 ? void 0 : progressHook({
|
|
268
|
+
progressHook === null || progressHook === void 0 ? void 0 : progressHook({
|
|
269
|
+
status: 'failed',
|
|
270
|
+
elapsed: Date.now() - startTime,
|
|
271
|
+
});
|
|
266
272
|
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);
|
|
267
273
|
}
|
|
268
274
|
if (verdict !== 'success') {
|
|
@@ -277,12 +283,19 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
|
|
|
277
283
|
const displayTxHash = (_s = (0, helpers_1.toExternalTxHashDisplay)(chain, ob.observedTx.txHash)) !== null && _s !== void 0 ? _s : ob.observedTx.txHash;
|
|
278
284
|
let explorerUrl = '';
|
|
279
285
|
if (isSvm) {
|
|
280
|
-
const cluster = chain === enums_1.CHAIN.SOLANA_DEVNET
|
|
281
|
-
|
|
282
|
-
|
|
286
|
+
const cluster = chain === enums_1.CHAIN.SOLANA_DEVNET
|
|
287
|
+
? '?cluster=devnet'
|
|
288
|
+
: chain === enums_1.CHAIN.SOLANA_TESTNET
|
|
289
|
+
? '?cluster=testnet'
|
|
290
|
+
: '';
|
|
291
|
+
explorerUrl = explorerBaseUrl
|
|
292
|
+
? `${explorerBaseUrl}/tx/${displayTxHash}${cluster}`
|
|
293
|
+
: '';
|
|
283
294
|
}
|
|
284
295
|
else {
|
|
285
|
-
explorerUrl = explorerBaseUrl
|
|
296
|
+
explorerUrl = explorerBaseUrl
|
|
297
|
+
? `${explorerBaseUrl}/tx/${displayTxHash}`
|
|
298
|
+
: '';
|
|
286
299
|
}
|
|
287
300
|
// OutboundTxDetails carries the raw `0x`-hex form so internal
|
|
288
301
|
// consumers (R3 inbound tracker in response-builder.ts:786 →
|
|
@@ -298,7 +311,10 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
|
|
|
298
311
|
assetAddr: ob.externalAssetAddr,
|
|
299
312
|
};
|
|
300
313
|
(0, context_1.printLog)(ctx, `[waitForOutboundTx] FOUND on poll #${pollCount} | elapsed: ${Date.now() - startTime}ms | externalTxHash: ${displayTxHash}`);
|
|
301
|
-
progressHook === null || progressHook === void 0 ? void 0 : progressHook({
|
|
314
|
+
progressHook === null || progressHook === void 0 ? void 0 : progressHook({
|
|
315
|
+
status: 'found',
|
|
316
|
+
elapsed: Date.now() - startTime,
|
|
317
|
+
});
|
|
302
318
|
return details;
|
|
303
319
|
}
|
|
304
320
|
}
|
|
@@ -333,18 +349,24 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
|
|
|
333
349
|
*/
|
|
334
350
|
function waitForAllOutboundTxsV2(ctx, pushChainTxHash, outboundHops, options) {
|
|
335
351
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
336
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
337
|
-
const { initialWaitMs, pollingIntervalMs, timeout, progressHook, _resolvedSubTxId, } = options;
|
|
352
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
353
|
+
const { initialWaitMs, pollingIntervalMs, timeout, progressHook, _resolvedSubTxId, _outboundIndexByHop, } = options;
|
|
338
354
|
const startTime = Date.now();
|
|
339
|
-
// Build
|
|
355
|
+
// Build maps for matching outbound entries. When the cascade composer merged
|
|
356
|
+
// multiple logical hops into one outbound request, `_outboundIndexByHop` maps
|
|
357
|
+
// those hops to the same outbound ordinal.
|
|
340
358
|
const chainToHops = new Map();
|
|
341
359
|
for (const hop of outboundHops) {
|
|
342
360
|
const chainInfo = chain_1.CHAIN_INFO[hop.executionChain];
|
|
343
361
|
if (chainInfo) {
|
|
344
362
|
const namespace = `${chain_1.VM_NAMESPACE[chainInfo.vm]}:${chainInfo.chainId}`;
|
|
345
|
-
const
|
|
363
|
+
const existingByOrdinal = chainToHops.get(namespace) || new Map();
|
|
364
|
+
const fallbackOrdinal = [...existingByOrdinal.values()].reduce((count, hopsForOrdinal) => count + hopsForOrdinal.length, 0);
|
|
365
|
+
const outboundOrdinal = (_a = _outboundIndexByHop === null || _outboundIndexByHop === void 0 ? void 0 : _outboundIndexByHop.get(hop.hopIndex)) !== null && _a !== void 0 ? _a : fallbackOrdinal;
|
|
366
|
+
const existing = existingByOrdinal.get(outboundOrdinal) || [];
|
|
346
367
|
existing.push(hop);
|
|
347
|
-
|
|
368
|
+
existingByOrdinal.set(outboundOrdinal, existing);
|
|
369
|
+
chainToHops.set(namespace, existingByOrdinal);
|
|
348
370
|
}
|
|
349
371
|
}
|
|
350
372
|
const expectedChains = [...chainToHops.keys()];
|
|
@@ -387,7 +409,9 @@ function waitForAllOutboundTxsV2(ctx, pushChainTxHash, outboundHops, options) {
|
|
|
387
409
|
// Resolve query ID on first poll
|
|
388
410
|
if (!cachedQueryId) {
|
|
389
411
|
const allSubTxIds = yield (0, outbound_tracker_1.extractAllUniversalSubTxIds)(ctx, pushChainTxHash);
|
|
390
|
-
const subTxId = allSubTxIds.length > 0
|
|
412
|
+
const subTxId = allSubTxIds.length > 0
|
|
413
|
+
? allSubTxIds[0]
|
|
414
|
+
: (0, outbound_tracker_1.computeUniversalTxId)(ctx.pushNetwork, pushChainTxHash);
|
|
391
415
|
cachedQueryId = subTxId.startsWith('0x') ? subTxId.slice(2) : subTxId;
|
|
392
416
|
(0, context_1.printLog)(ctx, `[waitForAllOutboundTxsV2] Resolved queryId: ${cachedQueryId}`);
|
|
393
417
|
}
|
|
@@ -396,41 +420,45 @@ function waitForAllOutboundTxsV2(ctx, pushChainTxHash, outboundHops, options) {
|
|
|
396
420
|
consecutiveErrors = 0; // Reset on successful RPC call
|
|
397
421
|
const utx = v2Response === null || v2Response === void 0 ? void 0 : v2Response.universalTx;
|
|
398
422
|
const statusNum = utx === null || utx === void 0 ? void 0 : utx.universalStatus;
|
|
399
|
-
const statusName = (
|
|
400
|
-
(0, context_1.printLog)(ctx, `[waitForAllOutboundTxsV2] Poll #${pollCount} | status: ${statusNum} (${statusName}) | outboundTx count: ${(
|
|
401
|
-
if ((
|
|
423
|
+
const statusName = (_b = types_1.UniversalTxStatus[statusNum]) !== null && _b !== void 0 ? _b : statusNum;
|
|
424
|
+
(0, context_1.printLog)(ctx, `[waitForAllOutboundTxsV2] Poll #${pollCount} | status: ${statusNum} (${statusName}) | outboundTx count: ${(_d = (_c = utx === null || utx === void 0 ? void 0 : utx.outboundTx) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0}`);
|
|
425
|
+
if ((_e = utx === null || utx === void 0 ? void 0 : utx.outboundTx) === null || _e === void 0 ? void 0 : _e.length) {
|
|
402
426
|
const outboundOrdinalByChain = new Map();
|
|
403
427
|
for (const ob of utx.outboundTx) {
|
|
404
428
|
const destChain = ob.destinationChain;
|
|
405
|
-
const
|
|
406
|
-
if (!
|
|
429
|
+
const hopsByOrdinal = chainToHops.get(destChain);
|
|
430
|
+
if (!hopsByOrdinal)
|
|
407
431
|
continue;
|
|
408
|
-
const outboundOrdinal = (
|
|
432
|
+
const outboundOrdinal = (_f = outboundOrdinalByChain.get(destChain)) !== null && _f !== void 0 ? _f : 0;
|
|
409
433
|
outboundOrdinalByChain.set(destChain, outboundOrdinal + 1);
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
targetHop.status === 'failed') {
|
|
434
|
+
const targetHops = hopsByOrdinal.get(outboundOrdinal) || [];
|
|
435
|
+
const pendingTargetHops = targetHops.filter((hop) => hop.status !== 'confirmed' && hop.status !== 'failed');
|
|
436
|
+
if (pendingTargetHops.length === 0)
|
|
414
437
|
continue;
|
|
415
|
-
|
|
416
|
-
const externalTxHash = (
|
|
438
|
+
const primaryTargetHop = pendingTargetHops[0];
|
|
439
|
+
const externalTxHash = (_g = ob.observedTx) === null || _g === void 0 ? void 0 : _g.txHash;
|
|
417
440
|
const hasObservedTxHash = !!externalTxHash && externalTxHash !== 'EMPTY';
|
|
418
441
|
const observedFailure = hasObservedTxHash &&
|
|
419
|
-
((
|
|
420
|
-
Boolean(((
|
|
442
|
+
((_h = ob.observedTx) === null || _h === void 0 ? void 0 : _h.success) === false &&
|
|
443
|
+
Boolean(((_j = ob.observedTx) === null || _j === void 0 ? void 0 : _j.errorMsg) ||
|
|
421
444
|
ob.abortReason ||
|
|
422
445
|
ob.outboundStatus >= types_2.OutboundStatus.REVERTED);
|
|
423
446
|
// Fail fast on per-outbound REVERTED or observed destination failure.
|
|
424
|
-
if (ob.outboundStatus === types_2.OutboundStatus.REVERTED ||
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
447
|
+
if (ob.outboundStatus === types_2.OutboundStatus.REVERTED ||
|
|
448
|
+
observedFailure) {
|
|
449
|
+
for (const targetHop of pendingTargetHops) {
|
|
450
|
+
targetHop.status = 'failed';
|
|
451
|
+
progressHook === null || progressHook === void 0 ? void 0 : progressHook({
|
|
452
|
+
hopIndex: targetHop.hopIndex,
|
|
453
|
+
route: targetHop.route,
|
|
454
|
+
chain: targetHop.executionChain,
|
|
455
|
+
status: 'failed',
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
(0, context_1.printLog)(ctx, `[waitForAllOutboundTxsV2] Outbound to ${destChain} REVERTED | outboundIndex ${outboundOrdinal} | hops ${pendingTargetHops
|
|
459
|
+
.map((hop) => hop.hopIndex)
|
|
460
|
+
.join(', ')} | error: ${ob.abortReason || ((_k = ob.observedTx) === null || _k === void 0 ? void 0 : _k.errorMsg) || 'Unknown'}`);
|
|
461
|
+
return { success: false, failedAt: primaryTargetHop.hopIndex };
|
|
434
462
|
}
|
|
435
463
|
// Check for observed tx hash. Cosmos may lag the status transition,
|
|
436
464
|
// so EVM destinations are verified against the destination receipt.
|
|
@@ -442,15 +470,19 @@ function waitForAllOutboundTxsV2(ctx, pushChainTxHash, outboundHops, options) {
|
|
|
442
470
|
if (!isCosmosObserved) {
|
|
443
471
|
const verdict = yield verifyExternalEvmReceipt(ctx, chain, externalTxHash);
|
|
444
472
|
if (verdict === 'reverted') {
|
|
445
|
-
targetHop
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
473
|
+
for (const targetHop of pendingTargetHops) {
|
|
474
|
+
targetHop.status = 'failed';
|
|
475
|
+
progressHook === null || progressHook === void 0 ? void 0 : progressHook({
|
|
476
|
+
hopIndex: targetHop.hopIndex,
|
|
477
|
+
route: targetHop.route,
|
|
478
|
+
chain: targetHop.executionChain,
|
|
479
|
+
status: 'failed',
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
(0, context_1.printLog)(ctx, `[waitForAllOutboundTxsV2] Source-chain RPC reports REVERTED for ${destChain} tx ${externalTxHash} | outboundIndex ${outboundOrdinal} | hops ${pendingTargetHops
|
|
483
|
+
.map((hop) => hop.hopIndex)
|
|
484
|
+
.join(', ')}`);
|
|
485
|
+
return { success: false, failedAt: primaryTargetHop.hopIndex };
|
|
454
486
|
}
|
|
455
487
|
if (verdict !== 'success') {
|
|
456
488
|
continue;
|
|
@@ -462,38 +494,49 @@ function waitForAllOutboundTxsV2(ctx, pushChainTxHash, outboundHops, options) {
|
|
|
462
494
|
// inside this function; it's not exposed to consumers from the
|
|
463
495
|
// cascade path (cascade.ts doesn't call findChildUtxIdFromExternalTx
|
|
464
496
|
// for the cascade outbound hash).
|
|
465
|
-
const displayTxHash = (
|
|
497
|
+
const displayTxHash = (_l = (0, helpers_1.toExternalTxHashDisplay)(chain !== null && chain !== void 0 ? chain : undefined, externalTxHash)) !== null && _l !== void 0 ? _l : externalTxHash;
|
|
466
498
|
let explorerUrl = '';
|
|
467
499
|
if (chain && externalTxHash) {
|
|
468
|
-
const explorerBaseUrl = (
|
|
469
|
-
const isSvm = ((
|
|
500
|
+
const explorerBaseUrl = (_m = chain_1.CHAIN_INFO[chain]) === null || _m === void 0 ? void 0 : _m.explorerUrl;
|
|
501
|
+
const isSvm = ((_o = chain_1.CHAIN_INFO[chain]) === null || _o === void 0 ? void 0 : _o.vm) === enums_1.VM.SVM;
|
|
470
502
|
if (isSvm) {
|
|
471
|
-
const cluster = chain === enums_1.CHAIN.SOLANA_DEVNET
|
|
472
|
-
|
|
473
|
-
|
|
503
|
+
const cluster = chain === enums_1.CHAIN.SOLANA_DEVNET
|
|
504
|
+
? '?cluster=devnet'
|
|
505
|
+
: chain === enums_1.CHAIN.SOLANA_TESTNET
|
|
506
|
+
? '?cluster=testnet'
|
|
507
|
+
: '';
|
|
508
|
+
explorerUrl = explorerBaseUrl
|
|
509
|
+
? `${explorerBaseUrl}/tx/${displayTxHash}${cluster}`
|
|
510
|
+
: '';
|
|
474
511
|
}
|
|
475
512
|
else {
|
|
476
|
-
explorerUrl = explorerBaseUrl
|
|
513
|
+
explorerUrl = explorerBaseUrl
|
|
514
|
+
? `${explorerBaseUrl}/tx/${displayTxHash}`
|
|
515
|
+
: '';
|
|
477
516
|
}
|
|
478
517
|
}
|
|
479
|
-
targetHop
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
518
|
+
for (const targetHop of pendingTargetHops) {
|
|
519
|
+
targetHop.status = 'confirmed';
|
|
520
|
+
targetHop.txHash = displayTxHash;
|
|
521
|
+
targetHop.outboundDetails = {
|
|
522
|
+
externalTxHash: displayTxHash,
|
|
523
|
+
destinationChain: chain || targetHop.executionChain,
|
|
524
|
+
explorerUrl,
|
|
525
|
+
recipient: ob.recipient,
|
|
526
|
+
amount: ob.amount,
|
|
527
|
+
assetAddr: ob.externalAssetAddr,
|
|
528
|
+
};
|
|
529
|
+
progressHook === null || progressHook === void 0 ? void 0 : progressHook({
|
|
530
|
+
hopIndex: targetHop.hopIndex,
|
|
531
|
+
route: targetHop.route,
|
|
532
|
+
chain: targetHop.executionChain,
|
|
533
|
+
status: 'confirmed',
|
|
534
|
+
txHash: displayTxHash,
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
(0, context_1.printLog)(ctx, `[waitForAllOutboundTxsV2] FOUND outbound for ${destChain} | outboundIndex ${outboundOrdinal} | hops ${pendingTargetHops
|
|
538
|
+
.map((hop) => hop.hopIndex)
|
|
539
|
+
.join(', ')} | externalTxHash: ${displayTxHash}`);
|
|
497
540
|
}
|
|
498
541
|
}
|
|
499
542
|
}
|
|
@@ -508,7 +551,7 @@ function waitForAllOutboundTxsV2(ctx, pushChainTxHash, outboundHops, options) {
|
|
|
508
551
|
if (statusNum === types_1.UniversalTxStatus.PC_EXECUTED_SUCCESS) {
|
|
509
552
|
const stillUnresolved = outboundHops.filter((h) => h.status !== 'confirmed');
|
|
510
553
|
if (stillUnresolved.length > 0) {
|
|
511
|
-
const hasPendingOutbound = (
|
|
554
|
+
const hasPendingOutbound = (_p = utx === null || utx === void 0 ? void 0 : utx.outboundTx) === null || _p === void 0 ? void 0 : _p.some((ob) => {
|
|
512
555
|
var _a;
|
|
513
556
|
return ob.outboundStatus === types_2.OutboundStatus.PENDING &&
|
|
514
557
|
(!((_a = ob.observedTx) === null || _a === void 0 ? void 0 : _a.txHash) || ob.observedTx.txHash === 'EMPTY');
|
|
@@ -563,14 +563,32 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
563
563
|
}
|
|
564
564
|
}
|
|
565
565
|
const origin = `${chain_1.VM_NAMESPACE[vm]}:${chainId}:${originAddress}`;
|
|
566
|
-
// Create signature from transaction r, s, v values
|
|
566
|
+
// Create signature from transaction r, s, v values.
|
|
567
|
+
//
|
|
568
|
+
// Push Chain's derived (module-injected) inbound txs are reported over the EVM
|
|
569
|
+
// JSON-RPC as **legacy `type 0x0`**, which omits the `yParity` field that viem
|
|
570
|
+
// only populates for typed (EIP-1559/2930) txs — so `tx.yParity` is `undefined`.
|
|
571
|
+
// Per the chain team (the hash inconsistencies were fixed chain-side, but
|
|
572
|
+
// derived txs remain legacy 0x0 by design), the SDK must accept `0x0` and
|
|
573
|
+
// surface a numeric `yParity`. Derive it from `v`: 0/1 → as-is, 27/28 → v-27,
|
|
574
|
+
// EIP-155 → (v-35)%2. (For the zeroed-signature derived txs, v=0 → yParity=0.)
|
|
567
575
|
let signature;
|
|
568
576
|
try {
|
|
577
|
+
const vNum = typeof tx.v === 'bigint' ? Number(tx.v) : tx.v || 0;
|
|
578
|
+
let yParity = tx.yParity;
|
|
579
|
+
if (yParity === undefined) {
|
|
580
|
+
if (vNum === 0 || vNum === 1)
|
|
581
|
+
yParity = vNum;
|
|
582
|
+
else if (vNum === 27 || vNum === 28)
|
|
583
|
+
yParity = vNum - 27;
|
|
584
|
+
else
|
|
585
|
+
yParity = (vNum - 35) % 2;
|
|
586
|
+
}
|
|
569
587
|
signature = {
|
|
570
588
|
r: tx.r || '0x0',
|
|
571
589
|
s: tx.s || '0x0',
|
|
572
|
-
v:
|
|
573
|
-
yParity
|
|
590
|
+
v: vNum,
|
|
591
|
+
yParity,
|
|
574
592
|
};
|
|
575
593
|
}
|
|
576
594
|
catch (_d) {
|
|
@@ -609,6 +627,7 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
609
627
|
const universalTxResponse = {
|
|
610
628
|
// 1. Identity
|
|
611
629
|
hash: tx.hash,
|
|
630
|
+
finalTxHash: tx.hash, // Push tx hash; .wait()'s receipt refines it for R2/R3
|
|
612
631
|
origin,
|
|
613
632
|
// 2. Block Info
|
|
614
633
|
blockNumber: tx.blockNumber || BigInt(0),
|
|
@@ -630,7 +649,7 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
630
649
|
accessList: Array.isArray(tx.accessList) ? [...tx.accessList] : [],
|
|
631
650
|
// 6. Utilities
|
|
632
651
|
wait: (waitOptions) => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
633
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
652
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
634
653
|
// For trackTransaction replays the tx is historical — cosmos already
|
|
635
654
|
// has the full graph indexed, so the 20s/30s initial-wait buffers
|
|
636
655
|
// designed for live sends are pure deadweight. Default them to 0 when
|
|
@@ -775,7 +794,15 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
775
794
|
// Resolve the terminal hash for the whole journey: inbound (R3) >
|
|
776
795
|
// external outbound (R2) > the Push tx itself (R1). Single-tx analogue
|
|
777
796
|
// of CascadeCompletionResult.finalTxHash.
|
|
778
|
-
baseReceipt = Object.assign(Object.assign({}, baseReceipt), { finalTxHash: (_l = (_k = baseReceipt.pushInboundTxHash) !== null && _k !== void 0 ? _k : baseReceipt.externalTxHash) !== null && _l !== void 0 ? _l : baseReceipt.hash
|
|
797
|
+
baseReceipt = Object.assign(Object.assign({}, baseReceipt), { finalTxHash: (_l = (_k = baseReceipt.pushInboundTxHash) !== null && _k !== void 0 ? _k : baseReceipt.externalTxHash) !== null && _l !== void 0 ? _l : baseReceipt.hash,
|
|
798
|
+
// Ensure `externalChain` is populated whenever an external/inbound leg
|
|
799
|
+
// surfaced an `externalTxHash`. The outbound-success branch already sets
|
|
800
|
+
// it to the destination chain (so this `??` never overrides it); this
|
|
801
|
+
// only fills the inbound/R3 and failed/timeout paths, where it should be
|
|
802
|
+
// the route's external chain (= the response's `chain`).
|
|
803
|
+
externalChain: (_m = baseReceipt.externalChain) !== null && _m !== void 0 ? _m : (baseReceipt.externalTxHash
|
|
804
|
+
? universalTxResponse.chain
|
|
805
|
+
: baseReceipt.externalChain) });
|
|
779
806
|
return baseReceipt;
|
|
780
807
|
}),
|
|
781
808
|
// Internal: register a wait-phase progressHook without replaying
|
|
@@ -19,6 +19,13 @@ import { MoveableToken } from '../../constants/tokens';
|
|
|
19
19
|
import { TransactionRoute } from '../route-detector';
|
|
20
20
|
import type { ChainTarget, ExecuteParams, UniversalExecuteParams, UniversalOutboundTxRequest, UniversalTxRequest, UniversalTxResponse } from '../orchestrator.types';
|
|
21
21
|
import type { PUSH_NETWORK } from '../../constants/enums';
|
|
22
|
+
export declare function getRequiredNativeBalanceForOutbound(nativeValueForGas: bigint, gasReserve: bigint): bigint;
|
|
23
|
+
export declare function shouldSkipFeeLockingForOutbound(opts: {
|
|
24
|
+
isUEADeployed: boolean;
|
|
25
|
+
balance: bigint;
|
|
26
|
+
nativeValueForGas: bigint;
|
|
27
|
+
gasReserve: bigint;
|
|
28
|
+
}): boolean;
|
|
22
29
|
export declare function resolveR2DestinationFundsToken(token: MoveableToken, targetChain: CHAIN, pushNetwork: PUSH_NETWORK): MoveableToken;
|
|
23
30
|
type ExecuteFn = (params: ExecuteParams | UniversalExecuteParams) => Promise<UniversalTxResponse>;
|
|
24
31
|
/**
|