@pushchain/core 5.1.17 → 6.0.0
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/abi/cea.evm.d.ts +52 -0
- package/src/lib/constants/abi/cea.evm.js +66 -1
- package/src/lib/constants/abi/prc20.evm.d.ts +117 -11
- package/src/lib/constants/abi/prc20.evm.js +38 -11
- package/src/lib/constants/abi/uea.evm.js +41 -0
- package/src/lib/constants/abi/universalGatewayPC.evm.d.ts +117 -1
- package/src/lib/constants/abi/universalGatewayPC.evm.js +40 -1
- package/src/lib/constants/abi/universalGatewayV0.json +1 -1
- package/src/lib/constants/chain.js +14 -14
- 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/constants/tokens.js +1 -0
- package/src/lib/formatters.d.ts +7 -0
- package/src/lib/formatters.js +46 -0
- package/src/lib/index.d.ts +2 -0
- package/src/lib/index.js +7 -1
- package/src/lib/orchestrator/internals/cascade.d.ts +8 -1
- package/src/lib/orchestrator/internals/cascade.js +593 -192
- 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 +8 -5
- package/src/lib/orchestrator/internals/execute-funds-only.js +3 -2
- package/src/lib/orchestrator/internals/execute-funds-payload.js +2 -1
- package/src/lib/orchestrator/internals/execute-standard.js +11 -10
- package/src/lib/orchestrator/internals/gas-calculator.d.ts +1 -0
- package/src/lib/orchestrator/internals/gas-calculator.js +91 -22
- package/src/lib/orchestrator/internals/helpers.d.ts +2 -1
- package/src/lib/orchestrator/internals/helpers.js +14 -11
- package/src/lib/orchestrator/internals/inbound-tracker.js +4 -2
- package/src/lib/orchestrator/internals/outbound-sync.d.ts +1 -0
- package/src/lib/orchestrator/internals/outbound-sync.js +140 -71
- package/src/lib/orchestrator/internals/pc-usd-oracle.d.ts +1 -1
- package/src/lib/orchestrator/internals/pc-usd-oracle.js +4 -3
- package/src/lib/orchestrator/internals/preflight.d.ts +2 -16
- package/src/lib/orchestrator/internals/preflight.js +2 -36
- package/src/lib/orchestrator/internals/push-chain-tx.js +5 -1
- package/src/lib/orchestrator/internals/response-builder.js +23 -7
- package/src/lib/orchestrator/internals/route-handlers.js +182 -227
- package/src/lib/orchestrator/internals/signing.js +7 -2
- package/src/lib/orchestrator/internals/svm-helpers.js +3 -3
- package/src/lib/orchestrator/internals/svm-rent.d.ts +42 -9
- package/src/lib/orchestrator/internals/svm-rent.js +148 -14
- package/src/lib/orchestrator/internals/tx-transformer.js +5 -2
- package/src/lib/orchestrator/max-pc-for-gas.d.ts +60 -0
- package/src/lib/orchestrator/max-pc-for-gas.js +66 -0
- package/src/lib/orchestrator/orchestrator.d.ts +8 -1
- package/src/lib/orchestrator/orchestrator.js +40 -2
- package/src/lib/orchestrator/orchestrator.types.d.ts +35 -23
- package/src/lib/orchestrator/payload-builders.d.ts +7 -6
- package/src/lib/orchestrator/payload-builders.js +18 -6
- package/src/lib/progress-hook/progress-hook.js +39 -38
- 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/events.d.ts +3 -1
- package/src/lib/universal-tx-detector/events.js +3 -1
- package/src/lib/universal-tx-detector/normalize.d.ts +42 -0
- package/src/lib/universal-tx-detector/normalize.js +127 -0
- package/src/lib/universal-tx-detector/svm-events.d.ts +1 -1
- package/src/lib/universal-tx-detector/svm-events.js +1 -1
- package/src/lib/utils/external-tx-hash.d.ts +37 -0
- package/src/lib/utils/external-tx-hash.js +62 -0
|
@@ -11,6 +11,7 @@ exports.prepareTransaction = prepareTransaction;
|
|
|
11
11
|
exports.buildHopDescriptor = buildHopDescriptor;
|
|
12
12
|
exports.classifyIntoSegments = classifyIntoSegments;
|
|
13
13
|
exports.getSegmentType = getSegmentType;
|
|
14
|
+
exports.composeCascadeDetailed = composeCascadeDetailed;
|
|
14
15
|
exports.composeCascade = composeCascade;
|
|
15
16
|
exports.createCascadedBuilder = createCascadedBuilder;
|
|
16
17
|
const tslib_1 = require("tslib");
|
|
@@ -38,6 +39,7 @@ const preflight_1 = require("./preflight");
|
|
|
38
39
|
const svm_rent_1 = require("./svm-rent");
|
|
39
40
|
const errors_1 = require("./errors");
|
|
40
41
|
const context_2 = require("./context");
|
|
42
|
+
const inbound_tracker_1 = require("./inbound-tracker");
|
|
41
43
|
// ============================================================================
|
|
42
44
|
// dispatchCascadeProgressEvent
|
|
43
45
|
// ============================================================================
|
|
@@ -120,20 +122,32 @@ function prepareTransaction(ctx, params, callbacks) {
|
|
|
120
122
|
// ============================================================================
|
|
121
123
|
function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
122
124
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
123
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
124
|
-
// Pass 0 when user omits gasLimit
|
|
125
|
-
|
|
125
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
126
|
+
// Pass 0 when user omits gasLimit so the contract uses the per-chain base,
|
|
127
|
+
// except EVM Route 3 where a CEA deploy + sendUniversalTxToUEA needs more
|
|
128
|
+
// than the generic 500k source-chain base.
|
|
129
|
+
const defaultGasLimit = route === route_detector_1.TransactionRoute.CEA_TO_PUSH &&
|
|
130
|
+
((_a = params.from) === null || _a === void 0 ? void 0 : _a.chain) &&
|
|
131
|
+
!(0, payload_builders_1.isSvmChain)(params.from.chain)
|
|
132
|
+
? selectors_1.DEFAULT_CEA_TO_PUSH_GAS_LIMIT
|
|
133
|
+
: BigInt(0);
|
|
134
|
+
const gasLimit = (_b = params.gasLimit) !== null && _b !== void 0 ? _b : defaultGasLimit;
|
|
126
135
|
const routeStr = route;
|
|
127
136
|
const baseDescriptor = {
|
|
128
137
|
params,
|
|
129
138
|
route: routeStr,
|
|
130
139
|
gasLimit,
|
|
140
|
+
maxPCForGas: (_c = params.maxPCForGas) !== null && _c !== void 0 ? _c : BigInt(0),
|
|
131
141
|
ueaAddress,
|
|
132
142
|
revertRecipient: ueaAddress,
|
|
133
143
|
};
|
|
134
144
|
switch (route) {
|
|
135
145
|
case route_detector_1.TransactionRoute.UOA_TO_PUSH: {
|
|
136
146
|
// Route 1: Build Push Chain multicalls
|
|
147
|
+
const seedAmount = (_d = params.value) !== null && _d !== void 0 ? _d : BigInt(0);
|
|
148
|
+
if (isValueOnlyNativeSeedToOwnUea(params, ueaAddress)) {
|
|
149
|
+
return Object.assign(Object.assign({}, baseDescriptor), { pushMulticalls: [], nativeSeedOnly: true, nativeSeedAmount: seedAmount });
|
|
150
|
+
}
|
|
137
151
|
const executeParams = (0, helpers_1.toExecuteParams)(params);
|
|
138
152
|
const pushMulticalls = (0, payload_builders_1.buildExecuteMulticall)({
|
|
139
153
|
execute: executeParams,
|
|
@@ -155,7 +169,7 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
155
169
|
});
|
|
156
170
|
let prc20Token = selectors_1.ZERO_ADDRESS;
|
|
157
171
|
let burnAmount = BigInt(0);
|
|
158
|
-
if ((
|
|
172
|
+
if ((_e = params.funds) === null || _e === void 0 ? void 0 : _e.amount) {
|
|
159
173
|
const token = params.funds.token;
|
|
160
174
|
if (token) {
|
|
161
175
|
prc20Token = push_chain_1.PushChain.utils.tokens.getPRC20Address(token).address;
|
|
@@ -177,53 +191,70 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
177
191
|
}
|
|
178
192
|
let gasToken = selectors_1.ZERO_ADDRESS;
|
|
179
193
|
let gasFee = BigInt(0);
|
|
194
|
+
let gasPrice = BigInt(0);
|
|
180
195
|
let sizing;
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
|
|
184
|
-
|
|
196
|
+
// SVM finalize budget: compare the quoted gasFee in lamports against
|
|
197
|
+
// the gateway finalize minimum, then re-query with a bumped gasLimit
|
|
198
|
+
// if the default quote is too low.
|
|
199
|
+
const svmFundsToken = burnAmount > BigInt(0)
|
|
200
|
+
? (_f = params.funds) === null || _f === void 0 ? void 0 : _f.token
|
|
185
201
|
: undefined;
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
splMintBase58,
|
|
191
|
-
burnAmount,
|
|
192
|
-
effectiveGasLimit: gasLimit,
|
|
193
|
-
});
|
|
202
|
+
const splMintBase58 = (svmFundsToken === null || svmFundsToken === void 0 ? void 0 : svmFundsToken.mechanism) === 'approve'
|
|
203
|
+
? svmFundsToken.address
|
|
204
|
+
: undefined;
|
|
205
|
+
let effectiveGasLimit = gasLimit;
|
|
194
206
|
if (prc20Token !== selectors_1.ZERO_ADDRESS) {
|
|
195
|
-
|
|
207
|
+
let result = yield (0, gas_calculator_1.queryOutboundGasFee)(ctx, prc20Token, effectiveGasLimit, targetChain);
|
|
208
|
+
result = yield (0, svm_rent_1.ensureSvmFinalizeGasBudgetQuote)({
|
|
209
|
+
ctx,
|
|
210
|
+
ueaAddress,
|
|
211
|
+
targetChain,
|
|
212
|
+
prc20Token,
|
|
213
|
+
quote: result,
|
|
214
|
+
splMintBase58,
|
|
215
|
+
burnAmount,
|
|
216
|
+
pathTag: 'buildHopDescriptor',
|
|
217
|
+
});
|
|
196
218
|
gasToken = result.gasToken;
|
|
197
219
|
gasFee = result.gasFee;
|
|
220
|
+
gasPrice = result.gasPrice;
|
|
198
221
|
sizing = result.sizing;
|
|
222
|
+
effectiveGasLimit = result.gasLimitUsed;
|
|
223
|
+
if (!params.gasLimit) {
|
|
224
|
+
(0, context_1.printLog)(ctx, `buildHopDescriptor — SVM resolved effectiveGasLimit: ${effectiveGasLimit} ` +
|
|
225
|
+
`(gasFee=${result.gasFee}, gasPrice=${result.gasPrice})`);
|
|
226
|
+
}
|
|
199
227
|
}
|
|
200
228
|
return Object.assign(Object.assign({}, baseDescriptor), { targetChain, isSvmTarget: true, svmPayload,
|
|
201
229
|
prc20Token,
|
|
202
230
|
burnAmount,
|
|
203
231
|
gasToken,
|
|
204
232
|
gasFee,
|
|
205
|
-
sizing });
|
|
233
|
+
gasPrice, gasLimit: effectiveGasLimit, sizing });
|
|
206
234
|
}
|
|
207
235
|
// EVM path: Resolve CEA address + build CEA multicalls
|
|
208
|
-
const { cea: ceaAddress } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, targetChain, (
|
|
236
|
+
const { cea: ceaAddress } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, targetChain, (_g = ctx.rpcUrls[targetChain]) === null || _g === void 0 ? void 0 : _g[0]);
|
|
209
237
|
// Migration path: raw MIGRATION_SELECTOR payload, no multicall wrapping
|
|
210
238
|
if (params.migration) {
|
|
211
239
|
const prc20Token = (0, helpers_1.getNativePRC20ForChain)(targetChain, ctx.pushNetwork);
|
|
212
240
|
const burnAmount = BigInt(0); // Migration is logic-only — no funds. CEA rejects msg.value != 0.
|
|
213
241
|
let gasToken = selectors_1.ZERO_ADDRESS;
|
|
214
242
|
let gasFee = BigInt(0);
|
|
243
|
+
let gasPrice = BigInt(0);
|
|
215
244
|
let sizing;
|
|
216
245
|
if (prc20Token !== selectors_1.ZERO_ADDRESS) {
|
|
217
246
|
const result = yield (0, gas_calculator_1.queryOutboundGasFee)(ctx, prc20Token, gasLimit, targetChain);
|
|
218
247
|
gasToken = result.gasToken;
|
|
219
248
|
gasFee = result.gasFee;
|
|
249
|
+
gasPrice = result.gasPrice;
|
|
220
250
|
sizing = result.sizing;
|
|
221
251
|
}
|
|
222
252
|
return Object.assign(Object.assign({}, baseDescriptor), { targetChain,
|
|
223
253
|
ceaAddress, ceaMulticalls: [], prc20Token,
|
|
224
254
|
burnAmount,
|
|
225
255
|
gasToken,
|
|
226
|
-
gasFee,
|
|
256
|
+
gasFee,
|
|
257
|
+
gasPrice, isMigration: true, sizing });
|
|
227
258
|
}
|
|
228
259
|
// Build CEA multicalls
|
|
229
260
|
const ceaMulticalls = [];
|
|
@@ -235,7 +266,7 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
235
266
|
// When ERC-20 funds are provided with a single payload, auto-prepend a
|
|
236
267
|
// transfer() call so the tokens minted to the CEA are forwarded to the
|
|
237
268
|
// target address. This mirrors the Route 1 behavior in buildExecuteMulticall.
|
|
238
|
-
if ((
|
|
269
|
+
if ((_h = params.funds) === null || _h === void 0 ? void 0 : _h.amount) {
|
|
239
270
|
const token = params.funds.token;
|
|
240
271
|
if (token && token.mechanism !== 'native') {
|
|
241
272
|
const erc20Transfer = (0, viem_1.encodeFunctionData)({
|
|
@@ -255,7 +286,7 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
255
286
|
// native value to the CEA, and the multicall forwards it to the target.
|
|
256
287
|
ceaMulticalls.push({
|
|
257
288
|
to: target.address,
|
|
258
|
-
value: (
|
|
289
|
+
value: (_j = params.value) !== null && _j !== void 0 ? _j : BigInt(0),
|
|
259
290
|
data: params.data,
|
|
260
291
|
});
|
|
261
292
|
}
|
|
@@ -271,7 +302,7 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
271
302
|
});
|
|
272
303
|
}
|
|
273
304
|
}
|
|
274
|
-
else if ((
|
|
305
|
+
else if ((_k = params.funds) === null || _k === void 0 ? void 0 : _k.amount) {
|
|
275
306
|
// Funds-only transfer (no data, no value). Without this branch the
|
|
276
307
|
// CEA multicall is empty and relayed funds stay in the CEA instead
|
|
277
308
|
// of reaching the caller's recipient.
|
|
@@ -303,7 +334,7 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
303
334
|
// Determine PRC-20 token and burn amount
|
|
304
335
|
let prc20Token = selectors_1.ZERO_ADDRESS;
|
|
305
336
|
let burnAmount = BigInt(0);
|
|
306
|
-
if ((
|
|
337
|
+
if ((_l = params.funds) === null || _l === void 0 ? void 0 : _l.amount) {
|
|
307
338
|
const token = params.funds.token;
|
|
308
339
|
if (token) {
|
|
309
340
|
prc20Token = push_chain_1.PushChain.utils.tokens.getPRC20Address(token).address;
|
|
@@ -326,11 +357,13 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
326
357
|
// Query gas fee
|
|
327
358
|
let gasToken = selectors_1.ZERO_ADDRESS;
|
|
328
359
|
let gasFee = BigInt(0);
|
|
360
|
+
let gasPrice = BigInt(0);
|
|
329
361
|
let sizing;
|
|
330
362
|
if (prc20Token !== selectors_1.ZERO_ADDRESS) {
|
|
331
363
|
const result = yield (0, gas_calculator_1.queryOutboundGasFee)(ctx, prc20Token, gasLimit, targetChain);
|
|
332
364
|
gasToken = result.gasToken;
|
|
333
365
|
gasFee = result.gasFee;
|
|
366
|
+
gasPrice = result.gasPrice;
|
|
334
367
|
sizing = result.sizing;
|
|
335
368
|
}
|
|
336
369
|
return Object.assign(Object.assign({}, baseDescriptor), { targetChain,
|
|
@@ -340,11 +373,16 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
340
373
|
burnAmount,
|
|
341
374
|
gasToken,
|
|
342
375
|
gasFee,
|
|
376
|
+
gasPrice,
|
|
343
377
|
sizing });
|
|
344
378
|
}
|
|
345
379
|
case route_detector_1.TransactionRoute.CEA_TO_PUSH: {
|
|
346
380
|
// Route 3: Build CEA multicalls for sendUniversalTxFromCEA
|
|
347
381
|
const sourceChain = params.from.chain;
|
|
382
|
+
const seedAmount = (_m = params.value) !== null && _m !== void 0 ? _m : BigInt(0);
|
|
383
|
+
if (isValueOnlyNativeSeedToOwnUea(params, ueaAddress)) {
|
|
384
|
+
return Object.assign(Object.assign({}, baseDescriptor), { sourceChain, burnAmount: BigInt(0), gasToken: selectors_1.ZERO_ADDRESS, gasFee: BigInt(0), nativeSeedOnly: true, nativeSeedAmount: seedAmount });
|
|
385
|
+
}
|
|
348
386
|
// SVM chains use PDA-based CEA, not factory-deployed CEA
|
|
349
387
|
if ((0, payload_builders_1.isSvmChain)(sourceChain)) {
|
|
350
388
|
const lockerContract = chain_1.CHAIN_INFO[sourceChain].lockerContract;
|
|
@@ -361,7 +399,7 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
361
399
|
Buffer.from(ceaPda.toBytes()).toString('hex'));
|
|
362
400
|
let amount = BigInt(0);
|
|
363
401
|
let prc20Token;
|
|
364
|
-
if (((
|
|
402
|
+
if (((_o = params.funds) === null || _o === void 0 ? void 0 : _o.amount) && params.funds.amount > BigInt(0)) {
|
|
365
403
|
amount = params.funds.amount;
|
|
366
404
|
const token = params.funds.token;
|
|
367
405
|
if (token && token.address) {
|
|
@@ -381,25 +419,42 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
381
419
|
}
|
|
382
420
|
let gasToken = selectors_1.ZERO_ADDRESS;
|
|
383
421
|
let gasFee = BigInt(0);
|
|
422
|
+
let gasPrice = BigInt(0);
|
|
384
423
|
let sizing;
|
|
424
|
+
let effectiveGasLimit = gasLimit;
|
|
385
425
|
if (prc20Token !== selectors_1.ZERO_ADDRESS) {
|
|
386
|
-
|
|
426
|
+
let result = yield (0, gas_calculator_1.queryOutboundGasFee)(ctx, prc20Token, effectiveGasLimit, sourceChain);
|
|
427
|
+
result = yield (0, svm_rent_1.ensureSvmFinalizeGasBudgetQuote)({
|
|
428
|
+
ctx,
|
|
429
|
+
ueaAddress,
|
|
430
|
+
targetChain: sourceChain,
|
|
431
|
+
prc20Token,
|
|
432
|
+
quote: result,
|
|
433
|
+
splMintBase58: undefined,
|
|
434
|
+
burnAmount: BigInt(0),
|
|
435
|
+
pathTag: 'buildHopDescriptor',
|
|
436
|
+
});
|
|
387
437
|
gasToken = result.gasToken;
|
|
388
438
|
gasFee = result.gasFee;
|
|
439
|
+
gasPrice = result.gasPrice;
|
|
389
440
|
sizing = result.sizing;
|
|
441
|
+
effectiveGasLimit = result.gasLimitUsed;
|
|
390
442
|
}
|
|
391
|
-
return Object.assign(Object.assign({}, baseDescriptor), { sourceChain, ceaAddress: ceaPdaHex, isSvmTarget: true, prc20Token,
|
|
443
|
+
return Object.assign(Object.assign({}, baseDescriptor), { sourceChain, ceaAddress: ceaPdaHex, isSvmTarget: true, prc20Token,
|
|
444
|
+
// Route 3 is payload-only on Push: the drain amount lives inside the
|
|
445
|
+
// SVM payload. Burning here would require the UEA to pre-hold pSOL.
|
|
446
|
+
burnAmount: BigInt(0), gasToken,
|
|
392
447
|
gasFee,
|
|
393
|
-
sizing });
|
|
448
|
+
gasPrice, gasLimit: effectiveGasLimit, sizing });
|
|
394
449
|
}
|
|
395
|
-
const { cea: ceaAddress } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, sourceChain, (
|
|
450
|
+
const { cea: ceaAddress } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, sourceChain, (_p = ctx.rpcUrls[sourceChain]) === null || _p === void 0 ? void 0 : _p[0]);
|
|
396
451
|
// CEA auto-deploys on-chain: Vault.finalizeUniversalTx calls CEAFactory.deployCEA()
|
|
397
452
|
// if CEA doesn't exist yet. No SDK-side blocking needed.
|
|
398
453
|
// Determine token/amount for the inbound
|
|
399
454
|
let tokenAddress = selectors_1.ZERO_ADDRESS;
|
|
400
455
|
let amount = BigInt(0);
|
|
401
456
|
let nativeValue = BigInt(0);
|
|
402
|
-
if ((
|
|
457
|
+
if ((_q = params.funds) === null || _q === void 0 ? void 0 : _q.amount) {
|
|
403
458
|
const token = params.funds.token;
|
|
404
459
|
if (token) {
|
|
405
460
|
if (token.mechanism === 'native') {
|
|
@@ -420,17 +475,24 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
420
475
|
const prc20Token = (0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork);
|
|
421
476
|
let gasToken = selectors_1.ZERO_ADDRESS;
|
|
422
477
|
let gasFee = BigInt(0);
|
|
478
|
+
let gasPrice = BigInt(0);
|
|
423
479
|
let sizing;
|
|
424
480
|
if (prc20Token !== selectors_1.ZERO_ADDRESS) {
|
|
425
481
|
const result = yield (0, gas_calculator_1.queryOutboundGasFee)(ctx, prc20Token, gasLimit, sourceChain);
|
|
426
482
|
gasToken = result.gasToken;
|
|
427
483
|
gasFee = result.gasFee;
|
|
484
|
+
gasPrice = result.gasPrice;
|
|
428
485
|
sizing = result.sizing;
|
|
429
486
|
}
|
|
430
487
|
return Object.assign(Object.assign({}, baseDescriptor), { sourceChain,
|
|
431
488
|
ceaAddress,
|
|
432
|
-
prc20Token,
|
|
489
|
+
prc20Token,
|
|
490
|
+
// Route 3 is payload-only on Push: the CEA-side sendUniversalTxToUEA
|
|
491
|
+
// carries `amount`. Burning here would require the UEA to pre-hold the
|
|
492
|
+
// token it is trying to receive from the external CEA.
|
|
493
|
+
burnAmount: BigInt(0), gasToken,
|
|
433
494
|
gasFee,
|
|
495
|
+
gasPrice,
|
|
434
496
|
sizing });
|
|
435
497
|
}
|
|
436
498
|
default:
|
|
@@ -463,7 +525,9 @@ function classifyIntoSegments(hops) {
|
|
|
463
525
|
? currentSegment.targetChain === hop.targetChain && !hop.isSvmTarget
|
|
464
526
|
: segType === 'INBOUND_FROM_CEA'
|
|
465
527
|
? currentSegment.sourceChain === hop.sourceChain &&
|
|
466
|
-
!(0, payload_builders_1.isSvmChain)(hop.sourceChain)
|
|
528
|
+
!(0, payload_builders_1.isSvmChain)(hop.sourceChain) &&
|
|
529
|
+
isNativeSeedOnlyHop(currentSegment.hops[0]) ===
|
|
530
|
+
isNativeSeedOnlyHop(hop)
|
|
467
531
|
: segType === 'PUSH_EXECUTION');
|
|
468
532
|
if (canMerge && currentSegment) {
|
|
469
533
|
// Merge into current segment
|
|
@@ -483,6 +547,8 @@ function classifyIntoSegments(hops) {
|
|
|
483
547
|
// Accumulate gas fees
|
|
484
548
|
currentSegment.gasFee =
|
|
485
549
|
(currentSegment.gasFee || BigInt(0)) + (hop.gasFee || BigInt(0));
|
|
550
|
+
currentSegment.gasPrice = mergeGasPrice(currentSegment.gasPrice, hop.gasPrice);
|
|
551
|
+
currentSegment.maxPCForGas = mergeMaxPCForGas(currentSegment.maxPCForGas, hop.maxPCForGas);
|
|
486
552
|
}
|
|
487
553
|
else if (segType === 'INBOUND_FROM_CEA') {
|
|
488
554
|
// Sum burn amounts so the single sendUniversalTxToUEA carries the
|
|
@@ -495,6 +561,8 @@ function classifyIntoSegments(hops) {
|
|
|
495
561
|
}
|
|
496
562
|
currentSegment.gasFee =
|
|
497
563
|
(currentSegment.gasFee || BigInt(0)) + (hop.gasFee || BigInt(0));
|
|
564
|
+
currentSegment.gasPrice = mergeGasPrice(currentSegment.gasPrice, hop.gasPrice);
|
|
565
|
+
currentSegment.maxPCForGas = mergeMaxPCForGas(currentSegment.maxPCForGas, hop.maxPCForGas);
|
|
498
566
|
}
|
|
499
567
|
else if (segType === 'PUSH_EXECUTION') {
|
|
500
568
|
currentSegment.mergedPushMulticalls = [
|
|
@@ -532,7 +600,9 @@ function classifyIntoSegments(hops) {
|
|
|
532
600
|
prc20Token: hop.prc20Token,
|
|
533
601
|
gasToken: hop.gasToken,
|
|
534
602
|
gasFee: hop.gasFee,
|
|
603
|
+
gasPrice: hop.gasPrice,
|
|
535
604
|
gasLimit: hop.gasLimit,
|
|
605
|
+
maxPCForGas: hop.maxPCForGas,
|
|
536
606
|
sizing: hop.sizing,
|
|
537
607
|
};
|
|
538
608
|
segments.push(currentSegment);
|
|
@@ -544,6 +614,18 @@ function classifyIntoSegments(hops) {
|
|
|
544
614
|
function categoryRank(c) {
|
|
545
615
|
return c === 'C' ? 2 : c === 'B' ? 1 : 0;
|
|
546
616
|
}
|
|
617
|
+
function mergeMaxPCForGas(current, next) {
|
|
618
|
+
const a = current !== null && current !== void 0 ? current : BigInt(0);
|
|
619
|
+
const b = next !== null && next !== void 0 ? next : BigInt(0);
|
|
620
|
+
if (a === BigInt(0) || b === BigInt(0))
|
|
621
|
+
return BigInt(0);
|
|
622
|
+
return a + b;
|
|
623
|
+
}
|
|
624
|
+
function mergeGasPrice(current, next) {
|
|
625
|
+
const a = current !== null && current !== void 0 ? current : BigInt(0);
|
|
626
|
+
const b = next !== null && next !== void 0 ? next : BigInt(0);
|
|
627
|
+
return a > b ? a : b;
|
|
628
|
+
}
|
|
547
629
|
// ============================================================================
|
|
548
630
|
// getSegmentType
|
|
549
631
|
// ============================================================================
|
|
@@ -559,46 +641,156 @@ function getSegmentType(route) {
|
|
|
559
641
|
return 'PUSH_EXECUTION';
|
|
560
642
|
}
|
|
561
643
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
function
|
|
644
|
+
function sumMulticallNativeValue(multicalls) {
|
|
645
|
+
return (multicalls !== null && multicalls !== void 0 ? multicalls : []).reduce((sum, mc) => { var _a; return sum + ((_a = mc.value) !== null && _a !== void 0 ? _a : BigInt(0)); }, BigInt(0));
|
|
646
|
+
}
|
|
647
|
+
function isEmptyPayloadData(data) {
|
|
648
|
+
return (data === undefined ||
|
|
649
|
+
data === '0x' ||
|
|
650
|
+
(Array.isArray(data) && data.length === 0));
|
|
651
|
+
}
|
|
652
|
+
function isValueOnlyNativeSeedToOwnUea(params, ueaAddress) {
|
|
653
|
+
var _a, _b;
|
|
654
|
+
return (((_a = params.value) !== null && _a !== void 0 ? _a : BigInt(0)) > BigInt(0) &&
|
|
655
|
+
!((_b = params.funds) === null || _b === void 0 ? void 0 : _b.amount) &&
|
|
656
|
+
isEmptyPayloadData(params.data) &&
|
|
657
|
+
typeof params.to === 'string' &&
|
|
658
|
+
params.to.toLowerCase() === ueaAddress.toLowerCase());
|
|
659
|
+
}
|
|
660
|
+
function isNativeSeedOnlyHop(hop) {
|
|
661
|
+
return (hop === null || hop === void 0 ? void 0 : hop.nativeSeedOnly) === true;
|
|
662
|
+
}
|
|
663
|
+
function isNativeSeedOnlySegment(segment) {
|
|
664
|
+
return (segment.type === 'INBOUND_FROM_CEA' &&
|
|
665
|
+
segment.hops.length > 0 &&
|
|
666
|
+
segment.hops.every((hop) => isNativeSeedOnlyHop(hop)));
|
|
667
|
+
}
|
|
668
|
+
function segmentNeedsOutboundGas(segment) {
|
|
669
|
+
return segment.type !== 'PUSH_EXECUTION' && !isNativeSeedOnlySegment(segment);
|
|
670
|
+
}
|
|
671
|
+
function buildRootOutboundIndexByHop(segments, hops) {
|
|
672
|
+
var _a;
|
|
673
|
+
const hopIndexByDescriptor = new Map();
|
|
674
|
+
hops.forEach((hop, index) => hopIndexByDescriptor.set(hop, index));
|
|
675
|
+
const nextIndexByChain = new Map();
|
|
676
|
+
const result = new Map();
|
|
677
|
+
for (const segment of segments) {
|
|
678
|
+
let chain;
|
|
679
|
+
if (segment.type === 'OUTBOUND_TO_CEA') {
|
|
680
|
+
chain = segment.targetChain;
|
|
681
|
+
}
|
|
682
|
+
else if (segment.type === 'INBOUND_FROM_CEA' &&
|
|
683
|
+
!isNativeSeedOnlySegment(segment)) {
|
|
684
|
+
chain = segment.sourceChain;
|
|
685
|
+
}
|
|
686
|
+
if (!chain)
|
|
687
|
+
continue;
|
|
688
|
+
const outboundIndex = (_a = nextIndexByChain.get(chain)) !== null && _a !== void 0 ? _a : 0;
|
|
689
|
+
for (const hop of segment.hops) {
|
|
690
|
+
const hopIndex = hopIndexByDescriptor.get(hop);
|
|
691
|
+
if (hopIndex !== undefined) {
|
|
692
|
+
result.set(hopIndex, outboundIndex);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
nextIndexByChain.set(chain, outboundIndex + 1);
|
|
696
|
+
}
|
|
697
|
+
return result;
|
|
698
|
+
}
|
|
699
|
+
function sumNativeSeedAmount(hops) {
|
|
700
|
+
return hops.reduce((sum, hop) => { var _a; return sum + ((_a = hop.nativeSeedAmount) !== null && _a !== void 0 ? _a : BigInt(0)); }, BigInt(0));
|
|
701
|
+
}
|
|
702
|
+
function getCascadeNativeSeed(segments) {
|
|
703
|
+
var _a, _b, _c;
|
|
704
|
+
let total = BigInt(0);
|
|
705
|
+
for (const segment of segments) {
|
|
706
|
+
for (const hop of segment.hops) {
|
|
707
|
+
const value = (_a = hop.params.value) !== null && _a !== void 0 ? _a : BigInt(0);
|
|
708
|
+
if (isNativeSeedOnlyHop(hop)) {
|
|
709
|
+
total += (_b = hop.nativeSeedAmount) !== null && _b !== void 0 ? _b : value;
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
// In a CEA->Push hop that also supplies `funds`, `value` is native PC
|
|
713
|
+
// forwarded inside the inbound UEA payload. That value is available to
|
|
714
|
+
// later Push-side cascade calls and must be counted for sizing fresh UEAs.
|
|
715
|
+
if (segment.type === 'INBOUND_FROM_CEA' &&
|
|
716
|
+
value > BigInt(0) &&
|
|
717
|
+
((_c = hop.params.funds) === null || _c === void 0 ? void 0 : _c.amount)) {
|
|
718
|
+
total += value;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
return total;
|
|
723
|
+
}
|
|
724
|
+
function getInboundFundingForBurnToken(segments, beforeSegmentIndex, burnToken, pushNetwork) {
|
|
725
|
+
var _a;
|
|
726
|
+
let total = BigInt(0);
|
|
727
|
+
const normalizedBurnToken = burnToken.toLowerCase();
|
|
728
|
+
for (const segment of segments.slice(0, beforeSegmentIndex)) {
|
|
729
|
+
if (segment.type !== 'INBOUND_FROM_CEA')
|
|
730
|
+
continue;
|
|
731
|
+
for (const hop of segment.hops) {
|
|
732
|
+
const params = hop.params;
|
|
733
|
+
let fundedToken;
|
|
734
|
+
let fundedAmount = BigInt(0);
|
|
735
|
+
if ((_a = params.funds) === null || _a === void 0 ? void 0 : _a.amount) {
|
|
736
|
+
const token = params.funds.token;
|
|
737
|
+
if (token) {
|
|
738
|
+
fundedToken = push_chain_1.PushChain.utils.tokens.getPRC20Address(token).address;
|
|
739
|
+
fundedAmount = params.funds.amount;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
else if (params.value &&
|
|
743
|
+
params.value > BigInt(0) &&
|
|
744
|
+
hop.sourceChain &&
|
|
745
|
+
!isNativeSeedOnlyHop(hop)) {
|
|
746
|
+
fundedToken = (0, helpers_1.getNativePRC20ForChain)(hop.sourceChain, pushNetwork);
|
|
747
|
+
fundedAmount = params.value;
|
|
748
|
+
}
|
|
749
|
+
if ((fundedToken === null || fundedToken === void 0 ? void 0 : fundedToken.toLowerCase()) === normalizedBurnToken) {
|
|
750
|
+
total += fundedAmount;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
return total;
|
|
755
|
+
}
|
|
756
|
+
function composeCascadeDetailed(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
566
757
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
567
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
758
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
|
|
568
759
|
let accumulatedPushMulticalls = [];
|
|
760
|
+
let requiredNativeValue = BigInt(0);
|
|
569
761
|
const gatewayPcAddress = (0, helpers_1.getUniversalGatewayPCAddress)();
|
|
762
|
+
const currentUeaBalance = ueaBalance !== null && ueaBalance !== void 0 ? ueaBalance : BigInt(0);
|
|
763
|
+
const cascadeNativeSeed = getCascadeNativeSeed(segments);
|
|
764
|
+
const effectiveUeaBalance = currentUeaBalance + cascadeNativeSeed;
|
|
765
|
+
if (cascadeNativeSeed > BigInt(0)) {
|
|
766
|
+
(0, context_1.printLog)(ctx, `composeCascade — counting cascade native seed ${cascadeNativeSeed.toString()} for cascade sizing (current UEA balance ${currentUeaBalance.toString()})`);
|
|
767
|
+
}
|
|
570
768
|
// Compute per-outbound nativeValueForGas from UEA balance
|
|
571
769
|
// Each outbound segment needs native value for the gas swap on the destination chain.
|
|
572
770
|
// The contract refunds excess, so over-allocating is safe.
|
|
573
|
-
const numOutbounds = segments.filter(
|
|
771
|
+
const numOutbounds = segments.filter(segmentNeedsOutboundGas).length;
|
|
574
772
|
const CASCADE_GAS_RESERVE = BigInt(3e18); // 3 PC reserve for gas costs
|
|
575
773
|
// Cascade pre-flight: catches the zero-balance silent-segment-zero failure
|
|
576
774
|
// mode. When `ueaBalance <= CASCADE_GAS_RESERVE`, `perOutboundNativeValue`
|
|
577
775
|
// is left undefined and downstream segments silently allocate value=0,
|
|
578
776
|
// producing under-funded swaps that revert inside Uniswap. Throw early
|
|
579
777
|
// with a structured error so the caller knows which path / hop failed.
|
|
580
|
-
// Honor the per-call opt-out from the first non-PUSH segment (segments share
|
|
581
|
-
// the same UniversalExecuteParams.options.allowUnderfundedSwap shape).
|
|
582
|
-
const firstOutboundSegment = segments.find((s) => s.type !== 'PUSH_EXECUTION');
|
|
583
|
-
const cascadeAllowUnderfunded = ((_d = (_c = (_b = (_a = firstOutboundSegment === null || firstOutboundSegment === void 0 ? void 0 : firstOutboundSegment.hops) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.params) === null || _c === void 0 ? void 0 : _c.options) === null || _d === void 0 ? void 0 : _d.allowUnderfundedSwap) ===
|
|
584
|
-
true;
|
|
585
778
|
if (numOutbounds > 0) {
|
|
586
779
|
(0, preflight_1.runPreflight)({
|
|
587
780
|
ctx,
|
|
588
781
|
ueaAddress,
|
|
589
|
-
ueaBalance:
|
|
782
|
+
ueaBalance: effectiveUeaBalance,
|
|
590
783
|
// Required = at least one wei of allocatable PC after reserve. The
|
|
591
784
|
// per-segment min-swap check below catches finer-grained shortfalls.
|
|
592
785
|
requiredValue: BigInt(1),
|
|
593
786
|
gasReserve: CASCADE_GAS_RESERVE,
|
|
594
787
|
pathTag: 'CASCADE',
|
|
595
|
-
allowUnderfundedSwap: cascadeAllowUnderfunded,
|
|
596
788
|
});
|
|
597
789
|
}
|
|
598
790
|
let perOutboundNativeValue;
|
|
599
|
-
if (
|
|
791
|
+
if (numOutbounds > 0 && effectiveUeaBalance > CASCADE_GAS_RESERVE) {
|
|
600
792
|
perOutboundNativeValue =
|
|
601
|
-
(
|
|
793
|
+
(effectiveUeaBalance - CASCADE_GAS_RESERVE) / BigInt(numOutbounds);
|
|
602
794
|
}
|
|
603
795
|
// Pool-price-based native-value override for SVM outbounds.
|
|
604
796
|
// The flat split above works for EVM gas tokens (pBNB/pETH — cheap per unit),
|
|
@@ -614,11 +806,11 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
614
806
|
s.gasFee > BigInt(0);
|
|
615
807
|
});
|
|
616
808
|
const svmNativeValueBySegment = new Map();
|
|
617
|
-
if (svmSegments.length > 0 &&
|
|
809
|
+
if (svmSegments.length > 0 && effectiveUeaBalance > CASCADE_GAS_RESERVE) {
|
|
618
810
|
const universalCoreAddress = yield ctx.pushClient.readContract({
|
|
619
811
|
address: gatewayPcAddress,
|
|
620
812
|
abi: abi_1.UNIVERSAL_GATEWAY_PC,
|
|
621
|
-
functionName: '
|
|
813
|
+
functionName: 'universalCore',
|
|
622
814
|
args: [],
|
|
623
815
|
});
|
|
624
816
|
// Compute per-SVM budget = ueaBalance − (PC needed for EVM outbounds) − 1 PC safety
|
|
@@ -629,11 +821,11 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
629
821
|
? perOutboundNativeValue * BigInt(numEvmOutbounds)
|
|
630
822
|
: BigInt(0);
|
|
631
823
|
const outerSafety = BigInt(1e18); // 1 PC for outer-tx gas
|
|
632
|
-
const svmTotal =
|
|
633
|
-
?
|
|
824
|
+
const svmTotal = effectiveUeaBalance > evmReservation + outerSafety
|
|
825
|
+
? effectiveUeaBalance - evmReservation - outerSafety
|
|
634
826
|
: BigInt(0);
|
|
635
827
|
const perSvmCap = svmTotal / BigInt(svmSegments.length);
|
|
636
|
-
const UNCAPPED_BALANCE = BigInt(
|
|
828
|
+
const UNCAPPED_BALANCE = BigInt('1000000000000000000000000000000'); // effectively disable estimator's internal cap
|
|
637
829
|
for (const seg of svmSegments) {
|
|
638
830
|
// Cascade-level segment index (position in `segments`, not in `svmSegments`)
|
|
639
831
|
// so the error's `segmentIndex` lines up with what the caller sees.
|
|
@@ -643,8 +835,13 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
643
835
|
(0, preflight_1.maybeFireSvmWarnThreshold)(ctx, estimated, seg.gasToken, 'CASCADE');
|
|
644
836
|
const flat = perOutboundNativeValue !== null && perOutboundNativeValue !== void 0 ? perOutboundNativeValue : BigInt(0);
|
|
645
837
|
let value = estimated > flat ? estimated : flat;
|
|
646
|
-
if (perSvmCap > BigInt(0) && value > perSvmCap)
|
|
647
|
-
|
|
838
|
+
if (perSvmCap > BigInt(0) && value > perSvmCap) {
|
|
839
|
+
const cappedValue = perSvmCap >= estimated ? perSvmCap : estimated;
|
|
840
|
+
if (cappedValue !== perSvmCap) {
|
|
841
|
+
(0, context_1.printLog)(ctx, `composeCascade — SVM outbound to ${(_a = seg.hops[0]) === null || _a === void 0 ? void 0 : _a.targetChain}: perSvmCap=${perSvmCap} is below live pool quote=${estimated}; using quote to avoid underfunded gas swap`);
|
|
842
|
+
}
|
|
843
|
+
value = cappedValue;
|
|
844
|
+
}
|
|
648
845
|
// Upward-allocation ceiling (mirrors R3 SVM Fix #4 in route-handlers.ts:1690).
|
|
649
846
|
// When UEA balance is huge, the flat split or perSvmCap can produce a value
|
|
650
847
|
// far above what the swap actually needs. Submitting that into a Uniswap
|
|
@@ -659,16 +856,16 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
659
856
|
? estimated * BigInt(5)
|
|
660
857
|
: UPWARD_BASE_CEILING_CASCADE_SVM;
|
|
661
858
|
if (value > upwardCeilingCascadeSvm) {
|
|
662
|
-
(0, context_1.printLog)(ctx, `composeCascade — SVM outbound to ${(
|
|
859
|
+
(0, context_1.printLog)(ctx, `composeCascade — SVM outbound to ${(_b = seg.hops[0]) === null || _b === void 0 ? void 0 : _b.targetChain}: capping value from ${value} to upwardCeiling=${upwardCeilingCascadeSvm} (pool quote=${estimated})`);
|
|
663
860
|
value = upwardCeilingCascadeSvm;
|
|
664
861
|
}
|
|
665
|
-
(0, context_1.printLog)(ctx, `composeCascade — SVM outbound to ${(
|
|
862
|
+
(0, context_1.printLog)(ctx, `composeCascade — SVM outbound to ${(_c = seg.hops[0]) === null || _c === void 0 ? void 0 : _c.targetChain}: gasFee=${seg.gasFee}, estimatedWpc=${estimated}, flat=${flat}, perSvmCap=${perSvmCap}, upwardCeiling=${upwardCeilingCascadeSvm}, chosen=${value}`);
|
|
666
863
|
// Per-segment minimum-viable-swap check: if the chosen `value` is below
|
|
667
864
|
// the live pool quote (`estimated`), the cap squeezed the budget below
|
|
668
865
|
// what the swap actually needs and the segment will revert inside
|
|
669
866
|
// Uniswap with STF. Throw cleanly with `segmentIndex` so the caller
|
|
670
867
|
// knows which hop's pool is misbehaving.
|
|
671
|
-
if (estimated > BigInt(0) && value < estimated
|
|
868
|
+
if (estimated > BigInt(0) && value < estimated) {
|
|
672
869
|
const shortfall = estimated - value;
|
|
673
870
|
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_04, estimated, value, shortfall, ueaAddress, 'CASCADE', { kind: 'NATIVE', segmentIndex: cascadeIdx });
|
|
674
871
|
throw new errors_1.InsufficientUEABalanceError({
|
|
@@ -689,6 +886,11 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
689
886
|
switch (segment.type) {
|
|
690
887
|
case 'PUSH_EXECUTION': {
|
|
691
888
|
// Prepend Push Chain multicalls to accumulated
|
|
889
|
+
const seedAmount = sumNativeSeedAmount(segment.hops);
|
|
890
|
+
if (seedAmount > requiredNativeValue) {
|
|
891
|
+
requiredNativeValue = seedAmount;
|
|
892
|
+
}
|
|
893
|
+
requiredNativeValue += sumMulticallNativeValue(segment.mergedPushMulticalls);
|
|
692
894
|
accumulatedPushMulticalls = [
|
|
693
895
|
...(segment.mergedPushMulticalls || []),
|
|
694
896
|
...accumulatedPushMulticalls,
|
|
@@ -703,7 +905,7 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
703
905
|
const isMigration = (firstHop === null || firstHop === void 0 ? void 0 : firstHop.isMigration) === true;
|
|
704
906
|
if (isSvmSegment) {
|
|
705
907
|
// SVM: use the pre-built SVM payload from the hop descriptor
|
|
706
|
-
outboundPayload = (
|
|
908
|
+
outboundPayload = (_d = firstHop.svmPayload) !== null && _d !== void 0 ? _d : '0x';
|
|
707
909
|
// For SVM, to.address IS the target (program for execute, recipient for withdraw)
|
|
708
910
|
const svmTarget = firstHop.params.to;
|
|
709
911
|
targetForOutbound = svmTarget.address;
|
|
@@ -717,7 +919,10 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
717
919
|
// EVM: build CEA payload from merged multicalls
|
|
718
920
|
outboundPayload = (0, payload_builders_1.buildCeaMulticallPayload)(segment.mergedCeaMulticalls || []);
|
|
719
921
|
// Get CEA address from the first hop
|
|
720
|
-
targetForOutbound =
|
|
922
|
+
targetForOutbound = outboundPayload === '0x'
|
|
923
|
+
? selectors_1.ZERO_ADDRESS
|
|
924
|
+
: (firstHop === null || firstHop === void 0 ? void 0 : firstHop.ceaAddress) || ueaAddress;
|
|
925
|
+
(0, payload_builders_1.assertCeaFundsParkingInvariant)(targetForOutbound, outboundPayload);
|
|
721
926
|
}
|
|
722
927
|
// Per-segment PRC-20 burn-balance pre-check (cascade R2-style segments
|
|
723
928
|
// only — INBOUND_FROM_CEA segments are payload-only with totalBurnAmount=0
|
|
@@ -736,12 +941,24 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
736
941
|
});
|
|
737
942
|
const sufficient = onHand >= segBurnAmount;
|
|
738
943
|
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_03, segBurnAmount, onHand, sufficient, ueaAddress, 'CASCADE', { kind: 'PRC20', burnToken: segBurnToken, segmentIndex: segIdxLoop });
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
(
|
|
944
|
+
const priorPushExecutionMayFundBurn = segments
|
|
945
|
+
.slice(0, segIdxLoop)
|
|
946
|
+
.some((s) => s.type === 'PUSH_EXECUTION');
|
|
947
|
+
const priorInboundFundingForBurn = getInboundFundingForBurnToken(segments, segIdxLoop, segBurnToken, ctx.pushNetwork);
|
|
948
|
+
const priorInboundMayFundBurn = onHand + priorInboundFundingForBurn >= segBurnAmount;
|
|
949
|
+
if (!sufficient &&
|
|
950
|
+
!priorPushExecutionMayFundBurn &&
|
|
951
|
+
!priorInboundMayFundBurn) {
|
|
952
|
+
const projectedOnHand = onHand + priorInboundFundingForBurn;
|
|
953
|
+
const shortfall = segBurnAmount - projectedOnHand;
|
|
954
|
+
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_04, segBurnAmount, projectedOnHand, shortfall, ueaAddress, 'CASCADE', {
|
|
955
|
+
kind: 'PRC20',
|
|
956
|
+
burnToken: segBurnToken,
|
|
957
|
+
segmentIndex: segIdxLoop,
|
|
958
|
+
});
|
|
742
959
|
throw new errors_1.InsufficientUEABalanceError({
|
|
743
960
|
required: segBurnAmount,
|
|
744
|
-
available:
|
|
961
|
+
available: projectedOnHand,
|
|
745
962
|
shortfall,
|
|
746
963
|
ueaAddress,
|
|
747
964
|
pathTag: 'CASCADE',
|
|
@@ -750,9 +967,15 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
750
967
|
segmentIndex: segIdxLoop,
|
|
751
968
|
});
|
|
752
969
|
}
|
|
970
|
+
else if (!sufficient && priorPushExecutionMayFundBurn) {
|
|
971
|
+
(0, context_1.printLog)(ctx, `composeCascade — skipping PRC-20 preflight failure for segment ${segIdxLoop}; earlier Push execution may fund ${segBurnToken} before this outbound runs`);
|
|
972
|
+
}
|
|
973
|
+
else if (!sufficient && priorInboundMayFundBurn) {
|
|
974
|
+
(0, context_1.printLog)(ctx, `composeCascade — skipping PRC-20 preflight failure for segment ${segIdxLoop}; earlier inbound funds ${priorInboundFundingForBurn.toString()} units of ${segBurnToken} before this outbound runs`);
|
|
975
|
+
}
|
|
753
976
|
}
|
|
754
977
|
// Build outbound request
|
|
755
|
-
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(targetForOutbound, segment.prc20Token || selectors_1.ZERO_ADDRESS, segment.totalBurnAmount || BigInt(0), (
|
|
978
|
+
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(targetForOutbound, segment.prc20Token || selectors_1.ZERO_ADDRESS, segment.totalBurnAmount || BigInt(0), (_e = segment.gasLimit) !== null && _e !== void 0 ? _e : BigInt(0), outboundPayload, ueaAddress, (_f = segment.maxPCForGas) !== null && _f !== void 0 ? _f : BigInt(0), (_g = segment.gasPrice) !== null && _g !== void 0 ? _g : BigInt(0));
|
|
756
979
|
// Build approval + outbound multicalls
|
|
757
980
|
const segGasFee = segment.gasFee || BigInt(0);
|
|
758
981
|
const svmOverride = svmNativeValueBySegment.get(segment);
|
|
@@ -762,13 +985,14 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
762
985
|
// across outbound segments. The contract refunds excess via
|
|
763
986
|
// swapAndBurnGas, so overshooting is safe; undershooting causes STF.
|
|
764
987
|
let evmFallbackValue;
|
|
765
|
-
if (
|
|
766
|
-
evmFallbackValue =
|
|
988
|
+
if (effectiveUeaBalance > BigInt(0)) {
|
|
989
|
+
evmFallbackValue =
|
|
990
|
+
effectiveUeaBalance / BigInt(Math.max(numOutbounds, 1));
|
|
767
991
|
}
|
|
768
992
|
else {
|
|
769
993
|
evmFallbackValue = segGasFee * BigInt(1000000);
|
|
770
994
|
}
|
|
771
|
-
let nativeValueForGas = (
|
|
995
|
+
let nativeValueForGas = (_h = svmOverride !== null && svmOverride !== void 0 ? svmOverride : perOutboundNativeValue) !== null && _h !== void 0 ? _h : evmFallbackValue;
|
|
772
996
|
// SDK 5.2 Case C: when the segment's sizing is category C, compose
|
|
773
997
|
// R2/OUTBOUND_TO_CEA segments no longer apply Case A/B/C sizing
|
|
774
998
|
// (scoped to R1 + R3 only). segment.sizing may still be populated
|
|
@@ -784,6 +1008,7 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
784
1008
|
gatewayPcAddress,
|
|
785
1009
|
outboundRequest: outboundReq,
|
|
786
1010
|
});
|
|
1011
|
+
requiredNativeValue += sumMulticallNativeValue(outboundMulticalls);
|
|
787
1012
|
// Prepend to accumulated
|
|
788
1013
|
accumulatedPushMulticalls = [
|
|
789
1014
|
...outboundMulticalls,
|
|
@@ -794,13 +1019,21 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
794
1019
|
case 'INBOUND_FROM_CEA': {
|
|
795
1020
|
// The accumulated multicalls = what runs on Push Chain AFTER inbound arrives.
|
|
796
1021
|
// Wrap in UniversalPayload struct with correct UEA nonce for the relay.
|
|
1022
|
+
if (isNativeSeedOnlySegment(segment)) {
|
|
1023
|
+
const seedAmount = sumNativeSeedAmount(segment.hops);
|
|
1024
|
+
if (seedAmount > requiredNativeValue) {
|
|
1025
|
+
requiredNativeValue = seedAmount;
|
|
1026
|
+
}
|
|
1027
|
+
(0, context_1.printLog)(ctx, `composeCascade — value-only CEA_TO_PUSH seed ${seedAmount.toString()} folded into root Push execution; no source-chain outbound needed`);
|
|
1028
|
+
break;
|
|
1029
|
+
}
|
|
797
1030
|
// Build push multicalls from EVERY merged hop's own data in original
|
|
798
1031
|
// order (e.g. counter.increment() + value transfer). Multi-hop R3
|
|
799
1032
|
// segments (same sourceChain) bundle all target ops into the single
|
|
800
1033
|
// UEA multicall so no nested outbound is needed.
|
|
801
1034
|
const mergedHopMulticalls = [];
|
|
802
1035
|
for (const h of segment.hops) {
|
|
803
|
-
if (((
|
|
1036
|
+
if (((_j = h === null || h === void 0 ? void 0 : h.params) === null || _j === void 0 ? void 0 : _j.data) || ((_k = h === null || h === void 0 ? void 0 : h.params) === null || _k === void 0 ? void 0 : _k.value)) {
|
|
804
1037
|
const hopCalls = (0, payload_builders_1.buildExecuteMulticall)({
|
|
805
1038
|
execute: {
|
|
806
1039
|
to: h.params.to,
|
|
@@ -813,6 +1046,7 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
813
1046
|
}
|
|
814
1047
|
}
|
|
815
1048
|
if (mergedHopMulticalls.length > 0) {
|
|
1049
|
+
requiredNativeValue += sumMulticallNativeValue(mergedHopMulticalls);
|
|
816
1050
|
accumulatedPushMulticalls = [
|
|
817
1051
|
...mergedHopMulticalls,
|
|
818
1052
|
...accumulatedPushMulticalls,
|
|
@@ -824,7 +1058,9 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
824
1058
|
if (accumulatedPushMulticalls.length > 0) {
|
|
825
1059
|
const multicallPayload = (0, payload_builder_1.buildMulticallPayloadData)(ctx, ueaAddress, accumulatedPushMulticalls);
|
|
826
1060
|
// +1: the outbound tx consumes one nonce via execute()
|
|
827
|
-
intermediatePayload = (0, payload_builders_1.buildInboundUniversalPayload)(multicallPayload, {
|
|
1061
|
+
intermediatePayload = (0, payload_builders_1.buildInboundUniversalPayload)(multicallPayload, {
|
|
1062
|
+
nonce: (ueaNonce !== null && ueaNonce !== void 0 ? ueaNonce : BigInt(0)) + BigInt(1),
|
|
1063
|
+
});
|
|
828
1064
|
}
|
|
829
1065
|
const hop = segment.hops[0];
|
|
830
1066
|
const sourceChain = hop.sourceChain;
|
|
@@ -841,7 +1077,7 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
841
1077
|
let drainAmount = BigInt(0);
|
|
842
1078
|
let tokenMintHex;
|
|
843
1079
|
const params = hop.params;
|
|
844
|
-
if (((
|
|
1080
|
+
if (((_l = params.funds) === null || _l === void 0 ? void 0 : _l.amount) && params.funds.amount > BigInt(0)) {
|
|
845
1081
|
drainAmount = params.funds.amount;
|
|
846
1082
|
const token = params.funds.token;
|
|
847
1083
|
if (token && token.address) {
|
|
@@ -870,11 +1106,12 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
870
1106
|
});
|
|
871
1107
|
const svmBurnAmount = segment.totalBurnAmount || BigInt(0);
|
|
872
1108
|
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(gatewayProgramHex, segment.prc20Token ||
|
|
873
|
-
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork), svmBurnAmount, (
|
|
1109
|
+
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork), svmBurnAmount, (_m = segment.gasLimit) !== null && _m !== void 0 ? _m : BigInt(0), svmPayload, ueaAddress, (_o = segment.maxPCForGas) !== null && _o !== void 0 ? _o : BigInt(0), (_p = segment.gasPrice) !== null && _p !== void 0 ? _p : BigInt(0));
|
|
874
1110
|
const inboundGasFee = segment.gasFee || BigInt(0);
|
|
875
1111
|
let svmInboundFallback;
|
|
876
|
-
if (
|
|
877
|
-
svmInboundFallback =
|
|
1112
|
+
if (effectiveUeaBalance > BigInt(0)) {
|
|
1113
|
+
svmInboundFallback =
|
|
1114
|
+
effectiveUeaBalance / BigInt(Math.max(numOutbounds, 1));
|
|
878
1115
|
}
|
|
879
1116
|
else {
|
|
880
1117
|
svmInboundFallback = inboundGasFee * BigInt(1000000);
|
|
@@ -883,7 +1120,7 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
883
1120
|
// SDK 5.2 R3-style Case C bump: when the inbound segment's sizing
|
|
884
1121
|
// is C, top up the swap budget by the overflow. No bridge-swap —
|
|
885
1122
|
// R3 has no destination funds delivery.
|
|
886
|
-
if (((
|
|
1123
|
+
if (((_q = segment.sizing) === null || _q === void 0 ? void 0 : _q.category) === 'C' &&
|
|
887
1124
|
segment.sizing.overflowNativePc > BigInt(0)) {
|
|
888
1125
|
const bumped = svmInboundNativeValue + segment.sizing.overflowNativePc;
|
|
889
1126
|
(0, context_1.printLog)(ctx, `composeCascade — INBOUND_FROM_CEA (SVM) Case C: bumping nativeValueForGas from ${svmInboundNativeValue} to ${bumped} (overflow=${segment.sizing.overflowNativePc})`);
|
|
@@ -899,10 +1136,12 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
899
1136
|
gatewayPcAddress,
|
|
900
1137
|
outboundRequest: outboundReq,
|
|
901
1138
|
});
|
|
1139
|
+
requiredNativeValue += sumMulticallNativeValue(outboundMulticalls);
|
|
902
1140
|
accumulatedPushMulticalls = [...outboundMulticalls];
|
|
903
1141
|
break;
|
|
904
1142
|
}
|
|
905
|
-
// EVM path: Build CEA multicall:
|
|
1143
|
+
// EVM path: Build CEA multicall: sendUniversalTxToUEA(payload).
|
|
1144
|
+
// CEA handles ERC20 gateway approval internally.
|
|
906
1145
|
const ceaMulticalls = [];
|
|
907
1146
|
// Add primary hop's own CEA operations if any
|
|
908
1147
|
// (e.g., approve + swap before bridging back)
|
|
@@ -918,7 +1157,7 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
918
1157
|
let amount = BigInt(0);
|
|
919
1158
|
for (const mergedHop of segment.hops) {
|
|
920
1159
|
const hParams = mergedHop.params;
|
|
921
|
-
if ((
|
|
1160
|
+
if ((_r = hParams.funds) === null || _r === void 0 ? void 0 : _r.amount) {
|
|
922
1161
|
const token = hParams.funds.token;
|
|
923
1162
|
if (token) {
|
|
924
1163
|
if (token.mechanism === 'native') {
|
|
@@ -932,32 +1171,6 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
932
1171
|
}
|
|
933
1172
|
tokenAddress = addr;
|
|
934
1173
|
amount += hParams.funds.amount;
|
|
935
|
-
// CEA approves gateway once with the cumulative allowance.
|
|
936
|
-
const gatewayAddr = chain_1.UNIVERSAL_GATEWAY_ADDRESSES[sourceChain];
|
|
937
|
-
if (!gatewayAddr) {
|
|
938
|
-
throw new Error(`No UniversalGateway address configured for chain ${sourceChain}`);
|
|
939
|
-
}
|
|
940
|
-
// Reset allowance to 0 first for USDT-style tokens
|
|
941
|
-
const approveZeroData = (0, viem_1.encodeFunctionData)({
|
|
942
|
-
abi: erc20_evm_1.ERC20_EVM,
|
|
943
|
-
functionName: 'approve',
|
|
944
|
-
args: [gatewayAddr, BigInt(0)],
|
|
945
|
-
});
|
|
946
|
-
ceaMulticalls.push({
|
|
947
|
-
to: tokenAddress,
|
|
948
|
-
value: BigInt(0),
|
|
949
|
-
data: approveZeroData,
|
|
950
|
-
});
|
|
951
|
-
const approveData = (0, viem_1.encodeFunctionData)({
|
|
952
|
-
abi: erc20_evm_1.ERC20_EVM,
|
|
953
|
-
functionName: 'approve',
|
|
954
|
-
args: [gatewayAddr, hParams.funds.amount],
|
|
955
|
-
});
|
|
956
|
-
ceaMulticalls.push({
|
|
957
|
-
to: tokenAddress,
|
|
958
|
-
value: BigInt(0),
|
|
959
|
-
data: approveData,
|
|
960
|
-
});
|
|
961
1174
|
}
|
|
962
1175
|
}
|
|
963
1176
|
}
|
|
@@ -965,7 +1178,8 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
965
1178
|
amount += hParams.value;
|
|
966
1179
|
}
|
|
967
1180
|
}
|
|
968
|
-
// Build sendUniversalTxToUEA self-call on CEA
|
|
1181
|
+
// Build sendUniversalTxToUEA self-call on CEA. CEA self-calls must
|
|
1182
|
+
// always use value=0; native funds are spent from the CEA balance.
|
|
969
1183
|
const sendCall = (0, payload_builders_1.buildSendUniversalTxToUEA)(ceaAddress, tokenAddress, amount, intermediatePayload, ceaAddress);
|
|
970
1184
|
ceaMulticalls.push(sendCall);
|
|
971
1185
|
// Wrap CEA multicall in outbound from Push Chain
|
|
@@ -974,17 +1188,17 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
974
1188
|
// gasLimit — UGPC.sendUniversalTxOutbound reverts with
|
|
975
1189
|
// "Missing or invalid parameters" on 0. When the hop didn't supply
|
|
976
1190
|
// one (typical for a pure-R3 leg composed inside a cascade), fall
|
|
977
|
-
// back to
|
|
978
|
-
// path does.
|
|
1191
|
+
// back to the EVM Route 3 default.
|
|
979
1192
|
const effectiveGasLimit = segment.gasLimit && segment.gasLimit > BigInt(0)
|
|
980
1193
|
? segment.gasLimit
|
|
981
|
-
: selectors_1.
|
|
1194
|
+
: selectors_1.DEFAULT_CEA_TO_PUSH_GAS_LIMIT;
|
|
982
1195
|
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(ceaAddress, segment.prc20Token ||
|
|
983
|
-
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork), segment.totalBurnAmount || BigInt(0), effectiveGasLimit, ceaPayload, ueaAddress);
|
|
1196
|
+
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork), segment.totalBurnAmount || BigInt(0), effectiveGasLimit, ceaPayload, ueaAddress, (_s = segment.maxPCForGas) !== null && _s !== void 0 ? _s : BigInt(0), (_t = segment.gasPrice) !== null && _t !== void 0 ? _t : BigInt(0));
|
|
984
1197
|
const inboundGasFee = segment.gasFee || BigInt(0);
|
|
985
1198
|
let evmInboundFallback;
|
|
986
|
-
if (
|
|
987
|
-
evmInboundFallback =
|
|
1199
|
+
if (effectiveUeaBalance > BigInt(0)) {
|
|
1200
|
+
evmInboundFallback =
|
|
1201
|
+
effectiveUeaBalance / BigInt(Math.max(numOutbounds, 1));
|
|
988
1202
|
}
|
|
989
1203
|
else {
|
|
990
1204
|
evmInboundFallback = inboundGasFee * BigInt(1000000);
|
|
@@ -993,7 +1207,7 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
993
1207
|
// SDK 5.2 R3-style Case C bump: when the inbound segment's sizing
|
|
994
1208
|
// is C, top up the swap budget by the overflow. No bridge-swap —
|
|
995
1209
|
// R3 has no destination funds delivery.
|
|
996
|
-
if (((
|
|
1210
|
+
if (((_u = segment.sizing) === null || _u === void 0 ? void 0 : _u.category) === 'C' &&
|
|
997
1211
|
segment.sizing.overflowNativePc > BigInt(0)) {
|
|
998
1212
|
const bumped = evmInboundNativeValue + segment.sizing.overflowNativePc;
|
|
999
1213
|
(0, context_1.printLog)(ctx, `composeCascade — INBOUND_FROM_CEA (EVM) Case C: bumping nativeValueForGas from ${evmInboundNativeValue} to ${bumped} (overflow=${segment.sizing.overflowNativePc})`);
|
|
@@ -1009,19 +1223,29 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
1009
1223
|
gatewayPcAddress,
|
|
1010
1224
|
outboundRequest: outboundReq,
|
|
1011
1225
|
});
|
|
1226
|
+
requiredNativeValue += sumMulticallNativeValue(outboundMulticalls);
|
|
1012
1227
|
// Reset accumulated -- everything is now inside this outbound
|
|
1013
1228
|
accumulatedPushMulticalls = [...outboundMulticalls];
|
|
1014
1229
|
break;
|
|
1015
1230
|
}
|
|
1016
1231
|
}
|
|
1017
1232
|
}
|
|
1018
|
-
return
|
|
1233
|
+
return {
|
|
1234
|
+
multicalls: accumulatedPushMulticalls,
|
|
1235
|
+
requiredNativeValue,
|
|
1236
|
+
};
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
1240
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
1241
|
+
const result = yield composeCascadeDetailed(ctx, segments, ueaAddress, ueaBalance, ueaNonce);
|
|
1242
|
+
return result.multicalls;
|
|
1019
1243
|
});
|
|
1020
1244
|
}
|
|
1021
1245
|
// ============================================================================
|
|
1022
1246
|
// createCascadedBuilder
|
|
1023
1247
|
// ============================================================================
|
|
1024
|
-
function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
1248
|
+
function createCascadedBuilder(ctx, preparedTxs, callbacks, defaultEventHook) {
|
|
1025
1249
|
return {
|
|
1026
1250
|
send: () => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
1027
1251
|
var _a;
|
|
@@ -1031,8 +1255,7 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1031
1255
|
// Classify into segments
|
|
1032
1256
|
const segments = classifyIntoSegments(hops);
|
|
1033
1257
|
// Check if this is a single-hop Route 1 (no composition needed)
|
|
1034
|
-
if (preparedTxs.length === 1 &&
|
|
1035
|
-
preparedTxs[0].route === 'UOA_TO_PUSH') {
|
|
1258
|
+
if (preparedTxs.length === 1 && preparedTxs[0].route === 'UOA_TO_PUSH') {
|
|
1036
1259
|
const response = yield callbacks.executeFn(hops[0].params);
|
|
1037
1260
|
const singleRoute1Result = {
|
|
1038
1261
|
initialTxHash: response.hash,
|
|
@@ -1066,8 +1289,7 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1066
1289
|
return singleRoute1Result;
|
|
1067
1290
|
}
|
|
1068
1291
|
// Check if single-hop Route 2 (just execute directly)
|
|
1069
|
-
if (preparedTxs.length === 1 &&
|
|
1070
|
-
preparedTxs[0].route === 'UOA_TO_CEA') {
|
|
1292
|
+
if (preparedTxs.length === 1 && preparedTxs[0].route === 'UOA_TO_CEA') {
|
|
1071
1293
|
const response = yield callbacks.executeFn(hops[0].params);
|
|
1072
1294
|
const targetChain = hops[0].targetChain || (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork);
|
|
1073
1295
|
const singleRoute2Result = {
|
|
@@ -1111,8 +1333,11 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1111
1333
|
? yield (0, uea_manager_1.getUEANonce)(ctx, ueaAddress)
|
|
1112
1334
|
: BigInt(0);
|
|
1113
1335
|
let composedMulticalls;
|
|
1336
|
+
let cascadeRequiredNativeValue = BigInt(0);
|
|
1114
1337
|
try {
|
|
1115
|
-
|
|
1338
|
+
const composed = yield composeCascadeDetailed(ctx, segments, ueaAddress, ueaBalance, ueaNonceCascade);
|
|
1339
|
+
composedMulticalls = composed.multicalls;
|
|
1340
|
+
cascadeRequiredNativeValue = composed.requiredNativeValue;
|
|
1116
1341
|
}
|
|
1117
1342
|
catch (err) {
|
|
1118
1343
|
// Pre-flight or per-segment min-swap failure inside composeCascade
|
|
@@ -1129,6 +1354,7 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1129
1354
|
// Execute the composed multicall as a single Push Chain tx
|
|
1130
1355
|
const executeParams = {
|
|
1131
1356
|
to: ueaAddress,
|
|
1357
|
+
value: cascadeRequiredNativeValue,
|
|
1132
1358
|
data: composedMulticalls,
|
|
1133
1359
|
};
|
|
1134
1360
|
const response = yield callbacks.executeFn(executeParams);
|
|
@@ -1136,7 +1362,9 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1136
1362
|
const hopInfos = hops.map((hop, index) => ({
|
|
1137
1363
|
hopIndex: index,
|
|
1138
1364
|
route: hop.route,
|
|
1139
|
-
executionChain: hop.targetChain ||
|
|
1365
|
+
executionChain: hop.targetChain ||
|
|
1366
|
+
hop.sourceChain ||
|
|
1367
|
+
(0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork),
|
|
1140
1368
|
status: 'pending',
|
|
1141
1369
|
}));
|
|
1142
1370
|
// Mark first hop as submitted
|
|
@@ -1150,8 +1378,8 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1150
1378
|
hops: hopInfos,
|
|
1151
1379
|
hopCount: hops.length,
|
|
1152
1380
|
waitForAll: (opts) => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
1153
|
-
var _a, _b, _c, _d, _e;
|
|
1154
|
-
const { pollingIntervalMs = 10000, timeout = 300000, progressHook: cascadeProgressHook, eventHook, } = opts || {};
|
|
1381
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1382
|
+
const { pollingIntervalMs = 10000, timeout = 300000, progressHook: cascadeProgressHook, eventHook = defaultEventHook, } = opts || {};
|
|
1155
1383
|
const startTime = Date.now();
|
|
1156
1384
|
// Per-hop progress emission. Fans out cascade markers to BOTH the
|
|
1157
1385
|
// explicit `eventHook` (passed into waitForAll) AND the init-time
|
|
@@ -1180,9 +1408,7 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1180
1408
|
if (!isMulti)
|
|
1181
1409
|
return;
|
|
1182
1410
|
const n = hopIndex0 + 1;
|
|
1183
|
-
const fromChain = hopIndex0 === 0
|
|
1184
|
-
? signerOriginChain
|
|
1185
|
-
: chainLabels[hopIndex0 - 1];
|
|
1411
|
+
const fromChain = hopIndex0 === 0 ? signerOriginChain : chainLabels[hopIndex0 - 1];
|
|
1186
1412
|
const toChain = chainLabels[hopIndex0];
|
|
1187
1413
|
emitHopEvent(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_002_01](n, totalHops, fromChain, toChain));
|
|
1188
1414
|
};
|
|
@@ -1229,49 +1455,14 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1229
1455
|
elapsed: Date.now() - startTime,
|
|
1230
1456
|
});
|
|
1231
1457
|
yield response.wait();
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
route: hop.route,
|
|
1240
|
-
chain: (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork),
|
|
1241
|
-
status: 'confirmed',
|
|
1242
|
-
txHash: response.hash,
|
|
1243
|
-
elapsed: Date.now() - startTime,
|
|
1244
|
-
});
|
|
1245
|
-
emitHopComplete(hop.hopIndex);
|
|
1246
|
-
}
|
|
1247
|
-
}
|
|
1248
|
-
// 2. Track outbound hops (Route 2: UOA_TO_CEA)
|
|
1249
|
-
// Hops after a CEA_TO_PUSH are "child outbounds" — they execute inside
|
|
1250
|
-
// the inbound payload on Push Chain and live under a DIFFERENT utx_id
|
|
1251
|
-
// (the inbound UTX, not the parent). We can't track them via the parent
|
|
1252
|
-
// utx_id polling, so we auto-confirm them.
|
|
1253
|
-
const ceaToPushIndex = hopInfos.findIndex((h) => h.route === 'CEA_TO_PUSH');
|
|
1254
|
-
const outboundHops = hopInfos.filter((h, i) => {
|
|
1255
|
-
if (h.route !== 'UOA_TO_CEA')
|
|
1256
|
-
return false;
|
|
1257
|
-
// Child outbounds (after CEA_TO_PUSH) live under the inbound UTX,
|
|
1258
|
-
// not the parent — auto-confirm since we can't poll them here.
|
|
1259
|
-
if (ceaToPushIndex >= 0 && i > ceaToPushIndex) {
|
|
1260
|
-
h.status = 'confirmed';
|
|
1261
|
-
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
1262
|
-
hopIndex: h.hopIndex,
|
|
1263
|
-
route: h.route,
|
|
1264
|
-
chain: h.executionChain,
|
|
1265
|
-
status: 'confirmed',
|
|
1266
|
-
elapsed: Date.now() - startTime,
|
|
1267
|
-
});
|
|
1268
|
-
return false;
|
|
1269
|
-
}
|
|
1270
|
-
return true;
|
|
1271
|
-
});
|
|
1272
|
-
if (outboundHops.length > 0) {
|
|
1458
|
+
const ceaToPushIndex = hopInfos.findIndex((h, index) => h.route === 'CEA_TO_PUSH' && !isNativeSeedOnlyHop(hops[index]));
|
|
1459
|
+
const isAfterCeaToPush = (index) => ceaToPushIndex >= 0 && index > ceaToPushIndex;
|
|
1460
|
+
const rootOutboundIndexByHop = buildRootOutboundIndexByHop(segments, hops);
|
|
1461
|
+
const trackOutboundHops = (outboundHops, pushTxHash, resolvedSubTxId, outboundIndexByHop) => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
1462
|
+
var _a, _b, _c, _d;
|
|
1463
|
+
if (outboundHops.length === 0)
|
|
1464
|
+
return null;
|
|
1273
1465
|
if (outboundHops.length === 1) {
|
|
1274
|
-
// Single direct outbound hop: use the existing V1-based tracking
|
|
1275
1466
|
const hop = outboundHops[0];
|
|
1276
1467
|
const hopHooks = (0, progress_route_hooks_1.pickWaitHooks)(hop.route);
|
|
1277
1468
|
const remainingTimeout = timeout - (Date.now() - startTime);
|
|
@@ -1303,11 +1494,11 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1303
1494
|
});
|
|
1304
1495
|
let lastEmittedStatus;
|
|
1305
1496
|
try {
|
|
1306
|
-
const outboundDetails = yield callbacks.waitForOutboundTxFn(
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
progressHook: (event) => {
|
|
1497
|
+
const outboundDetails = yield callbacks.waitForOutboundTxFn(pushTxHash, Object.assign(Object.assign({ initialWaitMs: Math.min(60000, remainingTimeout), pollingIntervalMs, timeout: remainingTimeout, _resolvedSubTxId: resolvedSubTxId, _expectedDestinationChain: hop.executionChain }, (outboundIndexByHop
|
|
1498
|
+
? {
|
|
1499
|
+
_outboundIndex: (_a = outboundIndexByHop.get(hop.hopIndex)) !== null && _a !== void 0 ? _a : 0,
|
|
1500
|
+
}
|
|
1501
|
+
: {})), { progressHook: (event) => {
|
|
1311
1502
|
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
1312
1503
|
hopIndex: hop.hopIndex,
|
|
1313
1504
|
route: hop.route,
|
|
@@ -1320,19 +1511,25 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1320
1511
|
lastEmittedStatus = 'polling';
|
|
1321
1512
|
emitHopEvent(hopHooks.polling(hop.executionChain, event.elapsed));
|
|
1322
1513
|
}
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1514
|
+
} }));
|
|
1515
|
+
// `outboundDetails.externalTxHash` from waitForOutboundTx
|
|
1516
|
+
// is the raw `0x`-hex form (internal canonical). For the
|
|
1517
|
+
// user-facing `hop.txHash`, `hop.outboundDetails`, and
|
|
1518
|
+
// cascade progress event, normalize to base58 for SVM so
|
|
1519
|
+
// consumers can paste it straight into a Solana explorer.
|
|
1520
|
+
const displayTxHash = (_b = (0, helpers_1.toExternalTxHashDisplay)(outboundDetails.destinationChain, outboundDetails.externalTxHash)) !== null && _b !== void 0 ? _b : outboundDetails.externalTxHash;
|
|
1521
|
+
const userFacingOutboundDetails = Object.assign(Object.assign({}, outboundDetails), { externalTxHash: displayTxHash });
|
|
1325
1522
|
hop.status = 'confirmed';
|
|
1326
|
-
hop.txHash =
|
|
1327
|
-
hop.outboundDetails =
|
|
1328
|
-
emitHopEvent(hopHooks.success(
|
|
1523
|
+
hop.txHash = displayTxHash;
|
|
1524
|
+
hop.outboundDetails = userFacingOutboundDetails;
|
|
1525
|
+
emitHopEvent(hopHooks.success(userFacingOutboundDetails));
|
|
1329
1526
|
emitHopComplete(hop.hopIndex);
|
|
1330
1527
|
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
1331
1528
|
hopIndex: hop.hopIndex,
|
|
1332
1529
|
route: hop.route,
|
|
1333
1530
|
chain: hop.executionChain,
|
|
1334
1531
|
status: 'confirmed',
|
|
1335
|
-
txHash:
|
|
1532
|
+
txHash: displayTxHash,
|
|
1336
1533
|
elapsed: Date.now() - startTime,
|
|
1337
1534
|
});
|
|
1338
1535
|
}
|
|
@@ -1364,19 +1561,17 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1364
1561
|
}
|
|
1365
1562
|
}
|
|
1366
1563
|
else {
|
|
1367
|
-
// Multiple outbound hops: use V2 API which returns outboundTx[]
|
|
1368
|
-
// Emit "Awaiting External Chain" once per outbound hop before
|
|
1369
|
-
// polling begins, using the route-specific awaiting hook.
|
|
1370
1564
|
for (const outHop of outboundHops) {
|
|
1371
1565
|
emitHopStart(outHop.hopIndex);
|
|
1372
1566
|
emitHopEvent((0, progress_route_hooks_1.pickWaitHooks)(outHop.route).awaiting(outHop.executionChain));
|
|
1373
1567
|
}
|
|
1374
1568
|
const perHopLastStatus = new Map();
|
|
1375
1569
|
const confirmedHops = new Set();
|
|
1376
|
-
const allOutboundDetails = yield callbacks.waitForAllOutboundTxsFn(
|
|
1570
|
+
const allOutboundDetails = yield callbacks.waitForAllOutboundTxsFn(pushTxHash, outboundHops, {
|
|
1377
1571
|
initialWaitMs: Math.min(60000, timeout - (Date.now() - startTime)),
|
|
1378
1572
|
pollingIntervalMs,
|
|
1379
1573
|
timeout: timeout - (Date.now() - startTime),
|
|
1574
|
+
_resolvedSubTxId: resolvedSubTxId,
|
|
1380
1575
|
progressHook: (event) => {
|
|
1381
1576
|
var _a, _b;
|
|
1382
1577
|
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
@@ -1390,8 +1585,7 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1390
1585
|
const matchedHop = outboundHops.find((h) => h.hopIndex === event.hopIndex);
|
|
1391
1586
|
const eventHooks = (0, progress_route_hooks_1.pickWaitHooks)(matchedHop === null || matchedHop === void 0 ? void 0 : matchedHop.route);
|
|
1392
1587
|
const prev = perHopLastStatus.get(event.hopIndex);
|
|
1393
|
-
if (event.status === 'polling' &&
|
|
1394
|
-
prev !== 'polling') {
|
|
1588
|
+
if (event.status === 'polling' && prev !== 'polling') {
|
|
1395
1589
|
perHopLastStatus.set(event.hopIndex, 'polling');
|
|
1396
1590
|
emitHopEvent(eventHooks.polling((_b = (_a = matchedHop === null || matchedHop === void 0 ? void 0 : matchedHop.executionChain) !== null && _a !== void 0 ? _a : event.chain) !== null && _b !== void 0 ? _b : '', Date.now() - startTime));
|
|
1397
1591
|
}
|
|
@@ -1412,12 +1606,12 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1412
1606
|
},
|
|
1413
1607
|
});
|
|
1414
1608
|
if (!allOutboundDetails.success) {
|
|
1415
|
-
const failedIdx = (
|
|
1609
|
+
const failedIdx = (_c = allOutboundDetails.failedAt) !== null && _c !== void 0 ? _c : 0;
|
|
1416
1610
|
const failedHop = outboundHops.find((h) => h.hopIndex === failedIdx);
|
|
1417
1611
|
const failMsg = failedHop
|
|
1418
1612
|
? `Outbound failed for hop ${failedIdx} on ${failedHop.executionChain}`
|
|
1419
1613
|
: `Outbound cascade failed at hop ${failedIdx}`;
|
|
1420
|
-
emitHopEvent((0, progress_route_hooks_1.pickWaitHooks)(failedHop === null || failedHop === void 0 ? void 0 : failedHop.route).failed((
|
|
1614
|
+
emitHopEvent((0, progress_route_hooks_1.pickWaitHooks)(failedHop === null || failedHop === void 0 ? void 0 : failedHop.route).failed((_d = failedHop === null || failedHop === void 0 ? void 0 : failedHop.executionChain) !== null && _d !== void 0 ? _d : '', failMsg));
|
|
1421
1615
|
emitCascadeFailed(failedIdx, failMsg);
|
|
1422
1616
|
return {
|
|
1423
1617
|
success: false,
|
|
@@ -1426,23 +1620,230 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
1426
1620
|
};
|
|
1427
1621
|
}
|
|
1428
1622
|
}
|
|
1623
|
+
return null;
|
|
1624
|
+
});
|
|
1625
|
+
// Mark only root Push Chain (Route 1) hops as confirmed. Route 1
|
|
1626
|
+
// hops after a Route 3 leg execute in the child inbound Push tx and
|
|
1627
|
+
// must wait for that child UTX to reach terminal success.
|
|
1628
|
+
for (const hop of hopInfos) {
|
|
1629
|
+
if (hop.route === 'CEA_TO_PUSH' &&
|
|
1630
|
+
isNativeSeedOnlyHop(hops[hop.hopIndex])) {
|
|
1631
|
+
emitHopStart(hop.hopIndex);
|
|
1632
|
+
hop.status = 'confirmed';
|
|
1633
|
+
hop.txHash = response.hash;
|
|
1634
|
+
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
1635
|
+
hopIndex: hop.hopIndex,
|
|
1636
|
+
route: hop.route,
|
|
1637
|
+
chain: (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork),
|
|
1638
|
+
status: 'confirmed',
|
|
1639
|
+
txHash: response.hash,
|
|
1640
|
+
elapsed: Date.now() - startTime,
|
|
1641
|
+
});
|
|
1642
|
+
emitHopComplete(hop.hopIndex);
|
|
1643
|
+
}
|
|
1429
1644
|
}
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1645
|
+
for (const hop of hopInfos) {
|
|
1646
|
+
if (hop.route === 'UOA_TO_PUSH' && !isAfterCeaToPush(hop.hopIndex)) {
|
|
1647
|
+
hop.status = 'confirmed';
|
|
1648
|
+
hop.txHash = response.hash;
|
|
1649
|
+
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
1650
|
+
hopIndex: hop.hopIndex,
|
|
1651
|
+
route: hop.route,
|
|
1652
|
+
chain: (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork),
|
|
1653
|
+
status: 'confirmed',
|
|
1654
|
+
txHash: response.hash,
|
|
1655
|
+
elapsed: Date.now() - startTime,
|
|
1656
|
+
});
|
|
1657
|
+
emitHopComplete(hop.hopIndex);
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
// 2. Track direct outbound hops (Route 2: UOA_TO_CEA) that belong
|
|
1661
|
+
// to the root Push UTX.
|
|
1662
|
+
const rootOutboundHops = hopInfos.filter((h) => h.route === 'UOA_TO_CEA' && !isAfterCeaToPush(h.hopIndex));
|
|
1663
|
+
const rootOutboundFailure = yield trackOutboundHops(rootOutboundHops, response.hash, undefined, rootOutboundIndexByHop);
|
|
1664
|
+
if (rootOutboundFailure)
|
|
1665
|
+
return rootOutboundFailure;
|
|
1666
|
+
let childInbound;
|
|
1667
|
+
if (ceaToPushIndex >= 0) {
|
|
1668
|
+
const inboundHop = hopInfos[ceaToPushIndex];
|
|
1669
|
+
const hopHooks = (0, progress_route_hooks_1.pickWaitHooks)(inboundHop.route);
|
|
1670
|
+
const remainingTimeout = timeout - (Date.now() - startTime);
|
|
1671
|
+
if (remainingTimeout <= 0) {
|
|
1672
|
+
inboundHop.status = 'failed';
|
|
1673
|
+
emitHopEvent(hopHooks.timeout(inboundHop.executionChain, Date.now() - startTime));
|
|
1674
|
+
emitCascadeTimeout(inboundHop.hopIndex);
|
|
1675
|
+
return {
|
|
1676
|
+
success: false,
|
|
1677
|
+
hops: hopInfos,
|
|
1678
|
+
failedAt: inboundHop.hopIndex,
|
|
1679
|
+
};
|
|
1680
|
+
}
|
|
1437
1681
|
emitHopStart(inboundHop.hopIndex);
|
|
1682
|
+
emitHopEvent(hopHooks.awaiting(inboundHop.executionChain));
|
|
1683
|
+
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
1684
|
+
hopIndex: inboundHop.hopIndex,
|
|
1685
|
+
route: inboundHop.route,
|
|
1686
|
+
chain: inboundHop.executionChain,
|
|
1687
|
+
status: 'polling',
|
|
1688
|
+
elapsed: Date.now() - startTime,
|
|
1689
|
+
});
|
|
1690
|
+
let outboundLastStatus;
|
|
1691
|
+
let sourceOutboundDetails;
|
|
1692
|
+
try {
|
|
1693
|
+
sourceOutboundDetails = yield callbacks.waitForOutboundTxFn(response.hash, {
|
|
1694
|
+
initialWaitMs: Math.min(60000, remainingTimeout),
|
|
1695
|
+
pollingIntervalMs,
|
|
1696
|
+
timeout: remainingTimeout,
|
|
1697
|
+
_expectedDestinationChain: inboundHop.executionChain,
|
|
1698
|
+
_outboundIndex: (_d = rootOutboundIndexByHop.get(inboundHop.hopIndex)) !== null && _d !== void 0 ? _d : 0,
|
|
1699
|
+
progressHook: (event) => {
|
|
1700
|
+
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
1701
|
+
hopIndex: inboundHop.hopIndex,
|
|
1702
|
+
route: inboundHop.route,
|
|
1703
|
+
chain: inboundHop.executionChain,
|
|
1704
|
+
status: event.status,
|
|
1705
|
+
elapsed: Date.now() - startTime,
|
|
1706
|
+
});
|
|
1707
|
+
if (event.status === 'polling' &&
|
|
1708
|
+
outboundLastStatus !== 'polling') {
|
|
1709
|
+
outboundLastStatus = 'polling';
|
|
1710
|
+
emitHopEvent(hopHooks.polling(inboundHop.executionChain, event.elapsed));
|
|
1711
|
+
}
|
|
1712
|
+
},
|
|
1713
|
+
});
|
|
1714
|
+
}
|
|
1715
|
+
catch (err) {
|
|
1716
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1717
|
+
const isTimeout = errMsg.startsWith('Timeout waiting for outbound transaction');
|
|
1718
|
+
emitHopEvent(isTimeout
|
|
1719
|
+
? hopHooks.timeout(inboundHop.executionChain, remainingTimeout)
|
|
1720
|
+
: hopHooks.failed(inboundHop.executionChain, errMsg));
|
|
1721
|
+
if (isTimeout)
|
|
1722
|
+
emitCascadeTimeout(inboundHop.hopIndex);
|
|
1723
|
+
else
|
|
1724
|
+
emitCascadeFailed(inboundHop.hopIndex, errMsg);
|
|
1725
|
+
inboundHop.status = 'failed';
|
|
1726
|
+
const failedExternalTxHash = err === null || err === void 0 ? void 0 : err.externalTxHash;
|
|
1727
|
+
const failedDisplayTxHash = (_e = (0, helpers_1.toExternalTxHashDisplay)(inboundHop.executionChain, failedExternalTxHash)) !== null && _e !== void 0 ? _e : failedExternalTxHash;
|
|
1728
|
+
if (failedDisplayTxHash)
|
|
1729
|
+
inboundHop.txHash = failedDisplayTxHash;
|
|
1730
|
+
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
1731
|
+
hopIndex: inboundHop.hopIndex,
|
|
1732
|
+
route: inboundHop.route,
|
|
1733
|
+
chain: inboundHop.executionChain,
|
|
1734
|
+
status: 'failed',
|
|
1735
|
+
txHash: failedDisplayTxHash,
|
|
1736
|
+
elapsed: Date.now() - startTime,
|
|
1737
|
+
});
|
|
1738
|
+
return {
|
|
1739
|
+
success: false,
|
|
1740
|
+
hops: hopInfos,
|
|
1741
|
+
failedAt: inboundHop.hopIndex,
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
const displayExternalTxHash = (_f = (0, helpers_1.toExternalTxHashDisplay)(sourceOutboundDetails.destinationChain, sourceOutboundDetails.externalTxHash)) !== null && _f !== void 0 ? _f : sourceOutboundDetails.externalTxHash;
|
|
1745
|
+
inboundHop.outboundDetails = Object.assign(Object.assign({}, sourceOutboundDetails), { externalTxHash: displayExternalTxHash });
|
|
1746
|
+
inboundHop.txHash = displayExternalTxHash;
|
|
1747
|
+
emitHopEvent(hopHooks.success(inboundHop.outboundDetails));
|
|
1748
|
+
emitHopEvent(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_310_01](inboundHop.executionChain));
|
|
1749
|
+
let inboundLastStatus;
|
|
1750
|
+
const inboundRemainingTimeout = timeout - (Date.now() - startTime);
|
|
1751
|
+
try {
|
|
1752
|
+
childInbound = yield ((_g = callbacks.waitForInboundPushTxFn) !== null && _g !== void 0 ? _g : ((externalTxHash, sourceChain, opts) => (0, inbound_tracker_1.waitForInboundPushTx)(ctx, externalTxHash, sourceChain, opts)))(sourceOutboundDetails.externalTxHash, inboundHop.executionChain, {
|
|
1753
|
+
initialWaitMs: Math.min(60000, inboundRemainingTimeout),
|
|
1754
|
+
pollingIntervalMs,
|
|
1755
|
+
timeout: inboundRemainingTimeout,
|
|
1756
|
+
progressHook: (event) => {
|
|
1757
|
+
if (event.status === 'polling' &&
|
|
1758
|
+
inboundLastStatus !== 'polling') {
|
|
1759
|
+
inboundLastStatus = 'polling';
|
|
1760
|
+
emitHopEvent(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_310_02](inboundHop.executionChain, event.elapsedMs));
|
|
1761
|
+
}
|
|
1762
|
+
},
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
catch (err) {
|
|
1766
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1767
|
+
const isTimeout = err instanceof inbound_tracker_1.InboundTimeoutError;
|
|
1768
|
+
emitHopEvent(isTimeout
|
|
1769
|
+
? progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_03](inboundHop.executionChain, inboundRemainingTimeout, 'inbound')
|
|
1770
|
+
: progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](errMsg, 'inbound', inboundHop.executionChain));
|
|
1771
|
+
if (isTimeout)
|
|
1772
|
+
emitCascadeTimeout(inboundHop.hopIndex);
|
|
1773
|
+
else
|
|
1774
|
+
emitCascadeFailed(inboundHop.hopIndex, errMsg);
|
|
1775
|
+
inboundHop.status = 'failed';
|
|
1776
|
+
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
1777
|
+
hopIndex: inboundHop.hopIndex,
|
|
1778
|
+
route: inboundHop.route,
|
|
1779
|
+
chain: inboundHop.executionChain,
|
|
1780
|
+
status: 'failed',
|
|
1781
|
+
elapsed: Date.now() - startTime,
|
|
1782
|
+
});
|
|
1783
|
+
return {
|
|
1784
|
+
success: false,
|
|
1785
|
+
hops: hopInfos,
|
|
1786
|
+
failedAt: inboundHop.hopIndex,
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
if (childInbound.status !== 'confirmed') {
|
|
1790
|
+
const failMsg = (_h = childInbound.errorMessage) !== null && _h !== void 0 ? _h : 'inbound execution failed on Push Chain';
|
|
1791
|
+
inboundHop.status = 'failed';
|
|
1792
|
+
inboundHop.txHash =
|
|
1793
|
+
childInbound.pushTxHash || displayExternalTxHash;
|
|
1794
|
+
emitHopEvent(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](failMsg, 'inbound', inboundHop.executionChain));
|
|
1795
|
+
emitCascadeFailed(inboundHop.hopIndex, failMsg);
|
|
1796
|
+
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
1797
|
+
hopIndex: inboundHop.hopIndex,
|
|
1798
|
+
route: inboundHop.route,
|
|
1799
|
+
chain: inboundHop.executionChain,
|
|
1800
|
+
status: 'failed',
|
|
1801
|
+
txHash: inboundHop.txHash,
|
|
1802
|
+
elapsed: Date.now() - startTime,
|
|
1803
|
+
});
|
|
1804
|
+
return {
|
|
1805
|
+
success: false,
|
|
1806
|
+
hops: hopInfos,
|
|
1807
|
+
failedAt: inboundHop.hopIndex,
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1810
|
+
inboundHop.status = 'confirmed';
|
|
1811
|
+
inboundHop.txHash =
|
|
1812
|
+
childInbound.pushTxHash || displayExternalTxHash;
|
|
1813
|
+
emitHopEvent(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_01](inboundHop.executionChain, childInbound.pushTxHash));
|
|
1814
|
+
emitHopComplete(inboundHop.hopIndex);
|
|
1438
1815
|
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
1439
1816
|
hopIndex: inboundHop.hopIndex,
|
|
1440
1817
|
route: inboundHop.route,
|
|
1441
1818
|
chain: inboundHop.executionChain,
|
|
1442
|
-
status: '
|
|
1819
|
+
status: 'confirmed',
|
|
1820
|
+
txHash: inboundHop.txHash,
|
|
1443
1821
|
elapsed: Date.now() - startTime,
|
|
1444
1822
|
});
|
|
1445
1823
|
}
|
|
1824
|
+
if (childInbound) {
|
|
1825
|
+
for (const hop of hopInfos) {
|
|
1826
|
+
if (hop.route === 'UOA_TO_PUSH' &&
|
|
1827
|
+
isAfterCeaToPush(hop.hopIndex)) {
|
|
1828
|
+
emitHopStart(hop.hopIndex);
|
|
1829
|
+
hop.status = 'confirmed';
|
|
1830
|
+
hop.txHash = childInbound.pushTxHash;
|
|
1831
|
+
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
1832
|
+
hopIndex: hop.hopIndex,
|
|
1833
|
+
route: hop.route,
|
|
1834
|
+
chain: (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork),
|
|
1835
|
+
status: 'confirmed',
|
|
1836
|
+
txHash: childInbound.pushTxHash,
|
|
1837
|
+
elapsed: Date.now() - startTime,
|
|
1838
|
+
});
|
|
1839
|
+
emitHopComplete(hop.hopIndex);
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
const childOutboundHops = hopInfos.filter((h) => h.route === 'UOA_TO_CEA' && isAfterCeaToPush(h.hopIndex));
|
|
1843
|
+
const childOutboundFailure = yield trackOutboundHops(childOutboundHops, childInbound.pushTxHash || response.hash, childInbound.childUtxId);
|
|
1844
|
+
if (childOutboundFailure)
|
|
1845
|
+
return childOutboundFailure;
|
|
1846
|
+
}
|
|
1446
1847
|
emitCascadeSuccess();
|
|
1447
1848
|
return { success: true, hops: hopInfos };
|
|
1448
1849
|
}
|