@pushchain/core 6.0.20 → 6.0.21
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 +48 -0
- package/package.json +1 -1
- package/src/lib/cache/cache.js +2 -0
- package/src/lib/constants/abi/index.d.ts +1 -0
- package/src/lib/constants/abi/index.js +8 -1
- package/src/lib/constants/abi/pc20.evm.d.ts +217 -0
- package/src/lib/constants/abi/pc20.evm.js +150 -0
- package/src/lib/constants/abi/prc20.evm.d.ts +172 -0
- package/src/lib/constants/abi/prc20.evm.js +97 -0
- package/src/lib/constants/abi/universalGatewayV0.json +1 -1
- package/src/lib/constants/chain.js +38 -8
- package/src/lib/constants/selectors.js +2 -2
- package/src/lib/constants/tokens.js +4 -3
- package/src/lib/formatters.js +16 -6
- package/src/lib/generated/uexecutor/v1/query.js +2 -4
- package/src/lib/generated/uexecutor/v1/types.d.ts +14 -0
- package/src/lib/generated/uexecutor/v1/types.js +90 -47
- package/src/lib/generated/uexecutor/v2/query.js +2 -4
- package/src/lib/generated/uexecutor/v2/types.d.ts +20 -0
- package/src/lib/generated/uexecutor/v2/types.js +49 -33
- package/src/lib/generated/v1/tx.js +30 -37
- package/src/lib/index.d.ts +3 -0
- package/src/lib/index.js +21 -3
- package/src/lib/internal/buffer.js +1 -2
- package/src/lib/orchestrator/cea-utils.js +73 -83
- package/src/lib/orchestrator/internals/account-manager.js +130 -139
- package/src/lib/orchestrator/internals/cascade.d.ts +0 -6
- package/src/lib/orchestrator/internals/cascade.js +1184 -1059
- package/src/lib/orchestrator/internals/confirmation.js +138 -148
- package/src/lib/orchestrator/internals/error-decoder.js +1 -1
- package/src/lib/orchestrator/internals/errors.js +12 -3
- package/src/lib/orchestrator/internals/execute-funds-only.d.ts +2 -2
- package/src/lib/orchestrator/internals/execute-funds-only.js +297 -259
- package/src/lib/orchestrator/internals/execute-funds-payload.d.ts +2 -2
- package/src/lib/orchestrator/internals/execute-funds-payload.js +220 -220
- package/src/lib/orchestrator/internals/execute-standard.d.ts +0 -8
- package/src/lib/orchestrator/internals/execute-standard.js +339 -342
- package/src/lib/orchestrator/internals/gas-calculator.js +497 -520
- package/src/lib/orchestrator/internals/gas-usd-sizer.js +101 -110
- package/src/lib/orchestrator/internals/gateway-client.js +102 -103
- package/src/lib/orchestrator/internals/helpers.js +30 -27
- package/src/lib/orchestrator/internals/inbound-tracker.js +234 -238
- package/src/lib/orchestrator/internals/outbound-sync.js +463 -452
- package/src/lib/orchestrator/internals/outbound-tracker.js +27 -34
- package/src/lib/orchestrator/internals/payload-builder.d.ts +2 -2
- package/src/lib/orchestrator/internals/payload-builder.js +119 -100
- package/src/lib/orchestrator/internals/pc-usd-oracle.js +121 -129
- package/src/lib/orchestrator/internals/pc20/address-codec.d.ts +31 -0
- package/src/lib/orchestrator/internals/pc20/address-codec.js +124 -0
- package/src/lib/orchestrator/internals/pc20/chain-namespace.d.ts +68 -0
- package/src/lib/orchestrator/internals/pc20/chain-namespace.js +136 -0
- package/src/lib/orchestrator/internals/pc20/errors.d.ts +160 -0
- package/src/lib/orchestrator/internals/pc20/errors.js +236 -0
- package/src/lib/orchestrator/internals/pc20/export.d.ts +172 -0
- package/src/lib/orchestrator/internals/pc20/export.js +412 -0
- package/src/lib/orchestrator/internals/pc20/gate.d.ts +67 -0
- package/src/lib/orchestrator/internals/pc20/gate.js +184 -0
- package/src/lib/orchestrator/internals/pc20/resolver.d.ts +187 -0
- package/src/lib/orchestrator/internals/pc20/resolver.js +658 -0
- package/src/lib/orchestrator/internals/pc20/svm.d.ts +189 -0
- package/src/lib/orchestrator/internals/pc20/svm.js +286 -0
- package/src/lib/orchestrator/internals/pc20/tracking.d.ts +46 -0
- package/src/lib/orchestrator/internals/pc20/tracking.js +109 -0
- package/src/lib/orchestrator/internals/preflight.js +1 -1
- package/src/lib/orchestrator/internals/progress-route-hooks.js +2 -2
- package/src/lib/orchestrator/internals/push-chain-tx.js +319 -329
- package/src/lib/orchestrator/internals/quote.js +90 -94
- package/src/lib/orchestrator/internals/rescue.js +76 -79
- package/src/lib/orchestrator/internals/response-builder.d.ts +28 -1
- package/src/lib/orchestrator/internals/response-builder.js +817 -701
- package/src/lib/orchestrator/internals/route-handlers.d.ts +7 -15
- package/src/lib/orchestrator/internals/route-handlers.js +1512 -1178
- package/src/lib/orchestrator/internals/signing.js +78 -83
- package/src/lib/orchestrator/internals/svm-bridge.d.ts +2 -2
- package/src/lib/orchestrator/internals/svm-bridge.js +161 -93
- package/src/lib/orchestrator/internals/svm-helpers.d.ts +15 -1
- package/src/lib/orchestrator/internals/svm-helpers.js +68 -24
- package/src/lib/orchestrator/internals/svm-rent.d.ts +19 -1
- package/src/lib/orchestrator/internals/svm-rent.js +163 -141
- package/src/lib/orchestrator/internals/tx-transformer.js +26 -23
- package/src/lib/orchestrator/internals/uea-manager.js +89 -86
- package/src/lib/orchestrator/max-pc-for-gas.js +5 -6
- package/src/lib/orchestrator/orchestrator.js +217 -200
- package/src/lib/orchestrator/orchestrator.types.d.ts +121 -1
- package/src/lib/orchestrator/orchestrator.types.js +19 -0
- package/src/lib/orchestrator/payload-builders.d.ts +2 -2
- package/src/lib/orchestrator/payload-builders.js +26 -24
- package/src/lib/orchestrator/route-detector.js +26 -9
- package/src/lib/orchestrator/svm-idl/ix-encoder.js +1 -2
- package/src/lib/orchestrator/svm-idl/normalize-address.js +2 -2
- package/src/lib/orchestrator/svm-idl/resolve.js +1 -2
- package/src/lib/price-fetch/price-fetch.js +67 -68
- package/src/lib/progress-hook/progress-hook.js +124 -72
- package/src/lib/push-chain/push-chain.js +171 -153
- package/src/lib/push-client/push-client.js +223 -237
- package/src/lib/universal/account/account.js +349 -365
- package/src/lib/universal/signer/signer.js +306 -294
- package/src/lib/universal-tx-detector/auto-detect.js +55 -60
- package/src/lib/universal-tx-detector/cascade.js +160 -172
- package/src/lib/universal-tx-detector/child-inbounds.js +67 -75
- package/src/lib/universal-tx-detector/classify.js +2 -3
- package/src/lib/universal-tx-detector/detector-svm.js +139 -147
- package/src/lib/universal-tx-detector/detector.js +145 -157
- package/src/lib/universal-tx-detector/normalize.js +7 -7
- package/src/lib/utils/external-tx-hash.js +1 -2
- package/src/lib/utils.d.ts +44 -0
- package/src/lib/utils.js +762 -683
- package/src/lib/vm-client/evm-client.js +186 -202
- package/src/lib/vm-client/svm-client.d.ts +1 -1
- package/src/lib/vm-client/svm-client.js +220 -224
- package/src/lib/vm-client/vm-client.types.d.ts +14 -2
|
@@ -15,7 +15,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
exports.InboundTimeoutError = void 0;
|
|
16
16
|
exports.findChildUtxIdFromExternalTx = findChildUtxIdFromExternalTx;
|
|
17
17
|
exports.waitForInboundPushTx = waitForInboundPushTx;
|
|
18
|
-
const tslib_1 = require("tslib");
|
|
19
18
|
const types_1 = require("../../generated/uexecutor/v2/types");
|
|
20
19
|
const context_1 = require("./context");
|
|
21
20
|
const detector_1 = require("../../universal-tx-detector/detector");
|
|
@@ -51,58 +50,56 @@ const ensureHex = (id) => id.startsWith('0x') ? id : `0x${id}`;
|
|
|
51
50
|
* has seen it yet, or `{ utxId: null, error }` when both paths failed with
|
|
52
51
|
* recoverable RPC errors.
|
|
53
52
|
*/
|
|
54
|
-
function findChildUtxIdFromExternalTx(ctx, externalTxHash, sourceChain) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return { utxId: ensureHex(match.universalTxId), derivedFrom: 'detector' };
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
catch (err) {
|
|
74
|
-
const wrapped = err instanceof Error ? err : new Error(String(err));
|
|
75
|
-
(0, context_1.printLog)(ctx, `[findChildUtxIdFromExternalTx] detector path failed: ${wrapped.message} — falling back to cosmos search`);
|
|
76
|
-
// Fall through to cosmos search.
|
|
53
|
+
async function findChildUtxIdFromExternalTx(ctx, externalTxHash, sourceChain) {
|
|
54
|
+
// Primary: detector-based deterministic derivation.
|
|
55
|
+
if (sourceChain) {
|
|
56
|
+
try {
|
|
57
|
+
const detection = await (0, detector_1.detectUniversalTx)(externalTxHash, sourceChain, {
|
|
58
|
+
pushClient: ctx.pushClient,
|
|
59
|
+
rpcUrls: ctx.rpcUrls,
|
|
60
|
+
skipPushChainLookup: true,
|
|
61
|
+
});
|
|
62
|
+
const resolutions = await (0, child_inbounds_1.resolveChildInboundsFromDetection)(ctx.pushClient, detection);
|
|
63
|
+
// Pick the R3 return-trip child: prefer UniversalTx over RevertUniversalTx.
|
|
64
|
+
const match = resolutions.find((r) => r.sourceEventName === 'UniversalTx') ??
|
|
65
|
+
resolutions[0];
|
|
66
|
+
if (match?.universalTxId) {
|
|
67
|
+
(0, context_1.printLog)(ctx, `[findChildUtxIdFromExternalTx] detector derived utxId ${match.universalTxId} for ${externalTxHash} on ${sourceChain}`);
|
|
68
|
+
return { utxId: ensureHex(match.universalTxId), derivedFrom: 'detector' };
|
|
77
69
|
}
|
|
78
70
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
71
|
+
catch (err) {
|
|
72
|
+
const wrapped = err instanceof Error ? err : new Error(String(err));
|
|
73
|
+
(0, context_1.printLog)(ctx, `[findChildUtxIdFromExternalTx] detector path failed: ${wrapped.message} — falling back to cosmos search`);
|
|
74
|
+
// Fall through to cosmos search.
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Fallback: cosmos text search (original path).
|
|
78
|
+
try {
|
|
79
|
+
const query = `universal_tx_created.inbound_tx_hash='${externalTxHash}'`;
|
|
80
|
+
const results = await ctx.pushClient.searchCosmosByQuery(query);
|
|
81
|
+
for (const tx of results) {
|
|
82
|
+
for (const event of tx.events ?? []) {
|
|
83
|
+
if (event.type === 'universal_tx_created' ||
|
|
84
|
+
event.type === 'outbound_created') {
|
|
85
|
+
for (const attr of event.attributes ?? []) {
|
|
86
|
+
if (attr.key === 'utx_id' && attr.value) {
|
|
87
|
+
return {
|
|
88
|
+
utxId: ensureHex(attr.value),
|
|
89
|
+
derivedFrom: 'cosmos-fallback',
|
|
90
|
+
};
|
|
94
91
|
}
|
|
95
92
|
}
|
|
96
93
|
}
|
|
97
94
|
}
|
|
98
|
-
return { utxId: null };
|
|
99
|
-
}
|
|
100
|
-
catch (err) {
|
|
101
|
-
const wrapped = err instanceof Error ? err : new Error(String(err));
|
|
102
|
-
(0, context_1.printLog)(ctx, `[findChildUtxIdFromExternalTx] cosmos fallback also failed: ${wrapped.message}`);
|
|
103
|
-
return { utxId: null, error: wrapped };
|
|
104
95
|
}
|
|
105
|
-
|
|
96
|
+
return { utxId: null };
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
const wrapped = err instanceof Error ? err : new Error(String(err));
|
|
100
|
+
(0, context_1.printLog)(ctx, `[findChildUtxIdFromExternalTx] cosmos fallback also failed: ${wrapped.message}`);
|
|
101
|
+
return { utxId: null, error: wrapped };
|
|
102
|
+
}
|
|
106
103
|
}
|
|
107
104
|
/**
|
|
108
105
|
* Polls Push Chain for the inbound tx that closes an R3 round-trip.
|
|
@@ -110,91 +107,155 @@ function findChildUtxIdFromExternalTx(ctx, externalTxHash, sourceChain) {
|
|
|
110
107
|
* rejects with a Timeout error if neither child UTX nor terminal state is
|
|
111
108
|
* observed within the configured timeout.
|
|
112
109
|
*/
|
|
113
|
-
function waitForInboundPushTx(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
110
|
+
async function waitForInboundPushTx(ctx, outboundExternalTxHash, sourceChain, opts = {}) {
|
|
111
|
+
const initialWaitMs = opts.initialWaitMs ?? 30000;
|
|
112
|
+
const pollingIntervalMs = opts.pollingIntervalMs ?? 5000;
|
|
113
|
+
const timeout = opts.timeout ?? 300000;
|
|
114
|
+
const progressHook = opts.progressHook;
|
|
115
|
+
const startedAt = Date.now();
|
|
116
|
+
const elapsed = () => Date.now() - startedAt;
|
|
117
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Starting | externalTxHash: ${outboundExternalTxHash} | sourceChain: ${sourceChain} | initialWait: ${initialWaitMs}ms | pollInterval: ${pollingIntervalMs}ms | timeout: ${timeout}ms`);
|
|
118
|
+
progressHook?.({ status: 'waiting', elapsedMs: 0 });
|
|
119
|
+
if (initialWaitMs > 0) {
|
|
120
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Initial wait of ${initialWaitMs}ms...`);
|
|
121
|
+
await new Promise((r) => setTimeout(r, Math.min(initialWaitMs, timeout)));
|
|
122
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Initial wait done. Starting polling. Elapsed: ${elapsed()}ms`);
|
|
123
|
+
}
|
|
124
|
+
let childUtxId = null;
|
|
125
|
+
let strippedChildUtxId;
|
|
126
|
+
let pushTxHash;
|
|
127
|
+
let lastEmittedStatus;
|
|
128
|
+
let consecutiveRpcErrors = 0;
|
|
129
|
+
let pendingTerminalSuccessRetries = 0;
|
|
130
|
+
let pollCount = 0;
|
|
131
|
+
// Heuristic threshold — log a distinct warning when this many back-to-back
|
|
132
|
+
// RPC failures happen so callers can see the difference between
|
|
133
|
+
// "indexer hasn't seen it yet" and "RPC is down."
|
|
134
|
+
const RPC_FAILURE_WARN_THRESHOLD = 5;
|
|
135
|
+
// When chain reports terminal success but pcTx hasn't populated yet, give
|
|
136
|
+
// the indexer one extra poll cycle to catch up before returning empty hash.
|
|
137
|
+
const MAX_PENDING_TERMINAL_RETRIES = 2;
|
|
138
|
+
while (elapsed() < timeout) {
|
|
139
|
+
pollCount++;
|
|
140
|
+
const pollStart = Date.now();
|
|
141
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Poll #${pollCount} | Elapsed: ${elapsed()}ms / ${timeout}ms | phase: ${childUtxId ? 'utx-status' : 'child-search'}`);
|
|
142
|
+
// Phase 1 — find child UTX id from the outbound external tx hash
|
|
143
|
+
if (!childUtxId) {
|
|
144
|
+
const search = await findChildUtxIdFromExternalTx(ctx, outboundExternalTxHash, sourceChain);
|
|
145
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Poll #${pollCount} child-search result: utxId=${search.utxId ?? 'null'}${search.error ? ` error=${search.error.message}` : ''}`);
|
|
146
|
+
if (search.error) {
|
|
147
|
+
consecutiveRpcErrors++;
|
|
148
|
+
if (consecutiveRpcErrors === RPC_FAILURE_WARN_THRESHOLD) {
|
|
149
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] ${RPC_FAILURE_WARN_THRESHOLD} consecutive Cosmos search errors — RPC may be unhealthy. Continuing until timeout.`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
consecutiveRpcErrors = 0;
|
|
154
|
+
if (search.utxId) {
|
|
155
|
+
childUtxId = search.utxId;
|
|
156
|
+
strippedChildUtxId = stripHex(childUtxId);
|
|
157
|
+
progressHook?.({
|
|
158
|
+
status: 'found',
|
|
159
|
+
elapsedMs: elapsed(),
|
|
160
|
+
childUtxId,
|
|
161
|
+
});
|
|
162
|
+
lastEmittedStatus = 'found';
|
|
163
|
+
}
|
|
164
|
+
else if (lastEmittedStatus !== 'polling') {
|
|
165
|
+
progressHook?.({ status: 'polling', elapsedMs: elapsed() });
|
|
166
|
+
lastEmittedStatus = 'polling';
|
|
167
|
+
}
|
|
168
|
+
}
|
|
128
169
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
// "indexer hasn't seen it yet" and "RPC is down."
|
|
139
|
-
const RPC_FAILURE_WARN_THRESHOLD = 5;
|
|
140
|
-
// When chain reports terminal success but pcTx hasn't populated yet, give
|
|
141
|
-
// the indexer one extra poll cycle to catch up before returning empty hash.
|
|
142
|
-
const MAX_PENDING_TERMINAL_RETRIES = 2;
|
|
143
|
-
while (elapsed() < timeout) {
|
|
144
|
-
pollCount++;
|
|
145
|
-
const pollStart = Date.now();
|
|
146
|
-
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Poll #${pollCount} | Elapsed: ${elapsed()}ms / ${timeout}ms | phase: ${childUtxId ? 'utx-status' : 'child-search'}`);
|
|
147
|
-
// Phase 1 — find child UTX id from the outbound external tx hash
|
|
148
|
-
if (!childUtxId) {
|
|
149
|
-
const search = yield findChildUtxIdFromExternalTx(ctx, outboundExternalTxHash, sourceChain);
|
|
150
|
-
(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}` : ''}`);
|
|
151
|
-
if (search.error) {
|
|
152
|
-
consecutiveRpcErrors++;
|
|
153
|
-
if (consecutiveRpcErrors === RPC_FAILURE_WARN_THRESHOLD) {
|
|
154
|
-
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] ${RPC_FAILURE_WARN_THRESHOLD} consecutive Cosmos search errors — RPC may be unhealthy. Continuing until timeout.`);
|
|
155
|
-
}
|
|
170
|
+
// Phase 2 — once we have the child UTX, query its status until terminal
|
|
171
|
+
if (childUtxId && strippedChildUtxId) {
|
|
172
|
+
try {
|
|
173
|
+
const response = await ctx.pushClient.getUniversalTxByIdV2(strippedChildUtxId);
|
|
174
|
+
consecutiveRpcErrors = 0;
|
|
175
|
+
const utx = response?.universalTx;
|
|
176
|
+
const status = utx?.universalStatus ?? -1;
|
|
177
|
+
if (utx?.pcTx?.[0]?.txHash) {
|
|
178
|
+
pushTxHash = utx.pcTx[0].txHash;
|
|
156
179
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
180
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Poll #${pollCount} utx-status | status: ${status} | pcTx[0].txHash: '${pushTxHash ?? ''}' | pcTx len: ${utx?.pcTx?.length ?? 0}`);
|
|
181
|
+
const failedPcTx = utx?.pcTx?.find((pcTx) => {
|
|
182
|
+
const pcTxStatus = String(pcTx.status || '').toUpperCase();
|
|
183
|
+
return pcTxStatus === 'FAILED' || Boolean(pcTx.errorMsg);
|
|
184
|
+
});
|
|
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?.({
|
|
193
|
+
status: 'confirmed',
|
|
164
194
|
elapsedMs: elapsed(),
|
|
165
195
|
childUtxId,
|
|
196
|
+
pushTxHash,
|
|
166
197
|
});
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
198
|
+
return {
|
|
199
|
+
childUtxId,
|
|
200
|
+
pushTxHash: pushTxHash ?? '',
|
|
201
|
+
sourceChain,
|
|
202
|
+
outboundExternalTxHash,
|
|
203
|
+
status: 'confirmed',
|
|
204
|
+
};
|
|
172
205
|
}
|
|
173
206
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
pushTxHash = utx.pcTx[0].txHash;
|
|
184
|
-
}
|
|
185
|
-
(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}`);
|
|
186
|
-
const failedPcTx = (_k = utx === null || utx === void 0 ? void 0 : utx.pcTx) === null || _k === void 0 ? void 0 : _k.find((pcTx) => {
|
|
187
|
-
const pcTxStatus = String(pcTx.status || '').toUpperCase();
|
|
188
|
-
return pcTxStatus === 'FAILED' || Boolean(pcTx.errorMsg);
|
|
207
|
+
else if (TERMINAL_FAILURE_STATUSES.has(status)) {
|
|
208
|
+
const errMsg = failedPcTx?.errorMsg
|
|
209
|
+
? (0, formatters_1.normalizePcInsufficientFundsError)(failedPcTx.errorMsg)
|
|
210
|
+
: `inbound terminated with status ${status}`;
|
|
211
|
+
progressHook?.({
|
|
212
|
+
status: 'failed',
|
|
213
|
+
elapsedMs: elapsed(),
|
|
214
|
+
childUtxId,
|
|
215
|
+
pushTxHash,
|
|
189
216
|
});
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
217
|
+
return {
|
|
218
|
+
childUtxId,
|
|
219
|
+
pushTxHash: pushTxHash ?? '',
|
|
220
|
+
sourceChain,
|
|
221
|
+
outboundExternalTxHash,
|
|
222
|
+
status: 'failed',
|
|
223
|
+
errorMessage: errMsg,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
else if (failedPcTx) {
|
|
227
|
+
const errMsg = failedPcTx.errorMsg
|
|
228
|
+
? (0, formatters_1.normalizePcInsufficientFundsError)(failedPcTx.errorMsg)
|
|
229
|
+
: `inbound Push tx failed while universalStatus=${status}`;
|
|
230
|
+
progressHook?.({
|
|
231
|
+
status: 'failed',
|
|
232
|
+
elapsedMs: elapsed(),
|
|
233
|
+
childUtxId,
|
|
234
|
+
pushTxHash,
|
|
235
|
+
});
|
|
236
|
+
return {
|
|
237
|
+
childUtxId,
|
|
238
|
+
pushTxHash: pushTxHash ?? '',
|
|
239
|
+
sourceChain,
|
|
240
|
+
outboundExternalTxHash,
|
|
241
|
+
status: 'failed',
|
|
242
|
+
errorMessage: errMsg,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
else if (pushTxHash) {
|
|
246
|
+
// Tiebreaker: cosmos has the Push Chain tx hash populated but the
|
|
247
|
+
// indexer hasn't transitioned universalStatus to a terminal yet.
|
|
248
|
+
// Query Push RPC directly for the receipt — if it's confirmed on
|
|
249
|
+
// chain, treat as terminal-success; if it reverted, treat as
|
|
250
|
+
// terminal-failure. Cosmos-indexer lag stops blocking us here.
|
|
251
|
+
try {
|
|
252
|
+
// Archive-fallback variant: a Push-leg receipt outside the prune
|
|
253
|
+
// window still resolves via the archive node. On chains without an
|
|
254
|
+
// archive endpoint this behaves as a plain prune-only lookup.
|
|
255
|
+
const receipt = await ctx.pushClient.getTransactionReceiptWithArchiveFallback(pushTxHash);
|
|
256
|
+
if (receipt?.status === 'success') {
|
|
257
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Push RPC tiebreaker: ${pushTxHash} confirmed on chain (cosmos still status=${status}); treating as terminal-success`);
|
|
258
|
+
progressHook?.({
|
|
198
259
|
status: 'confirmed',
|
|
199
260
|
elapsedMs: elapsed(),
|
|
200
261
|
childUtxId,
|
|
@@ -202,132 +263,65 @@ function waitForInboundPushTx(ctx_1, outboundExternalTxHash_1, sourceChain_1) {
|
|
|
202
263
|
});
|
|
203
264
|
return {
|
|
204
265
|
childUtxId,
|
|
205
|
-
pushTxHash
|
|
266
|
+
pushTxHash,
|
|
206
267
|
sourceChain,
|
|
207
268
|
outboundExternalTxHash,
|
|
208
269
|
status: 'confirmed',
|
|
209
270
|
};
|
|
210
271
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
status: 'failed',
|
|
228
|
-
errorMessage: errMsg,
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
else if (failedPcTx) {
|
|
232
|
-
const errMsg = failedPcTx.errorMsg
|
|
233
|
-
? (0, formatters_1.normalizePcInsufficientFundsError)(failedPcTx.errorMsg)
|
|
234
|
-
: `inbound Push tx failed while universalStatus=${status}`;
|
|
235
|
-
progressHook === null || progressHook === void 0 ? void 0 : progressHook({
|
|
236
|
-
status: 'failed',
|
|
237
|
-
elapsedMs: elapsed(),
|
|
238
|
-
childUtxId,
|
|
239
|
-
pushTxHash,
|
|
240
|
-
});
|
|
241
|
-
return {
|
|
242
|
-
childUtxId,
|
|
243
|
-
pushTxHash: pushTxHash !== null && pushTxHash !== void 0 ? pushTxHash : '',
|
|
244
|
-
sourceChain,
|
|
245
|
-
outboundExternalTxHash,
|
|
246
|
-
status: 'failed',
|
|
247
|
-
errorMessage: errMsg,
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
else if (pushTxHash) {
|
|
251
|
-
// Tiebreaker: cosmos has the Push Chain tx hash populated but the
|
|
252
|
-
// indexer hasn't transitioned universalStatus to a terminal yet.
|
|
253
|
-
// Query Push RPC directly for the receipt — if it's confirmed on
|
|
254
|
-
// chain, treat as terminal-success; if it reverted, treat as
|
|
255
|
-
// terminal-failure. Cosmos-indexer lag stops blocking us here.
|
|
256
|
-
try {
|
|
257
|
-
// Archive-fallback variant: a Push-leg receipt outside the prune
|
|
258
|
-
// window still resolves via the archive node. On chains without an
|
|
259
|
-
// archive endpoint this behaves as a plain prune-only lookup.
|
|
260
|
-
const receipt = yield ctx.pushClient.getTransactionReceiptWithArchiveFallback(pushTxHash);
|
|
261
|
-
if ((receipt === null || receipt === void 0 ? void 0 : receipt.status) === 'success') {
|
|
262
|
-
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Push RPC tiebreaker: ${pushTxHash} confirmed on chain (cosmos still status=${status}); treating as terminal-success`);
|
|
263
|
-
progressHook === null || progressHook === void 0 ? void 0 : progressHook({
|
|
264
|
-
status: 'confirmed',
|
|
265
|
-
elapsedMs: elapsed(),
|
|
266
|
-
childUtxId,
|
|
267
|
-
pushTxHash,
|
|
268
|
-
});
|
|
269
|
-
return {
|
|
270
|
-
childUtxId,
|
|
271
|
-
pushTxHash,
|
|
272
|
-
sourceChain,
|
|
273
|
-
outboundExternalTxHash,
|
|
274
|
-
status: 'confirmed',
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
if ((receipt === null || receipt === void 0 ? void 0 : receipt.status) === 'reverted') {
|
|
278
|
-
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Push RPC tiebreaker: ${pushTxHash} REVERTED on chain (cosmos still status=${status}); treating as terminal-failure`);
|
|
279
|
-
progressHook === null || progressHook === void 0 ? void 0 : progressHook({
|
|
280
|
-
status: 'failed',
|
|
281
|
-
elapsedMs: elapsed(),
|
|
282
|
-
childUtxId,
|
|
283
|
-
pushTxHash,
|
|
284
|
-
});
|
|
285
|
-
return {
|
|
286
|
-
childUtxId,
|
|
287
|
-
pushTxHash,
|
|
288
|
-
sourceChain,
|
|
289
|
-
outboundExternalTxHash,
|
|
290
|
-
status: 'failed',
|
|
291
|
-
errorMessage: 'Push Chain inbound tx reverted on chain',
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
// receipt missing / pending — keep polling.
|
|
295
|
-
}
|
|
296
|
-
catch (rpcErr) {
|
|
297
|
-
// TransactionReceiptNotFoundError means not yet mined — continue
|
|
298
|
-
// polling. Other errors get logged but don't break the loop.
|
|
299
|
-
const msg = rpcErr instanceof Error ? rpcErr.message : String(rpcErr);
|
|
300
|
-
if (!/not found|TransactionReceiptNotFound|could not be found/i.test(msg)) {
|
|
301
|
-
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Push RPC tiebreaker failed for ${pushTxHash}: ${msg}`);
|
|
302
|
-
}
|
|
272
|
+
if (receipt?.status === 'reverted') {
|
|
273
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Push RPC tiebreaker: ${pushTxHash} REVERTED on chain (cosmos still status=${status}); treating as terminal-failure`);
|
|
274
|
+
progressHook?.({
|
|
275
|
+
status: 'failed',
|
|
276
|
+
elapsedMs: elapsed(),
|
|
277
|
+
childUtxId,
|
|
278
|
+
pushTxHash,
|
|
279
|
+
});
|
|
280
|
+
return {
|
|
281
|
+
childUtxId,
|
|
282
|
+
pushTxHash,
|
|
283
|
+
sourceChain,
|
|
284
|
+
outboundExternalTxHash,
|
|
285
|
+
status: 'failed',
|
|
286
|
+
errorMessage: 'Push Chain inbound tx reverted on chain',
|
|
287
|
+
};
|
|
303
288
|
}
|
|
289
|
+
// receipt missing / pending — keep polling.
|
|
304
290
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
291
|
+
catch (rpcErr) {
|
|
292
|
+
// TransactionReceiptNotFoundError means not yet mined — continue
|
|
293
|
+
// polling. Other errors get logged but don't break the loop.
|
|
294
|
+
const msg = rpcErr instanceof Error ? rpcErr.message : String(rpcErr);
|
|
295
|
+
if (!/not found|TransactionReceiptNotFound|could not be found/i.test(msg)) {
|
|
296
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Push RPC tiebreaker failed for ${pushTxHash}: ${msg}`);
|
|
297
|
+
}
|
|
310
298
|
}
|
|
311
|
-
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] getUniversalTxByIdV2 failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
312
299
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
});
|
|
319
|
-
lastEmittedStatus = 'polling';
|
|
300
|
+
}
|
|
301
|
+
catch (err) {
|
|
302
|
+
consecutiveRpcErrors++;
|
|
303
|
+
if (consecutiveRpcErrors === RPC_FAILURE_WARN_THRESHOLD) {
|
|
304
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] ${RPC_FAILURE_WARN_THRESHOLD} consecutive getUniversalTxByIdV2 errors — RPC may be unhealthy. Continuing until timeout.`);
|
|
320
305
|
}
|
|
306
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] getUniversalTxByIdV2 failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
307
|
+
}
|
|
308
|
+
if (lastEmittedStatus !== 'polling') {
|
|
309
|
+
progressHook?.({
|
|
310
|
+
status: 'polling',
|
|
311
|
+
elapsedMs: elapsed(),
|
|
312
|
+
childUtxId,
|
|
313
|
+
});
|
|
314
|
+
lastEmittedStatus = 'polling';
|
|
321
315
|
}
|
|
322
|
-
if (elapsed() >= timeout)
|
|
323
|
-
break;
|
|
324
|
-
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Poll #${pollCount} not ready (${Date.now() - pollStart}ms). Waiting ${pollingIntervalMs}ms...`);
|
|
325
|
-
yield new Promise((r) => setTimeout(r, pollingIntervalMs));
|
|
326
316
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
317
|
+
if (elapsed() >= timeout)
|
|
318
|
+
break;
|
|
319
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Poll #${pollCount} not ready (${Date.now() - pollStart}ms). Waiting ${pollingIntervalMs}ms...`);
|
|
320
|
+
await new Promise((r) => setTimeout(r, pollingIntervalMs));
|
|
321
|
+
}
|
|
322
|
+
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] TIMEOUT after ${pollCount} polls | elapsed: ${elapsed()}ms`);
|
|
323
|
+
progressHook?.({ status: 'timeout', elapsedMs: elapsed() });
|
|
324
|
+
throw new InboundTimeoutError(outboundExternalTxHash, elapsed());
|
|
331
325
|
}
|
|
332
326
|
/**
|
|
333
327
|
* Thrown by `waitForInboundPushTx` when the polling loop exceeds the
|
|
@@ -336,9 +330,11 @@ function waitForInboundPushTx(ctx_1, outboundExternalTxHash_1, sourceChain_1) {
|
|
|
336
330
|
* from generic failure (→ 399-02) without relying on error-message prefixes.
|
|
337
331
|
*/
|
|
338
332
|
class InboundTimeoutError extends Error {
|
|
333
|
+
code = 'INBOUND_TIMEOUT';
|
|
334
|
+
correlationKey;
|
|
335
|
+
elapsedMs;
|
|
339
336
|
constructor(correlationKey, elapsedMs) {
|
|
340
337
|
super(`Timeout waiting for inbound Push tx after ${Math.round(elapsedMs / 1000)}s (correlation key: ${correlationKey}).`);
|
|
341
|
-
this.code = 'INBOUND_TIMEOUT';
|
|
342
338
|
this.name = 'InboundTimeoutError';
|
|
343
339
|
this.correlationKey = correlationKey;
|
|
344
340
|
this.elapsedMs = elapsedMs;
|