@pushchain/core 6.0.23 → 6.0.25
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 +84 -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 +23 -1
- package/src/lib/constants/enums.d.ts +7 -0
- package/src/lib/constants/enums.js +11 -0
- package/src/lib/constants/index.d.ts +52 -0
- package/src/lib/constants/index.js +37 -8
- package/src/lib/constants/read-state.d.ts +53 -0
- package/src/lib/constants/read-state.js +59 -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 +37 -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 +271 -0
- package/src/lib/progress-hook/progress-hook.types.d.ts +32 -0
- package/src/lib/progress-hook/progress-hook.types.js +34 -0
- package/src/lib/push-chain/push-chain.d.ts +70 -0
- package/src/lib/push-chain/push-chain.js +27 -0
- package/src/lib/push-client/push-client.d.ts +35 -2
- package/src/lib/push-client/push-client.js +117 -4
- 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 +148 -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 +107 -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 +212 -0
- package/src/lib/read-state/read-params.d.ts +205 -0
- package/src/lib/read-state/read-params.js +120 -0
- package/src/lib/read-state/read-state.types.d.ts +417 -0
- package/src/lib/read-state/read-state.types.js +50 -0
- package/src/lib/read-state/read-tracker.d.ts +50 -0
- package/src/lib/read-state/read-tracker.js +415 -0
- package/src/lib/read-state/registry.d.ts +21 -0
- package/src/lib/read-state/registry.js +54 -0
- package/src/lib/read-state/result-decoder.d.ts +16 -0
- package/src/lib/read-state/result-decoder.js +73 -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/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
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ERC20_BALANCE_OF_ABI = void 0;
|
|
4
|
+
exports.toReadDestination = toReadDestination;
|
|
5
|
+
exports.toReadQuery = toReadQuery;
|
|
6
|
+
exports.toBuildReadSpecParams = toBuildReadSpecParams;
|
|
7
|
+
exports.getReadQueryKey = getReadQueryKey;
|
|
8
|
+
exports.toLifecycleOptions = toLifecycleOptions;
|
|
9
|
+
const viem_1 = require("viem");
|
|
10
|
+
const enums_1 = require("../constants/enums");
|
|
11
|
+
const registry_1 = require("./registry");
|
|
12
|
+
const read_state_1 = require("../constants/read-state");
|
|
13
|
+
const destination_1 = require("./destination");
|
|
14
|
+
const svm_1 = require("./envelopes/svm");
|
|
15
|
+
const errors_1 = require("./errors");
|
|
16
|
+
/** Just `balanceOf` — it also types the decoded result as uint256. */
|
|
17
|
+
exports.ERC20_BALANCE_OF_ABI = [
|
|
18
|
+
{
|
|
19
|
+
type: 'function',
|
|
20
|
+
name: 'balanceOf',
|
|
21
|
+
stateMutability: 'view',
|
|
22
|
+
inputs: [{ name: 'account', type: 'address' }],
|
|
23
|
+
outputs: [{ name: '', type: 'uint256' }],
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
const QUERY_KEYS = ['token', 'abi', 'storageSlot', 'web2'];
|
|
27
|
+
function queryKind(o) {
|
|
28
|
+
const present = QUERY_KEYS.filter((k) => o[k] !== undefined);
|
|
29
|
+
if (present.length > 1) {
|
|
30
|
+
throw new errors_1.InvalidReadQueryError(`query keys are mutually exclusive, got ${present.join(' + ')}`);
|
|
31
|
+
}
|
|
32
|
+
if ((o.functionName !== undefined || o.args !== undefined) && o.abi === undefined) {
|
|
33
|
+
throw new errors_1.InvalidReadQueryError('functionName and args need abi');
|
|
34
|
+
}
|
|
35
|
+
return present[0] ?? 'native';
|
|
36
|
+
}
|
|
37
|
+
function toReadDestination(chain) {
|
|
38
|
+
return chain === enums_1.CHAIN.WEB2 ? read_state_1.WEB2_DESTINATION : { chain };
|
|
39
|
+
}
|
|
40
|
+
/** Build the internal query from the public grammar. Pure. */
|
|
41
|
+
function toReadQuery(subject, o) {
|
|
42
|
+
const dest = (0, destination_1.resolveDestination)(toReadDestination(o.chain));
|
|
43
|
+
const kind = queryKind(o);
|
|
44
|
+
if (o.tokenProgram !== undefined && (dest.namespace !== read_state_1.READ_NAMESPACE.SVM || kind !== 'token' || !['spl-token', 'token-2022'].includes(o.tokenProgram))) {
|
|
45
|
+
throw new errors_1.InvalidReadQueryError('tokenProgram requires a Solana token balance query and must be spl-token or token-2022');
|
|
46
|
+
}
|
|
47
|
+
if (dest.namespace === read_state_1.READ_NAMESPACE.WEB2) {
|
|
48
|
+
if (kind !== 'web2' || !o.web2)
|
|
49
|
+
throw new errors_1.InvalidReadQueryError('a web2 read needs the `web2` option and no other query key');
|
|
50
|
+
if (!/^https:\/\//i.test(subject))
|
|
51
|
+
throw new errors_1.InvalidReadQueryError('web2 subject must be an https:// URL');
|
|
52
|
+
return { type: 'http', url: subject, ...o.web2 };
|
|
53
|
+
}
|
|
54
|
+
if (kind === 'web2')
|
|
55
|
+
throw new errors_1.InvalidReadQueryError('`web2` is only valid with chain CHAIN.WEB2');
|
|
56
|
+
if (dest.namespace === read_state_1.READ_NAMESPACE.EVM) {
|
|
57
|
+
if (!(0, viem_1.isAddress)(subject))
|
|
58
|
+
throw new errors_1.InvalidReadQueryError(`EVM subject must be an address, got ${subject}`);
|
|
59
|
+
switch (kind) {
|
|
60
|
+
case 'native':
|
|
61
|
+
return { type: 'accountBalance', target: subject };
|
|
62
|
+
case 'token': {
|
|
63
|
+
const token = o.token;
|
|
64
|
+
if (!(0, viem_1.isAddress)(token))
|
|
65
|
+
throw new errors_1.InvalidReadQueryError(`token must be an address, got ${token}`);
|
|
66
|
+
return { type: 'contractCall', target: token, abi: exports.ERC20_BALANCE_OF_ABI, functionName: 'balanceOf', args: [subject] };
|
|
67
|
+
}
|
|
68
|
+
case 'abi':
|
|
69
|
+
if (!o.functionName)
|
|
70
|
+
throw new errors_1.InvalidReadQueryError('abi needs functionName');
|
|
71
|
+
return { type: 'contractCall', target: subject, abi: o.abi, functionName: o.functionName, args: o.args };
|
|
72
|
+
case 'storageSlot':
|
|
73
|
+
return { type: 'storageSlot', target: subject, slot: o.storageSlot };
|
|
74
|
+
default:
|
|
75
|
+
throw new errors_1.InvalidReadQueryError(`unsupported query for eip155: ${kind}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// SVM: the account rides in ReadSpec.account.owner; the ATA is derived here, no network.
|
|
79
|
+
switch (kind) {
|
|
80
|
+
case 'native':
|
|
81
|
+
return { type: 'lamportBalance', account: subject };
|
|
82
|
+
case 'token':
|
|
83
|
+
return { type: 'splTokenAccount', account: (0, svm_1.deriveAssociatedTokenAddress)(subject, o.token, o.tokenProgram === 'token-2022' ? svm_1.TOKEN_2022_PROGRAM_ID : svm_1.TOKEN_PROGRAM_ID).toBase58() };
|
|
84
|
+
default:
|
|
85
|
+
throw new errors_1.InvalidReadQueryError(`unsupported query for solana: ${kind} (program reads land with idl support)`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** Public options → the spec builder's params. Pure; throws `InvalidReadQueryError` on a malformed request. */
|
|
89
|
+
function toBuildReadSpecParams(subject, o, network = enums_1.PUSH_NETWORK.TESTNET_DONUT) {
|
|
90
|
+
const destination = toReadDestination(o.chain);
|
|
91
|
+
const namespace = (0, destination_1.resolveDestination)(destination).namespace;
|
|
92
|
+
if (namespace !== read_state_1.READ_NAMESPACE.EVM && (o.blockNumber !== undefined || o.minConfirmations !== undefined)) {
|
|
93
|
+
throw new errors_1.InvalidReadQueryError(`${namespace} reads do not expose blockNumber or minConfirmations; the SDK selects the read reference internally`);
|
|
94
|
+
}
|
|
95
|
+
const query = toReadQuery(subject, o);
|
|
96
|
+
const callback = (0, registry_1.resolveReadCallback)(o.callback, network, (0, registry_1.computeReadQueryKey)(destination, query));
|
|
97
|
+
return {
|
|
98
|
+
callback,
|
|
99
|
+
destination,
|
|
100
|
+
query,
|
|
101
|
+
callbackGasLimit: callback.gasLimit,
|
|
102
|
+
refundTo: o.refundTo,
|
|
103
|
+
minConfirmations: o.minConfirmations,
|
|
104
|
+
blockNumber: o.blockNumber,
|
|
105
|
+
expiryBlocks: o.expiryBlocks,
|
|
106
|
+
maxFee: o.maxFee,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/** Offline logical query key for the registry's latestResult lookup. */
|
|
110
|
+
function getReadQueryKey(subject, options) {
|
|
111
|
+
return (0, registry_1.computeReadQueryKey)(toReadDestination(options.chain), toReadQuery(subject, options));
|
|
112
|
+
}
|
|
113
|
+
function toLifecycleOptions(o) {
|
|
114
|
+
return {
|
|
115
|
+
pollingIntervalMs: o?.advanced?.pollingIntervalMs,
|
|
116
|
+
timeoutMs: o?.advanced?.timeout,
|
|
117
|
+
resultShape: o?.resultShape,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=read-params.js.map
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import type { Abi, Address, Hex } from 'viem';
|
|
2
|
+
import type { CHAIN } from '../constants/enums';
|
|
3
|
+
import type { ReadNamespace } from '../constants/read-state';
|
|
4
|
+
/**
|
|
5
|
+
* Where a read goes. `CHAIN` enum values are CAIP-2 and split cleanly; the
|
|
6
|
+
* explicit form is the low-level escape hatch; the public API uses `CHAIN.WEB2`.
|
|
7
|
+
*/
|
|
8
|
+
export type ReadChain = CHAIN | typeof CHAIN.WEB2;
|
|
9
|
+
export type ReadDestination = {
|
|
10
|
+
chain: ReadChain;
|
|
11
|
+
} | {
|
|
12
|
+
chainNamespace: string;
|
|
13
|
+
chainId: string;
|
|
14
|
+
};
|
|
15
|
+
export type ResolvedDestination = {
|
|
16
|
+
chainNamespace: string;
|
|
17
|
+
chainId: string;
|
|
18
|
+
/** `${chainNamespace}:${chainId}` — the key the oracle and the node route on. */
|
|
19
|
+
caip2: string;
|
|
20
|
+
namespace: ReadNamespace;
|
|
21
|
+
};
|
|
22
|
+
export type EvmReadQuery = {
|
|
23
|
+
type: 'accountBalance';
|
|
24
|
+
target: Address;
|
|
25
|
+
} | {
|
|
26
|
+
type: 'contractCall';
|
|
27
|
+
target: Address;
|
|
28
|
+
callData: Hex;
|
|
29
|
+
} | {
|
|
30
|
+
type: 'contractCall';
|
|
31
|
+
target: Address;
|
|
32
|
+
/** encodes the call AND decodes the result */
|
|
33
|
+
abi: Abi;
|
|
34
|
+
functionName: string;
|
|
35
|
+
args?: readonly unknown[];
|
|
36
|
+
} | {
|
|
37
|
+
type: 'storageSlot';
|
|
38
|
+
target: Address;
|
|
39
|
+
slot: Hex | bigint;
|
|
40
|
+
};
|
|
41
|
+
/** The account being read rides in `ReadSpec.account.owner` as a raw 32-byte pubkey, not in the envelope. */
|
|
42
|
+
export type SvmReadQuery = {
|
|
43
|
+
type: 'lamportBalance';
|
|
44
|
+
account: string | Uint8Array;
|
|
45
|
+
} | {
|
|
46
|
+
type: 'splTokenAccount';
|
|
47
|
+
account: string | Uint8Array;
|
|
48
|
+
} | {
|
|
49
|
+
type: 'rawAccountData';
|
|
50
|
+
account: string | Uint8Array;
|
|
51
|
+
};
|
|
52
|
+
export type Web2ValueType = 'uint256' | 'int256' | 'bool' | 'string' | 'bytes';
|
|
53
|
+
export interface Web2Extract {
|
|
54
|
+
/** JSONPath, e.g. "$.data.price" */
|
|
55
|
+
path: string;
|
|
56
|
+
valueType: Web2ValueType;
|
|
57
|
+
/** Numeric only. Value × 10^decimals, TRUNCATED before encoding. */
|
|
58
|
+
decimals?: number;
|
|
59
|
+
}
|
|
60
|
+
export interface Web2ReadQuery {
|
|
61
|
+
type: 'http';
|
|
62
|
+
method?: 'GET' | 'POST';
|
|
63
|
+
url: string;
|
|
64
|
+
/** ⚠ Written to a public event log, forever. */
|
|
65
|
+
headers?: Record<string, string>;
|
|
66
|
+
/** POST only */
|
|
67
|
+
body?: string | Uint8Array;
|
|
68
|
+
timeoutMs?: number;
|
|
69
|
+
/** 1–16 entries; result values come back in this order. */
|
|
70
|
+
extract: readonly Web2Extract[];
|
|
71
|
+
}
|
|
72
|
+
export type ReadQuery = EvmReadQuery | SvmReadQuery | Web2ReadQuery;
|
|
73
|
+
export type ReadResultShape = {
|
|
74
|
+
kind: 'uint256';
|
|
75
|
+
} | {
|
|
76
|
+
kind: 'bytes32';
|
|
77
|
+
} | {
|
|
78
|
+
kind: 'raw';
|
|
79
|
+
} | {
|
|
80
|
+
kind: 'evmCall';
|
|
81
|
+
abi: Abi;
|
|
82
|
+
functionName: string;
|
|
83
|
+
} | {
|
|
84
|
+
kind: 'web2';
|
|
85
|
+
extract: readonly Web2Extract[];
|
|
86
|
+
};
|
|
87
|
+
export interface EncodedReadQuery {
|
|
88
|
+
namespace: ReadNamespace;
|
|
89
|
+
queryType: number;
|
|
90
|
+
/** abi.encode(envelope tuple) — goes into ReadSpec.query */
|
|
91
|
+
encoded: Hex;
|
|
92
|
+
/** EVM: pinned block. SVM: minSlot floor. Web2: 0. Mirrored into ReadSpec.blockNumber by the spec builder. */
|
|
93
|
+
blockRef: bigint;
|
|
94
|
+
resultShape: ReadResultShape;
|
|
95
|
+
/** SVM only: the raw 32-byte pubkey that MUST go in ReadSpec.account.owner. */
|
|
96
|
+
ownerBytes?: Hex;
|
|
97
|
+
/** Non-fatal advisories (e.g. a sensitive-looking web2 header). */
|
|
98
|
+
warnings: string[];
|
|
99
|
+
}
|
|
100
|
+
export type DecodedReadResult = {
|
|
101
|
+
kind: 'uint256';
|
|
102
|
+
value: bigint;
|
|
103
|
+
} | {
|
|
104
|
+
kind: 'bytes32';
|
|
105
|
+
value: Hex;
|
|
106
|
+
} | {
|
|
107
|
+
kind: 'raw';
|
|
108
|
+
value: Hex;
|
|
109
|
+
} | {
|
|
110
|
+
kind: 'evmCall';
|
|
111
|
+
value: unknown;
|
|
112
|
+
} | {
|
|
113
|
+
kind: 'web2';
|
|
114
|
+
values: readonly unknown[];
|
|
115
|
+
};
|
|
116
|
+
export interface ReadPreflight {
|
|
117
|
+
destination: ResolvedDestination;
|
|
118
|
+
/** `UniversalCallback.estimateFee(ns, chainId)` — the protocol fee ONLY. 0 on Donut today. */
|
|
119
|
+
protocolFee: bigint;
|
|
120
|
+
/**
|
|
121
|
+
* `UniversalCore.chainHeightByChainNamespace(caip2)` — the oracle-observed height of the
|
|
122
|
+
* destination and the ceiling for `blockNumber`. Lags the real head. 0 for heightless
|
|
123
|
+
* namespaces (web2), where `blockNumber` must then be 0.
|
|
124
|
+
*/
|
|
125
|
+
observedChainHeight: bigint;
|
|
126
|
+
/** Current Push Chain height, for expiry. */
|
|
127
|
+
pushBlockNumber: bigint;
|
|
128
|
+
/** Push gas price used to size the callback budget. */
|
|
129
|
+
pushGasPrice: bigint;
|
|
130
|
+
universalCallback: Address;
|
|
131
|
+
universalCore: Address;
|
|
132
|
+
/** Date.now() at fetch — pushBlockNumber moves every block; a stale preflight can miss expiry. */
|
|
133
|
+
fetchedAt: number;
|
|
134
|
+
}
|
|
135
|
+
export interface ReadSpec {
|
|
136
|
+
account: {
|
|
137
|
+
chainNamespace: string;
|
|
138
|
+
chainId: string;
|
|
139
|
+
owner: Hex;
|
|
140
|
+
};
|
|
141
|
+
query: Hex;
|
|
142
|
+
/** uint16, ≥ 1 */
|
|
143
|
+
minConfirmations: number;
|
|
144
|
+
/** uint64. Heightless namespaces (web2) MUST be 0; else 1..oracleHeight */
|
|
145
|
+
blockNumber: bigint;
|
|
146
|
+
/** uint64, > current Push height */
|
|
147
|
+
expiryPushChainHeight: bigint;
|
|
148
|
+
/** ≥ msg.value */
|
|
149
|
+
maxFee: bigint;
|
|
150
|
+
/** ≠ 0. Refunds are PUSHED here. */
|
|
151
|
+
revertRecipient: Address;
|
|
152
|
+
}
|
|
153
|
+
/** Positional form for `encodeFunctionData` / `encodeAbiParameters`. */
|
|
154
|
+
export type ReadSpecTuple = readonly [
|
|
155
|
+
readonly [string, string, Hex],
|
|
156
|
+
Hex,
|
|
157
|
+
number,
|
|
158
|
+
bigint,
|
|
159
|
+
bigint,
|
|
160
|
+
bigint,
|
|
161
|
+
Address
|
|
162
|
+
];
|
|
163
|
+
export interface ReadCallback {
|
|
164
|
+
target?: Address;
|
|
165
|
+
/** Gas for the result callback, not the request entrypoint. */
|
|
166
|
+
gasLimit?: bigint;
|
|
167
|
+
/** Public payable request entrypoint on the application contract. */
|
|
168
|
+
abi?: Abi;
|
|
169
|
+
functionName?: string;
|
|
170
|
+
/** Defaults to (spec, callbackGasLimit). Must request exactly one read with this spec. */
|
|
171
|
+
args?: (spec: ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];
|
|
172
|
+
}
|
|
173
|
+
export interface BuildReadSpecParams {
|
|
174
|
+
callback?: ReadCallback;
|
|
175
|
+
destination: ReadDestination;
|
|
176
|
+
query: ReadQuery;
|
|
177
|
+
/** 1n..1_000_000n. Execution bound on YOUR callback; also sizes the budget. */
|
|
178
|
+
callbackGasLimit: bigint;
|
|
179
|
+
/**
|
|
180
|
+
* Where unspent budget is PUSHED (ReadSpec.revertRecipient). Required by the contract.
|
|
181
|
+
* Default: the sending account (a UEA has a payable receive()). A non-UEA contract
|
|
182
|
+
* without one forfeits the refund — prepareRead warns.
|
|
183
|
+
*/
|
|
184
|
+
refundTo?: Address;
|
|
185
|
+
/** EVM/web2 only: ReadSpec.account.owner. Ignored by validators for EVM; defaults to refundTo. SVM derives it from the query. */
|
|
186
|
+
owner?: Hex;
|
|
187
|
+
/** ≥ 1. Default 1. */
|
|
188
|
+
minConfirmations?: number;
|
|
189
|
+
/** Pinned destination height. Default observedChainHeight − minConfirmations (≥ 1). Web2: forced to 0. */
|
|
190
|
+
blockNumber?: bigint;
|
|
191
|
+
/** Default 300n. */
|
|
192
|
+
expiryBlocks?: bigint;
|
|
193
|
+
/** Absolute override for expiryBlocks. */
|
|
194
|
+
expiryPushChainHeight?: bigint;
|
|
195
|
+
/** Escrowed on top of the protocol fee. Default sizeCallbackBudget(gasLimit, gasPrice). Must be > 0. */
|
|
196
|
+
callbackBudget?: bigint;
|
|
197
|
+
/** Multiplier used by the default budget. */
|
|
198
|
+
budgetBuffer?: number;
|
|
199
|
+
/** Cap on msg.value. Default value × (1 + maxFeeBufferBps/10_000). */
|
|
200
|
+
maxFee?: bigint;
|
|
201
|
+
maxFeeBufferBps?: number;
|
|
202
|
+
}
|
|
203
|
+
declare const preparedReadValue: unique symbol;
|
|
204
|
+
export interface PreparedRead<T = unknown> {
|
|
205
|
+
/** SDK logical query identity, independent of pinning and payment. */
|
|
206
|
+
queryKey: Hex;
|
|
207
|
+
/** Type-only result metadata retained through preparation and execution. */
|
|
208
|
+
readonly [preparedReadValue]?: T;
|
|
209
|
+
/** App request entrypoint retained for read()/executeReads(). */
|
|
210
|
+
callback?: ReadCallback;
|
|
211
|
+
/** Public destination identifier used to prepare this read. */
|
|
212
|
+
chain: ReadChain;
|
|
213
|
+
spec: ReadSpec;
|
|
214
|
+
/** Positional form for viem calls. */
|
|
215
|
+
specTuple: ReadSpecTuple;
|
|
216
|
+
/** abi.encode(spec) for hand-assembled calldata. */
|
|
217
|
+
encodedSpec: Hex;
|
|
218
|
+
/** msg.value to send: protocolFee + callbackBudget. */
|
|
219
|
+
value: bigint;
|
|
220
|
+
protocolFee: bigint;
|
|
221
|
+
callbackBudget: bigint;
|
|
222
|
+
/** The same three numbers, grouped: `total` === `value`. */
|
|
223
|
+
fees: {
|
|
224
|
+
protocolFee: bigint;
|
|
225
|
+
callbackBudget: bigint;
|
|
226
|
+
total: bigint;
|
|
227
|
+
};
|
|
228
|
+
callbackGasLimit: bigint;
|
|
229
|
+
/** Carries the result shape for decoding, and any encoder warnings. */
|
|
230
|
+
encodedQuery: EncodedReadQuery;
|
|
231
|
+
/** Public decoder description retained through execution. */
|
|
232
|
+
resultShape: ReadResultShape;
|
|
233
|
+
preflight: ReadPreflight;
|
|
234
|
+
/** Advisories: sensitive headers, refundTo is a non-UEA contract, … */
|
|
235
|
+
warnings: string[];
|
|
236
|
+
}
|
|
237
|
+
export type SimulateReadResult = {
|
|
238
|
+
ok: true;
|
|
239
|
+
} | {
|
|
240
|
+
ok: false;
|
|
241
|
+
error: string;
|
|
242
|
+
errorName?: string;
|
|
243
|
+
args?: readonly unknown[];
|
|
244
|
+
};
|
|
245
|
+
export interface ParsedReadRequest {
|
|
246
|
+
/** 32-byte topic hex, lowercase — the node's primary key */
|
|
247
|
+
requestId: Hex;
|
|
248
|
+
requestIdUint: bigint;
|
|
249
|
+
callbackTarget: Address;
|
|
250
|
+
originalFunder: Address;
|
|
251
|
+
spec: ReadSpec;
|
|
252
|
+
callbackGasLimit: bigint;
|
|
253
|
+
totalPaid: bigint;
|
|
254
|
+
protocolFee: bigint;
|
|
255
|
+
callbackBudget: bigint;
|
|
256
|
+
logIndex: number;
|
|
257
|
+
}
|
|
258
|
+
/** What the fulfil / settle / expiry transactions said, parsed from UniversalCallback logs. */
|
|
259
|
+
export interface FulfilOutcome {
|
|
260
|
+
/** true = ReadFulfilled, false = CallbackFailed, undefined = neither seen in this receipt */
|
|
261
|
+
delivered?: boolean;
|
|
262
|
+
/** revert data from CallbackFailed */
|
|
263
|
+
failReason?: Hex;
|
|
264
|
+
gasReported?: bigint;
|
|
265
|
+
burned?: bigint;
|
|
266
|
+
refunded?: bigint;
|
|
267
|
+
refundTo?: Address;
|
|
268
|
+
/** RefundFailed seen — budget forfeited to the admin rescue pool */
|
|
269
|
+
refundFailed?: boolean;
|
|
270
|
+
/** RequestExpired seen */
|
|
271
|
+
expired?: boolean;
|
|
272
|
+
}
|
|
273
|
+
/** Minimal structural receipt — works with viem receipts and `cast receipt --json`. */
|
|
274
|
+
export interface ReceiptLike {
|
|
275
|
+
logs: readonly {
|
|
276
|
+
address: string;
|
|
277
|
+
topics: readonly string[];
|
|
278
|
+
data: string;
|
|
279
|
+
logIndex?: number | string;
|
|
280
|
+
}[];
|
|
281
|
+
}
|
|
282
|
+
export type ReadRef = {
|
|
283
|
+
txHash: Hex;
|
|
284
|
+
} | {
|
|
285
|
+
requestId: Hex | bigint;
|
|
286
|
+
};
|
|
287
|
+
export interface ReadLifecycleOptions {
|
|
288
|
+
/** Default `expiryBlocks × PUSH_BLOCK_TIME_MS`, capped at READ_TRACK_MAX_TIMEOUT_MS. */
|
|
289
|
+
timeoutMs?: number;
|
|
290
|
+
/** Default READ_TRACK_POLL_INTERVAL_MS; floor READ_TRACK_MIN_POLL_INTERVAL_MS. */
|
|
291
|
+
pollingIntervalMs?: number;
|
|
292
|
+
/**
|
|
293
|
+
* How to decode `resultData`. When omitted the tracker infers it from the on-chain
|
|
294
|
+
* envelope (balances → uint256, storage → bytes32, web2 → its extract list); a
|
|
295
|
+
* contract call has no ABI on chain and decodes to raw bytes unless given here.
|
|
296
|
+
*/
|
|
297
|
+
resultShape?: ReadResultShape;
|
|
298
|
+
}
|
|
299
|
+
/** Accounting for one read, assembled from the request record and the settlement logs. */
|
|
300
|
+
export interface ReadFees {
|
|
301
|
+
/** msg.value at request time (`feesDeposited`) */
|
|
302
|
+
paid: bigint;
|
|
303
|
+
/** gone at request time, never refunded */
|
|
304
|
+
protocolFee: bigint;
|
|
305
|
+
/** escrowed for the callback */
|
|
306
|
+
callbackBudget: bigint;
|
|
307
|
+
/** consumed by the callback — `CallbackGasReported` */
|
|
308
|
+
burned?: bigint;
|
|
309
|
+
/** pushed back to `refundTo` — `RefundSent` / `RequestExpired` */
|
|
310
|
+
/** Unknown for EndBlock expiry: EXPIRED does not prove the recipient accepted payment. */
|
|
311
|
+
refunded?: bigint;
|
|
312
|
+
/** the push was rejected — budget sits in the admin rescue pool */
|
|
313
|
+
refundFailed?: boolean;
|
|
314
|
+
}
|
|
315
|
+
export interface UniversalReadResponse<T = unknown> {
|
|
316
|
+
requestId: Hex;
|
|
317
|
+
/** Push tx that carried the request */
|
|
318
|
+
txHash: Hex;
|
|
319
|
+
destination: ResolvedDestination;
|
|
320
|
+
/** Required read destination, including `CHAIN.WEB2`. */
|
|
321
|
+
chain: ReadChain;
|
|
322
|
+
status: UNIVERSAL_READ_STATUS;
|
|
323
|
+
isTerminal: boolean;
|
|
324
|
+
/**
|
|
325
|
+
* FULFILLED only. true = `ReadFulfilled`; false = `CallbackFailed` (your callback
|
|
326
|
+
* reverted / ran out of gas). FULFILLED does NOT imply delivered — check both.
|
|
327
|
+
*/
|
|
328
|
+
callbackDelivered?: boolean;
|
|
329
|
+
/** Revert data from `CallbackFailed`. */
|
|
330
|
+
callbackFailReason?: Hex;
|
|
331
|
+
/** Decoded result. Present iff FULFILLED && callbackDelivered && result SUCCESS && decodable. */
|
|
332
|
+
value?: T;
|
|
333
|
+
decoded?: DecodedReadResult;
|
|
334
|
+
/** Why `value` is absent although the read succeeded (shape mismatch). */
|
|
335
|
+
decodeError?: string;
|
|
336
|
+
/** Consensus bytes — what ⅔ of validators voted on. `null` before a result exists. */
|
|
337
|
+
raw: {
|
|
338
|
+
status: READ_STATUS;
|
|
339
|
+
resultData: Hex;
|
|
340
|
+
errorCode: READ_ERROR_CODE;
|
|
341
|
+
} | null;
|
|
342
|
+
errorMsg: string;
|
|
343
|
+
fees: ReadFees;
|
|
344
|
+
request: {
|
|
345
|
+
spec: ReadSpec;
|
|
346
|
+
callbackTarget: Address;
|
|
347
|
+
/** who paid (msg.sender at request) — NOT where refunds go */
|
|
348
|
+
originalFunder: Address;
|
|
349
|
+
/** where refunds go */
|
|
350
|
+
refundTo: Address;
|
|
351
|
+
callbackGasLimit: bigint;
|
|
352
|
+
logIndex: number;
|
|
353
|
+
createdAtHeight: bigint;
|
|
354
|
+
};
|
|
355
|
+
/** Push txs the node sent for this read (fulfil, settle, expiry sweep). */
|
|
356
|
+
pcTx: readonly {
|
|
357
|
+
txHash: Hex;
|
|
358
|
+
blockHeight: number;
|
|
359
|
+
status: string;
|
|
360
|
+
errorMsg: string;
|
|
361
|
+
}[];
|
|
362
|
+
explorerUrl: string;
|
|
363
|
+
/** Poll until terminal (or already terminal → resolves at once). Only a timeout throws. */
|
|
364
|
+
wait(opts?: ReadLifecycleOptions): Promise<UniversalReadResponse<T>>;
|
|
365
|
+
/** One fresh snapshot, no polling. */
|
|
366
|
+
refresh(): Promise<UniversalReadResponse<T>>;
|
|
367
|
+
}
|
|
368
|
+
export type ReadResponseTuple<R extends readonly PreparedRead[]> = {
|
|
369
|
+
-readonly [K in keyof R]: UniversalReadResponse<R[K] extends PreparedRead<infer T> ? T : unknown>;
|
|
370
|
+
};
|
|
371
|
+
/** One execution containing one or more independently settled read requests. */
|
|
372
|
+
export interface BatchReadResponse<R extends readonly PreparedRead[] = readonly PreparedRead[]> {
|
|
373
|
+
/** Primary Push transaction hash. For sequential fallback, see `transactionHashes`. */
|
|
374
|
+
txHash: Hex;
|
|
375
|
+
/** All request transactions in submission order when execution was non-atomic. */
|
|
376
|
+
transactionHashes?: readonly Hex[];
|
|
377
|
+
reads: ReadResponseTuple<R>;
|
|
378
|
+
count: number;
|
|
379
|
+
atomic: boolean;
|
|
380
|
+
/** Wait until every read is terminal. Terminal failures resolve; only timeout throws. */
|
|
381
|
+
wait(opts?: Omit<ReadLifecycleOptions, 'resultShape'>): Promise<ReadResponseTuple<R>>;
|
|
382
|
+
}
|
|
383
|
+
export declare enum UNIVERSAL_READ_STATUS {
|
|
384
|
+
UNSPECIFIED = 0,
|
|
385
|
+
PENDING = 1,
|
|
386
|
+
VOTING = 2,
|
|
387
|
+
/** fulfil tx succeeded — check `callbackDelivered` before trusting the result */
|
|
388
|
+
FULFILLED = 3,
|
|
389
|
+
EXPIRED = 4,
|
|
390
|
+
/** contract had already settled the request another way */
|
|
391
|
+
FAILED = 5,
|
|
392
|
+
ABORTED = 6
|
|
393
|
+
}
|
|
394
|
+
export declare enum READ_STATUS {
|
|
395
|
+
UNSPECIFIED = 0,
|
|
396
|
+
SUCCESS = 1,
|
|
397
|
+
ERROR = 2
|
|
398
|
+
}
|
|
399
|
+
export declare enum READ_ERROR_CODE {
|
|
400
|
+
UNSPECIFIED = 0,
|
|
401
|
+
INVALID_QUERY = 1,
|
|
402
|
+
UNSUPPORTED = 2,
|
|
403
|
+
REVERTED = 3,
|
|
404
|
+
NOT_FOUND = 4,
|
|
405
|
+
INVALID_RESULT = 5,
|
|
406
|
+
REJECTED = 6
|
|
407
|
+
}
|
|
408
|
+
/** On-chain lifecycle (`RequestStatus` in ReadTypes.sol). */
|
|
409
|
+
export declare enum CONTRACT_REQUEST_STATUS {
|
|
410
|
+
NONE = 0,
|
|
411
|
+
PENDING = 1,
|
|
412
|
+
EXECUTED = 2,
|
|
413
|
+
SETTLED = 3,
|
|
414
|
+
EXPIRED = 4
|
|
415
|
+
}
|
|
416
|
+
export declare const TERMINAL_READ_STATUSES: ReadonlySet<UNIVERSAL_READ_STATUS>;
|
|
417
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TERMINAL_READ_STATUSES = exports.CONTRACT_REQUEST_STATUS = exports.READ_ERROR_CODE = exports.READ_STATUS = exports.UNIVERSAL_READ_STATUS = void 0;
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Status enums (mirror ucallback.v1 protos; re-exported for the public surface)
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
var UNIVERSAL_READ_STATUS;
|
|
8
|
+
(function (UNIVERSAL_READ_STATUS) {
|
|
9
|
+
UNIVERSAL_READ_STATUS[UNIVERSAL_READ_STATUS["UNSPECIFIED"] = 0] = "UNSPECIFIED";
|
|
10
|
+
UNIVERSAL_READ_STATUS[UNIVERSAL_READ_STATUS["PENDING"] = 1] = "PENDING";
|
|
11
|
+
UNIVERSAL_READ_STATUS[UNIVERSAL_READ_STATUS["VOTING"] = 2] = "VOTING";
|
|
12
|
+
/** fulfil tx succeeded — check `callbackDelivered` before trusting the result */
|
|
13
|
+
UNIVERSAL_READ_STATUS[UNIVERSAL_READ_STATUS["FULFILLED"] = 3] = "FULFILLED";
|
|
14
|
+
UNIVERSAL_READ_STATUS[UNIVERSAL_READ_STATUS["EXPIRED"] = 4] = "EXPIRED";
|
|
15
|
+
/** contract had already settled the request another way */
|
|
16
|
+
UNIVERSAL_READ_STATUS[UNIVERSAL_READ_STATUS["FAILED"] = 5] = "FAILED";
|
|
17
|
+
UNIVERSAL_READ_STATUS[UNIVERSAL_READ_STATUS["ABORTED"] = 6] = "ABORTED";
|
|
18
|
+
})(UNIVERSAL_READ_STATUS || (exports.UNIVERSAL_READ_STATUS = UNIVERSAL_READ_STATUS = {}));
|
|
19
|
+
var READ_STATUS;
|
|
20
|
+
(function (READ_STATUS) {
|
|
21
|
+
READ_STATUS[READ_STATUS["UNSPECIFIED"] = 0] = "UNSPECIFIED";
|
|
22
|
+
READ_STATUS[READ_STATUS["SUCCESS"] = 1] = "SUCCESS";
|
|
23
|
+
READ_STATUS[READ_STATUS["ERROR"] = 2] = "ERROR";
|
|
24
|
+
})(READ_STATUS || (exports.READ_STATUS = READ_STATUS = {}));
|
|
25
|
+
var READ_ERROR_CODE;
|
|
26
|
+
(function (READ_ERROR_CODE) {
|
|
27
|
+
READ_ERROR_CODE[READ_ERROR_CODE["UNSPECIFIED"] = 0] = "UNSPECIFIED";
|
|
28
|
+
READ_ERROR_CODE[READ_ERROR_CODE["INVALID_QUERY"] = 1] = "INVALID_QUERY";
|
|
29
|
+
READ_ERROR_CODE[READ_ERROR_CODE["UNSUPPORTED"] = 2] = "UNSUPPORTED";
|
|
30
|
+
READ_ERROR_CODE[READ_ERROR_CODE["REVERTED"] = 3] = "REVERTED";
|
|
31
|
+
READ_ERROR_CODE[READ_ERROR_CODE["NOT_FOUND"] = 4] = "NOT_FOUND";
|
|
32
|
+
READ_ERROR_CODE[READ_ERROR_CODE["INVALID_RESULT"] = 5] = "INVALID_RESULT";
|
|
33
|
+
READ_ERROR_CODE[READ_ERROR_CODE["REJECTED"] = 6] = "REJECTED";
|
|
34
|
+
})(READ_ERROR_CODE || (exports.READ_ERROR_CODE = READ_ERROR_CODE = {}));
|
|
35
|
+
/** On-chain lifecycle (`RequestStatus` in ReadTypes.sol). */
|
|
36
|
+
var CONTRACT_REQUEST_STATUS;
|
|
37
|
+
(function (CONTRACT_REQUEST_STATUS) {
|
|
38
|
+
CONTRACT_REQUEST_STATUS[CONTRACT_REQUEST_STATUS["NONE"] = 0] = "NONE";
|
|
39
|
+
CONTRACT_REQUEST_STATUS[CONTRACT_REQUEST_STATUS["PENDING"] = 1] = "PENDING";
|
|
40
|
+
CONTRACT_REQUEST_STATUS[CONTRACT_REQUEST_STATUS["EXECUTED"] = 2] = "EXECUTED";
|
|
41
|
+
CONTRACT_REQUEST_STATUS[CONTRACT_REQUEST_STATUS["SETTLED"] = 3] = "SETTLED";
|
|
42
|
+
CONTRACT_REQUEST_STATUS[CONTRACT_REQUEST_STATUS["EXPIRED"] = 4] = "EXPIRED";
|
|
43
|
+
})(CONTRACT_REQUEST_STATUS || (exports.CONTRACT_REQUEST_STATUS = CONTRACT_REQUEST_STATUS = {}));
|
|
44
|
+
exports.TERMINAL_READ_STATUSES = new Set([
|
|
45
|
+
UNIVERSAL_READ_STATUS.FULFILLED,
|
|
46
|
+
UNIVERSAL_READ_STATUS.EXPIRED,
|
|
47
|
+
UNIVERSAL_READ_STATUS.FAILED,
|
|
48
|
+
UNIVERSAL_READ_STATUS.ABORTED,
|
|
49
|
+
]);
|
|
50
|
+
//# sourceMappingURL=read-state.types.js.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* trackRead / wait / refresh — resume a read from its Push tx hash or requestId
|
|
3
|
+
* and follow it to a terminal status.
|
|
4
|
+
*
|
|
5
|
+
* Source of truth is the node's `ucallback.v1.Query` record. What the node
|
|
6
|
+
* does NOT tell us is parsed from the UniversalCallback logs of the Push txs it
|
|
7
|
+
* lists in `pc_tx` (fulfil → ReadFulfilled | CallbackFailed; settle →
|
|
8
|
+
* CallbackGasReported + RefundSent | RefundFailed).
|
|
9
|
+
*
|
|
10
|
+
* Two rules verified live on Donut (2026-09-09):
|
|
11
|
+
* - FULFILLED does not mean delivered: the node sets it even when the app
|
|
12
|
+
* callback reverted. `callbackDelivered` is the real answer (I4).
|
|
13
|
+
* - EXPIRED has no EVM-indexed tx / receipt / logs (EndBlocker); never fetch
|
|
14
|
+
* its `pc_tx`. The refund is confirmed from the EndBlock `tx_log` events in the
|
|
15
|
+
* Cosmos block results instead (RefundSent / RefundFailed); if that lookup fails
|
|
16
|
+
* the refund fields stay undefined rather than guessed.
|
|
17
|
+
*/
|
|
18
|
+
import { type Hex } from 'viem';
|
|
19
|
+
import { PUSH_NETWORK } from '../constants/enums';
|
|
20
|
+
import type { PushClient } from '../push-client/push-client';
|
|
21
|
+
import { type ReadLifecycleOptions, type ReadResultShape, type UniversalReadResponse } from './read-state.types';
|
|
22
|
+
export type ReadHookEmitter = (hookId: string, ...args: unknown[]) => void;
|
|
23
|
+
export interface TrackReadDeps {
|
|
24
|
+
pushClient: Pick<PushClient, 'getUniversalRead' | 'getReadsByTx' | 'getTransactionReceiptWithArchiveFallback' | 'getBlockResultEvents'> & {
|
|
25
|
+
publicClient: Pick<PushClient['publicClient'], 'getBlockNumber'>;
|
|
26
|
+
};
|
|
27
|
+
pushNetwork: PUSH_NETWORK;
|
|
28
|
+
/** Progress events. Wire to `fireProgressHook(ctx, …)` in the orchestrator. */
|
|
29
|
+
emit?: ReadHookEmitter;
|
|
30
|
+
/** Override for tests. */
|
|
31
|
+
now?: () => number;
|
|
32
|
+
}
|
|
33
|
+
export declare function trackRead(deps: TrackReadDeps, ref: {
|
|
34
|
+
txHash: Hex;
|
|
35
|
+
}, opts?: ReadLifecycleOptions): Promise<UniversalReadResponse[]>;
|
|
36
|
+
export declare function trackRead(deps: TrackReadDeps, ref: {
|
|
37
|
+
requestId: Hex | bigint;
|
|
38
|
+
}, opts?: ReadLifecycleOptions): Promise<UniversalReadResponse>;
|
|
39
|
+
/** Normalise a bigint / hex requestId to the node's lowercase 32-byte key. */
|
|
40
|
+
export declare function toRequestIdHex(id: Hex | bigint): Hex;
|
|
41
|
+
/** Best-effort shape from the on-chain envelope. Contract calls carry no ABI → raw. */
|
|
42
|
+
export declare function inferResultShape(namespace: string, query: Hex): ReadResultShape;
|
|
43
|
+
export declare function statusName(status: number): string;
|
|
44
|
+
/** Default: remaining Push blocks plus observation margin, capped at 180 seconds. */
|
|
45
|
+
export declare function defaultWaitTimeoutMs(currentPushHeight: bigint, expiryPushChainHeight: bigint): number;
|
|
46
|
+
/**
|
|
47
|
+
* Poll until terminal. Resolves on EVERY terminal status (EXPIRED / FAILED / ABORTED
|
|
48
|
+
* are statuses, not throws — house convention); only a client timeout throws.
|
|
49
|
+
*/
|
|
50
|
+
export declare function waitForRead(deps: TrackReadDeps, initial: UniversalReadResponse, opts: ReadLifecycleOptions): Promise<UniversalReadResponse>;
|