@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
|
@@ -10,7 +10,6 @@ exports.PushChainExecutionError = void 0;
|
|
|
10
10
|
exports.sendPushTx = sendPushTx;
|
|
11
11
|
exports.sendUniversalTx = sendUniversalTx;
|
|
12
12
|
exports.extractPcTxAndTransform = extractPcTxAndTransform;
|
|
13
|
-
const tslib_1 = require("tslib");
|
|
14
13
|
const bs58_1 = require("../../internal/bs58");
|
|
15
14
|
const viem_1 = require("viem");
|
|
16
15
|
const chain_1 = require("../../constants/chain");
|
|
@@ -25,36 +24,34 @@ const formatters_1 = require("../../formatters");
|
|
|
25
24
|
const PUSH_TX_INDEX_TIMEOUT_MS = 30000;
|
|
26
25
|
const PUSH_TX_INDEX_POLL_MS = 1000;
|
|
27
26
|
const TX_NOT_INDEXED_RE = /not found|TransactionNotFound|TransactionReceiptNotFound|could not be found|No transaction found/i;
|
|
28
|
-
function getIndexedPushTransaction(ctx, txHash, label) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
receiptWaited = true;
|
|
41
|
-
}
|
|
42
|
-
return yield ctx.pushClient.getTransaction(txHash);
|
|
27
|
+
async function getIndexedPushTransaction(ctx, txHash, label) {
|
|
28
|
+
const startedAt = Date.now();
|
|
29
|
+
let receiptWaited = false;
|
|
30
|
+
let retryLogged = false;
|
|
31
|
+
// eslint-disable-next-line no-constant-condition
|
|
32
|
+
while (true) {
|
|
33
|
+
try {
|
|
34
|
+
if (!receiptWaited) {
|
|
35
|
+
await ctx.pushClient.publicClient.waitForTransactionReceipt({
|
|
36
|
+
hash: txHash,
|
|
37
|
+
});
|
|
38
|
+
receiptWaited = true;
|
|
43
39
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
(0, context_1.printLog)(ctx, `${label} — Push tx ${txHash} has a receipt but is not indexed yet; retrying transaction lookup`);
|
|
52
|
-
retryLogged = true;
|
|
53
|
-
}
|
|
54
|
-
yield new Promise((r) => setTimeout(r, PUSH_TX_INDEX_POLL_MS));
|
|
40
|
+
return await ctx.pushClient.getTransaction(txHash);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
const msg = err?.shortMessage || err?.message || String(err);
|
|
44
|
+
const retryable = TX_NOT_INDEXED_RE.test(msg);
|
|
45
|
+
if (!retryable || Date.now() - startedAt >= PUSH_TX_INDEX_TIMEOUT_MS) {
|
|
46
|
+
throw err;
|
|
55
47
|
}
|
|
48
|
+
if (!retryLogged) {
|
|
49
|
+
(0, context_1.printLog)(ctx, `${label} — Push tx ${txHash} has a receipt but is not indexed yet; retrying transaction lookup`);
|
|
50
|
+
retryLogged = true;
|
|
51
|
+
}
|
|
52
|
+
await new Promise((r) => setTimeout(r, PUSH_TX_INDEX_POLL_MS));
|
|
56
53
|
}
|
|
57
|
-
}
|
|
54
|
+
}
|
|
58
55
|
}
|
|
59
56
|
// ============================================================================
|
|
60
57
|
// sendPushTx
|
|
@@ -66,140 +63,137 @@ function getIndexedPushTransaction(ctx, txHash, label) {
|
|
|
66
63
|
* For multicall arrays: executes each call as a separate transaction with
|
|
67
64
|
* local nonce management and per-tx receipt confirmation.
|
|
68
65
|
*/
|
|
69
|
-
function sendPushTx(ctx, execute, eventBuffer, transformFn) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
66
|
+
async function sendPushTx(ctx, execute, eventBuffer, transformFn) {
|
|
67
|
+
if (Array.isArray(execute.data)) {
|
|
68
|
+
const calls = execute.data;
|
|
69
|
+
// Reject a zero `to` BEFORE route selection so behaviour is identical
|
|
70
|
+
// regardless of signer capability: ERC-7821 (the 7702 path) reinterprets
|
|
71
|
+
// `target == 0` as the account itself, whereas the legacy loop would send to
|
|
72
|
+
// the zero address. A zero target is almost always a bug — disallow it.
|
|
73
|
+
if (calls.some((c) => /^0x0{40}$/i.test(c.to))) {
|
|
74
|
+
throw new errors_1.PushChainExecutionError('A multicall entry has a zero `to` address. Use an explicit target ' +
|
|
75
|
+
'(the EIP-7702 executor reinterprets a zero target as the account itself).');
|
|
76
|
+
}
|
|
77
|
+
// Preferred path: execute the batch atomically in a single EIP-7702 type-4
|
|
78
|
+
// transaction. Requires (a) a deployed PushBatchExecutor on this chain and
|
|
79
|
+
// (b) a wallet that can sign a 7702 authorization. When either is missing we
|
|
80
|
+
// fall back to the legacy non-atomic per-call loop below.
|
|
81
|
+
const executor = (0, chain_1.getBatchExecutorAddress)(ctx.universalSigner.account.chain);
|
|
82
|
+
if (executor && ctx.universalSigner.signAuthorization) {
|
|
83
|
+
try {
|
|
84
|
+
(0, context_1.printLog)(ctx, `sendPushTx — executing ${calls.length} call(s) atomically via EIP-7702 (executor: ${executor})`);
|
|
85
|
+
const txHash = await ctx.pushClient.sendBatch7702({
|
|
86
|
+
executor,
|
|
87
|
+
calls,
|
|
88
|
+
signer: ctx.universalSigner,
|
|
89
|
+
});
|
|
90
|
+
const txResponse = await getIndexedPushTransaction(ctx, txHash, 'sendPushTx');
|
|
91
|
+
return await transformFn(txResponse, eventBuffer);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
// Only fall back when the wallet genuinely can't sign a 7702
|
|
95
|
+
// authorization. This is raised before any broadcast, so falling back
|
|
96
|
+
// to sequential execution cannot double-execute. Any other error
|
|
97
|
+
// (e.g. a real revert) must surface.
|
|
98
|
+
if (!(err instanceof evm_client_1.EIP7702NotSupportedError))
|
|
99
|
+
throw err;
|
|
100
|
+
(0, context_1.printLog)(ctx, `sendPushTx — wallet cannot sign EIP-7702 authorization; falling back to sequential execution`);
|
|
101
|
+
// eslint-disable-next-line no-console
|
|
102
|
+
console.warn('[push-chain] Wallet cannot produce an EIP-7702 authorization — batch ' +
|
|
103
|
+
'will execute as separate, non-atomic transactions (if one call reverts, ' +
|
|
104
|
+
'earlier calls remain committed).');
|
|
81
105
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
106
|
+
}
|
|
107
|
+
else if (!ctx.universalSigner.signAuthorization) {
|
|
108
|
+
// eslint-disable-next-line no-console
|
|
109
|
+
console.warn('[push-chain] Signer does not support EIP-7702 — batch will execute as ' +
|
|
110
|
+
'separate, non-atomic transactions (if one call reverts, earlier calls ' +
|
|
111
|
+
'remain committed).');
|
|
112
|
+
}
|
|
113
|
+
const MAX_NONCE_RETRIES = 3;
|
|
114
|
+
let nonce = await ctx.pushClient.publicClient.getTransactionCount({
|
|
115
|
+
address: ctx.universalSigner.account.address,
|
|
116
|
+
blockTag: 'pending',
|
|
117
|
+
});
|
|
118
|
+
let lastTxHash = '0x';
|
|
119
|
+
for (let i = 0; i < calls.length; i++) {
|
|
120
|
+
const call = calls[i];
|
|
121
|
+
let txSent = false;
|
|
122
|
+
for (let retry = 0; retry < MAX_NONCE_RETRIES && !txSent; retry++) {
|
|
88
123
|
try {
|
|
89
|
-
(0, context_1.printLog)(ctx, `sendPushTx — executing ${calls.length} call
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
124
|
+
(0, context_1.printLog)(ctx, `sendPushTx — executing multicall operation ${i + 1}/${calls.length} to: ${call.to} (nonce: ${nonce})`);
|
|
125
|
+
lastTxHash = await ctx.pushClient.sendTransaction({
|
|
126
|
+
to: call.to,
|
|
127
|
+
data: (call.data || '0x'),
|
|
128
|
+
value: call.value,
|
|
93
129
|
signer: ctx.universalSigner,
|
|
130
|
+
nonce,
|
|
94
131
|
});
|
|
95
|
-
|
|
96
|
-
return yield transformFn(txResponse, eventBuffer);
|
|
132
|
+
txSent = true;
|
|
97
133
|
}
|
|
98
134
|
catch (err) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
135
|
+
const msg = err?.message || err?.details || '';
|
|
136
|
+
if (msg.includes('invalid nonce') || msg.includes('invalid sequence')) {
|
|
137
|
+
(0, context_1.printLog)(ctx, `sendPushTx — nonce mismatch on operation ${i + 1}/${calls.length} (retry ${retry + 1}/${MAX_NONCE_RETRIES}), re-fetching nonce`);
|
|
138
|
+
nonce = await ctx.pushClient.publicClient.getTransactionCount({
|
|
139
|
+
address: ctx.universalSigner.account.address,
|
|
140
|
+
blockTag: 'pending',
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
104
144
|
throw err;
|
|
105
|
-
|
|
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).');
|
|
145
|
+
}
|
|
110
146
|
}
|
|
111
147
|
}
|
|
112
|
-
|
|
113
|
-
|
|
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).');
|
|
148
|
+
if (!txSent) {
|
|
149
|
+
throw new Error(`sendPushTx — multicall operation ${i + 1}/${calls.length} failed after ${MAX_NONCE_RETRIES} nonce retries`);
|
|
117
150
|
}
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
address: ctx.universalSigner.account.address,
|
|
121
|
-
blockTag: 'pending',
|
|
151
|
+
const receipt = await ctx.pushClient.publicClient.waitForTransactionReceipt({
|
|
152
|
+
hash: lastTxHash,
|
|
122
153
|
});
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
signer: ctx.universalSigner,
|
|
135
|
-
nonce,
|
|
136
|
-
});
|
|
137
|
-
txSent = true;
|
|
138
|
-
}
|
|
139
|
-
catch (err) {
|
|
140
|
-
const msg = (err === null || err === void 0 ? void 0 : err.message) || (err === null || err === void 0 ? void 0 : err.details) || '';
|
|
141
|
-
if (msg.includes('invalid nonce') || msg.includes('invalid sequence')) {
|
|
142
|
-
(0, context_1.printLog)(ctx, `sendPushTx — nonce mismatch on operation ${i + 1}/${calls.length} (retry ${retry + 1}/${MAX_NONCE_RETRIES}), re-fetching nonce`);
|
|
143
|
-
nonce = yield ctx.pushClient.publicClient.getTransactionCount({
|
|
144
|
-
address: ctx.universalSigner.account.address,
|
|
145
|
-
blockTag: 'pending',
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
throw err;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
if (!txSent) {
|
|
154
|
-
throw new Error(`sendPushTx — multicall operation ${i + 1}/${calls.length} failed after ${MAX_NONCE_RETRIES} nonce retries`);
|
|
154
|
+
if (receipt.status === 'reverted') {
|
|
155
|
+
// Simulate the failed call to extract the revert reason
|
|
156
|
+
let revertReason = 'unknown';
|
|
157
|
+
try {
|
|
158
|
+
await ctx.pushClient.publicClient.call({
|
|
159
|
+
to: call.to,
|
|
160
|
+
data: (call.data || '0x'),
|
|
161
|
+
value: call.value,
|
|
162
|
+
account: ctx.universalSigner.account.address,
|
|
163
|
+
blockNumber: receipt.blockNumber,
|
|
164
|
+
});
|
|
155
165
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
//
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
to: call.to,
|
|
165
|
-
data: (call.data || '0x'),
|
|
166
|
-
value: call.value,
|
|
167
|
-
account: ctx.universalSigner.account.address,
|
|
168
|
-
blockNumber: receipt.blockNumber,
|
|
169
|
-
});
|
|
166
|
+
catch (simErr) {
|
|
167
|
+
// viem decodes common revert reasons into shortMessage
|
|
168
|
+
revertReason =
|
|
169
|
+
simErr?.shortMessage || simErr?.cause?.reason || simErr?.cause?.message || simErr?.message || String(simErr);
|
|
170
|
+
// Also log the raw revert data if available
|
|
171
|
+
const revertData = simErr?.cause?.data || simErr?.data;
|
|
172
|
+
if (revertData) {
|
|
173
|
+
revertReason += ` [data: ${revertData}]`;
|
|
170
174
|
}
|
|
171
|
-
catch (simErr) {
|
|
172
|
-
// viem decodes common revert reasons into shortMessage
|
|
173
|
-
revertReason =
|
|
174
|
-
(simErr === null || simErr === void 0 ? void 0 : simErr.shortMessage) || ((_a = simErr === null || simErr === void 0 ? void 0 : simErr.cause) === null || _a === void 0 ? void 0 : _a.reason) || ((_b = simErr === null || simErr === void 0 ? void 0 : simErr.cause) === null || _b === void 0 ? void 0 : _b.message) || (simErr === null || simErr === void 0 ? void 0 : simErr.message) || String(simErr);
|
|
175
|
-
// Also log the raw revert data if available
|
|
176
|
-
const revertData = ((_c = simErr === null || simErr === void 0 ? void 0 : simErr.cause) === null || _c === void 0 ? void 0 : _c.data) || (simErr === null || simErr === void 0 ? void 0 : simErr.data);
|
|
177
|
-
if (revertData) {
|
|
178
|
-
revertReason += ` [data: ${revertData}]`;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
(0, context_1.printLog)(ctx, `sendPushTx — multicall operation ${i + 1}/${calls.length} reverted (to: ${call.to}, txHash: ${lastTxHash}, revertReason: ${revertReason})`);
|
|
182
|
-
throw new Error(`sendPushTx — multicall operation ${i + 1}/${calls.length} reverted (to: ${call.to}, txHash: ${lastTxHash}, revertReason: ${revertReason})`);
|
|
183
175
|
}
|
|
184
|
-
(0, context_1.printLog)(ctx, `sendPushTx — operation ${i + 1}/${calls.length}
|
|
185
|
-
|
|
176
|
+
(0, context_1.printLog)(ctx, `sendPushTx — multicall operation ${i + 1}/${calls.length} reverted (to: ${call.to}, txHash: ${lastTxHash}, revertReason: ${revertReason})`);
|
|
177
|
+
throw new Error(`sendPushTx — multicall operation ${i + 1}/${calls.length} reverted (to: ${call.to}, txHash: ${lastTxHash}, revertReason: ${revertReason})`);
|
|
186
178
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
// atomic (an earlier call can be committed while a later one reverts).
|
|
190
|
-
const resp = yield transformFn(txResponse, eventBuffer);
|
|
191
|
-
resp.atomic = false;
|
|
192
|
-
return resp;
|
|
179
|
+
(0, context_1.printLog)(ctx, `sendPushTx — operation ${i + 1}/${calls.length} confirmed in block ${receipt.blockNumber}`);
|
|
180
|
+
nonce++;
|
|
193
181
|
}
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
182
|
+
const txResponse = await getIndexedPushTransaction(ctx, lastTxHash, 'sendPushTx');
|
|
183
|
+
// Sequential fallback: each call was a separate tx, so the batch is NOT
|
|
184
|
+
// atomic (an earlier call can be committed while a later one reverts).
|
|
185
|
+
const resp = await transformFn(txResponse, eventBuffer);
|
|
186
|
+
resp.atomic = false;
|
|
187
|
+
return resp;
|
|
188
|
+
}
|
|
189
|
+
const txHash = await ctx.pushClient.sendTransaction({
|
|
190
|
+
to: execute.to,
|
|
191
|
+
data: (execute.data || '0x'),
|
|
192
|
+
value: execute.value,
|
|
193
|
+
signer: ctx.universalSigner,
|
|
202
194
|
});
|
|
195
|
+
const txResponse = await getIndexedPushTransaction(ctx, txHash, 'sendPushTx');
|
|
196
|
+
return await transformFn(txResponse, eventBuffer);
|
|
203
197
|
}
|
|
204
198
|
// ============================================================================
|
|
205
199
|
// sendUniversalTx
|
|
@@ -228,139 +222,138 @@ const SEQ_RETRY_BASE_DELAY_MS = 400;
|
|
|
228
222
|
* `InvalidEVMSignature()` selector. Each retry calls `resignFn` to obtain
|
|
229
223
|
* a payload re-signed against the UEA's current on-chain nonce.
|
|
230
224
|
*/
|
|
231
|
-
function sendUniversalTx(ctx, isUEADeployed, feeLockTxHash, universalPayload, verificationData, eventBuffer, transformFn, resignFn) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
? address
|
|
241
|
-
:
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
if (COSMOS_SEQUENCE_MISMATCH_RE.test(msg) &&
|
|
268
|
-
seqRetryCount < MAX_SEQ_RETRIES) {
|
|
269
|
-
seqRetryCount++;
|
|
270
|
-
const delay = Math.round(SEQ_RETRY_BASE_DELAY_MS * seqRetryCount * (1 + Math.random() * 0.2));
|
|
271
|
-
(0, context_1.printLog)(ctx, `sendUniversalTx — Cosmos sequence mismatch on broadcast (retry ${seqRetryCount}/${MAX_SEQ_RETRIES}), sleeping ${delay}ms: ${msg}`);
|
|
272
|
-
yield new Promise((r) => setTimeout(r, delay));
|
|
273
|
-
attempt--; // don't consume EVM-signature retry budget
|
|
274
|
-
continue;
|
|
275
|
-
}
|
|
276
|
-
throw err;
|
|
277
|
-
}
|
|
278
|
-
if (tx.code === 0)
|
|
279
|
-
break;
|
|
280
|
-
// Cosmos sequence race: returned via tx.rawLog rather than thrown
|
|
281
|
-
const isSeqMismatch = typeof tx.rawLog === 'string' &&
|
|
282
|
-
COSMOS_SEQUENCE_MISMATCH_RE.test(tx.rawLog);
|
|
283
|
-
if (isSeqMismatch && seqRetryCount < MAX_SEQ_RETRIES) {
|
|
225
|
+
async function sendUniversalTx(ctx, isUEADeployed, feeLockTxHash, universalPayload, verificationData, eventBuffer, transformFn, resignFn) {
|
|
226
|
+
const { chain, address } = ctx.universalSigner.account;
|
|
227
|
+
const { vm, chainId } = chain_1.CHAIN_INFO[chain];
|
|
228
|
+
const universalAccountId = {
|
|
229
|
+
chainNamespace: chain_1.VM_NAMESPACE[vm],
|
|
230
|
+
chainId: chainId,
|
|
231
|
+
owner: vm === enums_1.VM.EVM
|
|
232
|
+
? address
|
|
233
|
+
: vm === enums_1.VM.SVM
|
|
234
|
+
? (0, viem_1.bytesToHex)(new Uint8Array(bs58_1.bs58.decode(address)))
|
|
235
|
+
: address,
|
|
236
|
+
};
|
|
237
|
+
const { cosmosAddress: signer } = ctx.pushClient.getSignerAddress();
|
|
238
|
+
let currentPayload = universalPayload;
|
|
239
|
+
let currentVerificationData = verificationData;
|
|
240
|
+
let tx;
|
|
241
|
+
let seqRetryCount = 0;
|
|
242
|
+
for (let attempt = 0; attempt <= MAX_SIG_RETRIES; attempt++) {
|
|
243
|
+
const msgs = [];
|
|
244
|
+
if (currentPayload && currentVerificationData) {
|
|
245
|
+
msgs.push(ctx.pushClient.createMsgExecutePayload({
|
|
246
|
+
signer,
|
|
247
|
+
universalAccountId,
|
|
248
|
+
universalPayload: currentPayload,
|
|
249
|
+
verificationData: currentVerificationData,
|
|
250
|
+
}));
|
|
251
|
+
}
|
|
252
|
+
const txBody = await ctx.pushClient.createCosmosTxBody(msgs);
|
|
253
|
+
const txRaw = await ctx.pushClient.signCosmosTx(txBody);
|
|
254
|
+
try {
|
|
255
|
+
tx = await ctx.pushClient.broadcastCosmosTx(txRaw);
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
const msg = err?.message || String(err);
|
|
259
|
+
if (COSMOS_SEQUENCE_MISMATCH_RE.test(msg) &&
|
|
260
|
+
seqRetryCount < MAX_SEQ_RETRIES) {
|
|
284
261
|
seqRetryCount++;
|
|
285
262
|
const delay = Math.round(SEQ_RETRY_BASE_DELAY_MS * seqRetryCount * (1 + Math.random() * 0.2));
|
|
286
|
-
(0, context_1.printLog)(ctx, `sendUniversalTx — Cosmos sequence mismatch
|
|
287
|
-
|
|
263
|
+
(0, context_1.printLog)(ctx, `sendUniversalTx — Cosmos sequence mismatch on broadcast (retry ${seqRetryCount}/${MAX_SEQ_RETRIES}), sleeping ${delay}ms: ${msg}`);
|
|
264
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
288
265
|
attempt--; // don't consume EVM-signature retry budget
|
|
289
266
|
continue;
|
|
290
267
|
}
|
|
291
|
-
|
|
292
|
-
// tx inclusion. Re-sign with the fresh nonce and rebroadcast.
|
|
293
|
-
const isSigMismatch = typeof tx.rawLog === 'string' &&
|
|
294
|
-
tx.rawLog.includes(INVALID_EVM_SIGNATURE_SELECTOR);
|
|
295
|
-
if (attempt < MAX_SIG_RETRIES && isSigMismatch && resignFn) {
|
|
296
|
-
(0, context_1.printLog)(ctx, `sendUniversalTx — InvalidEVMSignature on attempt ${attempt + 1} (${tx.rawLog}); re-signing with fresh UEA nonce (retry ${attempt + 1}/${MAX_SIG_RETRIES})`);
|
|
297
|
-
const fresh = yield resignFn();
|
|
298
|
-
currentPayload = fresh.universalPayload;
|
|
299
|
-
currentVerificationData = fresh.verificationData;
|
|
300
|
-
continue;
|
|
301
|
-
}
|
|
302
|
-
// Terminal failure
|
|
303
|
-
const failedEthTxHashes = (_b = (_a = tx.events) === null || _a === void 0 ? void 0 : _a.filter((e) => e.type === 'ethereum_tx').flatMap((e) => {
|
|
304
|
-
var _a;
|
|
305
|
-
return (_a = e.attributes) === null || _a === void 0 ? void 0 : _a.filter((attr) => attr.key === 'ethereumTxHash').map((attr) => attr.value);
|
|
306
|
-
})) !== null && _b !== void 0 ? _b : [];
|
|
307
|
-
// Decode known revert selectors (e.g. `ret 0xacfdb444`) from the cosmos
|
|
308
|
-
// rawLog so the consumer-facing error AND the diagnostic failureSummary
|
|
309
|
-
// log carry an actionable hint instead of raw 4-byte hex. Mirrors the
|
|
310
|
-
// wiring in `extractPcTxAndTransform` for the post-success `pcTx FAILED`
|
|
311
|
-
// path. Also feeds the structured `decodedError` payload through to the
|
|
312
|
-
// terminal hook (199-02 / 299-02 / 399-02 / 999-02).
|
|
313
|
-
const rawMessage = (_c = tx.rawLog) !== null && _c !== void 0 ? _c : '';
|
|
314
|
-
let publicMessage = (0, formatters_1.normalizePublicErrorMessage)(rawMessage);
|
|
315
|
-
let decodedForPayload;
|
|
316
|
-
const decoded = (0, error_decoder_1.decodeRevert)(rawMessage);
|
|
317
|
-
if ((decoded === null || decoded === void 0 ? void 0 : decoded.kind) === 'custom') {
|
|
318
|
-
publicMessage = (0, error_decoder_1.formatDecodedRevertForUser)(decoded);
|
|
319
|
-
decodedForPayload = {
|
|
320
|
-
name: decoded.name,
|
|
321
|
-
hint: decoded.hint,
|
|
322
|
-
selector: decoded.selector,
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
else if ((decoded === null || decoded === void 0 ? void 0 : decoded.kind) === 'string') {
|
|
326
|
-
publicMessage = (0, error_decoder_1.formatDecodedRevertForUser)(decoded);
|
|
327
|
-
decodedForPayload = {
|
|
328
|
-
decoded: decoded.decoded,
|
|
329
|
-
selector: decoded.selector,
|
|
330
|
-
};
|
|
331
|
-
}
|
|
332
|
-
else if ((decoded === null || decoded === void 0 ? void 0 : decoded.kind) === 'unknown') {
|
|
333
|
-
(0, context_1.printLog)(ctx, `[error-decoder] unknown selector ${decoded.selector} — consider adding to KNOWN_ERROR_SELECTORS`);
|
|
334
|
-
}
|
|
335
|
-
const failureSummary = [
|
|
336
|
-
`PUSH CHAIN TRANSACTION FAILED`,
|
|
337
|
-
`Cosmos TX Hash: ${tx.transactionHash}`,
|
|
338
|
-
`Block Height: ${tx.height}, TX Code: ${tx.code} (error)`,
|
|
339
|
-
`Gas Used: ${tx.gasUsed}, Gas Wanted: ${tx.gasWanted}`,
|
|
340
|
-
...(failedEthTxHashes.length > 0 ? [`Ethereum TX Hash(es): ${failedEthTxHashes.join(', ')}`] : []),
|
|
341
|
-
`Error: ${publicMessage}`,
|
|
342
|
-
].join(' | ');
|
|
343
|
-
(0, context_1.printLog)(ctx, failureSummary);
|
|
344
|
-
// Throw a typed error so the orchestrator's outer catch can lift the
|
|
345
|
-
// structured `decodedError` straight onto the terminal-hook payload.
|
|
346
|
-
throw new errors_1.PushChainExecutionError(publicMessage, {
|
|
347
|
-
decodedError: decodedForPayload,
|
|
348
|
-
});
|
|
268
|
+
throw err;
|
|
349
269
|
}
|
|
350
|
-
if (
|
|
351
|
-
|
|
270
|
+
if (tx.code === 0)
|
|
271
|
+
break;
|
|
272
|
+
// Cosmos sequence race: returned via tx.rawLog rather than thrown
|
|
273
|
+
const isSeqMismatch = typeof tx.rawLog === 'string' &&
|
|
274
|
+
COSMOS_SEQUENCE_MISMATCH_RE.test(tx.rawLog);
|
|
275
|
+
if (isSeqMismatch && seqRetryCount < MAX_SEQ_RETRIES) {
|
|
276
|
+
seqRetryCount++;
|
|
277
|
+
const delay = Math.round(SEQ_RETRY_BASE_DELAY_MS * seqRetryCount * (1 + Math.random() * 0.2));
|
|
278
|
+
(0, context_1.printLog)(ctx, `sendUniversalTx — Cosmos sequence mismatch in tx.rawLog (retry ${seqRetryCount}/${MAX_SEQ_RETRIES}), sleeping ${delay}ms: ${tx.rawLog}`);
|
|
279
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
280
|
+
attempt--; // don't consume EVM-signature retry budget
|
|
281
|
+
continue;
|
|
352
282
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
if (
|
|
358
|
-
|
|
283
|
+
// Nonce-race retry: UEA storage nonce advanced between our read and
|
|
284
|
+
// tx inclusion. Re-sign with the fresh nonce and rebroadcast.
|
|
285
|
+
const isSigMismatch = typeof tx.rawLog === 'string' &&
|
|
286
|
+
tx.rawLog.includes(INVALID_EVM_SIGNATURE_SELECTOR);
|
|
287
|
+
if (attempt < MAX_SIG_RETRIES && isSigMismatch && resignFn) {
|
|
288
|
+
(0, context_1.printLog)(ctx, `sendUniversalTx — InvalidEVMSignature on attempt ${attempt + 1} (${tx.rawLog}); re-signing with fresh UEA nonce (retry ${attempt + 1}/${MAX_SIG_RETRIES})`);
|
|
289
|
+
const fresh = await resignFn();
|
|
290
|
+
currentPayload = fresh.universalPayload;
|
|
291
|
+
currentVerificationData = fresh.verificationData;
|
|
292
|
+
continue;
|
|
359
293
|
}
|
|
360
|
-
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
294
|
+
// Terminal failure
|
|
295
|
+
const failedEthTxHashes = tx.events
|
|
296
|
+
?.filter((e) => e.type === 'ethereum_tx')
|
|
297
|
+
.flatMap((e) => e.attributes
|
|
298
|
+
?.filter((attr) => attr.key === 'ethereumTxHash')
|
|
299
|
+
.map((attr) => attr.value)) ?? [];
|
|
300
|
+
// Decode known revert selectors (e.g. `ret 0xacfdb444`) from the cosmos
|
|
301
|
+
// rawLog so the consumer-facing error AND the diagnostic failureSummary
|
|
302
|
+
// log carry an actionable hint instead of raw 4-byte hex. Mirrors the
|
|
303
|
+
// wiring in `extractPcTxAndTransform` for the post-success `pcTx FAILED`
|
|
304
|
+
// path. Also feeds the structured `decodedError` payload through to the
|
|
305
|
+
// terminal hook (199-02 / 299-02 / 399-02 / 999-02).
|
|
306
|
+
const rawMessage = tx.rawLog ?? '';
|
|
307
|
+
let publicMessage = (0, formatters_1.normalizePublicErrorMessage)(rawMessage);
|
|
308
|
+
let decodedForPayload;
|
|
309
|
+
const decoded = (0, error_decoder_1.decodeRevert)(rawMessage);
|
|
310
|
+
if (decoded?.kind === 'custom') {
|
|
311
|
+
publicMessage = (0, error_decoder_1.formatDecodedRevertForUser)(decoded);
|
|
312
|
+
decodedForPayload = {
|
|
313
|
+
name: decoded.name,
|
|
314
|
+
hint: decoded.hint,
|
|
315
|
+
selector: decoded.selector,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
else if (decoded?.kind === 'string') {
|
|
319
|
+
publicMessage = (0, error_decoder_1.formatDecodedRevertForUser)(decoded);
|
|
320
|
+
decodedForPayload = {
|
|
321
|
+
decoded: decoded.decoded,
|
|
322
|
+
selector: decoded.selector,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
else if (decoded?.kind === 'unknown') {
|
|
326
|
+
(0, context_1.printLog)(ctx, `[error-decoder] unknown selector ${decoded.selector} — consider adding to KNOWN_ERROR_SELECTORS`);
|
|
327
|
+
}
|
|
328
|
+
const failureSummary = [
|
|
329
|
+
`PUSH CHAIN TRANSACTION FAILED`,
|
|
330
|
+
`Cosmos TX Hash: ${tx.transactionHash}`,
|
|
331
|
+
`Block Height: ${tx.height}, TX Code: ${tx.code} (error)`,
|
|
332
|
+
`Gas Used: ${tx.gasUsed}, Gas Wanted: ${tx.gasWanted}`,
|
|
333
|
+
...(failedEthTxHashes.length > 0 ? [`Ethereum TX Hash(es): ${failedEthTxHashes.join(', ')}`] : []),
|
|
334
|
+
`Error: ${publicMessage}`,
|
|
335
|
+
].join(' | ');
|
|
336
|
+
(0, context_1.printLog)(ctx, failureSummary);
|
|
337
|
+
// Throw a typed error so the orchestrator's outer catch can lift the
|
|
338
|
+
// structured `decodedError` straight onto the terminal-hook payload.
|
|
339
|
+
throw new errors_1.PushChainExecutionError(publicMessage, {
|
|
340
|
+
decodedError: decodedForPayload,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
if (!tx || tx.code !== 0) {
|
|
344
|
+
throw new Error(`sendUniversalTx — unreachable: loop exited without success or throw`);
|
|
345
|
+
}
|
|
346
|
+
const ethTxHashes = tx.events
|
|
347
|
+
?.filter((e) => e.type === 'ethereum_tx')
|
|
348
|
+
.flatMap((e) => e.attributes
|
|
349
|
+
?.filter((attr) => attr.key === 'ethereumTxHash')
|
|
350
|
+
.map((attr) => attr.value)) ?? [];
|
|
351
|
+
if (ethTxHashes.length === 0) {
|
|
352
|
+
throw new Error('No ethereumTxHash found in transaction events');
|
|
353
|
+
}
|
|
354
|
+
const evmTxs = await Promise.all(ethTxHashes.map(async (hash) => getIndexedPushTransaction(ctx, hash, 'sendUniversalTx')));
|
|
355
|
+
const responses = await Promise.all(evmTxs.map((tx, index) => transformFn(tx, index === evmTxs.length - 1 ? eventBuffer : [])));
|
|
356
|
+
return responses;
|
|
364
357
|
}
|
|
365
358
|
// ============================================================================
|
|
366
359
|
// extractPcTxAndTransform
|
|
@@ -369,66 +362,63 @@ function sendUniversalTx(ctx, isUEADeployed, feeLockTxHash, universalPayload, ve
|
|
|
369
362
|
* Validates Push Chain tx response, extracts last pcTx, fetches EVM tx,
|
|
370
363
|
* and transforms to UniversalTxResponse.
|
|
371
364
|
*/
|
|
372
|
-
function extractPcTxAndTransform(ctx, pushChainUniversalTx, gatewayTxHash, eventBuffer, label, transformFn) {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
365
|
+
async function extractPcTxAndTransform(ctx, pushChainUniversalTx, gatewayTxHash, eventBuffer, label, transformFn) {
|
|
366
|
+
if (!pushChainUniversalTx?.pcTx?.length) {
|
|
367
|
+
throw new Error(`Failed to retrieve Push Chain transaction status for gateway tx: ${gatewayTxHash}. ` +
|
|
368
|
+
`The transaction may have failed on Push Chain or not been indexed yet.`);
|
|
369
|
+
}
|
|
370
|
+
const lastPcTransaction = pushChainUniversalTx.pcTx.at(-1);
|
|
371
|
+
(0, context_1.printLog)(ctx, `${label} — pcTx: ` + JSON.stringify(pushChainUniversalTx.pcTx.map((p) => ({ txHash: p.txHash, status: p.status, errorMsg: p.errorMsg })), null, 2));
|
|
372
|
+
(0, context_1.printLog)(ctx, `${label} — using lastPcTransaction: ` + JSON.stringify(lastPcTransaction, null, 2));
|
|
373
|
+
if (!lastPcTransaction?.txHash || lastPcTransaction.status === 'FAILED') {
|
|
374
|
+
const failedPcTx = lastPcTransaction?.status === 'FAILED'
|
|
375
|
+
? lastPcTransaction
|
|
376
|
+
: pushChainUniversalTx.pcTx.find((pcTx) => pcTx.status === 'FAILED' && pcTx.errorMsg);
|
|
377
|
+
const rawFailedPcTxErrorMsg = failedPcTx?.errorMsg ?? '';
|
|
378
|
+
let failedPcTxErrorMsg = rawFailedPcTxErrorMsg
|
|
379
|
+
? (0, formatters_1.normalizePublicErrorMessage)(rawFailedPcTxErrorMsg)
|
|
380
|
+
: '';
|
|
381
|
+
const errorDetails = failedPcTxErrorMsg ? `: ${failedPcTxErrorMsg}` : '';
|
|
382
|
+
// Decode known revert selectors and ABI-encoded `Error(string)` reverts
|
|
383
|
+
// into actionable hints. Unknown selectors are logged at INFO so the
|
|
384
|
+
// table can grow from real reverts.
|
|
385
|
+
let hint = '';
|
|
386
|
+
let decodedForPayload;
|
|
387
|
+
const decoded = (0, error_decoder_1.decodeRevert)(rawFailedPcTxErrorMsg);
|
|
388
|
+
if (decoded?.kind === 'custom') {
|
|
389
|
+
failedPcTxErrorMsg = (0, error_decoder_1.formatDecodedRevertForUser)(decoded);
|
|
390
|
+
hint = '';
|
|
391
|
+
decodedForPayload = {
|
|
392
|
+
name: decoded.name,
|
|
393
|
+
hint: decoded.hint,
|
|
394
|
+
selector: decoded.selector,
|
|
395
|
+
};
|
|
378
396
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
const rawFailedPcTxErrorMsg = (_b = failedPcTx === null || failedPcTx === void 0 ? void 0 : failedPcTx.errorMsg) !== null && _b !== void 0 ? _b : '';
|
|
387
|
-
let failedPcTxErrorMsg = rawFailedPcTxErrorMsg
|
|
388
|
-
? (0, formatters_1.normalizePublicErrorMessage)(rawFailedPcTxErrorMsg)
|
|
389
|
-
: '';
|
|
390
|
-
const errorDetails = failedPcTxErrorMsg ? `: ${failedPcTxErrorMsg}` : '';
|
|
391
|
-
// Decode known revert selectors and ABI-encoded `Error(string)` reverts
|
|
392
|
-
// into actionable hints. Unknown selectors are logged at INFO so the
|
|
393
|
-
// table can grow from real reverts.
|
|
394
|
-
let hint = '';
|
|
395
|
-
let decodedForPayload;
|
|
396
|
-
const decoded = (0, error_decoder_1.decodeRevert)(rawFailedPcTxErrorMsg);
|
|
397
|
-
if ((decoded === null || decoded === void 0 ? void 0 : decoded.kind) === 'custom') {
|
|
398
|
-
failedPcTxErrorMsg = (0, error_decoder_1.formatDecodedRevertForUser)(decoded);
|
|
399
|
-
hint = '';
|
|
400
|
-
decodedForPayload = {
|
|
401
|
-
name: decoded.name,
|
|
402
|
-
hint: decoded.hint,
|
|
403
|
-
selector: decoded.selector,
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
else if ((decoded === null || decoded === void 0 ? void 0 : decoded.kind) === 'string') {
|
|
407
|
-
failedPcTxErrorMsg = (0, error_decoder_1.formatDecodedRevertForUser)(decoded);
|
|
408
|
-
hint = '';
|
|
409
|
-
decodedForPayload = {
|
|
410
|
-
decoded: decoded.decoded,
|
|
411
|
-
selector: decoded.selector,
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
else if ((decoded === null || decoded === void 0 ? void 0 : decoded.kind) === 'unknown') {
|
|
415
|
-
(0, context_1.printLog)(ctx, `[error-decoder] unknown selector ${decoded.selector} — consider adding to KNOWN_ERROR_SELECTORS`);
|
|
416
|
-
}
|
|
417
|
-
const decodedErrorDetails = failedPcTxErrorMsg
|
|
418
|
-
? `: ${failedPcTxErrorMsg}`
|
|
419
|
-
: errorDetails;
|
|
420
|
-
const fullMessage = `Push Chain transaction failed for gateway tx: ${gatewayTxHash}${decodedErrorDetails}${hint}`;
|
|
421
|
-
// Live-emit 199-02 before throwing so the terminal failure hook reaches
|
|
422
|
-
// any caller-registered progress stream (parity with reconstructProgressEvents
|
|
423
|
-
// which emits 199-02 on replay).
|
|
424
|
-
(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);
|
|
425
|
-
throw new errors_1.PushChainExecutionError(fullMessage, {
|
|
426
|
-
gatewayTxHash,
|
|
427
|
-
decodedError: decodedForPayload,
|
|
428
|
-
});
|
|
397
|
+
else if (decoded?.kind === 'string') {
|
|
398
|
+
failedPcTxErrorMsg = (0, error_decoder_1.formatDecodedRevertForUser)(decoded);
|
|
399
|
+
hint = '';
|
|
400
|
+
decodedForPayload = {
|
|
401
|
+
decoded: decoded.decoded,
|
|
402
|
+
selector: decoded.selector,
|
|
403
|
+
};
|
|
429
404
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
405
|
+
else if (decoded?.kind === 'unknown') {
|
|
406
|
+
(0, context_1.printLog)(ctx, `[error-decoder] unknown selector ${decoded.selector} — consider adding to KNOWN_ERROR_SELECTORS`);
|
|
407
|
+
}
|
|
408
|
+
const decodedErrorDetails = failedPcTxErrorMsg
|
|
409
|
+
? `: ${failedPcTxErrorMsg}`
|
|
410
|
+
: errorDetails;
|
|
411
|
+
const fullMessage = `Push Chain transaction failed for gateway tx: ${gatewayTxHash}${decodedErrorDetails}${hint}`;
|
|
412
|
+
// Live-emit 199-02 before throwing so the terminal failure hook reaches
|
|
413
|
+
// any caller-registered progress stream (parity with reconstructProgressEvents
|
|
414
|
+
// which emits 199-02 on replay).
|
|
415
|
+
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02, fullMessage, decodedForPayload, failedPcTx?.txHash);
|
|
416
|
+
throw new errors_1.PushChainExecutionError(fullMessage, {
|
|
417
|
+
gatewayTxHash,
|
|
418
|
+
decodedError: decodedForPayload,
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
const tx = await getIndexedPushTransaction(ctx, lastPcTransaction.txHash, label);
|
|
422
|
+
return transformFn(tx, eventBuffer);
|
|
433
423
|
}
|
|
434
424
|
//# sourceMappingURL=push-chain-tx.js.map
|