@pushchain/core 6.0.19 → 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 +54 -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 +4 -1
- 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 -331
- 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.d.ts +2 -1
- package/src/lib/universal/signer/signer.js +315 -299
- 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
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PushClient = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
4
|
const viem_1 = require("viem");
|
|
6
5
|
const tx_1 = require("../generated/v1/tx");
|
|
7
6
|
const tx_2 = require("cosmjs-types/cosmos/tx/v1beta1/tx");
|
|
@@ -26,18 +25,33 @@ function pushNetworkToChain(network) {
|
|
|
26
25
|
return enums_1.CHAIN.PUSH_LOCALNET;
|
|
27
26
|
}
|
|
28
27
|
class PushClient extends evm_client_1.EvmClient {
|
|
28
|
+
/** Gas limit for Cosmos transactions on Push Chain */
|
|
29
|
+
static COSMOS_GAS_LIMIT = 100000000000;
|
|
30
|
+
pushChainInfo;
|
|
31
|
+
ephemeralKey;
|
|
32
|
+
ephemeralAccount;
|
|
33
|
+
currentRpcIndex = 0;
|
|
34
|
+
/**
|
|
35
|
+
* Archive (full-history) endpoints. History-sensitive reads fall back from
|
|
36
|
+
* the prune RPC to these on a pruned-history miss. Resolved from the chain's
|
|
37
|
+
* configured archive endpoints — empty/undefined for chains without one
|
|
38
|
+
* (mainnet/localnet), where the fallback is a no-op (prune-only behaviour).
|
|
39
|
+
*/
|
|
40
|
+
archiveTendermintRpc;
|
|
41
|
+
archivePublicClient;
|
|
29
42
|
constructor(clientOptions) {
|
|
30
|
-
var _a, _b, _c;
|
|
31
43
|
const pushChainKey = pushNetworkToChain(clientOptions.network);
|
|
32
|
-
const chain =
|
|
33
|
-
super(
|
|
34
|
-
|
|
44
|
+
const chain = clientOptions.chain ?? (0, chain_1.getPushViemChain)(pushChainKey);
|
|
45
|
+
super({
|
|
46
|
+
...clientOptions,
|
|
47
|
+
chain,
|
|
48
|
+
});
|
|
35
49
|
this.pushChainInfo = chain_1.PUSH_CHAIN_INFO[pushChainKey];
|
|
36
50
|
// Archive fallback is always set up; it's inert for chains without an
|
|
37
51
|
// archive endpoint (mainnet/localnet → empty lists), and otherwise lets
|
|
38
52
|
// history-sensitive reads recover a pruned tx from the archive node.
|
|
39
|
-
this.archiveTendermintRpc =
|
|
40
|
-
const archiveEvmUrls =
|
|
53
|
+
this.archiveTendermintRpc = this.pushChainInfo.archiveTendermintRpc ?? [];
|
|
54
|
+
const archiveEvmUrls = chain_1.CHAIN_INFO[pushChainKey].archiveRPC ?? [];
|
|
41
55
|
if (archiveEvmUrls.length > 0) {
|
|
42
56
|
this.archivePublicClient = (0, viem_1.createPublicClient)({
|
|
43
57
|
chain,
|
|
@@ -51,58 +65,55 @@ class PushClient extends evm_client_1.EvmClient {
|
|
|
51
65
|
* Executes an operation with automatic fallback to next RPC endpoint on failure.
|
|
52
66
|
* Follows the same pattern as SvmClient.executeWithFallback().
|
|
53
67
|
*/
|
|
54
|
-
executeWithRpcFallback(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (sticky && rpcIndex !== this.currentRpcIndex) {
|
|
86
|
-
this.currentRpcIndex = rpcIndex;
|
|
87
|
-
}
|
|
88
|
-
return result;
|
|
68
|
+
async executeWithRpcFallback(operation, operationName = 'operation', rpcUrls = this.pushChainInfo.tendermintRpc,
|
|
69
|
+
// Sticky cursor (`currentRpcIndex`) is only meaningful for the primary
|
|
70
|
+
// prune pool; the archive pass passes `sticky=false` so a single archive
|
|
71
|
+
// URL can't pin the prune cursor.
|
|
72
|
+
sticky = true) {
|
|
73
|
+
let lastError = null;
|
|
74
|
+
// Cycle the RPC URLs, but also RETRY transient failures (5xx / network /
|
|
75
|
+
// "HTTP request failed") with backoff — otherwise a single 502 on a
|
|
76
|
+
// single-endpoint chain (e.g. Donut) aborts a tx mid status-poll. Total
|
|
77
|
+
// attempts = urls × (RETRIES_PER_URL + 1).
|
|
78
|
+
const RETRIES_PER_URL = 4;
|
|
79
|
+
const totalAttempts = rpcUrls.length * (RETRIES_PER_URL + 1);
|
|
80
|
+
const isTransient = (e) => {
|
|
81
|
+
const m = `${e?.message ?? ''}`.toLowerCase();
|
|
82
|
+
return (/\b(502|503|504|429)\b/.test(m) ||
|
|
83
|
+
m.includes('http request failed') ||
|
|
84
|
+
m.includes('server error') ||
|
|
85
|
+
m.includes('timeout') ||
|
|
86
|
+
m.includes('timed out') ||
|
|
87
|
+
m.includes('econnreset') ||
|
|
88
|
+
m.includes('socket hang up') ||
|
|
89
|
+
m.includes('fetch failed'));
|
|
90
|
+
};
|
|
91
|
+
for (let attempt = 0; attempt < totalAttempts; attempt++) {
|
|
92
|
+
const baseIndex = sticky ? this.currentRpcIndex : 0;
|
|
93
|
+
const rpcIndex = (baseIndex + attempt) % rpcUrls.length;
|
|
94
|
+
const rpcUrl = rpcUrls[rpcIndex];
|
|
95
|
+
try {
|
|
96
|
+
const result = await operation(rpcUrl);
|
|
97
|
+
if (sticky && rpcIndex !== this.currentRpcIndex) {
|
|
98
|
+
this.currentRpcIndex = rpcIndex;
|
|
89
99
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// back off (200ms → 400 → 800 …, capped) so a flaky RPC can recover.
|
|
97
|
-
const cycle = Math.floor(attempt / rpcUrls.length);
|
|
98
|
-
const delay = isTransient(lastError)
|
|
99
|
-
? Math.min(2000, 200 * Math.pow(2, cycle))
|
|
100
|
-
: 100;
|
|
101
|
-
yield new Promise((resolve) => setTimeout(resolve, delay));
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
lastError = error;
|
|
104
|
+
if (attempt === totalAttempts - 1) {
|
|
105
|
+
break;
|
|
102
106
|
}
|
|
107
|
+
// Non-transient errors: move to the next URL quickly. Transient ones:
|
|
108
|
+
// back off (200ms → 400 → 800 …, capped) so a flaky RPC can recover.
|
|
109
|
+
const cycle = Math.floor(attempt / rpcUrls.length);
|
|
110
|
+
const delay = isTransient(lastError)
|
|
111
|
+
? Math.min(2000, 200 * 2 ** cycle)
|
|
112
|
+
: 100;
|
|
113
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
103
114
|
}
|
|
104
|
-
|
|
105
|
-
});
|
|
115
|
+
}
|
|
116
|
+
throw new Error(`All RPC endpoints failed for ${operationName}. Last error: ${lastError?.message}`);
|
|
106
117
|
}
|
|
107
118
|
/**
|
|
108
119
|
* Runs a history-sensitive Tendermint operation over the prune pool first and,
|
|
@@ -116,30 +127,28 @@ class PushClient extends evm_client_1.EvmClient {
|
|
|
116
127
|
* off) this is a pass-through: the original throw or empty result is returned
|
|
117
128
|
* unchanged — behaviour identical to before.
|
|
118
129
|
*/
|
|
119
|
-
executeWithArchiveFallback(operation, operationName, isEmpty) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
return this.executeWithRpcFallback(operation, `${operationName} (archive)`, this.archiveTendermintRpc, false);
|
|
142
|
-
});
|
|
130
|
+
async executeWithArchiveFallback(operation, operationName, isEmpty) {
|
|
131
|
+
let pruneResult;
|
|
132
|
+
let pruneError;
|
|
133
|
+
try {
|
|
134
|
+
pruneResult = await this.executeWithRpcFallback(operation, operationName);
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
pruneError = error;
|
|
138
|
+
}
|
|
139
|
+
const pruneMissed = pruneError !== undefined ||
|
|
140
|
+
(pruneResult !== undefined && isEmpty(pruneResult));
|
|
141
|
+
if (!pruneMissed) {
|
|
142
|
+
return pruneResult;
|
|
143
|
+
}
|
|
144
|
+
if (this.archiveTendermintRpc.length === 0) {
|
|
145
|
+
// No archive: preserve original behaviour (re-throw, or return empty).
|
|
146
|
+
if (pruneError !== undefined)
|
|
147
|
+
throw pruneError;
|
|
148
|
+
return pruneResult;
|
|
149
|
+
}
|
|
150
|
+
// Prune missed + archive available → re-query archive (non-sticky).
|
|
151
|
+
return this.executeWithRpcFallback(operation, `${operationName} (archive)`, this.archiveTendermintRpc, false);
|
|
143
152
|
}
|
|
144
153
|
/** True when this client has a usable archive EVM endpoint configured. */
|
|
145
154
|
get hasArchiveEvm() {
|
|
@@ -185,10 +194,8 @@ class PushClient extends evm_client_1.EvmClient {
|
|
|
185
194
|
};
|
|
186
195
|
}
|
|
187
196
|
// --- Tx Builder ---
|
|
188
|
-
createCosmosTxBody(messages, memo) {
|
|
189
|
-
return
|
|
190
|
-
return tx_2.TxBody.fromPartial({ messages, memo });
|
|
191
|
-
});
|
|
197
|
+
async createCosmosTxBody(messages, memo) {
|
|
198
|
+
return tx_2.TxBody.fromPartial({ messages, memo });
|
|
192
199
|
}
|
|
193
200
|
// --- Tx Signer ---
|
|
194
201
|
getSignerAddress() {
|
|
@@ -201,124 +208,114 @@ class PushClient extends evm_client_1.EvmClient {
|
|
|
201
208
|
* Signs a Cosmos tx using a temporary account.
|
|
202
209
|
* In prod, signer should be passed in instead.
|
|
203
210
|
*/
|
|
204
|
-
signCosmosTx(txBody) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
console.warn(`[PushClient:signCosmosTx] Account lookup failed for ${sender}:`, err);
|
|
222
|
-
}
|
|
211
|
+
async signCosmosTx(txBody) {
|
|
212
|
+
const sender = (0, encoding_1.toBech32)(this.pushChainInfo.prefix, (0, viem_1.hexToBytes)(this.ephemeralAccount.address));
|
|
213
|
+
return this.executeWithRpcFallback(async (rpcUrl) => {
|
|
214
|
+
const tmClient = await tendermint_rpc_1.Tendermint34Client.connect(rpcUrl);
|
|
215
|
+
const status = await tmClient.status();
|
|
216
|
+
const chainId = status.nodeInfo.network;
|
|
217
|
+
const queryClient = stargate_1.QueryClient.withExtensions(tmClient, stargate_1.setupAuthExtension);
|
|
218
|
+
let baseAccount = null;
|
|
219
|
+
try {
|
|
220
|
+
const accountResp = await queryClient.auth.account(sender);
|
|
221
|
+
baseAccount = auth_1.BaseAccount.decode(accountResp.value);
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
// Account may not exist on-chain yet; default to sequence=0 / accountNumber=0
|
|
225
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
226
|
+
if (!msg.includes('NotFound') && !msg.includes('not found')) {
|
|
227
|
+
console.warn(`[PushClient:signCosmosTx] Account lookup failed for ${sender}:`, err);
|
|
223
228
|
}
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
})
|
|
253
|
-
});
|
|
229
|
+
}
|
|
230
|
+
// 📦 Encode pubkey
|
|
231
|
+
const uncompressedPubKey = (0, viem_1.hexToBytes)(this.ephemeralAccount.publicKey);
|
|
232
|
+
const compressedPubKey = crypto_1.Secp256k1.compressPubkey(uncompressedPubKey);
|
|
233
|
+
// Manual protobuf encode: field 1 (tag=10), length-delimited bytes
|
|
234
|
+
const keyLen = compressedPubKey.length;
|
|
235
|
+
const pubkeyValue = new Uint8Array(2 + keyLen);
|
|
236
|
+
pubkeyValue[0] = 10; // field 1, wire type 2 (length-delimited)
|
|
237
|
+
pubkeyValue[1] = keyLen;
|
|
238
|
+
pubkeyValue.set(compressedPubKey, 2);
|
|
239
|
+
const pubkeyEncoded = {
|
|
240
|
+
typeUrl: '/cosmos.evm.crypto.v1.ethsecp256k1.PubKey',
|
|
241
|
+
value: pubkeyValue,
|
|
242
|
+
};
|
|
243
|
+
const authInfoBytes = (0, proto_signing_1.makeAuthInfoBytes)([
|
|
244
|
+
{
|
|
245
|
+
pubkey: pubkeyEncoded,
|
|
246
|
+
sequence: baseAccount ? Number(baseAccount.sequence) : 0,
|
|
247
|
+
},
|
|
248
|
+
], [], PushClient.COSMOS_GAS_LIMIT, undefined, undefined);
|
|
249
|
+
const txBodyBytes = tx_2.TxBody.encode(txBody).finish();
|
|
250
|
+
const signDoc = (0, proto_signing_1.makeSignDoc)(txBodyBytes, authInfoBytes, chainId, baseAccount ? Number(baseAccount.accountNumber) : 0);
|
|
251
|
+
const digest = (0, viem_1.keccak256)(tx_2.SignDoc.encode(signDoc).finish());
|
|
252
|
+
const signature = await this.ephemeralAccount.sign({ hash: digest });
|
|
253
|
+
return tx_2.TxRaw.fromPartial({
|
|
254
|
+
bodyBytes: txBodyBytes,
|
|
255
|
+
authInfoBytes,
|
|
256
|
+
signatures: [(0, viem_1.hexToBytes)(signature)],
|
|
257
|
+
});
|
|
258
|
+
}, 'signCosmosTx');
|
|
254
259
|
}
|
|
255
|
-
broadcastCosmosTx(txRaw) {
|
|
256
|
-
return
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}), 'broadcastCosmosTx');
|
|
261
|
-
});
|
|
260
|
+
async broadcastCosmosTx(txRaw) {
|
|
261
|
+
return this.executeWithRpcFallback(async (rpcUrl) => {
|
|
262
|
+
const client = await stargate_1.StargateClient.connect(rpcUrl);
|
|
263
|
+
return client.broadcastTx(tx_2.TxRaw.encode(txRaw).finish());
|
|
264
|
+
}, 'broadcastCosmosTx');
|
|
262
265
|
}
|
|
263
266
|
/**
|
|
264
267
|
* Queries Push Chain's uexecutor gRPC service for a UniversalTx by its ID.
|
|
265
268
|
*/
|
|
266
|
-
getUniversalTxById(id) {
|
|
267
|
-
return
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}), 'getUniversalTxById');
|
|
276
|
-
});
|
|
269
|
+
async getUniversalTxById(id) {
|
|
270
|
+
return this.executeWithRpcFallback(async (rpcUrl) => {
|
|
271
|
+
const tmClient = await tendermint_rpc_1.Tendermint34Client.connect(rpcUrl);
|
|
272
|
+
const queryClient = new stargate_1.QueryClient(tmClient);
|
|
273
|
+
const rpc = (0, stargate_1.createProtobufRpcClient)(queryClient);
|
|
274
|
+
const request = query_1.QueryGetUniversalTxRequest.fromPartial({ id });
|
|
275
|
+
const responseBytes = await rpc.request('uexecutor.v1.Query', 'GetUniversalTx', query_1.QueryGetUniversalTxRequest.encode(request).finish());
|
|
276
|
+
return query_1.QueryGetUniversalTxResponse.decode(responseBytes);
|
|
277
|
+
}, 'getUniversalTxById');
|
|
277
278
|
}
|
|
278
279
|
/**
|
|
279
280
|
* Queries Push Chain's uexecutor v2 gRPC service for a UniversalTx by its ID.
|
|
280
281
|
* V2 returns expanded OutboundTx fields and repeated outbound_tx array.
|
|
281
282
|
*/
|
|
282
|
-
getUniversalTxByIdV2(id) {
|
|
283
|
-
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
304
|
-
});
|
|
283
|
+
async getUniversalTxByIdV2(id) {
|
|
284
|
+
const operation = async (rpcUrl) => {
|
|
285
|
+
const tmClient = await tendermint_rpc_1.Tendermint34Client.connect(rpcUrl);
|
|
286
|
+
const queryClient = new stargate_1.QueryClient(tmClient);
|
|
287
|
+
const rpc = (0, stargate_1.createProtobufRpcClient)(queryClient);
|
|
288
|
+
const request = query_2.QueryGetUniversalTxRequestV2.fromPartial({ id });
|
|
289
|
+
const responseBytes = await rpc.request('uexecutor.v2.Query', 'GetUniversalTx', query_2.QueryGetUniversalTxRequestV2.encode(request).finish());
|
|
290
|
+
return query_2.QueryGetUniversalTxResponseV2.decode(responseBytes);
|
|
291
|
+
};
|
|
292
|
+
// This is a current-STATE query (abci_query), so prune is always
|
|
293
|
+
// authoritative — an empty `universalTx` is a real "doesn't exist", not a
|
|
294
|
+
// pruned-history miss. Only fall back to archive on a hard error (all prune
|
|
295
|
+
// attempts failed); never on an empty result (would double-load on polls).
|
|
296
|
+
try {
|
|
297
|
+
return await this.executeWithRpcFallback(operation, 'getUniversalTxByIdV2');
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
if (this.archiveTendermintRpc.length === 0)
|
|
301
|
+
throw error;
|
|
302
|
+
return this.executeWithRpcFallback(operation, 'getUniversalTxByIdV2 (archive)', this.archiveTendermintRpc, false);
|
|
303
|
+
}
|
|
305
304
|
}
|
|
306
305
|
/**
|
|
307
306
|
* Generic Cosmos searchTx — returns the raw indexed results so callers can
|
|
308
307
|
* walk events themselves. Used by the inbound-tracker to find a child UTX
|
|
309
308
|
* created from an external tx hash (`universal_tx_created.inbound_tx_hash`).
|
|
310
309
|
*/
|
|
311
|
-
searchCosmosByQuery(query) {
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
return this.executeWithArchiveFallback(operation, 'searchCosmosByQuery', (results) => results.length === 0);
|
|
321
|
-
});
|
|
310
|
+
async searchCosmosByQuery(query) {
|
|
311
|
+
const operation = async (rpcUrl) => {
|
|
312
|
+
const client = await stargate_1.StargateClient.connect(rpcUrl);
|
|
313
|
+
const results = await client.searchTx(query);
|
|
314
|
+
return results.map((result) => JSON.parse(JSON.stringify(result, (_key, value) => typeof value === 'bigint' ? value.toString() : value)));
|
|
315
|
+
};
|
|
316
|
+
// History-sensitive (tx_search): an empty result on prune may just mean the
|
|
317
|
+
// matching tx is outside the prune window → retry archive.
|
|
318
|
+
return this.executeWithArchiveFallback(operation, 'searchCosmosByQuery', (results) => results.length === 0);
|
|
322
319
|
}
|
|
323
320
|
/**
|
|
324
321
|
* Fetches a Cosmos transaction by its hash.
|
|
@@ -326,71 +323,60 @@ class PushClient extends evm_client_1.EvmClient {
|
|
|
326
323
|
* @returns The indexed transaction (height, logs, events, etc.).
|
|
327
324
|
* @throws If the tx isn't found.
|
|
328
325
|
*/
|
|
329
|
-
getCosmosTx(txHash) {
|
|
330
|
-
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
return this.executeWithArchiveFallback(operation, 'getCosmosTx', () => false);
|
|
348
|
-
});
|
|
326
|
+
async getCosmosTx(txHash) {
|
|
327
|
+
const operation = async (rpcUrl) => {
|
|
328
|
+
const client = await stargate_1.StargateClient.connect(rpcUrl);
|
|
329
|
+
const query = `ethereum_tx.ethereumTxHash='${txHash}'`;
|
|
330
|
+
const results = await client.searchTx(query);
|
|
331
|
+
// Convert bigint values to strings in the results. This is done to avoid JSON.stringify()
|
|
332
|
+
// from converting bigint to string when on the client side.
|
|
333
|
+
// On documentation, one thing very common was to use JSON.stringify() to log the results, then we would get an error.
|
|
334
|
+
const convertedResults = results.map((result) => JSON.parse(JSON.stringify(result, (key, value) => typeof value === 'bigint' ? value.toString() : value)));
|
|
335
|
+
if (convertedResults.length === 0) {
|
|
336
|
+
throw new Error(`No Cosmos-indexed tx for EVM hash ${txHash}`);
|
|
337
|
+
}
|
|
338
|
+
return { ...convertedResults[0], transactionHash: txHash };
|
|
339
|
+
};
|
|
340
|
+
// History-sensitive (tx_search). The op throws on an empty result, so the
|
|
341
|
+
// pruned-history miss surfaces as a thrown error — `isEmpty` stays false and
|
|
342
|
+
// the wrapper retries archive via its caught-error path.
|
|
343
|
+
return this.executeWithArchiveFallback(operation, 'getCosmosTx', () => false);
|
|
349
344
|
}
|
|
350
345
|
/**
|
|
351
346
|
* EVM `getTransaction` with archive fallback. Prune first; on a not-found
|
|
352
347
|
* (pruned, or not yet indexed) and an archive EVM endpoint configured, retry
|
|
353
348
|
* the archive client. Without archive this is exactly `super.getTransaction`.
|
|
354
349
|
*/
|
|
355
|
-
getTransaction(txHash) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
const tx = yield archiveClient.getTransaction({ hash: txHash });
|
|
368
|
-
const wait = (...args_1) => tslib_1.__awaiter(this, [...args_1], void 0, function* (confirmations = 1) { return archiveClient.waitForTransactionReceipt({ hash: txHash, confirmations }); });
|
|
369
|
-
return Object.assign(Object.assign({}, tx), { wait });
|
|
370
|
-
}
|
|
371
|
-
});
|
|
350
|
+
async getTransaction(txHash) {
|
|
351
|
+
try {
|
|
352
|
+
return await super.getTransaction(txHash);
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
if (!this.hasArchiveEvm)
|
|
356
|
+
throw error;
|
|
357
|
+
const archiveClient = this.archivePublicClient;
|
|
358
|
+
const tx = await archiveClient.getTransaction({ hash: txHash });
|
|
359
|
+
const wait = async (confirmations = 1) => archiveClient.waitForTransactionReceipt({ hash: txHash, confirmations });
|
|
360
|
+
return { ...tx, wait };
|
|
361
|
+
}
|
|
372
362
|
}
|
|
373
363
|
/**
|
|
374
364
|
* EVM `getTransactionReceipt` with archive fallback. Used by the inbound
|
|
375
365
|
* tracker to fetch a Push-leg receipt that may predate the prune window.
|
|
376
366
|
* Prune first; on not-found, retry the archive EVM client if configured.
|
|
377
367
|
*/
|
|
378
|
-
getTransactionReceiptWithArchiveFallback(txHash) {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
390
|
-
});
|
|
368
|
+
async getTransactionReceiptWithArchiveFallback(txHash) {
|
|
369
|
+
try {
|
|
370
|
+
return await this.publicClient.getTransactionReceipt({ hash: txHash });
|
|
371
|
+
}
|
|
372
|
+
catch (error) {
|
|
373
|
+
if (!this.hasArchiveEvm)
|
|
374
|
+
throw error;
|
|
375
|
+
return this.archivePublicClient.getTransactionReceipt({
|
|
376
|
+
hash: txHash,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
391
379
|
}
|
|
392
380
|
}
|
|
393
381
|
exports.PushClient = PushClient;
|
|
394
|
-
/** Gas limit for Cosmos transactions on Push Chain */
|
|
395
|
-
PushClient.COSMOS_GAS_LIMIT = 100000000000;
|
|
396
382
|
//# sourceMappingURL=push-client.js.map
|