@pushchain/core 6.0.24 → 6.0.26
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 +150 -0
- package/package.json +1 -1
- package/src/lib/constants/abi/index.d.ts +1 -0
- package/src/lib/constants/abi/index.js +4 -1
- package/src/lib/constants/abi/prc20.evm.d.ts +32 -0
- package/src/lib/constants/abi/prc20.evm.js +20 -0
- package/src/lib/constants/abi/uea-factory.d.ts +31 -0
- package/src/lib/constants/abi/uea-factory.js +19 -0
- package/src/lib/constants/abi/universalCallback.evm.d.ts +561 -0
- package/src/lib/constants/abi/universalCallback.evm.js +247 -0
- package/src/lib/constants/abi/universalGatewayV0.json +1 -1
- package/src/lib/constants/abi/universalReadRegistry.evm.d.ts +247 -0
- package/src/lib/constants/abi/universalReadRegistry.evm.js +38 -0
- package/src/lib/constants/chain.d.ts +12 -0
- package/src/lib/constants/chain.js +24 -2
- package/src/lib/constants/enums.d.ts +7 -0
- package/src/lib/constants/enums.js +11 -0
- package/src/lib/constants/index.d.ts +54 -0
- package/src/lib/constants/index.js +38 -8
- package/src/lib/constants/read-state.d.ts +57 -0
- package/src/lib/constants/read-state.js +63 -0
- package/src/lib/generated/ucallback/v1/index.d.ts +2 -0
- package/src/lib/generated/ucallback/v1/index.js +6 -0
- package/src/lib/generated/ucallback/v1/query.d.ts +47 -0
- package/src/lib/generated/ucallback/v1/query.js +131 -0
- package/src/lib/generated/ucallback/v1/types.d.ts +99 -0
- package/src/lib/generated/ucallback/v1/types.js +366 -0
- package/src/lib/generated/uexecutor/v1/query.d.ts +29 -0
- package/src/lib/generated/uexecutor/v1/query.js +98 -1
- package/src/lib/index.d.ts +9 -0
- package/src/lib/index.js +38 -1
- package/src/lib/orchestrator/internals/cascade.js +5 -2
- package/src/lib/orchestrator/internals/errors.d.ts +6 -0
- package/src/lib/orchestrator/internals/errors.js +13 -1
- package/src/lib/orchestrator/internals/index.d.ts +1 -0
- package/src/lib/orchestrator/internals/index.js +6 -1
- package/src/lib/orchestrator/internals/push-chain-tx.js +81 -61
- package/src/lib/orchestrator/internals/read-state.d.ts +24 -0
- package/src/lib/orchestrator/internals/read-state.js +47 -0
- package/src/lib/orchestrator/internals/route-handlers.js +6 -1
- package/src/lib/orchestrator/internals/svm-helpers.js +24 -0
- package/src/lib/orchestrator/orchestrator.d.ts +26 -0
- package/src/lib/orchestrator/orchestrator.js +22 -0
- package/src/lib/orchestrator/orchestrator.types.d.ts +2 -0
- package/src/lib/orchestrator/route-detector.js +4 -0
- package/src/lib/progress-hook/progress-hook.js +292 -0
- package/src/lib/progress-hook/progress-hook.types.d.ts +35 -0
- package/src/lib/progress-hook/progress-hook.types.js +37 -0
- package/src/lib/push-chain/push-chain.d.ts +71 -0
- package/src/lib/push-chain/push-chain.js +28 -0
- package/src/lib/push-client/push-client.d.ts +42 -2
- package/src/lib/push-client/push-client.js +152 -13
- package/src/lib/read-state/budget.d.ts +16 -0
- package/src/lib/read-state/budget.js +32 -0
- package/src/lib/read-state/destination.d.ts +12 -0
- package/src/lib/read-state/destination.js +51 -0
- package/src/lib/read-state/envelopes/evm.d.ts +24 -0
- package/src/lib/read-state/envelopes/evm.js +147 -0
- package/src/lib/read-state/envelopes/index.d.ts +12 -0
- package/src/lib/read-state/envelopes/index.js +45 -0
- package/src/lib/read-state/envelopes/svm.d.ts +32 -0
- package/src/lib/read-state/envelopes/svm.js +117 -0
- package/src/lib/read-state/envelopes/web2.d.ts +29 -0
- package/src/lib/read-state/envelopes/web2.js +149 -0
- package/src/lib/read-state/errors.d.ts +70 -0
- package/src/lib/read-state/errors.js +116 -0
- package/src/lib/read-state/index.d.ts +13 -0
- package/src/lib/read-state/index.js +38 -0
- package/src/lib/read-state/preflight.d.ts +21 -0
- package/src/lib/read-state/preflight.js +70 -0
- package/src/lib/read-state/read-events.d.ts +27 -0
- package/src/lib/read-state/read-events.js +135 -0
- package/src/lib/read-state/read-executor.d.ts +18 -0
- package/src/lib/read-state/read-executor.js +216 -0
- package/src/lib/read-state/read-params.d.ts +250 -0
- package/src/lib/read-state/read-params.js +164 -0
- package/src/lib/read-state/read-state.types.d.ts +458 -0
- package/src/lib/read-state/read-state.types.js +72 -0
- package/src/lib/read-state/read-tracker.d.ts +55 -0
- package/src/lib/read-state/read-tracker.js +481 -0
- package/src/lib/read-state/registry.d.ts +21 -0
- package/src/lib/read-state/registry.js +53 -0
- package/src/lib/read-state/result-decoder.d.ts +16 -0
- package/src/lib/read-state/result-decoder.js +79 -0
- package/src/lib/read-state/spec-builder.d.ts +47 -0
- package/src/lib/read-state/spec-builder.js +251 -0
- package/src/lib/read-state/svm-account.d.ts +20 -0
- package/src/lib/read-state/svm-account.js +114 -0
- package/src/lib/read-state/svm-pda.d.ts +13 -0
- package/src/lib/read-state/svm-pda.js +147 -0
- package/src/lib/read-state/validate.d.ts +22 -0
- package/src/lib/read-state/validate.js +80 -0
- package/src/lib/universal-tx-detector/child-inbounds.d.ts +3 -1
- package/src/lib/universal-tx-detector/child-inbounds.js +4 -5
- package/src/lib/universal-tx-detector/detector-svm.js +29 -20
- package/src/lib/universal-tx-detector/svm-events.d.ts +17 -5
- package/src/lib/universal-tx-detector/svm-events.js +81 -6
- package/src/lib/vm-client/evm-client.js +27 -10
|
@@ -5,12 +5,15 @@ import { TxBody, TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx';
|
|
|
5
5
|
import { DeliverTxResponse } from '@cosmjs/stargate';
|
|
6
6
|
import { QueryGetUniversalTxResponse } from '../generated/uexecutor/v1/query';
|
|
7
7
|
import { QueryGetUniversalTxResponseV2 } from '../generated/uexecutor/v2/query';
|
|
8
|
+
import { QueryReadsByTxResponse, QueryUniversalReadResponse } from '../generated/ucallback/v1';
|
|
8
9
|
import { EvmClient } from '../vm-client/evm-client';
|
|
9
10
|
import { PushClientOptions } from './push-client.types';
|
|
10
11
|
import { TxResponse } from '../vm-client/vm-client.types';
|
|
11
12
|
export declare class PushClient extends EvmClient {
|
|
12
|
-
/**
|
|
13
|
-
private static readonly
|
|
13
|
+
/** Conservative SDK ceiling and fallback for gasless Cosmos transactions. */
|
|
14
|
+
private static readonly DEFAULT_COSMOS_GAS_LIMIT;
|
|
15
|
+
private static readonly GASLESS_GAS_LIMIT_CACHE_TTL_MS;
|
|
16
|
+
private static readonly MSG_EXECUTE_PAYLOAD_TYPE_URL;
|
|
14
17
|
pushChainInfo: {
|
|
15
18
|
chainId: string;
|
|
16
19
|
vm: import("../constants/enums").VM;
|
|
@@ -42,6 +45,7 @@ export declare class PushClient extends EvmClient {
|
|
|
42
45
|
private readonly ephemeralKey;
|
|
43
46
|
private readonly ephemeralAccount;
|
|
44
47
|
private currentRpcIndex;
|
|
48
|
+
private gaslessGasLimitCache?;
|
|
45
49
|
/**
|
|
46
50
|
* Archive (full-history) endpoints. History-sensitive reads fall back from
|
|
47
51
|
* the prune RPC to these on a pruned-history miss. Resolved from the chain's
|
|
@@ -50,6 +54,13 @@ export declare class PushClient extends EvmClient {
|
|
|
50
54
|
*/
|
|
51
55
|
private readonly archiveTendermintRpc;
|
|
52
56
|
private readonly archivePublicClient?;
|
|
57
|
+
/**
|
|
58
|
+
* Prune endpoints with transport retries off, raced against the archive. A
|
|
59
|
+
* receipt miss on the prune node answers -32002 "Requested resource not
|
|
60
|
+
* available" after ~8 s (measured on Donut 2026-09-23), and the shared
|
|
61
|
+
* client's `http({ retryCount: 5 })` would retry that on top.
|
|
62
|
+
*/
|
|
63
|
+
private readonly pruneProbeClient?;
|
|
53
64
|
constructor(clientOptions: PushClientOptions);
|
|
54
65
|
/**
|
|
55
66
|
* Executes an operation with automatic fallback to next RPC endpoint on failure.
|
|
@@ -93,11 +104,40 @@ export declare class PushClient extends EvmClient {
|
|
|
93
104
|
* In prod, signer should be passed in instead.
|
|
94
105
|
*/
|
|
95
106
|
signCosmosTx(txBody: TxBody): Promise<TxRaw>;
|
|
107
|
+
private resolveCosmosGasLimit;
|
|
96
108
|
broadcastCosmosTx(txRaw: TxRaw): Promise<DeliverTxResponse>;
|
|
97
109
|
/**
|
|
98
110
|
* Queries Push Chain's uexecutor gRPC service for a UniversalTx by its ID.
|
|
99
111
|
*/
|
|
100
112
|
getUniversalTxById(id: string): Promise<QueryGetUniversalTxResponse>;
|
|
113
|
+
/**
|
|
114
|
+
* Queries x/ucallback for one cross-chain read by its requestId (0x-prefixed uint256 hex).
|
|
115
|
+
*
|
|
116
|
+
* Current-state query — an absent `read` is a real "does not exist", so there is
|
|
117
|
+
* deliberately no archive fallback (see getUniversalTxByIdV2 for the rationale).
|
|
118
|
+
*/
|
|
119
|
+
getUniversalRead(requestId: string): Promise<QueryUniversalReadResponse>;
|
|
120
|
+
/**
|
|
121
|
+
* Cosmos `block_results` for one height, raw over the Tendermint HTTP RPC. Push Chain
|
|
122
|
+
* runs CometBFT 0.38 and emits `finalize_block_events`, which the cosmjs 0.33 decoders
|
|
123
|
+
* still drop (they only read `end_block_events`) — hence the direct call. This is the
|
|
124
|
+
* only place the EndBlocker's work is visible: read-state expiry runs there and leaves
|
|
125
|
+
* no EVM-indexed tx or receipt. Attribute values are plain strings.
|
|
126
|
+
*/
|
|
127
|
+
getBlockResultEvents(height: number): Promise<readonly {
|
|
128
|
+
type: string;
|
|
129
|
+
attributes: readonly {
|
|
130
|
+
key: string;
|
|
131
|
+
value: string;
|
|
132
|
+
}[];
|
|
133
|
+
}[]>;
|
|
134
|
+
/**
|
|
135
|
+
* Queries x/ucallback for every read a Push transaction requested. One tx can emit
|
|
136
|
+
* several ReadRequested logs; this reassembles that batch. The node keys on the exact
|
|
137
|
+
* lowercase 0x hash, which is what the SDK's own tx responses carry — verified for
|
|
138
|
+
* both EOA and UEA-originated requests.
|
|
139
|
+
*/
|
|
140
|
+
getReadsByTx(txHash: string): Promise<QueryReadsByTxResponse>;
|
|
101
141
|
/**
|
|
102
142
|
* Queries Push Chain's uexecutor v2 gRPC service for a UniversalTx by its ID.
|
|
103
143
|
* V2 returns expanded OutboundTx fields and repeated outbound_tx array.
|
|
@@ -8,6 +8,7 @@ const proto_signing_1 = require("@cosmjs/proto-signing");
|
|
|
8
8
|
const stargate_1 = require("@cosmjs/stargate");
|
|
9
9
|
const query_1 = require("../generated/uexecutor/v1/query");
|
|
10
10
|
const query_2 = require("../generated/uexecutor/v2/query");
|
|
11
|
+
const v1_1 = require("../generated/ucallback/v1");
|
|
11
12
|
const crypto_1 = require("@cosmjs/crypto");
|
|
12
13
|
const tendermint_rpc_1 = require("@cosmjs/tendermint-rpc");
|
|
13
14
|
const auth_1 = require("cosmjs-types/cosmos/auth/v1beta1/auth");
|
|
@@ -24,13 +25,21 @@ function pushNetworkToChain(network) {
|
|
|
24
25
|
return enums_1.CHAIN.PUSH_TESTNET_DONUT;
|
|
25
26
|
return enums_1.CHAIN.PUSH_LOCALNET;
|
|
26
27
|
}
|
|
28
|
+
/** ABCI code 22 / gRPC NotFound from x/ucallback — "no read request with id …: key not found". */
|
|
29
|
+
function isUcallbackNotFound(err) {
|
|
30
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
31
|
+
return /\(22\)|code = NotFound|key not found/i.test(msg);
|
|
32
|
+
}
|
|
27
33
|
class PushClient extends evm_client_1.EvmClient {
|
|
28
|
-
/**
|
|
29
|
-
static
|
|
34
|
+
/** Conservative SDK ceiling and fallback for gasless Cosmos transactions. */
|
|
35
|
+
static DEFAULT_COSMOS_GAS_LIMIT = 100_000_000;
|
|
36
|
+
static GASLESS_GAS_LIMIT_CACHE_TTL_MS = 60_000;
|
|
37
|
+
static MSG_EXECUTE_PAYLOAD_TYPE_URL = '/uexecutor.v1.MsgExecutePayload';
|
|
30
38
|
pushChainInfo;
|
|
31
39
|
ephemeralKey;
|
|
32
40
|
ephemeralAccount;
|
|
33
41
|
currentRpcIndex = 0;
|
|
42
|
+
gaslessGasLimitCache;
|
|
34
43
|
/**
|
|
35
44
|
* Archive (full-history) endpoints. History-sensitive reads fall back from
|
|
36
45
|
* the prune RPC to these on a pruned-history miss. Resolved from the chain's
|
|
@@ -39,6 +48,13 @@ class PushClient extends evm_client_1.EvmClient {
|
|
|
39
48
|
*/
|
|
40
49
|
archiveTendermintRpc;
|
|
41
50
|
archivePublicClient;
|
|
51
|
+
/**
|
|
52
|
+
* Prune endpoints with transport retries off, raced against the archive. A
|
|
53
|
+
* receipt miss on the prune node answers -32002 "Requested resource not
|
|
54
|
+
* available" after ~8 s (measured on Donut 2026-09-23), and the shared
|
|
55
|
+
* client's `http({ retryCount: 5 })` would retry that on top.
|
|
56
|
+
*/
|
|
57
|
+
pruneProbeClient;
|
|
42
58
|
constructor(clientOptions) {
|
|
43
59
|
const pushChainKey = pushNetworkToChain(clientOptions.network);
|
|
44
60
|
const chain = clientOptions.chain ?? (0, chain_1.getPushViemChain)(pushChainKey);
|
|
@@ -57,6 +73,10 @@ class PushClient extends evm_client_1.EvmClient {
|
|
|
57
73
|
chain,
|
|
58
74
|
transport: (0, viem_1.fallback)(archiveEvmUrls.map((url) => (0, viem_1.http)(url, { retryCount: 5, retryDelay: 500 }))),
|
|
59
75
|
});
|
|
76
|
+
this.pruneProbeClient = (0, viem_1.createPublicClient)({
|
|
77
|
+
chain,
|
|
78
|
+
transport: (0, viem_1.fallback)(clientOptions.rpcUrls.map((url) => (0, viem_1.http)(url, { retryCount: 0 }))),
|
|
79
|
+
});
|
|
60
80
|
}
|
|
61
81
|
this.ephemeralKey = (0, accounts_1.generatePrivateKey)();
|
|
62
82
|
this.ephemeralAccount = (0, accounts_1.privateKeyToAccount)(this.ephemeralKey);
|
|
@@ -215,6 +235,7 @@ class PushClient extends evm_client_1.EvmClient {
|
|
|
215
235
|
const status = await tmClient.status();
|
|
216
236
|
const chainId = status.nodeInfo.network;
|
|
217
237
|
const queryClient = stargate_1.QueryClient.withExtensions(tmClient, stargate_1.setupAuthExtension);
|
|
238
|
+
const cosmosGasLimit = await this.resolveCosmosGasLimit(txBody, queryClient, chainId);
|
|
218
239
|
let baseAccount = null;
|
|
219
240
|
try {
|
|
220
241
|
const accountResp = await queryClient.auth.account(sender);
|
|
@@ -245,7 +266,7 @@ class PushClient extends evm_client_1.EvmClient {
|
|
|
245
266
|
pubkey: pubkeyEncoded,
|
|
246
267
|
sequence: baseAccount ? Number(baseAccount.sequence) : 0,
|
|
247
268
|
},
|
|
248
|
-
], [],
|
|
269
|
+
], [], cosmosGasLimit, undefined, undefined);
|
|
249
270
|
const txBodyBytes = tx_2.TxBody.encode(txBody).finish();
|
|
250
271
|
const signDoc = (0, proto_signing_1.makeSignDoc)(txBodyBytes, authInfoBytes, chainId, baseAccount ? Number(baseAccount.accountNumber) : 0);
|
|
251
272
|
const digest = (0, viem_1.keccak256)(tx_2.SignDoc.encode(signDoc).finish());
|
|
@@ -257,6 +278,42 @@ class PushClient extends evm_client_1.EvmClient {
|
|
|
257
278
|
});
|
|
258
279
|
}, 'signCosmosTx');
|
|
259
280
|
}
|
|
281
|
+
async resolveCosmosGasLimit(txBody, queryClient, chainId) {
|
|
282
|
+
const isGaslessExecutePayload = txBody.messages.length > 0 &&
|
|
283
|
+
txBody.messages.every(({ typeUrl }) => typeUrl === PushClient.MSG_EXECUTE_PAYLOAD_TYPE_URL);
|
|
284
|
+
if (!isGaslessExecutePayload) {
|
|
285
|
+
return PushClient.DEFAULT_COSMOS_GAS_LIMIT;
|
|
286
|
+
}
|
|
287
|
+
const cached = this.gaslessGasLimitCache;
|
|
288
|
+
if (cached?.chainId === chainId && cached.expiresAt > Date.now()) {
|
|
289
|
+
return cached.gasLimit;
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
const rpc = (0, stargate_1.createProtobufRpcClient)(queryClient);
|
|
293
|
+
const request = query_1.QueryParamsRequest.fromPartial({});
|
|
294
|
+
const responseBytes = await rpc.request('uexecutor.v1.Query', 'Params', query_1.QueryParamsRequest.encode(request).finish());
|
|
295
|
+
const response = query_1.QueryParamsResponse.decode(responseBytes);
|
|
296
|
+
const onChainMaximum = response.params?.maxGaslessTxGas ?? BigInt(0);
|
|
297
|
+
if (onChainMaximum > BigInt(0)) {
|
|
298
|
+
const selected = onChainMaximum < BigInt(PushClient.DEFAULT_COSMOS_GAS_LIMIT)
|
|
299
|
+
? onChainMaximum
|
|
300
|
+
: BigInt(PushClient.DEFAULT_COSMOS_GAS_LIMIT);
|
|
301
|
+
const gasLimit = Number(selected);
|
|
302
|
+
if (Number.isSafeInteger(gasLimit) && gasLimit > 0) {
|
|
303
|
+
this.gaslessGasLimitCache = {
|
|
304
|
+
chainId,
|
|
305
|
+
gasLimit,
|
|
306
|
+
expiresAt: Date.now() + PushClient.GASLESS_GAS_LIMIT_CACHE_TTL_MS,
|
|
307
|
+
};
|
|
308
|
+
return gasLimit;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
// Older/unavailable query endpoints fall back to the current safe cap.
|
|
314
|
+
}
|
|
315
|
+
return PushClient.DEFAULT_COSMOS_GAS_LIMIT;
|
|
316
|
+
}
|
|
260
317
|
async broadcastCosmosTx(txRaw) {
|
|
261
318
|
return this.executeWithRpcFallback(async (rpcUrl) => {
|
|
262
319
|
const client = await stargate_1.StargateClient.connect(rpcUrl);
|
|
@@ -276,6 +333,73 @@ class PushClient extends evm_client_1.EvmClient {
|
|
|
276
333
|
return query_1.QueryGetUniversalTxResponse.decode(responseBytes);
|
|
277
334
|
}, 'getUniversalTxById');
|
|
278
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* Queries x/ucallback for one cross-chain read by its requestId (0x-prefixed uint256 hex).
|
|
338
|
+
*
|
|
339
|
+
* Current-state query — an absent `read` is a real "does not exist", so there is
|
|
340
|
+
* deliberately no archive fallback (see getUniversalTxByIdV2 for the rationale).
|
|
341
|
+
*/
|
|
342
|
+
async getUniversalRead(requestId) {
|
|
343
|
+
const id = requestId.toLowerCase();
|
|
344
|
+
return this.executeWithRpcFallback(async (rpcUrl) => {
|
|
345
|
+
const tmClient = await tendermint_rpc_1.Tendermint34Client.connect(rpcUrl);
|
|
346
|
+
const queryClient = new stargate_1.QueryClient(tmClient);
|
|
347
|
+
const rpc = (0, stargate_1.createProtobufRpcClient)(queryClient);
|
|
348
|
+
const request = v1_1.QueryUniversalReadRequest.fromPartial({ requestId: id });
|
|
349
|
+
try {
|
|
350
|
+
const responseBytes = await rpc.request(v1_1.UCALLBACK_QUERY_SERVICE, 'UniversalRead', v1_1.QueryUniversalReadRequest.encode(request).finish());
|
|
351
|
+
return v1_1.QueryUniversalReadResponse.decode(responseBytes);
|
|
352
|
+
}
|
|
353
|
+
catch (err) {
|
|
354
|
+
// The node answers an unknown id with ABCI code 22 (sdk NotFound), which cosmjs
|
|
355
|
+
// throws. That is a deterministic miss, not a transport failure — classify it
|
|
356
|
+
// here so the RPC fallback does not retry it on every endpoint.
|
|
357
|
+
if (isUcallbackNotFound(err))
|
|
358
|
+
return v1_1.QueryUniversalReadResponse.fromPartial({});
|
|
359
|
+
throw err;
|
|
360
|
+
}
|
|
361
|
+
}, 'getUniversalRead');
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Cosmos `block_results` for one height, raw over the Tendermint HTTP RPC. Push Chain
|
|
365
|
+
* runs CometBFT 0.38 and emits `finalize_block_events`, which the cosmjs 0.33 decoders
|
|
366
|
+
* still drop (they only read `end_block_events`) — hence the direct call. This is the
|
|
367
|
+
* only place the EndBlocker's work is visible: read-state expiry runs there and leaves
|
|
368
|
+
* no EVM-indexed tx or receipt. Attribute values are plain strings.
|
|
369
|
+
*/
|
|
370
|
+
async getBlockResultEvents(height) {
|
|
371
|
+
// Prune nodes drop old heights ("height N is not available"); the archive keeps them.
|
|
372
|
+
return this.executeWithArchiveFallback(async (rpcUrl) => {
|
|
373
|
+
const url = `${rpcUrl.replace(/\/+$/, '')}/block_results?height=${height}`;
|
|
374
|
+
const res = await fetch(url);
|
|
375
|
+
// CometBFT answers a pruned height with HTTP 500 plus a JSON-RPC error. Surface that
|
|
376
|
+
// error so it reads as a definite miss (→ archive), not a transient HTTP failure to retry.
|
|
377
|
+
const body = (await res.json().catch(() => undefined));
|
|
378
|
+
if (body?.error)
|
|
379
|
+
throw new Error(`block_results ${height}: ${body.error.data ?? body.error.message ?? 'error'}`);
|
|
380
|
+
if (!res.ok || !body)
|
|
381
|
+
throw new Error(`HTTP request failed: ${res.status} ${url}`);
|
|
382
|
+
const events = body.result?.finalize_block_events ?? body.result?.end_block_events ?? [];
|
|
383
|
+
return events;
|
|
384
|
+
}, 'getBlockResultEvents', () => false);
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Queries x/ucallback for every read a Push transaction requested. One tx can emit
|
|
388
|
+
* several ReadRequested logs; this reassembles that batch. The node keys on the exact
|
|
389
|
+
* lowercase 0x hash, which is what the SDK's own tx responses carry — verified for
|
|
390
|
+
* both EOA and UEA-originated requests.
|
|
391
|
+
*/
|
|
392
|
+
async getReadsByTx(txHash) {
|
|
393
|
+
const hash = txHash.toLowerCase();
|
|
394
|
+
return this.executeWithRpcFallback(async (rpcUrl) => {
|
|
395
|
+
const tmClient = await tendermint_rpc_1.Tendermint34Client.connect(rpcUrl);
|
|
396
|
+
const queryClient = new stargate_1.QueryClient(tmClient);
|
|
397
|
+
const rpc = (0, stargate_1.createProtobufRpcClient)(queryClient);
|
|
398
|
+
const request = v1_1.QueryReadsByTxRequest.fromPartial({ txHash: hash });
|
|
399
|
+
const responseBytes = await rpc.request(v1_1.UCALLBACK_QUERY_SERVICE, 'ReadsByTx', v1_1.QueryReadsByTxRequest.encode(request).finish());
|
|
400
|
+
return v1_1.QueryReadsByTxResponse.decode(responseBytes);
|
|
401
|
+
}, 'getReadsByTx');
|
|
402
|
+
}
|
|
279
403
|
/**
|
|
280
404
|
* Queries Push Chain's uexecutor v2 gRPC service for a UniversalTx by its ID.
|
|
281
405
|
* V2 returns expanded OutboundTx fields and repeated outbound_tx array.
|
|
@@ -356,7 +480,10 @@ class PushClient extends evm_client_1.EvmClient {
|
|
|
356
480
|
throw error;
|
|
357
481
|
const archiveClient = this.archivePublicClient;
|
|
358
482
|
const tx = await archiveClient.getTransaction({ hash: txHash });
|
|
359
|
-
const wait = async (confirmations = 1) => archiveClient.waitForTransactionReceipt({
|
|
483
|
+
const wait = async (confirmations = 1) => archiveClient.waitForTransactionReceipt({
|
|
484
|
+
hash: txHash,
|
|
485
|
+
confirmations,
|
|
486
|
+
});
|
|
360
487
|
return { ...tx, wait };
|
|
361
488
|
}
|
|
362
489
|
}
|
|
@@ -366,17 +493,29 @@ class PushClient extends evm_client_1.EvmClient {
|
|
|
366
493
|
* Prune first; on not-found, retry the archive EVM client if configured.
|
|
367
494
|
*/
|
|
368
495
|
async getTransactionReceiptWithArchiveFallback(txHash) {
|
|
369
|
-
|
|
370
|
-
return
|
|
371
|
-
}
|
|
372
|
-
catch (error) {
|
|
373
|
-
if (!this.hasArchiveEvm)
|
|
374
|
-
throw error;
|
|
375
|
-
return this.archivePublicClient.getTransactionReceipt({
|
|
376
|
-
hash: txHash,
|
|
377
|
-
});
|
|
496
|
+
if (!this.hasArchiveEvm || !this.pruneProbeClient) {
|
|
497
|
+
return this.publicClient.getTransactionReceipt({ hash: txHash });
|
|
378
498
|
}
|
|
499
|
+
// Race prune and archive; the first receipt wins. A pruned receipt costs one
|
|
500
|
+
// archive round trip, a fresh one the prune round trip (if the archive lags).
|
|
501
|
+
const prune = this.pruneProbeClient.getTransactionReceipt({ hash: txHash });
|
|
502
|
+
const archive = this.archivePublicClient.getTransactionReceipt({
|
|
503
|
+
hash: txHash,
|
|
504
|
+
});
|
|
505
|
+
return firstFulfilled([archive, prune]);
|
|
379
506
|
}
|
|
380
507
|
}
|
|
381
508
|
exports.PushClient = PushClient;
|
|
509
|
+
/** First promise to resolve; if all reject, the last rejection. */
|
|
510
|
+
function firstFulfilled(promises) {
|
|
511
|
+
return new Promise((resolve, reject) => {
|
|
512
|
+
let pending = promises.length;
|
|
513
|
+
for (const p of promises) {
|
|
514
|
+
p.then(resolve, (error) => {
|
|
515
|
+
if (--pending === 0)
|
|
516
|
+
reject(error);
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
}
|
|
382
521
|
//# sourceMappingURL=push-client.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gas price assumed when the chain reports 0 (dev chains). Donut charges 1 gwei per
|
|
3
|
+
* gas on module fulfil txs (verified: 118,289 gas → 118,289 × 10⁹ wei burned).
|
|
4
|
+
*/
|
|
5
|
+
export declare const MIN_CALLBACK_BUDGET_GAS_PRICE = 1000000000n;
|
|
6
|
+
/**
|
|
7
|
+
* Size the callback budget escrowed on top of the protocol fee.
|
|
8
|
+
*
|
|
9
|
+
* msg.value = protocolFee + callbackBudget
|
|
10
|
+
*
|
|
11
|
+
* The node refuses to fulfil a read whose budget cannot cover its callback
|
|
12
|
+
* ("callback budget too small") and lets it expire with the fee already spent, so a
|
|
13
|
+
* zero or thin budget is a guaranteed loss. This errs high by `buffer`; whatever the
|
|
14
|
+
* callback does not burn is pushed back to `refundTo` at settlement.
|
|
15
|
+
*/
|
|
16
|
+
export declare function sizeCallbackBudget(callbackGasLimit: bigint, pushGasPrice: bigint, buffer?: number): bigint;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MIN_CALLBACK_BUDGET_GAS_PRICE = void 0;
|
|
4
|
+
exports.sizeCallbackBudget = sizeCallbackBudget;
|
|
5
|
+
const read_state_1 = require("../constants/read-state");
|
|
6
|
+
const errors_1 = require("./errors");
|
|
7
|
+
/**
|
|
8
|
+
* Gas price assumed when the chain reports 0 (dev chains). Donut charges 1 gwei per
|
|
9
|
+
* gas on module fulfil txs (verified: 118,289 gas → 118,289 × 10⁹ wei burned).
|
|
10
|
+
*/
|
|
11
|
+
exports.MIN_CALLBACK_BUDGET_GAS_PRICE = 1000000000n;
|
|
12
|
+
/**
|
|
13
|
+
* Size the callback budget escrowed on top of the protocol fee.
|
|
14
|
+
*
|
|
15
|
+
* msg.value = protocolFee + callbackBudget
|
|
16
|
+
*
|
|
17
|
+
* The node refuses to fulfil a read whose budget cannot cover its callback
|
|
18
|
+
* ("callback budget too small") and lets it expire with the fee already spent, so a
|
|
19
|
+
* zero or thin budget is a guaranteed loss. This errs high by `buffer`; whatever the
|
|
20
|
+
* callback does not burn is pushed back to `refundTo` at settlement.
|
|
21
|
+
*/
|
|
22
|
+
function sizeCallbackBudget(callbackGasLimit, pushGasPrice, buffer = read_state_1.CALLBACK_BUDGET_BUFFER) {
|
|
23
|
+
if (callbackGasLimit <= 0n)
|
|
24
|
+
throw new errors_1.InvalidReadQueryError('callbackGasLimit must be > 0');
|
|
25
|
+
if (!Number.isInteger(buffer) || buffer < 1)
|
|
26
|
+
throw new errors_1.InvalidReadQueryError('budget buffer must be an integer ≥ 1');
|
|
27
|
+
const price = pushGasPrice > 0n ? pushGasPrice : exports.MIN_CALLBACK_BUDGET_GAS_PRICE;
|
|
28
|
+
const budget = callbackGasLimit * price * BigInt(buffer);
|
|
29
|
+
// cannot be zero by construction, but the invariant is worth stating
|
|
30
|
+
return budget > 0n ? budget : 1n;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=budget.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReadDestination, ResolvedDestination } from './read-state.types';
|
|
2
|
+
/**
|
|
3
|
+
* Split a destination into the pieces the contract, the oracle and the node use.
|
|
4
|
+
*
|
|
5
|
+
* - `ReadSpec.account.chainNamespace` / `chainId` are the two halves.
|
|
6
|
+
* - `UniversalCore.chainHeightByChainNamespace` is keyed by the JOINED `caip2`.
|
|
7
|
+
* - The node routes on `chainNamespace + ":" + chainId`.
|
|
8
|
+
*
|
|
9
|
+
* Passing the joined form as the namespace would produce `eip155:1:1` on the node,
|
|
10
|
+
* so it is rejected here.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveDestination(dest: ReadDestination): ResolvedDestination;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveDestination = resolveDestination;
|
|
4
|
+
const read_state_1 = require("../constants/read-state");
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
const KNOWN = new Set(Object.values(read_state_1.READ_NAMESPACE));
|
|
7
|
+
/**
|
|
8
|
+
* Split a destination into the pieces the contract, the oracle and the node use.
|
|
9
|
+
*
|
|
10
|
+
* - `ReadSpec.account.chainNamespace` / `chainId` are the two halves.
|
|
11
|
+
* - `UniversalCore.chainHeightByChainNamespace` is keyed by the JOINED `caip2`.
|
|
12
|
+
* - The node routes on `chainNamespace + ":" + chainId`.
|
|
13
|
+
*
|
|
14
|
+
* Passing the joined form as the namespace would produce `eip155:1:1` on the node,
|
|
15
|
+
* so it is rejected here.
|
|
16
|
+
*/
|
|
17
|
+
function resolveDestination(dest) {
|
|
18
|
+
let chainNamespace;
|
|
19
|
+
let chainId;
|
|
20
|
+
if ('chain' in dest) {
|
|
21
|
+
const idx = dest.chain.indexOf(':');
|
|
22
|
+
if (idx <= 0) {
|
|
23
|
+
throw new errors_1.UnsupportedReadDestinationError(`chain is not CAIP-2: ${dest.chain}`);
|
|
24
|
+
}
|
|
25
|
+
chainNamespace = dest.chain.slice(0, idx);
|
|
26
|
+
chainId = dest.chain.slice(idx + 1);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
chainNamespace = dest.chainNamespace;
|
|
30
|
+
chainId = dest.chainId;
|
|
31
|
+
}
|
|
32
|
+
if (!chainNamespace || !chainId) {
|
|
33
|
+
throw new errors_1.UnsupportedReadDestinationError('destination needs both chainNamespace and chainId');
|
|
34
|
+
}
|
|
35
|
+
if (chainNamespace.includes(':')) {
|
|
36
|
+
throw new errors_1.UnsupportedReadDestinationError(`chainNamespace must be the bare namespace, not CAIP-2: ${chainNamespace}`, { hint: 'Pass { chainNamespace: "eip155", chainId: "1" } or { chain: CHAIN.X }.' });
|
|
37
|
+
}
|
|
38
|
+
if (!KNOWN.has(chainNamespace)) {
|
|
39
|
+
throw new errors_1.UnsupportedReadDestinationError(`unsupported read namespace: ${chainNamespace}`, {
|
|
40
|
+
destination: `${chainNamespace}:${chainId}`,
|
|
41
|
+
hint: `Supported: ${[...KNOWN].join(', ')}`,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
chainNamespace,
|
|
46
|
+
chainId,
|
|
47
|
+
caip2: `${chainNamespace}:${chainId}`,
|
|
48
|
+
namespace: chainNamespace,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=destination.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Hex } from 'viem';
|
|
2
|
+
import type { EncodedReadQuery, EvmReadQuery } from '../read-state.types';
|
|
3
|
+
/** `universalClient/externalchains/evm/read_envelope.go` — evmQueryType. */
|
|
4
|
+
export declare const EVM_QUERY_TYPE: {
|
|
5
|
+
readonly ACCOUNT_BALANCE: 0;
|
|
6
|
+
readonly CONTRACT_CALL: 1;
|
|
7
|
+
readonly STORAGE_SLOT: 2;
|
|
8
|
+
};
|
|
9
|
+
/** Normalise a storage slot (hex or bigint) to bytes32. */
|
|
10
|
+
export declare function toStorageSlot(slot: Hex | bigint): Hex;
|
|
11
|
+
/**
|
|
12
|
+
* Encode an `eip155` read query. Pure — `blockNumber` is the pinned destination
|
|
13
|
+
* height and is also mirrored into `ReadSpec.blockNumber` by the spec builder.
|
|
14
|
+
*/
|
|
15
|
+
export declare function encodeEvmQueryEnvelope(query: EvmReadQuery, options: {
|
|
16
|
+
blockNumber: bigint;
|
|
17
|
+
}): EncodedReadQuery;
|
|
18
|
+
/** Decode an envelope with the exact tuple shape the validator uses. */
|
|
19
|
+
export declare function decodeEvmQueryEnvelope(encoded: Hex): {
|
|
20
|
+
queryType: number;
|
|
21
|
+
refType: number;
|
|
22
|
+
blockNumber: bigint;
|
|
23
|
+
payload: Hex;
|
|
24
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EVM_QUERY_TYPE = void 0;
|
|
4
|
+
exports.toStorageSlot = toStorageSlot;
|
|
5
|
+
exports.encodeEvmQueryEnvelope = encodeEvmQueryEnvelope;
|
|
6
|
+
exports.decodeEvmQueryEnvelope = decodeEvmQueryEnvelope;
|
|
7
|
+
const viem_1 = require("viem");
|
|
8
|
+
const read_state_1 = require("../../constants/read-state");
|
|
9
|
+
const errors_1 = require("../errors");
|
|
10
|
+
/** `universalClient/externalchains/evm/read_envelope.go` — evmQueryType. */
|
|
11
|
+
exports.EVM_QUERY_TYPE = {
|
|
12
|
+
ACCOUNT_BALANCE: 0,
|
|
13
|
+
CONTRACT_CALL: 1,
|
|
14
|
+
STORAGE_SLOT: 2,
|
|
15
|
+
};
|
|
16
|
+
/** Only AT_NUMBER exists in v1. */
|
|
17
|
+
const EVM_BLOCK_REF_AT_NUMBER = 0;
|
|
18
|
+
/**
|
|
19
|
+
* The validator unpacks `abi.Arguments{ ONE tuple }`. The envelope MUST therefore be
|
|
20
|
+
* `abi.encode(struct)` — a single dynamic tuple with a 0x20 head offset — never the
|
|
21
|
+
* fields as separate parameters. The three-parameter layout parses only by coincidence
|
|
22
|
+
* when queryType == 0 and cost the first live read (2026-09-09).
|
|
23
|
+
*/
|
|
24
|
+
const EVM_ENVELOPE_ABI = [
|
|
25
|
+
{
|
|
26
|
+
type: 'tuple',
|
|
27
|
+
components: [
|
|
28
|
+
{ name: 'queryType', type: 'uint8' },
|
|
29
|
+
{
|
|
30
|
+
name: 'blockRef',
|
|
31
|
+
type: 'tuple',
|
|
32
|
+
components: [
|
|
33
|
+
{ name: 'refType', type: 'uint8' },
|
|
34
|
+
{ name: 'blockNumber', type: 'uint64' },
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
{ name: 'payload', type: 'bytes' },
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
const UINT64_MAX = (1n << 64n) - 1n;
|
|
42
|
+
function assertAddress(value, what) {
|
|
43
|
+
if (!(0, viem_1.isAddress)(value))
|
|
44
|
+
throw new errors_1.InvalidReadQueryError(`${what} is not an EVM address: ${value}`);
|
|
45
|
+
}
|
|
46
|
+
function assertBlockNumber(blockNumber) {
|
|
47
|
+
if (blockNumber < 0n || blockNumber > UINT64_MAX) {
|
|
48
|
+
throw new errors_1.InvalidReadQueryError(`blockNumber out of uint64 range: ${blockNumber}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Normalise a storage slot (hex or bigint) to bytes32. */
|
|
52
|
+
function toStorageSlot(slot) {
|
|
53
|
+
if (typeof slot === 'bigint') {
|
|
54
|
+
if (slot < 0n || slot >= 1n << 256n)
|
|
55
|
+
throw new errors_1.InvalidReadQueryError(`storage slot out of range: ${slot}`);
|
|
56
|
+
return (0, viem_1.toHex)(slot, { size: 32 });
|
|
57
|
+
}
|
|
58
|
+
if (!(0, viem_1.isHex)(slot))
|
|
59
|
+
throw new errors_1.InvalidReadQueryError(`storage slot is not hex: ${slot}`);
|
|
60
|
+
if ((0, viem_1.size)(slot) > 32)
|
|
61
|
+
throw new errors_1.InvalidReadQueryError(`storage slot longer than 32 bytes: ${slot}`);
|
|
62
|
+
return (0, viem_1.pad)(slot, { size: 32 });
|
|
63
|
+
}
|
|
64
|
+
function encodeEnvelope(queryType, blockNumber, payload) {
|
|
65
|
+
return (0, viem_1.encodeAbiParameters)(EVM_ENVELOPE_ABI, [
|
|
66
|
+
{ queryType, blockRef: { refType: EVM_BLOCK_REF_AT_NUMBER, blockNumber }, payload },
|
|
67
|
+
]);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Encode an `eip155` read query. Pure — `blockNumber` is the pinned destination
|
|
71
|
+
* height and is also mirrored into `ReadSpec.blockNumber` by the spec builder.
|
|
72
|
+
*/
|
|
73
|
+
function encodeEvmQueryEnvelope(query, options) {
|
|
74
|
+
const { blockNumber } = options;
|
|
75
|
+
assertBlockNumber(blockNumber);
|
|
76
|
+
assertAddress(query.target, 'target');
|
|
77
|
+
let queryType;
|
|
78
|
+
let payload;
|
|
79
|
+
let resultShape;
|
|
80
|
+
switch (query.type) {
|
|
81
|
+
case 'accountBalance': {
|
|
82
|
+
queryType = exports.EVM_QUERY_TYPE.ACCOUNT_BALANCE;
|
|
83
|
+
// abi.encode(address) — 32 bytes. The raw 20-byte address is rejected by validators.
|
|
84
|
+
payload = (0, viem_1.encodeAbiParameters)([{ type: 'address' }], [query.target]);
|
|
85
|
+
resultShape = { kind: 'uint256' };
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case 'contractCall': {
|
|
89
|
+
queryType = exports.EVM_QUERY_TYPE.CONTRACT_CALL;
|
|
90
|
+
let callData;
|
|
91
|
+
if ('callData' in query) {
|
|
92
|
+
if (!(0, viem_1.isHex)(query.callData) || (0, viem_1.size)(query.callData) < 4) {
|
|
93
|
+
throw new errors_1.InvalidReadQueryError('callData must be hex with at least a 4-byte selector');
|
|
94
|
+
}
|
|
95
|
+
callData = query.callData;
|
|
96
|
+
resultShape = { kind: 'raw' };
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
const item = (0, viem_1.getAbiItem)({
|
|
100
|
+
abi: query.abi,
|
|
101
|
+
name: query.functionName,
|
|
102
|
+
args: query.args,
|
|
103
|
+
});
|
|
104
|
+
if (!item || item.type !== 'function') {
|
|
105
|
+
throw new errors_1.InvalidReadQueryError(`function not found in abi: ${query.functionName}`);
|
|
106
|
+
}
|
|
107
|
+
// Any mutability: validators run the call as an eth_call simulation at the
|
|
108
|
+
// pinned block, so nonpayable/payable functions return data and never execute.
|
|
109
|
+
callData = (0, viem_1.encodeFunctionData)({
|
|
110
|
+
abi: query.abi,
|
|
111
|
+
functionName: query.functionName,
|
|
112
|
+
args: query.args,
|
|
113
|
+
});
|
|
114
|
+
resultShape = { kind: 'evmCall', abi: [item], functionName: query.functionName };
|
|
115
|
+
}
|
|
116
|
+
payload = (0, viem_1.encodeAbiParameters)([{ type: 'address' }, { type: 'bytes' }], [query.target, callData]);
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
case 'storageSlot': {
|
|
120
|
+
queryType = exports.EVM_QUERY_TYPE.STORAGE_SLOT;
|
|
121
|
+
payload = (0, viem_1.encodeAbiParameters)([{ type: 'address' }, { type: 'bytes32' }], [query.target, toStorageSlot(query.slot)]);
|
|
122
|
+
resultShape = { kind: 'bytes32' };
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
default:
|
|
126
|
+
throw new errors_1.InvalidReadQueryError(`unknown EVM query type: ${query.type}`);
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
namespace: read_state_1.READ_NAMESPACE.EVM,
|
|
130
|
+
queryType,
|
|
131
|
+
encoded: encodeEnvelope(queryType, blockNumber, payload),
|
|
132
|
+
blockRef: blockNumber,
|
|
133
|
+
resultShape,
|
|
134
|
+
warnings: [],
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/** Decode an envelope with the exact tuple shape the validator uses. */
|
|
138
|
+
function decodeEvmQueryEnvelope(encoded) {
|
|
139
|
+
const [env] = (0, viem_1.decodeAbiParameters)(EVM_ENVELOPE_ABI, encoded);
|
|
140
|
+
return {
|
|
141
|
+
queryType: env.queryType,
|
|
142
|
+
refType: env.blockRef.refType,
|
|
143
|
+
blockNumber: env.blockRef.blockNumber,
|
|
144
|
+
payload: env.payload,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=evm.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { EncodedReadQuery, ReadDestination, ReadQuery } from '../read-state.types';
|
|
2
|
+
export * from './evm';
|
|
3
|
+
export * from './svm';
|
|
4
|
+
export * from './web2';
|
|
5
|
+
/**
|
|
6
|
+
* Encode any read query for its destination. Rejects a query kind that does not
|
|
7
|
+
* belong to the destination's namespace (e.g. a `storageSlot` read against Solana).
|
|
8
|
+
*/
|
|
9
|
+
export declare function encodeReadQuery(destination: ReadDestination, query: ReadQuery, options?: {
|
|
10
|
+
blockNumber?: bigint;
|
|
11
|
+
minSlot?: bigint;
|
|
12
|
+
}): EncodedReadQuery;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.encodeReadQuery = encodeReadQuery;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const read_state_1 = require("../../constants/read-state");
|
|
6
|
+
const destination_1 = require("../destination");
|
|
7
|
+
const errors_1 = require("../errors");
|
|
8
|
+
const evm_1 = require("./evm");
|
|
9
|
+
const svm_1 = require("./svm");
|
|
10
|
+
const web2_1 = require("./web2");
|
|
11
|
+
tslib_1.__exportStar(require("./evm"), exports);
|
|
12
|
+
tslib_1.__exportStar(require("./svm"), exports);
|
|
13
|
+
tslib_1.__exportStar(require("./web2"), exports);
|
|
14
|
+
const EVM_TYPES = new Set(['accountBalance', 'contractCall', 'storageSlot']);
|
|
15
|
+
const SVM_TYPES = new Set(['lamportBalance', 'splTokenAccount', 'rawAccountData']);
|
|
16
|
+
/**
|
|
17
|
+
* Encode any read query for its destination. Rejects a query kind that does not
|
|
18
|
+
* belong to the destination's namespace (e.g. a `storageSlot` read against Solana).
|
|
19
|
+
*/
|
|
20
|
+
function encodeReadQuery(destination, query, options = {}) {
|
|
21
|
+
const dest = (0, destination_1.resolveDestination)(destination);
|
|
22
|
+
switch (dest.namespace) {
|
|
23
|
+
case read_state_1.READ_NAMESPACE.EVM: {
|
|
24
|
+
if (!EVM_TYPES.has(query.type))
|
|
25
|
+
throw new errors_1.InvalidReadQueryError(`query type ${query.type} is not valid for ${dest.caip2}`);
|
|
26
|
+
if (options.blockNumber === undefined) {
|
|
27
|
+
throw new errors_1.InvalidReadQueryError('EVM reads need options.blockNumber (the pinned destination height)');
|
|
28
|
+
}
|
|
29
|
+
return (0, evm_1.encodeEvmQueryEnvelope)(query, { blockNumber: options.blockNumber });
|
|
30
|
+
}
|
|
31
|
+
case read_state_1.READ_NAMESPACE.SVM: {
|
|
32
|
+
if (!SVM_TYPES.has(query.type))
|
|
33
|
+
throw new errors_1.InvalidReadQueryError(`query type ${query.type} is not valid for ${dest.caip2}`);
|
|
34
|
+
return (0, svm_1.encodeSvmQueryEnvelope)(query, { minSlot: options.minSlot });
|
|
35
|
+
}
|
|
36
|
+
case read_state_1.READ_NAMESPACE.WEB2: {
|
|
37
|
+
if (query.type !== 'http')
|
|
38
|
+
throw new errors_1.InvalidReadQueryError(`query type ${query.type} is not valid for web2`);
|
|
39
|
+
return (0, web2_1.encodeWeb2QueryEnvelope)(query);
|
|
40
|
+
}
|
|
41
|
+
default:
|
|
42
|
+
throw new errors_1.UnsupportedReadDestinationError(`unsupported namespace: ${dest.namespace}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=index.js.map
|