@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
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
* Extracted from Orchestrator.waitForOutboundTx / waitForAllOutboundTxsV2.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.OUTBOUND_MAX_TIMEOUT_MS = exports.OUTBOUND_POLL_INTERVAL_MS = exports.OUTBOUND_INITIAL_WAIT_MS = void 0;
|
|
9
|
+
exports.OutboundFailedError = exports.OutboundTimeoutError = exports.INBOUND_INITIAL_WAIT_MS = exports.INBOUND_MAX_TIMEOUT_MS = exports.OUTBOUND_MAX_TIMEOUT_MS = exports.OUTBOUND_POLL_INTERVAL_MS = exports.OUTBOUND_INITIAL_WAIT_MS = void 0;
|
|
10
10
|
exports.waitForOutboundTx = waitForOutboundTx;
|
|
11
11
|
exports.waitForAllOutboundTxsV2 = waitForAllOutboundTxsV2;
|
|
12
12
|
const tslib_1 = require("tslib");
|
|
13
|
+
const viem_1 = require("viem");
|
|
13
14
|
const bs58_1 = require("../../internal/bs58");
|
|
14
15
|
const chain_1 = require("../../constants/chain");
|
|
15
16
|
const enums_1 = require("../../constants/enums");
|
|
@@ -25,11 +26,107 @@ const outbound_tracker_1 = require("./outbound-tracker");
|
|
|
25
26
|
exports.OUTBOUND_INITIAL_WAIT_MS = 20000; // 20s
|
|
26
27
|
/** Interval between consecutive polls (ms). */
|
|
27
28
|
exports.OUTBOUND_POLL_INTERVAL_MS = 5000; // 5s
|
|
28
|
-
/** Maximum total timeout for the polling loop (ms). */
|
|
29
|
+
/** Maximum total timeout for the outbound polling loop (ms). */
|
|
29
30
|
exports.OUTBOUND_MAX_TIMEOUT_MS = 180000; // 180s (3 min)
|
|
31
|
+
/** Maximum total timeout for the R3 inbound round-trip polling loop (ms). */
|
|
32
|
+
exports.INBOUND_MAX_TIMEOUT_MS = 300000; // 300s (5 min) — covers R3 inbound latency on testnet
|
|
33
|
+
/** Initial wait before the first inbound poll (ms). Set to 0 — the outbound just completed, so the indexer may already have the child UTX. */
|
|
34
|
+
exports.INBOUND_INITIAL_WAIT_MS = 0;
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// Typed errors
|
|
37
|
+
// ============================================================================
|
|
38
|
+
/**
|
|
39
|
+
* Thrown by `waitForOutboundTx` when the polling loop exceeds the configured
|
|
40
|
+
* timeout without observing an external tx hash. Callers can `instanceof`
|
|
41
|
+
* check to distinguish between timeout (→ 299-03) and terminal failure
|
|
42
|
+
* (→ 299-02) without resorting to error-message prefix matching.
|
|
43
|
+
*/
|
|
44
|
+
class OutboundTimeoutError extends Error {
|
|
45
|
+
constructor(pushChainTxHash, elapsedMs, timeoutMs) {
|
|
46
|
+
super(`Timeout waiting for outbound transaction. Push Chain TX: ${pushChainTxHash}. Timeout: ${timeoutMs}ms. The relay may still be processing.`);
|
|
47
|
+
this.code = 'OUTBOUND_TIMEOUT';
|
|
48
|
+
this.name = 'OutboundTimeoutError';
|
|
49
|
+
this.pushChainTxHash = pushChainTxHash;
|
|
50
|
+
this.elapsedMs = elapsedMs;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.OutboundTimeoutError = OutboundTimeoutError;
|
|
54
|
+
/**
|
|
55
|
+
* Thrown by `waitForOutboundTx` when the universal tx reaches a terminal
|
|
56
|
+
* failure state or an outbound leg reports REVERTED status. Distinguishes
|
|
57
|
+
* a *failure* (→ 299-02) from a *timeout* (→ 299-03).
|
|
58
|
+
*/
|
|
59
|
+
class OutboundFailedError extends Error {
|
|
60
|
+
constructor(message, pushChainTxHash, destinationChain, externalTxHash) {
|
|
61
|
+
super(message);
|
|
62
|
+
this.code = 'OUTBOUND_FAILED';
|
|
63
|
+
this.name = 'OutboundFailedError';
|
|
64
|
+
this.pushChainTxHash = pushChainTxHash;
|
|
65
|
+
this.destinationChain = destinationChain;
|
|
66
|
+
this.externalTxHash = externalTxHash;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.OutboundFailedError = OutboundFailedError;
|
|
30
70
|
// ============================================================================
|
|
31
71
|
// waitForOutboundTx
|
|
32
72
|
// ============================================================================
|
|
73
|
+
/**
|
|
74
|
+
* Source-chain RPC tiebreaker.
|
|
75
|
+
*
|
|
76
|
+
* Cosmos sometimes populates `observedTx.txHash` while the relayer is still
|
|
77
|
+
* voting on the outboundStatus update. The Push indexer can stay at
|
|
78
|
+
* UNSPECIFIED for the full 180s budget even though the destination tx mined
|
|
79
|
+
* minutes earlier. To avoid those false timeouts we ask the destination
|
|
80
|
+
* chain's own RPC: if it has a confirmed receipt with status=success, we
|
|
81
|
+
* trust it and return FOUND; if status=reverted, we throw OutboundFailedError
|
|
82
|
+
* (preserves the silent-success bug fix); if no receipt yet or RPC failure,
|
|
83
|
+
* we keep polling.
|
|
84
|
+
*
|
|
85
|
+
* EVM-only — SVM tiebreaker would need a separate signature lookup path.
|
|
86
|
+
*/
|
|
87
|
+
function verifyExternalEvmReceipt(ctx, destinationChain, externalTxHash) {
|
|
88
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
89
|
+
var _a;
|
|
90
|
+
const chainInfo = chain_1.CHAIN_INFO[destinationChain];
|
|
91
|
+
if (!chainInfo || chainInfo.vm !== enums_1.VM.EVM) {
|
|
92
|
+
return 'unsupported';
|
|
93
|
+
}
|
|
94
|
+
// Guard against unit-test contexts that don't pass a real rpcUrls map —
|
|
95
|
+
// we'd otherwise hit live testnet RPC inside Jest.
|
|
96
|
+
if (!ctx.rpcUrls)
|
|
97
|
+
return 'unsupported';
|
|
98
|
+
const rpcUrls = ((_a = ctx.rpcUrls) === null || _a === void 0 ? void 0 : _a[destinationChain]) && ctx.rpcUrls[destinationChain].length > 0
|
|
99
|
+
? ctx.rpcUrls[destinationChain]
|
|
100
|
+
: chainInfo.defaultRPC;
|
|
101
|
+
if (!(rpcUrls === null || rpcUrls === void 0 ? void 0 : rpcUrls.length))
|
|
102
|
+
return 'unsupported';
|
|
103
|
+
try {
|
|
104
|
+
const client = (0, viem_1.createPublicClient)({
|
|
105
|
+
transport: (0, viem_1.fallback)(rpcUrls.map((url) => (0, viem_1.http)(url))),
|
|
106
|
+
});
|
|
107
|
+
const receipt = yield client.getTransactionReceipt({
|
|
108
|
+
hash: externalTxHash,
|
|
109
|
+
});
|
|
110
|
+
if (!receipt)
|
|
111
|
+
return 'pending';
|
|
112
|
+
if (receipt.status === 'success')
|
|
113
|
+
return 'success';
|
|
114
|
+
if (receipt.status === 'reverted')
|
|
115
|
+
return 'reverted';
|
|
116
|
+
return 'pending';
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
// viem throws TransactionReceiptNotFoundError when the tx isn't mined
|
|
120
|
+
// yet — treat as 'pending' rather than 'unsupported' so we keep polling.
|
|
121
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
122
|
+
if (/not found|TransactionReceiptNotFound|could not be found/i.test(msg)) {
|
|
123
|
+
return 'pending';
|
|
124
|
+
}
|
|
125
|
+
(0, context_1.printLog)(ctx, `[verifyExternalEvmReceipt] RPC error for ${destinationChain} tx ${externalTxHash}: ${msg}`);
|
|
126
|
+
return 'pending';
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
33
130
|
/**
|
|
34
131
|
* Wait for outbound transaction to complete and return external chain details.
|
|
35
132
|
* @internal Used by .wait() for outbound routes - not part of public API.
|
|
@@ -45,7 +142,7 @@ exports.OUTBOUND_MAX_TIMEOUT_MS = 180000; // 180s (3 min)
|
|
|
45
142
|
*/
|
|
46
143
|
function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
|
|
47
144
|
return tslib_1.__awaiter(this, arguments, void 0, function* (ctx, pushChainTxHash, options = {}) {
|
|
48
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
145
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
49
146
|
const { initialWaitMs = exports.OUTBOUND_INITIAL_WAIT_MS, pollingIntervalMs = exports.OUTBOUND_POLL_INTERVAL_MS, timeout = exports.OUTBOUND_MAX_TIMEOUT_MS, progressHook, _resolvedSubTxId, _expectedDestinationChain, } = options;
|
|
50
147
|
// Terminal failure states — fail fast instead of polling until timeout
|
|
51
148
|
const TERMINAL_FAILURE_STATES = new Set([
|
|
@@ -56,8 +153,21 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
|
|
|
56
153
|
const startTime = Date.now();
|
|
57
154
|
(0, context_1.printLog)(ctx, `[waitForOutboundTx] Starting | txHash: ${pushChainTxHash} | initialWait: ${initialWaitMs}ms | pollInterval: ${pollingIntervalMs}ms | timeout: ${timeout}ms`);
|
|
58
155
|
progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'waiting', elapsed: 0 });
|
|
59
|
-
|
|
60
|
-
|
|
156
|
+
// Clamp the initial wait to the configured timeout so a short per-call
|
|
157
|
+
// `outboundTimeoutMs` (e.g. from `tx.wait({ outboundTimeoutMs })`) isn't
|
|
158
|
+
// blocked by the default 20s settle-time. Mirrors the equivalent
|
|
159
|
+
// Math.min(initialWaitMs, timeout) clamp in inbound-tracker.ts.
|
|
160
|
+
const effectiveInitialWaitMs = Math.min(initialWaitMs, timeout);
|
|
161
|
+
(0, context_1.printLog)(ctx, `[waitForOutboundTx] Initial wait of ${effectiveInitialWaitMs}ms (configured: ${initialWaitMs}ms, clamped to timeout ${timeout}ms)...`);
|
|
162
|
+
yield new Promise((resolve) => setTimeout(resolve, effectiveInitialWaitMs));
|
|
163
|
+
// Fast-exit: if the clamped initial wait already consumed the full budget,
|
|
164
|
+
// skip the poll loop and go straight to the timeout throw below.
|
|
165
|
+
if (Date.now() - startTime >= timeout) {
|
|
166
|
+
const elapsedMs = Date.now() - startTime;
|
|
167
|
+
(0, context_1.printLog)(ctx, `[waitForOutboundTx] Timeout reached during initial wait (elapsed: ${elapsedMs}ms / ${timeout}ms)`);
|
|
168
|
+
progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'timeout', elapsed: elapsedMs });
|
|
169
|
+
throw new OutboundTimeoutError(pushChainTxHash, elapsedMs, timeout);
|
|
170
|
+
}
|
|
61
171
|
// Start polling
|
|
62
172
|
(0, context_1.printLog)(ctx, `[waitForOutboundTx] Initial wait done. Starting polling. Elapsed: ${Date.now() - startTime}ms`);
|
|
63
173
|
progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'polling', elapsed: Date.now() - startTime });
|
|
@@ -90,7 +200,7 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
|
|
|
90
200
|
if (TERMINAL_FAILURE_STATES.has(statusNum)) {
|
|
91
201
|
(0, context_1.printLog)(ctx, `[waitForOutboundTx] Terminal failure state: ${statusName}`);
|
|
92
202
|
progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'failed', elapsed: Date.now() - startTime });
|
|
93
|
-
throw new
|
|
203
|
+
throw new OutboundFailedError(`Outbound transaction failed with status ${statusName}. Push Chain TX: ${pushChainTxHash}.`, pushChainTxHash);
|
|
94
204
|
}
|
|
95
205
|
// Iterate V2 outbound array
|
|
96
206
|
for (const ob of outbounds) {
|
|
@@ -98,18 +208,43 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
|
|
|
98
208
|
if (ob.outboundStatus === types_2.OutboundStatus.REVERTED) {
|
|
99
209
|
(0, context_1.printLog)(ctx, `[waitForOutboundTx] Outbound to ${ob.destinationChain} REVERTED`);
|
|
100
210
|
progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'failed', elapsed: Date.now() - startTime });
|
|
101
|
-
throw new
|
|
211
|
+
throw new OutboundFailedError(`Outbound to ${ob.destinationChain} reverted: ${((_h = ob.observedTx) === null || _h === void 0 ? void 0 : _h.errorMsg) || 'Unknown'}. Push Chain TX: ${pushChainTxHash}.`, pushChainTxHash, ob.destinationChain, (_j = ob.observedTx) === null || _j === void 0 ? void 0 : _j.txHash);
|
|
102
212
|
}
|
|
103
|
-
|
|
213
|
+
// FOUND gating logic:
|
|
214
|
+
// 1. Primary path — cosmos has transitioned to OBSERVED (the
|
|
215
|
+
// authoritative success signal from the indexer).
|
|
216
|
+
// 2. Tiebreaker — cosmos has the txHash but outboundStatus is
|
|
217
|
+
// still UNSPECIFIED/PENDING (indexer lag). We ask the
|
|
218
|
+
// destination chain's own RPC: if its receipt is success,
|
|
219
|
+
// treat as FOUND; if reverted, throw OutboundFailedError.
|
|
220
|
+
// Pending receipts keep polling.
|
|
221
|
+
if ((_k = ob.observedTx) === null || _k === void 0 ? void 0 : _k.txHash) {
|
|
104
222
|
// If a destination chain filter is set, skip outbound entries that don't match
|
|
105
223
|
if (_expectedDestinationChain && ob.destinationChain !== _expectedDestinationChain) {
|
|
106
224
|
(0, context_1.printLog)(ctx, `[waitForOutboundTx] Poll #${pollCount} | outbound chain '${ob.destinationChain}' does not match expected '${_expectedDestinationChain}', skipping`);
|
|
107
225
|
continue;
|
|
108
226
|
}
|
|
109
227
|
const chain = (0, helpers_1.chainFromNamespace)(ob.destinationChain);
|
|
110
|
-
if (chain)
|
|
111
|
-
|
|
112
|
-
|
|
228
|
+
if (!chain)
|
|
229
|
+
continue;
|
|
230
|
+
const isCosmosObserved = ob.outboundStatus === types_2.OutboundStatus.OBSERVED;
|
|
231
|
+
if (!isCosmosObserved) {
|
|
232
|
+
// Tiebreaker: ask the destination-chain RPC directly.
|
|
233
|
+
const verdict = yield verifyExternalEvmReceipt(ctx, chain, ob.observedTx.txHash);
|
|
234
|
+
if (verdict === 'reverted') {
|
|
235
|
+
(0, context_1.printLog)(ctx, `[waitForOutboundTx] Source-chain RPC reports REVERTED for ${ob.destinationChain} tx ${ob.observedTx.txHash} (cosmos still ${(_l = types_1.UniversalTxStatus[statusNum]) !== null && _l !== void 0 ? _l : statusNum})`);
|
|
236
|
+
progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'failed', elapsed: Date.now() - startTime });
|
|
237
|
+
throw new OutboundFailedError(`Outbound to ${ob.destinationChain} reverted on source-chain RPC (tx: ${ob.observedTx.txHash}). Push Chain TX: ${pushChainTxHash}.`, pushChainTxHash, ob.destinationChain, ob.observedTx.txHash);
|
|
238
|
+
}
|
|
239
|
+
if (verdict !== 'success') {
|
|
240
|
+
// 'pending' or 'unsupported' — keep polling, cosmos will catch up.
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
(0, context_1.printLog)(ctx, `[waitForOutboundTx] Source-chain RPC tiebreaker: ${chain} tx ${ob.observedTx.txHash} succeeded; treating as FOUND despite cosmos status ${(_m = types_1.UniversalTxStatus[statusNum]) !== null && _m !== void 0 ? _m : statusNum}`);
|
|
244
|
+
}
|
|
245
|
+
{
|
|
246
|
+
const explorerBaseUrl = (_o = chain_1.CHAIN_INFO[chain]) === null || _o === void 0 ? void 0 : _o.explorerUrl;
|
|
247
|
+
const isSvm = ((_p = chain_1.CHAIN_INFO[chain]) === null || _p === void 0 ? void 0 : _p.vm) === enums_1.VM.SVM;
|
|
113
248
|
// For SVM chains, convert hex txHash to base58 and append cluster param
|
|
114
249
|
let displayTxHash = ob.observedTx.txHash;
|
|
115
250
|
let explorerUrl = '';
|
|
@@ -139,8 +274,10 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
|
|
|
139
274
|
}
|
|
140
275
|
}
|
|
141
276
|
catch (error) {
|
|
142
|
-
// Re-throw terminal failure
|
|
143
|
-
|
|
277
|
+
// Re-throw typed terminal failure so the caller can classify it as
|
|
278
|
+
// 299-02. Transient errors (RPC hiccups, deserialization) are logged
|
|
279
|
+
// and the loop continues polling until timeout.
|
|
280
|
+
if (error instanceof OutboundFailedError) {
|
|
144
281
|
throw error;
|
|
145
282
|
}
|
|
146
283
|
(0, context_1.printLog)(ctx, `[waitForOutboundTx] Poll #${pollCount} ERROR: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -149,10 +286,10 @@ function waitForOutboundTx(ctx_1, pushChainTxHash_1) {
|
|
|
149
286
|
// Wait before next poll
|
|
150
287
|
yield new Promise((resolve) => setTimeout(resolve, pollingIntervalMs));
|
|
151
288
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
289
|
+
const elapsedMs = Date.now() - startTime;
|
|
290
|
+
(0, context_1.printLog)(ctx, `[waitForOutboundTx] TIMEOUT after ${pollCount} polls | elapsed: ${elapsedMs}ms`);
|
|
291
|
+
progressHook === null || progressHook === void 0 ? void 0 : progressHook({ status: 'timeout', elapsed: elapsedMs });
|
|
292
|
+
throw new OutboundTimeoutError(pushChainTxHash, elapsedMs, timeout);
|
|
156
293
|
});
|
|
157
294
|
}
|
|
158
295
|
// ============================================================================
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { CHAIN } from '../../constants/enums';
|
|
2
|
+
import type { OrchestratorContext } from './context';
|
|
3
|
+
type StableKey = 'USDT_ETH' | 'USDT_ARB' | 'USDT_BASE' | 'USDT_BNB' | 'USDT_SOL';
|
|
4
|
+
/**
|
|
5
|
+
* Get $PC/USD price (8 decimals) for the given origin chain's route.
|
|
6
|
+
* Returns 0 on any failure — caller is expected to fall back to
|
|
7
|
+
* pushClient.pushToUSDC (the hardcoded $0.10 rate).
|
|
8
|
+
*/
|
|
9
|
+
export declare function getPcUsdPrice(ctx: OrchestratorContext, originChain: CHAIN): Promise<bigint>;
|
|
10
|
+
/**
|
|
11
|
+
* Convert a nPUSH (18-dec) amount to USD (8-dec) using the per-route oracle.
|
|
12
|
+
* Falls back to the fixed pushToUSDC rate if the oracle returns 0.
|
|
13
|
+
*/
|
|
14
|
+
export declare function pcToUsd(ctx: OrchestratorContext, pcAmount: bigint, originChain: CHAIN): Promise<bigint>;
|
|
15
|
+
/**
|
|
16
|
+
* Convert a USD (8-dec) amount to nPUSH (18-dec) using the per-route oracle.
|
|
17
|
+
* Falls back to the fixed usdcToPush rate if the oracle returns 0.
|
|
18
|
+
*/
|
|
19
|
+
export declare function usdToPc(ctx: OrchestratorContext, usdAmount: bigint, originChain: CHAIN): Promise<bigint>;
|
|
20
|
+
/**
|
|
21
|
+
* Test-only: clear the module-level cache. Unit tests mock `readContract`
|
|
22
|
+
* and need a fresh slate between runs.
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
export declare function __resetPcUsdCache(): void;
|
|
26
|
+
/** Re-exported for tests that need to assert chain coverage. */
|
|
27
|
+
export declare const __ORIGIN_TO_STABLE: Partial<Record<CHAIN, StableKey>>;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.__ORIGIN_TO_STABLE = void 0;
|
|
4
|
+
exports.getPcUsdPrice = getPcUsdPrice;
|
|
5
|
+
exports.pcToUsd = pcToUsd;
|
|
6
|
+
exports.usdToPc = usdToPc;
|
|
7
|
+
exports.__resetPcUsdCache = __resetPcUsdCache;
|
|
8
|
+
const tslib_1 = require("tslib");
|
|
9
|
+
/**
|
|
10
|
+
* Per-route $PC/USD oracle.
|
|
11
|
+
*
|
|
12
|
+
* There is no on-chain $PC/USD price feed today. Per Harsh (2026-04-17),
|
|
13
|
+
* derive $PC/USD from the WPC/stable Uniswap V3 pool on Push Chain, with
|
|
14
|
+
* the stable leg chosen by the origin route:
|
|
15
|
+
* - Ethereum / Arbitrum / Base / BNB → WPC/USDT.<route>
|
|
16
|
+
* - Solana → WPC/USDT.sol
|
|
17
|
+
*
|
|
18
|
+
* Pool pair (USDT vs USDC) is pending Zaryab/Zartaj confirmation — flip the
|
|
19
|
+
* ORIGIN_TO_STABLE map below if they pick USDC.
|
|
20
|
+
*
|
|
21
|
+
* Returns price in **8 decimals** (USD per 1 WPC) to match the convention
|
|
22
|
+
* used by PriceFetch.getPrice.
|
|
23
|
+
*/
|
|
24
|
+
const viem_1 = require("viem");
|
|
25
|
+
const abi_1 = require("../../constants/abi");
|
|
26
|
+
const chain_1 = require("../../constants/chain");
|
|
27
|
+
const enums_1 = require("../../constants/enums");
|
|
28
|
+
const context_1 = require("./context");
|
|
29
|
+
const helpers_1 = require("./helpers");
|
|
30
|
+
/**
|
|
31
|
+
* Chosen stable token per origin chain. Change these values to switch to USDC.
|
|
32
|
+
* Decimals: assume 6 (standard USDT/USDC). If a PRC-20 deviates, add an entry
|
|
33
|
+
* to STABLE_DECIMALS override below.
|
|
34
|
+
*/
|
|
35
|
+
const ORIGIN_TO_STABLE = {
|
|
36
|
+
[enums_1.CHAIN.ETHEREUM_SEPOLIA]: 'USDT_ETH',
|
|
37
|
+
[enums_1.CHAIN.ARBITRUM_SEPOLIA]: 'USDT_ARB',
|
|
38
|
+
[enums_1.CHAIN.BASE_SEPOLIA]: 'USDT_BASE',
|
|
39
|
+
[enums_1.CHAIN.BNB_TESTNET]: 'USDT_BNB',
|
|
40
|
+
[enums_1.CHAIN.SOLANA_DEVNET]: 'USDT_SOL',
|
|
41
|
+
};
|
|
42
|
+
/** Default decimals for stable PRC-20s on Push Chain. */
|
|
43
|
+
const DEFAULT_STABLE_DECIMALS = 6;
|
|
44
|
+
// ============================================================================
|
|
45
|
+
// QuoterV2 ABI (same subset used elsewhere in gas-calculator.ts)
|
|
46
|
+
// ============================================================================
|
|
47
|
+
const QUOTER_V2_ABI = [
|
|
48
|
+
{
|
|
49
|
+
type: 'function',
|
|
50
|
+
name: 'quoteExactInputSingle',
|
|
51
|
+
inputs: [
|
|
52
|
+
{
|
|
53
|
+
type: 'tuple',
|
|
54
|
+
components: [
|
|
55
|
+
{ name: 'tokenIn', type: 'address' },
|
|
56
|
+
{ name: 'tokenOut', type: 'address' },
|
|
57
|
+
{ name: 'amountIn', type: 'uint256' },
|
|
58
|
+
{ name: 'fee', type: 'uint24' },
|
|
59
|
+
{ name: 'sqrtPriceLimitX96', type: 'uint160' },
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
outputs: [
|
|
64
|
+
{ name: 'amountOut', type: 'uint256' },
|
|
65
|
+
{ name: 'sqrtPriceX96After', type: 'uint160' },
|
|
66
|
+
{ name: 'initializedTicksCrossed', type: 'uint32' },
|
|
67
|
+
{ name: 'gasEstimate', type: 'uint256' },
|
|
68
|
+
],
|
|
69
|
+
stateMutability: 'view',
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
const UNIVERSAL_CORE_SWAP_HELPERS_ABI = [
|
|
73
|
+
{
|
|
74
|
+
type: 'function',
|
|
75
|
+
name: 'WPC',
|
|
76
|
+
inputs: [],
|
|
77
|
+
outputs: [{ name: '', type: 'address' }],
|
|
78
|
+
stateMutability: 'view',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
type: 'function',
|
|
82
|
+
name: 'uniswapV3Factory',
|
|
83
|
+
inputs: [],
|
|
84
|
+
outputs: [{ name: '', type: 'address' }],
|
|
85
|
+
stateMutability: 'view',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
type: 'function',
|
|
89
|
+
name: 'defaultFeeTier',
|
|
90
|
+
inputs: [{ name: '', type: 'address' }],
|
|
91
|
+
outputs: [{ name: '', type: 'uint24' }],
|
|
92
|
+
stateMutability: 'view',
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
const UNISWAP_V3_FACTORY_ABI = [
|
|
96
|
+
{
|
|
97
|
+
type: 'function',
|
|
98
|
+
name: 'getPool',
|
|
99
|
+
inputs: [
|
|
100
|
+
{ name: 'tokenA', type: 'address' },
|
|
101
|
+
{ name: 'tokenB', type: 'address' },
|
|
102
|
+
{ name: 'fee', type: 'uint24' },
|
|
103
|
+
],
|
|
104
|
+
outputs: [{ name: 'pool', type: 'address' }],
|
|
105
|
+
stateMutability: 'view',
|
|
106
|
+
},
|
|
107
|
+
];
|
|
108
|
+
/**
|
|
109
|
+
* Fee tiers to probe when `defaultFeeTier(stable)` returns 0 on UniversalCore.
|
|
110
|
+
* Per the 2026-04-17 testnet probe, all WPC/USDT.* stable pools live at 500.
|
|
111
|
+
* Fall back through the standard Uniswap V3 tier set if 500 misses.
|
|
112
|
+
*/
|
|
113
|
+
const STABLE_FEE_TIER_FALLBACKS = [500, 3000, 100, 10000];
|
|
114
|
+
const ZERO_ADDR = '0x0000000000000000000000000000000000000000';
|
|
115
|
+
// ============================================================================
|
|
116
|
+
// Cache (module-level, 30s TTL — mirrors price-fetch.ts)
|
|
117
|
+
// ============================================================================
|
|
118
|
+
const PRICE_CACHE_TTL_MS = 30000;
|
|
119
|
+
const pcUsdPriceCache = new Map();
|
|
120
|
+
// ============================================================================
|
|
121
|
+
// Public API
|
|
122
|
+
// ============================================================================
|
|
123
|
+
/**
|
|
124
|
+
* Get $PC/USD price (8 decimals) for the given origin chain's route.
|
|
125
|
+
* Returns 0 on any failure — caller is expected to fall back to
|
|
126
|
+
* pushClient.pushToUSDC (the hardcoded $0.10 rate).
|
|
127
|
+
*/
|
|
128
|
+
function getPcUsdPrice(ctx, originChain) {
|
|
129
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
130
|
+
var _a, _b, _c;
|
|
131
|
+
const cached = pcUsdPriceCache.get(originChain);
|
|
132
|
+
if (cached && Date.now() < cached.expiry) {
|
|
133
|
+
return cached.price;
|
|
134
|
+
}
|
|
135
|
+
const stableKey = ORIGIN_TO_STABLE[originChain];
|
|
136
|
+
if (!stableKey) {
|
|
137
|
+
(0, context_1.printLog)(ctx, `getPcUsdPrice — no stable token mapped for origin ${originChain}; returning 0`);
|
|
138
|
+
return BigInt(0);
|
|
139
|
+
}
|
|
140
|
+
const pushChain = (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork);
|
|
141
|
+
const quoterAddress = (_b = (_a = chain_1.CHAIN_INFO[pushChain]) === null || _a === void 0 ? void 0 : _a.dex) === null || _b === void 0 ? void 0 : _b.uniV3QuoterV2;
|
|
142
|
+
if (!quoterAddress || quoterAddress.startsWith('0xTBD')) {
|
|
143
|
+
(0, context_1.printLog)(ctx, `getPcUsdPrice — no QuoterV2 configured for ${pushChain}; returning 0`);
|
|
144
|
+
return BigInt(0);
|
|
145
|
+
}
|
|
146
|
+
const stableAddress = (_c = chain_1.SYNTHETIC_PUSH_ERC20[ctx.pushNetwork]) === null || _c === void 0 ? void 0 : _c[stableKey];
|
|
147
|
+
if (!stableAddress || stableAddress.startsWith('0xTBD')) {
|
|
148
|
+
(0, context_1.printLog)(ctx, `getPcUsdPrice — no ${stableKey} mapped on ${ctx.pushNetwork}; returning 0`);
|
|
149
|
+
return BigInt(0);
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
const gatewayPcAddress = (0, helpers_1.getUniversalGatewayPCAddress)();
|
|
153
|
+
const universalCoreAddress = yield ctx.pushClient.readContract({
|
|
154
|
+
address: gatewayPcAddress,
|
|
155
|
+
abi: abi_1.UNIVERSAL_GATEWAY_PC,
|
|
156
|
+
functionName: 'UNIVERSAL_CORE',
|
|
157
|
+
args: [],
|
|
158
|
+
});
|
|
159
|
+
const [wpcAddress, factoryAddress, defaultFeeTier] = yield Promise.all([
|
|
160
|
+
ctx.pushClient.readContract({
|
|
161
|
+
address: universalCoreAddress,
|
|
162
|
+
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
163
|
+
functionName: 'WPC',
|
|
164
|
+
args: [],
|
|
165
|
+
}),
|
|
166
|
+
ctx.pushClient.readContract({
|
|
167
|
+
address: universalCoreAddress,
|
|
168
|
+
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
169
|
+
functionName: 'uniswapV3Factory',
|
|
170
|
+
args: [],
|
|
171
|
+
}),
|
|
172
|
+
ctx.pushClient.readContract({
|
|
173
|
+
address: universalCoreAddress,
|
|
174
|
+
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
175
|
+
functionName: 'defaultFeeTier',
|
|
176
|
+
args: [stableAddress],
|
|
177
|
+
}),
|
|
178
|
+
]);
|
|
179
|
+
if (!wpcAddress) {
|
|
180
|
+
(0, context_1.printLog)(ctx, `getPcUsdPrice — missing WPC; returning 0`);
|
|
181
|
+
return BigInt(0);
|
|
182
|
+
}
|
|
183
|
+
// UniversalCore's defaultFeeTier is set only for gas tokens (pETH*, pSOL).
|
|
184
|
+
// For stables, probe the factory for the first tier with a live pool.
|
|
185
|
+
let feeTier = defaultFeeTier;
|
|
186
|
+
if (!feeTier) {
|
|
187
|
+
for (const candidate of STABLE_FEE_TIER_FALLBACKS) {
|
|
188
|
+
const pool = yield ctx.pushClient.readContract({
|
|
189
|
+
address: factoryAddress,
|
|
190
|
+
abi: UNISWAP_V3_FACTORY_ABI,
|
|
191
|
+
functionName: 'getPool',
|
|
192
|
+
args: [wpcAddress, stableAddress, candidate],
|
|
193
|
+
});
|
|
194
|
+
if (pool && pool !== ZERO_ADDR) {
|
|
195
|
+
feeTier = candidate;
|
|
196
|
+
(0, context_1.printLog)(ctx, `getPcUsdPrice — resolved fee tier ${candidate} via factory probe for WPC/${stableKey}`);
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (!feeTier) {
|
|
202
|
+
(0, context_1.printLog)(ctx, `getPcUsdPrice — no WPC/${stableKey} pool found at any fee tier; returning 0`);
|
|
203
|
+
return BigInt(0);
|
|
204
|
+
}
|
|
205
|
+
// Quote: 1 WPC (1e18) → X stable (DEFAULT_STABLE_DECIMALS)
|
|
206
|
+
const oneWpc = (0, viem_1.parseUnits)('1', 18);
|
|
207
|
+
const result = yield ctx.pushClient.readContract({
|
|
208
|
+
address: quoterAddress,
|
|
209
|
+
abi: QUOTER_V2_ABI,
|
|
210
|
+
functionName: 'quoteExactInputSingle',
|
|
211
|
+
args: [
|
|
212
|
+
{
|
|
213
|
+
tokenIn: wpcAddress,
|
|
214
|
+
tokenOut: stableAddress,
|
|
215
|
+
amountIn: oneWpc,
|
|
216
|
+
fee: feeTier,
|
|
217
|
+
sqrtPriceLimitX96: BigInt(0),
|
|
218
|
+
},
|
|
219
|
+
],
|
|
220
|
+
});
|
|
221
|
+
const stableOut = result[0];
|
|
222
|
+
if (stableOut === BigInt(0)) {
|
|
223
|
+
(0, context_1.printLog)(ctx, `getPcUsdPrice — quoter returned 0 for WPC→${stableKey}`);
|
|
224
|
+
return BigInt(0);
|
|
225
|
+
}
|
|
226
|
+
// Normalize stableOut (DEFAULT_STABLE_DECIMALS) to 8-decimal USD.
|
|
227
|
+
// If stable decimals > 8, divide; otherwise multiply.
|
|
228
|
+
const decDelta = 8 - DEFAULT_STABLE_DECIMALS;
|
|
229
|
+
const price = decDelta >= 0
|
|
230
|
+
? stableOut * BigInt(Math.pow(10, decDelta))
|
|
231
|
+
: stableOut / BigInt(Math.pow(10, -decDelta));
|
|
232
|
+
(0, context_1.printLog)(ctx, `getPcUsdPrice — origin=${originChain} stable=${stableKey} quote: 1 WPC = ${stableOut.toString()} (${DEFAULT_STABLE_DECIMALS}d) = ${price.toString()} (1e8 USD)`);
|
|
233
|
+
pcUsdPriceCache.set(originChain, {
|
|
234
|
+
price,
|
|
235
|
+
expiry: Date.now() + PRICE_CACHE_TTL_MS,
|
|
236
|
+
});
|
|
237
|
+
return price;
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
(0, context_1.printLog)(ctx, `getPcUsdPrice — failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
241
|
+
return BigInt(0);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Convert a nPUSH (18-dec) amount to USD (8-dec) using the per-route oracle.
|
|
247
|
+
* Falls back to the fixed pushToUSDC rate if the oracle returns 0.
|
|
248
|
+
*/
|
|
249
|
+
function pcToUsd(ctx, pcAmount, originChain) {
|
|
250
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
251
|
+
const price = yield getPcUsdPrice(ctx, originChain);
|
|
252
|
+
if (price === BigInt(0)) {
|
|
253
|
+
return ctx.pushClient.pushToUSDC(pcAmount);
|
|
254
|
+
}
|
|
255
|
+
const oneWpc = (0, viem_1.parseUnits)('1', 18);
|
|
256
|
+
return (pcAmount * price) / oneWpc;
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Convert a USD (8-dec) amount to nPUSH (18-dec) using the per-route oracle.
|
|
261
|
+
* Falls back to the fixed usdcToPush rate if the oracle returns 0.
|
|
262
|
+
*/
|
|
263
|
+
function usdToPc(ctx, usdAmount, originChain) {
|
|
264
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
265
|
+
const price = yield getPcUsdPrice(ctx, originChain);
|
|
266
|
+
if (price === BigInt(0)) {
|
|
267
|
+
return ctx.pushClient.usdcToPush(usdAmount);
|
|
268
|
+
}
|
|
269
|
+
const oneWpc = (0, viem_1.parseUnits)('1', 18);
|
|
270
|
+
return (usdAmount * oneWpc + (price - BigInt(1))) / price;
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Test-only: clear the module-level cache. Unit tests mock `readContract`
|
|
275
|
+
* and need a fresh slate between runs.
|
|
276
|
+
* @internal
|
|
277
|
+
*/
|
|
278
|
+
function __resetPcUsdCache() {
|
|
279
|
+
pcUsdPriceCache.clear();
|
|
280
|
+
}
|
|
281
|
+
/** Re-exported for tests that need to assert chain coverage. */
|
|
282
|
+
exports.__ORIGIN_TO_STABLE = ORIGIN_TO_STABLE;
|
|
283
|
+
// Reference to keep VM import used (stable decimals may differ by VM later).
|
|
284
|
+
void enums_1.VM;
|
|
285
|
+
//# sourceMappingURL=pc-usd-oracle.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-route progress hook builders for the outbound polling phase
|
|
3
|
+
* (.wait() in response-builder.ts and per-hop loops in cascade.waitForAll).
|
|
4
|
+
*
|
|
5
|
+
* Splitting this out gives both call sites a single source of truth for
|
|
6
|
+
* which IDs fire on each route, so cascade hops and single-tx outbound
|
|
7
|
+
* stay in lockstep.
|
|
8
|
+
*/
|
|
9
|
+
import type { OutboundTxDetails } from '../orchestrator.types';
|
|
10
|
+
import type { ProgressEvent } from '../../progress-hook/progress-hook.types';
|
|
11
|
+
import { TransactionRoute } from '../route-detector';
|
|
12
|
+
export type WaitHookSet = {
|
|
13
|
+
intermediatePushOk?: (chain: string, pushTxHash: string) => ProgressEvent;
|
|
14
|
+
awaiting: (chain: string) => ProgressEvent;
|
|
15
|
+
polling: (chain: string, elapsedMs: number) => ProgressEvent;
|
|
16
|
+
success: (details: OutboundTxDetails) => ProgressEvent;
|
|
17
|
+
timeout: (chain: string, elapsedMs: number) => ProgressEvent;
|
|
18
|
+
failed: (chain: string, errMsg: string) => ProgressEvent;
|
|
19
|
+
};
|
|
20
|
+
export declare function pickWaitHooks(route: TransactionRoute | string | undefined): WaitHookSet;
|
|
21
|
+
/** True when the hook set is the no-op placeholder (route has no spec'd
|
|
22
|
+
* ID range). Emission sites should skip firing and receipt-mutation blocks. */
|
|
23
|
+
export declare function isNoopHookSet(hooks: WaitHookSet): boolean;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Per-route progress hook builders for the outbound polling phase
|
|
4
|
+
* (.wait() in response-builder.ts and per-hop loops in cascade.waitForAll).
|
|
5
|
+
*
|
|
6
|
+
* Splitting this out gives both call sites a single source of truth for
|
|
7
|
+
* which IDs fire on each route, so cascade hops and single-tx outbound
|
|
8
|
+
* stay in lockstep.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.pickWaitHooks = pickWaitHooks;
|
|
12
|
+
exports.isNoopHookSet = isNoopHookSet;
|
|
13
|
+
const tslib_1 = require("tslib");
|
|
14
|
+
const progress_hook_types_1 = require("../../progress-hook/progress-hook.types");
|
|
15
|
+
const progress_hook_1 = tslib_1.__importDefault(require("../../progress-hook/progress-hook"));
|
|
16
|
+
const route_detector_1 = require("../route-detector");
|
|
17
|
+
function pickWaitHooks(route) {
|
|
18
|
+
if (route === route_detector_1.TransactionRoute.UOA_TO_CEA) {
|
|
19
|
+
return {
|
|
20
|
+
intermediatePushOk: (chain, txHash) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_99](chain, txHash),
|
|
21
|
+
awaiting: (chain) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_209_01](chain),
|
|
22
|
+
polling: (chain, elapsed) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_209_02](chain, elapsed),
|
|
23
|
+
success: (details) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_01](details),
|
|
24
|
+
timeout: (chain, elapsed) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_03](chain, elapsed),
|
|
25
|
+
failed: (chain, msg) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_02](chain, msg),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (route === route_detector_1.TransactionRoute.CEA_TO_PUSH) {
|
|
29
|
+
return {
|
|
30
|
+
intermediatePushOk: (_chain, txHash) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_99_99](txHash),
|
|
31
|
+
awaiting: (chain) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_309_01](chain),
|
|
32
|
+
polling: (chain, elapsed) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_309_02](chain, elapsed),
|
|
33
|
+
// For R3, the outbound-poll "success" is the source-chain CEA executing
|
|
34
|
+
// (309-03 INFO). Terminal 399-01 fires after the inbound-to-Push poll
|
|
35
|
+
// (handled by waitForInboundPushTx in response-builder).
|
|
36
|
+
success: (details) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_309_03](details.destinationChain, details.externalTxHash),
|
|
37
|
+
// R3 outbound (source-chain CEA) failures share the 399-02/03 IDs with
|
|
38
|
+
// R3 inbound; pass phase='outbound' so the title reflects the source
|
|
39
|
+
// chain instead of "Push Chain Inbound …".
|
|
40
|
+
timeout: (chain, elapsed) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_03](chain, elapsed, 'outbound'),
|
|
41
|
+
failed: (chain, msg) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](msg, 'outbound', chain),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// Route 4 (CEA_TO_CEA) has no spec'd ID range yet; cascade hops and
|
|
45
|
+
// trackTransaction of pre-existing R4 UTXs still flow through here. Return
|
|
46
|
+
// a no-op set so wait() / cascade progress without emitting progress
|
|
47
|
+
// events for R4. When R4 gets its own ID range, add a branch above.
|
|
48
|
+
return NOOP_WAIT_HOOKS;
|
|
49
|
+
}
|
|
50
|
+
/** Sentinel event returned by NOOP_WAIT_HOOKS. Emission sites can detect
|
|
51
|
+
* and skip it by id === '' if they want to suppress no-op events. */
|
|
52
|
+
const NOOP_EVENT = Object.freeze({
|
|
53
|
+
id: '',
|
|
54
|
+
title: '',
|
|
55
|
+
message: '',
|
|
56
|
+
level: 'INFO',
|
|
57
|
+
response: null,
|
|
58
|
+
timestamp: '',
|
|
59
|
+
});
|
|
60
|
+
const NOOP_WAIT_HOOKS = Object.freeze({
|
|
61
|
+
awaiting: () => NOOP_EVENT,
|
|
62
|
+
polling: () => NOOP_EVENT,
|
|
63
|
+
success: () => NOOP_EVENT,
|
|
64
|
+
timeout: () => NOOP_EVENT,
|
|
65
|
+
failed: () => NOOP_EVENT,
|
|
66
|
+
});
|
|
67
|
+
/** True when the hook set is the no-op placeholder (route has no spec'd
|
|
68
|
+
* ID range). Emission sites should skip firing and receipt-mutation blocks. */
|
|
69
|
+
function isNoopHookSet(hooks) {
|
|
70
|
+
return hooks === NOOP_WAIT_HOOKS;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=progress-route-hooks.js.map
|