@pushchain/core 5.1.5-alpha.1 → 5.1.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.
- package/CHANGELOG.md +19 -0
- package/package.json +1 -1
- package/src/lib/constants/abi/index.d.ts +2 -0
- package/src/lib/constants/abi/index.js +6 -1
- package/src/lib/constants/abi/uniswap-v3-router.evm.d.ts +58 -0
- package/src/lib/constants/abi/uniswap-v3-router.evm.js +41 -0
- package/src/lib/constants/abi/wpc.evm.d.ts +24 -0
- package/src/lib/constants/abi/wpc.evm.js +27 -0
- package/src/lib/constants/chain.d.ts +1 -0
- package/src/lib/constants/chain.js +8 -6
- package/src/lib/constants/tokens.js +3 -3
- package/src/lib/generated/uexecutor/v2/types.d.ts +14 -0
- package/src/lib/generated/uexecutor/v2/types.js +96 -3
- package/src/lib/orchestrator/internals/cascade.d.ts +1 -1
- package/src/lib/orchestrator/internals/cascade.js +521 -239
- package/src/lib/orchestrator/internals/confirmation.js +60 -15
- package/src/lib/orchestrator/internals/context.d.ts +23 -0
- package/src/lib/orchestrator/internals/context.js +54 -0
- package/src/lib/orchestrator/internals/execute-funds-only.js +47 -21
- package/src/lib/orchestrator/internals/execute-funds-payload.js +53 -31
- package/src/lib/orchestrator/internals/execute-standard.js +137 -26
- package/src/lib/orchestrator/internals/gas-calculator.d.ts +5 -2
- package/src/lib/orchestrator/internals/gas-calculator.js +59 -11
- package/src/lib/orchestrator/internals/gas-usd-sizer.d.ts +53 -0
- package/src/lib/orchestrator/internals/gas-usd-sizer.js +165 -0
- package/src/lib/orchestrator/internals/helpers.js +2 -0
- package/src/lib/orchestrator/internals/inbound-tracker.d.ts +83 -0
- package/src/lib/orchestrator/internals/inbound-tracker.js +322 -0
- package/src/lib/orchestrator/internals/index.d.ts +3 -1
- package/src/lib/orchestrator/internals/index.js +8 -2
- package/src/lib/orchestrator/internals/outbound-sync.d.ts +32 -1
- package/src/lib/orchestrator/internals/outbound-sync.js +154 -17
- package/src/lib/orchestrator/internals/pc-usd-oracle.d.ts +28 -0
- package/src/lib/orchestrator/internals/pc-usd-oracle.js +285 -0
- package/src/lib/orchestrator/internals/progress-route-hooks.d.ts +23 -0
- package/src/lib/orchestrator/internals/progress-route-hooks.js +72 -0
- package/src/lib/orchestrator/internals/push-chain-tx.d.ts +27 -1
- package/src/lib/orchestrator/internals/push-chain-tx.js +111 -15
- package/src/lib/orchestrator/internals/rescue.js +1 -1
- package/src/lib/orchestrator/internals/response-builder.d.ts +5 -0
- package/src/lib/orchestrator/internals/response-builder.js +242 -66
- package/src/lib/orchestrator/internals/route-handlers.js +480 -206
- package/src/lib/orchestrator/internals/tx-transformer.js +293 -35
- package/src/lib/orchestrator/orchestrator.d.ts +7 -1
- package/src/lib/orchestrator/orchestrator.js +108 -56
- package/src/lib/orchestrator/orchestrator.types.d.ts +111 -5
- package/src/lib/orchestrator/payload-builders.d.ts +16 -0
- package/src/lib/orchestrator/payload-builders.js +6 -5
- package/src/lib/orchestrator/route-detector.js +20 -8
- package/src/lib/orchestrator/svm-idl/normalize-address.d.ts +19 -0
- package/src/lib/orchestrator/svm-idl/normalize-address.js +56 -0
- package/src/lib/orchestrator/svm-idl/registry.d.ts +13 -4
- package/src/lib/orchestrator/svm-idl/registry.js +15 -14
- package/src/lib/orchestrator/svm-idl/resolve.js +5 -2
- package/src/lib/progress-hook/progress-hook.d.ts +28 -0
- package/src/lib/progress-hook/progress-hook.js +545 -131
- package/src/lib/progress-hook/progress-hook.types.d.ts +76 -29
- package/src/lib/progress-hook/progress-hook.types.js +74 -35
- package/src/lib/push-client/push-client.d.ts +7 -0
- package/src/lib/push-client/push-client.js +18 -1
- package/src/lib/universal-tx-detector/__tests__/fixtures/builders.d.ts +32 -0
- package/src/lib/universal-tx-detector/__tests__/fixtures/builders.js +65 -0
- package/src/lib/universal-tx-detector/__tests__/fixtures/scenarios.d.ts +72 -0
- package/src/lib/universal-tx-detector/__tests__/fixtures/scenarios.js +669 -0
- package/src/lib/universal-tx-detector/auto-detect.d.ts +37 -0
- package/src/lib/universal-tx-detector/auto-detect.js +112 -0
- package/src/lib/universal-tx-detector/cascade.d.ts +64 -0
- package/src/lib/universal-tx-detector/cascade.js +254 -0
- package/src/lib/universal-tx-detector/child-inbounds.d.ts +58 -0
- package/src/lib/universal-tx-detector/child-inbounds.js +145 -0
- package/src/lib/universal-tx-detector/classify.d.ts +33 -0
- package/src/lib/universal-tx-detector/classify.js +228 -0
- package/src/lib/universal-tx-detector/detector-svm.d.ts +46 -0
- package/src/lib/universal-tx-detector/detector-svm.js +324 -0
- package/src/lib/universal-tx-detector/detector.d.ts +13 -0
- package/src/lib/universal-tx-detector/detector.js +233 -0
- package/src/lib/universal-tx-detector/events.d.ts +765 -0
- package/src/lib/universal-tx-detector/events.js +241 -0
- package/src/lib/universal-tx-detector/index.d.ts +18 -0
- package/src/lib/universal-tx-detector/index.js +36 -0
- package/src/lib/universal-tx-detector/svm-events.d.ts +41 -0
- package/src/lib/universal-tx-detector/svm-events.js +68 -0
- package/src/lib/universal-tx-detector/types.d.ts +100 -0
- package/src/lib/universal-tx-detector/types.js +3 -0
- package/src/lib/utils.d.ts +30 -13
- package/src/lib/utils.js +47 -21
|
@@ -25,7 +25,39 @@ const context_1 = require("./context");
|
|
|
25
25
|
const helpers_1 = require("./helpers");
|
|
26
26
|
const svm_helpers_1 = require("./svm-helpers");
|
|
27
27
|
const outbound_tracker_1 = require("./outbound-tracker");
|
|
28
|
+
const inbound_tracker_1 = require("./inbound-tracker");
|
|
28
29
|
const tx_transformer_1 = require("./tx-transformer");
|
|
30
|
+
const progress_route_hooks_1 = require("./progress-route-hooks");
|
|
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
|
+
/**
|
|
46
|
+
* Fan out a progress event to one or two registered callbacks, deduping
|
|
47
|
+
* when both slots hold the same reference. Keeps the emission policy in a
|
|
48
|
+
* single place shared by `emitProgress` (execute phase) and `emit` (wait
|
|
49
|
+
* 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.
|
|
52
|
+
*/
|
|
53
|
+
function fanOut(event, primary, secondary) {
|
|
54
|
+
if (INTERMEDIATE_INTERNAL_IDS.has(event.id))
|
|
55
|
+
return;
|
|
56
|
+
if (primary)
|
|
57
|
+
primary(event);
|
|
58
|
+
if (secondary && secondary !== primary)
|
|
59
|
+
secondary(event);
|
|
60
|
+
}
|
|
29
61
|
// ============================================================================
|
|
30
62
|
// queryUniversalTxStatusFromGatewayTx
|
|
31
63
|
// ============================================================================
|
|
@@ -107,8 +139,8 @@ txHash, evmGatewayMethod) {
|
|
|
107
139
|
}, null, 2));
|
|
108
140
|
// Fetch UniversalTx via gRPC with linear-then-exponential retry
|
|
109
141
|
const LINEAR_ATTEMPTS = 10;
|
|
110
|
-
const LINEAR_DELAY_MS =
|
|
111
|
-
const EXPONENTIAL_BASE_MS =
|
|
142
|
+
const LINEAR_DELAY_MS = 3600;
|
|
143
|
+
const EXPONENTIAL_BASE_MS = 4800;
|
|
112
144
|
const MAX_ATTEMPTS = 15;
|
|
113
145
|
let universalTxObj;
|
|
114
146
|
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
@@ -148,6 +180,7 @@ txHash, evmGatewayMethod) {
|
|
|
148
180
|
// ============================================================================
|
|
149
181
|
function trackTransaction(ctx, txHash, options, callbacks) {
|
|
150
182
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
183
|
+
var _a, _b;
|
|
151
184
|
if (!callbacks) {
|
|
152
185
|
throw new Error('trackTransaction requires ResponseBuilderCallbacks');
|
|
153
186
|
}
|
|
@@ -155,18 +188,13 @@ function trackTransaction(ctx, txHash, options, callbacks) {
|
|
|
155
188
|
const { timeout = 300000, pollingIntervalMs = 1000, rpcUrls = {} } = advanced;
|
|
156
189
|
// Event buffer for replay via response.progressHook()
|
|
157
190
|
const eventBuffer = [];
|
|
158
|
-
// Helper to emit progress events
|
|
191
|
+
// Helper to emit progress events. Per-tx hook (passed to trackTransaction)
|
|
192
|
+
// fires first, then the orchestrator-level hook — deduped via `fanOut` so
|
|
193
|
+
// a caller that wires the same callback at both levels isn't double-fired.
|
|
159
194
|
const emitProgress = (event) => {
|
|
160
195
|
eventBuffer.push(event);
|
|
161
196
|
(0, context_1.printLog)(ctx, event.message);
|
|
162
|
-
|
|
163
|
-
if (progressHook) {
|
|
164
|
-
progressHook(event);
|
|
165
|
-
}
|
|
166
|
-
// Orchestrator-level hook called SECOND
|
|
167
|
-
if (ctx.progressHook) {
|
|
168
|
-
ctx.progressHook(event);
|
|
169
|
-
}
|
|
197
|
+
fanOut(event, progressHook, ctx.progressHook);
|
|
170
198
|
};
|
|
171
199
|
// Create client for target chain with optional RPC override
|
|
172
200
|
const chainRPCs = rpcUrls[chain] || ctx.rpcUrls[chain] || chain_1.CHAIN_INFO[chain].defaultRPC;
|
|
@@ -205,7 +233,7 @@ function trackTransaction(ctx, txHash, options, callbacks) {
|
|
|
205
233
|
universalTxData = utxResponse.universalTx;
|
|
206
234
|
}
|
|
207
235
|
}
|
|
208
|
-
catch (
|
|
236
|
+
catch (_c) {
|
|
209
237
|
// Ignore - try computed ID next
|
|
210
238
|
}
|
|
211
239
|
if (!universalTxData) {
|
|
@@ -217,7 +245,7 @@ function trackTransaction(ctx, txHash, options, callbacks) {
|
|
|
217
245
|
universalTxData = utxResponse.universalTx;
|
|
218
246
|
}
|
|
219
247
|
}
|
|
220
|
-
catch (
|
|
248
|
+
catch (_d) {
|
|
221
249
|
// Ignore - try Cosmos event extraction next
|
|
222
250
|
}
|
|
223
251
|
}
|
|
@@ -232,7 +260,7 @@ function trackTransaction(ctx, txHash, options, callbacks) {
|
|
|
232
260
|
}
|
|
233
261
|
}
|
|
234
262
|
}
|
|
235
|
-
catch (
|
|
263
|
+
catch (_e) {
|
|
236
264
|
// Ignore - no universal tx data available
|
|
237
265
|
}
|
|
238
266
|
}
|
|
@@ -243,12 +271,48 @@ function trackTransaction(ctx, txHash, options, callbacks) {
|
|
|
243
271
|
const detectedRoute = (0, tx_transformer_1.detectRouteFromUniversalTxData)(universalTxData);
|
|
244
272
|
if (detectedRoute) {
|
|
245
273
|
universalTxResponse.route = detectedRoute;
|
|
274
|
+
// Mirror the route on the context so emission code in wait()/cascade
|
|
275
|
+
// picks the correct ID range — keeps trackTransaction in lockstep with
|
|
276
|
+
// sendUniversalTransaction, which sets currentRoute in execute().
|
|
277
|
+
ctx.currentRoute = detectedRoute;
|
|
278
|
+
// Populate the destination/source chain on the response so
|
|
279
|
+
// reconstructR2/R3 (and any downstream emission that reads
|
|
280
|
+
// universalTxResponse.chain) emit the proper friendly chain name
|
|
281
|
+
// instead of the "external" fallback. The first outbound's destination
|
|
282
|
+
// is the target chain for R2 and the source CEA chain for R3.
|
|
283
|
+
const firstOutboundChain = (_b = (_a = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.outboundTx) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.destinationChain;
|
|
284
|
+
if (firstOutboundChain && !universalTxResponse.chain) {
|
|
285
|
+
universalTxResponse.chain = firstOutboundChain;
|
|
286
|
+
universalTxResponse.chainNamespace = firstOutboundChain;
|
|
287
|
+
}
|
|
288
|
+
// For R3 replays, enable inbound round-trip tracking so `.wait()` runs
|
|
289
|
+
// the 310-01 → 399-01 sequence. Live execute sets this in
|
|
290
|
+
// route-handlers.ts via `amount > 0n`; trackTransaction has no
|
|
291
|
+
// execute-phase args, so we enable it unconditionally for CEA_TO_PUSH.
|
|
292
|
+
// The inbound block tolerates no-inbound (payload-only R3) by timing
|
|
293
|
+
// out — same as live behaviour when the source tx has no round-trip.
|
|
294
|
+
if (detectedRoute === route_detector_1.TransactionRoute.CEA_TO_PUSH) {
|
|
295
|
+
universalTxResponse._expectsInboundRoundTrip = true;
|
|
296
|
+
}
|
|
246
297
|
}
|
|
247
298
|
// Reconstruct and emit SEND-TX-* progress events
|
|
248
299
|
const reconstructedEvents = (0, tx_transformer_1.reconstructProgressEvents)(universalTxResponse, universalTxData);
|
|
249
300
|
for (const event of reconstructedEvents) {
|
|
250
301
|
emitProgress(event);
|
|
251
302
|
}
|
|
303
|
+
// Mark the response so the wait() closure (when later invoked) doesn't
|
|
304
|
+
// call trackTransaction a second time and re-emit the same reconstructed
|
|
305
|
+
// events to the user's progressHook.
|
|
306
|
+
universalTxResponse._eventsReconstructed = true;
|
|
307
|
+
// Auto-register the caller's per-call progressHook as the response's
|
|
308
|
+
// registeredProgressHook so that tracked.wait() fires wait-phase events
|
|
309
|
+
// (209-xx / 299-xx / 399-xx) to the same callback without requiring
|
|
310
|
+
// tracked.progressHook(cb) to be called again. Skip replay of buffered
|
|
311
|
+
// events because we just fired them above via emitProgress — calling
|
|
312
|
+
// response.progressHook(cb) here would re-emit the reconstructed stream.
|
|
313
|
+
if (progressHook && universalTxResponse._setProgressHookNoReplay) {
|
|
314
|
+
universalTxResponse._setProgressHookNoReplay(progressHook);
|
|
315
|
+
}
|
|
252
316
|
return universalTxResponse;
|
|
253
317
|
});
|
|
254
318
|
}
|
|
@@ -280,18 +344,36 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
280
344
|
}
|
|
281
345
|
from = (0, viem_1.getAddress)(tx.to);
|
|
282
346
|
let decoded;
|
|
347
|
+
let decodedPayload = null;
|
|
283
348
|
if (tx.input !== '0x') {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
349
|
+
// Try to decode the input as a known UEA_EVM call. Older txs — or
|
|
350
|
+
// txs sent to a UEA that was upgraded to expose a function not yet
|
|
351
|
+
// reflected in the bundled `uea.evm.ts` ABI — carry a selector that
|
|
352
|
+
// viem can't match. In that case the reconstructor should still
|
|
353
|
+
// produce a usable response (and emit progress hooks) using the raw
|
|
354
|
+
// tx fields, rather than throwing before any hook fires.
|
|
355
|
+
try {
|
|
356
|
+
decoded = (0, viem_1.decodeFunctionData)({ abi: uea_evm_1.UEA_EVM, data: tx.input });
|
|
357
|
+
if (decoded === null || decoded === void 0 ? void 0 : decoded.args) {
|
|
358
|
+
decodedPayload = decoded.args[0];
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
catch (_a) {
|
|
362
|
+
decodedPayload = null;
|
|
363
|
+
}
|
|
364
|
+
if (decodedPayload) {
|
|
365
|
+
to = decodedPayload.to;
|
|
366
|
+
value = BigInt(decodedPayload.value);
|
|
367
|
+
data = decodedPayload.data;
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
// Unknown / unsupported UEA function — fall back to raw fields so
|
|
371
|
+
// transformToUniversalTxResponse can still return a valid response
|
|
372
|
+
// and downstream progress-hook reconstruction can proceed.
|
|
373
|
+
to = (0, viem_1.getAddress)(tx.to);
|
|
374
|
+
value = tx.value;
|
|
375
|
+
data = tx.input;
|
|
290
376
|
}
|
|
291
|
-
const universalPayload = decoded === null || decoded === void 0 ? void 0 : decoded.args[0];
|
|
292
|
-
to = universalPayload.to;
|
|
293
|
-
value = BigInt(universalPayload.value);
|
|
294
|
-
data = universalPayload.data;
|
|
295
377
|
// Extract 'to' from single-element multicall
|
|
296
378
|
if (data && data.length >= 10) {
|
|
297
379
|
const multicallSelector = (0, viem_1.keccak256)((0, viem_1.toBytes)('UEA_MULTICALL')).slice(0, 10);
|
|
@@ -313,7 +395,7 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
313
395
|
to = (0, viem_1.getAddress)(decodedCalls[0].to);
|
|
314
396
|
}
|
|
315
397
|
}
|
|
316
|
-
catch (
|
|
398
|
+
catch (_b) {
|
|
317
399
|
// Keep original 'to' if decoding fails
|
|
318
400
|
}
|
|
319
401
|
}
|
|
@@ -381,7 +463,7 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
381
463
|
from = '0x0000000000000000000000000000000000000000';
|
|
382
464
|
}
|
|
383
465
|
}
|
|
384
|
-
catch (
|
|
466
|
+
catch (_c) {
|
|
385
467
|
// Keep original values if decoding fails
|
|
386
468
|
}
|
|
387
469
|
}
|
|
@@ -397,7 +479,7 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
397
479
|
yParity: tx.yParity,
|
|
398
480
|
};
|
|
399
481
|
}
|
|
400
|
-
catch (
|
|
482
|
+
catch (_d) {
|
|
401
483
|
// Fallback signature if parsing fails
|
|
402
484
|
signature = {
|
|
403
485
|
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
@@ -453,65 +535,159 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
453
535
|
maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
|
|
454
536
|
accessList: Array.isArray(tx.accessList) ? [...tx.accessList] : [],
|
|
455
537
|
// 6. Utilities
|
|
456
|
-
wait: () => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
538
|
+
wait: (waitOptions) => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
539
|
+
var _a, _b, _c, _d, _e, _f;
|
|
540
|
+
// For trackTransaction replays the tx is historical — cosmos already
|
|
541
|
+
// has the full graph indexed, so the 20s/30s initial-wait buffers
|
|
542
|
+
// designed for live sends are pure deadweight. Default them to 0 when
|
|
543
|
+
// replaying; callers can still override via WaitOptions.
|
|
544
|
+
const isReplay = universalTxResponse._eventsReconstructed === true;
|
|
545
|
+
const outboundTimeoutMs = (_a = waitOptions === null || waitOptions === void 0 ? void 0 : waitOptions.outboundTimeoutMs) !== null && _a !== void 0 ? _a : callbacks.outboundConstants.maxTimeoutMs;
|
|
546
|
+
const inboundTimeoutMs = (_b = waitOptions === null || waitOptions === void 0 ? void 0 : waitOptions.inboundTimeoutMs) !== null && _b !== void 0 ? _b : callbacks.inboundConstants.maxTimeoutMs;
|
|
547
|
+
const outboundInitialWaitMs = (_c = waitOptions === null || waitOptions === void 0 ? void 0 : waitOptions.outboundInitialWaitMs) !== null && _c !== void 0 ? _c : (isReplay ? 0 : callbacks.outboundConstants.initialWaitMs);
|
|
548
|
+
const outboundPollingIntervalMs = (_d = waitOptions === null || waitOptions === void 0 ? void 0 : waitOptions.outboundPollingIntervalMs) !== null && _d !== void 0 ? _d : callbacks.outboundConstants.pollingIntervalMs;
|
|
549
|
+
const inboundInitialWaitMs = isReplay
|
|
550
|
+
? 0
|
|
551
|
+
: 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
|
+
// Build the base receipt directly from this response. Any per-call
|
|
560
|
+
// `tx.progressHook(cb)` already replayed buffered execute-phase events
|
|
561
|
+
// to `cb` via the progressHook setter — re-running trackTransaction
|
|
562
|
+
// here would duplicate the reconstructed stream on top of that replay,
|
|
563
|
+
// which is exactly what broke R1 parity. Wait-phase events (209-xx /
|
|
564
|
+
// 299-xx / 399-xx) still reach `registeredProgressHook` and
|
|
565
|
+
// `ctx.progressHook` via the `emit` closure in the outbound branch.
|
|
566
|
+
const receipt = yield tx.wait();
|
|
567
|
+
let baseReceipt = callbacks.transformToUniversalTxReceipt(receipt, universalTxResponse);
|
|
472
568
|
// If outbound route, poll for external chain details
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
: undefined;
|
|
569
|
+
const route = universalTxResponse.route;
|
|
570
|
+
const routeInfo = route ? (0, route_detector_1.getRouteInfo)(route) : undefined;
|
|
476
571
|
if (routeInfo === null || routeInfo === void 0 ? void 0 : routeInfo.isOutbound) {
|
|
477
|
-
//
|
|
478
|
-
//
|
|
479
|
-
// events
|
|
480
|
-
//
|
|
481
|
-
|
|
572
|
+
// Pick route-specific hook builders. R4 (CEA_TO_CEA) currently has
|
|
573
|
+
// no spec'd IDs — pickWaitHooks returns a no-op set that yields
|
|
574
|
+
// events with `id: ''`. `emit` drops those so the consumer never
|
|
575
|
+
// sees placeholder events, while receipt mutation still runs.
|
|
576
|
+
const hooks = (0, progress_route_hooks_1.pickWaitHooks)(route);
|
|
577
|
+
const targetChain = ((_e = universalTxResponse.chain) !== null && _e !== void 0 ? _e : 'external');
|
|
578
|
+
const emit = (event) => {
|
|
579
|
+
if (!event.id)
|
|
580
|
+
return;
|
|
581
|
+
fanOut(event, registeredProgressHook, ctx.progressHook);
|
|
582
|
+
};
|
|
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
|
+
// Awaiting relay
|
|
593
|
+
emit(hooks.awaiting(targetChain));
|
|
482
594
|
let lastEmittedStatus;
|
|
483
595
|
const outboundTranslator = (event) => {
|
|
484
|
-
if (!registeredProgressHook)
|
|
485
|
-
return;
|
|
486
596
|
if (event.status === 'polling' && lastEmittedStatus !== 'polling') {
|
|
487
597
|
lastEmittedStatus = 'polling';
|
|
488
|
-
|
|
598
|
+
emit(hooks.polling(targetChain, event.elapsed));
|
|
489
599
|
}
|
|
490
600
|
};
|
|
491
601
|
try {
|
|
492
602
|
const outboundDetails = yield callbacks.waitForOutboundTx(tx.hash, {
|
|
493
|
-
initialWaitMs:
|
|
494
|
-
pollingIntervalMs:
|
|
495
|
-
timeout:
|
|
603
|
+
initialWaitMs: outboundInitialWaitMs,
|
|
604
|
+
pollingIntervalMs: outboundPollingIntervalMs,
|
|
605
|
+
timeout: outboundTimeoutMs,
|
|
496
606
|
progressHook: outboundTranslator,
|
|
497
607
|
});
|
|
498
|
-
|
|
608
|
+
emit(hooks.success(outboundDetails));
|
|
499
609
|
// Merge external chain details into receipt
|
|
500
|
-
baseReceipt = Object.assign(Object.assign({}, baseReceipt), { externalTxHash: outboundDetails.externalTxHash, externalChain: outboundDetails.destinationChain, externalExplorerUrl: outboundDetails.explorerUrl, externalRecipient: outboundDetails.recipient, externalAmount: outboundDetails.amount, externalAssetAddr: outboundDetails.assetAddr });
|
|
610
|
+
baseReceipt = Object.assign(Object.assign({}, baseReceipt), { externalTxHash: outboundDetails.externalTxHash, externalChain: outboundDetails.destinationChain, externalExplorerUrl: outboundDetails.explorerUrl, externalRecipient: outboundDetails.recipient, externalAmount: outboundDetails.amount, externalAssetAddr: outboundDetails.assetAddr, externalStatus: 'success' });
|
|
611
|
+
// R3 round-trip: poll Push Chain for the inbound tx that the
|
|
612
|
+
// source-chain CEA's sendUniversalTxToUEA call produces. Correlate
|
|
613
|
+
// via the outbound external tx hash → child UTX id → child pcTx.
|
|
614
|
+
// Only run when the CEA payload actually fires sendUniversalTxToUEA;
|
|
615
|
+
// payload-only R3 (no funds flowing back) has no child UTX and would
|
|
616
|
+
// otherwise time out after 300s.
|
|
617
|
+
if (route === route_detector_1.TransactionRoute.CEA_TO_PUSH &&
|
|
618
|
+
universalTxResponse._expectsInboundRoundTrip === true) {
|
|
619
|
+
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_310_01](targetChain));
|
|
620
|
+
let inboundLastEmitted;
|
|
621
|
+
try {
|
|
622
|
+
const inbound = yield (0, inbound_tracker_1.waitForInboundPushTx)(ctx, outboundDetails.externalTxHash, targetChain, {
|
|
623
|
+
initialWaitMs: inboundInitialWaitMs,
|
|
624
|
+
pollingIntervalMs: callbacks.inboundConstants.pollingIntervalMs,
|
|
625
|
+
timeout: inboundTimeoutMs,
|
|
626
|
+
progressHook: (event) => {
|
|
627
|
+
if (event.status === 'polling' &&
|
|
628
|
+
inboundLastEmitted !== 'polling') {
|
|
629
|
+
inboundLastEmitted = 'polling';
|
|
630
|
+
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_310_02](targetChain, event.elapsedMs));
|
|
631
|
+
}
|
|
632
|
+
},
|
|
633
|
+
});
|
|
634
|
+
if (inbound.status === 'confirmed') {
|
|
635
|
+
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_01](targetChain, inbound.pushTxHash, baseReceipt));
|
|
636
|
+
baseReceipt = Object.assign(Object.assign({}, baseReceipt), { pushInboundTxHash: inbound.pushTxHash, pushInboundUtxId: inbound.childUtxId });
|
|
637
|
+
}
|
|
638
|
+
else {
|
|
639
|
+
// status === 'failed' (terminal failure status from chain)
|
|
640
|
+
const failMsg = (_f = inbound.errorMessage) !== null && _f !== void 0 ? _f : 'inbound execution failed on Push Chain';
|
|
641
|
+
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](failMsg, 'inbound', targetChain));
|
|
642
|
+
baseReceipt = Object.assign(Object.assign({}, baseReceipt), { pushInboundUtxId: inbound.childUtxId, pushInboundTxHash: inbound.pushTxHash || undefined, externalStatus: 'failed', externalError: failMsg });
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
catch (inboundErr) {
|
|
646
|
+
const errMsg = inboundErr instanceof Error
|
|
647
|
+
? inboundErr.message
|
|
648
|
+
: String(inboundErr);
|
|
649
|
+
const isTimeout = inboundErr instanceof inbound_tracker_1.InboundTimeoutError;
|
|
650
|
+
// Annotate receipt for inbound-leg outcome too.
|
|
651
|
+
baseReceipt = Object.assign(Object.assign({}, baseReceipt), { externalStatus: isTimeout ? 'timeout' : 'failed', externalError: errMsg });
|
|
652
|
+
emit(isTimeout
|
|
653
|
+
? progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_03](targetChain, inboundTimeoutMs, 'inbound')
|
|
654
|
+
: progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](errMsg, 'inbound', targetChain));
|
|
655
|
+
callbacks.printLog(`[wait] R3 inbound tracking failed: ${errMsg}`);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
501
658
|
}
|
|
502
659
|
catch (error) {
|
|
503
660
|
const errMsg = error instanceof Error ? error.message : String(error);
|
|
504
|
-
const isTimeout =
|
|
505
|
-
|
|
506
|
-
?
|
|
507
|
-
:
|
|
508
|
-
//
|
|
509
|
-
//
|
|
510
|
-
|
|
661
|
+
const isTimeout = error instanceof outbound_sync_1.OutboundTimeoutError;
|
|
662
|
+
emit(isTimeout
|
|
663
|
+
? hooks.timeout(targetChain, outboundTimeoutMs)
|
|
664
|
+
: hooks.failed(targetChain, errMsg));
|
|
665
|
+
// Annotate the receipt so callers can distinguish external-leg
|
|
666
|
+
// outcomes without sniffing errMsg. Push Chain leg still succeeded
|
|
667
|
+
// (status stays 1); inspect `externalStatus` / `externalError` for
|
|
668
|
+
// the external/inbound leg outcome. On a reverted outbound the
|
|
669
|
+
// observed tx hash is carried by OutboundFailedError — expose it
|
|
670
|
+
// as externalTxHash so consumers can link to the explorer.
|
|
671
|
+
const failedExternalTxHash = error instanceof outbound_sync_1.OutboundFailedError ? error.externalTxHash : undefined;
|
|
672
|
+
baseReceipt = Object.assign(Object.assign(Object.assign({}, baseReceipt), { externalStatus: isTimeout ? 'timeout' : 'failed', externalError: errMsg }), (failedExternalTxHash
|
|
673
|
+
? { externalTxHash: failedExternalTxHash }
|
|
674
|
+
: {}));
|
|
675
|
+
// Outbound polling timed out or failed — return the annotated
|
|
676
|
+
// receipt without throwing. Push Chain tx succeeded, external
|
|
677
|
+
// tracking can be retried later.
|
|
678
|
+
callbacks.printLog(`[wait] External chain tracking ${isTimeout ? 'timed out' : 'failed'}: ${errMsg}`);
|
|
511
679
|
}
|
|
512
680
|
}
|
|
513
681
|
return baseReceipt;
|
|
514
682
|
}),
|
|
683
|
+
// Internal: register a wait-phase progressHook without replaying
|
|
684
|
+
// buffered events. Used by trackTransaction() after it has already
|
|
685
|
+
// emitted the reconstructed stream to the caller's per-call hook,
|
|
686
|
+
// so that tracked.wait() can deliver wait-phase events (209-xx /
|
|
687
|
+
// 299-xx / 399-xx) to the same callback without duplicating replay.
|
|
688
|
+
_setProgressHookNoReplay: (callback) => {
|
|
689
|
+
registeredProgressHook = callback;
|
|
690
|
+
},
|
|
515
691
|
progressHook: (callback) => {
|
|
516
692
|
registeredProgressHook = callback;
|
|
517
693
|
// Immediately replay buffered events from execution
|