@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.
Files changed (86) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/package.json +1 -1
  3. package/src/lib/constants/abi/index.d.ts +2 -0
  4. package/src/lib/constants/abi/index.js +6 -1
  5. package/src/lib/constants/abi/uniswap-v3-router.evm.d.ts +58 -0
  6. package/src/lib/constants/abi/uniswap-v3-router.evm.js +41 -0
  7. package/src/lib/constants/abi/wpc.evm.d.ts +24 -0
  8. package/src/lib/constants/abi/wpc.evm.js +27 -0
  9. package/src/lib/constants/chain.d.ts +1 -0
  10. package/src/lib/constants/chain.js +8 -6
  11. package/src/lib/constants/tokens.js +3 -3
  12. package/src/lib/generated/uexecutor/v2/types.d.ts +14 -0
  13. package/src/lib/generated/uexecutor/v2/types.js +96 -3
  14. package/src/lib/orchestrator/internals/cascade.d.ts +1 -1
  15. package/src/lib/orchestrator/internals/cascade.js +556 -225
  16. package/src/lib/orchestrator/internals/confirmation.js +60 -15
  17. package/src/lib/orchestrator/internals/context.d.ts +23 -0
  18. package/src/lib/orchestrator/internals/context.js +54 -0
  19. package/src/lib/orchestrator/internals/execute-funds-only.js +47 -21
  20. package/src/lib/orchestrator/internals/execute-funds-payload.js +53 -31
  21. package/src/lib/orchestrator/internals/execute-standard.js +137 -26
  22. package/src/lib/orchestrator/internals/gas-calculator.d.ts +5 -2
  23. package/src/lib/orchestrator/internals/gas-calculator.js +59 -11
  24. package/src/lib/orchestrator/internals/gas-usd-sizer.d.ts +53 -0
  25. package/src/lib/orchestrator/internals/gas-usd-sizer.js +165 -0
  26. package/src/lib/orchestrator/internals/helpers.js +2 -0
  27. package/src/lib/orchestrator/internals/inbound-tracker.d.ts +83 -0
  28. package/src/lib/orchestrator/internals/inbound-tracker.js +322 -0
  29. package/src/lib/orchestrator/internals/index.d.ts +3 -1
  30. package/src/lib/orchestrator/internals/index.js +8 -2
  31. package/src/lib/orchestrator/internals/outbound-sync.d.ts +32 -1
  32. package/src/lib/orchestrator/internals/outbound-sync.js +154 -17
  33. package/src/lib/orchestrator/internals/pc-usd-oracle.d.ts +28 -0
  34. package/src/lib/orchestrator/internals/pc-usd-oracle.js +285 -0
  35. package/src/lib/orchestrator/internals/progress-route-hooks.d.ts +23 -0
  36. package/src/lib/orchestrator/internals/progress-route-hooks.js +72 -0
  37. package/src/lib/orchestrator/internals/push-chain-tx.d.ts +27 -1
  38. package/src/lib/orchestrator/internals/push-chain-tx.js +111 -15
  39. package/src/lib/orchestrator/internals/rescue.js +1 -1
  40. package/src/lib/orchestrator/internals/response-builder.d.ts +5 -0
  41. package/src/lib/orchestrator/internals/response-builder.js +252 -53
  42. package/src/lib/orchestrator/internals/route-handlers.js +480 -206
  43. package/src/lib/orchestrator/internals/tx-transformer.js +293 -35
  44. package/src/lib/orchestrator/orchestrator.d.ts +7 -1
  45. package/src/lib/orchestrator/orchestrator.js +108 -56
  46. package/src/lib/orchestrator/orchestrator.types.d.ts +120 -5
  47. package/src/lib/orchestrator/payload-builders.d.ts +16 -0
  48. package/src/lib/orchestrator/payload-builders.js +6 -5
  49. package/src/lib/orchestrator/route-detector.js +20 -8
  50. package/src/lib/orchestrator/svm-idl/normalize-address.d.ts +19 -0
  51. package/src/lib/orchestrator/svm-idl/normalize-address.js +56 -0
  52. package/src/lib/orchestrator/svm-idl/registry.d.ts +13 -4
  53. package/src/lib/orchestrator/svm-idl/registry.js +15 -14
  54. package/src/lib/orchestrator/svm-idl/resolve.js +5 -2
  55. package/src/lib/progress-hook/progress-hook.d.ts +28 -0
  56. package/src/lib/progress-hook/progress-hook.js +555 -101
  57. package/src/lib/progress-hook/progress-hook.types.d.ts +76 -24
  58. package/src/lib/progress-hook/progress-hook.types.js +74 -29
  59. package/src/lib/push-client/push-client.d.ts +7 -0
  60. package/src/lib/push-client/push-client.js +18 -1
  61. package/src/lib/universal-tx-detector/__tests__/fixtures/builders.d.ts +32 -0
  62. package/src/lib/universal-tx-detector/__tests__/fixtures/builders.js +65 -0
  63. package/src/lib/universal-tx-detector/__tests__/fixtures/scenarios.d.ts +72 -0
  64. package/src/lib/universal-tx-detector/__tests__/fixtures/scenarios.js +669 -0
  65. package/src/lib/universal-tx-detector/auto-detect.d.ts +37 -0
  66. package/src/lib/universal-tx-detector/auto-detect.js +112 -0
  67. package/src/lib/universal-tx-detector/cascade.d.ts +64 -0
  68. package/src/lib/universal-tx-detector/cascade.js +254 -0
  69. package/src/lib/universal-tx-detector/child-inbounds.d.ts +58 -0
  70. package/src/lib/universal-tx-detector/child-inbounds.js +145 -0
  71. package/src/lib/universal-tx-detector/classify.d.ts +33 -0
  72. package/src/lib/universal-tx-detector/classify.js +228 -0
  73. package/src/lib/universal-tx-detector/detector-svm.d.ts +46 -0
  74. package/src/lib/universal-tx-detector/detector-svm.js +324 -0
  75. package/src/lib/universal-tx-detector/detector.d.ts +13 -0
  76. package/src/lib/universal-tx-detector/detector.js +233 -0
  77. package/src/lib/universal-tx-detector/events.d.ts +765 -0
  78. package/src/lib/universal-tx-detector/events.js +241 -0
  79. package/src/lib/universal-tx-detector/index.d.ts +18 -0
  80. package/src/lib/universal-tx-detector/index.js +36 -0
  81. package/src/lib/universal-tx-detector/svm-events.d.ts +41 -0
  82. package/src/lib/universal-tx-detector/svm-events.js +68 -0
  83. package/src/lib/universal-tx-detector/types.d.ts +100 -0
  84. package/src/lib/universal-tx-detector/types.js +3 -0
  85. package/src/lib/utils.d.ts +30 -13
  86. package/src/lib/utils.js +47 -21
