-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathutilsTenderly7702.test.js
More file actions
157 lines (142 loc) · 5.13 KB
/
Copy pathutilsTenderly7702.test.js
File metadata and controls
157 lines (142 loc) · 5.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Regression tests for EIP-7702 handling in the Tenderly simulation helpers:
// short/padded factory markers, fresh-delegation code overrides, and
// non-empty factoryData (sender initialization). Mocks global fetch and
// inspects the simulate-bundle request bodies.
const ak = require("../dist/index.cjs");
const ENTRYPOINT_V8 = "0x4337084d9e255ff0702461cf8895ce9e3b5ff108";
const SENDER_CREATOR_V8 = "0x449ed7c3e6fee6a97311d4b55475df59c44add33";
const PADDED_MARKER = "0x7702000000000000000000000000000000000000";
const SENDER = "0x1f9090aae28b8a3dceadf281b0f12828e676c326";
const DELEGATEE = "0xe6cae83bde06e4c305530e199d7217f42808555b";
const DELEGATION_CODE = `0xef0100${DELEGATEE.slice(2)}`;
function makeV8UserOperation(overrides = {}) {
return {
sender: SENDER,
nonce: 1n,
factory: "0x7702",
factoryData: null,
callData: "0xb61d27f6",
callGasLimit: 100000n,
verificationGasLimit: 100000n,
preVerificationGas: 50000n,
maxFeePerGas: 1000000n,
maxPriorityFeePerGas: 1000000n,
paymaster: null,
paymasterVerificationGasLimit: null,
paymasterPostOpGasLimit: null,
paymasterData: null,
signature: "0x",
eip7702Auth: { address: DELEGATEE },
...overrides,
};
}
describe("Tenderly EIP-7702 simulation handling", () => {
const originalFetch = global.fetch;
let requests;
beforeEach(() => {
requests = [];
global.fetch = async (url, init) => {
const body = JSON.parse(init.body);
requests.push({ url, body });
return {
ok: true,
status: 200,
statusText: "OK",
text: async () =>
JSON.stringify({
simulation_results: body.simulations.map((_s, i) => ({
transaction: {},
simulation: { id: `sim-${i}` },
})),
}),
};
};
});
afterEach(() => {
global.fetch = originalFetch;
});
describe("full handleOps simulation (simulateUserOperationWithTenderly)", () => {
async function runFullSimulation(userOperation) {
await ak.simulateUserOperationWithTenderly(
"account",
"project",
"key",
1n,
ENTRYPOINT_V8,
userOperation,
);
expect(requests).toHaveLength(1);
return requests[0].body.simulations[0];
}
test("short marker with non-empty factoryData packs a padded marker head", async () => {
const sim = await runFullSimulation(
makeV8UserOperation({ factory: "0x7702", factoryData: "0xdeadbeef" }),
);
// initCode must be 0x7702 right-padded to 20 bytes ‖ factoryData …
expect(sim.input).toContain(`${PADDED_MARKER.slice(2)}deadbeef`);
// … not the malformed direct concatenation 0x7702‖factoryData
expect(sim.input).not.toContain("7702deadbeef");
});
test("padded marker with non-empty factoryData packs identically", async () => {
const sim = await runFullSimulation(
makeV8UserOperation({ factory: PADDED_MARKER, factoryData: "0xdeadbeef" }),
);
expect(sim.input).toContain(`${PADDED_MARKER.slice(2)}deadbeef`);
});
test("installs the sender delegation-code override", async () => {
const sim = await runFullSimulation(makeV8UserOperation());
expect(sim.state_objects[SENDER].code).toBe(DELEGATION_CODE);
});
});
describe("direct call-data simulation (simulateUserOperationCallDataWithTenderly)", () => {
async function runCallDataSimulation(userOperation, stateOverrides) {
await ak.simulateUserOperationCallDataWithTenderly(
"account",
"project",
"key",
1n,
ENTRYPOINT_V8,
userOperation,
null,
stateOverrides,
);
expect(requests).toHaveLength(1);
return requests[0].body.simulations;
}
test("fresh delegation installs the sender code override", async () => {
const sims = await runCallDataSimulation(makeV8UserOperation());
expect(sims).toHaveLength(1);
expect(sims[0].to).toBe(SENDER);
expect(sims[0].state_objects[SENDER].code).toBe(DELEGATION_CODE);
});
test("non-empty factoryData enqueues a SenderCreator-to-sender initialization", async () => {
const sims = await runCallDataSimulation(
makeV8UserOperation({ factoryData: "0xdeadbeef" }),
);
expect(sims).toHaveLength(2);
// initialization call: SenderCreator -> sender with the init data
expect(sims[0].from).toBe(SENDER_CREATOR_V8);
expect(sims[0].to).toBe(SENDER);
expect(sims[0].input).toBe("0xdeadbeef");
// call-data execution follows, both with the delegation override
expect(sims[1].to).toBe(SENDER);
expect(sims[1].input).toBe("0xb61d27f6");
expect(sims[0].state_objects[SENDER].code).toBe(DELEGATION_CODE);
expect(sims[1].state_objects[SENDER].code).toBe(DELEGATION_CODE);
});
test("without eip7702Auth no code override is installed", async () => {
const sims = await runCallDataSimulation(makeV8UserOperation({ eip7702Auth: null }));
expect(sims).toHaveLength(1);
expect(sims[0].state_objects).toBeUndefined();
});
test("merges the delegation override without mutating caller state overrides", async () => {
const callerOverrides = { [SENDER]: { balance: "0x1" } };
const sims = await runCallDataSimulation(makeV8UserOperation(), callerOverrides);
expect(sims[0].state_objects[SENDER]).toEqual({
balance: "0x1",
code: DELEGATION_CODE,
});
expect(callerOverrides).toEqual({ [SENDER]: { balance: "0x1" } });
});
});
});