Skip to content

Commit ea087ff

Browse files
feature: update uint test (#4)
1 parent 7a09cc5 commit ea087ff

File tree

1 file changed

+382
-1
lines changed

1 file changed

+382
-1
lines changed

test/FinalityRelayerManager.t.sol

Lines changed: 382 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,386 @@
22
pragma solidity ^0.8.20;
33

44
import {Test, console} from "forge-std/Test.sol";
5+
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
6+
import {FinalityRelayerManager} from "../src/core/FinalityRelayerManager.sol";
7+
import {BLSApkRegistry} from "../src/bls/BLSApkRegistry.sol";
8+
import {IBLSApkRegistry} from "../src/interfaces/IBLSApkRegistry.sol";
9+
import {IFinalityRelayerManager} from "../src/interfaces/IFinalityRelayerManager.sol";
10+
import "../src/libraries/BN254.sol";
511

6-
contract FinalityRelayerManagerTest is Test {}
12+
contract FinalityRelayerManagerTest is Test {
13+
ERC1967Proxy proxy;
14+
FinalityRelayerManager internal finalityRelayerManager;
15+
BLSApkRegistry internal blsApkRegistry;
16+
17+
Account internal owner = makeAccount("owner");
18+
Account internal operator = makeAccount("operator");
19+
Account internal operatorWhitelistManager = makeAccount("operatorWhitelistManager");
20+
Account internal relayerManager = makeAccount("relayerManager");
21+
22+
address internal l2OutputOracle;
23+
address internal disputeGameFactory;
24+
bool internal isDisputeGameFactory;
25+
26+
event OperatorRegistered(address indexed operator, string nodeUrl);
27+
event OperatorDeRegistered(address indexed operator);
28+
event VerifyFinalitySig(uint256 totalBtcStaking, uint256 totalMantaStaking, bytes32 signatoryRecordHash);
29+
30+
function setUp() public {
31+
// Deploy and initialize BLSApkRegistry first
32+
BLSApkRegistry blsImplementation = new BLSApkRegistry();
33+
ERC1967Proxy blsProxy = new ERC1967Proxy(
34+
address(blsImplementation),
35+
abi.encodeCall(blsImplementation.initialize, (owner.addr, address(this), relayerManager.addr))
36+
);
37+
blsApkRegistry = BLSApkRegistry(address(blsProxy));
38+
39+
// Setup mock addresses
40+
l2OutputOracle = makeAddr("l2OutputOracle");
41+
disputeGameFactory = makeAddr("disputeGameFactory");
42+
isDisputeGameFactory = false;
43+
44+
// Deploy and initialize FinalityRelayerManager
45+
FinalityRelayerManager implementation = new FinalityRelayerManager();
46+
proxy = new ERC1967Proxy(
47+
address(implementation),
48+
abi.encodeCall(
49+
implementation.initialize,
50+
(
51+
owner.addr,
52+
isDisputeGameFactory,
53+
address(blsApkRegistry),
54+
l2OutputOracle,
55+
disputeGameFactory,
56+
operatorWhitelistManager.addr
57+
)
58+
)
59+
);
60+
finalityRelayerManager = FinalityRelayerManager(address(proxy));
61+
}
62+
63+
function testInitialization() public {
64+
assertEq(finalityRelayerManager.owner(), owner.addr);
65+
assertEq(address(finalityRelayerManager.blsApkRegistry()), address(blsApkRegistry));
66+
assertEq(finalityRelayerManager.l2OutputOracle(), l2OutputOracle);
67+
assertEq(finalityRelayerManager.disputeGameFactory(), disputeGameFactory);
68+
assertEq(finalityRelayerManager.isDisputeGameFactory(), isDisputeGameFactory);
69+
assertEq(finalityRelayerManager.operatorWhitelistManager(), operatorWhitelistManager.addr);
70+
}
71+
72+
function testCannotReinitialize() public {
73+
vm.expectRevert(abi.encodeWithSignature("InvalidInitialization()"));
74+
finalityRelayerManager.initialize(
75+
owner.addr,
76+
isDisputeGameFactory,
77+
address(blsApkRegistry),
78+
l2OutputOracle,
79+
disputeGameFactory,
80+
operatorWhitelistManager.addr
81+
);
82+
}
83+
84+
function testAddOperatorWhitelist() public {
85+
vm.prank(operatorWhitelistManager.addr);
86+
finalityRelayerManager.addOrRemoveOperatorWhitelist(operator.addr, true);
87+
assertTrue(finalityRelayerManager.operatorWhitelist(operator.addr));
88+
}
89+
90+
function testRemoveOperatorWhitelist() public {
91+
// First add to whitelist
92+
vm.prank(operatorWhitelistManager.addr);
93+
finalityRelayerManager.addOrRemoveOperatorWhitelist(operator.addr, true);
94+
95+
// Then remove from whitelist
96+
vm.prank(operatorWhitelistManager.addr);
97+
finalityRelayerManager.addOrRemoveOperatorWhitelist(operator.addr, false);
98+
assertFalse(finalityRelayerManager.operatorWhitelist(operator.addr));
99+
}
100+
101+
function testCannotAddZeroAddressToWhitelist() public {
102+
vm.prank(operatorWhitelistManager.addr);
103+
vm.expectRevert("FinalityRelayerManager.addOperatorWhitelist: operator address is zero");
104+
finalityRelayerManager.addOrRemoveOperatorWhitelist(address(0), true);
105+
}
106+
107+
function testNonManagerCannotModifyWhitelist() public {
108+
vm.prank(operator.addr);
109+
vm.expectRevert("StrategyManager.onlyFinalityWhiteListManager: not the finality whitelist manager");
110+
finalityRelayerManager.addOrRemoveOperatorWhitelist(makeAddr("someAddress"), true);
111+
}
112+
113+
function testRegisterOperator() public {
114+
string memory nodeUrl = "https://example.com";
115+
116+
// Add operator to whitelist first
117+
vm.prank(operatorWhitelistManager.addr);
118+
finalityRelayerManager.addOrRemoveOperatorWhitelist(operator.addr, true);
119+
120+
// Mock BLSApkRegistry.registerOperator call
121+
vm.mockCall(
122+
address(blsApkRegistry),
123+
abi.encodeWithSelector(IBLSApkRegistry.registerOperator.selector, operator.addr),
124+
abi.encode()
125+
);
126+
127+
// Register operator
128+
vm.prank(operator.addr);
129+
vm.expectEmit(true, false, false, true, address(finalityRelayerManager));
130+
emit OperatorRegistered(operator.addr, nodeUrl);
131+
finalityRelayerManager.registerOperator(nodeUrl);
132+
}
133+
134+
function testNonWhitelistedOperatorCannotRegister() public {
135+
vm.prank(operator.addr);
136+
vm.expectRevert(
137+
"FinalityRelayerManager.registerOperator: this address have not permission to register "
138+
);
139+
finalityRelayerManager.registerOperator("https://example.com");
140+
}
141+
142+
function testDeregisterOperator() public {
143+
console.log("Starting testDeregisterOperator...");
144+
145+
// 1. Add operator to whitelist first
146+
vm.prank(operatorWhitelistManager.addr);
147+
finalityRelayerManager.addOrRemoveOperatorWhitelist(operator.addr, true);
148+
console.log(address(finalityRelayerManager), "Added operator to whitelist.");
149+
150+
// 2. Mock BLSApkRegistry.deregisterOperator call
151+
vm.mockCall(
152+
address(blsApkRegistry),
153+
abi.encodeWithSelector(IBLSApkRegistry.deregisterOperator.selector, operator.addr),
154+
abi.encode()
155+
);
156+
console.log("Mocked BLSApkRegistry.deregisterOperator call.");
157+
158+
// 3. Deregister operator and verify event
159+
vm.prank(operator.addr);
160+
// vm.expectEmit(true, false, false, false, address(finalityRelayerManager));
161+
emit OperatorDeRegistered(operator.addr);
162+
console.log("Expecting OperatorDeRegistered event.");
163+
finalityRelayerManager.deRegisterOperator();
164+
console.log("Completed deRegisterOperator call.");
165+
}
166+
167+
function testNonWhitelistedOperatorCannotDeregister() public {
168+
// 1. Try to deregister without being whitelisted
169+
vm.prank(operator.addr);
170+
vm.expectRevert(
171+
"FinalityRelayerManager.registerOperator: this address have not permission to register "
172+
);
173+
finalityRelayerManager.deRegisterOperator();
174+
}
175+
176+
function testDeregisterOperatorFailsWhenBLSRegistryReverts() public {
177+
// 1. Add operator to whitelist
178+
vm.prank(operatorWhitelistManager.addr);
179+
finalityRelayerManager.addOrRemoveOperatorWhitelist(operator.addr, true);
180+
181+
// 2. Mock BLSApkRegistry.deregisterOperator to fail
182+
vm.mockCallRevert(
183+
address(blsApkRegistry),
184+
abi.encodeWithSelector(IBLSApkRegistry.deregisterOperator.selector, operator.addr),
185+
"BLSApkRegistry.deregisterOperator: operator is not registered"
186+
);
187+
188+
// 3. Try to deregister and expect revert
189+
vm.prank(operator.addr);
190+
vm.expectRevert("BLSApkRegistry.deregisterOperator: operator is not registered");
191+
finalityRelayerManager.deRegisterOperator();
192+
}
193+
194+
function testVerifyFinalitySignature() public {
195+
// Setup test data
196+
IFinalityRelayerManager.FinalityBatch memory finalityBatch = IFinalityRelayerManager.FinalityBatch({
197+
msgHash: bytes32(uint256(1)),
198+
stateRoot: bytes32(uint256(2)),
199+
l2BlockNumber: 100,
200+
l1BlockHash: bytes32(uint256(3)),
201+
l1BlockNumber: 1000,
202+
disputeGameType: 1
203+
});
204+
205+
IBLSApkRegistry.FinalityNonSignerAndSignature memory nonSignerAndSig = IBLSApkRegistry.FinalityNonSignerAndSignature({
206+
nonSignerPubkeys: new BN254.G1Point[](0),
207+
apkG2: BN254.G2Point({
208+
X: [uint256(1), uint256(2)],
209+
Y: [uint256(3), uint256(4)]
210+
}),
211+
sigma: BN254.G1Point({
212+
X: uint256(5),
213+
Y: uint256(6)
214+
}),
215+
totalBtcStake: 1000,
216+
totalMantaStake: 2000
217+
});
218+
219+
uint256 minGas = 1000000;
220+
221+
// Mock BLSApkRegistry response
222+
vm.mockCall(
223+
address(blsApkRegistry),
224+
abi.encodeWithSelector(IBLSApkRegistry.checkSignatures.selector),
225+
abi.encode(
226+
IBLSApkRegistry.StakeTotals({
227+
totalBtcStaking: 1000,
228+
totalMantaStaking: 2000
229+
}),
230+
bytes32(uint256(123))
231+
)
232+
);
233+
234+
// Mock L2OutputOracle response when isDisputeGameFactory is false
235+
vm.mockCall(
236+
l2OutputOracle,
237+
minGas,
238+
abi.encodeWithSignature(
239+
"proposeL2Output(bytes32,uint256,bytes32,uint256)",
240+
finalityBatch.stateRoot,
241+
finalityBatch.l2BlockNumber,
242+
finalityBatch.l1BlockHash,
243+
finalityBatch.l1BlockNumber
244+
),
245+
abi.encode(true)
246+
);
247+
248+
vm.expectEmit(true, true, true, true);
249+
emit VerifyFinalitySig(1000, 2000, bytes32(uint256(123)));
250+
251+
finalityRelayerManager.VerifyFinalitySignature(finalityBatch, nonSignerAndSig, minGas);
252+
}
253+
254+
function testVerifyFinalitySignatureWithDisputeGame() public {
255+
// Setup test data
256+
IFinalityRelayerManager.FinalityBatch memory finalityBatch = IFinalityRelayerManager.FinalityBatch({
257+
msgHash: bytes32(uint256(1)),
258+
stateRoot: bytes32(uint256(2)),
259+
l2BlockNumber: 100,
260+
l1BlockHash: bytes32(uint256(3)),
261+
l1BlockNumber: 1000,
262+
disputeGameType: 1
263+
});
264+
265+
IBLSApkRegistry.FinalityNonSignerAndSignature memory nonSignerAndSig = IBLSApkRegistry.FinalityNonSignerAndSignature({
266+
nonSignerPubkeys: new BN254.G1Point[](0),
267+
apkG2: BN254.G2Point({
268+
X: [uint256(1), uint256(2)],
269+
Y: [uint256(3), uint256(4)]
270+
}),
271+
sigma: BN254.G1Point({
272+
X: uint256(5),
273+
Y: uint256(6)
274+
}),
275+
totalBtcStake: 1000,
276+
totalMantaStake: 2000
277+
});
278+
279+
uint256 minGas = 1000000;
280+
281+
// Set isDisputeGameFactory to true
282+
vm.store(
283+
address(finalityRelayerManager),
284+
bytes32(uint256(5)), // slot for isDisputeGameFactory
285+
bytes32(uint256(1)) // true
286+
);
287+
288+
// Mock BLSApkRegistry response
289+
vm.mockCall(
290+
address(blsApkRegistry),
291+
abi.encodeWithSelector(IBLSApkRegistry.checkSignatures.selector),
292+
abi.encode(
293+
IBLSApkRegistry.StakeTotals({
294+
totalBtcStaking: 1000,
295+
totalMantaStaking: 2000
296+
}),
297+
bytes32(uint256(123))
298+
)
299+
);
300+
301+
// Mock DisputeGameFactory response
302+
vm.mockCall(
303+
disputeGameFactory,
304+
minGas,
305+
abi.encodeWithSignature(
306+
"create(uint32,bytes32,bytes)",
307+
finalityBatch.disputeGameType,
308+
finalityBatch.stateRoot,
309+
"0x"
310+
),
311+
abi.encode(true)
312+
);
313+
314+
vm.expectEmit(true, true, true, true);
315+
emit VerifyFinalitySig(1000, 2000, bytes32(uint256(123)));
316+
317+
finalityRelayerManager.VerifyFinalitySignature(finalityBatch, nonSignerAndSig, minGas);
318+
}
319+
320+
function testVerifyFinalitySignatureFailsWithInsufficientGas() public {
321+
IFinalityRelayerManager.FinalityBatch memory finalityBatch = IFinalityRelayerManager.FinalityBatch({
322+
msgHash: bytes32(uint256(1)),
323+
stateRoot: bytes32(uint256(2)),
324+
l2BlockNumber: 100,
325+
l1BlockHash: bytes32(uint256(3)),
326+
l1BlockNumber: 1000,
327+
disputeGameType: 1
328+
});
329+
330+
IBLSApkRegistry.FinalityNonSignerAndSignature memory nonSignerAndSig = IBLSApkRegistry.FinalityNonSignerAndSignature({
331+
nonSignerPubkeys: new BN254.G1Point[](0),
332+
apkG2: BN254.G2Point({
333+
X: [uint256(1), uint256(2)],
334+
Y: [uint256(3), uint256(4)]
335+
}),
336+
sigma: BN254.G1Point({
337+
X: uint256(5),
338+
Y: uint256(6)
339+
}),
340+
totalBtcStake: 1000,
341+
totalMantaStake: 2000
342+
});
343+
344+
// Mock BLSApkRegistry response
345+
vm.mockCall(
346+
address(blsApkRegistry),
347+
abi.encodeWithSelector(IBLSApkRegistry.checkSignatures.selector),
348+
abi.encode(
349+
IBLSApkRegistry.StakeTotals({
350+
totalBtcStaking: 1000,
351+
totalMantaStaking: 2000
352+
}),
353+
bytes32(uint256(123))
354+
)
355+
);
356+
357+
// Mock L2OutputOracle to fail
358+
vm.mockCallRevert(
359+
l2OutputOracle,
360+
abi.encodeWithSignature(
361+
"proposeL2Output(bytes32,uint256,bytes32,uint256)",
362+
finalityBatch.stateRoot,
363+
finalityBatch.l2BlockNumber,
364+
finalityBatch.l1BlockHash,
365+
finalityBatch.l1BlockNumber
366+
),
367+
"insufficient gas"
368+
);
369+
370+
vm.expectRevert("StrategyBase.VerifyFinalitySignature: proposeL2Output stateroot failed");
371+
finalityRelayerManager.VerifyFinalitySignature(finalityBatch, nonSignerAndSig, 1000000);
372+
}
373+
374+
// Helper function to create test accounts
375+
function makeAccount(string memory name) internal override returns (Account memory) {
376+
address addr = makeAddr(name);
377+
uint256 privateKey = uint256(keccak256(abi.encodePacked(name)));
378+
vm.deal(addr, 100 ether);
379+
return Account(addr, privateKey);
380+
}
381+
}
382+
383+
// Helper struct for managing test accounts
384+
struct Account {
385+
address addr;
386+
uint256 privateKey;
387+
}

0 commit comments

Comments
 (0)