@@ -0,0 +1,83 @@
1
+ /**
2
+ * R3 inbound-to-Push tracking. After CEA executes on the source chain
3
+ * (R3 outbound poll completes with 309-03), the source-chain CEA fires
4
+ * `sendUniversalTxToUEA` which produces a child UniversalTx whose pcTx[0]
5
+ * is the inbound Push Chain tx that closes the round-trip.
6
+ *
7
+ * The correlation mechanism mirrors `scripts/poll-outbound.ts` Step D:
8
+ * 1. Search Cosmos for `universal_tx_created.inbound_tx_hash='${extHash}'`
9
+ * and pull the child `utx_id` from the resulting events.
10
+ * 2. Query the child UTX via `getUniversalTxByIdV2(utxId)`. Its `pcTx[0]`
11
+ * is the inbound Push Chain tx; its `universalStatus` tells us terminal.
12
+ */
13
+ import type { OrchestratorContext } from './context';
14
+ export type InboundPushTxStatus = 'pending' | 'confirmed' | 'failed';
15
+ export interface InboundPushTxDetails {
16
+ /** The Push Chain tx hash that processed the inbound from the CEA. */
17
+ pushTxHash: string;
18
+ /** Child UTX id (Push Chain UniversalTx that owns the inbound). */
19
+ childUtxId: string;
20
+ /** Source chain that the CEA executed on. */
21
+ sourceChain: string;
22
+ /** External tx hash used as the correlation key. */
23
+ outboundExternalTxHash: string;
24
+ /** Final status of the inbound execution. */
25
+ status: InboundPushTxStatus;
26
+ /** Error message when status === 'failed'. */
27
+ errorMessage?: string;
28
+ }
29
+ export interface WaitForInboundOptions {
30
+ initialWaitMs?: number;
31
+ pollingIntervalMs?: number;
32
+ /** Total timeout from the call site (includes initialWaitMs). */
33
+ timeout?: number;
34
+ /** Optional callback for streamed status updates. */
35
+ progressHook?: (event: {
36
+ status: 'waiting' | 'polling' | 'found' | 'confirmed' | 'failed' | 'timeout';
37
+ elapsedMs: number;
38
+ childUtxId?: string;
39
+ pushTxHash?: string;
40
+ }) => void;
41
+ }
42
+ /**
43
+ * Resolves the child UTX id for an R3 round-trip from the source-chain tx.
44
+ *
45
+ * Primary path: use the universal-tx-detector to parse the source-chain
46
+ * receipt, locate the `UniversalTx(fromCEA=true)` log emitted by the CEA's
47
+ * `sendUniversalTxToUEA` call, and derive the child utxId via the
48
+ * deterministic `sha256(caip:txHash:logIndex)` formula. This bypasses the
49
+ * cosmos `universal_tx_created.inbound_tx_hash` indexer which has been
50
+ * unreliable on testnet.
51
+ *
52
+ * Fallback: the original cosmos text search, kept in place so if the
53
+ * indexer ever becomes the source of truth again (or the detector path
54
+ * hits an RPC snag for the source chain) we still have a second chance.
55
+ *
56
+ * Returns `{ utxId: string }` on hit, `{ utxId: null }` when neither path
57
+ * has seen it yet, or `{ utxId: null, error }` when both paths failed with
58
+ * recoverable RPC errors.
59
+ */
60
+ export declare function findChildUtxIdFromExternalTx(ctx: OrchestratorContext, externalTxHash: string, sourceChain?: string): Promise<{
61
+ utxId: string | null;
62
+ error?: Error;
63
+ derivedFrom?: 'detector' | 'cosmos-fallback';
64
+ }>;
65
+ /**
66
+ * Polls Push Chain for the inbound tx that closes an R3 round-trip.
67
+ * Resolves when the child UTX reaches a terminal state (success/failure) or
68
+ * rejects with a Timeout error if neither child UTX nor terminal state is
69
+ * observed within the configured timeout.
70
+ */
71
+ export declare function waitForInboundPushTx(ctx: OrchestratorContext, outboundExternalTxHash: string, sourceChain: string, opts?: WaitForInboundOptions): Promise<InboundPushTxDetails>;
72
+ /**
73
+ * Thrown by `waitForInboundPushTx` when the polling loop exceeds the
74
+ * configured timeout without observing a terminal inbound Push tx. Callers
75
+ * (response-builder) `instanceof`-check to distinguish timeout (→ 399-03)
76
+ * from generic failure (→ 399-02) without relying on error-message prefixes.
77
+ */
78
+ export declare class InboundTimeoutError extends Error {
79
+ readonly code: "INBOUND_TIMEOUT";
80
+ readonly correlationKey: string;
81
+ readonly elapsedMs: number;
82
+ constructor(correlationKey: string, elapsedMs: number);
83
+ }
@@ -0,0 +1,322 @@
1
+ "use strict";
2
+ /**
3
+ * R3 inbound-to-Push tracking. After CEA executes on the source chain
4
+ * (R3 outbound poll completes with 309-03), the source-chain CEA fires
5
+ * `sendUniversalTxToUEA` which produces a child UniversalTx whose pcTx[0]
6
+ * is the inbound Push Chain tx that closes the round-trip.
7
+ *
8
+ * The correlation mechanism mirrors `scripts/poll-outbound.ts` Step D:
9
+ * 1. Search Cosmos for `universal_tx_created.inbound_tx_hash='${extHash}'`
10
+ * and pull the child `utx_id` from the resulting events.
11
+ * 2. Query the child UTX via `getUniversalTxByIdV2(utxId)`. Its `pcTx[0]`
12
+ * is the inbound Push Chain tx; its `universalStatus` tells us terminal.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.InboundTimeoutError = void 0;
16
+ exports.findChildUtxIdFromExternalTx = findChildUtxIdFromExternalTx;
17
+ exports.waitForInboundPushTx = waitForInboundPushTx;
18
+ const tslib_1 = require("tslib");
19
+ const types_1 = require("../../generated/uexecutor/v2/types");
20
+ const context_1 = require("./context");
21
+ const detector_1 = require("../../universal-tx-detector/detector");
22
+ const child_inbounds_1 = require("../../universal-tx-detector/child-inbounds");
23
+ const TERMINAL_SUCCESS_STATUSES = new Set([
24
+ types_1.UniversalTxStatus.INBOUND_SUCCESS,
25
+ types_1.UniversalTxStatus.PC_EXECUTED_SUCCESS,
26
+ ]);
27
+ const TERMINAL_FAILURE_STATUSES = new Set([
28
+ types_1.UniversalTxStatus.PC_EXECUTED_FAILED,
29
+ types_1.UniversalTxStatus.PC_PENDING_REVERT,
30
+ types_1.UniversalTxStatus.OUTBOUND_FAILED,
31
+ types_1.UniversalTxStatus.CANCELED,
32
+ ]);
33
+ const stripHex = (id) => id.startsWith('0x') ? id.slice(2) : id;
34
+ const ensureHex = (id) => id.startsWith('0x') ? id : `0x${id}`;
35
+ /**
36
+ * Resolves the child UTX id for an R3 round-trip from the source-chain tx.
37
+ *
38
+ * Primary path: use the universal-tx-detector to parse the source-chain
39
+ * receipt, locate the `UniversalTx(fromCEA=true)` log emitted by the CEA's
40
+ * `sendUniversalTxToUEA` call, and derive the child utxId via the
41
+ * deterministic `sha256(caip:txHash:logIndex)` formula. This bypasses the
42
+ * cosmos `universal_tx_created.inbound_tx_hash` indexer which has been
43
+ * unreliable on testnet.
44
+ *
45
+ * Fallback: the original cosmos text search, kept in place so if the
46
+ * indexer ever becomes the source of truth again (or the detector path
47
+ * hits an RPC snag for the source chain) we still have a second chance.
48
+ *
49
+ * Returns `{ utxId: string }` on hit, `{ utxId: null }` when neither path
50
+ * has seen it yet, or `{ utxId: null, error }` when both paths failed with
51
+ * recoverable RPC errors.
52
+ */
53
+ function findChildUtxIdFromExternalTx(ctx, externalTxHash, sourceChain) {
54
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
55
+ var _a, _b, _c;
56
+ // Primary: detector-based deterministic derivation.
57
+ if (sourceChain) {
58
+ try {
59
+ const detection = yield (0, detector_1.detectUniversalTx)(externalTxHash, sourceChain, {
60
+ pushClient: ctx.pushClient,
61
+ rpcUrls: ctx.rpcUrls,
62
+ skipPushChainLookup: true,
63
+ });
64
+ const resolutions = yield (0, child_inbounds_1.resolveChildInboundsFromDetection)(ctx.pushClient, detection);
65
+ // Pick the R3 return-trip child: prefer UniversalTx over RevertUniversalTx.
66
+ const match = (_a = resolutions.find((r) => r.sourceEventName === 'UniversalTx')) !== null && _a !== void 0 ? _a : resolutions[0];
67
+ if (match === null || match === void 0 ? void 0 : match.universalTxId) {
68
+ (0, context_1.printLog)(ctx, `[findChildUtxIdFromExternalTx] detector derived utxId ${match.universalTxId} for ${externalTxHash} on ${sourceChain}`);
69
+ return { utxId: ensureHex(match.universalTxId), derivedFrom: 'detector' };
70
+ }
71
+ }
72
+ catch (err) {
73
+ const wrapped = err instanceof Error ? err : new Error(String(err));
74
+ (0, context_1.printLog)(ctx, `[findChildUtxIdFromExternalTx] detector path failed: ${wrapped.message} — falling back to cosmos search`);
75
+ // Fall through to cosmos search.
76
+ }
77
+ }
78
+ // Fallback: cosmos text search (original path).
79
+ try {
80
+ const query = `universal_tx_created.inbound_tx_hash='${externalTxHash}'`;
81
+ const results = yield ctx.pushClient.searchCosmosByQuery(query);
82
+ for (const tx of results) {
83
+ for (const event of (_b = tx.events) !== null && _b !== void 0 ? _b : []) {
84
+ if (event.type === 'universal_tx_created' ||
85
+ event.type === 'outbound_created') {
86
+ for (const attr of (_c = event.attributes) !== null && _c !== void 0 ? _c : []) {
87
+ if (attr.key === 'utx_id' && attr.value) {
88
+ return {
89
+ utxId: ensureHex(attr.value),
90
+ derivedFrom: 'cosmos-fallback',
91
+ };
92
+ }
93
+ }
94
+ }
95
+ }
96
+ }
97
+ return { utxId: null };
98
+ }
99
+ catch (err) {
100
+ const wrapped = err instanceof Error ? err : new Error(String(err));
101
+ (0, context_1.printLog)(ctx, `[findChildUtxIdFromExternalTx] cosmos fallback also failed: ${wrapped.message}`);
102
+ return { utxId: null, error: wrapped };
103
+ }
104
+ });
105
+ }
106
+ /**
107
+ * Polls Push Chain for the inbound tx that closes an R3 round-trip.
108
+ * Resolves when the child UTX reaches a terminal state (success/failure) or
109
+ * rejects with a Timeout error if neither child UTX nor terminal state is
110
+ * observed within the configured timeout.
111
+ */
112
+ function waitForInboundPushTx(ctx_1, outboundExternalTxHash_1, sourceChain_1) {
113
+ return tslib_1.__awaiter(this, arguments, void 0, function* (ctx, outboundExternalTxHash, sourceChain, opts = {}) {
114
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
115
+ const initialWaitMs = (_a = opts.initialWaitMs) !== null && _a !== void 0 ? _a : 30000;
116
+ const pollingIntervalMs = (_b = opts.pollingIntervalMs) !== null && _b !== void 0 ? _b : 5000;
117
+ const timeout = (_c = opts.timeout) !== null && _c !== void 0 ? _c : 300000;
118
+ const progressHook = opts.progressHook;
119
+ const startedAt = Date.now();
120
+ const elapsed = () => Date.now() - startedAt;
121
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] Starting | externalTxHash: ${outboundExternalTxHash} | sourceChain: ${sourceChain} | initialWait: ${initialWaitMs}ms | pollInterval: ${pollingIntervalMs}ms | timeout: ${timeout}ms`);
122
+ progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'waiting', elapsedMs: 0 });
123
+ if (initialWaitMs > 0) {
124
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] Initial wait of ${initialWaitMs}ms...`);
125
+ yield new Promise((r) => setTimeout(r, Math.min(initialWaitMs, timeout)));
126
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] Initial wait done. Starting polling. Elapsed: ${elapsed()}ms`);
127
+ }
128
+ let childUtxId = null;
129
+ let strippedChildUtxId;
130
+ let pushTxHash;
131
+ let lastEmittedStatus;
132
+ let consecutiveRpcErrors = 0;
133
+ let pendingTerminalSuccessRetries = 0;
134
+ let pollCount = 0;
135
+ // Heuristic threshold — log a distinct warning when this many back-to-back
136
+ // RPC failures happen so callers can see the difference between
137
+ // "indexer hasn't seen it yet" and "RPC is down."
138
+ const RPC_FAILURE_WARN_THRESHOLD = 5;
139
+ // When chain reports terminal success but pcTx hasn't populated yet, give
140
+ // the indexer one extra poll cycle to catch up before returning empty hash.
141
+ const MAX_PENDING_TERMINAL_RETRIES = 2;
142
+ while (elapsed() < timeout) {
143
+ pollCount++;
144
+ const pollStart = Date.now();
145
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] Poll #${pollCount} | Elapsed: ${elapsed()}ms / ${timeout}ms | phase: ${childUtxId ? 'utx-status' : 'child-search'}`);
146
+ // Phase 1 — find child UTX id from the outbound external tx hash
147
+ if (!childUtxId) {
148
+ const search = yield findChildUtxIdFromExternalTx(ctx, outboundExternalTxHash, sourceChain);
149
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] Poll #${pollCount} child-search result: utxId=${(_d = search.utxId) !== null && _d !== void 0 ? _d : 'null'}${search.error ? ` error=${search.error.message}` : ''}`);
150
+ if (search.error) {
151
+ consecutiveRpcErrors++;
152
+ if (consecutiveRpcErrors === RPC_FAILURE_WARN_THRESHOLD) {
153
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] ${RPC_FAILURE_WARN_THRESHOLD} consecutive Cosmos search errors — RPC may be unhealthy. Continuing until timeout.`);
154
+ }
155
+ }
156
+ else {
157
+ consecutiveRpcErrors = 0;
158
+ if (search.utxId) {
159
+ childUtxId = search.utxId;
160
+ strippedChildUtxId = stripHex(childUtxId);
161
+ progressHook === null || progressHook === void 0 ? void 0 : progressHook({
162
+ status: 'found',
163
+ elapsedMs: elapsed(),
164
+ childUtxId,
165
+ });
166
+ lastEmittedStatus = 'found';
167
+ }
168
+ else if (lastEmittedStatus !== 'polling') {
169
+ progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'polling', elapsedMs: elapsed() });
170
+ lastEmittedStatus = 'polling';
171
+ }
172
+ }
173
+ }
174
+ // Phase 2 — once we have the child UTX, query its status until terminal
175
+ if (childUtxId && strippedChildUtxId) {
176
+ try {
177
+ const response = yield ctx.pushClient.getUniversalTxByIdV2(strippedChildUtxId);
178
+ consecutiveRpcErrors = 0;
179
+ const utx = response === null || response === void 0 ? void 0 : response.universalTx;
180
+ const status = (_e = utx === null || utx === void 0 ? void 0 : utx.universalStatus) !== null && _e !== void 0 ? _e : -1;
181
+ if ((_g = (_f = utx === null || utx === void 0 ? void 0 : utx.pcTx) === null || _f === void 0 ? void 0 : _f[0]) === null || _g === void 0 ? void 0 : _g.txHash) {
182
+ pushTxHash = utx.pcTx[0].txHash;
183
+ }
184
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] Poll #${pollCount} utx-status | status: ${status} | pcTx[0].txHash: '${pushTxHash !== null && pushTxHash !== void 0 ? pushTxHash : ''}' | pcTx len: ${(_j = (_h = utx === null || utx === void 0 ? void 0 : utx.pcTx) === null || _h === void 0 ? void 0 : _h.length) !== null && _j !== void 0 ? _j : 0}`);
185
+ if (TERMINAL_SUCCESS_STATUSES.has(status)) {
186
+ // Wait one more poll cycle if pcTx hasn't populated yet — the
187
+ // indexer occasionally flips status before the pcTx hash is queryable.
188
+ if (!pushTxHash && pendingTerminalSuccessRetries < MAX_PENDING_TERMINAL_RETRIES) {
189
+ pendingTerminalSuccessRetries++;
190
+ }
191
+ else {
192
+ progressHook === null || progressHook === void 0 ? void 0 : progressHook({
193
+ status: 'confirmed',
194
+ elapsedMs: elapsed(),
195
+ childUtxId,
196
+ pushTxHash,
197
+ });
198
+ return {
199
+ childUtxId,
200
+ pushTxHash: pushTxHash !== null && pushTxHash !== void 0 ? pushTxHash : '',
201
+ sourceChain,
202
+ outboundExternalTxHash,
203
+ status: 'confirmed',
204
+ };
205
+ }
206
+ }
207
+ else if (TERMINAL_FAILURE_STATUSES.has(status)) {
208
+ const errMsg = ((_l = (_k = utx === null || utx === void 0 ? void 0 : utx.pcTx) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l.errorMsg) ||
209
+ `inbound terminated with status ${status}`;
210
+ progressHook === null || progressHook === void 0 ? void 0 : progressHook({
211
+ status: 'failed',
212
+ elapsedMs: elapsed(),
213
+ childUtxId,
214
+ pushTxHash,
215
+ });
216
+ return {
217
+ childUtxId,
218
+ pushTxHash: pushTxHash !== null && pushTxHash !== void 0 ? pushTxHash : '',
219
+ sourceChain,
220
+ outboundExternalTxHash,
221
+ status: 'failed',
222
+ errorMessage: errMsg,
223
+ };
224
+ }
225
+ else if (pushTxHash) {
226
+ // Tiebreaker: cosmos has the Push Chain tx hash populated but the
227
+ // indexer hasn't transitioned universalStatus to a terminal yet.
228
+ // Query Push RPC directly for the receipt — if it's confirmed on
229
+ // chain, treat as terminal-success; if it reverted, treat as
230
+ // terminal-failure. Cosmos-indexer lag stops blocking us here.
231
+ try {
232
+ const receipt = yield ctx.pushClient.publicClient.getTransactionReceipt({
233
+ hash: pushTxHash,
234
+ });
235
+ if ((receipt === null || receipt === void 0 ? void 0 : receipt.status) === 'success') {
236
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] Push RPC tiebreaker: ${pushTxHash} confirmed on chain (cosmos still status=${status}); treating as terminal-success`);
237
+ progressHook === null || progressHook === void 0 ? void 0 : progressHook({
238
+ status: 'confirmed',
239
+ elapsedMs: elapsed(),
240
+ childUtxId,
241
+ pushTxHash,
242
+ });
243
+ return {
244
+ childUtxId,
245
+ pushTxHash,
246
+ sourceChain,
247
+ outboundExternalTxHash,
248
+ status: 'confirmed',
249
+ };
250
+ }
251
+ if ((receipt === null || receipt === void 0 ? void 0 : receipt.status) === 'reverted') {
252
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] Push RPC tiebreaker: ${pushTxHash} REVERTED on chain (cosmos still status=${status}); treating as terminal-failure`);
253
+ progressHook === null || progressHook === void 0 ? void 0 : progressHook({
254
+ status: 'failed',
255
+ elapsedMs: elapsed(),
256
+ childUtxId,
257
+ pushTxHash,
258
+ });
259
+ return {
260
+ childUtxId,
261
+ pushTxHash,
262
+ sourceChain,
263
+ outboundExternalTxHash,
264
+ status: 'failed',
265
+ errorMessage: 'Push Chain inbound tx reverted on chain',
266
+ };
267
+ }
268
+ // receipt missing / pending — keep polling.
269
+ }
270
+ catch (rpcErr) {
271
+ // TransactionReceiptNotFoundError means not yet mined — continue
272
+ // polling. Other errors get logged but don't break the loop.
273
+ const msg = rpcErr instanceof Error ? rpcErr.message : String(rpcErr);
274
+ if (!/not found|TransactionReceiptNotFound|could not be found/i.test(msg)) {
275
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] Push RPC tiebreaker failed for ${pushTxHash}: ${msg}`);
276
+ }
277
+ }
278
+ }
279
+ }
280
+ catch (err) {
281
+ consecutiveRpcErrors++;
282
+ if (consecutiveRpcErrors === RPC_FAILURE_WARN_THRESHOLD) {
283
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] ${RPC_FAILURE_WARN_THRESHOLD} consecutive getUniversalTxByIdV2 errors — RPC may be unhealthy. Continuing until timeout.`);
284
+ }
285
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] getUniversalTxByIdV2 failed: ${err instanceof Error ? err.message : String(err)}`);
286
+ }
287
+ if (lastEmittedStatus !== 'polling') {
288
+ progressHook === null || progressHook === void 0 ? void 0 : progressHook({
289
+ status: 'polling',
290
+ elapsedMs: elapsed(),
291
+ childUtxId,
292
+ });
293
+ lastEmittedStatus = 'polling';
294
+ }
295
+ }
296
+ if (elapsed() >= timeout)
297
+ break;
298
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] Poll #${pollCount} not ready (${Date.now() - pollStart}ms). Waiting ${pollingIntervalMs}ms...`);
299
+ yield new Promise((r) => setTimeout(r, pollingIntervalMs));
300
+ }
301
+ (0, context_1.printLog)(ctx, `[waitForInboundPushTx] TIMEOUT after ${pollCount} polls | elapsed: ${elapsed()}ms`);
302
+ progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'timeout', elapsedMs: elapsed() });
303
+ throw new InboundTimeoutError(outboundExternalTxHash, elapsed());
304
+ });
305
+ }
306
+ /**
307
+ * Thrown by `waitForInboundPushTx` when the polling loop exceeds the
308
+ * configured timeout without observing a terminal inbound Push tx. Callers
309
+ * (response-builder) `instanceof`-check to distinguish timeout (→ 399-03)
310
+ * from generic failure (→ 399-02) without relying on error-message prefixes.
311
+ */
312
+ class InboundTimeoutError extends Error {
313
+ constructor(correlationKey, elapsedMs) {
314
+ super(`Timeout waiting for inbound Push tx after ${Math.round(elapsedMs / 1000)}s (correlation key: ${correlationKey}).`);
315
+ this.code = 'INBOUND_TIMEOUT';
316
+ this.name = 'InboundTimeoutError';
317
+ this.correlationKey = correlationKey;
318
+ this.elapsedMs = elapsedMs;
319
+ }
320
+ }
321
+ exports.InboundTimeoutError = InboundTimeoutError;
322
+ //# sourceMappingURL=inbound-tracker.js.map
@@ -6,7 +6,9 @@ export { computeExecutionHash, computeMigrationHash, signUniversalPayload, signM
6
6
  export { waitForEvmConfirmationsWithCountdown, waitForSvmConfirmationsWithCountdown, waitForLockerFeeConfirmation, } from './confirmation';
7
7
  export { buildSvmUniversalTxRequest, buildSvmUniversalTxRequestFromReq, getSvmProtocolFee, getSvmGatewayLogIndexFromTx, } from './svm-helpers';
8
8
  export { computeUniversalTxId, extractUniversalSubTxIdFromTx, extractAllUniversalSubTxIds, } from './outbound-tracker';
9
- export { waitForOutboundTx, waitForAllOutboundTxsV2, OUTBOUND_INITIAL_WAIT_MS, OUTBOUND_POLL_INTERVAL_MS, OUTBOUND_MAX_TIMEOUT_MS, } from './outbound-sync';
9
+ export { waitForOutboundTx, waitForAllOutboundTxsV2, OUTBOUND_INITIAL_WAIT_MS, OUTBOUND_POLL_INTERVAL_MS, OUTBOUND_MAX_TIMEOUT_MS, INBOUND_INITIAL_WAIT_MS, INBOUND_MAX_TIMEOUT_MS, } from './outbound-sync';
10
+ export { findChildUtxIdFromExternalTx, waitForInboundPushTx, } from './inbound-tracker';
11
+ export type { InboundPushTxDetails, InboundPushTxStatus, WaitForInboundOptions, } from './inbound-tracker';
10
12
  export { transformToUniversalTxReceipt, reconstructProgressEvents, detectRouteFromUniversalTxData, } from './tx-transformer';
11
13
  export { ensureErc20Allowance, queryOutboundGasFee, queryRescueGasFee, calculateNativeAmountForDeposit, calculateGasAmountFromAmountOutMinETH, } from './gas-calculator';
12
14
  export { quoteExactOutput } from './quote';
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getUeaNonceForExecution = exports.getUEANonce = exports.computeUEA = exports.computeUEAOffchain = exports.quoteExactOutput = exports.calculateGasAmountFromAmountOutMinETH = exports.calculateNativeAmountForDeposit = exports.queryRescueGasFee = exports.queryOutboundGasFee = exports.ensureErc20Allowance = exports.detectRouteFromUniversalTxData = exports.reconstructProgressEvents = exports.transformToUniversalTxReceipt = exports.OUTBOUND_MAX_TIMEOUT_MS = exports.OUTBOUND_POLL_INTERVAL_MS = exports.OUTBOUND_INITIAL_WAIT_MS = exports.waitForAllOutboundTxsV2 = exports.waitForOutboundTx = exports.extractAllUniversalSubTxIds = exports.extractUniversalSubTxIdFromTx = exports.computeUniversalTxId = exports.getSvmGatewayLogIndexFromTx = exports.getSvmProtocolFee = exports.buildSvmUniversalTxRequestFromReq = exports.buildSvmUniversalTxRequest = exports.waitForLockerFeeConfirmation = exports.waitForSvmConfirmationsWithCountdown = exports.waitForEvmConfirmationsWithCountdown = exports.encodeUniversalPayloadSvm = exports.encodeUniversalPayload = exports.signMigrationPayload = exports.signUniversalPayload = exports.computeMigrationHash = exports.computeExecutionHash = exports.buildGatewayPayloadAndGas = exports.buildMulticallPayloadData = exports.buildUniversalTxRequest = exports.SUPPORTED_GATEWAY_CHAINS = exports.fetchOriginChainTransactionForProgress = exports.toExecuteParams = exports.bigintReplacer = exports.validateMainnetConnection = exports.getUniversalGatewayPCAddress = exports.getNativePRC20ForChain = exports.chainFromNamespace = exports.getChainNamespace = exports.getPushChainForNetwork = exports.isPushChain = exports.fireProgressHook = exports.printLog = void 0;
4
- exports.executeStandardPayload = exports.executeFundsWithPayload = exports.executeFundsOnly = exports.rescueFunds = exports.sendSVMTxWithFunds = exports.createCascadedBuilder = exports.composeCascade = exports.getSegmentType = exports.classifyIntoSegments = exports.buildHopDescriptor = exports.prepareTransaction = exports.buildPayloadForRoute = exports.executeCeaToCea = exports.executeCeaToPushSvm = exports.executeCeaToPush = exports.executeUoaToCeaSvm = exports.executeUoaToCea = exports.executeMultiChain = exports.extractPcTxAndTransform = exports.sendUniversalTx = exports.sendPushTx = exports.transformToUniversalTxResponse = exports.trackTransaction = exports.queryUniversalTxStatusFromGatewayTx = exports.getOriginGatewayContext = exports.lockFee = exports.sendGatewayTokenTxWithFallback = exports.sendGatewayTxWithFallback = exports.toGatewayTokenRequestV1 = exports.toGatewayRequestV1 = exports.migrateCEA = exports.fetchLatestUEAVersion = exports.upgradeAccount = exports.getAccountStatus = exports.fetchUEAVersion = exports.getUeaStatusAndNonce = void 0;
3
+ exports.quoteExactOutput = exports.calculateGasAmountFromAmountOutMinETH = exports.calculateNativeAmountForDeposit = exports.queryRescueGasFee = exports.queryOutboundGasFee = exports.ensureErc20Allowance = exports.detectRouteFromUniversalTxData = exports.reconstructProgressEvents = exports.transformToUniversalTxReceipt = exports.waitForInboundPushTx = exports.findChildUtxIdFromExternalTx = exports.INBOUND_MAX_TIMEOUT_MS = exports.INBOUND_INITIAL_WAIT_MS = exports.OUTBOUND_MAX_TIMEOUT_MS = exports.OUTBOUND_POLL_INTERVAL_MS = exports.OUTBOUND_INITIAL_WAIT_MS = exports.waitForAllOutboundTxsV2 = exports.waitForOutboundTx = exports.extractAllUniversalSubTxIds = exports.extractUniversalSubTxIdFromTx = exports.computeUniversalTxId = exports.getSvmGatewayLogIndexFromTx = exports.getSvmProtocolFee = exports.buildSvmUniversalTxRequestFromReq = exports.buildSvmUniversalTxRequest = exports.waitForLockerFeeConfirmation = exports.waitForSvmConfirmationsWithCountdown = exports.waitForEvmConfirmationsWithCountdown = exports.encodeUniversalPayloadSvm = exports.encodeUniversalPayload = exports.signMigrationPayload = exports.signUniversalPayload = exports.computeMigrationHash = exports.computeExecutionHash = exports.buildGatewayPayloadAndGas = exports.buildMulticallPayloadData = exports.buildUniversalTxRequest = exports.SUPPORTED_GATEWAY_CHAINS = exports.fetchOriginChainTransactionForProgress = exports.toExecuteParams = exports.bigintReplacer = exports.validateMainnetConnection = exports.getUniversalGatewayPCAddress = exports.getNativePRC20ForChain = exports.chainFromNamespace = exports.getChainNamespace = exports.getPushChainForNetwork = exports.isPushChain = exports.fireProgressHook = exports.printLog = void 0;
4
+ exports.executeStandardPayload = exports.executeFundsWithPayload = exports.executeFundsOnly = exports.rescueFunds = exports.sendSVMTxWithFunds = exports.createCascadedBuilder = exports.composeCascade = exports.getSegmentType = exports.classifyIntoSegments = exports.buildHopDescriptor = exports.prepareTransaction = exports.buildPayloadForRoute = exports.executeCeaToCea = exports.executeCeaToPushSvm = exports.executeCeaToPush = exports.executeUoaToCeaSvm = exports.executeUoaToCea = exports.executeMultiChain = exports.extractPcTxAndTransform = exports.sendUniversalTx = exports.sendPushTx = exports.transformToUniversalTxResponse = exports.trackTransaction = exports.queryUniversalTxStatusFromGatewayTx = exports.getOriginGatewayContext = exports.lockFee = exports.sendGatewayTokenTxWithFallback = exports.sendGatewayTxWithFallback = exports.toGatewayTokenRequestV1 = exports.toGatewayRequestV1 = exports.migrateCEA = exports.fetchLatestUEAVersion = exports.upgradeAccount = exports.getAccountStatus = exports.fetchUEAVersion = exports.getUeaStatusAndNonce = exports.getUeaNonceForExecution = exports.getUEANonce = exports.computeUEA = exports.computeUEAOffchain = void 0;
5
5
  var context_1 = require("./context");
6
6
  Object.defineProperty(exports, "printLog", { enumerable: true, get: function () { return context_1.printLog; } });
7
7
  Object.defineProperty(exports, "fireProgressHook", { enumerable: true, get: function () { return context_1.fireProgressHook; } });
@@ -53,6 +53,12 @@ Object.defineProperty(exports, "waitForAllOutboundTxsV2", { enumerable: true, ge
53
53
  Object.defineProperty(exports, "OUTBOUND_INITIAL_WAIT_MS", { enumerable: true, get: function () { return outbound_sync_1.OUTBOUND_INITIAL_WAIT_MS; } });
54
54
  Object.defineProperty(exports, "OUTBOUND_POLL_INTERVAL_MS", { enumerable: true, get: function () { return outbound_sync_1.OUTBOUND_POLL_INTERVAL_MS; } });
55
55
  Object.defineProperty(exports, "OUTBOUND_MAX_TIMEOUT_MS", { enumerable: true, get: function () { return outbound_sync_1.OUTBOUND_MAX_TIMEOUT_MS; } });
56
+ Object.defineProperty(exports, "INBOUND_INITIAL_WAIT_MS", { enumerable: true, get: function () { return outbound_sync_1.INBOUND_INITIAL_WAIT_MS; } });
57
+ Object.defineProperty(exports, "INBOUND_MAX_TIMEOUT_MS", { enumerable: true, get: function () { return outbound_sync_1.INBOUND_MAX_TIMEOUT_MS; } });
58
+ // === Inbound Tracking (R3 round-trip) ===
59
+ var inbound_tracker_1 = require("./inbound-tracker");
60
+ Object.defineProperty(exports, "findChildUtxIdFromExternalTx", { enumerable: true, get: function () { return inbound_tracker_1.findChildUtxIdFromExternalTx; } });
61
+ Object.defineProperty(exports, "waitForInboundPushTx", { enumerable: true, get: function () { return inbound_tracker_1.waitForInboundPushTx; } });
56
62
  // === Transaction Transformation ===
57
63
  var tx_transformer_1 = require("./tx-transformer");
58
64
  Object.defineProperty(exports, "transformToUniversalTxReceipt", { enumerable: true, get: function () { return tx_transformer_1.transformToUniversalTxReceipt; } });
@@ -11,8 +11,39 @@ import type { OrchestratorContext } from './context';
11
11
  export declare const OUTBOUND_INITIAL_WAIT_MS = 20000;
12
12
  /** Interval between consecutive polls (ms). */
13
13
  export declare const OUTBOUND_POLL_INTERVAL_MS = 5000;
14
- /** Maximum total timeout for the polling loop (ms). */
14
+ /** Maximum total timeout for the outbound polling loop (ms). */
15
15
  export declare const OUTBOUND_MAX_TIMEOUT_MS = 180000;
16
+ /** Maximum total timeout for the R3 inbound round-trip polling loop (ms). */
17
+ export declare const INBOUND_MAX_TIMEOUT_MS = 300000;
18
+ /** Initial wait before the first inbound poll (ms). Set to 0 — the outbound just completed, so the indexer may already have the child UTX. */
19
+ export declare const INBOUND_INITIAL_WAIT_MS = 0;
20
+ /**
21
+ * Thrown by `waitForOutboundTx` when the polling loop exceeds the configured
22
+ * timeout without observing an external tx hash. Callers can `instanceof`
23
+ * check to distinguish between timeout (→ 299-03) and terminal failure
24
+ * (→ 299-02) without resorting to error-message prefix matching.
25
+ */
26
+ export declare class OutboundTimeoutError extends Error {
27
+ readonly code: "OUTBOUND_TIMEOUT";
28
+ readonly pushChainTxHash: string;
29
+ readonly elapsedMs: number;
30
+ constructor(pushChainTxHash: string, elapsedMs: number, timeoutMs: number);
31
+ }
32
+ /**
33
+ * Thrown by `waitForOutboundTx` when the universal tx reaches a terminal
34
+ * failure state or an outbound leg reports REVERTED status. Distinguishes
35
+ * a *failure* (→ 299-02) from a *timeout* (→ 299-03).
36
+ */
37
+ export declare class OutboundFailedError extends Error {
38
+ readonly code: "OUTBOUND_FAILED";
39
+ readonly pushChainTxHash: string;
40
+ readonly destinationChain?: string;
41
+ /** Observed tx hash on the destination chain (when available). Lets the
42
+ * receipt expose the reverted external tx so consumers can link to the
43
+ * explorer without parsing the error message. */
44
+ readonly externalTxHash?: string;
45
+ constructor(message: string, pushChainTxHash: string, destinationChain?: string, externalTxHash?: string);
46
+ }
16
47
  /**
17
48
  * Wait for outbound transaction to complete and return external chain details.
18
49
  * @internal Used by .wait() for outbound routes - not part of public API.