@seljs/runtime 1.3.0-beta.3 → 1.3.0-beta.33
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/dependency-analyzer.cjs +3 -3
- package/dist/analysis/dependency-analyzer.mjs +4 -4
- package/dist/analysis/round-planner.cjs +3 -3
- package/dist/analysis/round-planner.mjs +4 -4
- package/dist/environment/client.d.cts +1 -1
- package/dist/environment/client.d.mts +1 -1
- package/dist/environment/contract-caller.cjs +1 -1
- package/dist/environment/contract-caller.mjs +2 -2
- package/dist/environment/environment.cjs +25 -15
- package/dist/environment/environment.d.cts +15 -4
- package/dist/environment/environment.d.mts +15 -4
- package/dist/environment/environment.mjs +26 -15
- package/dist/environment/error-wrapper.cjs +71 -13
- package/dist/environment/error-wrapper.mjs +71 -12
- package/dist/environment/types.d.cts +1 -1
- package/dist/environment/types.d.mts +1 -1
- package/dist/errors/errors.cjs +102 -33
- package/dist/errors/errors.d.cts +98 -31
- package/dist/errors/errors.d.mts +98 -31
- package/dist/errors/errors.mjs +96 -31
- package/dist/errors/index.d.mts +1 -1
- package/dist/execution/decode-revert.cjs +67 -0
- package/dist/execution/decode-revert.mjs +66 -0
- package/dist/execution/multicall-batcher.cjs +3 -3
- package/dist/execution/multicall-batcher.mjs +4 -4
- package/dist/execution/round-executor.cjs +18 -10
- package/dist/execution/round-executor.mjs +19 -11
- package/dist/execution/types.d.cts +37 -11
- package/dist/execution/types.d.mts +37 -11
- package/dist/index.cjs +11 -6
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +8 -7
package/dist/errors/errors.mjs
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import { SELError,
|
|
1
|
+
import { SELError as SELError$1, SELEvaluationError as SELEvaluationError$1, SELRuntimeError, SELStaticError } from "@seljs/common";
|
|
2
2
|
//#region src/errors/errors.ts
|
|
3
3
|
/**
|
|
4
|
-
* Thrown when
|
|
5
|
-
*
|
|
4
|
+
* Thrown when a contract-layer call fails after execution reached the
|
|
5
|
+
* chain (unknown method, ABI decode mismatch, etc.). Reverts are reported
|
|
6
|
+
* as {@link SELContractRevertError}, a subclass; batch-level Multicall3
|
|
7
|
+
* failures as {@link SELMulticallBatchError}.
|
|
6
8
|
*/
|
|
7
|
-
var
|
|
8
|
-
/**
|
|
9
|
-
* Thrown when contract validation or execution fails.
|
|
10
|
-
* Includes optional contract name and method name for context.
|
|
11
|
-
*/
|
|
12
|
-
var SELContractError = class extends SELError {
|
|
9
|
+
var SELContractError = class extends SELRuntimeError {
|
|
13
10
|
contractName;
|
|
14
11
|
methodName;
|
|
15
12
|
constructor(message, options) {
|
|
@@ -19,10 +16,93 @@ var SELContractError = class extends SELError {
|
|
|
19
16
|
}
|
|
20
17
|
};
|
|
21
18
|
/**
|
|
22
|
-
* Thrown when a
|
|
23
|
-
*
|
|
19
|
+
* Thrown when a contract call reverted. Carries the decoded revert
|
|
20
|
+
* reason, raw revert data, and — when the selector matched a custom
|
|
21
|
+
* error in the contract's ABI — the decoded custom-error name and args.
|
|
22
|
+
*/
|
|
23
|
+
var SELContractRevertError = class extends SELContractError {
|
|
24
|
+
revertReason;
|
|
25
|
+
revertData;
|
|
26
|
+
decodedError;
|
|
27
|
+
constructor(message, options) {
|
|
28
|
+
super(message, {
|
|
29
|
+
cause: options?.cause,
|
|
30
|
+
contractName: options?.contractName,
|
|
31
|
+
methodName: options?.methodName
|
|
32
|
+
});
|
|
33
|
+
this.revertReason = options?.revertReason;
|
|
34
|
+
this.revertData = options?.revertData;
|
|
35
|
+
this.decodedError = options?.decodedError;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Thrown when a Multicall3 batch fails at the batch level — the aggregate
|
|
40
|
+
* call itself reverted, or individual calls could not be encoded/decoded.
|
|
41
|
+
* Individual sub-call reverts surface as {@link SELContractRevertError},
|
|
42
|
+
* not as this class.
|
|
43
|
+
*/
|
|
44
|
+
var SELMulticallBatchError = class extends SELContractError {
|
|
45
|
+
failedCallIndex;
|
|
46
|
+
constructor(message, options) {
|
|
47
|
+
super(message, {
|
|
48
|
+
cause: options?.cause,
|
|
49
|
+
contractName: options?.contractName,
|
|
50
|
+
methodName: options?.methodName
|
|
51
|
+
});
|
|
52
|
+
this.failedCallIndex = options?.failedCallIndex;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Base for failures from the JSON-RPC transport or node — the call never
|
|
57
|
+
* reached the contract. Transport errors (HTTP, WebSocket, timeout) use
|
|
58
|
+
* {@link SELProviderTransportError}; node-reported JSON-RPC errors use
|
|
59
|
+
* {@link SELProviderRpcError}. Catch the base to retry safely against an
|
|
60
|
+
* alternate RPC.
|
|
61
|
+
*/
|
|
62
|
+
var SELProviderError = class extends SELRuntimeError {};
|
|
63
|
+
/**
|
|
64
|
+
* Thrown when the transport layer (HTTP, WebSocket) or a timeout
|
|
65
|
+
* prevented the request from reaching the node.
|
|
66
|
+
*/
|
|
67
|
+
var SELProviderTransportError = class extends SELProviderError {
|
|
68
|
+
httpStatus;
|
|
69
|
+
url;
|
|
70
|
+
body;
|
|
71
|
+
constructor(message, options) {
|
|
72
|
+
super(message, { cause: options?.cause });
|
|
73
|
+
this.httpStatus = options?.httpStatus;
|
|
74
|
+
this.url = options?.url;
|
|
75
|
+
this.body = options?.body;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Thrown when the node returned a JSON-RPC error response (rate limit,
|
|
80
|
+
* invalid params, unsupported method, user rejection, etc.).
|
|
24
81
|
*/
|
|
25
|
-
var
|
|
82
|
+
var SELProviderRpcError = class extends SELProviderError {
|
|
83
|
+
rpcCode;
|
|
84
|
+
rpcData;
|
|
85
|
+
method;
|
|
86
|
+
constructor(message, options) {
|
|
87
|
+
super(message, { cause: options?.cause });
|
|
88
|
+
this.rpcCode = options?.rpcCode;
|
|
89
|
+
this.rpcData = options?.rpcData;
|
|
90
|
+
this.method = options?.method;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Base for failures from the execution-framework layer that sits between
|
|
95
|
+
* parsed expressions and contract calls (dependency analysis, round
|
|
96
|
+
* planning). Concrete subclasses: {@link SELExecutionLimitError},
|
|
97
|
+
* {@link SELCircularDependencyError}.
|
|
98
|
+
*/
|
|
99
|
+
var SELExecutionError = class extends SELRuntimeError {};
|
|
100
|
+
/**
|
|
101
|
+
* Thrown when a circular dependency is detected in the call dependency
|
|
102
|
+
* graph. Indicates that call A depends on call B which depends on call A
|
|
103
|
+
* (directly or transitively).
|
|
104
|
+
*/
|
|
105
|
+
var SELCircularDependencyError = class extends SELExecutionError {
|
|
26
106
|
callIds;
|
|
27
107
|
constructor(message, options) {
|
|
28
108
|
super(message, { cause: options?.cause });
|
|
@@ -33,7 +113,7 @@ var CircularDependencyError = class extends SELError {
|
|
|
33
113
|
* Thrown when execution limits are exceeded (maxRounds or maxCalls).
|
|
34
114
|
* Prevents infinite loops and runaway execution.
|
|
35
115
|
*/
|
|
36
|
-
var
|
|
116
|
+
var SELExecutionLimitError = class extends SELExecutionError {
|
|
37
117
|
limitType;
|
|
38
118
|
limit;
|
|
39
119
|
actual;
|
|
@@ -45,31 +125,16 @@ var ExecutionLimitError = class extends SELError {
|
|
|
45
125
|
}
|
|
46
126
|
};
|
|
47
127
|
/**
|
|
48
|
-
* Thrown when a Multicall3 batch execution fails.
|
|
49
|
-
* Includes the failed call index and optional contract name/method name for context.
|
|
50
|
-
*/
|
|
51
|
-
var MulticallBatchError = class extends SELError {
|
|
52
|
-
failedCallIndex;
|
|
53
|
-
contractName;
|
|
54
|
-
methodName;
|
|
55
|
-
constructor(message, options) {
|
|
56
|
-
super(message, { cause: options?.cause });
|
|
57
|
-
this.failedCallIndex = options?.failedCallIndex;
|
|
58
|
-
this.contractName = options?.contractName;
|
|
59
|
-
this.methodName = options?.methodName;
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
/**
|
|
63
128
|
* Thrown when the provided client fails validation or is misconfigured.
|
|
64
129
|
*/
|
|
65
|
-
var SELClientError = class extends
|
|
130
|
+
var SELClientError = class extends SELStaticError {
|
|
66
131
|
name = "SELClientError";
|
|
67
132
|
};
|
|
68
133
|
/**
|
|
69
134
|
* Thrown when lint rules with error severity detect violations.
|
|
70
135
|
* Contains the diagnostics that caused the failure.
|
|
71
136
|
*/
|
|
72
|
-
var SELLintError = class extends
|
|
137
|
+
var SELLintError = class extends SELStaticError {
|
|
73
138
|
diagnostics;
|
|
74
139
|
constructor(diagnostics, options) {
|
|
75
140
|
const messages = diagnostics.map((d) => d.message).join("; ");
|
|
@@ -78,4 +143,4 @@ var SELLintError = class extends SELError {
|
|
|
78
143
|
}
|
|
79
144
|
};
|
|
80
145
|
//#endregion
|
|
81
|
-
export {
|
|
146
|
+
export { SELCircularDependencyError, SELClientError, SELContractError, SELContractRevertError, SELError$1 as SELError, SELEvaluationError$1 as SELEvaluationError, SELExecutionError, SELExecutionLimitError, SELLintError, SELMulticallBatchError, SELProviderError, SELProviderRpcError, SELProviderTransportError, SELRuntimeError, SELStaticError };
|
package/dist/errors/index.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SELCircularDependencyError, SELClientError, SELContractError, SELContractRevertError, SELError, SELEvaluationError, SELExecutionError, SELExecutionLimitError, SELLintError, SELMulticallBatchError, SELProviderError, SELProviderRpcError, SELProviderTransportError, SELRuntimeError, SELStaticError } from "./errors.mjs";
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
let ox = require("ox");
|
|
3
|
+
//#region src/execution/decode-revert.ts
|
|
4
|
+
const ERROR_STRING_SELECTOR = "0x08c379a0";
|
|
5
|
+
const PANIC_SELECTOR = "0x4e487b71";
|
|
6
|
+
const PANIC_CODES = {
|
|
7
|
+
0: "generic panic",
|
|
8
|
+
1: "assertion failed",
|
|
9
|
+
17: "arithmetic overflow or underflow",
|
|
10
|
+
18: "division or modulo by zero",
|
|
11
|
+
33: "enum conversion out of bounds",
|
|
12
|
+
34: "incorrectly encoded storage byte array",
|
|
13
|
+
49: "pop on empty array",
|
|
14
|
+
50: "array index out of bounds",
|
|
15
|
+
65: "excessive memory allocation",
|
|
16
|
+
81: "zero-initialized internal function type"
|
|
17
|
+
};
|
|
18
|
+
const errorStringAbi = ox.AbiError.from("error Error(string reason)");
|
|
19
|
+
const panicAbi = ox.AbiError.from("error Panic(uint256 code)");
|
|
20
|
+
function decodeRevertData(data, abi) {
|
|
21
|
+
if (data === "0x" || data.length < 10) return { data };
|
|
22
|
+
const selector = data.slice(0, 10).toLowerCase();
|
|
23
|
+
if (selector === ERROR_STRING_SELECTOR) try {
|
|
24
|
+
return {
|
|
25
|
+
data,
|
|
26
|
+
reason: ox.AbiError.decode(errorStringAbi, data)
|
|
27
|
+
};
|
|
28
|
+
} catch {
|
|
29
|
+
return { data };
|
|
30
|
+
}
|
|
31
|
+
if (selector === PANIC_SELECTOR) try {
|
|
32
|
+
const code = ox.AbiError.decode(panicAbi, data);
|
|
33
|
+
const numeric = Number(code);
|
|
34
|
+
return {
|
|
35
|
+
data,
|
|
36
|
+
reason: `Panic: ${PANIC_CODES[numeric] ?? `panic code 0x${numeric.toString(16)}`}`
|
|
37
|
+
};
|
|
38
|
+
} catch {
|
|
39
|
+
return { data };
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const error = ox.AbiError.fromAbi(abi, data);
|
|
43
|
+
const decoded = ox.AbiError.decode(error, data);
|
|
44
|
+
const args = decoded === void 0 ? [] : Array.isArray(decoded) ? decoded : [decoded];
|
|
45
|
+
const formattedArgs = args.map(formatArg).join(", ");
|
|
46
|
+
return {
|
|
47
|
+
data,
|
|
48
|
+
reason: `${error.name}(${formattedArgs})`,
|
|
49
|
+
decodedError: {
|
|
50
|
+
name: error.name,
|
|
51
|
+
args
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
} catch {
|
|
55
|
+
return { data };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function formatArg(arg) {
|
|
59
|
+
if (typeof arg === "bigint") return arg.toString();
|
|
60
|
+
if (typeof arg === "string") return arg;
|
|
61
|
+
if (typeof arg === "number" || typeof arg === "boolean" || arg === null || arg === void 0) return String(arg);
|
|
62
|
+
if (Array.isArray(arg)) return `[${arg.map(formatArg).join(", ")}]`;
|
|
63
|
+
if (typeof arg === "object") return `{${Object.entries(arg).map(([k, v]) => `${k}: ${formatArg(v)}`).join(", ")}}`;
|
|
64
|
+
return "";
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
exports.decodeRevertData = decodeRevertData;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { AbiError } from "ox";
|
|
2
|
+
//#region src/execution/decode-revert.ts
|
|
3
|
+
const ERROR_STRING_SELECTOR = "0x08c379a0";
|
|
4
|
+
const PANIC_SELECTOR = "0x4e487b71";
|
|
5
|
+
const PANIC_CODES = {
|
|
6
|
+
0: "generic panic",
|
|
7
|
+
1: "assertion failed",
|
|
8
|
+
17: "arithmetic overflow or underflow",
|
|
9
|
+
18: "division or modulo by zero",
|
|
10
|
+
33: "enum conversion out of bounds",
|
|
11
|
+
34: "incorrectly encoded storage byte array",
|
|
12
|
+
49: "pop on empty array",
|
|
13
|
+
50: "array index out of bounds",
|
|
14
|
+
65: "excessive memory allocation",
|
|
15
|
+
81: "zero-initialized internal function type"
|
|
16
|
+
};
|
|
17
|
+
const errorStringAbi = AbiError.from("error Error(string reason)");
|
|
18
|
+
const panicAbi = AbiError.from("error Panic(uint256 code)");
|
|
19
|
+
function decodeRevertData(data, abi) {
|
|
20
|
+
if (data === "0x" || data.length < 10) return { data };
|
|
21
|
+
const selector = data.slice(0, 10).toLowerCase();
|
|
22
|
+
if (selector === ERROR_STRING_SELECTOR) try {
|
|
23
|
+
return {
|
|
24
|
+
data,
|
|
25
|
+
reason: AbiError.decode(errorStringAbi, data)
|
|
26
|
+
};
|
|
27
|
+
} catch {
|
|
28
|
+
return { data };
|
|
29
|
+
}
|
|
30
|
+
if (selector === PANIC_SELECTOR) try {
|
|
31
|
+
const code = AbiError.decode(panicAbi, data);
|
|
32
|
+
const numeric = Number(code);
|
|
33
|
+
return {
|
|
34
|
+
data,
|
|
35
|
+
reason: `Panic: ${PANIC_CODES[numeric] ?? `panic code 0x${numeric.toString(16)}`}`
|
|
36
|
+
};
|
|
37
|
+
} catch {
|
|
38
|
+
return { data };
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const error = AbiError.fromAbi(abi, data);
|
|
42
|
+
const decoded = AbiError.decode(error, data);
|
|
43
|
+
const args = decoded === void 0 ? [] : Array.isArray(decoded) ? decoded : [decoded];
|
|
44
|
+
const formattedArgs = args.map(formatArg).join(", ");
|
|
45
|
+
return {
|
|
46
|
+
data,
|
|
47
|
+
reason: `${error.name}(${formattedArgs})`,
|
|
48
|
+
decodedError: {
|
|
49
|
+
name: error.name,
|
|
50
|
+
args
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
} catch {
|
|
54
|
+
return { data };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function formatArg(arg) {
|
|
58
|
+
if (typeof arg === "bigint") return arg.toString();
|
|
59
|
+
if (typeof arg === "string") return arg;
|
|
60
|
+
if (typeof arg === "number" || typeof arg === "boolean" || arg === null || arg === void 0) return String(arg);
|
|
61
|
+
if (Array.isArray(arg)) return `[${arg.map(formatArg).join(", ")}]`;
|
|
62
|
+
if (typeof arg === "object") return `{${Object.entries(arg).map(([k, v]) => `${k}: ${formatArg(v)}`).join(", ")}}`;
|
|
63
|
+
return "";
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
export { decodeRevertData };
|
|
@@ -38,14 +38,14 @@ var MulticallBatcher = class {
|
|
|
38
38
|
data,
|
|
39
39
|
blockNumber
|
|
40
40
|
});
|
|
41
|
-
if (!response.data) throw new require_errors.
|
|
41
|
+
if (!response.data) throw new require_errors.SELMulticallBatchError("Multicall3 aggregate3 returned no data");
|
|
42
42
|
return ox.AbiFunction.decodeResult(require_multicall.multicall3Function, response.data).map((r) => ({
|
|
43
43
|
success: r.success,
|
|
44
44
|
returnData: r.returnData
|
|
45
45
|
}));
|
|
46
46
|
} catch (error) {
|
|
47
|
-
if (error instanceof require_errors.
|
|
48
|
-
throw new require_errors.
|
|
47
|
+
if (error instanceof require_errors.SELMulticallBatchError) throw error;
|
|
48
|
+
throw new require_errors.SELMulticallBatchError("Multicall3 aggregate3 call failed", { cause: error });
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { multicall3Function } from "./multicall.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { SELMulticallBatchError } from "../errors/errors.mjs";
|
|
3
3
|
import "../errors/index.mjs";
|
|
4
4
|
import { createLogger } from "../debug.mjs";
|
|
5
5
|
import { AbiFunction } from "ox";
|
|
@@ -37,14 +37,14 @@ var MulticallBatcher = class {
|
|
|
37
37
|
data,
|
|
38
38
|
blockNumber
|
|
39
39
|
});
|
|
40
|
-
if (!response.data) throw new
|
|
40
|
+
if (!response.data) throw new SELMulticallBatchError("Multicall3 aggregate3 returned no data");
|
|
41
41
|
return AbiFunction.decodeResult(multicall3Function, response.data).map((r) => ({
|
|
42
42
|
success: r.success,
|
|
43
43
|
returnData: r.returnData
|
|
44
44
|
}));
|
|
45
45
|
} catch (error) {
|
|
46
|
-
if (error instanceof
|
|
47
|
-
throw new
|
|
46
|
+
if (error instanceof SELMulticallBatchError) throw error;
|
|
47
|
+
throw new SELMulticallBatchError("Multicall3 aggregate3 call failed", { cause: error });
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
};
|
|
@@ -2,7 +2,9 @@ require("../_virtual/_rolldown/runtime.cjs");
|
|
|
2
2
|
const require_errors = require("../errors/errors.cjs");
|
|
3
3
|
require("../errors/index.cjs");
|
|
4
4
|
const require_debug = require("../debug.cjs");
|
|
5
|
+
const require_decode_revert = require("./decode-revert.cjs");
|
|
5
6
|
let ox = require("ox");
|
|
7
|
+
let _seljs_common = require("@seljs/common");
|
|
6
8
|
//#region src/execution/round-executor.ts
|
|
7
9
|
const debug = require_debug.createLogger("execute:round");
|
|
8
10
|
var RoundExecutor = class {
|
|
@@ -22,17 +24,17 @@ var RoundExecutor = class {
|
|
|
22
24
|
failedCallContract = call.contract;
|
|
23
25
|
failedCallMethod = call.method;
|
|
24
26
|
const contract = this.contracts.get(call.contract);
|
|
25
|
-
if (!contract) throw new
|
|
27
|
+
if (!contract) throw new _seljs_common.SELConfigError(`No ABI registered for contract "${call.contract}"`, { setting: "abi" });
|
|
26
28
|
const resolvedArgs = this.resolveArgs(call.args, context);
|
|
27
29
|
encodedCalls.push({
|
|
28
30
|
target: contract.address,
|
|
29
|
-
allowFailure:
|
|
31
|
+
allowFailure: true,
|
|
30
32
|
callData: ox.AbiFunction.encodeData(contract.abi, call.method, resolvedArgs)
|
|
31
33
|
});
|
|
32
34
|
}
|
|
33
35
|
} catch (error) {
|
|
34
|
-
if (error instanceof require_errors.
|
|
35
|
-
throw new require_errors.
|
|
36
|
+
if (error instanceof require_errors.SELMulticallBatchError || error instanceof _seljs_common.SELConfigError) throw error;
|
|
37
|
+
throw new require_errors.SELMulticallBatchError("Failed to encode call", {
|
|
36
38
|
cause: error,
|
|
37
39
|
failedCallIndex,
|
|
38
40
|
contractName: failedCallContract,
|
|
@@ -43,13 +45,19 @@ var RoundExecutor = class {
|
|
|
43
45
|
const results = await this.batcher.executeBatch(encodedCalls, context.blockNumber);
|
|
44
46
|
for (const [i, call] of round.calls.entries()) {
|
|
45
47
|
const contract = this.contracts.get(call.contract);
|
|
46
|
-
if (!contract) throw new
|
|
48
|
+
if (!contract) throw new _seljs_common.SELConfigError(`No ABI registered for contract "${call.contract}"`, { setting: "abi" });
|
|
47
49
|
const result = results[i];
|
|
48
|
-
if (!result?.success)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
if (!result?.success) {
|
|
51
|
+
const decoded = require_decode_revert.decodeRevertData(result?.returnData ?? "0x", contract.abi);
|
|
52
|
+
const suffix = decoded.reason ? ` — ${decoded.reason}` : "";
|
|
53
|
+
throw new require_errors.SELContractRevertError(`Call reverted: ${call.contract}.${call.method}${suffix}`, {
|
|
54
|
+
contractName: call.contract,
|
|
55
|
+
methodName: call.method,
|
|
56
|
+
revertReason: decoded.reason,
|
|
57
|
+
revertData: decoded.data,
|
|
58
|
+
decodedError: decoded.decodedError
|
|
59
|
+
});
|
|
60
|
+
}
|
|
53
61
|
const decoded = ox.AbiFunction.decodeResult(contract.abi, call.method, result.returnData);
|
|
54
62
|
debug("decoded %s.%s -> %o", call.contract, call.method, decoded);
|
|
55
63
|
this.cache.set(call.id, decoded);
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SELContractRevertError, SELMulticallBatchError } from "../errors/errors.mjs";
|
|
2
2
|
import "../errors/index.mjs";
|
|
3
3
|
import { createLogger } from "../debug.mjs";
|
|
4
|
+
import { decodeRevertData } from "./decode-revert.mjs";
|
|
4
5
|
import { AbiFunction } from "ox";
|
|
6
|
+
import { SELConfigError } from "@seljs/common";
|
|
5
7
|
//#region src/execution/round-executor.ts
|
|
6
8
|
const debug = createLogger("execute:round");
|
|
7
9
|
var RoundExecutor = class {
|
|
@@ -21,17 +23,17 @@ var RoundExecutor = class {
|
|
|
21
23
|
failedCallContract = call.contract;
|
|
22
24
|
failedCallMethod = call.method;
|
|
23
25
|
const contract = this.contracts.get(call.contract);
|
|
24
|
-
if (!contract) throw new
|
|
26
|
+
if (!contract) throw new SELConfigError(`No ABI registered for contract "${call.contract}"`, { setting: "abi" });
|
|
25
27
|
const resolvedArgs = this.resolveArgs(call.args, context);
|
|
26
28
|
encodedCalls.push({
|
|
27
29
|
target: contract.address,
|
|
28
|
-
allowFailure:
|
|
30
|
+
allowFailure: true,
|
|
29
31
|
callData: AbiFunction.encodeData(contract.abi, call.method, resolvedArgs)
|
|
30
32
|
});
|
|
31
33
|
}
|
|
32
34
|
} catch (error) {
|
|
33
|
-
if (error instanceof
|
|
34
|
-
throw new
|
|
35
|
+
if (error instanceof SELMulticallBatchError || error instanceof SELConfigError) throw error;
|
|
36
|
+
throw new SELMulticallBatchError("Failed to encode call", {
|
|
35
37
|
cause: error,
|
|
36
38
|
failedCallIndex,
|
|
37
39
|
contractName: failedCallContract,
|
|
@@ -42,13 +44,19 @@ var RoundExecutor = class {
|
|
|
42
44
|
const results = await this.batcher.executeBatch(encodedCalls, context.blockNumber);
|
|
43
45
|
for (const [i, call] of round.calls.entries()) {
|
|
44
46
|
const contract = this.contracts.get(call.contract);
|
|
45
|
-
if (!contract) throw new
|
|
47
|
+
if (!contract) throw new SELConfigError(`No ABI registered for contract "${call.contract}"`, { setting: "abi" });
|
|
46
48
|
const result = results[i];
|
|
47
|
-
if (!result?.success)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
if (!result?.success) {
|
|
50
|
+
const decoded = decodeRevertData(result?.returnData ?? "0x", contract.abi);
|
|
51
|
+
const suffix = decoded.reason ? ` — ${decoded.reason}` : "";
|
|
52
|
+
throw new SELContractRevertError(`Call reverted: ${call.contract}.${call.method}${suffix}`, {
|
|
53
|
+
contractName: call.contract,
|
|
54
|
+
methodName: call.method,
|
|
55
|
+
revertReason: decoded.reason,
|
|
56
|
+
revertData: decoded.data,
|
|
57
|
+
decodedError: decoded.decodedError
|
|
58
|
+
});
|
|
59
|
+
}
|
|
52
60
|
const decoded = AbiFunction.decodeResult(contract.abi, call.method, result.returnData);
|
|
53
61
|
debug("decoded %s.%s -> %o", call.contract, call.method, decoded);
|
|
54
62
|
this.cache.set(call.id, decoded);
|
|
@@ -7,11 +7,17 @@ import { SELDiagnostic } from "@seljs/checker";
|
|
|
7
7
|
* Contains statistics and block information from the execution run.
|
|
8
8
|
*/
|
|
9
9
|
interface ExecutionMeta {
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Number of rounds executed (topological depth)
|
|
12
|
+
*/
|
|
11
13
|
roundsExecuted: number;
|
|
12
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Total number of contract calls executed
|
|
16
|
+
*/
|
|
13
17
|
totalCalls: number;
|
|
14
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Block number at which calls were executed
|
|
20
|
+
*/
|
|
15
21
|
blockNumber: bigint;
|
|
16
22
|
}
|
|
17
23
|
/**
|
|
@@ -19,9 +25,13 @@ interface ExecutionMeta {
|
|
|
19
25
|
* Maps call IDs to their decoded results.
|
|
20
26
|
*/
|
|
21
27
|
interface ExecutionResult {
|
|
22
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Map of callId to decoded result value
|
|
30
|
+
*/
|
|
23
31
|
results: Map<string, unknown>;
|
|
24
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Execution metadata
|
|
34
|
+
*/
|
|
25
35
|
meta: ExecutionMeta;
|
|
26
36
|
}
|
|
27
37
|
/**
|
|
@@ -29,16 +39,22 @@ interface ExecutionResult {
|
|
|
29
39
|
* Contains the block number and variable bindings.
|
|
30
40
|
*/
|
|
31
41
|
interface ExecutionContext {
|
|
32
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* Block number for consistent reads across all calls
|
|
44
|
+
*/
|
|
33
45
|
blockNumber: bigint;
|
|
34
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Variable name to value mapping from evaluate() context
|
|
48
|
+
*/
|
|
35
49
|
variables: Record<string, unknown>;
|
|
36
50
|
}
|
|
37
51
|
/**
|
|
38
52
|
* Options for the evaluate() call.
|
|
39
53
|
*/
|
|
40
54
|
interface EvaluateOptions {
|
|
41
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* Override client for this evaluation
|
|
57
|
+
*/
|
|
42
58
|
client?: SELClient;
|
|
43
59
|
}
|
|
44
60
|
/**
|
|
@@ -48,11 +64,21 @@ interface EvaluateOptions {
|
|
|
48
64
|
* contract calls were executed, absent for pure CEL expressions.
|
|
49
65
|
*/
|
|
50
66
|
interface EvaluateResult<T = unknown> {
|
|
51
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* The evaluated result value
|
|
69
|
+
*/
|
|
52
70
|
value: T;
|
|
53
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* The inferred type of the expression, when available
|
|
73
|
+
*/
|
|
74
|
+
type?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Execution metadata, present when contract calls were executed
|
|
77
|
+
*/
|
|
54
78
|
meta?: ExecutionMeta;
|
|
55
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* Advisory diagnostics (warnings/info) from lint rules, when non-empty
|
|
81
|
+
*/
|
|
56
82
|
diagnostics?: SELDiagnostic[];
|
|
57
83
|
}
|
|
58
84
|
//#endregion
|
|
@@ -7,11 +7,17 @@ import { SELDiagnostic } from "@seljs/checker";
|
|
|
7
7
|
* Contains statistics and block information from the execution run.
|
|
8
8
|
*/
|
|
9
9
|
interface ExecutionMeta {
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Number of rounds executed (topological depth)
|
|
12
|
+
*/
|
|
11
13
|
roundsExecuted: number;
|
|
12
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Total number of contract calls executed
|
|
16
|
+
*/
|
|
13
17
|
totalCalls: number;
|
|
14
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Block number at which calls were executed
|
|
20
|
+
*/
|
|
15
21
|
blockNumber: bigint;
|
|
16
22
|
}
|
|
17
23
|
/**
|
|
@@ -19,9 +25,13 @@ interface ExecutionMeta {
|
|
|
19
25
|
* Maps call IDs to their decoded results.
|
|
20
26
|
*/
|
|
21
27
|
interface ExecutionResult {
|
|
22
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Map of callId to decoded result value
|
|
30
|
+
*/
|
|
23
31
|
results: Map<string, unknown>;
|
|
24
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Execution metadata
|
|
34
|
+
*/
|
|
25
35
|
meta: ExecutionMeta;
|
|
26
36
|
}
|
|
27
37
|
/**
|
|
@@ -29,16 +39,22 @@ interface ExecutionResult {
|
|
|
29
39
|
* Contains the block number and variable bindings.
|
|
30
40
|
*/
|
|
31
41
|
interface ExecutionContext {
|
|
32
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* Block number for consistent reads across all calls
|
|
44
|
+
*/
|
|
33
45
|
blockNumber: bigint;
|
|
34
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Variable name to value mapping from evaluate() context
|
|
48
|
+
*/
|
|
35
49
|
variables: Record<string, unknown>;
|
|
36
50
|
}
|
|
37
51
|
/**
|
|
38
52
|
* Options for the evaluate() call.
|
|
39
53
|
*/
|
|
40
54
|
interface EvaluateOptions {
|
|
41
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* Override client for this evaluation
|
|
57
|
+
*/
|
|
42
58
|
client?: SELClient;
|
|
43
59
|
}
|
|
44
60
|
/**
|
|
@@ -48,11 +64,21 @@ interface EvaluateOptions {
|
|
|
48
64
|
* contract calls were executed, absent for pure CEL expressions.
|
|
49
65
|
*/
|
|
50
66
|
interface EvaluateResult<T = unknown> {
|
|
51
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* The evaluated result value
|
|
69
|
+
*/
|
|
52
70
|
value: T;
|
|
53
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* The inferred type of the expression, when available
|
|
73
|
+
*/
|
|
74
|
+
type?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Execution metadata, present when contract calls were executed
|
|
77
|
+
*/
|
|
54
78
|
meta?: ExecutionMeta;
|
|
55
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* Advisory diagnostics (warnings/info) from lint rules, when non-empty
|
|
81
|
+
*/
|
|
56
82
|
diagnostics?: SELDiagnostic[];
|
|
57
83
|
}
|
|
58
84
|
//#endregion
|
package/dist/index.cjs
CHANGED
|
@@ -7,16 +7,21 @@ const require_environment = require("./environment/environment.cjs");
|
|
|
7
7
|
require("./environment/index.cjs");
|
|
8
8
|
const require_factory = require("./factory.cjs");
|
|
9
9
|
let _seljs_common = require("@seljs/common");
|
|
10
|
-
exports.
|
|
11
|
-
exports.ExecutionLimitError = require_errors.ExecutionLimitError;
|
|
12
|
-
exports.MulticallBatchError = require_errors.MulticallBatchError;
|
|
10
|
+
exports.SELCircularDependencyError = require_errors.SELCircularDependencyError;
|
|
13
11
|
exports.SELClientError = require_errors.SELClientError;
|
|
14
12
|
exports.SELContractError = require_errors.SELContractError;
|
|
13
|
+
exports.SELContractRevertError = require_errors.SELContractRevertError;
|
|
15
14
|
exports.SELError = _seljs_common.SELError;
|
|
16
|
-
exports.SELEvaluationError =
|
|
15
|
+
exports.SELEvaluationError = _seljs_common.SELEvaluationError;
|
|
16
|
+
exports.SELExecutionError = require_errors.SELExecutionError;
|
|
17
|
+
exports.SELExecutionLimitError = require_errors.SELExecutionLimitError;
|
|
17
18
|
exports.SELLintError = require_errors.SELLintError;
|
|
18
|
-
exports.
|
|
19
|
+
exports.SELMulticallBatchError = require_errors.SELMulticallBatchError;
|
|
20
|
+
exports.SELProviderError = require_errors.SELProviderError;
|
|
21
|
+
exports.SELProviderRpcError = require_errors.SELProviderRpcError;
|
|
22
|
+
exports.SELProviderTransportError = require_errors.SELProviderTransportError;
|
|
19
23
|
exports.SELRuntime = require_environment.SELRuntime;
|
|
20
|
-
exports.
|
|
24
|
+
exports.SELRuntimeError = _seljs_common.SELRuntimeError;
|
|
25
|
+
exports.SELStaticError = _seljs_common.SELStaticError;
|
|
21
26
|
exports.createSEL = require_factory.createSEL;
|
|
22
27
|
exports.validateClient = require_client.validateClient;
|