@pushchain/core 5.1.5-alpha.0 → 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 +556 -225
- 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 +252 -53
- 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 +120 -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 +555 -101
- package/src/lib/progress-hook/progress-hook.types.d.ts +76 -24
- package/src/lib/progress-hook/progress-hook.types.js +74 -29
- 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
|
@@ -16,6 +16,8 @@ const viem_1 = require("viem");
|
|
|
16
16
|
const uea_evm_1 = require("../../constants/abi/uea.evm");
|
|
17
17
|
const chain_1 = require("../../constants/chain");
|
|
18
18
|
const enums_1 = require("../../constants/enums");
|
|
19
|
+
const progress_hook_types_1 = require("../../progress-hook/progress-hook.types");
|
|
20
|
+
const progress_hook_1 = tslib_1.__importDefault(require("../../progress-hook/progress-hook"));
|
|
19
21
|
const account_1 = require("../../universal/account/account");
|
|
20
22
|
const push_client_1 = require("../../push-client/push-client");
|
|
21
23
|
const route_detector_1 = require("../route-detector");
|
|
@@ -23,7 +25,39 @@ const context_1 = require("./context");
|
|
|
23
25
|
const helpers_1 = require("./helpers");
|
|
24
26
|
const svm_helpers_1 = require("./svm-helpers");
|
|
25
27
|
const outbound_tracker_1 = require("./outbound-tracker");
|
|
28
|
+
const inbound_tracker_1 = require("./inbound-tracker");
|
|
26
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
|
+
}
|
|
27
61
|
// ============================================================================
|
|
28
62
|
// queryUniversalTxStatusFromGatewayTx
|
|
29
63
|
// ============================================================================
|
|
@@ -105,8 +139,8 @@ txHash, evmGatewayMethod) {
|
|
|
105
139
|
}, null, 2));
|
|
106
140
|
// Fetch UniversalTx via gRPC with linear-then-exponential retry
|
|
107
141
|
const LINEAR_ATTEMPTS = 10;
|
|
108
|
-
const LINEAR_DELAY_MS =
|
|
109
|
-
const EXPONENTIAL_BASE_MS =
|
|
142
|
+
const LINEAR_DELAY_MS = 3600;
|
|
143
|
+
const EXPONENTIAL_BASE_MS = 4800;
|
|
110
144
|
const MAX_ATTEMPTS = 15;
|
|
111
145
|
let universalTxObj;
|
|
112
146
|
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
@@ -146,6 +180,7 @@ txHash, evmGatewayMethod) {
|
|
|
146
180
|
// ============================================================================
|
|
147
181
|
function trackTransaction(ctx, txHash, options, callbacks) {
|
|
148
182
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
183
|
+
var _a, _b;
|
|
149
184
|
if (!callbacks) {
|
|
150
185
|
throw new Error('trackTransaction requires ResponseBuilderCallbacks');
|
|
151
186
|
}
|
|
@@ -153,18 +188,13 @@ function trackTransaction(ctx, txHash, options, callbacks) {
|
|
|
153
188
|
const { timeout = 300000, pollingIntervalMs = 1000, rpcUrls = {} } = advanced;
|
|
154
189
|
// Event buffer for replay via response.progressHook()
|
|
155
190
|
const eventBuffer = [];
|
|
156
|
-
// 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.
|
|
157
194
|
const emitProgress = (event) => {
|
|
158
195
|
eventBuffer.push(event);
|
|
159
196
|
(0, context_1.printLog)(ctx, event.message);
|
|
160
|
-
|
|
161
|
-
if (progressHook) {
|
|
162
|
-
progressHook(event);
|
|
163
|
-
}
|
|
164
|
-
// Orchestrator-level hook called SECOND
|
|
165
|
-
if (ctx.progressHook) {
|
|
166
|
-
ctx.progressHook(event);
|
|
167
|
-
}
|
|
197
|
+
fanOut(event, progressHook, ctx.progressHook);
|
|
168
198
|
};
|
|
169
199
|
// Create client for target chain with optional RPC override
|
|
170
200
|
const chainRPCs = rpcUrls[chain] || ctx.rpcUrls[chain] || chain_1.CHAIN_INFO[chain].defaultRPC;
|
|
@@ -203,7 +233,7 @@ function trackTransaction(ctx, txHash, options, callbacks) {
|
|
|
203
233
|
universalTxData = utxResponse.universalTx;
|
|
204
234
|
}
|
|
205
235
|
}
|
|
206
|
-
catch (
|
|
236
|
+
catch (_c) {
|
|
207
237
|
// Ignore - try computed ID next
|
|
208
238
|
}
|
|
209
239
|
if (!universalTxData) {
|
|
@@ -215,7 +245,7 @@ function trackTransaction(ctx, txHash, options, callbacks) {
|
|
|
215
245
|
universalTxData = utxResponse.universalTx;
|
|
216
246
|
}
|
|
217
247
|
}
|
|
218
|
-
catch (
|
|
248
|
+
catch (_d) {
|
|
219
249
|
// Ignore - try Cosmos event extraction next
|
|
220
250
|
}
|
|
221
251
|
}
|
|
@@ -230,7 +260,7 @@ function trackTransaction(ctx, txHash, options, callbacks) {
|
|
|
230
260
|
}
|
|
231
261
|
}
|
|
232
262
|
}
|
|
233
|
-
catch (
|
|
263
|
+
catch (_e) {
|
|
234
264
|
// Ignore - no universal tx data available
|
|
235
265
|
}
|
|
236
266
|
}
|
|
@@ -241,12 +271,48 @@ function trackTransaction(ctx, txHash, options, callbacks) {
|
|
|
241
271
|
const detectedRoute = (0, tx_transformer_1.detectRouteFromUniversalTxData)(universalTxData);
|
|
242
272
|
if (detectedRoute) {
|
|
243
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
|
+
}
|
|
244
297
|
}
|
|
245
298
|
// Reconstruct and emit SEND-TX-* progress events
|
|
246
299
|
const reconstructedEvents = (0, tx_transformer_1.reconstructProgressEvents)(universalTxResponse, universalTxData);
|
|
247
300
|
for (const event of reconstructedEvents) {
|
|
248
301
|
emitProgress(event);
|
|
249
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
|
+
}
|
|
250
316
|
return universalTxResponse;
|
|
251
317
|
});
|
|
252
318
|
}
|
|
@@ -278,18 +344,36 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
278
344
|
}
|
|
279
345
|
from = (0, viem_1.getAddress)(tx.to);
|
|
280
346
|
let decoded;
|
|
347
|
+
let decodedPayload = null;
|
|
281
348
|
if (tx.input !== '0x') {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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;
|
|
288
376
|
}
|
|
289
|
-
const universalPayload = decoded === null || decoded === void 0 ? void 0 : decoded.args[0];
|
|
290
|
-
to = universalPayload.to;
|
|
291
|
-
value = BigInt(universalPayload.value);
|
|
292
|
-
data = universalPayload.data;
|
|
293
377
|
// Extract 'to' from single-element multicall
|
|
294
378
|
if (data && data.length >= 10) {
|
|
295
379
|
const multicallSelector = (0, viem_1.keccak256)((0, viem_1.toBytes)('UEA_MULTICALL')).slice(0, 10);
|
|
@@ -311,7 +395,7 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
311
395
|
to = (0, viem_1.getAddress)(decodedCalls[0].to);
|
|
312
396
|
}
|
|
313
397
|
}
|
|
314
|
-
catch (
|
|
398
|
+
catch (_b) {
|
|
315
399
|
// Keep original 'to' if decoding fails
|
|
316
400
|
}
|
|
317
401
|
}
|
|
@@ -379,7 +463,7 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
379
463
|
from = '0x0000000000000000000000000000000000000000';
|
|
380
464
|
}
|
|
381
465
|
}
|
|
382
|
-
catch (
|
|
466
|
+
catch (_c) {
|
|
383
467
|
// Keep original values if decoding fails
|
|
384
468
|
}
|
|
385
469
|
}
|
|
@@ -395,7 +479,7 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
395
479
|
yParity: tx.yParity,
|
|
396
480
|
};
|
|
397
481
|
}
|
|
398
|
-
catch (
|
|
482
|
+
catch (_d) {
|
|
399
483
|
// Fallback signature if parsing fails
|
|
400
484
|
signature = {
|
|
401
485
|
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
@@ -451,44 +535,159 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
451
535
|
maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
|
|
452
536
|
accessList: Array.isArray(tx.accessList) ? [...tx.accessList] : [],
|
|
453
537
|
// 6. Utilities
|
|
454
|
-
wait: () => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
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);
|
|
470
568
|
// If outbound route, poll for external chain details
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
: undefined;
|
|
569
|
+
const route = universalTxResponse.route;
|
|
570
|
+
const routeInfo = route ? (0, route_detector_1.getRouteInfo)(route) : undefined;
|
|
474
571
|
if (routeInfo === null || routeInfo === void 0 ? void 0 : routeInfo.isOutbound) {
|
|
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));
|
|
594
|
+
let lastEmittedStatus;
|
|
595
|
+
const outboundTranslator = (event) => {
|
|
596
|
+
if (event.status === 'polling' && lastEmittedStatus !== 'polling') {
|
|
597
|
+
lastEmittedStatus = 'polling';
|
|
598
|
+
emit(hooks.polling(targetChain, event.elapsed));
|
|
599
|
+
}
|
|
600
|
+
};
|
|
475
601
|
try {
|
|
476
602
|
const outboundDetails = yield callbacks.waitForOutboundTx(tx.hash, {
|
|
477
|
-
initialWaitMs:
|
|
478
|
-
pollingIntervalMs:
|
|
479
|
-
timeout:
|
|
603
|
+
initialWaitMs: outboundInitialWaitMs,
|
|
604
|
+
pollingIntervalMs: outboundPollingIntervalMs,
|
|
605
|
+
timeout: outboundTimeoutMs,
|
|
606
|
+
progressHook: outboundTranslator,
|
|
480
607
|
});
|
|
608
|
+
emit(hooks.success(outboundDetails));
|
|
481
609
|
// Merge external chain details into receipt
|
|
482
|
-
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
|
+
}
|
|
483
658
|
}
|
|
484
659
|
catch (error) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
660
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
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}`);
|
|
488
679
|
}
|
|
489
680
|
}
|
|
490
681
|
return baseReceipt;
|
|
491
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
|
+
},
|
|
492
691
|
progressHook: (callback) => {
|
|
493
692
|
registeredProgressHook = callback;
|
|
494
693
|
// Immediately replay buffered events from execution
|