@pushchain/core 5.1.5-alpha.1 → 5.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/package.json +1 -1
- package/src/lib/constants/abi/index.d.ts +2 -0
- package/src/lib/constants/abi/index.js +6 -1
- package/src/lib/constants/abi/uniswap-v3-router.evm.d.ts +58 -0
- package/src/lib/constants/abi/uniswap-v3-router.evm.js +41 -0
- package/src/lib/constants/abi/wpc.evm.d.ts +24 -0
- package/src/lib/constants/abi/wpc.evm.js +27 -0
- package/src/lib/constants/chain.d.ts +1 -0
- package/src/lib/constants/chain.js +8 -6
- package/src/lib/constants/tokens.js +3 -3
- package/src/lib/generated/uexecutor/v2/types.d.ts +14 -0
- package/src/lib/generated/uexecutor/v2/types.js +96 -3
- package/src/lib/orchestrator/internals/cascade.d.ts +1 -1
- package/src/lib/orchestrator/internals/cascade.js +521 -239
- package/src/lib/orchestrator/internals/confirmation.js +60 -15
- package/src/lib/orchestrator/internals/context.d.ts +23 -0
- package/src/lib/orchestrator/internals/context.js +54 -0
- package/src/lib/orchestrator/internals/execute-funds-only.js +47 -21
- package/src/lib/orchestrator/internals/execute-funds-payload.js +53 -31
- package/src/lib/orchestrator/internals/execute-standard.js +137 -26
- package/src/lib/orchestrator/internals/gas-calculator.d.ts +5 -2
- package/src/lib/orchestrator/internals/gas-calculator.js +59 -11
- package/src/lib/orchestrator/internals/gas-usd-sizer.d.ts +53 -0
- package/src/lib/orchestrator/internals/gas-usd-sizer.js +165 -0
- package/src/lib/orchestrator/internals/helpers.js +2 -0
- package/src/lib/orchestrator/internals/inbound-tracker.d.ts +83 -0
- package/src/lib/orchestrator/internals/inbound-tracker.js +322 -0
- package/src/lib/orchestrator/internals/index.d.ts +3 -1
- package/src/lib/orchestrator/internals/index.js +8 -2
- package/src/lib/orchestrator/internals/outbound-sync.d.ts +32 -1
- package/src/lib/orchestrator/internals/outbound-sync.js +154 -17
- package/src/lib/orchestrator/internals/pc-usd-oracle.d.ts +28 -0
- package/src/lib/orchestrator/internals/pc-usd-oracle.js +285 -0
- package/src/lib/orchestrator/internals/progress-route-hooks.d.ts +23 -0
- package/src/lib/orchestrator/internals/progress-route-hooks.js +72 -0
- package/src/lib/orchestrator/internals/push-chain-tx.d.ts +27 -1
- package/src/lib/orchestrator/internals/push-chain-tx.js +111 -15
- package/src/lib/orchestrator/internals/rescue.js +1 -1
- package/src/lib/orchestrator/internals/response-builder.d.ts +5 -0
- package/src/lib/orchestrator/internals/response-builder.js +242 -66
- package/src/lib/orchestrator/internals/route-handlers.js +480 -206
- package/src/lib/orchestrator/internals/tx-transformer.js +293 -35
- package/src/lib/orchestrator/orchestrator.d.ts +7 -1
- package/src/lib/orchestrator/orchestrator.js +108 -56
- package/src/lib/orchestrator/orchestrator.types.d.ts +111 -5
- package/src/lib/orchestrator/payload-builders.d.ts +16 -0
- package/src/lib/orchestrator/payload-builders.js +6 -5
- package/src/lib/orchestrator/route-detector.js +20 -8
- package/src/lib/orchestrator/svm-idl/normalize-address.d.ts +19 -0
- package/src/lib/orchestrator/svm-idl/normalize-address.js +56 -0
- package/src/lib/orchestrator/svm-idl/registry.d.ts +13 -4
- package/src/lib/orchestrator/svm-idl/registry.js +15 -14
- package/src/lib/orchestrator/svm-idl/resolve.js +5 -2
- package/src/lib/progress-hook/progress-hook.d.ts +28 -0
- package/src/lib/progress-hook/progress-hook.js +545 -131
- package/src/lib/progress-hook/progress-hook.types.d.ts +76 -29
- package/src/lib/progress-hook/progress-hook.types.js +74 -35
- package/src/lib/push-client/push-client.d.ts +7 -0
- package/src/lib/push-client/push-client.js +18 -1
- package/src/lib/universal-tx-detector/__tests__/fixtures/builders.d.ts +32 -0
- package/src/lib/universal-tx-detector/__tests__/fixtures/builders.js +65 -0
- package/src/lib/universal-tx-detector/__tests__/fixtures/scenarios.d.ts +72 -0
- package/src/lib/universal-tx-detector/__tests__/fixtures/scenarios.js +669 -0
- package/src/lib/universal-tx-detector/auto-detect.d.ts +37 -0
- package/src/lib/universal-tx-detector/auto-detect.js +112 -0
- package/src/lib/universal-tx-detector/cascade.d.ts +64 -0
- package/src/lib/universal-tx-detector/cascade.js +254 -0
- package/src/lib/universal-tx-detector/child-inbounds.d.ts +58 -0
- package/src/lib/universal-tx-detector/child-inbounds.js +145 -0
- package/src/lib/universal-tx-detector/classify.d.ts +33 -0
- package/src/lib/universal-tx-detector/classify.js +228 -0
- package/src/lib/universal-tx-detector/detector-svm.d.ts +46 -0
- package/src/lib/universal-tx-detector/detector-svm.js +324 -0
- package/src/lib/universal-tx-detector/detector.d.ts +13 -0
- package/src/lib/universal-tx-detector/detector.js +233 -0
- package/src/lib/universal-tx-detector/events.d.ts +765 -0
- package/src/lib/universal-tx-detector/events.js +241 -0
- package/src/lib/universal-tx-detector/index.d.ts +18 -0
- package/src/lib/universal-tx-detector/index.js +36 -0
- package/src/lib/universal-tx-detector/svm-events.d.ts +41 -0
- package/src/lib/universal-tx-detector/svm-events.js +68 -0
- package/src/lib/universal-tx-detector/types.d.ts +100 -0
- package/src/lib/universal-tx-detector/types.js +3 -0
- package/src/lib/utils.d.ts +30 -13
- package/src/lib/utils.js +47 -21
|
@@ -8,11 +8,15 @@ exports.transformToUniversalTxReceipt = transformToUniversalTxReceipt;
|
|
|
8
8
|
exports.reconstructProgressEvents = reconstructProgressEvents;
|
|
9
9
|
exports.detectRouteFromUniversalTxData = detectRouteFromUniversalTxData;
|
|
10
10
|
const tslib_1 = require("tslib");
|
|
11
|
+
const viem_1 = require("viem");
|
|
11
12
|
const chain_1 = require("../../constants/chain");
|
|
12
13
|
const enums_1 = require("../../constants/enums");
|
|
14
|
+
const selectors_1 = require("../../constants/selectors");
|
|
13
15
|
const types_1 = require("../../generated/uexecutor/v1/types");
|
|
16
|
+
const types_2 = require("../../generated/uexecutor/v2/types");
|
|
14
17
|
const progress_hook_1 = tslib_1.__importDefault(require("../../progress-hook/progress-hook"));
|
|
15
18
|
const progress_hook_types_1 = require("../../progress-hook/progress-hook.types");
|
|
19
|
+
const payload_builders_1 = require("../payload-builders");
|
|
16
20
|
const route_detector_1 = require("../route-detector");
|
|
17
21
|
// ============================================================================
|
|
18
22
|
// Receipt Transform
|
|
@@ -42,14 +46,66 @@ function transformToUniversalTxReceipt(receipt, originalTxResponse) {
|
|
|
42
46
|
// Progress Event Reconstruction
|
|
43
47
|
// ============================================================================
|
|
44
48
|
function reconstructProgressEvents(universalTxResponse, universalTxData) {
|
|
45
|
-
var _a;
|
|
49
|
+
var _a, _b, _c;
|
|
50
|
+
const route = universalTxResponse.route;
|
|
51
|
+
const pcTx = (_a = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.pcTx) === null || _a === void 0 ? void 0 : _a[0];
|
|
52
|
+
const isOutboundFailed = (universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.universalStatus) === types_1.UniversalTxStatus.OUTBOUND_FAILED;
|
|
53
|
+
const isPcFailed = (pcTx === null || pcTx === void 0 ? void 0 : pcTx.status) === 'FAILED';
|
|
54
|
+
// R1 fallback keeps the inclusive view (any terminal failure → 199-02).
|
|
55
|
+
// R2 and R3 reconstructors narrow to Push-chain-only failures (see call
|
|
56
|
+
// sites below) — an outbound-leg revert is re-detected during wait() by
|
|
57
|
+
// `waitForOutboundTx` and emitted as 299-02 / 399-02 with the correctly
|
|
58
|
+
// scoped phase ('outbound' + source-chain). Emitting in both places
|
|
59
|
+
// would double-fire the terminal with a misleading 'push' title on top.
|
|
60
|
+
const isFailed = isPcFailed || isOutboundFailed;
|
|
61
|
+
const errorMsg = isOutboundFailed
|
|
62
|
+
? 'Outbound transaction failed (status: OUTBOUND_FAILED)'
|
|
63
|
+
: ((pcTx === null || pcTx === void 0 ? void 0 : pcTx.errorMsg) || 'Unknown error');
|
|
64
|
+
// Route 2 / 3 reconstruction — keep parity with live emission from
|
|
65
|
+
// route-handlers.ts (which fires 201/203/207 or 301/303/307 then suppresses
|
|
66
|
+
// R1 IDs via fireProgressHook). Skip the R1 101–107 sequence here; it would
|
|
67
|
+
// only fire for R2/R3 because reconstructProgressEvents bypasses
|
|
68
|
+
// fireProgressHook (writes to events[] directly).
|
|
69
|
+
// For R2/R3 we only emit the reconstructed terminal when the Push-chain
|
|
70
|
+
// leg itself failed — so prefer pcTx.errorMsg over the outbound-failed
|
|
71
|
+
// sentinel. The outer `errorMsg` above carries the outbound text when
|
|
72
|
+
// `isOutboundFailed` is set; that path is handled by wait() instead.
|
|
73
|
+
const pcErrorMsg = (pcTx === null || pcTx === void 0 ? void 0 : pcTx.errorMsg) || 'Unknown error';
|
|
74
|
+
// Multichain cascade: a single Push-chain tx that fanned out into >1
|
|
75
|
+
// outbound legs (executeTransactions([tx1, tx2, …])). The cosmos record
|
|
76
|
+
// carries one UniversalTx with multiple outboundTx entries; wrap the
|
|
77
|
+
// per-leg R2/R3 backbones with the SEND-TX-001 / 002-xx / 999-xx markers
|
|
78
|
+
// so replay parity matches live cascade emission.
|
|
79
|
+
if (((_c = (_b = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.outboundTx) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) > 1) {
|
|
80
|
+
return reconstructMultichain(universalTxResponse, universalTxData, isFailed, errorMsg);
|
|
81
|
+
}
|
|
82
|
+
if (route === route_detector_1.TransactionRoute.UOA_TO_CEA) {
|
|
83
|
+
// R2: only Push-chain revert triggers the 299-02 terminal here; a
|
|
84
|
+
// cosmos OUTBOUND_FAILED without pcTx.FAILED is handled by wait().
|
|
85
|
+
return reconstructR2(universalTxResponse, universalTxData, isPcFailed, pcErrorMsg);
|
|
86
|
+
}
|
|
87
|
+
if (route === route_detector_1.TransactionRoute.CEA_TO_PUSH) {
|
|
88
|
+
// R3: same narrowing — only pcTx.FAILED triggers reconstructed 399-02.
|
|
89
|
+
return reconstructR3(universalTxResponse, universalTxData, isPcFailed, pcErrorMsg);
|
|
90
|
+
}
|
|
91
|
+
// Route 1 (and Route 4 fallback while R4 has no spec'd IDs) — emit the
|
|
92
|
+
// safe R1 backbone that applies to every sub-path: origin → gas → UEA
|
|
93
|
+
// (non-Push only) → broadcast → terminal. The sub-path-specific hooks
|
|
94
|
+
// (104-xx signature, 105-xx fee-lock, 106-xx funds-bridge) are intentionally
|
|
95
|
+
// omitted from reconstruction because R1 doesn't register a UniversalTx
|
|
96
|
+
// on Push Chain, so `universalTxData` is usually undefined here and we
|
|
97
|
+
// have no reliable signal to tell the three paths apart. Callers who want
|
|
98
|
+
// the full live sequence should either register `progressHook` at
|
|
99
|
+
// `initialize()` time (client-level) or call `tx.progressHook(cb)` after
|
|
100
|
+
// sendTransaction — both deliver the full stream from the execute-phase
|
|
101
|
+
// event buffer.
|
|
46
102
|
const events = [];
|
|
47
103
|
const originParts = universalTxResponse.origin.split(':');
|
|
48
104
|
const chainNamespace = originParts.length >= 2 ? `${originParts[0]}:${originParts[1]}` : originParts[0];
|
|
49
105
|
const originAddress = originParts.length >= 3 ? originParts[2] : universalTxResponse.from;
|
|
50
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.
|
|
51
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.
|
|
52
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.
|
|
106
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_101](chainNamespace, originAddress));
|
|
107
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_102_01]());
|
|
108
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_102_02](universalTxResponse.gasLimit));
|
|
53
109
|
const pushChainIds = [
|
|
54
110
|
chain_1.CHAIN_INFO[enums_1.CHAIN.PUSH_MAINNET].chainId,
|
|
55
111
|
chain_1.CHAIN_INFO[enums_1.CHAIN.PUSH_TESTNET_DONUT].chainId,
|
|
@@ -57,47 +113,239 @@ function reconstructProgressEvents(universalTxResponse, universalTxData) {
|
|
|
57
113
|
];
|
|
58
114
|
const isPushOrigin = pushChainIds.some((id) => chainNamespace.includes(`eip155:${id}`));
|
|
59
115
|
if (!isPushOrigin) {
|
|
60
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.
|
|
61
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.
|
|
116
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_01]());
|
|
117
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_02](universalTxResponse.from, true));
|
|
62
118
|
}
|
|
63
|
-
|
|
64
|
-
const hasFundsFlow = inboundTx && BigInt(inboundTx.amount || '0') > BigInt(0);
|
|
65
|
-
if (!isPushOrigin) {
|
|
66
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_02]());
|
|
67
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_03]());
|
|
68
|
-
}
|
|
69
|
-
if (hasFundsFlow && inboundTx) {
|
|
70
|
-
const amount = BigInt(inboundTx.amount);
|
|
71
|
-
const decimals = 18;
|
|
72
|
-
const symbol = 'TOKEN';
|
|
73
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_01](amount, decimals, symbol));
|
|
74
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_02](inboundTx.txHash, amount, decimals, symbol));
|
|
75
|
-
const confirmations = 1;
|
|
76
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_03](confirmations));
|
|
77
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_03_02](confirmations, confirmations));
|
|
78
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_04]());
|
|
79
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_05]());
|
|
80
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_06](amount, decimals, symbol));
|
|
81
|
-
}
|
|
82
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_07]());
|
|
83
|
-
const pcTx = (_a = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.pcTx) === null || _a === void 0 ? void 0 : _a[0];
|
|
84
|
-
const isOutboundFailed = (universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.universalStatus) === types_1.UniversalTxStatus.OUTBOUND_FAILED;
|
|
85
|
-
const isPcFailed = (pcTx === null || pcTx === void 0 ? void 0 : pcTx.status) === 'FAILED';
|
|
86
|
-
const isFailed = isPcFailed || isOutboundFailed;
|
|
119
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_107]());
|
|
87
120
|
if (isFailed) {
|
|
88
|
-
|
|
89
|
-
? 'Outbound transaction failed (status: OUTBOUND_FAILED)'
|
|
90
|
-
: ((pcTx === null || pcTx === void 0 ? void 0 : pcTx.errorMsg) || 'Unknown error');
|
|
91
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_02](errorMsg));
|
|
121
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02](errorMsg));
|
|
92
122
|
}
|
|
93
123
|
else {
|
|
94
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.
|
|
124
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_01]([universalTxResponse]));
|
|
125
|
+
}
|
|
126
|
+
return events;
|
|
127
|
+
}
|
|
128
|
+
function reconstructR2(universalTxResponse, universalTxData, isFailed, errorMsg) {
|
|
129
|
+
var _a, _b, _c, _d;
|
|
130
|
+
const events = [];
|
|
131
|
+
const targetChain = ((_a = universalTxResponse.chain) !== null && _a !== void 0 ? _a : 'external');
|
|
132
|
+
const targetAddress = (_d = (_c = (_b = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.outboundTx) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.recipient) !== null && _d !== void 0 ? _d : universalTxResponse.to;
|
|
133
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_201](targetChain, targetAddress));
|
|
134
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_202_01](targetChain));
|
|
135
|
+
// Reconstruction: gas split unavailable from historical data — pass zeroes
|
|
136
|
+
// so the shape matches live emission. totalCost derives to 0 in the message,
|
|
137
|
+
// which is acceptable for a tracked (past) transaction.
|
|
138
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_202_02](targetChain, BigInt(0), BigInt(0)));
|
|
139
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_01](targetChain));
|
|
140
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_02](universalTxResponse.from, targetAddress, targetChain, true));
|
|
141
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_204_01]());
|
|
142
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_204_02]());
|
|
143
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_204_03]());
|
|
144
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_207](targetChain));
|
|
145
|
+
if (isFailed) {
|
|
146
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_02](errorMsg));
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// Push Chain success is intermediate for R2 — the wait() outbound poll
|
|
150
|
+
// appends the real terminal (299-01/02/03) once the external leg resolves.
|
|
151
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_99](targetChain, universalTxResponse.hash));
|
|
152
|
+
}
|
|
153
|
+
return events;
|
|
154
|
+
}
|
|
155
|
+
function reconstructR3(universalTxResponse, universalTxData, isFailed, errorMsg) {
|
|
156
|
+
var _a, _b, _c, _d;
|
|
157
|
+
const events = [];
|
|
158
|
+
const sourceChain = ((_a = universalTxResponse.chain) !== null && _a !== void 0 ? _a : 'source');
|
|
159
|
+
const ceaAddress = (_d = (_c = (_b = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.outboundTx) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.recipient) !== null && _d !== void 0 ? _d : universalTxResponse.to;
|
|
160
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_301](sourceChain, ceaAddress));
|
|
161
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_302_01](sourceChain));
|
|
162
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_302_02](sourceChain, BigInt(0), BigInt(0)));
|
|
163
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_01](sourceChain));
|
|
164
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_02](universalTxResponse.from, ceaAddress, sourceChain));
|
|
165
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_304_01]());
|
|
166
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_304_02]());
|
|
167
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_304_03]());
|
|
168
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_307](sourceChain));
|
|
169
|
+
if (isFailed) {
|
|
170
|
+
// Reconstructed Push-chain-tx failure — phase='push' so the title reads
|
|
171
|
+
// "Push Chain Tx Failed" rather than the inbound copy.
|
|
172
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](errorMsg, 'push'));
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
// Push Chain success is intermediate for R3 — wait() drives the source-chain
|
|
176
|
+
// CEA poll (309-xx) and the inbound-to-Push poll (310-xx / 399-xx) on top.
|
|
177
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_99_99](universalTxResponse.hash));
|
|
178
|
+
}
|
|
179
|
+
return events;
|
|
180
|
+
}
|
|
181
|
+
// ============================================================================
|
|
182
|
+
// Multichain cascade reconstruction
|
|
183
|
+
// ============================================================================
|
|
184
|
+
function decodeUeaMulticall(data) {
|
|
185
|
+
if (!data)
|
|
186
|
+
return null;
|
|
187
|
+
const normalized = data.startsWith('0x') ? data : `0x${data}`;
|
|
188
|
+
if (!normalized.toLowerCase().startsWith(selectors_1.UEA_MULTICALL_SELECTOR))
|
|
189
|
+
return null;
|
|
190
|
+
try {
|
|
191
|
+
const body = `0x${normalized.slice(10)}`;
|
|
192
|
+
const [tuples] = (0, viem_1.decodeAbiParameters)([payload_builders_1.MULTICALL_TUPLE_TYPE], body);
|
|
193
|
+
return tuples;
|
|
194
|
+
}
|
|
195
|
+
catch (_a) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Count the merged R1 calls embedded inside an R3 outbound's payload.
|
|
201
|
+
*
|
|
202
|
+
* The outbound payload on-chain is UEA_MULTICALL_SELECTOR + abi-encoded
|
|
203
|
+
* MultiCall[] targeting the CEA. One of those inner calls is
|
|
204
|
+
* `sendUniversalTxToUEA(token, amount, payload, revertRecipient)` whose
|
|
205
|
+
* `payload` argument is itself a UEA_MULTICALL_SELECTOR + MultiCall[] blob
|
|
206
|
+
* — that blob is what will execute on Push Chain after the round-trip. Its
|
|
207
|
+
* tuple count equals the number of user R1 hops merged into this R3 leg.
|
|
208
|
+
*/
|
|
209
|
+
function decodeR3MergedInnerCount(outboundPayload) {
|
|
210
|
+
const outerCalls = decodeUeaMulticall(outboundPayload);
|
|
211
|
+
if (!outerCalls)
|
|
212
|
+
return 0;
|
|
213
|
+
for (const call of outerCalls) {
|
|
214
|
+
const d = (call.data || '').toLowerCase();
|
|
215
|
+
if (!d.startsWith(`0x${SEND_UNIVERSAL_TX_TO_UEA_SELECTOR}`))
|
|
216
|
+
continue;
|
|
217
|
+
try {
|
|
218
|
+
const innerBody = `0x${d.slice(10)}`;
|
|
219
|
+
// sendUniversalTxToUEA(token, amount, payload, revertRecipient).
|
|
220
|
+
// The `payload` arg is an ABI-encoded UniversalPayload struct
|
|
221
|
+
// produced by buildInboundUniversalPayload() — its `.data` field is
|
|
222
|
+
// the UEA_MULTICALL bytes that will execute on Push after the
|
|
223
|
+
// round-trip.
|
|
224
|
+
const [, , upStructBytes] = (0, viem_1.decodeAbiParameters)([
|
|
225
|
+
{ type: 'address' },
|
|
226
|
+
{ type: 'uint256' },
|
|
227
|
+
{ type: 'bytes' },
|
|
228
|
+
{ type: 'address' },
|
|
229
|
+
], innerBody);
|
|
230
|
+
const [universalPayload] = (0, viem_1.decodeAbiParameters)([
|
|
231
|
+
{
|
|
232
|
+
type: 'tuple',
|
|
233
|
+
components: [
|
|
234
|
+
{ name: 'to', type: 'address' },
|
|
235
|
+
{ name: 'value', type: 'uint256' },
|
|
236
|
+
{ name: 'data', type: 'bytes' },
|
|
237
|
+
{ name: 'gasLimit', type: 'uint256' },
|
|
238
|
+
{ name: 'maxFeePerGas', type: 'uint256' },
|
|
239
|
+
{ name: 'maxPriorityFeePerGas', type: 'uint256' },
|
|
240
|
+
{ name: 'nonce', type: 'uint256' },
|
|
241
|
+
{ name: 'deadline', type: 'uint256' },
|
|
242
|
+
{ name: 'vType', type: 'uint8' },
|
|
243
|
+
],
|
|
244
|
+
},
|
|
245
|
+
], upStructBytes);
|
|
246
|
+
const pushCalls = decodeUeaMulticall(universalPayload.data);
|
|
247
|
+
if (pushCalls)
|
|
248
|
+
return pushCalls.length;
|
|
249
|
+
}
|
|
250
|
+
catch (_a) {
|
|
251
|
+
// fall through to next outer call
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return 0;
|
|
255
|
+
}
|
|
256
|
+
function reconstructMultichain(universalTxResponse, universalTxData, isFailed, errorMsg) {
|
|
257
|
+
const events = [];
|
|
258
|
+
const outbounds = universalTxData.outboundTx;
|
|
259
|
+
// Merged-R1 recovery: each R3 outbound's payload embeds the
|
|
260
|
+
// sendUniversalTxToUEA call whose `payload` arg is the UEA multicall that
|
|
261
|
+
// will execute on Push after the round-trip. Its tuple count equals the
|
|
262
|
+
// number of user R1 hops the orchestrator folded into that R3 leg.
|
|
263
|
+
// Total user-level hopCount =
|
|
264
|
+
// (outbounds that are NOT R3) + Σ (merged inner-call count per R3 leg).
|
|
265
|
+
// Falls back to `outbounds.length` when no R3 legs or decode fails
|
|
266
|
+
// (pure R2 cascade).
|
|
267
|
+
let r3LegCount = 0;
|
|
268
|
+
let totalMergedInner = 0;
|
|
269
|
+
for (const ob of outbounds) {
|
|
270
|
+
const isR3 = (ob.payload || '')
|
|
271
|
+
.toLowerCase()
|
|
272
|
+
.includes(SEND_UNIVERSAL_TX_TO_UEA_SELECTOR);
|
|
273
|
+
if (!isR3)
|
|
274
|
+
continue;
|
|
275
|
+
r3LegCount += 1;
|
|
276
|
+
const inner = decodeR3MergedInnerCount(ob.payload || '');
|
|
277
|
+
// When decode fails, assume the R3 leg represents 1 user hop so the
|
|
278
|
+
// fallback converges on outbounds.length.
|
|
279
|
+
totalMergedInner += inner > 0 ? inner : 1;
|
|
280
|
+
}
|
|
281
|
+
const recovered = r3LegCount > 0
|
|
282
|
+
? outbounds.length - r3LegCount + totalMergedInner
|
|
283
|
+
: outbounds.length;
|
|
284
|
+
// Defensive clamp: never under-count what's already visible on-chain.
|
|
285
|
+
const hopCount = Math.max(recovered, outbounds.length);
|
|
286
|
+
// Source chain for SEND-TX-001: the Push Chain (initiator of a cascade
|
|
287
|
+
// always executes a multicall on Push first). Fall back to the response's
|
|
288
|
+
// chain if origin parsing fails.
|
|
289
|
+
const pushChainId = chain_1.CHAIN_INFO[enums_1.CHAIN.PUSH_TESTNET_DONUT].chainId;
|
|
290
|
+
const sourceChain = `eip155:${pushChainId}`;
|
|
291
|
+
const destChains = outbounds.map((ob) => ob.destinationChain);
|
|
292
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_001](hopCount, [
|
|
293
|
+
sourceChain,
|
|
294
|
+
...destChains,
|
|
295
|
+
]));
|
|
296
|
+
let failedAt = null;
|
|
297
|
+
let failureMsg = errorMsg;
|
|
298
|
+
outbounds.forEach((ob, i) => {
|
|
299
|
+
var _a;
|
|
300
|
+
const hopNum = i + 1;
|
|
301
|
+
const fromChain = i === 0 ? sourceChain : outbounds[i - 1].destinationChain;
|
|
302
|
+
const toChain = ob.destinationChain;
|
|
303
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_002_01](hopNum, hopCount, fromChain, toChain));
|
|
304
|
+
// Build a single-leg view so the per-leg reconstructors (R2/R3) emit
|
|
305
|
+
// their usual backbone. We narrow `outboundTx` to this leg so any field
|
|
306
|
+
// reads (e.g. `outboundTx[0].recipient`) resolve to this leg's data.
|
|
307
|
+
const legResponse = Object.assign(Object.assign({}, universalTxResponse), { chain: toChain, chainNamespace: toChain });
|
|
308
|
+
const legData = Object.assign(Object.assign({}, universalTxData), { outboundTx: [ob] });
|
|
309
|
+
const payload = (ob.payload || '').toLowerCase();
|
|
310
|
+
const isR3Leg = payload.includes(SEND_UNIVERSAL_TX_TO_UEA_SELECTOR);
|
|
311
|
+
const legFailed = ob.outboundStatus === types_2.OutboundStatus.REVERTED;
|
|
312
|
+
const legError = ob.abortReason || ((_a = ob.observedTx) === null || _a === void 0 ? void 0 : _a.errorMsg) || 'leg execution failed';
|
|
313
|
+
if (isR3Leg) {
|
|
314
|
+
events.push(...reconstructR3(legResponse, legData, legFailed, legError));
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
events.push(...reconstructR2(legResponse, legData, legFailed, legError));
|
|
318
|
+
}
|
|
319
|
+
if (!legFailed) {
|
|
320
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_002_99_99](hopNum, hopCount));
|
|
321
|
+
}
|
|
322
|
+
else if (failedAt === null) {
|
|
323
|
+
failedAt = hopNum;
|
|
324
|
+
failureMsg = legError;
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
if (failedAt !== null) {
|
|
328
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_999_02](failedAt, hopCount, failureMsg));
|
|
329
|
+
}
|
|
330
|
+
else if (isFailed) {
|
|
331
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_999_02](hopCount, hopCount, errorMsg));
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_999_01](hopCount));
|
|
95
335
|
}
|
|
96
336
|
return events;
|
|
97
337
|
}
|
|
98
338
|
// ============================================================================
|
|
99
339
|
// Route Detection from V2 Data
|
|
100
340
|
// ============================================================================
|
|
341
|
+
/**
|
|
342
|
+
* Function selector of `sendUniversalTxToUEA(address,uint256,bytes,address)`.
|
|
343
|
+
* R3 (CEA → Push round-trip) outbound payloads always contain a CEA
|
|
344
|
+
* self-call to this method — its presence in the outbound payload bytes
|
|
345
|
+
* disambiguates a fresh R3 outbound (no inbound leg yet) from R2.
|
|
346
|
+
* Verified via `keccak256(toBytes('sendUniversalTxToUEA(address,uint256,bytes,address)')).slice(0,10)`.
|
|
347
|
+
*/
|
|
348
|
+
const SEND_UNIVERSAL_TX_TO_UEA_SELECTOR = 'e7c1e3fc';
|
|
101
349
|
function detectRouteFromUniversalTxData(universalTxData) {
|
|
102
350
|
if (!universalTxData)
|
|
103
351
|
return undefined;
|
|
@@ -109,6 +357,16 @@ function detectRouteFromUniversalTxData(universalTxData) {
|
|
|
109
357
|
types_1.UniversalTxStatus.OUTBOUND_FAILED,
|
|
110
358
|
].includes(universalTxData.universalStatus);
|
|
111
359
|
if (hasOutbound || statusIndicatesOutbound) {
|
|
360
|
+
// Disambiguate R3 from R2 when the inbound leg of an R3 round-trip
|
|
361
|
+
// hasn't materialized yet (fresh tx). R3 outbounds always carry a CEA
|
|
362
|
+
// self-call to `sendUniversalTxToUEA(...)` — its selector in the
|
|
363
|
+
// payload bytes is a deterministic signal.
|
|
364
|
+
const r3Signal = universalTxData.outboundTx.some((ob) => {
|
|
365
|
+
const payload = (ob.payload || '').toLowerCase();
|
|
366
|
+
return payload.includes(SEND_UNIVERSAL_TX_TO_UEA_SELECTOR);
|
|
367
|
+
});
|
|
368
|
+
if (r3Signal)
|
|
369
|
+
return route_detector_1.TransactionRoute.CEA_TO_PUSH;
|
|
112
370
|
return hasInbound
|
|
113
371
|
? route_detector_1.TransactionRoute.CEA_TO_CEA
|
|
114
372
|
: route_detector_1.TransactionRoute.UOA_TO_CEA;
|
|
@@ -5,6 +5,7 @@ import { ProgressEvent } from '../progress-hook/progress-hook.types';
|
|
|
5
5
|
import { PushClient } from '../push-client/push-client';
|
|
6
6
|
import type { UniversalAccount, UniversalSigner } from '../universal/universal.types';
|
|
7
7
|
import { ExecuteParams, UniversalExecuteParams, PreparedUniversalTx, CascadedTxResponse, RescueFundsParams } from './orchestrator.types';
|
|
8
|
+
import { TransactionRoute } from './route-detector';
|
|
8
9
|
export declare class Orchestrator {
|
|
9
10
|
private readonly universalSigner;
|
|
10
11
|
private pushNetwork;
|
|
@@ -16,6 +17,11 @@ export declare class Orchestrator {
|
|
|
16
17
|
get pushClient(): PushClient;
|
|
17
18
|
accountStatusCache: AccountStatus | null;
|
|
18
19
|
accountStatusReadyPromise?: Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* @internal Mirrors `OrchestratorContext.currentRoute` — set at the top of
|
|
22
|
+
* execute()/trackTransaction() so emission sites pick the right ID range.
|
|
23
|
+
*/
|
|
24
|
+
currentRoute?: TransactionRoute;
|
|
19
25
|
private get ctx();
|
|
20
26
|
private _getResponseCallbacks;
|
|
21
27
|
private _getCascadeCallbacks;
|
|
@@ -87,7 +93,7 @@ export declare class Orchestrator {
|
|
|
87
93
|
/**
|
|
88
94
|
* Queries gas fee for an outbound transaction from the UniversalCore contract.
|
|
89
95
|
*/
|
|
90
|
-
queryOutboundGasFee(prc20Token: `0x${string}`, gasLimit: bigint): Promise<{
|
|
96
|
+
queryOutboundGasFee(prc20Token: `0x${string}`, gasLimit: bigint, destinationChain?: CHAIN): Promise<{
|
|
91
97
|
gasToken: `0x${string}`;
|
|
92
98
|
gasFee: bigint;
|
|
93
99
|
protocolFee: bigint;
|
|
@@ -23,6 +23,7 @@ class Orchestrator {
|
|
|
23
23
|
transformToUniversalTxReceipt: (receipt, resp) => (0, internals_1.transformToUniversalTxReceipt)(receipt, resp),
|
|
24
24
|
printLog: (msg) => (0, internals_1.printLog)(this.ctx, msg),
|
|
25
25
|
outboundConstants: { initialWaitMs: internals_1.OUTBOUND_INITIAL_WAIT_MS, pollingIntervalMs: internals_1.OUTBOUND_POLL_INTERVAL_MS, maxTimeoutMs: internals_1.OUTBOUND_MAX_TIMEOUT_MS },
|
|
26
|
+
inboundConstants: { initialWaitMs: internals_1.INBOUND_INITIAL_WAIT_MS, pollingIntervalMs: internals_1.OUTBOUND_POLL_INTERVAL_MS, maxTimeoutMs: internals_1.INBOUND_MAX_TIMEOUT_MS },
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
_getCascadeCallbacks() {
|
|
@@ -130,67 +131,118 @@ class Orchestrator {
|
|
|
130
131
|
execute(params) {
|
|
131
132
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
132
133
|
var _a, _b, _c, _d;
|
|
133
|
-
//
|
|
134
|
+
// Snapshot the caller's active route — `executeMultiChain` recurses into
|
|
135
|
+
// this same method for R2/R3's inner Push-side execution, and without
|
|
136
|
+
// snapshot/restore the recursive `detectRoute(params)` would clobber the
|
|
137
|
+
// outer R2/R3 route with UOA_TO_PUSH (the inner `to` is a string, no
|
|
138
|
+
// `from`), defeating R1-suppression in fireProgressHook.
|
|
139
|
+
const previousRoute = this.currentRoute;
|
|
140
|
+
const isRecursiveInnerCall = previousRoute !== undefined;
|
|
141
|
+
let detectedRoute;
|
|
134
142
|
try {
|
|
135
|
-
|
|
136
|
-
yield ((_a = this.accountStatusReadyPromise) !== null && _a !== void 0 ? _a : this.getAccountStatus());
|
|
137
|
-
}
|
|
138
|
-
// If background resolved but cache still empty (timeout/error), fetch fresh
|
|
139
|
-
if (!this.accountStatusCache || !this.accountStatusCache.uea.loaded) {
|
|
140
|
-
yield this.getAccountStatus();
|
|
141
|
-
}
|
|
142
|
-
if (((_b = this.accountStatusCache) === null || _b === void 0 ? void 0 : _b.uea.deployed) &&
|
|
143
|
-
((_c = this.accountStatusCache) === null || _c === void 0 ? void 0 : _c.uea.requiresUpgrade)) {
|
|
144
|
-
yield this.upgradeAccount({ progressHook: this.progressHook });
|
|
145
|
-
}
|
|
143
|
+
detectedRoute = (0, route_detector_1.detectRoute)(params);
|
|
146
144
|
}
|
|
147
|
-
catch (
|
|
148
|
-
|
|
145
|
+
catch (_e) {
|
|
146
|
+
detectedRoute = route_detector_1.TransactionRoute.UOA_TO_PUSH;
|
|
149
147
|
}
|
|
150
|
-
//
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
this.progressHook = (event) => {
|
|
162
|
-
eventBuffer.push(event);
|
|
163
|
-
if (originalHook)
|
|
164
|
-
originalHook(event);
|
|
165
|
-
};
|
|
148
|
+
// Don't downgrade an outer R2/R3/R4 route when the recursive inner call
|
|
149
|
+
// resolves to R1 — keep the outer perspective so emission stays consistent.
|
|
150
|
+
const shouldPreserveOuter = isRecursiveInnerCall &&
|
|
151
|
+
previousRoute !== route_detector_1.TransactionRoute.UOA_TO_PUSH &&
|
|
152
|
+
detectedRoute === route_detector_1.TransactionRoute.UOA_TO_PUSH;
|
|
153
|
+
this.currentRoute = shouldPreserveOuter ? previousRoute : detectedRoute;
|
|
154
|
+
// Reset the terminal-emitted flag at the start of each execute call so
|
|
155
|
+
// the outer catch below can tell whether a route handler already fired
|
|
156
|
+
// a terminal-ish error hook (104-04 / 204-04 / 304-04 / 199-02) and
|
|
157
|
+
// should suppress the second terminal (199-02 / 299-02 / 399-02).
|
|
158
|
+
this.ctx._routeTerminalEmitted = false;
|
|
166
159
|
try {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
160
|
+
// Lazy UEA upgrade check
|
|
161
|
+
try {
|
|
162
|
+
if (!this.accountStatusCache || !this.accountStatusCache.uea.loaded) {
|
|
163
|
+
yield ((_a = this.accountStatusReadyPromise) !== null && _a !== void 0 ? _a : this.getAccountStatus());
|
|
164
|
+
}
|
|
165
|
+
// If background resolved but cache still empty (timeout/error), fetch fresh
|
|
166
|
+
if (!this.accountStatusCache || !this.accountStatusCache.uea.loaded) {
|
|
167
|
+
yield this.getAccountStatus();
|
|
168
|
+
}
|
|
169
|
+
if (((_b = this.accountStatusCache) === null || _b === void 0 ? void 0 : _b.uea.deployed) &&
|
|
170
|
+
((_c = this.accountStatusCache) === null || _c === void 0 ? void 0 : _c.uea.requiresUpgrade)) {
|
|
171
|
+
yield this.upgradeAccount({ progressHook: this.progressHook });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
(0, internals_1.printLog)(this.ctx, `Lazy UEA upgrade check failed: ${err instanceof Error ? err.message : String(err)}. Proceeding with transaction.`);
|
|
176
|
+
}
|
|
177
|
+
// Check if this is a multi-chain request (has ChainTarget or from.chain)
|
|
178
|
+
const isMultiChain = (0, route_detector_1.isChainTarget)(params.to) || ('from' in params && ((_d = params.from) === null || _d === void 0 ? void 0 : _d.chain));
|
|
179
|
+
if (isMultiChain) {
|
|
180
|
+
return yield (0, internals_1.executeMultiChain)(this.ctx, params, this.execute.bind(this));
|
|
181
|
+
}
|
|
182
|
+
// Standard Push Chain execution (Route 1)
|
|
183
|
+
const execute = params;
|
|
184
|
+
const hasFunds = !!execute.funds;
|
|
185
|
+
const hasData = execute.data && execute.data !== '0x';
|
|
186
|
+
const eventBuffer = [];
|
|
187
|
+
const originalHook = this.progressHook;
|
|
188
|
+
this.progressHook = (event) => {
|
|
189
|
+
eventBuffer.push(event);
|
|
190
|
+
if (originalHook)
|
|
191
|
+
originalHook(event);
|
|
192
|
+
};
|
|
193
|
+
try {
|
|
194
|
+
const rcb = () => this._getResponseCallbacks();
|
|
195
|
+
if (execute.funds) {
|
|
196
|
+
return !hasData
|
|
197
|
+
? yield (0, internals_1.executeFundsOnly)(this.ctx, execute, eventBuffer, rcb)
|
|
198
|
+
: yield (0, internals_1.executeFundsWithPayload)(this.ctx, execute, eventBuffer, rcb);
|
|
199
|
+
}
|
|
200
|
+
return yield (0, internals_1.executeStandardPayload)(this.ctx, execute, eventBuffer, rcb);
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
const errMessage = err instanceof Error
|
|
204
|
+
? err.message
|
|
205
|
+
: typeof err === 'string'
|
|
206
|
+
? err
|
|
207
|
+
: (() => {
|
|
208
|
+
try {
|
|
209
|
+
return JSON.stringify(err);
|
|
210
|
+
}
|
|
211
|
+
catch (_a) {
|
|
212
|
+
return 'Unknown error';
|
|
213
|
+
}
|
|
214
|
+
})();
|
|
215
|
+
// Only the outermost frame emits the terminal error hook, and it picks
|
|
216
|
+
// the route-correct ID. Recursive inner frames just re-throw so the
|
|
217
|
+
// outer catch drives emission — avoids double-firing 199/299/399 events.
|
|
218
|
+
// Additionally, if an inner route handler already fired a terminal-ish
|
|
219
|
+
// error (104-04/204-04/304-04/199-02 via execute-standard), the flag is
|
|
220
|
+
// set on ctx and we skip emitting a second terminal here.
|
|
221
|
+
if (!isRecursiveInnerCall && !this.ctx._routeTerminalEmitted) {
|
|
222
|
+
// For R3, the failure surfaced during execute-phase (pre-wait) is a
|
|
223
|
+
// Push-chain-side failure — tag phase='push' so 399-02 renders the
|
|
224
|
+
// correct "Push Chain Tx Failed" title instead of the inbound copy.
|
|
225
|
+
if (this.currentRoute === route_detector_1.TransactionRoute.CEA_TO_PUSH) {
|
|
226
|
+
(0, internals_1.fireProgressHook)(this.ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02, errMessage, 'push');
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
const terminalId = this.currentRoute === route_detector_1.TransactionRoute.UOA_TO_CEA
|
|
230
|
+
? progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_02
|
|
231
|
+
: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02;
|
|
232
|
+
(0, internals_1.fireProgressHook)(this.ctx, terminalId, errMessage);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
throw err;
|
|
236
|
+
}
|
|
237
|
+
finally {
|
|
238
|
+
// Restore original progressHook
|
|
239
|
+
this.progressHook = originalHook;
|
|
172
240
|
}
|
|
173
|
-
return yield (0, internals_1.executeStandardPayload)(this.ctx, execute, eventBuffer, rcb);
|
|
174
|
-
}
|
|
175
|
-
catch (err) {
|
|
176
|
-
const errMessage = err instanceof Error
|
|
177
|
-
? err.message
|
|
178
|
-
: typeof err === 'string'
|
|
179
|
-
? err
|
|
180
|
-
: (() => {
|
|
181
|
-
try {
|
|
182
|
-
return JSON.stringify(err);
|
|
183
|
-
}
|
|
184
|
-
catch (_a) {
|
|
185
|
-
return 'Unknown error';
|
|
186
|
-
}
|
|
187
|
-
})();
|
|
188
|
-
(0, internals_1.fireProgressHook)(this.ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_02, errMessage);
|
|
189
|
-
throw err;
|
|
190
241
|
}
|
|
191
242
|
finally {
|
|
192
|
-
// Restore
|
|
193
|
-
|
|
243
|
+
// Restore the caller's route so a recursive inner R1 execute doesn't
|
|
244
|
+
// leak its UOA_TO_PUSH route back to the outer R2/R3 frame.
|
|
245
|
+
this.currentRoute = previousRoute;
|
|
194
246
|
}
|
|
195
247
|
});
|
|
196
248
|
}
|
|
@@ -219,9 +271,9 @@ class Orchestrator {
|
|
|
219
271
|
/**
|
|
220
272
|
* Queries gas fee for an outbound transaction from the UniversalCore contract.
|
|
221
273
|
*/
|
|
222
|
-
queryOutboundGasFee(prc20Token, gasLimit) {
|
|
274
|
+
queryOutboundGasFee(prc20Token, gasLimit, destinationChain) {
|
|
223
275
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
224
|
-
return (0, internals_1.queryOutboundGasFee)(this.ctx, prc20Token, gasLimit);
|
|
276
|
+
return (0, internals_1.queryOutboundGasFee)(this.ctx, prc20Token, gasLimit, destinationChain);
|
|
225
277
|
});
|
|
226
278
|
}
|
|
227
279
|
/**
|