@pushchain/core 6.0.3 → 6.0.5

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.
@@ -29,30 +29,14 @@ const inbound_tracker_1 = require("./inbound-tracker");
29
29
  const tx_transformer_1 = require("./tx-transformer");
30
30
  const progress_route_hooks_1 = require("./progress-route-hooks");
31
31
  const outbound_sync_1 = require("./outbound-sync");
32
- /**
33
- * Intermediate Push-success markers (199-99-99 for R3, 299-99 for R2) are
34
- * internal transition signals — they tell response-builder's wait-phase
35
- * branch that the Push leg has settled so it can skip re-emitting the
36
- * intermediate marker on top of a reconstructed stream. They are not part
37
- * of the published 1XX/2XX/3XX/4XX spec and are suppressed at the consumer
38
- * dispatch boundary. `printLog` still fires for these so internal traces
39
- * retain the transition record.
40
- */
41
- const INTERMEDIATE_INTERNAL_IDS = new Set([
42
- progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_99_99,
43
- progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_99,
44
- ]);
45
32
  /**
46
33
  * Fan out a progress event to one or two registered callbacks, deduping
47
34
  * when both slots hold the same reference. Keeps the emission policy in a
48
35
  * single place shared by `emitProgress` (execute phase) and `emit` (wait
49
36
  * phase) — so consumers that wire the same callback at multiple levels
50
- * never see double-invocation. Intermediate internal markers are dropped
51
- * here so they never reach the consumer.
37
+ * never see double-invocation.
52
38
  */
53
39
  function fanOut(event, primary, secondary) {
54
- if (INTERMEDIATE_INTERNAL_IDS.has(event.id))
55
- return;
56
40
  if (primary)
57
41
  primary(event);
58
42
  if (secondary && secondary !== primary)
@@ -549,13 +533,6 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
549
533
  const inboundInitialWaitMs = isReplay
550
534
  ? 0
551
535
  : callbacks.inboundConstants.initialWaitMs;
552
- // Track whether reconstruction already emitted the route's
553
- // intermediate Push-success marker (299-99 / 199-99-99). When it has,
554
- // skip re-emitting from the outbound branch below to avoid duplicates.
555
- // This flag is only true when `this` response was created by
556
- // trackTransaction() and the reconstructed stream already fired.
557
- const alreadyReconstructed = universalTxResponse._eventsReconstructed === true;
558
- let intermediateAlreadyEmitted = alreadyReconstructed;
559
536
  // Build the base receipt directly from this response. Any per-call
560
537
  // `tx.progressHook(cb)` already replayed buffered execute-phase events
561
538
  // to `cb` via the progressHook setter — re-running trackTransaction
@@ -580,15 +557,6 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
580
557
  return;
581
558
  fanOut(event, registeredProgressHook, ctx.progressHook);
582
559
  };
583
- // Intermediate INFO marker — Push Chain tx confirmed, external/inbound
584
- // leg still pending. Per spec, R1 keeps 199-01 as terminal; R2/R3
585
- // reclassify Push success as intermediate. Skip when trackTransaction
586
- // (called above) already reconstructed the same marker via
587
- // reconstructR2/R3, otherwise the consumer sees 299-99 / 199-99-99
588
- // twice in their stream.
589
- if (hooks.intermediatePushOk && !intermediateAlreadyEmitted) {
590
- emit(hooks.intermediatePushOk(targetChain, tx.hash));
591
- }
592
560
  // Awaiting relay
593
561
  emit(hooks.awaiting(targetChain));
594
562
  let lastEmittedStatus;
@@ -39,6 +39,7 @@ const price_fetch_1 = require("../../price-fetch/price-fetch");
39
39
  const route_detector_1 = require("../route-detector");
40
40
  const cea_utils_1 = require("../cea-utils");
41
41
  const build_payload_1 = require("../svm-idl/build-payload");
42
+ const data_utils_1 = require("../data-utils");
42
43
  const payload_builders_1 = require("../payload-builders");
43
44
  const selectors_1 = require("../../constants/selectors");
44
45
  const erc20_evm_1 = require("../../constants/abi/erc20.evm");
@@ -73,7 +74,7 @@ function resolveR2Prc20TokenEvm(params, targetChain, pushNetwork) {
73
74
  prc20Token = (0, helpers_1.getNativePRC20ForChain)(targetChain, pushNetwork);
74
75
  burnAmount = params.value;
75
76
  }
