@morpho-org/evm-simulation 4.0.0 → 4.0.1
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/lib/cjs/simulate/pipeline/bundler-retention.d.ts +5 -5
- package/lib/cjs/simulate/pipeline/bundler-retention.js +19 -11
- package/lib/cjs/simulate/simulate.d.ts +2 -2
- package/lib/cjs/simulate/simulate.js +2 -2
- package/lib/esm/simulate/pipeline/bundler-retention.d.ts +5 -5
- package/lib/esm/simulate/pipeline/bundler-retention.js +19 -11
- package/lib/esm/simulate/simulate.d.ts +2 -2
- package/lib/esm/simulate/simulate.js +2 -2
- package/package.json +5 -5
|
@@ -9,11 +9,11 @@ interface AssertNoBundlerRetentionParams {
|
|
|
9
9
|
*
|
|
10
10
|
* Uses net flow (inbound minus outbound) per (bundler address, token) pair.
|
|
11
11
|
* Bundler3 legitimately receives tokens as an intermediary (user → bundler3 →
|
|
12
|
-
* vault), so gross inbound would fire false positives. We only
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
12
|
+
* vault), so gross inbound would fire false positives. We only block positive
|
|
13
|
+
* net flow above `DUST_THRESHOLD` — tokens stuck in a bundler address. Negative
|
|
14
|
+
* net flow means the simulated bundle sweeps a pre-existing or state-overridden
|
|
15
|
+
* bundler balance. That is useful telemetry, but not current-bundle retention,
|
|
16
|
+
* so it is warned instead of raising a blacklist violation.
|
|
17
17
|
*/
|
|
18
18
|
export declare function assertNoBundlerRetention(params: AssertNoBundlerRetentionParams): void;
|
|
19
19
|
export {};
|
|
@@ -47,11 +47,11 @@ function getBundlerAddresses(chainId, logger) {
|
|
|
47
47
|
*
|
|
48
48
|
* Uses net flow (inbound minus outbound) per (bundler address, token) pair.
|
|
49
49
|
* Bundler3 legitimately receives tokens as an intermediary (user → bundler3 →
|
|
50
|
-
* vault), so gross inbound would fire false positives. We only
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
50
|
+
* vault), so gross inbound would fire false positives. We only block positive
|
|
51
|
+
* net flow above `DUST_THRESHOLD` — tokens stuck in a bundler address. Negative
|
|
52
|
+
* net flow means the simulated bundle sweeps a pre-existing or state-overridden
|
|
53
|
+
* bundler balance. That is useful telemetry, but not current-bundle retention,
|
|
54
|
+
* so it is warned instead of raising a blacklist violation.
|
|
55
55
|
*/
|
|
56
56
|
function assertNoBundlerRetention(params) {
|
|
57
57
|
const { chainId, transfers, logger } = params;
|
|
@@ -77,15 +77,23 @@ function assertNoBundlerRetention(params) {
|
|
|
77
77
|
if (bundlerAddresses.has(t.from))
|
|
78
78
|
recordFlow(t.from, t.token, -t.amount);
|
|
79
79
|
}
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
const entries = [...flow.values()];
|
|
81
|
+
const drained = entries.filter((e) => e.netChange < -DUST_THRESHOLD);
|
|
82
|
+
if (drained.length > 0) {
|
|
83
|
+
logger?.warn("Simulation detected pre-existing bundler balance being swept", {
|
|
84
|
+
changes: drained.map((e) => ({
|
|
85
|
+
address: e.address,
|
|
86
|
+
token: e.token,
|
|
87
|
+
netSwept: (-e.netChange).toString(),
|
|
88
|
+
})),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const retained = entries.filter((e) => e.netChange > DUST_THRESHOLD);
|
|
92
|
+
if (retained.length > 0) {
|
|
93
|
+
throw new errors_js_1.BlacklistViolationError("Simulation detected asset transfers retained by restricted bundler contracts", retained.map((e) => ({
|
|
83
94
|
address: e.address,
|
|
84
95
|
token: e.token,
|
|
85
96
|
netRetained: e.netChange.toString(),
|
|
86
97
|
})));
|
|
87
98
|
}
|
|
88
99
|
}
|
|
89
|
-
function absBigInt(x) {
|
|
90
|
-
return x < 0n ? -x : x;
|
|
91
|
-
}
|
|
@@ -29,8 +29,8 @@ import type { SimulateParams, SimulationConfig, SimulationResult } from "../type
|
|
|
29
29
|
* empty transactions, malformed authorizations).
|
|
30
30
|
* @throws {UnsupportedChainError} when the chain is not configured for any backend.
|
|
31
31
|
* @throws {SimulationRevertedError} when the bundle reverts on either backend.
|
|
32
|
-
* @throws {BlacklistViolationError} when the simulation leaves value retained by
|
|
33
|
-
*
|
|
32
|
+
* @throws {BlacklistViolationError} when the simulation leaves value retained by
|
|
33
|
+
* a `bundler3` address beyond the dust threshold.
|
|
34
34
|
* @throws {ExternalServiceError} (a) when both backends are unavailable within the
|
|
35
35
|
* timeout budget, or (b) when a backend returns a `calls` array whose length does
|
|
36
36
|
* not match the resolved `simulationTxs` — refusing to map transfers with mismatched
|
|
@@ -34,8 +34,8 @@ const index_js_2 = require("./pipeline/index.js");
|
|
|
34
34
|
* empty transactions, malformed authorizations).
|
|
35
35
|
* @throws {UnsupportedChainError} when the chain is not configured for any backend.
|
|
36
36
|
* @throws {SimulationRevertedError} when the bundle reverts on either backend.
|
|
37
|
-
* @throws {BlacklistViolationError} when the simulation leaves value retained by
|
|
38
|
-
*
|
|
37
|
+
* @throws {BlacklistViolationError} when the simulation leaves value retained by
|
|
38
|
+
* a `bundler3` address beyond the dust threshold.
|
|
39
39
|
* @throws {ExternalServiceError} (a) when both backends are unavailable within the
|
|
40
40
|
* timeout budget, or (b) when a backend returns a `calls` array whose length does
|
|
41
41
|
* not match the resolved `simulationTxs` — refusing to map transfers with mismatched
|
|
@@ -9,11 +9,11 @@ interface AssertNoBundlerRetentionParams {
|
|
|
9
9
|
*
|
|
10
10
|
* Uses net flow (inbound minus outbound) per (bundler address, token) pair.
|
|
11
11
|
* Bundler3 legitimately receives tokens as an intermediary (user → bundler3 →
|
|
12
|
-
* vault), so gross inbound would fire false positives. We only
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
12
|
+
* vault), so gross inbound would fire false positives. We only block positive
|
|
13
|
+
* net flow above `DUST_THRESHOLD` — tokens stuck in a bundler address. Negative
|
|
14
|
+
* net flow means the simulated bundle sweeps a pre-existing or state-overridden
|
|
15
|
+
* bundler balance. That is useful telemetry, but not current-bundle retention,
|
|
16
|
+
* so it is warned instead of raising a blacklist violation.
|
|
17
17
|
*/
|
|
18
18
|
export declare function assertNoBundlerRetention(params: AssertNoBundlerRetentionParams): void;
|
|
19
19
|
export {};
|
|
@@ -44,11 +44,11 @@ function getBundlerAddresses(chainId, logger) {
|
|
|
44
44
|
*
|
|
45
45
|
* Uses net flow (inbound minus outbound) per (bundler address, token) pair.
|
|
46
46
|
* Bundler3 legitimately receives tokens as an intermediary (user → bundler3 →
|
|
47
|
-
* vault), so gross inbound would fire false positives. We only
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
47
|
+
* vault), so gross inbound would fire false positives. We only block positive
|
|
48
|
+
* net flow above `DUST_THRESHOLD` — tokens stuck in a bundler address. Negative
|
|
49
|
+
* net flow means the simulated bundle sweeps a pre-existing or state-overridden
|
|
50
|
+
* bundler balance. That is useful telemetry, but not current-bundle retention,
|
|
51
|
+
* so it is warned instead of raising a blacklist violation.
|
|
52
52
|
*/
|
|
53
53
|
export function assertNoBundlerRetention(params) {
|
|
54
54
|
const { chainId, transfers, logger } = params;
|
|
@@ -74,15 +74,23 @@ export function assertNoBundlerRetention(params) {
|
|
|
74
74
|
if (bundlerAddresses.has(t.from))
|
|
75
75
|
recordFlow(t.from, t.token, -t.amount);
|
|
76
76
|
}
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
const entries = [...flow.values()];
|
|
78
|
+
const drained = entries.filter((e) => e.netChange < -DUST_THRESHOLD);
|
|
79
|
+
if (drained.length > 0) {
|
|
80
|
+
logger?.warn("Simulation detected pre-existing bundler balance being swept", {
|
|
81
|
+
changes: drained.map((e) => ({
|
|
82
|
+
address: e.address,
|
|
83
|
+
token: e.token,
|
|
84
|
+
netSwept: (-e.netChange).toString(),
|
|
85
|
+
})),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
const retained = entries.filter((e) => e.netChange > DUST_THRESHOLD);
|
|
89
|
+
if (retained.length > 0) {
|
|
90
|
+
throw new BlacklistViolationError("Simulation detected asset transfers retained by restricted bundler contracts", retained.map((e) => ({
|
|
80
91
|
address: e.address,
|
|
81
92
|
token: e.token,
|
|
82
93
|
netRetained: e.netChange.toString(),
|
|
83
94
|
})));
|
|
84
95
|
}
|
|
85
96
|
}
|
|
86
|
-
function absBigInt(x) {
|
|
87
|
-
return x < 0n ? -x : x;
|
|
88
|
-
}
|
|
@@ -29,8 +29,8 @@ import type { SimulateParams, SimulationConfig, SimulationResult } from "../type
|
|
|
29
29
|
* empty transactions, malformed authorizations).
|
|
30
30
|
* @throws {UnsupportedChainError} when the chain is not configured for any backend.
|
|
31
31
|
* @throws {SimulationRevertedError} when the bundle reverts on either backend.
|
|
32
|
-
* @throws {BlacklistViolationError} when the simulation leaves value retained by
|
|
33
|
-
*
|
|
32
|
+
* @throws {BlacklistViolationError} when the simulation leaves value retained by
|
|
33
|
+
* a `bundler3` address beyond the dust threshold.
|
|
34
34
|
* @throws {ExternalServiceError} (a) when both backends are unavailable within the
|
|
35
35
|
* timeout budget, or (b) when a backend returns a `calls` array whose length does
|
|
36
36
|
* not match the resolved `simulationTxs` — refusing to map transfers with mismatched
|
|
@@ -31,8 +31,8 @@ import { assertNoBundlerRetention, buildSimulationTxs, executeSimulation, valida
|
|
|
31
31
|
* empty transactions, malformed authorizations).
|
|
32
32
|
* @throws {UnsupportedChainError} when the chain is not configured for any backend.
|
|
33
33
|
* @throws {SimulationRevertedError} when the bundle reverts on either backend.
|
|
34
|
-
* @throws {BlacklistViolationError} when the simulation leaves value retained by
|
|
35
|
-
*
|
|
34
|
+
* @throws {BlacklistViolationError} when the simulation leaves value retained by
|
|
35
|
+
* a `bundler3` address beyond the dust threshold.
|
|
36
36
|
* @throws {ExternalServiceError} (a) when both backends are unavailable within the
|
|
37
37
|
* timeout budget, or (b) when a backend returns a `calls` array whose length does
|
|
38
38
|
* not match the resolved `simulationTxs` — refusing to map transfers with mismatched
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morpho-org/evm-simulation",
|
|
3
3
|
"description": "EVM simulation engine for Morpho transactions.",
|
|
4
|
-
"version": "4.0.
|
|
4
|
+
"version": "4.0.1",
|
|
5
5
|
"author": "Morpho Association <contact@morpho.org>",
|
|
6
6
|
"contributors": [
|
|
7
7
|
"Rubilmax <rmilon@gmail.com>"
|
|
@@ -25,16 +25,16 @@
|
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"zod": "^4.4.3",
|
|
28
|
-
"@morpho-org/
|
|
29
|
-
"@morpho-org/
|
|
28
|
+
"@morpho-org/morpho-ts": "^2.6.0",
|
|
29
|
+
"@morpho-org/blue-sdk": "^6.2.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"viem": "^2.0.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"typescript": "^6.0.3",
|
|
36
|
-
"viem": "
|
|
37
|
-
"vitest": "^4.1.
|
|
36
|
+
"viem": "2.52.2",
|
|
37
|
+
"vitest": "^4.1.8",
|
|
38
38
|
"@morpho-org/test": "^2.8.1"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|