@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
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.computeReadQueryKey = computeReadQueryKey;
|
|
4
|
+
exports.getReadRegistryAddress = getReadRegistryAddress;
|
|
5
|
+
exports.resolveReadCallback = resolveReadCallback;
|
|
6
|
+
exports.getRegistryReadResult = getRegistryReadResult;
|
|
7
|
+
exports.getLatestRegistryReadResult = getLatestRegistryReadResult;
|
|
8
|
+
const viem_1 = require("viem");
|
|
9
|
+
const read_state_1 = require("../constants/read-state");
|
|
10
|
+
const universalReadRegistry_evm_1 = require("../constants/abi/universalReadRegistry.evm");
|
|
11
|
+
const envelopes_1 = require("./envelopes");
|
|
12
|
+
const destination_1 = require("./destination");
|
|
13
|
+
const errors_1 = require("./errors");
|
|
14
|
+
/** Versioned logical identity. Height, fee, expiry, refund, callback and HTTP timeout are excluded. */
|
|
15
|
+
function computeReadQueryKey(destination, query) {
|
|
16
|
+
const dest = (0, destination_1.resolveDestination)(destination);
|
|
17
|
+
// Use fixed references in the existing canonical encoders; never hash live heights.
|
|
18
|
+
const encoded = (0, envelopes_1.encodeReadQuery)(destination, query.type === 'http' ? { ...query, timeoutMs: read_state_1.WEB2_DEFAULT_TIMEOUT_MS } : query, { blockNumber: 1n, minSlot: 0n });
|
|
19
|
+
return (0, viem_1.keccak256)((0, viem_1.encodeAbiParameters)([{ type: 'string' }, { type: 'string' }, { type: 'string' }, { type: 'bytes' }, { type: 'bytes' }], ['pushchain:universal-read:query:v1', dest.chainNamespace, dest.chainId, encoded.ownerBytes ?? '0x', encoded.encoded]));
|
|
20
|
+
}
|
|
21
|
+
function getReadRegistryAddress(network) {
|
|
22
|
+
const address = read_state_1.UNIVERSAL_READ_REGISTRY_ADDRESS[network];
|
|
23
|
+
if (!address)
|
|
24
|
+
throw new errors_1.ReadRegistryUnavailableError('read registry');
|
|
25
|
+
return address;
|
|
26
|
+
}
|
|
27
|
+
function resolveReadCallback(callback, network, queryKey) {
|
|
28
|
+
if (callback && 'request' in callback)
|
|
29
|
+
throw new errors_1.InvalidReadQueryError('callback.request was removed; use callback.abi, functionName and args');
|
|
30
|
+
if (callback?.target !== undefined) {
|
|
31
|
+
// Same default as the registry: unused callback budget is refunded.
|
|
32
|
+
return { ...callback, gasLimit: callback.gasLimit ?? read_state_1.REGISTRY_CALLBACK_GAS };
|
|
33
|
+
}
|
|
34
|
+
if (callback?.abi !== undefined || callback?.functionName !== undefined || callback?.args !== undefined) {
|
|
35
|
+
throw new errors_1.InvalidReadQueryError('callback abi, functionName and args require callback.target');
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
target: getReadRegistryAddress(network),
|
|
39
|
+
gasLimit: callback?.gasLimit ?? read_state_1.REGISTRY_CALLBACK_GAS,
|
|
40
|
+
abi: universalReadRegistry_evm_1.UNIVERSAL_READ_REGISTRY_EVM, functionName: 'read', args: (spec, gas) => [spec, queryKey, gas],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Raw registry storage only: presence does not prove successful consensus or freshness. */
|
|
44
|
+
function getRegistryReadResult(client, network, requestId) {
|
|
45
|
+
return client.readContract({ address: getReadRegistryAddress(network), abi: universalReadRegistry_evm_1.UNIVERSAL_READ_REGISTRY_EVM,
|
|
46
|
+
functionName: 'resultByRequestId', args: [requestId] });
|
|
47
|
+
}
|
|
48
|
+
/** Keys are caller-supplied labels; verify the associated request before relying on its identity. */
|
|
49
|
+
function getLatestRegistryReadResult(client, network, reader, queryKey) {
|
|
50
|
+
return client.readContract({ address: getReadRegistryAddress(network), abi: universalReadRegistry_evm_1.UNIVERSAL_READ_REGISTRY_EVM,
|
|
51
|
+
functionName: 'latestResult', args: [reader, queryKey] });
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Hex } from 'viem';
|
|
2
|
+
import type { DecodedReadResult, ReadResultShape } from './read-state.types';
|
|
3
|
+
/**
|
|
4
|
+
* Decode `resultData` using the shape recorded by the query that produced it.
|
|
5
|
+
*
|
|
6
|
+
* `resultData` is not self-describing. Shapes (from the validator executors):
|
|
7
|
+
* EVM AccountBalance / SVM LamportBalance / SVM SPLTokenAccount → abi.encode(uint256)
|
|
8
|
+
* EVM ContractCall → raw eth_call return bytes (decoded with the recorded ABI, else raw)
|
|
9
|
+
* EVM StorageSlot → raw 32 bytes
|
|
10
|
+
* SVM RawAccountData → raw account bytes
|
|
11
|
+
* Web2 → abi.encode(v1, v2, …) — a FLAT argument list, one per extract, in order
|
|
12
|
+
*
|
|
13
|
+
* Throws `ReadDecodeError` rather than mis-decoding. Do not call this for an ERROR
|
|
14
|
+
* result (empty bytes) — check `result.status` first.
|
|
15
|
+
*/
|
|
16
|
+
export declare function decodeReadResult(resultData: Hex, shape: ReadResultShape): DecodedReadResult;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decodeReadResult = decodeReadResult;
|
|
4
|
+
const viem_1 = require("viem");
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
const buffer_1 = require("buffer");
|
|
7
|
+
const svm_account_1 = require("./svm-account");
|
|
8
|
+
const WEB2_ABI_TYPE = {
|
|
9
|
+
uint256: 'uint256',
|
|
10
|
+
int256: 'int256',
|
|
11
|
+
bool: 'bool',
|
|
12
|
+
string: 'string',
|
|
13
|
+
bytes: 'bytes',
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Decode `resultData` using the shape recorded by the query that produced it.
|
|
17
|
+
*
|
|
18
|
+
* `resultData` is not self-describing. Shapes (from the validator executors):
|
|
19
|
+
* EVM AccountBalance / SVM LamportBalance / SVM SPLTokenAccount → abi.encode(uint256)
|
|
20
|
+
* EVM ContractCall → raw eth_call return bytes (decoded with the recorded ABI, else raw)
|
|
21
|
+
* EVM StorageSlot → raw 32 bytes
|
|
22
|
+
* SVM RawAccountData → raw account bytes
|
|
23
|
+
* Web2 → abi.encode(v1, v2, …) — a FLAT argument list, one per extract, in order
|
|
24
|
+
*
|
|
25
|
+
* Throws `ReadDecodeError` rather than mis-decoding. Do not call this for an ERROR
|
|
26
|
+
* result (empty bytes) — check `result.status` first.
|
|
27
|
+
*/
|
|
28
|
+
function decodeReadResult(resultData, shape) {
|
|
29
|
+
if (!(0, viem_1.isHex)(resultData))
|
|
30
|
+
throw new errors_1.ReadDecodeError('resultData is not hex');
|
|
31
|
+
const len = (0, viem_1.size)(resultData);
|
|
32
|
+
try {
|
|
33
|
+
switch (shape.kind) {
|
|
34
|
+
case 'svmAccount': {
|
|
35
|
+
const { accountName, value } = (0, svm_account_1.decodeIdlAccount)(shape.idl, buffer_1.Buffer.from(resultData.slice(2), 'hex'), shape.accountName);
|
|
36
|
+
return { kind: 'svmAccount', value, accountName };
|
|
37
|
+
}
|
|
38
|
+
case 'uint256': {
|
|
39
|
+
if (len !== 32)
|
|
40
|
+
throw new errors_1.ReadDecodeError(`expected 32 bytes for uint256, got ${len}`);
|
|
41
|
+
const [value] = (0, viem_1.decodeAbiParameters)([{ type: 'uint256' }], resultData);
|
|
42
|
+
return { kind: 'uint256', value };
|
|
43
|
+
}
|
|
44
|
+
case 'bytes32': {
|
|
45
|
+
if (len !== 32)
|
|
46
|
+
throw new errors_1.ReadDecodeError(`expected 32 bytes for bytes32, got ${len}`);
|
|
47
|
+
return { kind: 'bytes32', value: resultData };
|
|
48
|
+
}
|
|
49
|
+
case 'raw':
|
|
50
|
+
return { kind: 'raw', value: resultData };
|
|
51
|
+
case 'evmCall': {
|
|
52
|
+
if (len === 0)
|
|
53
|
+
throw new errors_1.ReadDecodeError('empty resultData for a contract call');
|
|
54
|
+
const item = (0, viem_1.getAbiItem)({ abi: shape.abi, name: shape.functionName });
|
|
55
|
+
if (!item)
|
|
56
|
+
throw new errors_1.ReadDecodeError(`function not found in abi: ${shape.functionName}`);
|
|
57
|
+
const decoded = (0, viem_1.decodeFunctionResult)({ abi: shape.abi, functionName: shape.functionName, data: resultData });
|
|
58
|
+
return { kind: 'evmCall', value: decoded };
|
|
59
|
+
}
|
|
60
|
+
case 'web2': {
|
|
61
|
+
if (shape.extract.length === 0)
|
|
62
|
+
throw new errors_1.ReadDecodeError('web2 shape has no extracts');
|
|
63
|
+
if (len === 0)
|
|
64
|
+
throw new errors_1.ReadDecodeError('empty resultData for a web2 read');
|
|
65
|
+
const params = shape.extract.map((e) => ({ type: WEB2_ABI_TYPE[e.valueType] }));
|
|
66
|
+
const values = (0, viem_1.decodeAbiParameters)(params, resultData);
|
|
67
|
+
return { kind: 'web2', values };
|
|
68
|
+
}
|
|
69
|
+
default:
|
|
70
|
+
throw new errors_1.ReadDecodeError(`unknown result shape: ${shape.kind}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
if (err instanceof errors_1.ReadDecodeError)
|
|
75
|
+
throw err;
|
|
76
|
+
throw new errors_1.ReadDecodeError(`resultData does not match shape ${shape.kind}: ${err.message}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=result-decoder.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type Abi, type Address, type Hex } from 'viem';
|
|
2
|
+
import { type PreflightDeps } from './preflight';
|
|
3
|
+
import type { BuildReadSpecParams, PreparedRead, ReadPreflight, ReadSpec, ReadSpecTuple, SimulateReadResult } from './read-state.types';
|
|
4
|
+
import type { ReadHookEmitter } from './read-tracker';
|
|
5
|
+
export interface PrepareReadDeps extends PreflightDeps {
|
|
6
|
+
emit?: ReadHookEmitter;
|
|
7
|
+
/** The signer's Push-side account (UEA or EOA). Used when `refundTo` is not given. */
|
|
8
|
+
defaultRefundTo?: Address;
|
|
9
|
+
}
|
|
10
|
+
export declare function encodeSpec(spec: ReadSpec): Hex;
|
|
11
|
+
/**
|
|
12
|
+
* Assemble a `PreparedRead` from an already-fetched preflight. Pure — no network.
|
|
13
|
+
* Use directly when preparing several reads from one preflight.
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildReadSpecFromPreflight(preflight: ReadPreflight, params: BuildReadSpecParams, defaults?: {
|
|
16
|
+
refundTo?: Address;
|
|
17
|
+
}): PreparedRead;
|
|
18
|
+
/**
|
|
19
|
+
* Preflight + build. Adds the `refundTo` advisory: a contract recipient that is not a
|
|
20
|
+
* UEA must have a payable receive() or the refund is forfeited to the admin rescue
|
|
21
|
+
* pool (verified live). UEAs (UEA_EVM / UEA_SVM) always have one.
|
|
22
|
+
*/
|
|
23
|
+
export declare function prepareRead(deps: PrepareReadDeps, params: BuildReadSpecParams): Promise<PreparedRead>;
|
|
24
|
+
/**
|
|
25
|
+
* Splice the prepared spec into the app's own entrypoint.
|
|
26
|
+
* Default argument order is `(spec, callbackGasLimit)`; pass `args` to remap.
|
|
27
|
+
*/
|
|
28
|
+
export declare function toCallData(prepared: PreparedRead, target: {
|
|
29
|
+
abi: Abi;
|
|
30
|
+
functionName: string;
|
|
31
|
+
args?: (spec: ReadSpecTuple, callbackGasLimit: bigint) => readonly unknown[];
|
|
32
|
+
}): {
|
|
33
|
+
data: Hex;
|
|
34
|
+
value: bigint;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* eth_call `requestExternalReadSelf` with `from` = the app contract, so validation
|
|
38
|
+
* reverts surface before broadcast, decoded into the contract's custom errors.
|
|
39
|
+
* Only meaningful for the app-contract persona: `callbackTarget` becomes `msg.sender`.
|
|
40
|
+
*/
|
|
41
|
+
export declare function simulateRead(deps: PreflightDeps, prepared: PreparedRead, opts: {
|
|
42
|
+
appContract: Address;
|
|
43
|
+
callbackSelector: Hex;
|
|
44
|
+
staleAfterMs?: number;
|
|
45
|
+
}): Promise<SimulateReadResult>;
|
|
46
|
+
/** Fresh validation only: never rebuild or mutate the prepared request. */
|
|
47
|
+
export declare function revalidateRead(deps: PreflightDeps, prepared: PreparedRead): Promise<void>;
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.encodeSpec = encodeSpec;
|
|
4
|
+
exports.buildReadSpecFromPreflight = buildReadSpecFromPreflight;
|
|
5
|
+
exports.prepareRead = prepareRead;
|
|
6
|
+
exports.toCallData = toCallData;
|
|
7
|
+
exports.simulateRead = simulateRead;
|
|
8
|
+
exports.revalidateRead = revalidateRead;
|
|
9
|
+
const viem_1 = require("viem");
|
|
10
|
+
const universalCallback_evm_1 = require("../constants/abi/universalCallback.evm");
|
|
11
|
+
const uea_factory_1 = require("../constants/abi/uea-factory");
|
|
12
|
+
const chain_1 = require("../constants/chain");
|
|
13
|
+
const read_state_1 = require("../constants/read-state");
|
|
14
|
+
const budget_1 = require("./budget");
|
|
15
|
+
const registry_1 = require("./registry");
|
|
16
|
+
const destination_1 = require("./destination");
|
|
17
|
+
const envelopes_1 = require("./envelopes");
|
|
18
|
+
const errors_1 = require("./errors");
|
|
19
|
+
const preflight_1 = require("./preflight");
|
|
20
|
+
const validate_1 = require("./validate");
|
|
21
|
+
const progress_hook_types_1 = require("../progress-hook/progress-hook.types");
|
|
22
|
+
/** The ReadSpec tuple as the contract declares it — for abi.encode(spec). */
|
|
23
|
+
const READ_SPEC_ABI_PARAM = (0, viem_1.getAbiItem)({ abi: universalCallback_evm_1.UNIVERSAL_CALLBACK_EVM, name: 'requestExternalReadSelf' }).inputs[0];
|
|
24
|
+
function toTuple(spec) {
|
|
25
|
+
return [
|
|
26
|
+
[spec.account.chainNamespace, spec.account.chainId, spec.account.owner],
|
|
27
|
+
spec.query,
|
|
28
|
+
spec.minConfirmations,
|
|
29
|
+
spec.blockNumber,
|
|
30
|
+
spec.expiryPushChainHeight,
|
|
31
|
+
spec.maxFee,
|
|
32
|
+
spec.revertRecipient,
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
function encodeSpec(spec) {
|
|
36
|
+
return (0, viem_1.encodeAbiParameters)([READ_SPEC_ABI_PARAM], [spec]);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Assemble a `PreparedRead` from an already-fetched preflight. Pure — no network.
|
|
40
|
+
* Use directly when preparing several reads from one preflight.
|
|
41
|
+
*/
|
|
42
|
+
function buildReadSpecFromPreflight(preflight, params, defaults = {}) {
|
|
43
|
+
const dest = preflight.destination;
|
|
44
|
+
if ((0, destination_1.resolveDestination)(params.destination).caip2 !== dest.caip2) {
|
|
45
|
+
throw new errors_1.InvalidReadQueryError('preflight destination does not match the requested destination');
|
|
46
|
+
}
|
|
47
|
+
const isWeb2 = dest.namespace === read_state_1.READ_NAMESPACE.WEB2;
|
|
48
|
+
const minConfirmations = params.minConfirmations ?? read_state_1.MIN_CONFIRMATIONS_FLOOR;
|
|
49
|
+
// --- pin ---
|
|
50
|
+
let blockNumber;
|
|
51
|
+
if (isWeb2) {
|
|
52
|
+
if (params.blockNumber !== undefined && params.blockNumber !== 0n) {
|
|
53
|
+
throw new errors_1.InvalidReadQueryError('web2 is heightless: blockNumber must be 0 (or omitted)');
|
|
54
|
+
}
|
|
55
|
+
blockNumber = 0n;
|
|
56
|
+
}
|
|
57
|
+
else if (params.blockNumber !== undefined) {
|
|
58
|
+
blockNumber = params.blockNumber;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// Back off by minConfirmations: validators hold until latest ≥ blockNumber + minConfirmations,
|
|
62
|
+
// and the oracle height IS roughly latest — pinning at the head would always wait.
|
|
63
|
+
const backed = preflight.observedChainHeight - BigInt(minConfirmations);
|
|
64
|
+
blockNumber = backed >= 1n ? backed : 1n;
|
|
65
|
+
}
|
|
66
|
+
// --- envelope ---
|
|
67
|
+
const encodedQuery = (0, envelopes_1.encodeReadQuery)(params.destination, params.query, {
|
|
68
|
+
blockNumber,
|
|
69
|
+
minSlot: dest.namespace === read_state_1.READ_NAMESPACE.SVM ? blockNumber : undefined,
|
|
70
|
+
});
|
|
71
|
+
// --- money ---
|
|
72
|
+
const callbackBudget = params.callbackBudget ?? (0, budget_1.sizeCallbackBudget)(params.callbackGasLimit, preflight.pushGasPrice, params.budgetBuffer);
|
|
73
|
+
const value = preflight.protocolFee + callbackBudget;
|
|
74
|
+
const bps = BigInt(params.maxFeeBufferBps ?? 0);
|
|
75
|
+
const maxFee = params.maxFee ?? value + (value * bps) / 10000n;
|
|
76
|
+
// --- identities ---
|
|
77
|
+
const refundTo = params.refundTo ?? defaults.refundTo;
|
|
78
|
+
if (!refundTo || !(0, viem_1.isAddress)(refundTo)) {
|
|
79
|
+
throw new errors_1.InvalidReadSpecError(['ZERO_REVERT_RECIPIENT'], {
|
|
80
|
+
destination: dest.caip2,
|
|
81
|
+
hint: 'Pass refundTo (where unspent budget is pushed). In the SDK it defaults to your Push-side account.',
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
let owner;
|
|
85
|
+
if (dest.namespace === read_state_1.READ_NAMESPACE.SVM) {
|
|
86
|
+
if (!encodedQuery.ownerBytes)
|
|
87
|
+
throw new errors_1.InvalidReadQueryError('SVM query did not yield the 32-byte owner');
|
|
88
|
+
if (params.owner !== undefined)
|
|
89
|
+
throw new errors_1.InvalidReadQueryError('SVM reads take the account from the query, not `owner`');
|
|
90
|
+
owner = encodedQuery.ownerBytes;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
owner = params.owner ?? refundTo.toLowerCase(); // validators ignore it for EVM; any non-empty bytes
|
|
94
|
+
}
|
|
95
|
+
const expiryPushChainHeight = params.expiryPushChainHeight ?? preflight.pushBlockNumber + (params.expiryBlocks ?? read_state_1.DEFAULT_EXPIRY_BLOCKS);
|
|
96
|
+
const spec = {
|
|
97
|
+
account: { chainNamespace: dest.chainNamespace, chainId: dest.chainId, owner },
|
|
98
|
+
query: encodedQuery.encoded,
|
|
99
|
+
minConfirmations,
|
|
100
|
+
blockNumber,
|
|
101
|
+
expiryPushChainHeight,
|
|
102
|
+
maxFee,
|
|
103
|
+
revertRecipient: refundTo,
|
|
104
|
+
};
|
|
105
|
+
(0, validate_1.assertValidReadSpec)({ spec, value, callbackGasLimit: params.callbackGasLimit, preflight });
|
|
106
|
+
return {
|
|
107
|
+
callback: params.callback,
|
|
108
|
+
queryKey: (0, registry_1.computeReadQueryKey)(params.destination, params.query),
|
|
109
|
+
chain: dest.caip2,
|
|
110
|
+
spec,
|
|
111
|
+
specTuple: toTuple(spec),
|
|
112
|
+
encodedSpec: encodeSpec(spec),
|
|
113
|
+
value,
|
|
114
|
+
protocolFee: preflight.protocolFee,
|
|
115
|
+
callbackBudget,
|
|
116
|
+
fees: { protocolFee: preflight.protocolFee, callbackBudget, total: value },
|
|
117
|
+
callbackGasLimit: params.callbackGasLimit,
|
|
118
|
+
encodedQuery,
|
|
119
|
+
resultShape: encodedQuery.resultShape,
|
|
120
|
+
preflight,
|
|
121
|
+
warnings: [...encodedQuery.warnings],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Preflight + build. Adds the `refundTo` advisory: a contract recipient that is not a
|
|
126
|
+
* UEA must have a payable receive() or the refund is forfeited to the admin rescue
|
|
127
|
+
* pool (verified live). UEAs (UEA_EVM / UEA_SVM) always have one.
|
|
128
|
+
*/
|
|
129
|
+
async function prepareRead(deps, params) {
|
|
130
|
+
const emit = deps.emit ?? (() => undefined);
|
|
131
|
+
const dest = (0, destination_1.resolveDestination)(params.destination);
|
|
132
|
+
emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_101, dest.caip2, dest.namespace, params.query.type);
|
|
133
|
+
emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_01, dest.caip2);
|
|
134
|
+
let preflight;
|
|
135
|
+
try {
|
|
136
|
+
preflight = await (0, preflight_1.preflightRead)(deps, params.destination);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
if (error instanceof errors_1.ReadHeightUnavailableError)
|
|
140
|
+
emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_03, dest.caip2);
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
const prepared = buildReadSpecFromPreflight(preflight, params, { refundTo: deps.defaultRefundTo });
|
|
144
|
+
emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_02, prepared.protocolFee, prepared.callbackBudget, prepared.value, prepared.spec.blockNumber, prepared.spec.expiryPushChainHeight);
|
|
145
|
+
if (params.query.type === 'http') {
|
|
146
|
+
const matched = Object.keys(params.query.headers ?? {}).filter((name) => /auth|key|token|secret|bearer/i.test(name));
|
|
147
|
+
if (matched.length)
|
|
148
|
+
emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_103_03, matched);
|
|
149
|
+
}
|
|
150
|
+
const refundTo = prepared.spec.revertRecipient;
|
|
151
|
+
const code = await deps.pushClient.publicClient.getCode({ address: refundTo });
|
|
152
|
+
// EIP-7702 delegation designator (0xef0100 + delegate): an EOA that batches via the SDK's
|
|
153
|
+
// executor. It receives value like an EOA — refunds to such accounts have landed live.
|
|
154
|
+
const isDelegatedEoa = !!code && code.toLowerCase().startsWith('0xef0100');
|
|
155
|
+
if (code && code !== '0x' && !isDelegatedEoa) {
|
|
156
|
+
const [, isUEA] = await deps.pushClient.readContract({
|
|
157
|
+
address: chain_1.UEA_FACTORY[deps.pushNetwork],
|
|
158
|
+
abi: uea_factory_1.UEA_FACTORY_ABI,
|
|
159
|
+
functionName: 'getOriginForUEA',
|
|
160
|
+
args: [refundTo],
|
|
161
|
+
});
|
|
162
|
+
if (!isUEA) {
|
|
163
|
+
emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_05, refundTo);
|
|
164
|
+
prepared.warnings.push(`refundTo ${refundTo} is a contract that is not a UEA — it must have a payable receive() or the unspent callback budget is forfeited`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return prepared;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Splice the prepared spec into the app's own entrypoint.
|
|
171
|
+
* Default argument order is `(spec, callbackGasLimit)`; pass `args` to remap.
|
|
172
|
+
*/
|
|
173
|
+
function toCallData(prepared, target) {
|
|
174
|
+
// Positional tuple: viem accepts it whether the app ABI names the struct components or not.
|
|
175
|
+
const args = target.args ? target.args(prepared.specTuple, prepared.callbackGasLimit) : [prepared.specTuple, prepared.callbackGasLimit];
|
|
176
|
+
return {
|
|
177
|
+
data: (0, viem_1.encodeFunctionData)({ abi: target.abi, functionName: target.functionName, args: args }),
|
|
178
|
+
value: prepared.value,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* eth_call `requestExternalReadSelf` with `from` = the app contract, so validation
|
|
183
|
+
* reverts surface before broadcast, decoded into the contract's custom errors.
|
|
184
|
+
* Only meaningful for the app-contract persona: `callbackTarget` becomes `msg.sender`.
|
|
185
|
+
*/
|
|
186
|
+
async function simulateRead(deps, prepared, opts) {
|
|
187
|
+
const age = Date.now() - prepared.preflight.fetchedAt;
|
|
188
|
+
if (age > (opts.staleAfterMs ?? read_state_1.READ_PREFLIGHT_STALE_MS)) {
|
|
189
|
+
prepared.warnings.push(`preflight is ${Math.round(age / 1000)} s old — pushBlockNumber moves every block; rebuild before sending`);
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
await deps.pushClient.publicClient.simulateContract({
|
|
193
|
+
address: prepared.preflight.universalCallback,
|
|
194
|
+
abi: universalCallback_evm_1.UNIVERSAL_CALLBACK_EVM,
|
|
195
|
+
functionName: 'requestExternalReadSelf',
|
|
196
|
+
args: [prepared.spec, opts.callbackSelector, prepared.callbackGasLimit],
|
|
197
|
+
account: opts.appContract,
|
|
198
|
+
value: prepared.value,
|
|
199
|
+
// In the real flow the app contract forwards the msg.value it just received from the
|
|
200
|
+
// user, so for the simulation it must "hold" it. Without this the node answers
|
|
201
|
+
// "insufficient balance for transfer" — and maps it to JSON-RPC -32602, which viem
|
|
202
|
+
// renders as the misleading "Missing or invalid parameters". Verified on Donut.
|
|
203
|
+
stateOverride: [{ address: opts.appContract, balance: prepared.value * 2n + 10n ** 18n }],
|
|
204
|
+
});
|
|
205
|
+
return { ok: true };
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
if (err instanceof viem_1.BaseError) {
|
|
209
|
+
const reverted = err.walk((e) => e instanceof viem_1.ContractFunctionRevertedError);
|
|
210
|
+
if (reverted instanceof viem_1.ContractFunctionRevertedError && reverted.data) {
|
|
211
|
+
return { ok: false, error: reverted.shortMessage, errorName: reverted.data.errorName, args: reverted.data.args };
|
|
212
|
+
}
|
|
213
|
+
// Surface the node's own reason when viem's summary is generic.
|
|
214
|
+
const details = err.details || err.cause?.details;
|
|
215
|
+
return { ok: false, error: details ? `${err.shortMessage} (${details})` : err.shortMessage };
|
|
216
|
+
}
|
|
217
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/** Fresh validation only: never rebuild or mutate the prepared request. */
|
|
221
|
+
async function revalidateRead(deps, prepared) {
|
|
222
|
+
const [preflight, block] = await Promise.all([
|
|
223
|
+
(0, preflight_1.preflightRead)(deps, {
|
|
224
|
+
chainNamespace: prepared.spec.account.chainNamespace,
|
|
225
|
+
chainId: prepared.spec.account.chainId,
|
|
226
|
+
}),
|
|
227
|
+
deps.pushClient.publicClient.getBlock({ blockTag: 'latest' }),
|
|
228
|
+
]);
|
|
229
|
+
// Mirrors node keeper.CallbackCost / CanAffordCallback (x/ucallback/keeper/evm.go).
|
|
230
|
+
// The module prices declared gas at base fee, without tips or the SDK sizing buffer.
|
|
231
|
+
const baseFee = block.baseFeePerGas;
|
|
232
|
+
if (baseFee === null || baseFee === undefined) {
|
|
233
|
+
throw new errors_1.ReadStateError('READ_CALLBACK_BASE_FEE_UNAVAILABLE', 'cannot validate callback affordability without the current Push base fee');
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
(0, validate_1.assertValidReadSpec)({ spec: prepared.spec, value: prepared.value, callbackGasLimit: prepared.callbackGasLimit, preflight });
|
|
237
|
+
if (prepared.value - preflight.protocolFee < prepared.callbackGasLimit * baseFee) {
|
|
238
|
+
throw new errors_1.InvalidReadSpecError(['INSUFFICIENT_CALLBACK_BUDGET']);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
if (error instanceof errors_1.InvalidReadSpecError) {
|
|
243
|
+
throw new errors_1.InvalidReadSpecError([...error.violations], {
|
|
244
|
+
destination: preflight.destination.caip2,
|
|
245
|
+
hint: 'Prepared read is no longer valid. Call prepareRead again and review its pin, expiry and payment before executing.',
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
throw error;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=spec-builder.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type Idl } from '@coral-xyz/anchor';
|
|
2
|
+
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import type { CHAIN } from '../constants/enums';
|
|
4
|
+
/** snake_case, camelCase and PascalCase spellings of one name share a key. */
|
|
5
|
+
export declare function idlNameKey(name: string): string;
|
|
6
|
+
/** Structural checks the coder does not make, so a bad IDL fails at prepare time. */
|
|
7
|
+
export declare function validateIdl(idl: Idl): void;
|
|
8
|
+
/** The IDL's own spelling of an account layout name given in any case style. */
|
|
9
|
+
export declare function resolveAccountName(idl: Idl, name: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Decode account bytes with the IDL. With `accountName`, the data's discriminator
|
|
12
|
+
* must match that layout; without it, the layout is the one whose discriminator
|
|
13
|
+
* prefixes the data.
|
|
14
|
+
*/
|
|
15
|
+
export declare function decodeIdlAccount(idl: Idl, data: Uint8Array, accountName?: string): {
|
|
16
|
+
accountName: string;
|
|
17
|
+
value: unknown;
|
|
18
|
+
};
|
|
19
|
+
/** Inspect the mint owner; the chain alone cannot distinguish SPL Token and Token-2022. */
|
|
20
|
+
export declare function detectTokenProgram(mint: string, chain: CHAIN, rpcUrls?: string[]): Promise<PublicKey>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.idlNameKey = idlNameKey;
|
|
4
|
+
exports.validateIdl = validateIdl;
|
|
5
|
+
exports.resolveAccountName = resolveAccountName;
|
|
6
|
+
exports.decodeIdlAccount = decodeIdlAccount;
|
|
7
|
+
exports.detectTokenProgram = detectTokenProgram;
|
|
8
|
+
const anchor_1 = require("@coral-xyz/anchor");
|
|
9
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
10
|
+
const chain_1 = require("../constants/chain");
|
|
11
|
+
const buffer_1 = require("buffer");
|
|
12
|
+
const errors_1 = require("./errors");
|
|
13
|
+
const svm_1 = require("./envelopes/svm");
|
|
14
|
+
/** snake_case, camelCase and PascalCase spellings of one name share a key. */
|
|
15
|
+
function idlNameKey(name) {
|
|
16
|
+
return name.replace(/_/g, '').toLowerCase();
|
|
17
|
+
}
|
|
18
|
+
/** Structural checks the coder does not make, so a bad IDL fails at prepare time. */
|
|
19
|
+
function validateIdl(idl) {
|
|
20
|
+
try {
|
|
21
|
+
if (!idl || typeof idl !== 'object')
|
|
22
|
+
throw new Error('idl must be an Anchor IDL object');
|
|
23
|
+
new web3_js_1.PublicKey(idl.address);
|
|
24
|
+
if (!idl.accounts?.length)
|
|
25
|
+
throw new Error('the IDL declares no accounts');
|
|
26
|
+
for (const a of idl.accounts) {
|
|
27
|
+
const d = a.discriminator;
|
|
28
|
+
if (!Array.isArray(d) || d.length === 0 || d.some(b => !Number.isInteger(b) || b < 0 || b > 255)) {
|
|
29
|
+
throw new Error(`account ${a.name}: discriminator must be a non-empty byte array`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
new anchor_1.BorshAccountsCoder(idl);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
throw new errors_1.InvalidReadQueryError(`invalid Solana account IDL: ${error.message}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** The IDL's own spelling of an account layout name given in any case style. */
|
|
39
|
+
function resolveAccountName(idl, name) {
|
|
40
|
+
const accounts = idl.accounts ?? [];
|
|
41
|
+
const exact = accounts.find(a => a.name === name);
|
|
42
|
+
if (exact)
|
|
43
|
+
return exact.name;
|
|
44
|
+
const key = idlNameKey(name);
|
|
45
|
+
const matches = accounts.filter(a => idlNameKey(a.name) === key);
|
|
46
|
+
if (matches.length === 1)
|
|
47
|
+
return matches[0].name;
|
|
48
|
+
const known = accounts.map(a => a.name).join(', ') || 'none';
|
|
49
|
+
throw new errors_1.InvalidReadQueryError(matches.length > 1 ? `functionName ${name} is ambiguous in the IDL (${matches.map(a => a.name).join(', ')})` : `functionName ${name} is not an account in the IDL (accounts: ${known})`);
|
|
50
|
+
}
|
|
51
|
+
function hasDiscriminator(a, data) {
|
|
52
|
+
return data.length >= a.discriminator.length && a.discriminator.every((b, i) => data[i] === b);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Decode account bytes with the IDL. With `accountName`, the data's discriminator
|
|
56
|
+
* must match that layout; without it, the layout is the one whose discriminator
|
|
57
|
+
* prefixes the data.
|
|
58
|
+
*/
|
|
59
|
+
function decodeIdlAccount(idl, data, accountName) {
|
|
60
|
+
const accounts = idl.accounts ?? [];
|
|
61
|
+
let def;
|
|
62
|
+
if (accountName !== undefined) {
|
|
63
|
+
def = accounts.find(a => a.name === resolveAccountName(idl, accountName));
|
|
64
|
+
if (def && !hasDiscriminator(def, data)) {
|
|
65
|
+
throw new errors_1.ReadDecodeError(`account data discriminator does not match ${def.name}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const found = accounts.filter(a => hasDiscriminator(a, data));
|
|
70
|
+
// Longest match wins if one discriminator prefixes another.
|
|
71
|
+
def = found.sort((x, y) => y.discriminator.length - x.discriminator.length)[0];
|
|
72
|
+
if (!def) {
|
|
73
|
+
const head = buffer_1.Buffer.from(data.subarray(0, 8)).toString('hex');
|
|
74
|
+
throw new errors_1.ReadDecodeError(`no IDL account discriminator matches the account data (0x${head})`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!def)
|
|
78
|
+
throw new errors_1.ReadDecodeError('account not found in the IDL');
|
|
79
|
+
return { accountName: def.name, value: new anchor_1.BorshAccountsCoder(idl).decode(def.name, buffer_1.Buffer.from(data)) };
|
|
80
|
+
}
|
|
81
|
+
/** Inspect the mint owner; the chain alone cannot distinguish SPL Token and Token-2022. */
|
|
82
|
+
async function detectTokenProgram(mint, chain, rpcUrls) {
|
|
83
|
+
const address = new web3_js_1.PublicKey(mint);
|
|
84
|
+
const urls = rpcUrls ?? chain_1.CHAIN_INFO[chain]?.defaultRPC;
|
|
85
|
+
if (!urls?.length)
|
|
86
|
+
throw new errors_1.InvalidReadQueryError(`no Solana RPC configured for ${chain}`);
|
|
87
|
+
let lastError;
|
|
88
|
+
for (const url of urls) {
|
|
89
|
+
let info;
|
|
90
|
+
try {
|
|
91
|
+
info = await new web3_js_1.Connection(url, 'finalized').getAccountInfo(address, 'finalized');
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
lastError = error;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (!info)
|
|
98
|
+
throw new errors_1.InvalidReadQueryError(`token mint does not exist: ${mint}`);
|
|
99
|
+
if (!info.owner.equals(svm_1.TOKEN_PROGRAM_ID) && !info.owner.equals(svm_1.TOKEN_2022_PROGRAM_ID)) {
|
|
100
|
+
throw new errors_1.InvalidReadQueryError('mint is not owned by SPL Token or Token-2022');
|
|
101
|
+
}
|
|
102
|
+
// Mint base layout: 82 bytes, initialized flag at byte 45. Token-2022
|
|
103
|
+
// extensions pad to 165 bytes and carry AccountType.Mint (1) at byte 165.
|
|
104
|
+
if (info.executable || info.data.length < 82 || info.data[45] !== 1 ||
|
|
105
|
+
(info.owner.equals(svm_1.TOKEN_PROGRAM_ID) && info.data.length !== 82) ||
|
|
106
|
+
(info.owner.equals(svm_1.TOKEN_2022_PROGRAM_ID) && info.data.length !== 82 &&
|
|
107
|
+
(info.data.length < 166 || info.data[165] !== 1))) {
|
|
108
|
+
throw new errors_1.InvalidReadQueryError('token address is not an initialized mint');
|
|
109
|
+
}
|
|
110
|
+
return info.owner;
|
|
111
|
+
}
|
|
112
|
+
throw lastError;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=svm-account.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PDA derivation for `read(programId, { idl, functionName, args })`.
|
|
3
|
+
*
|
|
4
|
+
* The seed layout comes from the IDL, never from a guessed encoding: Anchor
|
|
5
|
+
* records each PDA's seeds on the instruction accounts that use it. `args` fill
|
|
6
|
+
* the non-constant seeds in order, encoded as the IDL declares them.
|
|
7
|
+
*/
|
|
8
|
+
import type { Idl } from '@coral-xyz/anchor';
|
|
9
|
+
import { PublicKey } from '@solana/web3.js';
|
|
10
|
+
/** Derive the PDA of account layout `functionName` from its IDL seed template and positional `args`. */
|
|
11
|
+
export declare function deriveIdlPda(idl: Idl, functionName: string, args?: readonly unknown[]): PublicKey;
|
|
12
|
+
/** Whether `subject` is the IDL's program id (base58 or 0x-hex). */
|
|
13
|
+
export declare function isProgramSubject(idl: Idl, subject: string): boolean;
|