@pushchain/core 6.0.18 → 6.0.19
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 +8 -0
- package/package.json +1 -1
- package/src/lib/constants/chain.d.ts +16 -0
- package/src/lib/constants/chain.js +32 -4
- package/src/lib/formatters.d.ts +1 -0
- package/src/lib/formatters.js +66 -1
- package/src/lib/orchestrator/internals/cascade.js +64 -46
- package/src/lib/orchestrator/internals/confirmation.js +8 -8
- package/src/lib/orchestrator/internals/error-decoder.d.ts +1 -0
- package/src/lib/orchestrator/internals/error-decoder.js +10 -0
- package/src/lib/orchestrator/internals/errors.js +1 -1
- package/src/lib/orchestrator/internals/execute-funds-only.js +8 -6
- package/src/lib/orchestrator/internals/execute-funds-payload.js +6 -4
- package/src/lib/orchestrator/internals/execute-standard.js +10 -8
- package/src/lib/orchestrator/internals/gateway-client.js +34 -1
- package/src/lib/orchestrator/internals/inbound-tracker.js +4 -3
- package/src/lib/orchestrator/internals/progress-route-hooks.d.ts +8 -4
- package/src/lib/orchestrator/internals/progress-route-hooks.js +8 -8
- package/src/lib/orchestrator/internals/push-chain-tx.js +71 -15
- package/src/lib/orchestrator/internals/response-builder.js +25 -16
- package/src/lib/orchestrator/internals/tx-transformer.js +11 -6
- package/src/lib/orchestrator/orchestrator.js +3 -17
- package/src/lib/orchestrator/orchestrator.types.d.ts +7 -0
- package/src/lib/progress-hook/progress-hook.js +37 -40
- package/src/lib/push-client/push-client.d.ts +39 -0
- package/src/lib/push-client/push-client.js +130 -12
- package/src/lib/universal/signer/signer.d.ts +1 -1
- package/src/lib/universal/signer/signer.js +83 -3
- package/src/lib/universal/universal.types.d.ts +37 -0
- package/src/lib/vm-client/evm-client.d.ts +43 -0
- package/src/lib/vm-client/evm-client.js +154 -1
|
@@ -182,13 +182,15 @@ function executeFundsOnlyEvm(ctx, execute, eventBuffer, transformFn, chain, rpcU
|
|
|
182
182
|
txHash = yield (0, gateway_client_1.sendGatewayTxWithFallback)(ctx, evmClient, gatewayAddress, req, ctx.universalSigner, isNative ? nativeAmount + bridgeAmount : nativeAmount);
|
|
183
183
|
}
|
|
184
184
|
catch (err) {
|
|
185
|
-
(0,
|
|
186
|
-
|
|
185
|
+
const errMsg = (0, formatters_1.normalizePublicErrorMessage)(err);
|
|
186
|
+
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_104_04, errMsg);
|
|
187
|
+
ctx._routeTerminalEmitted = true;
|
|
188
|
+
throw new Error(errMsg);
|
|
187
189
|
}
|
|
188
190
|
const originTx = yield (0, helpers_2.fetchOriginChainTransactionForProgress)(ctx, chain, txHash, txHash);
|
|
189
191
|
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_02, txHash, bridgeAmount, execute.funds.token.decimals, symbol, originTx);
|
|
190
192
|
yield (0, confirmation_1.waitForEvmConfirmationsWithCountdown)(ctx, evmClient, txHash, chain_1.CHAIN_INFO[chain].confirmations, chain_1.CHAIN_INFO[chain].timeout);
|
|
191
|
-
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_04);
|
|
193
|
+
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_04, txHash);
|
|
192
194
|
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_05);
|
|
193
195
|
(0, context_2.printLog)(ctx, 'sendFunds — querying Push Chain status: ' + JSON.stringify({
|
|
194
196
|
txHash, evmGatewayMethod: execute.to === ueaAddress ? 'sendFunds' : 'sendTxWithFunds',
|
|
@@ -202,7 +204,7 @@ function executeFundsOnlyEvm(ctx, execute, eventBuffer, transformFn, chain, rpcU
|
|
|
202
204
|
}
|
|
203
205
|
catch (err) {
|
|
204
206
|
if (!(err instanceof push_chain_tx_1.PushChainExecutionError)) {
|
|
205
|
-
const errMsg = (0, formatters_1.
|
|
207
|
+
const errMsg = (0, formatters_1.normalizePublicErrorMessage)(err);
|
|
206
208
|
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02, errMsg);
|
|
207
209
|
throw new push_chain_tx_1.PushChainExecutionError(errMsg, { gatewayTxHash: txHash });
|
|
208
210
|
}
|
|
@@ -284,7 +286,7 @@ function executeFundsOnlySvm(ctx, execute, eventBuffer, transformFn, chain, rpcU
|
|
|
284
286
|
const originTx = yield (0, helpers_2.fetchOriginChainTransactionForProgress)(ctx, chain, '0x', txSignature);
|
|
285
287
|
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_02, txSignature, bridgeAmount, execute.funds.token.decimals, symbol, originTx);
|
|
286
288
|
yield (0, confirmation_1.waitForSvmConfirmationsWithCountdown)(ctx, svmClient, txSignature, chain_1.CHAIN_INFO[chain].confirmations, chain_1.CHAIN_INFO[chain].timeout);
|
|
287
|
-
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_04);
|
|
289
|
+
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_04, txSignature);
|
|
288
290
|
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_05);
|
|
289
291
|
let response;
|
|
290
292
|
try {
|
|
@@ -293,7 +295,7 @@ function executeFundsOnlySvm(ctx, execute, eventBuffer, transformFn, chain, rpcU
|
|
|
293
295
|
}
|
|
294
296
|
catch (err) {
|
|
295
297
|
if (!(err instanceof push_chain_tx_1.PushChainExecutionError)) {
|
|
296
|
-
const errMsg = (0, formatters_1.
|
|
298
|
+
const errMsg = (0, formatters_1.normalizePublicErrorMessage)(err);
|
|
297
299
|
(0, context_2.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02, errMsg);
|
|
298
300
|
throw new push_chain_tx_1.PushChainExecutionError(errMsg, { gatewayTxHash: txSignature });
|
|
299
301
|
}
|
|
@@ -222,8 +222,10 @@ function executeFundsWithPayload(ctx, execute, eventBuffer, getResponseCallbacks
|
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
224
|
catch (err) {
|
|
225
|
-
(0,
|
|
226
|
-
|
|
225
|
+
const errMsg = (0, formatters_1.normalizePublicErrorMessage)(err);
|
|
226
|
+
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_104_04, errMsg);
|
|
227
|
+
ctx._routeTerminalEmitted = true;
|
|
228
|
+
throw new Error(errMsg);
|
|
227
229
|
}
|
|
228
230
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_104_03);
|
|
229
231
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_02, txHash, bridgeAmount, execute.funds.token.decimals, symbol);
|
|
@@ -246,7 +248,7 @@ function executeFundsWithPayload(ctx, execute, eventBuffer, getResponseCallbacks
|
|
|
246
248
|
feeLockTxHash = (0, viem_1.bytesToHex)(new Uint8Array(decoded));
|
|
247
249
|
}
|
|
248
250
|
}
|
|
249
|
-
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_04);
|
|
251
|
+
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_04, txHash);
|
|
250
252
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_106_05);
|
|
251
253
|
let response;
|
|
252
254
|
try {
|
|
@@ -261,7 +263,7 @@ function executeFundsWithPayload(ctx, execute, eventBuffer, getResponseCallbacks
|
|
|
261
263
|
}
|
|
262
264
|
catch (err) {
|
|
263
265
|
if (!(err instanceof push_chain_tx_1.PushChainExecutionError)) {
|
|
264
|
-
const errMsg = (0, formatters_1.
|
|
266
|
+
const errMsg = (0, formatters_1.normalizePublicErrorMessage)(err);
|
|
265
267
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02, errMsg);
|
|
266
268
|
throw new push_chain_tx_1.PushChainExecutionError(errMsg, { gatewayTxHash: txHash });
|
|
267
269
|
}
|
|
@@ -111,7 +111,7 @@ function executeStandardPayload(ctx, execute, eventBuffer, getResponseCallbacks)
|
|
|
111
111
|
catch (err) {
|
|
112
112
|
// Push Chain broadcast failed. Wallet rejection surfaces as 104-04;
|
|
113
113
|
// everything else (RPC fail, on-chain revert) as 199-02.
|
|
114
|
-
const errMsg = (0, formatters_1.
|
|
114
|
+
const errMsg = (0, formatters_1.normalizePublicErrorMessage)(err);
|
|
115
115
|
const { isUserDecline } = (0, progress_hook_1.classifyDeclineError)(errMsg);
|
|
116
116
|
(0, context_1.fireProgressHook)(ctx, isUserDecline ? progress_hook_types_1.PROGRESS_HOOK.SEND_TX_104_04 : progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02, errMsg);
|
|
117
117
|
// Mark that a terminal-ish error hook has already fired so the
|
|
@@ -274,9 +274,10 @@ function executeStandardPayload(ctx, execute, eventBuffer, getResponseCallbacks)
|
|
|
274
274
|
// Wallet decline, contract revert during sign, or RPC failure — the
|
|
275
275
|
// 104-04 builder's classifyDeclineError heuristic picks the right
|
|
276
276
|
// copy (real decline → "Verification Declined"; else "Signature Failed").
|
|
277
|
-
const errMsg = (0, formatters_1.
|
|
277
|
+
const errMsg = (0, formatters_1.normalizePublicErrorMessage)(err);
|
|
278
278
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_104_04, errMsg);
|
|
279
|
-
|
|
279
|
+
ctx._routeTerminalEmitted = true;
|
|
280
|
+
throw new Error(errMsg);
|
|
280
281
|
}
|
|
281
282
|
verificationData = (0, viem_1.bytesToHex)(signature);
|
|
282
283
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_104_03);
|
|
@@ -393,9 +394,10 @@ function executeStandardPayload(ctx, execute, eventBuffer, getResponseCallbacks)
|
|
|
393
394
|
catch (err) {
|
|
394
395
|
// User declined the fee-lock tx submission or the origin-chain RPC
|
|
395
396
|
// rejected it — classifier picks decline vs generic signature failure.
|
|
396
|
-
const errMsg =
|
|
397
|
+
const errMsg = (0, formatters_1.normalizePublicErrorMessage)(err);
|
|
397
398
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_104_04, errMsg);
|
|
398
|
-
|
|
399
|
+
ctx._routeTerminalEmitted = true;
|
|
400
|
+
throw new Error(errMsg);
|
|
399
401
|
}
|
|
400
402
|
feeLockTxHash = (0, viem_1.bytesToHex)(feeLockTxHashBytes);
|
|
401
403
|
verificationData = (0, viem_1.bytesToHex)(feeLockTxHashBytes);
|
|
@@ -406,7 +408,7 @@ function executeStandardPayload(ctx, execute, eventBuffer, getResponseCallbacks)
|
|
|
406
408
|
const originTx = yield (0, helpers_1.fetchOriginChainTransactionForProgress)(ctx, chain, feeLockTxHash, feeLockTxHashDisplay);
|
|
407
409
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_105_01, feeLockTxHashDisplay, originTx);
|
|
408
410
|
yield (0, confirmation_1.waitForLockerFeeConfirmation)(ctx, feeLockTxHashBytes);
|
|
409
|
-
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_105_02);
|
|
411
|
+
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_105_02, feeLockTxHashDisplay);
|
|
410
412
|
const { defaultRPC, lockerContract } = chain_1.CHAIN_INFO[chain];
|
|
411
413
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_107);
|
|
412
414
|
let response;
|
|
@@ -420,7 +422,7 @@ function executeStandardPayload(ctx, execute, eventBuffer, getResponseCallbacks)
|
|
|
420
422
|
}
|
|
421
423
|
catch (err) {
|
|
422
424
|
if (!(err instanceof push_chain_tx_1.PushChainExecutionError)) {
|
|
423
|
-
const errMsg = (0, formatters_1.
|
|
425
|
+
const errMsg = (0, formatters_1.normalizePublicErrorMessage)(err);
|
|
424
426
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02, errMsg);
|
|
425
427
|
throw new push_chain_tx_1.PushChainExecutionError(errMsg, { gatewayTxHash: feeLockTxHash });
|
|
426
428
|
}
|
|
@@ -454,7 +456,7 @@ function executeStandardPayload(ctx, execute, eventBuffer, getResponseCallbacks)
|
|
|
454
456
|
// exhaustion). Surface terminal 199-02 before re-throwing so the stream
|
|
455
457
|
// ends with the spec'd error hook. Typed PushChainExecutionError lets
|
|
456
458
|
// callers classify via instanceof without message sniffing.
|
|
457
|
-
const errMsg = (0, formatters_1.
|
|
459
|
+
const errMsg = (0, formatters_1.normalizePublicErrorMessage)(err);
|
|
458
460
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02, errMsg);
|
|
459
461
|
if (err instanceof push_chain_tx_1.PushChainExecutionError)
|
|
460
462
|
throw err;
|
|
@@ -30,6 +30,27 @@ const svm_helpers_2 = require("./svm-helpers");
|
|
|
30
30
|
// ABI
|
|
31
31
|
// ============================================================================
|
|
32
32
|
const GATEWAY_ABI = abi_1.UNIVERSAL_GATEWAY_V1_SEND;
|
|
33
|
+
const SOURCE_NATIVE_SYMBOL = {
|
|
34
|
+
[enums_1.CHAIN.ETHEREUM_MAINNET]: 'ETH',
|
|
35
|
+
[enums_1.CHAIN.ETHEREUM_SEPOLIA]: 'ETH',
|
|
36
|
+
[enums_1.CHAIN.ARBITRUM_SEPOLIA]: 'ETH',
|
|
37
|
+
[enums_1.CHAIN.BASE_SEPOLIA]: 'ETH',
|
|
38
|
+
[enums_1.CHAIN.BNB_TESTNET]: 'BNB',
|
|
39
|
+
[enums_1.CHAIN.SOLANA_MAINNET]: 'SOL',
|
|
40
|
+
[enums_1.CHAIN.SOLANA_TESTNET]: 'SOL',
|
|
41
|
+
[enums_1.CHAIN.SOLANA_DEVNET]: 'SOL',
|
|
42
|
+
};
|
|
43
|
+
function formatSourceNative(chain, amount) {
|
|
44
|
+
var _a;
|
|
45
|
+
const decimals = chain_1.CHAIN_INFO[chain].vm === enums_1.VM.SVM ? 9 : 18;
|
|
46
|
+
const symbol = (_a = SOURCE_NATIVE_SYMBOL[chain]) !== null && _a !== void 0 ? _a : 'native token';
|
|
47
|
+
return `${utils_1.Utils.helpers.formatUnits(amount, decimals)} ${symbol}`;
|
|
48
|
+
}
|
|
49
|
+
function insufficientSourceBalanceMessage(chain, available, required) {
|
|
50
|
+
return (`Insufficient source balance for transaction gas/value: ` +
|
|
51
|
+
`have ${formatSourceNative(chain, available)}, ` +
|
|
52
|
+
`need at least ${formatSourceNative(chain, required)}.`);
|
|
53
|
+
}
|
|
33
54
|
// ============================================================================
|
|
34
55
|
// Request Conversion (V0 struct → V1 flat format)
|
|
35
56
|
// ============================================================================
|
|
@@ -104,6 +125,13 @@ req) {
|
|
|
104
125
|
(nativeTokenUsdPrice - BigInt(1))) /
|
|
105
126
|
nativeTokenUsdPrice;
|
|
106
127
|
nativeAmount = nativeAmount + BigInt(1);
|
|
128
|
+
const sourceAddress = ctx.universalSigner.account.address;
|
|
129
|
+
const sourceBalance = yield evmClient.publicClient.getBalance({
|
|
130
|
+
address: sourceAddress,
|
|
131
|
+
});
|
|
132
|
+
if (sourceBalance < nativeAmount) {
|
|
133
|
+
throw new Error(insufficientSourceBalanceMessage(chain, sourceBalance, nativeAmount));
|
|
134
|
+
}
|
|
107
135
|
const txHash = yield sendGatewayTxWithFallback(ctx, evmClient, lockerContract, req, ctx.universalSigner, nativeAmount);
|
|
108
136
|
return (0, viem_1.hexToBytes)(txHash);
|
|
109
137
|
}
|
|
@@ -130,12 +158,17 @@ req) {
|
|
|
130
158
|
const userPk = new web3_js_1.PublicKey(ctx.universalSigner.account.address);
|
|
131
159
|
const { feeVaultPda, protocolFeeLamports } = yield (0, svm_helpers_2.getSvmProtocolFee)(svmClient, programId);
|
|
132
160
|
const gasReq = (0, svm_helpers_1.buildSvmUniversalTxRequestFromReq)(req, userPk);
|
|
161
|
+
const requiredLamports = nativeAmount + protocolFeeLamports;
|
|
162
|
+
const sourceBalance = yield svmClient.getBalance(userPk.toBase58());
|
|
163
|
+
if (sourceBalance < requiredLamports) {
|
|
164
|
+
throw new Error(insufficientSourceBalanceMessage(chain, sourceBalance, requiredLamports));
|
|
165
|
+
}
|
|
133
166
|
try {
|
|
134
167
|
const txHash = yield svmClient.writeContract({
|
|
135
168
|
abi: abi_1.SVM_GATEWAY_IDL,
|
|
136
169
|
address: programId.toBase58(),
|
|
137
170
|
functionName: 'sendUniversalTx',
|
|
138
|
-
args: [gasReq,
|
|
171
|
+
args: [gasReq, requiredLamports],
|
|
139
172
|
signer: ctx.universalSigner,
|
|
140
173
|
accounts: {
|
|
141
174
|
config: configPda,
|
|
@@ -254,9 +254,10 @@ function waitForInboundPushTx(ctx_1, outboundExternalTxHash_1, sourceChain_1) {
|
|
|
254
254
|
// chain, treat as terminal-success; if it reverted, treat as
|
|
255
255
|
// terminal-failure. Cosmos-indexer lag stops blocking us here.
|
|
256
256
|
try {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
// Archive-fallback variant: a Push-leg receipt outside the prune
|
|
258
|
+
// window still resolves via the archive node. On chains without an
|
|
259
|
+
// archive endpoint this behaves as a plain prune-only lookup.
|
|
260
|
+
const receipt = yield ctx.pushClient.getTransactionReceiptWithArchiveFallback(pushTxHash);
|
|
260
261
|
if ((receipt === null || receipt === void 0 ? void 0 : receipt.status) === 'success') {
|
|
261
262
|
(0, context_1.printLog)(ctx, `[waitForInboundPushTx] Push RPC tiebreaker: ${pushTxHash} confirmed on chain (cosmos still status=${status}); treating as terminal-success`);
|
|
262
263
|
progressHook === null || progressHook === void 0 ? void 0 : progressHook({
|
|
@@ -9,12 +9,16 @@
|
|
|
9
9
|
import type { OutboundTxDetails } from '../orchestrator.types';
|
|
10
10
|
import type { ProgressEvent } from '../../progress-hook/progress-hook.types';
|
|
11
11
|
import { TransactionRoute } from '../route-detector';
|
|
12
|
+
export type WaitHookMetadata = {
|
|
13
|
+
pushTxHash?: string;
|
|
14
|
+
txHash?: string;
|
|
15
|
+
};
|
|
12
16
|
export type WaitHookSet = {
|
|
13
|
-
awaiting: (chain: string) => ProgressEvent;
|
|
14
|
-
polling: (chain: string, elapsedMs: number) => ProgressEvent;
|
|
17
|
+
awaiting: (chain: string, pushTxHash?: string) => ProgressEvent;
|
|
18
|
+
polling: (chain: string, elapsedMs: number, pushTxHash?: string) => ProgressEvent;
|
|
15
19
|
success: (details: OutboundTxDetails) => ProgressEvent;
|
|
16
|
-
timeout: (chain: string, elapsedMs: number) => ProgressEvent;
|
|
17
|
-
failed: (chain: string, errMsg: string) => ProgressEvent;
|
|
20
|
+
timeout: (chain: string, elapsedMs: number, pushTxHash?: string) => ProgressEvent;
|
|
21
|
+
failed: (chain: string, errMsg: string, metadata?: WaitHookMetadata) => ProgressEvent;
|
|
18
22
|
};
|
|
19
23
|
export declare function pickWaitHooks(route: TransactionRoute | string | undefined): WaitHookSet;
|
|
20
24
|
/** True when the hook set is the no-op placeholder (route has no spec'd
|
|
@@ -17,17 +17,17 @@ const route_detector_1 = require("../route-detector");
|
|
|
17
17
|
function pickWaitHooks(route) {
|
|
18
18
|
if (route === route_detector_1.TransactionRoute.UOA_TO_CEA) {
|
|
19
19
|
return {
|
|
20
|
-
awaiting: (chain) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_209_01](chain),
|
|
21
|
-
polling: (chain, elapsed) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_209_02](chain, elapsed),
|
|
20
|
+
awaiting: (chain, pushTxHash) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_209_01](chain, pushTxHash),
|
|
21
|
+
polling: (chain, elapsed, pushTxHash) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_209_02](chain, elapsed, pushTxHash),
|
|
22
22
|
success: (details) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_01](details),
|
|
23
|
-
timeout: (chain, elapsed) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_03](chain, elapsed),
|
|
24
|
-
failed: (chain, msg) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_02](chain, msg),
|
|
23
|
+
timeout: (chain, elapsed, pushTxHash) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_03](chain, elapsed, pushTxHash),
|
|
24
|
+
failed: (chain, msg, metadata) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_02](chain, msg, undefined, metadata === null || metadata === void 0 ? void 0 : metadata.pushTxHash, metadata === null || metadata === void 0 ? void 0 : metadata.txHash),
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
if (route === route_detector_1.TransactionRoute.CEA_TO_PUSH) {
|
|
28
28
|
return {
|
|
29
|
-
awaiting: (chain) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_309_01](chain),
|
|
30
|
-
polling: (chain, elapsed) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_309_02](chain, elapsed),
|
|
29
|
+
awaiting: (chain, pushTxHash) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_309_01](chain, pushTxHash),
|
|
30
|
+
polling: (chain, elapsed, pushTxHash) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_309_02](chain, elapsed, pushTxHash),
|
|
31
31
|
// For R3, the outbound-poll "success" is the source-chain CEA executing
|
|
32
32
|
// (309-03 INFO). Terminal 399-01 fires after the inbound-to-Push poll
|
|
33
33
|
// (handled by waitForInboundPushTx in response-builder).
|
|
@@ -35,8 +35,8 @@ function pickWaitHooks(route) {
|
|
|
35
35
|
// R3 outbound (source-chain CEA) failures share the 399-02/03 IDs with
|
|
36
36
|
// R3 inbound; pass phase='outbound' so the title reflects the source
|
|
37
37
|
// chain instead of "Push Chain Inbound …".
|
|
38
|
-
timeout: (chain, elapsed) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_03](chain, elapsed, 'outbound'),
|
|
39
|
-
failed: (chain, msg) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](msg, 'outbound', chain),
|
|
38
|
+
timeout: (chain, elapsed, pushTxHash) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_03](chain, elapsed, 'outbound', pushTxHash),
|
|
39
|
+
failed: (chain, msg, metadata) => progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](msg, 'outbound', chain, undefined, metadata === null || metadata === void 0 ? void 0 : metadata.pushTxHash, metadata === null || metadata === void 0 ? void 0 : metadata.txHash),
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
42
|
// Route 4 (CEA_TO_CEA) has no spec'd ID range yet; cascade hops and
|
|
@@ -16,6 +16,7 @@ const viem_1 = require("viem");
|
|
|
16
16
|
const chain_1 = require("../../constants/chain");
|
|
17
17
|
const enums_1 = require("../../constants/enums");
|
|
18
18
|
const progress_hook_types_1 = require("../../progress-hook/progress-hook.types");
|
|
19
|
+
const evm_client_1 = require("../../vm-client/evm-client");
|
|
19
20
|
const context_1 = require("./context");
|
|
20
21
|
const error_decoder_1 = require("./error-decoder");
|
|
21
22
|
const errors_1 = require("./errors");
|
|
@@ -69,6 +70,51 @@ function sendPushTx(ctx, execute, eventBuffer, transformFn) {
|
|
|
69
70
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
70
71
|
var _a, _b, _c;
|
|
71
72
|
if (Array.isArray(execute.data)) {
|
|
73
|
+
const calls = execute.data;
|
|
74
|
+
// Reject a zero `to` BEFORE route selection so behaviour is identical
|
|
75
|
+
// regardless of signer capability: ERC-7821 (the 7702 path) reinterprets
|
|
76
|
+
// `target == 0` as the account itself, whereas the legacy loop would send to
|
|
77
|
+
// the zero address. A zero target is almost always a bug — disallow it.
|
|
78
|
+
if (calls.some((c) => /^0x0{40}$/i.test(c.to))) {
|
|
79
|
+
throw new errors_1.PushChainExecutionError('A multicall entry has a zero `to` address. Use an explicit target ' +
|
|
80
|
+
'(the EIP-7702 executor reinterprets a zero target as the account itself).');
|
|
81
|
+
}
|
|
82
|
+
// Preferred path: execute the batch atomically in a single EIP-7702 type-4
|
|
83
|
+
// transaction. Requires (a) a deployed PushBatchExecutor on this chain and
|
|
84
|
+
// (b) a wallet that can sign a 7702 authorization. When either is missing we
|
|
85
|
+
// fall back to the legacy non-atomic per-call loop below.
|
|
86
|
+
const executor = (0, chain_1.getBatchExecutorAddress)(ctx.universalSigner.account.chain);
|
|
87
|
+
if (executor && ctx.universalSigner.signAuthorization) {
|
|
88
|
+
try {
|
|
89
|
+
(0, context_1.printLog)(ctx, `sendPushTx — executing ${calls.length} call(s) atomically via EIP-7702 (executor: ${executor})`);
|
|
90
|
+
const txHash = yield ctx.pushClient.sendBatch7702({
|
|
91
|
+
executor,
|
|
92
|
+
calls,
|
|
93
|
+
signer: ctx.universalSigner,
|
|
94
|
+
});
|
|
95
|
+
const txResponse = yield getIndexedPushTransaction(ctx, txHash, 'sendPushTx');
|
|
96
|
+
return yield transformFn(txResponse, eventBuffer);
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
// Only fall back when the wallet genuinely can't sign a 7702
|
|
100
|
+
// authorization. This is raised before any broadcast, so falling back
|
|
101
|
+
// to sequential execution cannot double-execute. Any other error
|
|
102
|
+
// (e.g. a real revert) must surface.
|
|
103
|
+
if (!(err instanceof evm_client_1.EIP7702NotSupportedError))
|
|
104
|
+
throw err;
|
|
105
|
+
(0, context_1.printLog)(ctx, `sendPushTx — wallet cannot sign EIP-7702 authorization; falling back to sequential execution`);
|
|
106
|
+
// eslint-disable-next-line no-console
|
|
107
|
+
console.warn('[push-chain] Wallet cannot produce an EIP-7702 authorization — batch ' +
|
|
108
|
+
'will execute as separate, non-atomic transactions (if one call reverts, ' +
|
|
109
|
+
'earlier calls remain committed).');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else if (!ctx.universalSigner.signAuthorization) {
|
|
113
|
+
// eslint-disable-next-line no-console
|
|
114
|
+
console.warn('[push-chain] Signer does not support EIP-7702 — batch will execute as ' +
|
|
115
|
+
'separate, non-atomic transactions (if one call reverts, earlier calls ' +
|
|
116
|
+
'remain committed).');
|
|
117
|
+
}
|
|
72
118
|
const PUSH_CHAIN_GAS_LIMIT = BigInt(500000);
|
|
73
119
|
const MAX_NONCE_RETRIES = 3;
|
|
74
120
|
let nonce = yield ctx.pushClient.publicClient.getTransactionCount({
|
|
@@ -76,7 +122,6 @@ function sendPushTx(ctx, execute, eventBuffer, transformFn) {
|
|
|
76
122
|
blockTag: 'pending',
|
|
77
123
|
});
|
|
78
124
|
let lastTxHash = '0x';
|
|
79
|
-
const calls = execute.data;
|
|
80
125
|
for (let i = 0; i < calls.length; i++) {
|
|
81
126
|
const call = calls[i];
|
|
82
127
|
let txSent = false;
|
|
@@ -142,7 +187,11 @@ function sendPushTx(ctx, execute, eventBuffer, transformFn) {
|
|
|
142
187
|
nonce++;
|
|
143
188
|
}
|
|
144
189
|
const txResponse = yield getIndexedPushTransaction(ctx, lastTxHash, 'sendPushTx');
|
|
145
|
-
|
|
190
|
+
// Sequential fallback: each call was a separate tx, so the batch is NOT
|
|
191
|
+
// atomic (an earlier call can be committed while a later one reverts).
|
|
192
|
+
const resp = yield transformFn(txResponse, eventBuffer);
|
|
193
|
+
resp.atomic = false;
|
|
194
|
+
return resp;
|
|
146
195
|
}
|
|
147
196
|
const txHash = yield ctx.pushClient.sendTransaction({
|
|
148
197
|
to: execute.to,
|
|
@@ -263,11 +312,12 @@ function sendUniversalTx(ctx, isUEADeployed, feeLockTxHash, universalPayload, ve
|
|
|
263
312
|
// wiring in `extractPcTxAndTransform` for the post-success `pcTx FAILED`
|
|
264
313
|
// path. Also feeds the structured `decodedError` payload through to the
|
|
265
314
|
// terminal hook (199-02 / 299-02 / 399-02 / 999-02).
|
|
266
|
-
|
|
315
|
+
const rawMessage = (_c = tx.rawLog) !== null && _c !== void 0 ? _c : '';
|
|
316
|
+
let publicMessage = (0, formatters_1.normalizePublicErrorMessage)(rawMessage);
|
|
267
317
|
let decodedForPayload;
|
|
268
|
-
const decoded = (0, error_decoder_1.decodeRevert)(
|
|
318
|
+
const decoded = (0, error_decoder_1.decodeRevert)(rawMessage);
|
|
269
319
|
if ((decoded === null || decoded === void 0 ? void 0 : decoded.kind) === 'custom') {
|
|
270
|
-
|
|
320
|
+
publicMessage = (0, error_decoder_1.formatDecodedRevertForUser)(decoded);
|
|
271
321
|
decodedForPayload = {
|
|
272
322
|
name: decoded.name,
|
|
273
323
|
hint: decoded.hint,
|
|
@@ -275,7 +325,7 @@ function sendUniversalTx(ctx, isUEADeployed, feeLockTxHash, universalPayload, ve
|
|
|
275
325
|
};
|
|
276
326
|
}
|
|
277
327
|
else if ((decoded === null || decoded === void 0 ? void 0 : decoded.kind) === 'string') {
|
|
278
|
-
|
|
328
|
+
publicMessage = (0, error_decoder_1.formatDecodedRevertForUser)(decoded);
|
|
279
329
|
decodedForPayload = {
|
|
280
330
|
decoded: decoded.decoded,
|
|
281
331
|
selector: decoded.selector,
|
|
@@ -290,12 +340,12 @@ function sendUniversalTx(ctx, isUEADeployed, feeLockTxHash, universalPayload, ve
|
|
|
290
340
|
`Block Height: ${tx.height}, TX Code: ${tx.code} (error)`,
|
|
291
341
|
`Gas Used: ${tx.gasUsed}, Gas Wanted: ${tx.gasWanted}`,
|
|
292
342
|
...(failedEthTxHashes.length > 0 ? [`Ethereum TX Hash(es): ${failedEthTxHashes.join(', ')}`] : []),
|
|
293
|
-
`Error: ${
|
|
343
|
+
`Error: ${publicMessage}`,
|
|
294
344
|
].join(' | ');
|
|
295
345
|
(0, context_1.printLog)(ctx, failureSummary);
|
|
296
346
|
// Throw a typed error so the orchestrator's outer catch can lift the
|
|
297
347
|
// structured `decodedError` straight onto the terminal-hook payload.
|
|
298
|
-
throw new errors_1.PushChainExecutionError(
|
|
348
|
+
throw new errors_1.PushChainExecutionError(publicMessage, {
|
|
299
349
|
decodedError: decodedForPayload,
|
|
300
350
|
});
|
|
301
351
|
}
|
|
@@ -335,8 +385,9 @@ function extractPcTxAndTransform(ctx, pushChainUniversalTx, gatewayTxHash, event
|
|
|
335
385
|
const failedPcTx = (lastPcTransaction === null || lastPcTransaction === void 0 ? void 0 : lastPcTransaction.status) === 'FAILED'
|
|
336
386
|
? lastPcTransaction
|
|
337
387
|
: pushChainUniversalTx.pcTx.find((pcTx) => pcTx.status === 'FAILED' && pcTx.errorMsg);
|
|
338
|
-
const
|
|
339
|
-
|
|
388
|
+
const rawFailedPcTxErrorMsg = (_b = failedPcTx === null || failedPcTx === void 0 ? void 0 : failedPcTx.errorMsg) !== null && _b !== void 0 ? _b : '';
|
|
389
|
+
let failedPcTxErrorMsg = rawFailedPcTxErrorMsg
|
|
390
|
+
? (0, formatters_1.normalizePublicErrorMessage)(rawFailedPcTxErrorMsg)
|
|
340
391
|
: '';
|
|
341
392
|
const errorDetails = failedPcTxErrorMsg ? `: ${failedPcTxErrorMsg}` : '';
|
|
342
393
|
// Decode known revert selectors and ABI-encoded `Error(string)` reverts
|
|
@@ -344,9 +395,10 @@ function extractPcTxAndTransform(ctx, pushChainUniversalTx, gatewayTxHash, event
|
|
|
344
395
|
// table can grow from real reverts.
|
|
345
396
|
let hint = '';
|
|
346
397
|
let decodedForPayload;
|
|
347
|
-
const decoded = (0, error_decoder_1.decodeRevert)(
|
|
398
|
+
const decoded = (0, error_decoder_1.decodeRevert)(rawFailedPcTxErrorMsg);
|
|
348
399
|
if ((decoded === null || decoded === void 0 ? void 0 : decoded.kind) === 'custom') {
|
|
349
|
-
|
|
400
|
+
failedPcTxErrorMsg = (0, error_decoder_1.formatDecodedRevertForUser)(decoded);
|
|
401
|
+
hint = '';
|
|
350
402
|
decodedForPayload = {
|
|
351
403
|
name: decoded.name,
|
|
352
404
|
hint: decoded.hint,
|
|
@@ -354,7 +406,8 @@ function extractPcTxAndTransform(ctx, pushChainUniversalTx, gatewayTxHash, event
|
|
|
354
406
|
};
|
|
355
407
|
}
|
|
356
408
|
else if ((decoded === null || decoded === void 0 ? void 0 : decoded.kind) === 'string') {
|
|
357
|
-
|
|
409
|
+
failedPcTxErrorMsg = (0, error_decoder_1.formatDecodedRevertForUser)(decoded);
|
|
410
|
+
hint = '';
|
|
358
411
|
decodedForPayload = {
|
|
359
412
|
decoded: decoded.decoded,
|
|
360
413
|
selector: decoded.selector,
|
|
@@ -363,11 +416,14 @@ function extractPcTxAndTransform(ctx, pushChainUniversalTx, gatewayTxHash, event
|
|
|
363
416
|
else if ((decoded === null || decoded === void 0 ? void 0 : decoded.kind) === 'unknown') {
|
|
364
417
|
(0, context_1.printLog)(ctx, `[error-decoder] unknown selector ${decoded.selector} — consider adding to KNOWN_ERROR_SELECTORS`);
|
|
365
418
|
}
|
|
366
|
-
const
|
|
419
|
+
const decodedErrorDetails = failedPcTxErrorMsg
|
|
420
|
+
? `: ${failedPcTxErrorMsg}`
|
|
421
|
+
: errorDetails;
|
|
422
|
+
const fullMessage = `Push Chain transaction failed for gateway tx: ${gatewayTxHash}${decodedErrorDetails}${hint}`;
|
|
367
423
|
// Live-emit 199-02 before throwing so the terminal failure hook reaches
|
|
368
424
|
// any caller-registered progress stream (parity with reconstructProgressEvents
|
|
369
425
|
// which emits 199-02 on replay).
|
|
370
|
-
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02, fullMessage, decodedForPayload);
|
|
426
|
+
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02, fullMessage, decodedForPayload, failedPcTx === null || failedPcTx === void 0 ? void 0 : failedPcTx.txHash);
|
|
371
427
|
throw new errors_1.PushChainExecutionError(fullMessage, {
|
|
372
428
|
gatewayTxHash,
|
|
373
429
|
decodedError: decodedForPayload,
|
|
@@ -687,12 +687,12 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
687
687
|
fanOut(event, registeredProgressHook, ctx.progressHook);
|
|
688
688
|
};
|
|
689
689
|
// Awaiting relay
|
|
690
|
-
emit(hooks.awaiting(targetChain));
|
|
690
|
+
emit(hooks.awaiting(targetChain, universalTxResponse.hash));
|
|
691
691
|
let lastEmittedStatus;
|
|
692
692
|
const outboundTranslator = (event) => {
|
|
693
693
|
if (event.status === 'polling' && lastEmittedStatus !== 'polling') {
|
|
694
694
|
lastEmittedStatus = 'polling';
|
|
695
|
-
emit(hooks.polling(targetChain, event.elapsed));
|
|
695
|
+
emit(hooks.polling(targetChain, event.elapsed, universalTxResponse.hash));
|
|
696
696
|
}
|
|
697
697
|
};
|
|
698
698
|
try {
|
|
@@ -721,7 +721,7 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
721
721
|
// otherwise time out after 300s.
|
|
722
722
|
if (route === route_detector_1.TransactionRoute.CEA_TO_PUSH &&
|
|
723
723
|
universalTxResponse._expectsInboundRoundTrip === true) {
|
|
724
|
-
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_310_01](targetChain));
|
|
724
|
+
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_310_01](targetChain, universalTxResponse.hash));
|
|
725
725
|
let inboundLastEmitted;
|
|
726
726
|
try {
|
|
727
727
|
const inbound = yield (0, inbound_tracker_1.waitForInboundPushTx)(ctx, outboundDetails.externalTxHash, targetChain, {
|
|
@@ -732,7 +732,7 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
732
732
|
if (event.status === 'polling' &&
|
|
733
733
|
inboundLastEmitted !== 'polling') {
|
|
734
734
|
inboundLastEmitted = 'polling';
|
|
735
|
-
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_310_02](targetChain, event.elapsedMs));
|
|
735
|
+
emit(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_310_02](targetChain, event.elapsedMs, universalTxResponse.hash));
|
|
736
736
|
}
|
|
737
737
|
},
|
|
738
738
|
});
|
|
@@ -743,7 +743,7 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
743
743
|
else {
|
|
744
744
|
// status === 'failed' (terminal failure status from chain)
|
|
745
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));
|
|
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
747
|
baseReceipt = Object.assign(Object.assign({}, baseReceipt), { pushInboundUtxId: inbound.childUtxId, pushInboundTxHash: inbound.pushTxHash || undefined, externalStatus: 'failed', externalError: failMsg });
|
|
748
748
|
}
|
|
749
749
|
}
|
|
@@ -755,8 +755,8 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
755
755
|
// Annotate receipt for inbound-leg outcome too.
|
|
756
756
|
baseReceipt = Object.assign(Object.assign({}, baseReceipt), { externalStatus: isTimeout ? 'timeout' : 'failed', externalError: errMsg });
|
|
757
757
|
emit(isTimeout
|
|
758
|
-
? progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_03](targetChain, inboundTimeoutMs, 'inbound')
|
|
759
|
-
: progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](errMsg, 'inbound', targetChain));
|
|
758
|
+
? progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_03](targetChain, inboundTimeoutMs, 'inbound', universalTxResponse.hash)
|
|
759
|
+
: progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](errMsg, 'inbound', targetChain, undefined, universalTxResponse.hash));
|
|
760
760
|
callbacks.printLog(`[wait] R3 inbound tracking failed: ${errMsg}`);
|
|
761
761
|
}
|
|
762
762
|
}
|
|
@@ -764,15 +764,6 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
764
764
|
catch (error) {
|
|
765
765
|
const errMsg = error instanceof Error ? error.message : String(error);
|
|
766
766
|
const isTimeout = error instanceof outbound_sync_1.OutboundTimeoutError;
|
|
767
|
-
emit(isTimeout
|
|
768
|
-
? hooks.timeout(targetChain, outboundTimeoutMs)
|
|
769
|
-
: hooks.failed(targetChain, errMsg));
|
|
770
|
-
// Annotate the receipt so callers can distinguish external-leg
|
|
771
|
-
// outcomes without sniffing errMsg. Push Chain leg still succeeded
|
|
772
|
-
// (status stays 1); inspect `externalStatus` / `externalError` for
|
|
773
|
-
// the external/inbound leg outcome. On a reverted outbound the
|
|
774
|
-
// observed tx hash is carried by OutboundFailedError — expose it
|
|
775
|
-
// as externalTxHash so consumers can link to the explorer.
|
|
776
767
|
const failedExternalTxHash = error instanceof outbound_sync_1.OutboundFailedError ? error.externalTxHash : undefined;
|
|
777
768
|
// Normalize to chain-native display form for SVM (base58); EVM hex
|
|
778
769
|
// passes through unchanged. `OutboundFailedError.destinationChain`
|
|
@@ -782,6 +773,18 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
782
773
|
? (_h = (0, helpers_1.chainFromNamespace)(error.destinationChain)) !== null && _h !== void 0 ? _h : undefined
|
|
783
774
|
: undefined;
|
|
784
775
|
const failedExternalTxHashDisplay = (_j = (0, helpers_1.toExternalTxHashDisplay)(failedChain, failedExternalTxHash)) !== null && _j !== void 0 ? _j : failedExternalTxHash;
|
|
776
|
+
emit(isTimeout
|
|
777
|
+
? hooks.timeout(targetChain, outboundTimeoutMs, universalTxResponse.hash)
|
|
778
|
+
: hooks.failed(targetChain, errMsg, {
|
|
779
|
+
pushTxHash: universalTxResponse.hash,
|
|
780
|
+
txHash: failedExternalTxHashDisplay,
|
|
781
|
+
}));
|
|
782
|
+
// Annotate the receipt so callers can distinguish external-leg
|
|
783
|
+
// outcomes without sniffing errMsg. Push Chain leg still succeeded
|
|
784
|
+
// (status stays 1); inspect `externalStatus` / `externalError` for
|
|
785
|
+
// the external/inbound leg outcome. On a reverted outbound the
|
|
786
|
+
// observed tx hash is carried by OutboundFailedError — expose it
|
|
787
|
+
// as externalTxHash so consumers can link to the explorer.
|
|
785
788
|
baseReceipt = Object.assign(Object.assign(Object.assign({}, baseReceipt), { externalStatus: isTimeout ? 'timeout' : 'failed', externalError: errMsg }), (failedExternalTxHashDisplay
|
|
786
789
|
? { externalTxHash: failedExternalTxHashDisplay }
|
|
787
790
|
: {}));
|
|
@@ -825,6 +828,12 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
825
828
|
// 7. Metadata
|
|
826
829
|
type,
|
|
827
830
|
typeVerbose,
|
|
831
|
+
// Atomic by default — a single tx, an EIP-7702 batch, and a UEA multicall
|
|
832
|
+
// are all all-or-nothing. Only the native sequential fallback loop overrides
|
|
833
|
+
// this to `false` (see sendPushTx in push-chain-tx.ts). Historical lookups
|
|
834
|
+
// via trackTransaction also keep the default, since the past execution mode
|
|
835
|
+
// isn't always recoverable.
|
|
836
|
+
atomic: true,
|
|
828
837
|
signature,
|
|
829
838
|
// 8. Raw Universal Fields
|
|
830
839
|
raw: rawTransactionData,
|
|
@@ -124,7 +124,7 @@ function reconstructProgressEvents(universalTxResponse, universalTxData) {
|
|
|
124
124
|
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_03_04](universalTxResponse.gasLimit, BigInt(0)));
|
|
125
125
|
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_107]());
|
|
126
126
|
if (isFailed) {
|
|
127
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02](errorMsg));
|
|
127
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02](errorMsg, undefined, universalTxResponse.hash));
|
|
128
128
|
}
|
|
129
129
|
else {
|
|
130
130
|
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_01]([universalTxResponse]));
|
|
@@ -161,7 +161,7 @@ function reconstructR2(universalTxResponse, universalTxData, isFailed, errorMsg)
|
|
|
161
161
|
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_204_03]());
|
|
162
162
|
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_207](targetChain));
|
|
163
163
|
if (isFailed) {
|
|
164
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_02](errorMsg));
|
|
164
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_02](targetChain, errorMsg, undefined, universalTxResponse.hash));
|
|
165
165
|
}
|
|
166
166
|
return events;
|
|
167
167
|
}
|
|
@@ -187,7 +187,7 @@ function reconstructR3(universalTxResponse, universalTxData, isFailed, errorMsg)
|
|
|
187
187
|
if (isFailed) {
|
|
188
188
|
// Reconstructed Push-chain-tx failure — phase='push' so the title reads
|
|
189
189
|
// "Push Chain Tx Failed" rather than the inbound copy.
|
|
190
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](errorMsg, 'push'));
|
|
190
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02](errorMsg, 'push', undefined, undefined, undefined, universalTxResponse.hash));
|
|
191
191
|
}
|
|
192
192
|
return events;
|
|
193
193
|
}
|
|
@@ -267,6 +267,7 @@ function decodeR3MergedInnerCount(outboundPayload) {
|
|
|
267
267
|
return 0;
|
|
268
268
|
}
|
|
269
269
|
function reconstructMultichain(universalTxResponse, universalTxData, isFailed, errorMsg) {
|
|
270
|
+
var _a, _b, _c, _d, _e;
|
|
270
271
|
const events = [];
|
|
271
272
|
const outbounds = universalTxData.outboundTx;
|
|
272
273
|
// Merged-R1 recovery: each R3 outbound's payload embeds the
|
|
@@ -343,14 +344,18 @@ function reconstructMultichain(universalTxResponse, universalTxData, isFailed, e
|
|
|
343
344
|
failureMsg = legError;
|
|
344
345
|
}
|
|
345
346
|
});
|
|
347
|
+
const finalObservedTxHash = (_c = (_b = (_a = [...outbounds].reverse().find((ob) => { var _a; return (_a = ob.observedTx) === null || _a === void 0 ? void 0 : _a.txHash; })) === null || _a === void 0 ? void 0 : _a.observedTx) === null || _b === void 0 ? void 0 : _b.txHash) !== null && _c !== void 0 ? _c : universalTxResponse.hash;
|
|
348
|
+
const failedObservedTxHash = failedAt !== null
|
|
349
|
+
? (_e = (_d = outbounds[failedAt - 1]) === null || _d === void 0 ? void 0 : _d.observedTx) === null || _e === void 0 ? void 0 : _e.txHash
|
|
350
|
+
: undefined;
|
|
346
351
|
if (failedAt !== null) {
|
|
347
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_999_02](failedAt, hopCount, failureMsg));
|
|
352
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_999_02](failedAt, hopCount, failureMsg, failedObservedTxHash, universalTxResponse.hash));
|
|
348
353
|
}
|
|
349
354
|
else if (isFailed) {
|
|
350
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_999_02](hopCount, hopCount, errorMsg));
|
|
355
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_999_02](hopCount, hopCount, errorMsg, undefined, universalTxResponse.hash));
|
|
351
356
|
}
|
|
352
357
|
else {
|
|
353
|
-
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_999_01](hopCount));
|
|
358
|
+
events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_999_01](hopCount, finalObservedTxHash));
|
|
354
359
|
}
|
|
355
360
|
return events;
|
|
356
361
|
}
|