@seljs/runtime 1.3.0-beta.1 → 1.3.0-beta.12
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/dist/analysis/call-collector.cjs +19 -0
- package/dist/analysis/call-collector.mjs +19 -0
- package/dist/analysis/dependency-analyzer.cjs +1 -2
- package/dist/analysis/dependency-analyzer.mjs +1 -1
- package/dist/analysis/round-planner.cjs +1 -2
- package/dist/analysis/round-planner.mjs +1 -1
- package/dist/environment/builtin-contracts.cjs +22 -0
- package/dist/environment/builtin-contracts.mjs +22 -0
- package/dist/environment/client.cjs +16 -0
- package/dist/environment/client.d.cts +33 -0
- package/dist/environment/client.d.mts +33 -0
- package/dist/environment/client.mjs +16 -0
- package/dist/environment/contract-caller.cjs +13 -12
- package/dist/environment/contract-caller.mjs +13 -12
- package/dist/environment/environment.cjs +35 -10
- package/dist/environment/environment.d.cts +5 -0
- package/dist/environment/environment.d.mts +5 -0
- package/dist/environment/environment.mjs +35 -10
- package/dist/environment/index.cjs +1 -0
- package/dist/environment/index.d.mts +1 -0
- package/dist/environment/index.mjs +1 -0
- package/dist/environment/types.d.cts +4 -4
- package/dist/environment/types.d.mts +4 -4
- package/dist/errors/errors.cjs +7 -0
- package/dist/errors/errors.d.cts +7 -1
- package/dist/errors/errors.d.mts +7 -1
- package/dist/errors/errors.mjs +7 -1
- package/dist/errors/index.d.mts +1 -1
- package/dist/execution/multi-round-executor.cjs +1 -4
- package/dist/execution/multi-round-executor.mjs +1 -3
- package/dist/execution/multicall-batcher.cjs +11 -9
- package/dist/execution/multicall-batcher.mjs +11 -9
- package/dist/execution/multicall.cjs +28 -4
- package/dist/execution/multicall.mjs +26 -4
- package/dist/execution/round-executor.cjs +4 -12
- package/dist/execution/round-executor.mjs +4 -12
- package/dist/execution/types.d.cts +40 -16
- package/dist/execution/types.d.mts +40 -16
- package/dist/index.cjs +3 -0
- package/dist/index.d.cts +3 -2
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +3 -2
- package/package.json +7 -7
|
@@ -196,6 +196,25 @@ const collectCalls = (ast, registry) => {
|
|
|
196
196
|
return;
|
|
197
197
|
}
|
|
198
198
|
if (!receiverName || !registry.get(receiverName)) {
|
|
199
|
+
if (method === "balance" && args.length === 0) {
|
|
200
|
+
const receiverNode = node.args[1];
|
|
201
|
+
const { arg: receiverArg, traversed } = classifyArg(receiverNode);
|
|
202
|
+
if (receiverArg) {
|
|
203
|
+
const call = {
|
|
204
|
+
id: generateCallId("__multicall3", "getEthBalance", [receiverArg]),
|
|
205
|
+
contract: "__multicall3",
|
|
206
|
+
method: "getEthBalance",
|
|
207
|
+
args: [receiverArg],
|
|
208
|
+
astNode: node
|
|
209
|
+
};
|
|
210
|
+
calls.push(call);
|
|
211
|
+
debug("found address accessor %s (id=%s)", "balance", call.id);
|
|
212
|
+
return call;
|
|
213
|
+
}
|
|
214
|
+
deferredNodes.add(node);
|
|
215
|
+
if (!traversed) traverse(receiverNode);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
199
218
|
handleNonContractRCall(node, method, args);
|
|
200
219
|
return;
|
|
201
220
|
}
|
|
@@ -195,6 +195,25 @@ const collectCalls = (ast, registry) => {
|
|
|
195
195
|
return;
|
|
196
196
|
}
|
|
197
197
|
if (!receiverName || !registry.get(receiverName)) {
|
|
198
|
+
if (method === "balance" && args.length === 0) {
|
|
199
|
+
const receiverNode = node.args[1];
|
|
200
|
+
const { arg: receiverArg, traversed } = classifyArg(receiverNode);
|
|
201
|
+
if (receiverArg) {
|
|
202
|
+
const call = {
|
|
203
|
+
id: generateCallId("__multicall3", "getEthBalance", [receiverArg]),
|
|
204
|
+
contract: "__multicall3",
|
|
205
|
+
method: "getEthBalance",
|
|
206
|
+
args: [receiverArg],
|
|
207
|
+
astNode: node
|
|
208
|
+
};
|
|
209
|
+
calls.push(call);
|
|
210
|
+
debug("found address accessor %s (id=%s)", "balance", call.id);
|
|
211
|
+
return call;
|
|
212
|
+
}
|
|
213
|
+
deferredNodes.add(node);
|
|
214
|
+
if (!traversed) traverse(receiverNode);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
198
217
|
handleNonContractRCall(node, method, args);
|
|
199
218
|
return;
|
|
200
219
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
const require_debug = require("../debug.cjs");
|
|
2
1
|
const require_errors = require("../errors/errors.cjs");
|
|
3
2
|
require("../errors/index.cjs");
|
|
4
3
|
//#region src/analysis/dependency-analyzer.ts
|
|
5
|
-
const debug =
|
|
4
|
+
const debug = require("../debug.cjs").createLogger("analysis:dependency");
|
|
6
5
|
/**
|
|
7
6
|
* Detects circular dependencies in the graph using DFS with a recursion stack.
|
|
8
7
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createLogger } from "../debug.mjs";
|
|
2
1
|
import { CircularDependencyError } from "../errors/errors.mjs";
|
|
3
2
|
import "../errors/index.mjs";
|
|
3
|
+
import { createLogger } from "../debug.mjs";
|
|
4
4
|
//#region src/analysis/dependency-analyzer.ts
|
|
5
5
|
const debug = createLogger("analysis:dependency");
|
|
6
6
|
/**
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
const require_debug = require("../debug.cjs");
|
|
2
1
|
const require_errors = require("../errors/errors.cjs");
|
|
3
2
|
require("../errors/index.cjs");
|
|
4
3
|
//#region src/analysis/round-planner.ts
|
|
5
|
-
const debug =
|
|
4
|
+
const debug = require("../debug.cjs").createLogger("analysis:plan");
|
|
6
5
|
/**
|
|
7
6
|
* Plans execution rounds from a dependency graph using topological sorting.
|
|
8
7
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createLogger } from "../debug.mjs";
|
|
2
1
|
import { ExecutionLimitError } from "../errors/errors.mjs";
|
|
3
2
|
import "../errors/index.mjs";
|
|
3
|
+
import { createLogger } from "../debug.mjs";
|
|
4
4
|
//#region src/analysis/round-planner.ts
|
|
5
5
|
const debug = createLogger("analysis:plan");
|
|
6
6
|
/**
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const require_multicall = require("../execution/multicall.cjs");
|
|
2
|
+
//#region src/environment/builtin-contracts.ts
|
|
3
|
+
/**
|
|
4
|
+
* Returns built-in contract schemas that are always available in the runtime.
|
|
5
|
+
* These are internal contracts not defined by the user schema but required
|
|
6
|
+
* for built-in features like address accessors.
|
|
7
|
+
*/
|
|
8
|
+
const getBuiltinContracts = (multicall) => [{
|
|
9
|
+
name: "__multicall3",
|
|
10
|
+
address: multicall?.address ?? "0xcA11bde05977b3631167028862bE2a173976CA11",
|
|
11
|
+
methods: [{
|
|
12
|
+
name: "getEthBalance",
|
|
13
|
+
params: [{
|
|
14
|
+
name: "addr",
|
|
15
|
+
type: "sol_address"
|
|
16
|
+
}],
|
|
17
|
+
returns: "sol_int",
|
|
18
|
+
abi: require_multicall.getEthBalanceAbi
|
|
19
|
+
}]
|
|
20
|
+
}];
|
|
21
|
+
//#endregion
|
|
22
|
+
exports.getBuiltinContracts = getBuiltinContracts;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { getEthBalanceAbi } from "../execution/multicall.mjs";
|
|
2
|
+
//#region src/environment/builtin-contracts.ts
|
|
3
|
+
/**
|
|
4
|
+
* Returns built-in contract schemas that are always available in the runtime.
|
|
5
|
+
* These are internal contracts not defined by the user schema but required
|
|
6
|
+
* for built-in features like address accessors.
|
|
7
|
+
*/
|
|
8
|
+
const getBuiltinContracts = (multicall) => [{
|
|
9
|
+
name: "__multicall3",
|
|
10
|
+
address: multicall?.address ?? "0xcA11bde05977b3631167028862bE2a173976CA11",
|
|
11
|
+
methods: [{
|
|
12
|
+
name: "getEthBalance",
|
|
13
|
+
params: [{
|
|
14
|
+
name: "addr",
|
|
15
|
+
type: "sol_address"
|
|
16
|
+
}],
|
|
17
|
+
returns: "sol_int",
|
|
18
|
+
abi: getEthBalanceAbi
|
|
19
|
+
}]
|
|
20
|
+
}];
|
|
21
|
+
//#endregion
|
|
22
|
+
export { getBuiltinContracts };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const require_errors = require("../errors/errors.cjs");
|
|
2
|
+
require("../errors/index.cjs");
|
|
3
|
+
//#region src/environment/client.ts
|
|
4
|
+
/**
|
|
5
|
+
* Validates that an object satisfies the SELClient interface.
|
|
6
|
+
* Throws SELClientError if validation fails.
|
|
7
|
+
* Called at construction time for fail-fast behavior.
|
|
8
|
+
*/
|
|
9
|
+
function validateClient(client) {
|
|
10
|
+
if (!client || typeof client !== "object") throw new require_errors.SELClientError("Client must be an object");
|
|
11
|
+
const c = client;
|
|
12
|
+
if (typeof c["call"] !== "function") throw new require_errors.SELClientError("Client must implement call({ to, data, blockNumber? }). ");
|
|
13
|
+
if (typeof c["getBlockNumber"] !== "function") throw new require_errors.SELClientError("Client must implement getBlockNumber(). ");
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
exports.validateClient = validateClient;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/environment/client.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Minimal client interface for SEL runtime contract execution.
|
|
4
|
+
*
|
|
5
|
+
* Framework-agnostic: works with viem PublicClient, ethers.js Provider,
|
|
6
|
+
* web3.js, or any object that can make eth_call and eth_blockNumber requests.
|
|
7
|
+
*
|
|
8
|
+
* A viem PublicClient structurally satisfies this interface.
|
|
9
|
+
*/
|
|
10
|
+
interface SELClient {
|
|
11
|
+
/**
|
|
12
|
+
* Execute an eth_call against a contract
|
|
13
|
+
*/
|
|
14
|
+
call: (params: {
|
|
15
|
+
to: `0x${string}`;
|
|
16
|
+
data: `0x${string}`;
|
|
17
|
+
blockNumber?: bigint;
|
|
18
|
+
}) => Promise<{
|
|
19
|
+
data?: `0x${string}` | undefined;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Get the current block number (eth_blockNumber) for pinning reads
|
|
23
|
+
*/
|
|
24
|
+
getBlockNumber: () => Promise<bigint>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Validates that an object satisfies the SELClient interface.
|
|
28
|
+
* Throws SELClientError if validation fails.
|
|
29
|
+
* Called at construction time for fail-fast behavior.
|
|
30
|
+
*/
|
|
31
|
+
declare function validateClient(client: unknown): asserts client is SELClient;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { SELClient, validateClient };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/environment/client.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Minimal client interface for SEL runtime contract execution.
|
|
4
|
+
*
|
|
5
|
+
* Framework-agnostic: works with viem PublicClient, ethers.js Provider,
|
|
6
|
+
* web3.js, or any object that can make eth_call and eth_blockNumber requests.
|
|
7
|
+
*
|
|
8
|
+
* A viem PublicClient structurally satisfies this interface.
|
|
9
|
+
*/
|
|
10
|
+
interface SELClient {
|
|
11
|
+
/**
|
|
12
|
+
* Execute an eth_call against a contract
|
|
13
|
+
*/
|
|
14
|
+
call: (params: {
|
|
15
|
+
to: `0x${string}`;
|
|
16
|
+
data: `0x${string}`;
|
|
17
|
+
blockNumber?: bigint;
|
|
18
|
+
}) => Promise<{
|
|
19
|
+
data?: `0x${string}` | undefined;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Get the current block number (eth_blockNumber) for pinning reads
|
|
23
|
+
*/
|
|
24
|
+
getBlockNumber: () => Promise<bigint>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Validates that an object satisfies the SELClient interface.
|
|
28
|
+
* Throws SELClientError if validation fails.
|
|
29
|
+
* Called at construction time for fail-fast behavior.
|
|
30
|
+
*/
|
|
31
|
+
declare function validateClient(client: unknown): asserts client is SELClient;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { SELClient, validateClient };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SELClientError } from "../errors/errors.mjs";
|
|
2
|
+
import "../errors/index.mjs";
|
|
3
|
+
//#region src/environment/client.ts
|
|
4
|
+
/**
|
|
5
|
+
* Validates that an object satisfies the SELClient interface.
|
|
6
|
+
* Throws SELClientError if validation fails.
|
|
7
|
+
* Called at construction time for fail-fast behavior.
|
|
8
|
+
*/
|
|
9
|
+
function validateClient(client) {
|
|
10
|
+
if (!client || typeof client !== "object") throw new SELClientError("Client must be an object");
|
|
11
|
+
const c = client;
|
|
12
|
+
if (typeof c["call"] !== "function") throw new SELClientError("Client must implement call({ to, data, blockNumber? }). ");
|
|
13
|
+
if (typeof c["getBlockNumber"] !== "function") throw new SELClientError("Client must implement getBlockNumber(). ");
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { validateClient };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
-
const require_replay_cache = require("./replay-cache.cjs");
|
|
3
|
-
const require_debug = require("../debug.cjs");
|
|
4
2
|
const require_errors = require("../errors/errors.cjs");
|
|
5
3
|
require("../errors/index.cjs");
|
|
6
|
-
|
|
4
|
+
const require_replay_cache = require("./replay-cache.cjs");
|
|
5
|
+
const require_debug = require("../debug.cjs");
|
|
6
|
+
let ox = require("ox");
|
|
7
7
|
//#region src/environment/contract-caller.ts
|
|
8
8
|
const debug = require_debug.createLogger("contract-caller");
|
|
9
9
|
/**
|
|
@@ -42,12 +42,16 @@ const executeContractCall = async (contract, method, args, options) => {
|
|
|
42
42
|
});
|
|
43
43
|
options.callCounter?.increment(contract.name, method.name);
|
|
44
44
|
try {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
const data = ox.AbiFunction.encodeData([method.abi], method.name, normalizedArgs);
|
|
46
|
+
const result = await options.client.call({
|
|
47
|
+
to: contract.address,
|
|
48
|
+
data
|
|
49
|
+
});
|
|
50
|
+
if (!result.data) throw new require_errors.SELContractError(`Contract call returned no data: ${contract.name}.${method.name}`, {
|
|
51
|
+
contractName: contract.name,
|
|
52
|
+
methodName: method.name
|
|
50
53
|
});
|
|
54
|
+
return ox.AbiFunction.decodeResult([method.abi], method.name, result.data);
|
|
51
55
|
} catch (error) {
|
|
52
56
|
if (error instanceof require_errors.SELContractError) throw error;
|
|
53
57
|
throw new require_errors.SELContractError(`Contract call failed: ${contract.name}.${method.name}`, {
|
|
@@ -58,10 +62,7 @@ const executeContractCall = async (contract, method, args, options) => {
|
|
|
58
62
|
}
|
|
59
63
|
};
|
|
60
64
|
const resolveExecutionBlockNumber = async (client) => {
|
|
61
|
-
|
|
62
|
-
if (typeof clientWithGetBlockNumber.getBlockNumber === "function") return await clientWithGetBlockNumber.getBlockNumber();
|
|
63
|
-
if (typeof clientWithGetBlockNumber.request === "function") return;
|
|
64
|
-
return 0n;
|
|
65
|
+
return await client.getBlockNumber();
|
|
65
66
|
};
|
|
66
67
|
const buildContractInfoMap = (contracts) => {
|
|
67
68
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { createReplayCallId } from "./replay-cache.mjs";
|
|
2
|
-
import { createLogger } from "../debug.mjs";
|
|
3
1
|
import { ExecutionLimitError, SELContractError } from "../errors/errors.mjs";
|
|
4
2
|
import "../errors/index.mjs";
|
|
5
|
-
import {
|
|
3
|
+
import { createReplayCallId } from "./replay-cache.mjs";
|
|
4
|
+
import { createLogger } from "../debug.mjs";
|
|
5
|
+
import { AbiFunction } from "ox";
|
|
6
6
|
//#region src/environment/contract-caller.ts
|
|
7
7
|
const debug = createLogger("contract-caller");
|
|
8
8
|
/**
|
|
@@ -41,12 +41,16 @@ const executeContractCall = async (contract, method, args, options) => {
|
|
|
41
41
|
});
|
|
42
42
|
options.callCounter?.increment(contract.name, method.name);
|
|
43
43
|
try {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
const data = AbiFunction.encodeData([method.abi], method.name, normalizedArgs);
|
|
45
|
+
const result = await options.client.call({
|
|
46
|
+
to: contract.address,
|
|
47
|
+
data
|
|
48
|
+
});
|
|
49
|
+
if (!result.data) throw new SELContractError(`Contract call returned no data: ${contract.name}.${method.name}`, {
|
|
50
|
+
contractName: contract.name,
|
|
51
|
+
methodName: method.name
|
|
49
52
|
});
|
|
53
|
+
return AbiFunction.decodeResult([method.abi], method.name, result.data);
|
|
50
54
|
} catch (error) {
|
|
51
55
|
if (error instanceof SELContractError) throw error;
|
|
52
56
|
throw new SELContractError(`Contract call failed: ${contract.name}.${method.name}`, {
|
|
@@ -57,10 +61,7 @@ const executeContractCall = async (contract, method, args, options) => {
|
|
|
57
61
|
}
|
|
58
62
|
};
|
|
59
63
|
const resolveExecutionBlockNumber = async (client) => {
|
|
60
|
-
|
|
61
|
-
if (typeof clientWithGetBlockNumber.getBlockNumber === "function") return await clientWithGetBlockNumber.getBlockNumber();
|
|
62
|
-
if (typeof clientWithGetBlockNumber.request === "function") return;
|
|
63
|
-
return 0n;
|
|
64
|
+
return await client.getBlockNumber();
|
|
64
65
|
};
|
|
65
66
|
const buildContractInfoMap = (contracts) => {
|
|
66
67
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_builtin_contracts = require("./builtin-contracts.cjs");
|
|
3
|
+
const require_errors = require("../errors/errors.cjs");
|
|
4
|
+
require("../errors/index.cjs");
|
|
5
|
+
const require_client = require("./client.cjs");
|
|
2
6
|
const require_context = require("./context.cjs");
|
|
3
7
|
const require_replay_cache = require("./replay-cache.cjs");
|
|
4
8
|
const require_debug = require("../debug.cjs");
|
|
5
|
-
const require_errors = require("../errors/errors.cjs");
|
|
6
|
-
require("../errors/index.cjs");
|
|
7
9
|
const require_contract_caller = require("./contract-caller.cjs");
|
|
8
10
|
const require_error_wrapper = require("./error-wrapper.cjs");
|
|
9
11
|
const require_call_collector = require("../analysis/call-collector.cjs");
|
|
@@ -70,17 +72,22 @@ var SELRuntime = class {
|
|
|
70
72
|
this.maxRounds = limits?.maxRounds ?? 10;
|
|
71
73
|
this.maxCalls = limits?.maxCalls ?? 100;
|
|
72
74
|
this.multicallOptions = config.multicall;
|
|
75
|
+
if (config.client) require_client.validateClient(config.client);
|
|
73
76
|
this.client = config.client;
|
|
74
|
-
this.schema =
|
|
77
|
+
this.schema = {
|
|
78
|
+
...config.schema,
|
|
79
|
+
contracts: [...config.schema.contracts, ...require_builtin_contracts.getBuiltinContracts(config.multicall)]
|
|
80
|
+
};
|
|
75
81
|
const handler = (contractName, methodName, args) => {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
const resolved = this.resolveCall(contractName, methodName, args);
|
|
83
|
+
const contract = this.findContract(resolved.contractName);
|
|
84
|
+
if (!contract) throw new require_errors.SELContractError(`Unknown contract "${resolved.contractName}"`, { contractName: resolved.contractName });
|
|
85
|
+
const method = contract.methods.find((m) => m.name === resolved.methodName);
|
|
86
|
+
if (!method) throw new require_errors.SELContractError(`Unknown method "${resolved.contractName}.${resolved.methodName}"`, {
|
|
87
|
+
contractName: resolved.contractName,
|
|
88
|
+
methodName: resolved.methodName
|
|
82
89
|
});
|
|
83
|
-
return require_contract_caller.executeContractCall(contract, method, args, {
|
|
90
|
+
return require_contract_caller.executeContractCall(contract, method, resolved.args, {
|
|
84
91
|
executionCache: this.currentCache,
|
|
85
92
|
client: this.currentClient ?? this.client,
|
|
86
93
|
codecRegistry: this.codecRegistry,
|
|
@@ -207,6 +214,7 @@ var SELRuntime = class {
|
|
|
207
214
|
async doEvaluate(expression, context, options) {
|
|
208
215
|
debug("evaluate: %s", expression);
|
|
209
216
|
const resolvedClient = options?.client ?? this.client;
|
|
217
|
+
if (resolvedClient && resolvedClient !== this.client) require_client.validateClient(resolvedClient);
|
|
210
218
|
try {
|
|
211
219
|
const { parseResult, collectedCalls, normalizedContext, executionVariables, typeCheckResult, diagnostics } = this.planExecution(expression, context ?? {});
|
|
212
220
|
let executionMeta;
|
|
@@ -238,12 +246,29 @@ var SELRuntime = class {
|
|
|
238
246
|
value,
|
|
239
247
|
meta: executionMeta
|
|
240
248
|
} : { value };
|
|
249
|
+
if (typeCheckResult.type) evalResult.type = typeCheckResult.type;
|
|
241
250
|
if (diagnostics.length > 0) evalResult.diagnostics = diagnostics;
|
|
242
251
|
return evalResult;
|
|
243
252
|
} catch (error) {
|
|
244
253
|
throw require_error_wrapper.wrapError(error);
|
|
245
254
|
}
|
|
246
255
|
}
|
|
256
|
+
/**
|
|
257
|
+
* Remaps receiver method calls to their underlying contract calls.
|
|
258
|
+
* e.g., sol_address.balance() → __multicall3.getEthBalance(addr)
|
|
259
|
+
*/
|
|
260
|
+
resolveCall(contractName, methodName, args) {
|
|
261
|
+
if (contractName === "sol_address" && methodName === "balance") return {
|
|
262
|
+
contractName: "__multicall3",
|
|
263
|
+
methodName: "getEthBalance",
|
|
264
|
+
args
|
|
265
|
+
};
|
|
266
|
+
return {
|
|
267
|
+
contractName,
|
|
268
|
+
methodName,
|
|
269
|
+
args
|
|
270
|
+
};
|
|
271
|
+
}
|
|
247
272
|
findContract(name) {
|
|
248
273
|
return this.schema.contracts.find((c) => c.name === name);
|
|
249
274
|
}
|
|
@@ -79,6 +79,11 @@ declare class SELRuntime {
|
|
|
79
79
|
private planExecution;
|
|
80
80
|
private executeContractCalls;
|
|
81
81
|
private doEvaluate;
|
|
82
|
+
/**
|
|
83
|
+
* Remaps receiver method calls to their underlying contract calls.
|
|
84
|
+
* e.g., sol_address.balance() → __multicall3.getEthBalance(addr)
|
|
85
|
+
*/
|
|
86
|
+
private resolveCall;
|
|
82
87
|
private findContract;
|
|
83
88
|
}
|
|
84
89
|
//#endregion
|
|
@@ -79,6 +79,11 @@ declare class SELRuntime {
|
|
|
79
79
|
private planExecution;
|
|
80
80
|
private executeContractCalls;
|
|
81
81
|
private doEvaluate;
|
|
82
|
+
/**
|
|
83
|
+
* Remaps receiver method calls to their underlying contract calls.
|
|
84
|
+
* e.g., sol_address.balance() → __multicall3.getEthBalance(addr)
|
|
85
|
+
*/
|
|
86
|
+
private resolveCall;
|
|
82
87
|
private findContract;
|
|
83
88
|
}
|
|
84
89
|
//#endregion
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { getBuiltinContracts } from "./builtin-contracts.mjs";
|
|
2
|
+
import { MulticallBatchError, SELContractError, SELLintError, SELTypeError } from "../errors/errors.mjs";
|
|
3
|
+
import "../errors/index.mjs";
|
|
4
|
+
import { validateClient } from "./client.mjs";
|
|
1
5
|
import { normalizeContextForEvaluation } from "./context.mjs";
|
|
2
6
|
import { buildExecutionReplayCache } from "./replay-cache.mjs";
|
|
3
7
|
import { createLogger } from "../debug.mjs";
|
|
4
|
-
import { MulticallBatchError, SELContractError, SELLintError, SELTypeError } from "../errors/errors.mjs";
|
|
5
|
-
import "../errors/index.mjs";
|
|
6
8
|
import { CallCounter, buildContractInfoMap, executeContractCall, resolveExecutionBlockNumber } from "./contract-caller.mjs";
|
|
7
9
|
import { wrapError } from "./error-wrapper.mjs";
|
|
8
10
|
import { collectCalls } from "../analysis/call-collector.mjs";
|
|
@@ -68,17 +70,22 @@ var SELRuntime = class {
|
|
|
68
70
|
this.maxRounds = limits?.maxRounds ?? 10;
|
|
69
71
|
this.maxCalls = limits?.maxCalls ?? 100;
|
|
70
72
|
this.multicallOptions = config.multicall;
|
|
73
|
+
if (config.client) validateClient(config.client);
|
|
71
74
|
this.client = config.client;
|
|
72
|
-
this.schema =
|
|
75
|
+
this.schema = {
|
|
76
|
+
...config.schema,
|
|
77
|
+
contracts: [...config.schema.contracts, ...getBuiltinContracts(config.multicall)]
|
|
78
|
+
};
|
|
73
79
|
const handler = (contractName, methodName, args) => {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
const resolved = this.resolveCall(contractName, methodName, args);
|
|
81
|
+
const contract = this.findContract(resolved.contractName);
|
|
82
|
+
if (!contract) throw new SELContractError(`Unknown contract "${resolved.contractName}"`, { contractName: resolved.contractName });
|
|
83
|
+
const method = contract.methods.find((m) => m.name === resolved.methodName);
|
|
84
|
+
if (!method) throw new SELContractError(`Unknown method "${resolved.contractName}.${resolved.methodName}"`, {
|
|
85
|
+
contractName: resolved.contractName,
|
|
86
|
+
methodName: resolved.methodName
|
|
80
87
|
});
|
|
81
|
-
return executeContractCall(contract, method, args, {
|
|
88
|
+
return executeContractCall(contract, method, resolved.args, {
|
|
82
89
|
executionCache: this.currentCache,
|
|
83
90
|
client: this.currentClient ?? this.client,
|
|
84
91
|
codecRegistry: this.codecRegistry,
|
|
@@ -205,6 +212,7 @@ var SELRuntime = class {
|
|
|
205
212
|
async doEvaluate(expression, context, options) {
|
|
206
213
|
debug("evaluate: %s", expression);
|
|
207
214
|
const resolvedClient = options?.client ?? this.client;
|
|
215
|
+
if (resolvedClient && resolvedClient !== this.client) validateClient(resolvedClient);
|
|
208
216
|
try {
|
|
209
217
|
const { parseResult, collectedCalls, normalizedContext, executionVariables, typeCheckResult, diagnostics } = this.planExecution(expression, context ?? {});
|
|
210
218
|
let executionMeta;
|
|
@@ -236,12 +244,29 @@ var SELRuntime = class {
|
|
|
236
244
|
value,
|
|
237
245
|
meta: executionMeta
|
|
238
246
|
} : { value };
|
|
247
|
+
if (typeCheckResult.type) evalResult.type = typeCheckResult.type;
|
|
239
248
|
if (diagnostics.length > 0) evalResult.diagnostics = diagnostics;
|
|
240
249
|
return evalResult;
|
|
241
250
|
} catch (error) {
|
|
242
251
|
throw wrapError(error);
|
|
243
252
|
}
|
|
244
253
|
}
|
|
254
|
+
/**
|
|
255
|
+
* Remaps receiver method calls to their underlying contract calls.
|
|
256
|
+
* e.g., sol_address.balance() → __multicall3.getEthBalance(addr)
|
|
257
|
+
*/
|
|
258
|
+
resolveCall(contractName, methodName, args) {
|
|
259
|
+
if (contractName === "sol_address" && methodName === "balance") return {
|
|
260
|
+
contractName: "__multicall3",
|
|
261
|
+
methodName: "getEthBalance",
|
|
262
|
+
args
|
|
263
|
+
};
|
|
264
|
+
return {
|
|
265
|
+
contractName,
|
|
266
|
+
methodName,
|
|
267
|
+
args
|
|
268
|
+
};
|
|
269
|
+
}
|
|
245
270
|
findContract(name) {
|
|
246
271
|
return this.schema.contracts.find((c) => c.name === name);
|
|
247
272
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { SELClient } from "./client.cjs";
|
|
1
2
|
import { SELCheckerOptions } from "@seljs/checker";
|
|
2
3
|
import { SELSchema } from "@seljs/schema";
|
|
3
|
-
import { Address, PublicClient } from "viem";
|
|
4
4
|
|
|
5
5
|
//#region src/environment/types.d.ts
|
|
6
6
|
/**
|
|
@@ -13,7 +13,7 @@ interface MulticallOptions {
|
|
|
13
13
|
/** Maximum number of calls per multicall3 batch. Unbounded if omitted. */
|
|
14
14
|
batchSize?: number;
|
|
15
15
|
/** Custom multicall3 contract address. Defaults to the canonical deployment. */
|
|
16
|
-
address?:
|
|
16
|
+
address?: `0x${string}`;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Limits for contract call execution.
|
|
@@ -36,8 +36,8 @@ interface SELLimits {
|
|
|
36
36
|
interface SELRuntimeConfig extends SELCheckerOptions {
|
|
37
37
|
/** SEL schema describing contracts, variables, types, functions, and macros */
|
|
38
38
|
schema: SELSchema;
|
|
39
|
-
/**
|
|
40
|
-
client?:
|
|
39
|
+
/** Client for on-chain reads. Any viem PublicClient or SELClient-compatible object. */
|
|
40
|
+
client?: SELClient;
|
|
41
41
|
/** Multicall3 batching options for contract call execution */
|
|
42
42
|
multicall?: MulticallOptions;
|
|
43
43
|
/** Execution limits for contract call rounds and total calls */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { SELClient } from "./client.mjs";
|
|
1
2
|
import { SELCheckerOptions } from "@seljs/checker";
|
|
2
|
-
import { Address, PublicClient } from "viem";
|
|
3
3
|
import { SELSchema } from "@seljs/schema";
|
|
4
4
|
|
|
5
5
|
//#region src/environment/types.d.ts
|
|
@@ -13,7 +13,7 @@ interface MulticallOptions {
|
|
|
13
13
|
/** Maximum number of calls per multicall3 batch. Unbounded if omitted. */
|
|
14
14
|
batchSize?: number;
|
|
15
15
|
/** Custom multicall3 contract address. Defaults to the canonical deployment. */
|
|
16
|
-
address?:
|
|
16
|
+
address?: `0x${string}`;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Limits for contract call execution.
|
|
@@ -36,8 +36,8 @@ interface SELLimits {
|
|
|
36
36
|
interface SELRuntimeConfig extends SELCheckerOptions {
|
|
37
37
|
/** SEL schema describing contracts, variables, types, functions, and macros */
|
|
38
38
|
schema: SELSchema;
|
|
39
|
-
/**
|
|
40
|
-
client?:
|
|
39
|
+
/** Client for on-chain reads. Any viem PublicClient or SELClient-compatible object. */
|
|
40
|
+
client?: SELClient;
|
|
41
41
|
/** Multicall3 batching options for contract call execution */
|
|
42
42
|
multicall?: MulticallOptions;
|
|
43
43
|
/** Execution limits for contract call rounds and total calls */
|
package/dist/errors/errors.cjs
CHANGED
|
@@ -61,6 +61,12 @@ var MulticallBatchError = class extends _seljs_common.SELError {
|
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
63
|
/**
|
|
64
|
+
* Thrown when the provided client fails validation or is misconfigured.
|
|
65
|
+
*/
|
|
66
|
+
var SELClientError = class extends _seljs_common.SELError {
|
|
67
|
+
name = "SELClientError";
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
64
70
|
* Thrown when lint rules with error severity detect violations.
|
|
65
71
|
* Contains the diagnostics that caused the failure.
|
|
66
72
|
*/
|
|
@@ -76,6 +82,7 @@ var SELLintError = class extends _seljs_common.SELError {
|
|
|
76
82
|
exports.CircularDependencyError = CircularDependencyError;
|
|
77
83
|
exports.ExecutionLimitError = ExecutionLimitError;
|
|
78
84
|
exports.MulticallBatchError = MulticallBatchError;
|
|
85
|
+
exports.SELClientError = SELClientError;
|
|
79
86
|
exports.SELContractError = SELContractError;
|
|
80
87
|
exports.SELEvaluationError = SELEvaluationError;
|
|
81
88
|
exports.SELLintError = SELLintError;
|
package/dist/errors/errors.d.cts
CHANGED
|
@@ -61,6 +61,12 @@ declare class MulticallBatchError extends SELError {
|
|
|
61
61
|
methodName?: string;
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Thrown when the provided client fails validation or is misconfigured.
|
|
66
|
+
*/
|
|
67
|
+
declare class SELClientError extends SELError {
|
|
68
|
+
readonly name = "SELClientError";
|
|
69
|
+
}
|
|
64
70
|
/**
|
|
65
71
|
* Thrown when lint rules with error severity detect violations.
|
|
66
72
|
* Contains the diagnostics that caused the failure.
|
|
@@ -72,4 +78,4 @@ declare class SELLintError extends SELError {
|
|
|
72
78
|
});
|
|
73
79
|
}
|
|
74
80
|
//#endregion
|
|
75
|
-
export { CircularDependencyError, ExecutionLimitError, MulticallBatchError, SELContractError, SELError, SELEvaluationError, SELLintError, SELParseError, SELTypeError };
|
|
81
|
+
export { CircularDependencyError, ExecutionLimitError, MulticallBatchError, SELClientError, SELContractError, SELError, SELEvaluationError, SELLintError, SELParseError, SELTypeError };
|