76
- else if (params.data) {
77
+ else if ((0, data_utils_1.hasExecutablePayloadData)(params.data)) {
77
78
  // PAYLOAD-only (no value transfer): still need native token for chain namespace + gas fees
78
79
  prc20Token = (0, helpers_1.getNativePRC20ForChain)(targetChain, pushNetwork);
79
80
  burnAmount = BigInt(0);
@@ -132,12 +133,19 @@ function resolveR3SvmDrain(params, sourceChain, pushNetwork) {
132
133
  return { prc20Token, drainAmount, tokenMintHex };
133
134
  }
134
135
  function buildR3SvmExtraPayload(ctx, params, ueaAddress, sourceChain, inboundNonce) {
135
- if (!params.data) {
136
+ var _a, _b;
137
+ const shouldBuildPushPayload = (0, data_utils_1.hasExecutablePayloadData)(params.data) ||
138
+ Boolean(((_a = params.funds) === null || _a === void 0 ? void 0 : _a.amount) && ((_b = params.value) !== null && _b !== void 0 ? _b : BigInt(0)) > BigInt(0));
139
+ if (!shouldBuildPushPayload) {
136
140
  return undefined;
137
141
  }
138
142
  const executeParams = (0, helpers_1.toExecuteParams)(params);
139
143
  const multicallCtx = Object.assign(Object.assign({}, ctx), { universalSigner: Object.assign(Object.assign({}, ctx.universalSigner), { account: Object.assign(Object.assign({}, ctx.universalSigner.account), { chain: sourceChain }) }) });
140
- const multicallPayload = (0, payload_builder_1.buildMulticallPayloadData)(multicallCtx, executeParams.to, (0, payload_builders_1.buildExecuteMulticall)({ execute: executeParams, ueaAddress }));
144
+ const multicallPayload = (0, payload_builder_1.buildMulticallPayloadData)(multicallCtx, executeParams.to, (0, payload_builders_1.buildExecuteMulticall)({
145
+ execute: executeParams,
146
+ ueaAddress,
147
+ allowSelfValueCall: true,
148
+ }));
141
149
  const inboundPayload = (0, payload_builders_1.buildInboundUniversalPayload)(multicallPayload, {
142
150
  nonce: inboundNonce !== null && inboundNonce !== void 0 ? inboundNonce : BigInt(0),
143
151
  });
@@ -149,12 +157,13 @@ function buildR3SvmExtraPayload(ctx, params, ueaAddress, sourceChain, inboundNon
149
157
  * multicall when the target IS the CEA (avoids a CEA._handleMulticall revert).
150
158
  */
151
159
  function buildR2CeaPayloadEvm(params, ceaAddress, targetAddress) {
152
- var _a, _b, _c;
160
+ var _a, _b, _c, _d, _e;
153
161
  if (params.migration) {
154
162
  return (0, payload_builders_1.buildMigrationPayload)();
155
163
  }
156
164
  const ceaMulticalls = [];
157
- if (params.data) {
165
+ const hasData = (0, data_utils_1.hasExecutablePayloadData)(params.data);
166
+ if (hasData) {
158
167
  if (Array.isArray(params.data)) {
159
168
  ceaMulticalls.push(...params.data);
160
169
  }
@@ -186,36 +195,13 @@ function buildR2CeaPayloadEvm(params, ceaAddress, targetAddress) {
186
195
  });
187
196
  }
188
197
  }
189
- else if (params.value) {
190
- // Native value transfer only. Skip the multicall when sending to the CEA
191
- // itself — a value-bearing self-call would revert in CEA._handleMulticall.
192
- if (targetAddress.toLowerCase() !== ceaAddress.toLowerCase()) {
193
- ceaMulticalls.push({
194
- to: targetAddress,
195
- value: params.value,
196
- data: '0x',
197
- });
198
- }
199
- }
200
- else if ((_c = params.funds) === null || _c === void 0 ? void 0 : _c.amount) {
201
- // Funds-only transfer (no data, no value). Without this branch the CEA
202
- // multicall is empty and the relayed funds sit in the CEA instead of
203
- // being forwarded to the caller's recipient.
204
- const token = params.funds.token;
205
- if (token) {
206
- if (token.mechanism === 'native') {
207
- // Native funds (e.g. pETH → ETH): forward value to the recipient.
208
- // Self-CEA is skipped — the gateway already deposits into the CEA.
209
- if (targetAddress.toLowerCase() !== ceaAddress.toLowerCase()) {
210
- ceaMulticalls.push({
211
- to: targetAddress,
212
- value: params.funds.amount,
213
- data: '0x',
214
- });
215
- }
216
- }
217
- else {
218
- // ERC-20 funds: forward via ERC20.transfer from the CEA.
198
+ else {
199
+ const token = ((_c = params.funds) === null || _c === void 0 ? void 0 : _c.amount)
200
+ ? params.funds.token
201
+ : undefined;
202
+ if (((_d = params.funds) === null || _d === void 0 ? void 0 : _d.amount) && token && token.mechanism !== 'native') {
203
+ // ERC-20 funds: forward via ERC20.transfer from the CEA.
204
+ if (token) {
219
205
  const erc20Transfer = (0, viem_1.encodeFunctionData)({
220
206
  abi: erc20_evm_1.ERC20_EVM,
221
207
  functionName: 'transfer',
@@ -228,6 +214,28 @@ function buildR2CeaPayloadEvm(params, ceaAddress, targetAddress) {
228
214
  });
229
215
  }
230
216
  }
217
+ if (params.value) {
218
+ // Native value transfer only. Skip the multicall when sending to the CEA
219
+ // itself — a value-bearing self-call would revert in CEA._handleMulticall.
220
+ if (targetAddress.toLowerCase() !== ceaAddress.toLowerCase()) {
221
+ ceaMulticalls.push({
222
+ to: targetAddress,
223
+ value: params.value,
224
+ data: '0x',
225
+ });
226
+ }
227
+ }
228
+ else if (((_e = params.funds) === null || _e === void 0 ? void 0 : _e.amount) && (token === null || token === void 0 ? void 0 : token.mechanism) === 'native') {
229
+ // Native funds (e.g. pETH → ETH): forward value to the recipient.
230
+ // Self-CEA is skipped — the gateway already deposits into the CEA.
231
+ if (targetAddress.toLowerCase() !== ceaAddress.toLowerCase()) {
232
+ ceaMulticalls.push({
233
+ to: targetAddress,
234
+ value: params.funds.amount,
235
+ data: '0x',
236
+ });
237
+ }
238
+ }
231
239
  }
232
240
  return (0, payload_builders_1.buildCeaMulticallPayload)(ceaMulticalls);
233
241
  }
@@ -361,7 +369,9 @@ function executeUoaToCea(ctx, params, executeFn) {
361
369
  if (params.value && params.value > BigInt(0)) {
362
370
  (0, context_1.printLog)(ctx, `executeUoaToCea — auto-selected native PRC-20 ${prc20Token} for chain ${targetChain}, amount: ${burnAmount.toString()}`);
363
371
  }
364
- else if (!params.migration && !((_a = params.funds) === null || _a === void 0 ? void 0 : _a.amount) && params.data) {
372
+ else if (!params.migration &&
373
+ !((_a = params.funds) === null || _a === void 0 ? void 0 : _a.amount) &&
374
+ (0, data_utils_1.hasExecutablePayloadData)(params.data)) {
365
375
  (0, context_1.printLog)(ctx, `executeUoaToCea — PAYLOAD-only: using native PRC-20 ${prc20Token} for chain ${targetChain} with zero burn amount`);
366
376
  }
367
377
  const gasLimitForQuery = (_b = params.gasLimit) !== null && _b !== void 0 ? _b : BigInt(0);
@@ -804,7 +814,7 @@ function executeUoaToCeaSvm(ctx, params, target, executeFn) {
804
814
  */
805
815
  function executeCeaToPush(ctx, params, executeFn) {
806
816
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
807
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
817
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
808
818
  // 1. Validate and extract source chain
809
819
  if (!((_a = params.from) === null || _a === void 0 ? void 0 : _a.chain)) {
810
820
  throw new Error('Route 3 (CEA -> Push) requires from.chain to specify the source CEA chain');
@@ -893,7 +903,8 @@ function executeCeaToPush(ctx, params, executeFn) {
893
903
  // The relay expects a full UniversalPayload struct (to, value, data, gasLimit, ...),
894
904
  // where `data` contains the multicall payload (with UEA_MULTICALL_SELECTOR prefix).
895
905
  let pushPayload = '0x';
896
- if (params.data) {
906
+ if ((0, data_utils_1.hasExecutablePayloadData)(params.data) ||
907
+ (((_f = params.funds) === null || _f === void 0 ? void 0 : _f.amount) && ((_g = params.value) !== null && _g !== void 0 ? _g : BigInt(0)) > BigInt(0))) {
897
908
  const multicallData = (0, payload_builders_1.buildExecuteMulticall)({
898
909
  execute: {
899
910
  to: pushDestination,
@@ -901,6 +912,7 @@ function executeCeaToPush(ctx, params, executeFn) {
901
912
  data: params.data,
902
913
  },
903
914
  ueaAddress,
915
+ allowSelfValueCall: true,
904
916
  });
905
917
  const multicallPayload = (0, payload_builder_1.buildMulticallPayloadData)(ctx, pushDestination, multicallData);
906
918
  // Use ueaNonce + 1: the outbound tx itself consumes one nonce via execute(),
@@ -933,7 +945,7 @@ function executeCeaToPush(ctx, params, executeFn) {
933
945
  // tokens FROM the CEA back to Push Chain, not to round-trip them.
934
946
  const prc20Token = (0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork);
935
947
  const burnAmount = BigInt(0);
936
- const outboundGasLimit = (_f = params.gasLimit) !== null && _f !== void 0 ? _f : selectors_1.DEFAULT_CEA_TO_PUSH_GAS_LIMIT;
948
+ const outboundGasLimit = (_h = params.gasLimit) !== null && _h !== void 0 ? _h : selectors_1.DEFAULT_CEA_TO_PUSH_GAS_LIMIT;
937
949
  (0, context_1.printLog)(ctx, `executeCeaToPush — prc20Token: ${prc20Token}, burnAmount: ${burnAmount.toString()}`);
938
950
  // 9. Build outbound request (same structure as Route 2)
939
951
  // recipient = CEA address (for self-execution), value = 0 in payload
@@ -942,7 +954,7 @@ function executeCeaToPush(ctx, params, executeFn) {
942
954
  burnAmount, // amount: 0 (payload-only, CEA uses its own balance)
943
955
  outboundGasLimit, ceaPayload, // payload: ABI-encoded CEA multicall
944
956
  ueaAddress, // revertRecipient: UEA
945
- (_g = params.maxPCForGas) !== null && _g !== void 0 ? _g : BigInt(0));
957
+ (_j = params.maxPCForGas) !== null && _j !== void 0 ? _j : BigInt(0));
946
958
  (0, context_1.printLog)(ctx, `executeCeaToPush — outbound request: ${JSON.stringify({
947
959
  recipient: outboundReq.recipient,
948
960
  token: outboundReq.token,
@@ -973,8 +985,8 @@ function executeCeaToPush(ctx, params, executeFn) {
973
985
  protocolFeeR3 = result.protocolFee;
974
986
  nativeValueForGas = result.nativeValueForGas;
975
987
  sizingDecisionR3 = result.sizing;
976
- outboundReq = (0, payload_builders_1.buildOutboundRequest)(ceaAddress, prc20Token, burnAmount, outboundGasLimit, ceaPayload, ueaAddress, (_h = params.maxPCForGas) !== null && _h !== void 0 ? _h : BigInt(0), outboundGasPriceR3);
977
- (0, context_1.printLog)(ctx, `executeCeaToPush — queried gas fee: ${gasFee.toString()}, gasToken: ${gasToken}, nativeValueForGas: ${nativeValueForGas.toString()}, sizing=${(_k = (_j = result.sizing) === null || _j === void 0 ? void 0 : _j.category) !== null && _k !== void 0 ? _k : 'legacy'}`);
988
+ outboundReq = (0, payload_builders_1.buildOutboundRequest)(ceaAddress, prc20Token, burnAmount, outboundGasLimit, ceaPayload, ueaAddress, (_k = params.maxPCForGas) !== null && _k !== void 0 ? _k : BigInt(0), outboundGasPriceR3);
989
+ (0, context_1.printLog)(ctx, `executeCeaToPush — queried gas fee: ${gasFee.toString()}, gasToken: ${gasToken}, nativeValueForGas: ${nativeValueForGas.toString()}, sizing=${(_m = (_l = result.sizing) === null || _l === void 0 ? void 0 : _l.category) !== null && _m !== void 0 ? _m : 'legacy'}`);
978
990
  (0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_302_02, sourceChain, protocolFeeR3, gasFee);
979
991
  }
980
992
  catch (err) {
@@ -1056,7 +1068,7 @@ function executeCeaToPush(ctx, params, executeFn) {
1056
1068
  requiredValue: nativeValueForGas,
1057
1069
  gasReserve: OUTBOUND_GAS_RESERVE_R3,
1058
1070
  pathTag: 'R3_EVM',
1059
- enforceGasCheck: ((_l = params.options) === null || _l === void 0 ? void 0 : _l.enforceGasCheck) === true,
1071
+ enforceGasCheck: ((_o = params.options) === null || _o === void 0 ? void 0 : _o.enforceGasCheck) === true,
1060
1072
  });
1061
1073
  // 12. Build Push Chain multicalls (approvals + sendUniversalTxOutbound)
1062
1074
  const pushChainMulticalls = (0, payload_builders_1.buildOutboundApprovalAndCall)({
@@ -1343,7 +1355,7 @@ function executeCeaToCea(ctx, params, executeFn) {
1343
1355
  */
1344
1356
  function buildPayloadForRoute(ctx, params, route, nonce) {
1345
1357
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
1346
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
1358
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
1347
1359
  const ueaAddress = (0, uea_manager_1.computeUEAOffchain)(ctx);
1348
1360
  switch (route) {
1349
1361
  case route_detector_1.TransactionRoute.UOA_TO_PUSH: {
@@ -1396,7 +1408,7 @@ function buildPayloadForRoute(ctx, params, route, nonce) {
1396
1408
  const { cea: ceaAddress } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, target.chain, (_d = ctx.rpcUrls[target.chain]) === null || _d === void 0 ? void 0 : _d[0]);
1397
1409
  // Build CEA outbound payload
1398
1410
  const multicalls = [];
1399
- if (params.data) {
1411
+ if ((0, data_utils_1.hasExecutablePayloadData)(params.data)) {
1400
1412
  if (Array.isArray(params.data)) {
1401
1413
  multicalls.push(...params.data);
1402
1414
  }
@@ -1503,7 +1515,8 @@ function buildPayloadForRoute(ctx, params, route, nonce) {
1503
1515
  // Build Push Chain payload (what executes after inbound arrives)
1504
1516
  // Wrap in UniversalPayload struct for the relay.
1505
1517
  let pushPayload = '0x';
1506
- if (params.data) {
1518
+ if ((0, data_utils_1.hasExecutablePayloadData)(params.data) ||
1519
+ (((_o = params.funds) === null || _o === void 0 ? void 0 : _o.amount) && ((_p = params.value) !== null && _p !== void 0 ? _p : BigInt(0)) > BigInt(0))) {
1507
1520
  const multicallData = (0, payload_builders_1.buildExecuteMulticall)({
1508
1521
  execute: {
1509
1522
  to: pushDestination,
@@ -1511,6 +1524,7 @@ function buildPayloadForRoute(ctx, params, route, nonce) {
1511
1524
  data: params.data,
1512
1525
  },
1513
1526
  ueaAddress,
1527
+ allowSelfValueCall: true,
1514
1528
  });
1515
1529
  const multicallPayload = (0, payload_builder_1.buildMulticallPayloadData)(ctx, pushDestination, multicallData);
1516
1530
  pushPayload = (0, payload_builders_1.buildInboundUniversalPayload)(multicallPayload, { nonce: ueaNonceHop + BigInt(1) });
@@ -1524,8 +1538,8 @@ function buildPayloadForRoute(ctx, params, route, nonce) {
1524
1538
  // Route 3: CEA uses its own pre-existing balance — no PRC-20 burn needed.
1525
1539
  // burnAmount = 0 makes this a payload-only outbound relay.
1526
1540
  const burnAmount = BigInt(0);
1527
- const outboundGasLimit = (_o = params.gasLimit) !== null && _o !== void 0 ? _o : selectors_1.DEFAULT_CEA_TO_PUSH_GAS_LIMIT;
1528
- const outboundReq = (0, payload_builders_1.buildOutboundRequest)(ceaAddress, prc20Token, burnAmount, outboundGasLimit, ceaPayload, ueaAddress, (_p = params.maxPCForGas) !== null && _p !== void 0 ? _p : BigInt(0));
1541
+ const outboundGasLimit = (_q = params.gasLimit) !== null && _q !== void 0 ? _q : selectors_1.DEFAULT_CEA_TO_PUSH_GAS_LIMIT;
1542
+ const outboundReq = (0, payload_builders_1.buildOutboundRequest)(ceaAddress, prc20Token, burnAmount, outboundGasLimit, ceaPayload, ueaAddress, (_r = params.maxPCForGas) !== null && _r !== void 0 ? _r : BigInt(0));
1529
1543
  return { payload: ceaPayload, gatewayRequest: outboundReq };
1530
1544
  }
1531
1545
  default:
@@ -160,11 +160,6 @@ function reconstructR2(universalTxResponse, universalTxData, isFailed, errorMsg)
160
160
  if (isFailed) {
161
161
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_02](errorMsg));
162
162
  }
163
- else {
164
- // Push Chain success is intermediate for R2 — the wait() outbound poll
165
- // appends the real terminal (299-01/02/03) once the external leg resolves.
166
- events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_99](targetChain, universalTxResponse.hash));
167
- }
168
163
  return events;
169
164
  }
170
165
  function reconstructR3(universalTxResponse, universalTxData, isFailed, errorMsg) {
@@ -190,11 +185,6 @@ function reconstructR3(universalTxResponse, universalTxData, isFailed, errorMsg)
190
185
  // "Push Chain Tx Failed" rather than the inbound copy.
191
186
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](errorMsg, 'push'));
192
187
  }
193
- else {
194
- // Push Chain success is intermediate for R3 — wait() drives the source-chain
195
- // CEA poll (309-xx) and the inbound-to-Push poll (310-xx / 399-xx) on top.
196
- events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_99_99](universalTxResponse.hash));
197
- }
198
188
  return events;
199
189
  }
200
190
  // ============================================================================
@@ -315,7 +305,7 @@ function reconstructMultichain(universalTxResponse, universalTxData, isFailed, e
315
305
  let failedAt = null;
316
306
  let failureMsg = errorMsg;
317
307
  outbounds.forEach((ob, i) => {
318
- var _a;
308
+ var _a, _b;
319
309
  const hopNum = i + 1;
320
310
  const fromChain = i === 0 ? sourceChain : outbounds[i - 1].destinationChain;
321
311
  const toChain = ob.destinationChain;
@@ -336,6 +326,12 @@ function reconstructMultichain(universalTxResponse, universalTxData, isFailed, e
336
326
  events.push(...reconstructR2(legResponse, legData, legFailed, legError));
337
327
  }
338
328
  if (!legFailed) {
329
+ if (hopNum < hopCount) {
330
+ const txHash = ((_b = ob.observedTx) === null || _b === void 0 ? void 0 : _b.txHash) || legResponse.hash;
331
+ events.push(isR3Leg
332
+ ? progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_99](toChain, txHash)
333
+ : progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_99](toChain, txHash));
334
+ }
339
335
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_002_99_99](hopNum, hopCount));
340
336
  }
341
337
  else if (failedAt === null) {
@@ -7,6 +7,7 @@ const enums_1 = require("../constants/enums");
7
7
  const progress_hook_types_1 = require("../progress-hook/progress-hook.types");
8
8
  const push_client_1 = require("../push-client/push-client");
9
9
  const route_detector_1 = require("./route-detector");
10
+ const data_utils_1 = require("./data-utils");
10
11
  const internals_1 = require("./internals");
11
12
  class Orchestrator {
12
13
  /* @internal */ get pushClient() {
@@ -132,8 +133,9 @@ class Orchestrator {
132
133
  execute(params, options) {
133
134
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
134
135
  var _a, _b, _c, _d, _e;
135
- if (options) {
136
- params = Object.assign(Object.assign({}, params), { options: Object.assign(Object.assign({}, params.options), options) });
136
+ const inlineProgressHook = params.progressHook;
137
+ if (options || inlineProgressHook) {
138
+ params = Object.assign(Object.assign({}, params), { options: Object.assign(Object.assign(Object.assign({}, params.options), (inlineProgressHook ? { progressHook: inlineProgressHook } : {})), options) });
137
139
  }
138
140
  const perCallHook = (_a = params.options) === null || _a === void 0 ? void 0 : _a.progressHook;
139
141
  const originalExecuteHook = this.progressHook;
@@ -241,8 +243,7 @@ class Orchestrator {
241
243
  }
242
244
  // Standard Push Chain execution (Route 1)
243
245
  const execute = params;
244
- const hasFunds = !!execute.funds;
245
- const hasData = execute.data && execute.data !== '0x';
246
+ const hasData = (0, data_utils_1.hasExecutablePayloadData)(execute.data);
246
247
  const eventBuffer = [];
247
248
  const originalHook = this.progressHook;
248
249
  this.progressHook = (event) => {
@@ -101,6 +101,12 @@ export type ExecuteParams = {
101
101
  * Optional transaction behavior switches.
102
102
  */
103
103
  options?: TransactionExecutionOptions;
104
+ /**
105
+ * Optional per-call progress callback.
106
+ * Alias for `sendTransaction(params, { progressHook })`, kept so docs/UI
107
+ * examples can pass the hook inside the transaction object.
108
+ */
109
+ progressHook?: TransactionExecutionOptions['progressHook'];
104
110
  /**
105
111
  * Optional: pay gas in a specific token. If not provided, use `token` (bridge token) when present; otherwise, native token.
106
112
  */
@@ -633,6 +639,8 @@ export interface CascadedTxResponse {
633
639
  hops: CascadeHopInfo[];
634
640
  /** Total number of hops in the cascade */
635
641
  hopCount: number;
642
+ /** Final tx hash resolved by waitForAll()/wait(), when available */
643
+ finalTxHash?: string;
636
644
  /** Wait for ALL hops to complete across all chains */
637
645
  waitForAll: (opts?: CascadeTrackOptions) => Promise<CascadeCompletionResult>;
638
646
  /** Convenience alias for waitForAll() */
@@ -707,6 +715,10 @@ export interface CascadeCompletionResult {
707
715
  success: boolean;
708
716
  /** Final state of all hops */
709
717
  hops: CascadeHopInfo[];
718
+ /** Final tx hash for the last confirmed hop, when available */
719
+ finalTxHash?: string;
720
+ /** Original cascaded response object for consumers that need the full context */
721
+ finalTxResponse?: CascadedTxResponse;
710
722
  /** Index of first failed hop (if any) */
711
723
  failedAt?: number;
712
724
  }
@@ -1,9 +1,10 @@
1
1
  import { CHAIN } from '../constants/enums';
2
2
  import type { ExecuteParams, MultiCall, UniversalOutboundTxRequest, SvmExecutePayloadFields } from './orchestrator.types';
3
- export declare function buildExecuteMulticall({ execute, ueaAddress, logger, }: {
3
+ export declare function buildExecuteMulticall({ execute, ueaAddress, logger, allowSelfValueCall, }: {
4
4
  execute: ExecuteParams;
5
5
  ueaAddress: `0x${string}`;
6
6
  logger?: (msg: string) => void;
7
+ allowSelfValueCall?: boolean;
7
8
  }): MultiCall[];
8
9
  /**
9
10
  * Multicall tuple type definition for ABI encoding
@@ -23,14 +23,16 @@ const universalGatewayPC_evm_1 = require("../constants/abi/universalGatewayPC.ev
23
23
  const selectors_1 = require("../constants/selectors");
24
24
  const chain_1 = require("../constants/chain");
25
25
  const enums_1 = require("../constants/enums");
26
- function buildExecuteMulticall({ execute, ueaAddress, logger, }) {
26
+ const data_utils_1 = require("./data-utils");
27
+ function buildExecuteMulticall({ execute, ueaAddress, logger, allowSelfValueCall = false, }) {
27
28
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
28
29
  const log = (msg) => logger === null || logger === void 0 ? void 0 : logger(msg);
30
+ const hasData = (0, data_utils_1.hasExecutablePayloadData)(execute.data);
29
31
  log('buildExecuteMulticall — input: ' + JSON.stringify({
30
32
  to: execute.to,
31
33
  value: (_b = (_a = execute.value) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : 'undefined',
32
34
  data: execute.data ? (Array.isArray(execute.data) ? `Array(${execute.data.length})` : execute.data.slice(0, 20) + '...') : 'undefined',
33
- hasData: !!execute.data,
35
+ hasData,
34
36
  fundsAmount: (_e = (_d = (_c = execute.funds) === null || _c === void 0 ? void 0 : _c.amount) === null || _d === void 0 ? void 0 : _d.toString()) !== null && _e !== void 0 ? _e : 'undefined',
35
37
  fundsTokenSymbol: (_h = (_g = (_f = execute.funds) === null || _f === void 0 ? void 0 : _f.token) === null || _g === void 0 ? void 0 : _g.symbol) !== null && _h !== void 0 ? _h : 'undefined',
36
38
  fundsTokenMechanism: (_l = (_k = (_j = execute.funds) === null || _j === void 0 ? void 0 : _j.token) === null || _k === void 0 ? void 0 : _k.mechanism) !== null && _l !== void 0 ? _l : 'undefined',
@@ -38,19 +40,25 @@ function buildExecuteMulticall({ execute, ueaAddress, logger, }) {
38
40
  }, null, 2));
39
41
  const multicallData = [];
40
42
  // *** We will pass the value alongside with the data in a single message now ***
41
- const branch1 = !execute.data && execute.value;
42
- log(`buildExecuteMulticall — Branch 1 (!data && value): ${branch1} | !execute.data: ${!execute.data} | execute.value: ${(_o = (_m = execute.value) === null || _m === void 0 ? void 0 : _m.toString()) !== null && _o !== void 0 ? _o : 'undefined'}`);
43
- if (!execute.data && execute.value) {
44
- multicallData.push({
45
- to: execute.to,
46
- value: execute.value,
47
- data: '0x',
48
- });
49
- log(`buildExecuteMulticall — Branch 1 ENTERED: pushed native value transfer to ${execute.to}`);
43
+ const branch1 = !hasData && execute.value;
44
+ log(`buildExecuteMulticall — Branch 1 (!data && value): ${branch1} | !hasData: ${!hasData} | execute.value: ${(_o = (_m = execute.value) === null || _m === void 0 ? void 0 : _m.toString()) !== null && _o !== void 0 ? _o : 'undefined'}`);
45
+ if (!hasData && execute.value) {
46
+ const isValueToSelf = execute.to.toLowerCase() === ueaAddress.toLowerCase();
47
+ if (isValueToSelf && !allowSelfValueCall) {
48
+ log('buildExecuteMulticall — Branch 1 SKIPPED: native value targets the UEA itself; parking value via gateway deposit');
49
+ }
50
+ else {
51
+ multicallData.push({
52
+ to: execute.to,
53
+ value: execute.value,
54
+ data: '0x',
55
+ });
56
+ log(`buildExecuteMulticall — Branch 1 ENTERED: pushed native value transfer to ${execute.to}`);
57
+ }
50
58
  }
51
59
  if ((_p = execute.funds) === null || _p === void 0 ? void 0 : _p.amount) {
52
60
  const token = execute.funds.token;
53
- const isArrayMulticall = Array.isArray(execute.data);
61
+ const isArrayMulticall = Array.isArray(execute.data) && execute.data.length > 0;
54
62
  const isNative = token.mechanism === 'native';
55
63
  log('buildExecuteMulticall — Branch 2 (funds): ' + JSON.stringify({
56
64
  amount: execute.funds.amount.toString(),
@@ -82,8 +90,8 @@ function buildExecuteMulticall({ execute, ueaAddress, logger, }) {
82
90
  else {
83
91
  log('buildExecuteMulticall — Branch 2 SKIPPED: no funds.amount');
84
92
  }
85
- log(`buildExecuteMulticall — Branch 3 (execute.data): ${!!execute.data}`);
86
- if (execute.data) {
93
+ log(`buildExecuteMulticall — Branch 3 (execute.data): ${hasData}`);
94
+ if (hasData) {
87
95
  // *************************
88
96
  // Check for `execute.to`
89
97
  // *************************
@@ -21,6 +21,7 @@ exports.getRouteInfo = getRouteInfo;
21
21
  const enums_1 = require("../constants/enums");
22
22
  const tokens_1 = require("../constants/tokens");
23
23
  const payload_builders_1 = require("./payload-builders");
24
+ const data_utils_1 = require("./data-utils");
24
25
  const normalize_address_1 = require("./svm-idl/normalize-address");
25
26
  // ============================================================================
26
27
  // Transaction Route Enum
@@ -247,7 +248,7 @@ function validateRouteParams(params, context) {
247
248
  if (params.funds) {
248
249
  throw new RouteValidationError('migration is incompatible with funds');
249
250
  }
250
- if (params.data) {
251
+ if ((0, data_utils_1.hasExecutablePayloadData)(params.data)) {
251
252
  throw new RouteValidationError('migration is incompatible with data');
252
253
  }
253
254
  if (isChainTarget(params.to) && (0, payload_builders_1.isSvmChain)(params.to.chain)) {
@@ -23,10 +23,10 @@ const friendlyChain = (chainOrNs) => {
23
23
  const key = utils_1.Utils.chains.getChainName(asString);
24
24
  return key ? toTitleCase(key) : asString;
25
25
  };
26
- function preflightLevel(sufficient, enforceGasCheck) {
26
+ function preflightLevel(sufficient) {
27
27
  if (sufficient)
28
28
  return 'INFO';
29
- return enforceGasCheck === false ? 'WARNING' : 'ERROR';
29
+ return 'WARNING';
30
30
  }
31
31
  function preflightSuffix(sufficient, pathTag, enforceGasCheck) {
32
32
  if (sufficient)
@@ -273,6 +273,20 @@ const RAW_HOOKS_R1 = {
273
273
  level: 'ERROR',
274
274
  };
275
275
  },
276
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_03]: (targetChain, elapsedMs) => ({
277
+ id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_03,
278
+ title: `Syncing State with ${friendlyChain(targetChain)} Timeout`,
279
+ message: `Timed out waiting for UGPC relay to ${targetChain}`,
280
+ response: { error: 'relay timeout', chain: targetChain, elapsedMs },
281
+ level: 'ERROR',
282
+ }),
283
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_99]: (txHash) => ({
284
+ id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_99,
285
+ title: 'Push Chain Tx Completed',
286
+ message: `Intermediate Push Chain tx confirmed: ${txHash}, progressing to next phase`,
287
+ response: { txHash },
288
+ level: 'INFO',
289
+ }),
276
290
  };
277
291
  // =============================================================================
278
292
  // Route 2 — UEA → UGPC → CEA on target chain (201–299, signature-only)
@@ -342,7 +356,7 @@ const RAW_HOOKS_R2 = {
342
356
  warningOnly: !sufficient && enforceGasCheck === false,
343
357
  shortfall: (_d = extra === null || extra === void 0 ? void 0 : extra.shortfall) !== null && _d !== void 0 ? _d : null,
344
358
  },
345
- level: preflightLevel(sufficient, enforceGasCheck),
359
+ level: preflightLevel(sufficient),
346
360
  };
347
361
  },
348
362
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_04]: (required, available, shortfall, ueaAddress, pathTag, extra) => {
@@ -467,13 +481,6 @@ const RAW_HOOKS_R2 = {
467
481
  // Route 3 — UEA → UGPC → CEA → sendUniversalTxToUEA → Push Chain (301–399)
468
482
  // =============================================================================
469
483
  const RAW_HOOKS_R3 = {
470
- [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_99_99]: (txHash) => ({
471
- id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_99_99,
472
- title: 'Push Chain Tx Completed',
473
- message: `Intermediate Push Chain tx confirmed: ${txHash}, progressing to next phase`,
474
- response: { txHash },
475
- level: 'INFO',
476
- }),
477
484
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_301]: (sourceChain, ceaAddress) => ({
478
485
  id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_301,
479
486
  title: `${friendlyChain(sourceChain)}'s Executor Account Detected`,
@@ -560,7 +567,7 @@ const RAW_HOOKS_R3 = {
560
567
  warningOnly: !sufficient && enforceGasCheck === false,
561
568
  shortfall: (_d = extra === null || extra === void 0 ? void 0 : extra.shortfall) !== null && _d !== void 0 ? _d : null,
562
569
  },
563
- level: preflightLevel(sufficient, enforceGasCheck),
570
+ level: preflightLevel(sufficient),
564
571
  };
565
572
  },
566
573
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_05]: (required, available, shortfall, ueaAddress, pathTag, extra) => {
@@ -727,6 +734,13 @@ const RAW_HOOKS_R3 = {
727
734
  },
728
735
  level: 'ERROR',
729
736
  }),
737
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_99]: (sourceChain, txHash) => ({
738
+ id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_99,
739
+ title: `${friendlyChain(sourceChain)} Tx Completed`,
740
+ message: `Intermediate ${friendlyChain(sourceChain)} tx confirmed: ${txHash}, progressing to next phase`,
741
+ response: { chain: sourceChain, txHash },
742
+ level: 'INFO',
743
+ }),
730
744
  };
731
745
  // =============================================================================
732
746
  // UEA Migration hooks (unchanged)
@@ -828,7 +842,7 @@ const RAW_HOOKS_MULTICHAIN = {
828
842
  warningOnly: !sufficient && enforceGasCheck === false,
829
843
  shortfall: (_d = extra === null || extra === void 0 ? void 0 : extra.shortfall) !== null && _d !== void 0 ? _d : null,
830
844
  },
831
- level: preflightLevel(sufficient, enforceGasCheck),
845
+ level: preflightLevel(sufficient),
832
846
  };
833
847
  },
834
848
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_04]: (required, available, shortfall, ueaAddress, pathTag, extra) => {