@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
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* transformToUniversalTxResponse, and the ResponseBuilderCallbacks interface.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.findPC20GatewayLogIndex = findPC20GatewayLogIndex;
|
|
9
10
|
exports.queryUniversalTxStatusFromGatewayTx = queryUniversalTxStatusFromGatewayTx;
|
|
10
11
|
exports.resolveUniversalTxFromSourceHash = resolveUniversalTxFromSourceHash;
|
|
11
12
|
exports.trackTransaction = trackTransaction;
|
|
@@ -14,6 +15,8 @@ const tslib_1 = require("tslib");
|
|
|
14
15
|
const bs58_1 = require("../../internal/bs58");
|
|
15
16
|
const web3_js_1 = require("@solana/web3.js");
|
|
16
17
|
const viem_1 = require("viem");
|
|
18
|
+
const events_1 = require("../../universal-tx-detector/events");
|
|
19
|
+
const export_1 = require("./pc20/export");
|
|
17
20
|
const uea_evm_1 = require("../../constants/abi/uea.evm");
|
|
18
21
|
const chain_1 = require("../../constants/chain");
|
|
19
22
|
const enums_1 = require("../../constants/enums");
|
|
@@ -47,119 +50,166 @@ function fanOut(event, primary, secondary) {
|
|
|
47
50
|
// ============================================================================
|
|
48
51
|
// queryUniversalTxStatusFromGatewayTx
|
|
49
52
|
// ============================================================================
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Pick the gateway log whose event is the PC20 burn — the leg that carries the
|
|
55
|
+
* user's transfer.
|
|
56
|
+
*
|
|
57
|
+
* A PC20 return with a prepaid gas deposit makes the gateway emit TWO
|
|
58
|
+
* `UniversalTx` events from one user tx: the PC20 burn (payload prefixed with
|
|
59
|
+
* the `PC20` selector) and, second, a plain FUNDS event for the attached
|
|
60
|
+
* native value. Each becomes its own UTX on Push. The default "last gateway
|
|
61
|
+
* log" heuristic therefore selects the *fee-credit* leg, so a failure there
|
|
62
|
+
* (see the known fee-credit bug) is reported as the whole transfer failing —
|
|
63
|
+
* even though the tokens arrived via the first leg.
|
|
64
|
+
*
|
|
65
|
+
* Identification is by payload prefix rather than log order: the selector is
|
|
66
|
+
* what the gateway itself stamps on the PC20 leg, so it stays correct if the
|
|
67
|
+
* emission order ever changes. Returns null when no PC20 leg is present, and
|
|
68
|
+
* the caller keeps its existing behaviour.
|
|
69
|
+
*/
|
|
70
|
+
function findPC20GatewayLogIndex(ctx, gatewayLogs) {
|
|
71
|
+
for (let i = 0; i < gatewayLogs.length; i++) {
|
|
72
|
+
const log = gatewayLogs[i];
|
|
55
73
|
try {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
catch (_c) {
|
|
70
|
-
// Receipt might not be indexed yet on this RPC; wait briefly for it
|
|
71
|
-
receipt = yield evmClient.publicClient.waitForTransactionReceipt({
|
|
72
|
-
hash: txHash,
|
|
73
|
-
confirmations: 0,
|
|
74
|
-
timeout: chain_1.CHAIN_INFO[chain].timeout,
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
const gatewayLogs = (receipt.logs || []).filter((l) => (l.address || '').toLowerCase() === gatewayAddress.toLowerCase());
|
|
78
|
-
(0, context_1.printLog)(ctx, `queryUniversalTxStatus — receipt logs count: ${(_a = receipt.logs) === null || _a === void 0 ? void 0 : _a.length}, gateway logs count: ${gatewayLogs.length}, evmGatewayMethod: ${evmGatewayMethod}`);
|
|
79
|
-
(0, context_1.printLog)(ctx, 'queryUniversalTxStatus — gatewayLogs: ' + JSON.stringify(gatewayLogs.map((l) => { var _a; return ({ address: l.address, logIndex: l.logIndex, topics: (_a = l.topics) === null || _a === void 0 ? void 0 : _a[0] }); }), null, 2));
|
|
80
|
-
// Use the last gateway log to derive the log index
|
|
81
|
-
const logIndexToUse = gatewayLogs.length - 1;
|
|
82
|
-
const firstLog = (gatewayLogs[logIndexToUse] ||
|
|
83
|
-
(receipt.logs || []).at(-1));
|
|
84
|
-
const logIndexVal = (_b = firstLog === null || firstLog === void 0 ? void 0 : firstLog.logIndex) !== null && _b !== void 0 ? _b : 0;
|
|
85
|
-
(0, context_1.printLog)(ctx, `queryUniversalTxStatus — logIndexToUse: ${logIndexToUse}, firstLog.logIndex: ${firstLog === null || firstLog === void 0 ? void 0 : firstLog.logIndex}, logIndexVal: ${logIndexVal}`);
|
|
86
|
-
logIndexStr =
|
|
87
|
-
typeof logIndexVal === 'bigint'
|
|
88
|
-
? logIndexVal.toString()
|
|
89
|
-
: String(logIndexVal);
|
|
74
|
+
const decoded = (0, viem_1.decodeEventLog)({
|
|
75
|
+
abi: [events_1.EVENT_UNIVERSAL_TX],
|
|
76
|
+
data: log.data,
|
|
77
|
+
topics: log.topics,
|
|
78
|
+
});
|
|
79
|
+
const payload = decoded.args?.payload;
|
|
80
|
+
if (typeof payload === 'string' &&
|
|
81
|
+
payload.toLowerCase().startsWith(export_1.PC20_SELECTOR.toLowerCase())) {
|
|
82
|
+
(0, context_1.printLog)(ctx, `queryUniversalTxStatus — PC20 leg found at gateway log ${i} ` +
|
|
83
|
+
`(logIndex ${String(log.logIndex)}); tracking it instead of the last log`);
|
|
84
|
+
return i;
|
|
90
85
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// Not a UniversalTx event (or an ABI we do not model) — skip it.
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
async function queryUniversalTxStatusFromGatewayTx(ctx, evmClient, gatewayAddress,
|
|
94
|
+
// DEBUG: section marker added
|
|
95
|
+
txHash, evmGatewayMethod,
|
|
96
|
+
/**
|
|
97
|
+
* Set for PC20 imports (wrapper burns). Selects the PC20 burn leg rather
|
|
98
|
+
* than the last gateway log — see {@link findPC20GatewayLogIndex}.
|
|
99
|
+
*/
|
|
100
|
+
preferPC20Log = false) {
|
|
101
|
+
try {
|
|
102
|
+
const chain = ctx.universalSigner.account.chain;
|
|
103
|
+
const { vm } = chain_1.CHAIN_INFO[chain];
|
|
104
|
+
let logIndexStr = '0';
|
|
105
|
+
let txHashHex = txHash;
|
|
106
|
+
if (vm === enums_1.VM.EVM) {
|
|
107
|
+
if (!evmClient || !gatewayAddress)
|
|
108
|
+
throw new Error('Missing EVM context');
|
|
109
|
+
let receipt;
|
|
110
|
+
try {
|
|
111
|
+
receipt = await evmClient.publicClient.getTransactionReceipt({
|
|
112
|
+
hash: txHash,
|
|
110
113
|
});
|
|
111
|
-
// Derive proper log index using discriminator matching
|
|
112
|
-
const svmLogIndex = (0, svm_helpers_1.getSvmGatewayLogIndexFromTx)(txResp);
|
|
113
|
-
logIndexStr = String(svmLogIndex);
|
|
114
114
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
logIndexStr,
|
|
123
|
-
idInput,
|
|
124
|
-
idHex,
|
|
125
|
-
}, null, 2));
|
|
126
|
-
// Fetch UniversalTx via gRPC with linear-then-exponential retry
|
|
127
|
-
const LINEAR_ATTEMPTS = 10;
|
|
128
|
-
const LINEAR_DELAY_MS = 3600;
|
|
129
|
-
const EXPONENTIAL_BASE_MS = 4800;
|
|
130
|
-
const MAX_ATTEMPTS = 15;
|
|
131
|
-
let universalTxObj;
|
|
132
|
-
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
133
|
-
(0, context_1.printLog)(ctx, `[Sync] Attempt ${attempt + 1}/${MAX_ATTEMPTS} | Query ID: ${idHex}`);
|
|
134
|
-
try {
|
|
135
|
-
const universalTxResp = yield ctx.pushClient.getUniversalTxById(idHex);
|
|
136
|
-
universalTxObj = universalTxResp === null || universalTxResp === void 0 ? void 0 : universalTxResp.universalTx;
|
|
137
|
-
if (universalTxObj) {
|
|
138
|
-
break;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
catch (error) {
|
|
142
|
-
// ignore and retry
|
|
143
|
-
}
|
|
144
|
-
// Linear delay for first N attempts, then exponential backoff
|
|
145
|
-
let delay;
|
|
146
|
-
if (attempt < LINEAR_ATTEMPTS) {
|
|
147
|
-
delay = LINEAR_DELAY_MS;
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
// Exponential: 2000, 4000, 8000, 16000, ...
|
|
151
|
-
const exponentialAttempt = attempt - LINEAR_ATTEMPTS;
|
|
152
|
-
delay = EXPONENTIAL_BASE_MS * Math.pow(2, exponentialAttempt);
|
|
153
|
-
}
|
|
154
|
-
yield new Promise((r) => setTimeout(r, delay));
|
|
115
|
+
catch {
|
|
116
|
+
// Receipt might not be indexed yet on this RPC; wait briefly for it
|
|
117
|
+
receipt = await evmClient.publicClient.waitForTransactionReceipt({
|
|
118
|
+
hash: txHash,
|
|
119
|
+
confirmations: 0,
|
|
120
|
+
timeout: chain_1.CHAIN_INFO[chain].timeout,
|
|
121
|
+
});
|
|
155
122
|
}
|
|
156
|
-
|
|
123
|
+
const gatewayLogs = (receipt.logs || []).filter((l) => (l.address || '').toLowerCase() === gatewayAddress.toLowerCase());
|
|
124
|
+
(0, context_1.printLog)(ctx, `queryUniversalTxStatus — receipt logs count: ${receipt.logs?.length}, gateway logs count: ${gatewayLogs.length}, evmGatewayMethod: ${evmGatewayMethod}`);
|
|
125
|
+
(0, context_1.printLog)(ctx, 'queryUniversalTxStatus — gatewayLogs: ' + JSON.stringify(gatewayLogs.map((l) => ({ address: l.address, logIndex: l.logIndex, topics: l.topics?.[0] })), null, 2));
|
|
126
|
+
// Use the last gateway log to derive the log index, except for a PC20
|
|
127
|
+
// import, where the last log is the fee-credit leg rather than the
|
|
128
|
+
// user's transfer (see findPC20GatewayLogIndex).
|
|
129
|
+
const pc20LogIndex = preferPC20Log
|
|
130
|
+
? findPC20GatewayLogIndex(ctx, gatewayLogs)
|
|
131
|
+
: null;
|
|
132
|
+
const logIndexToUse = pc20LogIndex ?? gatewayLogs.length - 1;
|
|
133
|
+
const firstLog = (gatewayLogs[logIndexToUse] ||
|
|
134
|
+
(receipt.logs || []).at(-1));
|
|
135
|
+
const logIndexVal = firstLog?.logIndex ?? 0;
|
|
136
|
+
(0, context_1.printLog)(ctx, `queryUniversalTxStatus — logIndexToUse: ${logIndexToUse}, firstLog.logIndex: ${firstLog?.logIndex}, logIndexVal: ${logIndexVal}`);
|
|
137
|
+
logIndexStr =
|
|
138
|
+
typeof logIndexVal === 'bigint'
|
|
139
|
+
? logIndexVal.toString()
|
|
140
|
+
: String(logIndexVal);
|
|
157
141
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
142
|
+
else if (vm === enums_1.VM.SVM) {
|
|
143
|
+
// Normalize Solana signature to 0x-hex for ID composition
|
|
144
|
+
let txSignature = txHash;
|
|
145
|
+
if (!txHash.startsWith('0x')) {
|
|
146
|
+
const decoded = bs58_1.bs58.decode(txHash);
|
|
147
|
+
txHashHex = (0, viem_1.bytesToHex)(new Uint8Array(decoded));
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
// When provided as hex, convert to base58 for RPC
|
|
151
|
+
const hex = txHash.slice(2);
|
|
152
|
+
const bytes = Uint8Array.from(Buffer.from(hex, 'hex'));
|
|
153
|
+
txSignature = bs58_1.bs58.encode(Buffer.from(bytes));
|
|
154
|
+
}
|
|
155
|
+
// Fetch transaction by initializing a Connection and calling Solana RPC
|
|
156
|
+
const rpcUrls = ctx.rpcUrls[chain] || chain_1.CHAIN_INFO[chain].defaultRPC;
|
|
157
|
+
const connection = new web3_js_1.Connection(rpcUrls[0], 'confirmed');
|
|
158
|
+
const txResp = await connection.getTransaction(txSignature, {
|
|
159
|
+
maxSupportedTransactionVersion: 0,
|
|
160
|
+
commitment: 'confirmed',
|
|
161
|
+
});
|
|
162
|
+
// Derive proper log index using discriminator matching
|
|
163
|
+
const svmLogIndex = (0, svm_helpers_1.getSvmGatewayLogIndexFromTx)(txResp, preferPC20Log);
|
|
164
|
+
logIndexStr = String(svmLogIndex);
|
|
161
165
|
}
|
|
162
|
-
|
|
166
|
+
const sourceChain = `${chain_1.VM_NAMESPACE[vm]}:${chain_1.CHAIN_INFO[chain].chainId}`;
|
|
167
|
+
// ID = sha256("${sourceChain}:${txHash}:${logIndex}") as hex string (no 0x)
|
|
168
|
+
const idInput = `${sourceChain}:${txHashHex}:${logIndexStr}`;
|
|
169
|
+
const idHex = (0, viem_1.sha256)((0, viem_1.stringToBytes)(idInput)).slice(2);
|
|
170
|
+
(0, context_1.printLog)(ctx, 'Query ID extraction: ' + JSON.stringify({
|
|
171
|
+
sourceChain,
|
|
172
|
+
txHashHex,
|
|
173
|
+
logIndexStr,
|
|
174
|
+
idInput,
|
|
175
|
+
idHex,
|
|
176
|
+
}, null, 2));
|
|
177
|
+
// Fetch UniversalTx via gRPC with linear-then-exponential retry
|
|
178
|
+
const LINEAR_ATTEMPTS = 10;
|
|
179
|
+
const LINEAR_DELAY_MS = 3600;
|
|
180
|
+
const EXPONENTIAL_BASE_MS = 4800;
|
|
181
|
+
const MAX_ATTEMPTS = 15;
|
|
182
|
+
let universalTxObj;
|
|
183
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
184
|
+
(0, context_1.printLog)(ctx, `[Sync] Attempt ${attempt + 1}/${MAX_ATTEMPTS} | Query ID: ${idHex}`);
|
|
185
|
+
try {
|
|
186
|
+
const universalTxResp = await ctx.pushClient.getUniversalTxById(idHex);
|
|
187
|
+
universalTxObj = universalTxResp?.universalTx;
|
|
188
|
+
if (universalTxObj) {
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
// ignore and retry
|
|
194
|
+
}
|
|
195
|
+
// Linear delay for first N attempts, then exponential backoff
|
|
196
|
+
let delay;
|
|
197
|
+
if (attempt < LINEAR_ATTEMPTS) {
|
|
198
|
+
delay = LINEAR_DELAY_MS;
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
// Exponential: 2000, 4000, 8000, 16000, ...
|
|
202
|
+
const exponentialAttempt = attempt - LINEAR_ATTEMPTS;
|
|
203
|
+
delay = EXPONENTIAL_BASE_MS * Math.pow(2, exponentialAttempt);
|
|
204
|
+
}
|
|
205
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
206
|
+
}
|
|
207
|
+
return universalTxObj;
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
(0, context_1.printLog)(ctx, `queryUniversalTxStatusFromGatewayTx failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
163
213
|
}
|
|
164
214
|
// ============================================================================
|
|
165
215
|
// trackTransaction
|
|
@@ -182,342 +232,320 @@ const PUSH_CHAINS = new Set([
|
|
|
182
232
|
* the universal record and its first Push pcTx so the caller can reconstruct
|
|
183
233
|
* from the Push side.
|
|
184
234
|
*/
|
|
185
|
-
function resolveUniversalTxFromSourceHash(ctx, sourceHash, sourceChain, rpcUrls) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
// cross-ref can come back empty for SVM even when the record exists.
|
|
193
|
-
skipPushChainLookup: true,
|
|
194
|
-
});
|
|
195
|
-
const utxId = detection.decoded.universalTxId;
|
|
196
|
-
if (!utxId) {
|
|
197
|
-
throw new Error(`trackTransaction: could not resolve a universal transaction from hash ` +
|
|
198
|
-
`"${sourceHash}" on ${sourceChain} (detected kind: ${detection.kind}). ` +
|
|
199
|
-
`Pass the Push Chain root hash, or a source hash that emitted a ` +
|
|
200
|
-
`UniversalTx event.`);
|
|
201
|
-
}
|
|
202
|
-
const utxResponse = yield ctx.pushClient.getUniversalTxByIdV2(utxId);
|
|
203
|
-
const universalTxData = utxResponse === null || utxResponse === void 0 ? void 0 : utxResponse.universalTx;
|
|
204
|
-
if (!universalTxData) {
|
|
205
|
-
throw new Error(`trackTransaction: resolved universalTxId ${utxId} from ${sourceChain} ` +
|
|
206
|
-
`hash "${sourceHash}", but no universal transaction record exists on ` +
|
|
207
|
-
`Push Chain yet (it may still be relaying).`);
|
|
208
|
-
}
|
|
209
|
-
const pushTxHash = (_b = (_a = universalTxData.pcTx) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.txHash;
|
|
210
|
-
if (!pushTxHash) {
|
|
211
|
-
throw new Error(`trackTransaction: universal tx ${utxId} (from ${sourceChain} hash ` +
|
|
212
|
-
`"${sourceHash}") has no Push Chain tx recorded yet.`);
|
|
213
|
-
}
|
|
214
|
-
return { universalTxData, pushTxHash, sourceSender: detection.decoded.sender };
|
|
235
|
+
async function resolveUniversalTxFromSourceHash(ctx, sourceHash, sourceChain, rpcUrls) {
|
|
236
|
+
const detection = await (0, detector_1.detectUniversalTx)(sourceHash, sourceChain, {
|
|
237
|
+
pushClient: ctx.pushClient,
|
|
238
|
+
rpcUrls: { ...ctx.rpcUrls, ...rpcUrls },
|
|
239
|
+
// We do our own getUniversalTxByIdV2 below; the detector's cosmos
|
|
240
|
+
// cross-ref can come back empty for SVM even when the record exists.
|
|
241
|
+
skipPushChainLookup: true,
|
|
215
242
|
});
|
|
243
|
+
const utxId = detection.decoded.universalTxId;
|
|
244
|
+
if (!utxId) {
|
|
245
|
+
throw new Error(`trackTransaction: could not resolve a universal transaction from hash ` +
|
|
246
|
+
`"${sourceHash}" on ${sourceChain} (detected kind: ${detection.kind}). ` +
|
|
247
|
+
`Pass the Push Chain root hash, or a source hash that emitted a ` +
|
|
248
|
+
`UniversalTx event.`);
|
|
249
|
+
}
|
|
250
|
+
const utxResponse = await ctx.pushClient.getUniversalTxByIdV2(utxId);
|
|
251
|
+
const universalTxData = utxResponse?.universalTx;
|
|
252
|
+
if (!universalTxData) {
|
|
253
|
+
throw new Error(`trackTransaction: resolved universalTxId ${utxId} from ${sourceChain} ` +
|
|
254
|
+
`hash "${sourceHash}", but no universal transaction record exists on ` +
|
|
255
|
+
`Push Chain yet (it may still be relaying).`);
|
|
256
|
+
}
|
|
257
|
+
const pushTxHash = universalTxData.pcTx?.[0]?.txHash;
|
|
258
|
+
if (!pushTxHash) {
|
|
259
|
+
throw new Error(`trackTransaction: universal tx ${utxId} (from ${sourceChain} hash ` +
|
|
260
|
+
`"${sourceHash}") has no Push Chain tx recorded yet.`);
|
|
261
|
+
}
|
|
262
|
+
return { universalTxData, pushTxHash, sourceSender: detection.decoded.sender };
|
|
216
263
|
}
|
|
217
|
-
function trackTransaction(ctx, txHash, options, callbacks) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
264
|
+
async function trackTransaction(ctx, txHash, options, callbacks) {
|
|
265
|
+
if (!callbacks) {
|
|
266
|
+
throw new Error('trackTransaction requires ResponseBuilderCallbacks');
|
|
267
|
+
}
|
|
268
|
+
const { chain = (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork), progressHook, waitForCompletion = true, advanced = {}, } = options ?? {};
|
|
269
|
+
// Fail fast on an unsupported `chain`. It defaults to Push Chain when the
|
|
270
|
+
// caller omits it; an explicitly-passed value that isn't a known CHAIN_INFO
|
|
271
|
+
// entry (a raw numeric chainId, a typo, or a chain from a plain-JS caller
|
|
272
|
+
// that skips the CHAIN type) would otherwise throw an opaque "Cannot read
|
|
273
|
+
// properties of undefined (reading 'defaultRPC')" at the RPC lookup below.
|
|
274
|
+
if (!chain_1.CHAIN_INFO[chain]) {
|
|
275
|
+
throw new Error(`trackTransaction: unsupported chain "${String(chain)}". Pass a ` +
|
|
276
|
+
`PushChain.CONSTANTS.CHAIN value. Supported: ${Object.keys(chain_1.CHAIN_INFO).join(', ')}`);
|
|
277
|
+
}
|
|
278
|
+
const { timeout = 300000, pollingIntervalMs = 1000, rpcUrls = {} } = advanced;
|
|
279
|
+
// Source-hash mode: a non-Push `chain` means `txHash` is an origin/source-leg
|
|
280
|
+
// hash (a Sepolia tx hash, a Solana signature, …), not a Push Chain hash.
|
|
281
|
+
// Resolve it to the universal record + its Push pcTx via the detector, then
|
|
282
|
+
// reconstruct from the Push side. Push-native tracking (below) is unchanged.
|
|
283
|
+
let preResolvedUtxData;
|
|
284
|
+
let sourceOriginChain;
|
|
285
|
+
let sourceSender;
|
|
286
|
+
let trackChain = chain;
|
|
287
|
+
let trackHash = txHash;
|
|
288
|
+
if (!PUSH_CHAINS.has(chain)) {
|
|
289
|
+
const resolved = await resolveUniversalTxFromSourceHash(ctx, txHash, chain, rpcUrls);
|
|
290
|
+
preResolvedUtxData = resolved.universalTxData;
|
|
291
|
+
sourceOriginChain = chain;
|
|
292
|
+
sourceSender = resolved.sourceSender;
|
|
293
|
+
trackHash = resolved.pushTxHash;
|
|
294
|
+
trackChain = (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork);
|
|
295
|
+
}
|
|
296
|
+
// Event buffer for replay via response.progressHook()
|
|
297
|
+
const eventBuffer = [];
|
|
298
|
+
// Helper to emit progress events. Per-tx hook (passed to trackTransaction)
|
|
299
|
+
// fires first, then the orchestrator-level hook — deduped via `fanOut` so
|
|
300
|
+
// a caller that wires the same callback at both levels isn't double-fired.
|
|
301
|
+
const emitProgress = (event) => {
|
|
302
|
+
eventBuffer.push(event);
|
|
303
|
+
(0, context_1.printLog)(ctx, event.message);
|
|
304
|
+
fanOut(event, progressHook, ctx.progressHook);
|
|
305
|
+
};
|
|
306
|
+
// Create client for target chain with optional RPC override. In source-hash
|
|
307
|
+
// mode `trackChain` is Push (the resolved pcTx lives on Push Chain).
|
|
308
|
+
const chainRPCs = rpcUrls[trackChain] ||
|
|
309
|
+
ctx.rpcUrls[trackChain] ||
|
|
310
|
+
chain_1.CHAIN_INFO[trackChain].defaultRPC;
|
|
311
|
+
const client = new push_client_1.PushClient({
|
|
312
|
+
rpcUrls: chainRPCs,
|
|
313
|
+
network: ctx.pushNetwork,
|
|
314
|
+
});
|
|
315
|
+
// Poll for transaction
|
|
316
|
+
const start = Date.now();
|
|
317
|
+
let tx;
|
|
318
|
+
// eslint-disable-next-line no-constant-condition
|
|
319
|
+
while (true) {
|
|
320
|
+
try {
|
|
321
|
+
tx = await client.getTransaction(trackHash);
|
|
322
|
+
break; // Found transaction
|
|
250
323
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
// fires first, then the orchestrator-level hook — deduped via `fanOut` so
|
|
255
|
-
// a caller that wires the same callback at both levels isn't double-fired.
|
|
256
|
-
const emitProgress = (event) => {
|
|
257
|
-
eventBuffer.push(event);
|
|
258
|
-
(0, context_1.printLog)(ctx, event.message);
|
|
259
|
-
fanOut(event, progressHook, ctx.progressHook);
|
|
260
|
-
};
|
|
261
|
-
// Create client for target chain with optional RPC override. In source-hash
|
|
262
|
-
// mode `trackChain` is Push (the resolved pcTx lives on Push Chain).
|
|
263
|
-
const chainRPCs = rpcUrls[trackChain] ||
|
|
264
|
-
ctx.rpcUrls[trackChain] ||
|
|
265
|
-
chain_1.CHAIN_INFO[trackChain].defaultRPC;
|
|
266
|
-
const client = new push_client_1.PushClient({
|
|
267
|
-
rpcUrls: chainRPCs,
|
|
268
|
-
network: ctx.pushNetwork,
|
|
269
|
-
});
|
|
270
|
-
// Poll for transaction
|
|
271
|
-
const start = Date.now();
|
|
272
|
-
let tx;
|
|
273
|
-
// eslint-disable-next-line no-constant-condition
|
|
274
|
-
while (true) {
|
|
275
|
-
try {
|
|
276
|
-
tx = yield client.getTransaction(trackHash);
|
|
277
|
-
break; // Found transaction
|
|
324
|
+
catch (err) {
|
|
325
|
+
if (!waitForCompletion) {
|
|
326
|
+
throw new Error(`Transaction ${trackHash} not found`);
|
|
278
327
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
// Check timeout
|
|
284
|
-
if (Date.now() - start > timeout) {
|
|
285
|
-
throw new Error(`Timeout: transaction ${trackHash} not confirmed within ${timeout}ms`);
|
|
286
|
-
}
|
|
287
|
-
// Brief delay before retry
|
|
288
|
-
yield new Promise((r) => setTimeout(r, pollingIntervalMs));
|
|
328
|
+
// Check timeout
|
|
329
|
+
if (Date.now() - start > timeout) {
|
|
330
|
+
throw new Error(`Timeout: transaction ${trackHash} not confirmed within ${timeout}ms`);
|
|
289
331
|
}
|
|
332
|
+
// Brief delay before retry
|
|
333
|
+
await new Promise((r) => setTimeout(r, pollingIntervalMs));
|
|
290
334
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
}
|
|
302
|
-
catch (_c) {
|
|
303
|
-
// Ignore - try computed ID next
|
|
335
|
+
}
|
|
336
|
+
// Try to get UniversalTx data for richer progress reconstruction.
|
|
337
|
+
// In source-hash mode we already resolved the record above; otherwise run the
|
|
338
|
+
// three-tier lookup: direct hash → computed keccak ID → Cosmos extraction.
|
|
339
|
+
let universalTxData = preResolvedUtxData;
|
|
340
|
+
if (!universalTxData) {
|
|
341
|
+
try {
|
|
342
|
+
const utxResponse = await ctx.pushClient.getUniversalTxByIdV2(trackHash);
|
|
343
|
+
if (utxResponse?.universalTx) {
|
|
344
|
+
universalTxData = utxResponse.universalTx;
|
|
304
345
|
}
|
|
305
346
|
}
|
|
306
|
-
|
|
307
|
-
try
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
347
|
+
catch {
|
|
348
|
+
// Ignore - try computed ID next
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (!universalTxData) {
|
|
352
|
+
try {
|
|
353
|
+
const computedId = (0, outbound_tracker_1.computeUniversalTxId)(ctx.pushNetwork, trackHash);
|
|
354
|
+
const queryId = computedId.startsWith('0x') ? computedId.slice(2) : computedId;
|
|
355
|
+
const utxResponse = await ctx.pushClient.getUniversalTxByIdV2(queryId);
|
|
356
|
+
if (utxResponse?.universalTx) {
|
|
357
|
+
universalTxData = utxResponse.universalTx;
|
|
317
358
|
}
|
|
318
359
|
}
|
|
319
|
-
|
|
320
|
-
try
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
360
|
+
catch {
|
|
361
|
+
// Ignore - try Cosmos event extraction next
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (!universalTxData) {
|
|
365
|
+
try {
|
|
366
|
+
const extractedId = await (0, outbound_tracker_1.extractUniversalSubTxIdFromTx)(ctx, trackHash);
|
|
367
|
+
if (extractedId) {
|
|
368
|
+
const queryId = extractedId.startsWith('0x') ? extractedId.slice(2) : extractedId;
|
|
369
|
+
const utxResponse = await ctx.pushClient.getUniversalTxByIdV2(queryId);
|
|
370
|
+
if (utxResponse?.universalTx) {
|
|
371
|
+
universalTxData = utxResponse.universalTx;
|
|
328
372
|
}
|
|
329
373
|
}
|
|
330
|
-
catch (_e) {
|
|
331
|
-
// Ignore - no universal tx data available
|
|
332
|
-
}
|
|
333
374
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
// Detect route from UniversalTxV2 data and set on response
|
|
337
|
-
// This enables wait() to trigger outbound polling via waitForOutboundTx()
|
|
338
|
-
const detectedRoute = (0, tx_transformer_1.detectRouteFromUniversalTxData)(universalTxData);
|
|
339
|
-
if (detectedRoute) {
|
|
340
|
-
universalTxResponse.route = detectedRoute;
|
|
341
|
-
// Mirror the route on the context so emission code in wait()/cascade
|
|
342
|
-
// picks the correct ID range — keeps trackTransaction in lockstep with
|
|
343
|
-
// sendUniversalTransaction, which sets currentRoute in execute().
|
|
344
|
-
ctx.currentRoute = detectedRoute;
|
|
345
|
-
// Populate the destination/source chain on the response so
|
|
346
|
-
// reconstructR2/R3 (and any downstream emission that reads
|
|
347
|
-
// universalTxResponse.chain) emit the proper friendly chain name
|
|
348
|
-
// instead of the "external" fallback. The first outbound's destination
|
|
349
|
-
// is the target chain for R2 and the source CEA chain for R3.
|
|
350
|
-
const firstOutboundChain = (_b = (_a = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.outboundTx) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.destinationChain;
|
|
351
|
-
if (firstOutboundChain && !universalTxResponse.chain) {
|
|
352
|
-
universalTxResponse.chain = firstOutboundChain;
|
|
353
|
-
universalTxResponse.chainNamespace = firstOutboundChain;
|
|
354
|
-
}
|
|
355
|
-
// For R3 replays, enable inbound round-trip tracking so `.wait()` runs
|
|
356
|
-
// the 310-01 → 399-01 sequence. Live execute sets this in
|
|
357
|
-
// route-handlers.ts via `amount > 0n`; trackTransaction has no
|
|
358
|
-
// execute-phase args, so we enable it unconditionally for CEA_TO_PUSH.
|
|
359
|
-
// The inbound block tolerates no-inbound (payload-only R3) by timing
|
|
360
|
-
// out — same as live behaviour when the source tx has no round-trip.
|
|
361
|
-
if (detectedRoute === route_detector_1.TransactionRoute.CEA_TO_PUSH) {
|
|
362
|
-
universalTxResponse._expectsInboundRoundTrip = true;
|
|
363
|
-
}
|
|
375
|
+
catch {
|
|
376
|
+
// Ignore - no universal tx data available
|
|
364
377
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
378
|
+
}
|
|
379
|
+
// Transform to UniversalTxResponse
|
|
380
|
+
const universalTxResponse = await transformToUniversalTxResponse(ctx, tx, eventBuffer, callbacks);
|
|
381
|
+
// Detect route from UniversalTxV2 data and set on response
|
|
382
|
+
// This enables wait() to trigger outbound polling via waitForOutboundTx()
|
|
383
|
+
const detectedRoute = (0, tx_transformer_1.detectRouteFromUniversalTxData)(universalTxData);
|
|
384
|
+
if (detectedRoute) {
|
|
385
|
+
universalTxResponse.route = detectedRoute;
|
|
386
|
+
// Mirror the route on the context so emission code in wait()/cascade
|
|
387
|
+
// picks the correct ID range — keeps trackTransaction in lockstep with
|
|
388
|
+
// sendUniversalTransaction, which sets currentRoute in execute().
|
|
389
|
+
ctx.currentRoute = detectedRoute;
|
|
390
|
+
// Populate the destination/source chain on the response so
|
|
391
|
+
// reconstructR2/R3 (and any downstream emission that reads
|
|
392
|
+
// universalTxResponse.chain) emit the proper friendly chain name
|
|
393
|
+
// instead of the "external" fallback. The first outbound's destination
|
|
394
|
+
// is the target chain for R2 and the source CEA chain for R3.
|
|
395
|
+
const firstOutboundChain = universalTxData?.outboundTx?.[0]?.destinationChain;
|
|
396
|
+
if (firstOutboundChain && !universalTxResponse.chain) {
|
|
397
|
+
universalTxResponse.chain = firstOutboundChain;
|
|
398
|
+
universalTxResponse.chainNamespace = firstOutboundChain;
|
|
372
399
|
}
|
|
373
|
-
//
|
|
374
|
-
//
|
|
375
|
-
//
|
|
376
|
-
//
|
|
377
|
-
//
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
originAddr =
|
|
382
|
-
chain_1.CHAIN_INFO[sourceOriginChain].vm === enums_1.VM.SVM
|
|
383
|
-
? bs58_1.bs58.encode((0, viem_1.toBytes)(sourceSender))
|
|
384
|
-
: (0, viem_1.getAddress)(sourceSender);
|
|
385
|
-
}
|
|
386
|
-
catch (_f) {
|
|
387
|
-
// Keep the raw sender if re-encoding fails.
|
|
388
|
-
}
|
|
389
|
-
universalTxResponse.origin = `${sourceOriginChain}:${originAddr}`;
|
|
390
|
-
universalTxResponse.chainId = chain_1.CHAIN_INFO[sourceOriginChain].chainId;
|
|
400
|
+
// For R3 replays, enable inbound round-trip tracking so `.wait()` runs
|
|
401
|
+
// the 310-01 → 399-01 sequence. Live execute sets this in
|
|
402
|
+
// route-handlers.ts via `amount > 0n`; trackTransaction has no
|
|
403
|
+
// execute-phase args, so we enable it unconditionally for CEA_TO_PUSH.
|
|
404
|
+
// The inbound block tolerates no-inbound (payload-only R3) by timing
|
|
405
|
+
// out — same as live behaviour when the source tx has no round-trip.
|
|
406
|
+
if (detectedRoute === route_detector_1.TransactionRoute.CEA_TO_PUSH) {
|
|
407
|
+
universalTxResponse._expectsInboundRoundTrip = true;
|
|
391
408
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
409
|
+
}
|
|
410
|
+
// Source-hash mode: the pcTx we fetched lives on Push Chain, so the
|
|
411
|
+
// transform resolves chain to the Push side. Surface the true source chain
|
|
412
|
+
// the caller tracked so `chain`/`chainNamespace` reflect where the universal
|
|
413
|
+
// tx actually originated. (An outbound-derived chain above, if any, wins.)
|
|
414
|
+
if (sourceOriginChain && !universalTxResponse.chain) {
|
|
415
|
+
universalTxResponse.chain = sourceOriginChain;
|
|
416
|
+
universalTxResponse.chainNamespace = sourceOriginChain;
|
|
417
|
+
}
|
|
418
|
+
// Override `origin` with the true source account. The transform derives
|
|
419
|
+
// origin from the Push pcTx (whose `from` is the keeper that submitted the
|
|
420
|
+
// inbound), so in source-hash mode it would otherwise read as a Push
|
|
421
|
+
// address. Rebuild it as `<sourceChainCaip>:<sourceSender>` using the
|
|
422
|
+
// chain's native address encoding (0x for EVM, base58 for SVM).
|
|
423
|
+
if (sourceOriginChain && sourceSender) {
|
|
424
|
+
let originAddr = sourceSender;
|
|
425
|
+
try {
|
|
426
|
+
originAddr =
|
|
427
|
+
chain_1.CHAIN_INFO[sourceOriginChain].vm === enums_1.VM.SVM
|
|
428
|
+
? bs58_1.bs58.encode((0, viem_1.toBytes)(sourceSender))
|
|
429
|
+
: (0, viem_1.getAddress)(sourceSender);
|
|
396
430
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
// events to the user's progressHook.
|
|
400
|
-
universalTxResponse._eventsReconstructed = true;
|
|
401
|
-
// Auto-register the caller's per-call progressHook as the response's
|
|
402
|
-
// registeredProgressHook so that tracked.wait() fires wait-phase events
|
|
403
|
-
// (209-xx / 299-xx / 399-xx) to the same callback without requiring
|
|
404
|
-
// tracked.progressHook(cb) to be called again. Skip replay of buffered
|
|
405
|
-
// events because we just fired them above via emitProgress — calling
|
|
406
|
-
// response.progressHook(cb) here would re-emit the reconstructed stream.
|
|
407
|
-
if (progressHook && universalTxResponse._setProgressHookNoReplay) {
|
|
408
|
-
universalTxResponse._setProgressHookNoReplay(progressHook);
|
|
431
|
+
catch {
|
|
432
|
+
// Keep the raw sender if re-encoding fails.
|
|
409
433
|
}
|
|
410
|
-
|
|
411
|
-
|
|
434
|
+
universalTxResponse.origin = `${sourceOriginChain}:${originAddr}`;
|
|
435
|
+
universalTxResponse.chainId = chain_1.CHAIN_INFO[sourceOriginChain].chainId;
|
|
436
|
+
}
|
|
437
|
+
// Reconstruct and emit SEND-TX-* progress events
|
|
438
|
+
const reconstructedEvents = (0, tx_transformer_1.reconstructProgressEvents)(universalTxResponse, universalTxData);
|
|
439
|
+
for (const event of reconstructedEvents) {
|
|
440
|
+
emitProgress(event);
|
|
441
|
+
}
|
|
442
|
+
// Mark the response so the wait() closure (when later invoked) doesn't
|
|
443
|
+
// call trackTransaction a second time and re-emit the same reconstructed
|
|
444
|
+
// events to the user's progressHook.
|
|
445
|
+
universalTxResponse._eventsReconstructed = true;
|
|
446
|
+
// Auto-register the caller's per-call progressHook as the response's
|
|
447
|
+
// registeredProgressHook so that tracked.wait() fires wait-phase events
|
|
448
|
+
// (209-xx / 299-xx / 399-xx) to the same callback without requiring
|
|
449
|
+
// tracked.progressHook(cb) to be called again. Skip replay of buffered
|
|
450
|
+
// events because we just fired them above via emitProgress — calling
|
|
451
|
+
// response.progressHook(cb) here would re-emit the reconstructed stream.
|
|
452
|
+
if (progressHook && universalTxResponse._setProgressHookNoReplay) {
|
|
453
|
+
universalTxResponse._setProgressHookNoReplay(progressHook);
|
|
454
|
+
}
|
|
455
|
+
return universalTxResponse;
|
|
412
456
|
}
|
|
413
457
|
// ============================================================================
|
|
414
458
|
// transformToUniversalTxResponse
|
|
415
459
|
// ============================================================================
|
|
416
|
-
function transformToUniversalTxResponse(
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
if (ueaOrigin.
|
|
428
|
-
|
|
429
|
-
|
|
460
|
+
async function transformToUniversalTxResponse(ctx, tx, eventBuffer = [], callbacks) {
|
|
461
|
+
const chain = ctx.universalSigner.account.chain;
|
|
462
|
+
let { vm, chainId } = chain_1.CHAIN_INFO[chain];
|
|
463
|
+
let from;
|
|
464
|
+
let to;
|
|
465
|
+
let value;
|
|
466
|
+
let data;
|
|
467
|
+
let rawTransactionData;
|
|
468
|
+
const ueaOrigin = await (0, account_1.convertExecutorToOrigin)(tx.to, { _internal: true });
|
|
469
|
+
let originAddress;
|
|
470
|
+
if (ueaOrigin.exists) {
|
|
471
|
+
if (!ueaOrigin.account) {
|
|
472
|
+
throw new Error('UEA origin account is null');
|
|
473
|
+
}
|
|
474
|
+
originAddress = ueaOrigin.account.address;
|
|
475
|
+
// Use the resolved origin chain for vm/chainId so that the `origin`
|
|
476
|
+
// field reflects the transaction's actual origin, not the tracker's.
|
|
477
|
+
const resolvedChainInfo = chain_1.CHAIN_INFO[ueaOrigin.account.chain];
|
|
478
|
+
if (resolvedChainInfo) {
|
|
479
|
+
vm = resolvedChainInfo.vm;
|
|
480
|
+
chainId = resolvedChainInfo.chainId;
|
|
481
|
+
}
|
|
482
|
+
from = (0, viem_1.getAddress)(tx.to);
|
|
483
|
+
let decoded;
|
|
484
|
+
let decodedPayload = null;
|
|
485
|
+
if (tx.input !== '0x') {
|
|
486
|
+
// Try to decode the input as a known UEA_EVM call. Older txs — or
|
|
487
|
+
// txs sent to a UEA that was upgraded to expose a function not yet
|
|
488
|
+
// reflected in the bundled `uea.evm.ts` ABI — carry a selector that
|
|
489
|
+
// viem can't match. In that case the reconstructor should still
|
|
490
|
+
// produce a usable response (and emit progress hooks) using the raw
|
|
491
|
+
// tx fields, rather than throwing before any hook fires.
|
|
492
|
+
try {
|
|
493
|
+
decoded = (0, viem_1.decodeFunctionData)({ abi: uea_evm_1.UEA_EVM, data: tx.input });
|
|
494
|
+
if (decoded?.args) {
|
|
495
|
+
decodedPayload = decoded.args[0];
|
|
496
|
+
}
|
|
430
497
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
// field reflects the transaction's actual origin, not the tracker's.
|
|
434
|
-
const resolvedChainInfo = chain_1.CHAIN_INFO[ueaOrigin.account.chain];
|
|
435
|
-
if (resolvedChainInfo) {
|
|
436
|
-
vm = resolvedChainInfo.vm;
|
|
437
|
-
chainId = resolvedChainInfo.chainId;
|
|
498
|
+
catch {
|
|
499
|
+
decodedPayload = null;
|
|
438
500
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
// Try to decode the input as a known UEA_EVM call. Older txs — or
|
|
444
|
-
// txs sent to a UEA that was upgraded to expose a function not yet
|
|
445
|
-
// reflected in the bundled `uea.evm.ts` ABI — carry a selector that
|
|
446
|
-
// viem can't match. In that case the reconstructor should still
|
|
447
|
-
// produce a usable response (and emit progress hooks) using the raw
|
|
448
|
-
// tx fields, rather than throwing before any hook fires.
|
|
449
|
-
try {
|
|
450
|
-
decoded = (0, viem_1.decodeFunctionData)({ abi: uea_evm_1.UEA_EVM, data: tx.input });
|
|
451
|
-
if (decoded === null || decoded === void 0 ? void 0 : decoded.args) {
|
|
452
|
-
decodedPayload = decoded.args[0];
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
catch (_a) {
|
|
456
|
-
decodedPayload = null;
|
|
457
|
-
}
|
|
458
|
-
if (decodedPayload) {
|
|
459
|
-
to = decodedPayload.to;
|
|
460
|
-
value = BigInt(decodedPayload.value);
|
|
461
|
-
data = decodedPayload.data;
|
|
462
|
-
}
|
|
463
|
-
else {
|
|
464
|
-
// Unknown / unsupported UEA function — fall back to raw fields so
|
|
465
|
-
// transformToUniversalTxResponse can still return a valid response
|
|
466
|
-
// and downstream progress-hook reconstruction can proceed.
|
|
467
|
-
to = (0, viem_1.getAddress)(tx.to);
|
|
468
|
-
value = tx.value;
|
|
469
|
-
data = tx.input;
|
|
470
|
-
}
|
|
471
|
-
// Extract 'to' from single-element multicall
|
|
472
|
-
if (data && data.length >= 10) {
|
|
473
|
-
const multicallSelector = (0, viem_1.keccak256)((0, viem_1.toBytes)('UEA_MULTICALL')).slice(0, 10);
|
|
474
|
-
if (data.slice(0, 10) === multicallSelector) {
|
|
475
|
-
try {
|
|
476
|
-
const innerData = ('0x' + data.slice(10));
|
|
477
|
-
const [decodedCalls] = (0, viem_1.decodeAbiParameters)([
|
|
478
|
-
{
|
|
479
|
-
type: 'tuple[]',
|
|
480
|
-
components: [
|
|
481
|
-
{ name: 'to', type: 'address' },
|
|
482
|
-
{ name: 'value', type: 'uint256' },
|
|
483
|
-
{ name: 'data', type: 'bytes' },
|
|
484
|
-
],
|
|
485
|
-
},
|
|
486
|
-
], innerData);
|
|
487
|
-
// If single call, use its 'to' address
|
|
488
|
-
if (decodedCalls.length === 1) {
|
|
489
|
-
to = (0, viem_1.getAddress)(decodedCalls[0].to);
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
catch (_b) {
|
|
493
|
-
// Keep original 'to' if decoding fails
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
rawTransactionData = {
|
|
498
|
-
from: (0, viem_1.getAddress)(tx.from),
|
|
499
|
-
to: (0, viem_1.getAddress)(tx.to),
|
|
500
|
-
nonce: tx.nonce,
|
|
501
|
-
data: tx.input,
|
|
502
|
-
value: tx.value,
|
|
503
|
-
};
|
|
501
|
+
if (decodedPayload) {
|
|
502
|
+
to = decodedPayload.to;
|
|
503
|
+
value = BigInt(decodedPayload.value);
|
|
504
|
+
data = decodedPayload.data;
|
|
504
505
|
}
|
|
505
506
|
else {
|
|
507
|
+
// Unknown / unsupported UEA function — fall back to raw fields so
|
|
508
|
+
// transformToUniversalTxResponse can still return a valid response
|
|
509
|
+
// and downstream progress-hook reconstruction can proceed.
|
|
506
510
|
to = (0, viem_1.getAddress)(tx.to);
|
|
507
511
|
value = tx.value;
|
|
508
512
|
data = tx.input;
|
|
509
|
-
rawTransactionData = {
|
|
510
|
-
from: (0, viem_1.getAddress)(tx.from),
|
|
511
|
-
to: (0, viem_1.getAddress)(tx.to),
|
|
512
|
-
nonce: tx.nonce,
|
|
513
|
-
data: tx.input,
|
|
514
|
-
value: tx.value,
|
|
515
|
-
};
|
|
516
513
|
}
|
|
514
|
+
// Extract 'to' from single-element multicall
|
|
515
|
+
if (data && data.length >= 10) {
|
|
516
|
+
const multicallSelector = (0, viem_1.keccak256)((0, viem_1.toBytes)('UEA_MULTICALL')).slice(0, 10);
|
|
517
|
+
if (data.slice(0, 10) === multicallSelector) {
|
|
518
|
+
try {
|
|
519
|
+
const innerData = ('0x' + data.slice(10));
|
|
520
|
+
const [decodedCalls] = (0, viem_1.decodeAbiParameters)([
|
|
521
|
+
{
|
|
522
|
+
type: 'tuple[]',
|
|
523
|
+
components: [
|
|
524
|
+
{ name: 'to', type: 'address' },
|
|
525
|
+
{ name: 'value', type: 'uint256' },
|
|
526
|
+
{ name: 'data', type: 'bytes' },
|
|
527
|
+
],
|
|
528
|
+
},
|
|
529
|
+
], innerData);
|
|
530
|
+
// If single call, use its 'to' address
|
|
531
|
+
if (decodedCalls.length === 1) {
|
|
532
|
+
to = (0, viem_1.getAddress)(decodedCalls[0].to);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
catch {
|
|
536
|
+
// Keep original 'to' if decoding fails
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
rawTransactionData = {
|
|
541
|
+
from: (0, viem_1.getAddress)(tx.from),
|
|
542
|
+
to: (0, viem_1.getAddress)(tx.to),
|
|
543
|
+
nonce: tx.nonce,
|
|
544
|
+
data: tx.input,
|
|
545
|
+
value: tx.value,
|
|
546
|
+
};
|
|
517
547
|
}
|
|
518
548
|
else {
|
|
519
|
-
originAddress = (0, viem_1.getAddress)(tx.from);
|
|
520
|
-
from = (0, viem_1.getAddress)(tx.from);
|
|
521
549
|
to = (0, viem_1.getAddress)(tx.to);
|
|
522
550
|
value = tx.value;
|
|
523
551
|
data = tx.input;
|
|
@@ -529,316 +557,404 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
529
557
|
value: tx.value,
|
|
530
558
|
};
|
|
531
559
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
originAddress = (0, viem_1.getAddress)(tx.from);
|
|
563
|
+
from = (0, viem_1.getAddress)(tx.from);
|
|
564
|
+
to = (0, viem_1.getAddress)(tx.to);
|
|
565
|
+
value = tx.value;
|
|
566
|
+
data = tx.input;
|
|
567
|
+
rawTransactionData = {
|
|
568
|
+
from: (0, viem_1.getAddress)(tx.from),
|
|
569
|
+
to: (0, viem_1.getAddress)(tx.to),
|
|
570
|
+
nonce: tx.nonce,
|
|
571
|
+
data: tx.input,
|
|
572
|
+
value: tx.value,
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
// Extract 'to' and 'from' from depositPRC20WithAutoSwap (precompile call)
|
|
576
|
+
if (data && data.length >= 10) {
|
|
577
|
+
const depositPRC20Selector = '0x780ad827';
|
|
578
|
+
if (data.slice(0, 10) === depositPRC20Selector) {
|
|
579
|
+
try {
|
|
580
|
+
const decoded = (0, viem_1.decodeFunctionData)({
|
|
581
|
+
abi: [
|
|
582
|
+
{
|
|
583
|
+
name: 'depositPRC20WithAutoSwap',
|
|
584
|
+
type: 'function',
|
|
585
|
+
inputs: [
|
|
586
|
+
{ name: 'prc20', type: 'address' },
|
|
587
|
+
{ name: 'amount', type: 'uint256' },
|
|
588
|
+
{ name: 'target', type: 'address' },
|
|
589
|
+
{ name: 'fee', type: 'uint24' },
|
|
590
|
+
{ name: 'minPCOut', type: 'uint256' },
|
|
591
|
+
{ name: 'deadline', type: 'uint256' },
|
|
592
|
+
],
|
|
593
|
+
},
|
|
594
|
+
],
|
|
595
|
+
data: data,
|
|
596
|
+
});
|
|
597
|
+
if (decoded.args) {
|
|
598
|
+
const target = decoded.args[2];
|
|
599
|
+
to = (0, viem_1.getAddress)(target);
|
|
600
|
+
from = '0x0000000000000000000000000000000000000000';
|
|
562
601
|
}
|
|
563
602
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
// Create signature from transaction r, s, v values.
|
|
567
|
-
//
|
|
568
|
-
// Push Chain's derived (module-injected) inbound txs are reported over the EVM
|
|
569
|
-
// JSON-RPC as **legacy `type 0x0`**, which omits the `yParity` field that viem
|
|
570
|
-
// only populates for typed (EIP-1559/2930) txs — so `tx.yParity` is `undefined`.
|
|
571
|
-
// Per the chain team (the hash inconsistencies were fixed chain-side, but
|
|
572
|
-
// derived txs remain legacy 0x0 by design), the SDK must accept `0x0` and
|
|
573
|
-
// surface a numeric `yParity`. Derive it from `v`: 0/1 → as-is, 27/28 → v-27,
|
|
574
|
-
// EIP-155 → (v-35)%2. (For the zeroed-signature derived txs, v=0 → yParity=0.)
|
|
575
|
-
let signature;
|
|
576
|
-
try {
|
|
577
|
-
const vNum = typeof tx.v === 'bigint' ? Number(tx.v) : tx.v || 0;
|
|
578
|
-
let yParity = tx.yParity;
|
|
579
|
-
if (yParity === undefined) {
|
|
580
|
-
if (vNum === 0 || vNum === 1)
|
|
581
|
-
yParity = vNum;
|
|
582
|
-
else if (vNum === 27 || vNum === 28)
|
|
583
|
-
yParity = vNum - 27;
|
|
584
|
-
else
|
|
585
|
-
yParity = (vNum - 35) % 2;
|
|
603
|
+
catch {
|
|
604
|
+
// Keep original values if decoding fails
|
|
586
605
|
}
|
|
587
|
-
signature = {
|
|
588
|
-
r: tx.r || '0x0',
|
|
589
|
-
s: tx.s || '0x0',
|
|
590
|
-
v: vNum,
|
|
591
|
-
yParity,
|
|
592
|
-
};
|
|
593
606
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
607
|
+
}
|
|
608
|
+
const origin = `${chain_1.VM_NAMESPACE[vm]}:${chainId}:${originAddress}`;
|
|
609
|
+
// Create signature from transaction r, s, v values.
|
|
610
|
+
//
|
|
611
|
+
// Push Chain's derived (module-injected) inbound txs are reported over the EVM
|
|
612
|
+
// JSON-RPC as **legacy `type 0x0`**, which omits the `yParity` field that viem
|
|
613
|
+
// only populates for typed (EIP-1559/2930) txs — so `tx.yParity` is `undefined`.
|
|
614
|
+
// Per the chain team (the hash inconsistencies were fixed chain-side, but
|
|
615
|
+
// derived txs remain legacy 0x0 by design), the SDK must accept `0x0` and
|
|
616
|
+
// surface a numeric `yParity`. Derive it from `v`: 0/1 → as-is, 27/28 → v-27,
|
|
617
|
+
// EIP-155 → (v-35)%2. (For the zeroed-signature derived txs, v=0 → yParity=0.)
|
|
618
|
+
let signature;
|
|
619
|
+
try {
|
|
620
|
+
const vNum = typeof tx.v === 'bigint' ? Number(tx.v) : tx.v || 0;
|
|
621
|
+
let yParity = tx.yParity;
|
|
622
|
+
if (yParity === undefined) {
|
|
623
|
+
if (vNum === 0 || vNum === 1)
|
|
624
|
+
yParity = vNum;
|
|
625
|
+
else if (vNum === 27 || vNum === 28)
|
|
626
|
+
yParity = vNum - 27;
|
|
627
|
+
else
|
|
628
|
+
yParity = (vNum - 35) % 2;
|
|
602
629
|
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
630
|
+
signature = {
|
|
631
|
+
r: tx.r || '0x0',
|
|
632
|
+
s: tx.s || '0x0',
|
|
633
|
+
v: vNum,
|
|
634
|
+
yParity,
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
catch {
|
|
638
|
+
// Fallback signature if parsing fails
|
|
639
|
+
signature = {
|
|
640
|
+
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
641
|
+
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
642
|
+
v: 0,
|
|
643
|
+
yParity: 0,
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
// Determine transaction type and typeVerbose
|
|
647
|
+
let type = '99'; // universal
|
|
648
|
+
let typeVerbose = 'universal';
|
|
649
|
+
if (tx.type !== undefined) {
|
|
650
|
+
const txType = tx.type;
|
|
651
|
+
if (txType === 'eip1559') {
|
|
652
|
+
type = '2';
|
|
653
|
+
typeVerbose = 'eip1559';
|
|
624
654
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
655
|
+
else if (txType === 'eip2930') {
|
|
656
|
+
type = '1';
|
|
657
|
+
typeVerbose = 'eip2930';
|
|
658
|
+
}
|
|
659
|
+
else if (txType === 'legacy') {
|
|
660
|
+
type = '0';
|
|
661
|
+
typeVerbose = 'legacy';
|
|
662
|
+
}
|
|
663
|
+
else if (txType === 'eip4844') {
|
|
664
|
+
type = '3';
|
|
665
|
+
typeVerbose = 'eip4844';
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
// Storage for registered progress callback (used by progressHook method)
|
|
669
|
+
let registeredProgressHook;
|
|
670
|
+
const universalTxResponse = {
|
|
671
|
+
// 1. Identity
|
|
672
|
+
hash: tx.hash,
|
|
673
|
+
finalTxHash: tx.hash, // Push tx hash; .wait()'s receipt refines it for R2/R3
|
|
674
|
+
origin,
|
|
675
|
+
// 2. Block Info
|
|
676
|
+
blockNumber: tx.blockNumber || BigInt(0),
|
|
677
|
+
blockHash: tx.blockHash || '',
|
|
678
|
+
transactionIndex: tx.transactionIndex || 0,
|
|
679
|
+
chainId,
|
|
680
|
+
// 3. Execution Context
|
|
681
|
+
from: from, // UEA (executor) address, checksummed for EVM
|
|
682
|
+
to: to || '',
|
|
683
|
+
nonce: tx.nonce,
|
|
684
|
+
// 4. Payload
|
|
685
|
+
data, // perceived calldata (was input)
|
|
686
|
+
value,
|
|
687
|
+
// 5. Gas
|
|
688
|
+
gasLimit: tx.gas || BigInt(0), // (was gas)
|
|
689
|
+
gasPrice: tx.gasPrice,
|
|
690
|
+
maxFeePerGas: tx.maxFeePerGas,
|
|
691
|
+
maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
|
|
692
|
+
accessList: Array.isArray(tx.accessList) ? [...tx.accessList] : [],
|
|
693
|
+
// 6. Utilities
|
|
694
|
+
wait: async (waitOptions) => {
|
|
695
|
+
// For trackTransaction replays the tx is historical — cosmos already
|
|
696
|
+
// has the full graph indexed, so the 20s/30s initial-wait buffers
|
|
697
|
+
// designed for live sends are pure deadweight. Default them to 0 when
|
|
698
|
+
// replaying; callers can still override via WaitOptions.
|
|
699
|
+
const isReplay = universalTxResponse._eventsReconstructed === true;
|
|
700
|
+
const outboundTimeoutMs = waitOptions?.outboundTimeoutMs ??
|
|
701
|
+
callbacks.outboundConstants.maxTimeoutMs;
|
|
702
|
+
const inboundTimeoutMs = waitOptions?.inboundTimeoutMs ??
|
|
703
|
+
callbacks.inboundConstants.maxTimeoutMs;
|
|
704
|
+
const outboundInitialWaitMs = waitOptions?.outboundInitialWaitMs ??
|
|
705
|
+
(isReplay ? 0 : callbacks.outboundConstants.initialWaitMs);
|
|
706
|
+
const outboundPollingIntervalMs = waitOptions?.outboundPollingIntervalMs ??
|
|
707
|
+
callbacks.outboundConstants.pollingIntervalMs;
|
|
708
|
+
const inboundInitialWaitMs = isReplay
|
|
709
|
+
? 0
|
|
710
|
+
: callbacks.inboundConstants.initialWaitMs;
|
|
711
|
+
// Build the base receipt directly from this response. Any per-call
|
|
712
|
+
// `tx.progressHook(cb)` already replayed buffered execute-phase events
|
|
713
|
+
// to `cb` via the progressHook setter — re-running trackTransaction
|
|
714
|
+
// here would duplicate the reconstructed stream on top of that replay,
|
|
715
|
+
// which is exactly what broke R1 parity. Wait-phase events (209-xx /
|
|
716
|
+
// 299-xx / 399-xx) still reach `registeredProgressHook` and
|
|
717
|
+
// `ctx.progressHook` via the `emit` closure in the outbound branch.
|
|
718
|
+
const receipt = await tx.wait();
|
|
719
|
+
let baseReceipt = callbacks.transformToUniversalTxReceipt(receipt, universalTxResponse);
|
|
720
|
+
// If outbound route, poll for external chain details
|
|
721
|
+
const route = universalTxResponse.route;
|
|
722
|
+
const routeInfo = route ? (0, route_detector_1.getRouteInfo)(route) : undefined;
|
|
723
|
+
// A reverted Push-chain root transaction can never produce an outbound
|
|
724
|
+
// leg. Previously we still entered waitForOutboundTx() here, which made
|
|
725
|
+
// a known failure look like an in-progress relay until the outbound
|
|
726
|
+
// timeout elapsed. Stop at the root receipt instead and emit the
|
|
727
|
+
// route-terminal failure immediately. `externalStatus` intentionally
|
|
728
|
+
// remains unset: no external transaction was submitted, so the failure
|
|
729
|
+
// is represented by the canonical receipt `status === 0`.
|
|
730
|
+
if (baseReceipt.status === 0) {
|
|
731
|
+
const errMsg = `Push Chain transaction ${universalTxResponse.hash} reverted; ` +
|
|
732
|
+
'outbound relay was not started';
|
|
733
|
+
if (routeInfo?.isOutbound) {
|
|
734
|
+
const targetChain = (universalTxResponse.chain ??
|
|
735
|
+
'external');
|
|
684
736
|
const emit = (event) => {
|
|
685
737
|
if (!event.id)
|
|
686
738
|
return;
|
|
687
739
|
fanOut(event, registeredProgressHook, ctx.progressHook);
|
|
688
740
|
};
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
741
|
+
if (route === route_detector_1.TransactionRoute.CEA_TO_PUSH) {
|
|
742
|
+
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](errMsg, 'push', targetChain, undefined, universalTxResponse.hash));
|
|
743
|
+
}
|
|
744
|
+
else {
|
|
745
|
+
emit((0, progress_route_hooks_1.pickWaitHooks)(route).failed(targetChain, errMsg, {
|
|
746
|
+
pushTxHash: universalTxResponse.hash,
|
|
747
|
+
}));
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
callbacks.printLog(`[wait] ${errMsg}`);
|
|
751
|
+
return baseReceipt;
|
|
752
|
+
}
|
|
753
|
+
if (routeInfo?.isOutbound) {
|
|
754
|
+
// Pick route-specific hook builders. R4 (CEA_TO_CEA) currently has
|
|
755
|
+
// no spec'd IDs — pickWaitHooks returns a no-op set that yields
|
|
756
|
+
// events with `id: ''`. `emit` drops those so the consumer never
|
|
757
|
+
// sees placeholder events, while receipt mutation still runs.
|
|
758
|
+
const hooks = (0, progress_route_hooks_1.pickWaitHooks)(route);
|
|
759
|
+
const targetChain = (universalTxResponse.chain ?? 'external');
|
|
760
|
+
const emit = (event) => {
|
|
761
|
+
if (!event.id)
|
|
762
|
+
return;
|
|
763
|
+
fanOut(event, registeredProgressHook, ctx.progressHook);
|
|
764
|
+
};
|
|
765
|
+
// Awaiting relay
|
|
766
|
+
emit(hooks.awaiting(targetChain, universalTxResponse.hash));
|
|
767
|
+
let lastEmittedStatus;
|
|
768
|
+
const outboundTranslator = (event) => {
|
|
769
|
+
if (event.status === 'polling' && lastEmittedStatus !== 'polling') {
|
|
770
|
+
lastEmittedStatus = 'polling';
|
|
771
|
+
emit(hooks.polling(targetChain, event.elapsed, universalTxResponse.hash));
|
|
772
|
+
}
|
|
773
|
+
};
|
|
774
|
+
try {
|
|
775
|
+
const outboundDetails = await callbacks.waitForOutboundTx(tx.hash, {
|
|
776
|
+
initialWaitMs: outboundInitialWaitMs,
|
|
777
|
+
pollingIntervalMs: outboundPollingIntervalMs,
|
|
778
|
+
timeout: outboundTimeoutMs,
|
|
779
|
+
progressHook: outboundTranslator,
|
|
780
|
+
});
|
|
781
|
+
// `outboundDetails.externalTxHash` is the raw `0x`-hex form (kept
|
|
782
|
+
// internally so the R3 inbound tracker below can query Cosmos with
|
|
783
|
+
// it via `waitForInboundPushTx → findChildUtxIdFromExternalTx`).
|
|
784
|
+
// For every USER-FACING surface (progress hook event + receipt) we
|
|
785
|
+
// want the chain-native form so consumers can paste it straight
|
|
786
|
+
// into an explorer / RPC: base58 for SVM, hex for EVM. Build a
|
|
787
|
+
// display copy and use it for both the hook and the receipt.
|
|
788
|
+
const displayExternalTxHash = (0, helpers_1.toExternalTxHashDisplay)(outboundDetails.destinationChain, outboundDetails.externalTxHash) ?? outboundDetails.externalTxHash;
|
|
789
|
+
const userFacingOutboundDetails = {
|
|
790
|
+
...outboundDetails,
|
|
791
|
+
externalTxHash: displayExternalTxHash,
|
|
697
792
|
};
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
baseReceipt = Object.assign(Object.assign({}, baseReceipt), { pushInboundTxHash: inbound.pushTxHash, pushInboundUtxId: inbound.childUtxId });
|
|
742
|
-
}
|
|
743
|
-
else {
|
|
744
|
-
// status === 'failed' (terminal failure status from chain)
|
|
745
|
-
const failMsg = (_g = inbound.errorMessage) !== null && _g !== void 0 ? _g : 'inbound execution failed on Push Chain';
|
|
746
|
-
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](failMsg, 'inbound', targetChain, undefined, universalTxResponse.hash, inbound.pushTxHash || undefined));
|
|
747
|
-
baseReceipt = Object.assign(Object.assign({}, baseReceipt), { pushInboundUtxId: inbound.childUtxId, pushInboundTxHash: inbound.pushTxHash || undefined, externalStatus: 'failed', externalError: failMsg });
|
|
748
|
-
}
|
|
793
|
+
emit(hooks.success(userFacingOutboundDetails));
|
|
794
|
+
baseReceipt = {
|
|
795
|
+
...baseReceipt,
|
|
796
|
+
externalTxHash: displayExternalTxHash,
|
|
797
|
+
externalChain: outboundDetails.destinationChain,
|
|
798
|
+
externalExplorerUrl: outboundDetails.explorerUrl,
|
|
799
|
+
externalRecipient: outboundDetails.recipient,
|
|
800
|
+
externalAmount: outboundDetails.amount,
|
|
801
|
+
externalAssetAddr: outboundDetails.assetAddr,
|
|
802
|
+
externalStatus: 'success',
|
|
803
|
+
};
|
|
804
|
+
// R3 round-trip: poll Push Chain for the inbound tx that the
|
|
805
|
+
// source-chain CEA's sendUniversalTxToUEA call produces. Correlate
|
|
806
|
+
// via the outbound external tx hash → child UTX id → child pcTx.
|
|
807
|
+
// Only run when the CEA payload actually fires sendUniversalTxToUEA;
|
|
808
|
+
// payload-only R3 (no funds flowing back) has no child UTX and would
|
|
809
|
+
// otherwise time out after 300s.
|
|
810
|
+
if (route === route_detector_1.TransactionRoute.CEA_TO_PUSH &&
|
|
811
|
+
universalTxResponse._expectsInboundRoundTrip === true) {
|
|
812
|
+
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_310_01](targetChain, universalTxResponse.hash));
|
|
813
|
+
let inboundLastEmitted;
|
|
814
|
+
try {
|
|
815
|
+
const inbound = await (0, inbound_tracker_1.waitForInboundPushTx)(ctx, outboundDetails.externalTxHash, targetChain, {
|
|
816
|
+
initialWaitMs: inboundInitialWaitMs,
|
|
817
|
+
pollingIntervalMs: callbacks.inboundConstants.pollingIntervalMs,
|
|
818
|
+
timeout: inboundTimeoutMs,
|
|
819
|
+
progressHook: (event) => {
|
|
820
|
+
if (event.status === 'polling' &&
|
|
821
|
+
inboundLastEmitted !== 'polling') {
|
|
822
|
+
inboundLastEmitted = 'polling';
|
|
823
|
+
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_310_02](targetChain, event.elapsedMs, universalTxResponse.hash));
|
|
824
|
+
}
|
|
825
|
+
},
|
|
826
|
+
});
|
|
827
|
+
if (inbound.status === 'confirmed') {
|
|
828
|
+
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_01](targetChain, inbound.pushTxHash, baseReceipt));
|
|
829
|
+
baseReceipt = {
|
|
830
|
+
...baseReceipt,
|
|
831
|
+
pushInboundTxHash: inbound.pushTxHash,
|
|
832
|
+
pushInboundUtxId: inbound.childUtxId,
|
|
833
|
+
// Round-trip completed. externalStatus stays 'success'
|
|
834
|
+
// (set on the outbound-found branch above).
|
|
835
|
+
};
|
|
749
836
|
}
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
:
|
|
760
|
-
|
|
837
|
+
else {
|
|
838
|
+
// status === 'failed' (terminal failure status from chain)
|
|
839
|
+
const failMsg = inbound.errorMessage ??
|
|
840
|
+
'inbound execution failed on Push Chain';
|
|
841
|
+
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](failMsg, 'inbound', targetChain, undefined, universalTxResponse.hash, inbound.pushTxHash || undefined));
|
|
842
|
+
baseReceipt = {
|
|
843
|
+
...baseReceipt,
|
|
844
|
+
pushInboundUtxId: inbound.childUtxId,
|
|
845
|
+
pushInboundTxHash: inbound.pushTxHash || undefined,
|
|
846
|
+
externalStatus: 'failed',
|
|
847
|
+
externalError: failMsg,
|
|
848
|
+
};
|
|
761
849
|
}
|
|
762
850
|
}
|
|
851
|
+
catch (inboundErr) {
|
|
852
|
+
const errMsg = inboundErr instanceof Error
|
|
853
|
+
? inboundErr.message
|
|
854
|
+
: String(inboundErr);
|
|
855
|
+
const isTimeout = inboundErr instanceof inbound_tracker_1.InboundTimeoutError;
|
|
856
|
+
// Annotate receipt for inbound-leg outcome too.
|
|
857
|
+
baseReceipt = {
|
|
858
|
+
...baseReceipt,
|
|
859
|
+
externalStatus: isTimeout ? 'timeout' : 'failed',
|
|
860
|
+
externalError: errMsg,
|
|
861
|
+
};
|
|
862
|
+
emit(isTimeout
|
|
863
|
+
? progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_03](targetChain, inboundTimeoutMs, 'inbound', universalTxResponse.hash)
|
|
864
|
+
: progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](errMsg, 'inbound', targetChain, undefined, universalTxResponse.hash));
|
|
865
|
+
callbacks.printLog(`[wait] R3 inbound tracking failed: ${errMsg}`);
|
|
866
|
+
}
|
|
763
867
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
868
|
+
}
|
|
869
|
+
catch (error) {
|
|
870
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
871
|
+
const isTimeout = error instanceof outbound_sync_1.OutboundTimeoutError;
|
|
872
|
+
const failedExternalTxHash = error instanceof outbound_sync_1.OutboundFailedError ? error.externalTxHash : undefined;
|
|
873
|
+
// Normalize to chain-native display form for SVM (base58); EVM hex
|
|
874
|
+
// passes through unchanged. `OutboundFailedError.destinationChain`
|
|
875
|
+
// is a chain namespace string (e.g., 'solana:devnet') — convert to
|
|
876
|
+
// the CHAIN enum via the same helper used in outbound-sync.
|
|
877
|
+
const failedChain = error instanceof outbound_sync_1.OutboundFailedError && error.destinationChain
|
|
878
|
+
? (0, helpers_1.chainFromNamespace)(error.destinationChain) ?? undefined
|
|
879
|
+
: undefined;
|
|
880
|
+
const failedExternalTxHashDisplay = (0, helpers_1.toExternalTxHashDisplay)(failedChain, failedExternalTxHash) ??
|
|
881
|
+
failedExternalTxHash;
|
|
882
|
+
emit(isTimeout
|
|
883
|
+
? hooks.timeout(targetChain, outboundTimeoutMs, universalTxResponse.hash)
|
|
884
|
+
: hooks.failed(targetChain, errMsg, {
|
|
885
|
+
pushTxHash: universalTxResponse.hash,
|
|
886
|
+
txHash: failedExternalTxHashDisplay,
|
|
887
|
+
}));
|
|
888
|
+
// Annotate the receipt so callers can distinguish external-leg
|
|
889
|
+
// outcomes without sniffing errMsg. Push Chain leg still succeeded
|
|
890
|
+
// (status stays 1); inspect `externalStatus` / `externalError` for
|
|
891
|
+
// the external/inbound leg outcome. On a reverted outbound the
|
|
892
|
+
// observed tx hash is carried by OutboundFailedError — expose it
|
|
893
|
+
// as externalTxHash so consumers can link to the explorer.
|
|
894
|
+
baseReceipt = {
|
|
895
|
+
...baseReceipt,
|
|
896
|
+
externalStatus: isTimeout ? 'timeout' : 'failed',
|
|
897
|
+
externalError: errMsg,
|
|
898
|
+
...(failedExternalTxHashDisplay
|
|
789
899
|
? { externalTxHash: failedExternalTxHashDisplay }
|
|
790
|
-
: {})
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
}
|
|
900
|
+
: {}),
|
|
901
|
+
};
|
|
902
|
+
// Outbound polling timed out or failed — return the annotated
|
|
903
|
+
// receipt without throwing. Push Chain tx succeeded, external
|
|
904
|
+
// tracking can be retried later.
|
|
905
|
+
callbacks.printLog(`[wait] External chain tracking ${isTimeout ? 'timed out' : 'failed'}: ${errMsg}`);
|
|
796
906
|
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
907
|
+
}
|
|
908
|
+
// Resolve the terminal hash for the whole journey: inbound (R3) >
|
|
909
|
+
// external outbound (R2) > the Push tx itself (R1). Single-tx analogue
|
|
910
|
+
// of CascadeCompletionResult.finalTxHash.
|
|
911
|
+
baseReceipt = {
|
|
912
|
+
...baseReceipt,
|
|
913
|
+
finalTxHash: baseReceipt.pushInboundTxHash ??
|
|
914
|
+
baseReceipt.externalTxHash ??
|
|
915
|
+
baseReceipt.hash,
|
|
916
|
+
// Ensure `externalChain` is populated whenever an external/inbound leg
|
|
917
|
+
// surfaced an `externalTxHash`. The outbound-success branch already sets
|
|
918
|
+
// it to the destination chain (so this `??` never overrides it); this
|
|
919
|
+
// only fills the inbound/R3 and failed/timeout paths, where it should be
|
|
920
|
+
// the route's external chain (= the response's `chain`).
|
|
921
|
+
externalChain: baseReceipt.externalChain ??
|
|
922
|
+
(baseReceipt.externalTxHash
|
|
807
923
|
? universalTxResponse.chain
|
|
808
|
-
: baseReceipt.externalChain)
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
924
|
+
: baseReceipt.externalChain),
|
|
925
|
+
};
|
|
926
|
+
return baseReceipt;
|
|
927
|
+
},
|
|
928
|
+
// Internal: register a wait-phase progressHook without replaying
|
|
929
|
+
// buffered events. Used by trackTransaction() after it has already
|
|
930
|
+
// emitted the reconstructed stream to the caller's per-call hook,
|
|
931
|
+
// so that tracked.wait() can deliver wait-phase events (209-xx /
|
|
932
|
+
// 299-xx / 399-xx) to the same callback without duplicating replay.
|
|
933
|
+
_setProgressHookNoReplay: (callback) => {
|
|
934
|
+
registeredProgressHook = callback;
|
|
935
|
+
},
|
|
936
|
+
progressHook: (callback) => {
|
|
937
|
+
registeredProgressHook = callback;
|
|
938
|
+
// Immediately replay buffered events from execution
|
|
939
|
+
if (eventBuffer.length > 0) {
|
|
940
|
+
for (const event of eventBuffer) {
|
|
941
|
+
callback(event);
|
|
826
942
|
}
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
943
|
+
}
|
|
944
|
+
},
|
|
945
|
+
// 7. Metadata
|
|
946
|
+
type,
|
|
947
|
+
typeVerbose,
|
|
948
|
+
// Atomic by default — a single tx, an EIP-7702 batch, and a UEA multicall
|
|
949
|
+
// are all all-or-nothing. Only the native sequential fallback loop overrides
|
|
950
|
+
// this to `false` (see sendPushTx in push-chain-tx.ts). Historical lookups
|
|
951
|
+
// via trackTransaction also keep the default, since the past execution mode
|
|
952
|
+
// isn't always recoverable.
|
|
953
|
+
atomic: true,
|
|
954
|
+
signature,
|
|
955
|
+
// 8. Raw Universal Fields
|
|
956
|
+
raw: rawTransactionData,
|
|
957
|
+
};
|
|
958
|
+
return universalTxResponse;
|
|
843
959
|
}
|
|
844
960
|
//# sourceMappingURL=response-builder.js.map
|