From 4189f5e21ae6f5d553b329f46573be12f5f96b2d Mon Sep 17 00:00:00 2001 From: wcgcyx Date: Wed, 17 Jul 2024 09:20:21 +1000 Subject: [PATCH] Add example --- test/invariant/InvariantBridge.t.sol | 343 +--------------- test/invariant/MockAdaptor.sol | 40 -- test/invariant/MockHandler.sol | 12 + test/invariant/MockMessenger.sol | 45 +++ .../child/ChildERC20BridgeHandler.sol | 366 ------------------ test/invariant/child/ChildHelper.sol | 92 ----- .../root/RootERC20BridgeFlowRateHandler.sol | 322 --------------- test/invariant/root/RootHelper.sol | 128 ------ 8 files changed, 78 insertions(+), 1270 deletions(-) delete mode 100644 test/invariant/MockAdaptor.sol create mode 100644 test/invariant/MockHandler.sol create mode 100644 test/invariant/MockMessenger.sol delete mode 100644 test/invariant/child/ChildERC20BridgeHandler.sol delete mode 100644 test/invariant/child/ChildHelper.sol delete mode 100644 test/invariant/root/RootERC20BridgeFlowRateHandler.sol delete mode 100644 test/invariant/root/RootHelper.sol diff --git a/test/invariant/InvariantBridge.t.sol b/test/invariant/InvariantBridge.t.sol index 12ec8695..60b86483 100644 --- a/test/invariant/InvariantBridge.t.sol +++ b/test/invariant/InvariantBridge.t.sol @@ -2,352 +2,51 @@ pragma solidity 0.8.19; import {Test} from "forge-std/Test.sol"; -import {ChildERC20} from "../../src/child/ChildERC20.sol"; -import {WIMX} from "../../src/child/WIMX.sol"; -import {WETH} from "../../src/lib/WETH.sol"; -import {IChildERC20Bridge, ChildERC20Bridge} from "../../src/child/ChildERC20Bridge.sol"; -import {IRootERC20Bridge, IERC20Metadata} from "../../src/root/RootERC20Bridge.sol"; -import {RootERC20BridgeFlowRate} from "../../src/root/flowrate/RootERC20BridgeFlowRate.sol"; -import {MockAdaptor} from "./MockAdaptor.sol"; -import {ChildHelper} from "./child/ChildHelper.sol"; -import {RootHelper} from "./root/RootHelper.sol"; -import {ChildERC20BridgeHandler} from "./child/ChildERC20BridgeHandler.sol"; -import {RootERC20BridgeFlowRateHandler} from "./root/RootERC20BridgeFlowRateHandler.sol"; +import {MockMessenger} from "./MockMessenger.sol"; +import {MockHandler} from "./MockHandler.sol"; import "forge-std/console.sol"; contract InvariantBridge is Test { string public constant CHAIN_URL = "http://127.0.0.1:8500"; - uint256 public constant IMX_DEPOSIT_LIMIT = 10000 ether; - uint256 public constant MAX_AMOUNT = 10000; address public constant ADMIN = address(0x111); - uint256 public constant NO_OF_USERS = 20; - uint256 public constant NO_OF_TOKENS = 10; - - address[] users; - address[] rootTokens; uint256 childId; uint256 rootId; - uint256 resetId; - ChildERC20Bridge childBridge; - RootERC20BridgeFlowRate rootBridge; - MockAdaptor childAdaptor; - MockAdaptor rootAdaptor; - ChildHelper childHelper; - RootHelper rootHelper; - ChildERC20BridgeHandler childBridgeHandler; - RootERC20BridgeFlowRateHandler rootBridgeHandler; - - uint256 mappingGas; + MockMessenger childMessenger; + MockMessenger rootMessenger; + MockHandler rootHandler; function setUp() public { + // Create two forks, child chain and root chain childId = vm.createFork(CHAIN_URL); rootId = vm.createFork(CHAIN_URL); - // Forge has an issue that fails to reset state at the end of each run. - // For example, we found out that if the context stays at child chain at the end of setUp(), - // the state on child chain will not be reset or if the context stays at root chain, the state - // on the root chain will not be reset, which causes subsequent runs to fail. - // We introduced a third chain called reset chain and we make the context to stay on the reset chain - // in order to reset state on both child chain and root chain. - resetId = vm.createFork(CHAIN_URL); - // Deploy contracts on child chain. + // Deploy messenger on child chain. vm.selectFork(childId); vm.startPrank(ADMIN); - ChildERC20 childTokenTemplate = new ChildERC20(); - childTokenTemplate.initialize(address(123), "Test", "TST", 18); - childAdaptor = new MockAdaptor(); + childMessenger = new MockMessenger(rootId); vm.stopPrank(); - childBridge = new ChildERC20Bridge(address(this)); - WIMX wIMX = new WIMX(); - - // Deploy contracts on root chain. + // Deploy messenger on root chain. vm.selectFork(rootId); vm.startPrank(ADMIN); - ChildERC20 rootTokenTemplate = new ChildERC20(); - rootTokenTemplate.initialize(address(123), "Test", "TST", 18); - rootAdaptor = new MockAdaptor(); + rootMessenger = new MockMessenger(childId); vm.stopPrank(); - rootBridge = new RootERC20BridgeFlowRate(address(this)); - ChildERC20 rootIMXToken = new ChildERC20(); - rootIMXToken.initialize(address(123), "Immutable X", "IMX", 18); - WETH wETH = new WETH(); - - // Configure contracts on child chain. - vm.selectFork(childId); - childAdaptor.initialize(rootId, address(childBridge)); - IChildERC20Bridge.InitializationRoles memory childRoles = IChildERC20Bridge.InitializationRoles({ - defaultAdmin: address(this), - pauser: address(this), - unpauser: address(this), - adaptorManager: address(this), - initialDepositor: address(this), - treasuryManager: address(this) - }); - childBridge.initialize( - childRoles, address(childAdaptor), address(childTokenTemplate), address(rootIMXToken), address(wIMX) - ); - vm.deal(address(childBridge), IMX_DEPOSIT_LIMIT); - - // Configure contracts on root chain. - vm.selectFork(rootId); - rootAdaptor.initialize(childId, address(rootBridge)); - IRootERC20Bridge.InitializationRoles memory rootRoles = IRootERC20Bridge.InitializationRoles({ - defaultAdmin: address(this), - pauser: address(this), - unpauser: address(this), - variableManager: address(this), - adaptorManager: address(this) - }); - rootBridge.initialize( - rootRoles, - address(rootAdaptor), - address(childBridge), - address(rootTokenTemplate), - address(rootIMXToken), - address(wETH), - IMX_DEPOSIT_LIMIT, - ADMIN - ); - - // Create users. - vm.selectFork(rootId); - for (uint256 i = 0; i < NO_OF_USERS; i++) { - address user = vm.addr(0x10000 + i); - // Mint ETH token - vm.deal(user, MAX_AMOUNT); - // Mint IMX token - rootIMXToken.mint(user, MAX_AMOUNT); - users.push(user); - } - // Create tokens. - for (uint256 i = 0; i < NO_OF_TOKENS; i++) { - vm.startPrank(address(0x234)); - ChildERC20 rootToken = new ChildERC20(); - rootToken.initialize(address(123), "Test", "TST", 18); - // Mint token to user - for (uint256 j = 0; j < NO_OF_USERS; j++) { - rootToken.mint(users[j], MAX_AMOUNT); - } - vm.stopPrank(); - // Configure rate for half tokens - if (i % 2 == 0) { - vm.prank(ADMIN); - rootBridge.setRateControlThreshold(address(rootToken), MAX_AMOUNT, MAX_AMOUNT / 3600, MAX_AMOUNT / 2); - } - rootTokens.push(address(rootToken)); - } - - // Deploy helpers and handlers on all chains. - vm.selectFork(childId); - vm.startPrank(ADMIN); - childHelper = new ChildHelper(payable(childBridge)); - address temp = address(new RootHelper(ADMIN, payable(rootBridge))); - childBridgeHandler = new ChildERC20BridgeHandler(childId, rootId, users, rootTokens, address(childHelper), temp); - new RootERC20BridgeFlowRateHandler(childId, rootId, users, rootTokens, address(childHelper), temp); - vm.stopPrank(); - - vm.selectFork(rootId); - vm.startPrank(ADMIN); - new ChildHelper(payable(childBridge)); - rootHelper = new RootHelper(ADMIN, payable(rootBridge)); - new ChildERC20BridgeHandler(childId, rootId, users, rootTokens, address(childHelper), address(rootHelper)); - rootBridgeHandler = new RootERC20BridgeFlowRateHandler( - childId, rootId, users, rootTokens, address(childHelper), address(rootHelper) - ); - vm.stopPrank(); - - // Map tokens - vm.selectFork(rootId); - for (uint256 i = 0; i < NO_OF_TOKENS; i++) { - address rootToken = rootTokens[i]; - rootBridge.mapToken{value: 1}(IERC20Metadata(rootToken)); - mappingGas += 1; - // Verify - address childTokenL1 = rootBridge.rootTokenToChildToken(address(rootToken)); - - vm.selectFork(childId); - address childTokenL2 = childBridge.rootTokenToChildToken(address(rootToken)); - vm.selectFork(rootId); - - assertEq(childTokenL1, childTokenL2, "Child token address mismatch between L1 and L2"); - } - - // Target contracts - bytes4[] memory childSelectors = new bytes4[](8); - childSelectors[0] = childBridgeHandler.withdraw.selector; - childSelectors[1] = childBridgeHandler.withdrawTo.selector; - childSelectors[2] = childBridgeHandler.withdrawIMX.selector; - childSelectors[3] = childBridgeHandler.withdrawIMXTo.selector; - childSelectors[4] = childBridgeHandler.withdrawWIMX.selector; - childSelectors[5] = childBridgeHandler.withdrawWIMXTo.selector; - childSelectors[6] = childBridgeHandler.withdrawETH.selector; - childSelectors[7] = childBridgeHandler.withdrawETHTo.selector; - targetSelector(FuzzSelector({addr: address(childBridgeHandler), selectors: childSelectors})); - - bytes4[] memory rootSelectors = new bytes4[](8); - rootSelectors[0] = rootBridgeHandler.deposit.selector; - rootSelectors[1] = rootBridgeHandler.depositTo.selector; - rootSelectors[2] = rootBridgeHandler.depositIMX.selector; - rootSelectors[3] = rootBridgeHandler.depositIMXTo.selector; - rootSelectors[4] = rootBridgeHandler.depositETH.selector; - rootSelectors[5] = rootBridgeHandler.depositETHTo.selector; - rootSelectors[6] = rootBridgeHandler.depositWETH.selector; - rootSelectors[7] = rootBridgeHandler.depositWETHTo.selector; - targetSelector(FuzzSelector({addr: address(rootBridgeHandler), selectors: rootSelectors})); - - targetContract(address(childBridgeHandler)); - targetContract(address(rootBridgeHandler)); + // Send a message from root chain to child chain + rootMessenger.sendMessage("0x1234"); - vm.selectFork(resetId); + // Set target contract + rootHandler = new MockHandler(); + bytes4[] memory rootSelectors = new bytes4[](1); + rootSelectors[0] = rootHandler.handler.selector; + targetSelector(FuzzSelector({addr: address(rootHandler), selectors: rootSelectors})); + targetContract(address(rootHandler)); } - /// forge-config: default.invariant.runs = 256 - /// forge-config: default.invariant.depth = 15 + /// forge-config: default.invariant.runs = 1 + /// forge-config: default.invariant.depth = 5 /// forge-config: default.invariant.fail-on-revert = true - function invariant_ERC20TokenBalanced() external { - for (uint256 i = 0; i < NO_OF_TOKENS; i++) { - address rootToken = rootTokens[i]; - - vm.selectFork(rootId); - uint256 bridgeBalance = ChildERC20(rootToken).balanceOf(address(rootBridge)); - address childToken = rootBridge.rootTokenToChildToken(rootToken); - - vm.selectFork(childId); - uint256 totalSupply = ChildERC20(childToken).totalSupply(); - - uint256 userBalanceSum = 0; - for (uint256 j = 0; j < NO_OF_USERS; j++) { - address user = users[j]; - userBalanceSum += ChildERC20(childToken).balanceOf(user); - } - - assertEq(bridgeBalance, totalSupply); - assertEq(bridgeBalance, userBalanceSum); - } - } - - /// forge-config: default.invariant.runs = 256 - /// forge-config: default.invariant.depth = 15 - /// forge-config: default.invariant.fail-on-revert = true - function invariant_IndividualERC20TokenBalanced() external { - for (uint256 i = 0; i < NO_OF_TOKENS; i++) { - address rootToken = rootTokens[i]; - vm.selectFork(rootId); - address childToken = rootBridge.rootTokenToChildToken(rootToken); - for (uint256 j = 0; j < NO_OF_USERS; j++) { - address user = users[j]; - - vm.selectFork(rootId); - uint256 balanceL1 = ChildERC20(rootToken).balanceOf(user); - - vm.selectFork(childId); - uint256 balanceL2 = ChildERC20(childToken).balanceOf(user); - - assertEq(balanceL1 + balanceL2, MAX_AMOUNT); - } - } - } - - /// forge-config: default.invariant.runs = 256 - /// forge-config: default.invariant.depth = 15 - /// forge-config: default.invariant.fail-on-revert = true - function invariant_IMXBalanced() external { - vm.selectFork(rootId); - uint256 bridgeBalance = ChildERC20(rootBridge.rootIMXToken()).balanceOf(address(rootBridge)); - - vm.selectFork(childId); - uint256 totalSupply = IMX_DEPOSIT_LIMIT - address(childBridge).balance; - - uint256 userBalanceSum = 0; - for (uint256 j = 0; j < NO_OF_USERS; j++) { - address user = users[j]; - userBalanceSum += user.balance; - } - - assertEq(bridgeBalance, totalSupply); - assertEq(bridgeBalance, userBalanceSum); - } - - /// forge-config: default.invariant.runs = 256 - /// forge-config: default.invariant.depth = 15 - /// forge-config: default.invariant.fail-on-revert = true - function invariant_IndividualIMXBalanced() external { - for (uint256 j = 0; j < NO_OF_USERS; j++) { - address user = users[j]; - - vm.selectFork(rootId); - uint256 balanceL1 = ChildERC20(rootBridge.rootIMXToken()).balanceOf(user); - - vm.selectFork(childId); - uint256 balanceL2 = user.balance; - - assertEq(balanceL1 + balanceL2, MAX_AMOUNT); - } - } - - /// forge-config: default.invariant.runs = 256 - /// forge-config: default.invariant.depth = 15 - /// forge-config: default.invariant.fail-on-revert = true - function invariant_ETHBalanced() external { - vm.selectFork(rootId); - uint256 bridgeBalance = address(rootBridge).balance; - - vm.selectFork(childId); - uint256 totalSupply = ChildERC20(childBridge.childETHToken()).totalSupply(); - - uint256 userBalanceSum = 0; - for (uint256 j = 0; j < NO_OF_USERS; j++) { - address user = users[j]; - userBalanceSum += ChildERC20(childBridge.childETHToken()).balanceOf(user); - } - - assertEq(bridgeBalance, totalSupply); - assertEq(bridgeBalance, userBalanceSum); - } - - /// forge-config: default.invariant.runs = 256 - /// forge-config: default.invariant.depth = 15 - /// forge-config: default.invariant.fail-on-revert = true - function invariant_IndividualETHBalanced() external { - for (uint256 j = 0; j < NO_OF_USERS; j++) { - address user = users[j]; - - vm.selectFork(rootId); - uint256 balanceL1 = user.balance; - - vm.selectFork(childId); - uint256 balanceL2 = ChildERC20(childBridge.childETHToken()).balanceOf(user); - - assertEq(balanceL1 + balanceL2, MAX_AMOUNT); - } - } - - /// forge-config: default.invariant.runs = 256 - /// forge-config: default.invariant.depth = 15 - /// forge-config: default.invariant.fail-on-revert = true - function invariant_NoRemainingWETH() external { - vm.selectFork(rootId); - assertEq(rootBridge.rootWETHToken().balance, 0); - } - - /// forge-config: default.invariant.runs = 256 - /// forge-config: default.invariant.depth = 15 - /// forge-config: default.invariant.fail-on-revert = true - function invariant_NoRemainingWIMX() external { - vm.selectFork(childId); - assertEq(childBridge.wIMXToken().balance, 0); - } - - /// forge-config: default.invariant.runs = 256 - /// forge-config: default.invariant.depth = 15 - /// forge-config: default.invariant.fail-on-revert = true - function invariant_GasBalanced() external { - vm.selectFork(rootId); - assertEq(address(rootAdaptor).balance - mappingGas, rootHelper.totalGas()); - vm.selectFork(childId); - assertEq(address(childAdaptor).balance, childHelper.totalGas()); + function invariant_test() external { } } diff --git a/test/invariant/MockAdaptor.sol b/test/invariant/MockAdaptor.sol deleted file mode 100644 index 0a5bfe83..00000000 --- a/test/invariant/MockAdaptor.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: Apache 2.0 -pragma solidity 0.8.19; - -import {Test} from "forge-std/Test.sol"; -import {IChildBridgeAdaptor} from "../../src/interfaces/child/IChildBridgeAdaptor.sol"; -import {IRootBridgeAdaptor} from "../../src/interfaces/root/IRootBridgeAdaptor.sol"; - -interface MessageReceiver { - function onMessageReceive(bytes calldata data) external; -} - -contract MockAdaptor is Test, IChildBridgeAdaptor, IRootBridgeAdaptor { - uint256 otherChainId; - MessageReceiver messageReceiver; - - constructor() {} - - function initialize(uint256 _otherChainId, address _messageReceiver) public { - otherChainId = _otherChainId; - messageReceiver = MessageReceiver(_messageReceiver); - } - - function sendMessage(bytes calldata payload, address /*refundRecipient*/ ) - external - payable - override(IChildBridgeAdaptor, IRootBridgeAdaptor) - { - uint256 original = vm.activeFork(); - - // Switch to the other chain. - vm.selectFork(otherChainId); - onMessageReceive(payload); - - vm.selectFork(original); - } - - function onMessageReceive(bytes calldata data) public { - messageReceiver.onMessageReceive(data); - } -} diff --git a/test/invariant/MockHandler.sol b/test/invariant/MockHandler.sol new file mode 100644 index 00000000..3a28895a --- /dev/null +++ b/test/invariant/MockHandler.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: Apache 2.0 +pragma solidity 0.8.19; + +import {Test} from "forge-std/Test.sol"; + +contract MockHandler is Test { + constructor() { + } + + function handler() public { + } +} \ No newline at end of file diff --git a/test/invariant/MockMessenger.sol b/test/invariant/MockMessenger.sol new file mode 100644 index 00000000..89df66ff --- /dev/null +++ b/test/invariant/MockMessenger.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: Apache 2.0 +pragma solidity 0.8.19; + +import {Test} from "forge-std/Test.sol"; +import "forge-std/console.sol"; + +contract MockMessenger is Test { + + uint256 otherChainId; + + constructor(uint256 _otherChainId) { + otherChainId = _otherChainId; + + uint256 currentChainId = vm.activeFork(); + if (currentChainId == otherChainId) { + revert("This should never happen"); + } + } + + function sendMessage(bytes calldata payload) external { + // Get current chain. + uint256 currentChainId = vm.activeFork(); + console.log("The current chain is", currentChainId, "other chain id is", otherChainId); + if (currentChainId == otherChainId) { + revert("This should never happen"); + } + + // Switch to the other chain. + vm.selectFork(otherChainId); + + currentChainId = vm.activeFork(); + console.log("The current chain is", currentChainId, "other chain id is", otherChainId); + if (currentChainId == otherChainId) { + revert("This should never happen"); + } + + onMessageReceive(payload); + + // Switch back to the original chain. + vm.selectFork(currentChainId); + } + + function onMessageReceive(bytes calldata data) public { + } +} \ No newline at end of file diff --git a/test/invariant/child/ChildERC20BridgeHandler.sol b/test/invariant/child/ChildERC20BridgeHandler.sol deleted file mode 100644 index 65f9d485..00000000 --- a/test/invariant/child/ChildERC20BridgeHandler.sol +++ /dev/null @@ -1,366 +0,0 @@ -// SPDX-License-Identifier: Apache 2.0 -pragma solidity 0.8.19; - -import {Test} from "forge-std/Test.sol"; -import {ChildERC20} from "../../../src/child/ChildERC20.sol"; -import {ChildHelper} from "./ChildHelper.sol"; -import {RootHelper} from "../root/RootHelper.sol"; -import {WIMX} from "../../../src/child/WIMX.sol"; - -contract ChildERC20BridgeHandler is Test { - uint256 public constant MAX_AMOUNT = 10000; - uint256 public constant MAX_GAS = 100; - - uint256 childId; - uint256 rootId; - address[] users; - address[] rootTokens; - ChildHelper childHelper; - RootHelper rootHelper; - - constructor( - uint256 _childId, - uint256 _rootId, - address[] memory _users, - address[] memory _rootTokens, - address _childHelper, - address _rootHelper - ) { - childId = _childId; - rootId = _rootId; - users = _users; - rootTokens = _rootTokens; - childHelper = ChildHelper(_childHelper); - rootHelper = RootHelper(_rootHelper); - } - - function initialize( - uint256 _childId, - uint256 _rootId, - address[] memory _users, - address[] memory _rootTokens, - address _childHelper, - address _rootHelper - ) public { - childId = _childId; - rootId = _rootId; - users = _users; - rootTokens = _rootTokens; - childHelper = ChildHelper(_childHelper); - rootHelper = RootHelper(_rootHelper); - } - - function withdraw(uint256 userIndexSeed, uint256 tokenIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to child chain - vm.selectFork(childId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - address rootToken = rootTokens[bound(tokenIndexSeed, 0, rootTokens.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get child token - address childToken = childHelper.childBridge().rootTokenToChildToken(rootToken); - - // Get current balance - uint256 currentBalance = ChildERC20(childToken).balanceOf(user); - - if (currentBalance < amount) { - // Fund difference - vm.selectFork(rootId); - rootHelper.deposit(user, rootToken, amount - currentBalance, gasAmt); - vm.selectFork(childId); - } - - vm.selectFork(rootId); - uint256 previousLen = rootHelper.getQueueSize(user); - vm.selectFork(childId); - - childHelper.withdraw(user, childToken, amount, gasAmt); - - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(user, previousLen); - - vm.selectFork(original); - } - - function withdrawTo( - uint256 userIndexSeed, - uint256 recipientIndexSeed, - uint256 tokenIndexSeed, - uint256 amount, - uint256 gasAmt - ) public { - uint256 original = vm.activeFork(); - - // Switch to child chain - vm.selectFork(childId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - address recipient = users[bound(recipientIndexSeed, 0, users.length - 1)]; - address rootToken = rootTokens[bound(tokenIndexSeed, 0, rootTokens.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get child token - address childToken = childHelper.childBridge().rootTokenToChildToken(rootToken); - - // Get current balance - uint256 currentBalance = ChildERC20(childToken).balanceOf(user); - - if (currentBalance < amount) { - // Fund difference - vm.selectFork(rootId); - rootHelper.deposit(user, rootToken, amount - currentBalance, gasAmt); - vm.selectFork(childId); - } - - vm.selectFork(rootId); - uint256 previousLen = rootHelper.getQueueSize(recipient); - vm.selectFork(childId); - - childHelper.withdrawTo(user, recipient, childToken, amount, gasAmt); - - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(recipient, previousLen); - // If recipient is different, transfer back - if (user != recipient) { - vm.prank(recipient); - ChildERC20(rootToken).transfer(user, amount); - } - - vm.selectFork(original); - } - - function withdrawIMX(uint256 userIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to child chain - vm.selectFork(childId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get current balance - uint256 currentBalance = user.balance; - - if (currentBalance < amount) { - // Fund difference - vm.selectFork(rootId); - rootHelper.depositIMX(user, amount - currentBalance, gasAmt); - vm.selectFork(childId); - } - - vm.selectFork(rootId); - uint256 previousLen = rootHelper.getQueueSize(user); - vm.selectFork(childId); - - childHelper.withdrawIMX(user, amount, gasAmt); - - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(user, previousLen); - - vm.selectFork(original); - } - - function withdrawIMXTo(uint256 userIndexSeed, uint256 recipientIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to child chain - vm.selectFork(childId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - address recipient = users[bound(recipientIndexSeed, 0, users.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get current balance - uint256 currentBalance = user.balance; - - if (currentBalance < amount) { - // Fund difference - vm.selectFork(rootId); - rootHelper.depositIMX(user, amount - currentBalance, gasAmt); - vm.selectFork(childId); - } - - vm.selectFork(rootId); - uint256 previousLen = rootHelper.getQueueSize(recipient); - vm.selectFork(childId); - - childHelper.withdrawIMXTo(user, recipient, amount, gasAmt); - - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(recipient, previousLen); - // If recipient is different, transfer back - if (user != recipient) { - address imx = rootHelper.rootBridge().rootIMXToken(); - vm.prank(recipient); - ChildERC20(imx).transfer(user, amount); - } - - vm.selectFork(original); - } - - function withdrawWIMX(uint256 userIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to child chain - vm.selectFork(childId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get current balance - uint256 currentBalance = user.balance; - - if (currentBalance < amount) { - // Fund difference - vm.selectFork(rootId); - rootHelper.depositIMX(user, amount - currentBalance, gasAmt); - vm.selectFork(childId); - } - - vm.selectFork(rootId); - uint256 previousLen = rootHelper.getQueueSize(user); - vm.selectFork(childId); - - // Wrap IMX - address payable wIMX = payable(childHelper.childBridge().wIMXToken()); - vm.prank(user); - WIMX(wIMX).deposit{value: amount}(); - - childHelper.withdrawWIMX(user, amount, gasAmt); - - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(user, previousLen); - - vm.selectFork(original); - } - - function withdrawWIMXTo(uint256 userIndexSeed, uint256 recipientIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to child chain - vm.selectFork(childId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - address recipient = users[bound(recipientIndexSeed, 0, users.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get current balance - uint256 currentBalance = user.balance; - - if (currentBalance < amount) { - // Fund difference - vm.selectFork(rootId); - rootHelper.depositIMX(user, amount - currentBalance, gasAmt); - vm.selectFork(childId); - } - - vm.selectFork(rootId); - uint256 previousLen = rootHelper.getQueueSize(recipient); - vm.selectFork(childId); - - // Wrap IMX - address payable wIMX = payable(childHelper.childBridge().wIMXToken()); - vm.prank(user); - WIMX(wIMX).deposit{value: amount}(); - - childHelper.withdrawWIMXTo(user, recipient, amount, gasAmt); - - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(recipient, previousLen); - // If recipient is different, transfer back - if (user != recipient) { - address imx = rootHelper.rootBridge().rootIMXToken(); - vm.prank(recipient); - ChildERC20(imx).transfer(user, amount); - } - - vm.selectFork(original); - } - - function withdrawETH(uint256 userIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to child chain - vm.selectFork(childId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get current balance - uint256 currentBalance = ChildERC20(childHelper.childBridge().childETHToken()).balanceOf(user); - - if (currentBalance < amount) { - // Fund difference - vm.selectFork(rootId); - rootHelper.depositETH(user, amount - currentBalance, gasAmt); - vm.selectFork(childId); - } - - vm.selectFork(rootId); - uint256 previousLen = rootHelper.getQueueSize(user); - vm.selectFork(childId); - - childHelper.withdrawETH(user, amount, gasAmt); - - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(user, previousLen); - - vm.selectFork(original); - } - - function withdrawETHTo(uint256 userIndexSeed, uint256 recipientIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to child chain - vm.selectFork(childId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - address recipient = users[bound(recipientIndexSeed, 0, users.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get current balance - uint256 currentBalance = ChildERC20(childHelper.childBridge().childETHToken()).balanceOf(user); - - if (currentBalance < amount) { - // Fund difference - vm.selectFork(rootId); - rootHelper.depositETH(user, amount - currentBalance, gasAmt); - vm.selectFork(childId); - } - - vm.selectFork(rootId); - uint256 previousLen = rootHelper.getQueueSize(recipient); - vm.selectFork(childId); - - childHelper.withdrawETHTo(user, recipient, amount, gasAmt); - - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(recipient, previousLen); - // If recipient is different, transfer back - if (user != recipient) { - vm.prank(recipient); - user.call{value: amount}(""); - } - - vm.selectFork(original); - } -} diff --git a/test/invariant/child/ChildHelper.sol b/test/invariant/child/ChildHelper.sol deleted file mode 100644 index ac1a8d3e..00000000 --- a/test/invariant/child/ChildHelper.sol +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: Apache 2.0 -pragma solidity 0.8.19; - -import {Test} from "forge-std/Test.sol"; -import {ChildERC20} from "../../../src/child/ChildERC20.sol"; -import {WIMX} from "../../../src/child/WIMX.sol"; -import {ChildERC20Bridge} from "../../../src/child/ChildERC20Bridge.sol"; -import {IChildERC20} from "../../../src/interfaces/child/IChildERC20.sol"; - -contract ChildHelper is Test { - ChildERC20Bridge public childBridge; - - uint256 public totalGas; - - constructor(address payable _childBridge) { - childBridge = ChildERC20Bridge(_childBridge); - } - - function withdraw(address user, address childToken, uint256 amount, uint256 gasAmt) public { - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - childBridge.withdraw{value: gasAmt}(IChildERC20(childToken), amount); - } - - function withdrawTo(address user, address recipient, address childToken, uint256 amount, uint256 gasAmt) public { - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - childBridge.withdrawTo{value: gasAmt}(IChildERC20(childToken), recipient, amount); - } - - function withdrawIMX(address user, uint256 amount, uint256 gasAmt) public { - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - childBridge.withdrawIMX{value: gasAmt + amount}(amount); - } - - function withdrawIMXTo(address user, address recipient, uint256 amount, uint256 gasAmt) public { - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - childBridge.withdrawIMXTo{value: gasAmt + amount}(recipient, amount); - } - - function withdrawWIMX(address user, uint256 amount, uint256 gasAmt) public { - address payable wIMX = payable(childBridge.wIMXToken()); - - vm.prank(user); - WIMX(wIMX).approve(address(childBridge), amount); - - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - childBridge.withdrawWIMX{value: gasAmt}(amount); - } - - function withdrawWIMXTo(address user, address recipient, uint256 amount, uint256 gasAmt) public { - address payable wIMX = payable(childBridge.wIMXToken()); - - vm.prank(user); - WIMX(wIMX).approve(address(childBridge), amount); - - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - childBridge.withdrawWIMXTo{value: gasAmt}(recipient, amount); - } - - function withdrawETH(address user, uint256 amount, uint256 gasAmt) public { - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - childBridge.withdrawETH{value: gasAmt}(amount); - } - - function withdrawETHTo(address user, address recipient, uint256 amount, uint256 gasAmt) public { - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - childBridge.withdrawETHTo{value: gasAmt}(recipient, amount); - } -} diff --git a/test/invariant/root/RootERC20BridgeFlowRateHandler.sol b/test/invariant/root/RootERC20BridgeFlowRateHandler.sol deleted file mode 100644 index a4334d6d..00000000 --- a/test/invariant/root/RootERC20BridgeFlowRateHandler.sol +++ /dev/null @@ -1,322 +0,0 @@ -// SPDX-License-Identifier: Apache 2.0 -pragma solidity 0.8.19; - -import {Test} from "forge-std/Test.sol"; -import {ChildERC20} from "../../../src/child/ChildERC20.sol"; -import {ChildHelper} from "../child/ChildHelper.sol"; -import {RootHelper} from "./RootHelper.sol"; -import {WIMX as WETH} from "../../../src/child/WIMX.sol"; - -contract RootERC20BridgeFlowRateHandler is Test { - uint256 public constant MAX_AMOUNT = 10000; - uint256 public constant MAX_GAS = 100; - - uint256 childId; - uint256 rootId; - address[] users; - address[] rootTokens; - ChildHelper childHelper; - RootHelper rootHelper; - - constructor( - uint256 _childId, - uint256 _rootId, - address[] memory _users, - address[] memory _rootTokens, - address _childHelper, - address _rootHelper - ) { - childId = _childId; - rootId = _rootId; - users = _users; - rootTokens = _rootTokens; - childHelper = ChildHelper(_childHelper); - rootHelper = RootHelper(_rootHelper); - } - - function deposit(uint256 userIndexSeed, uint256 tokenIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to root chain - vm.selectFork(rootId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - address rootToken = rootTokens[bound(tokenIndexSeed, 0, rootTokens.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get child token - address childToken = rootHelper.rootBridge().rootTokenToChildToken(rootToken); - - // Get current balance - uint256 currentBalance = ChildERC20(rootToken).balanceOf(user); - - if (currentBalance < amount) { - // Fund difference - uint256 previousLen = rootHelper.getQueueSize(user); - vm.selectFork(childId); - childHelper.withdraw(user, childToken, amount - currentBalance, gasAmt); - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(user, previousLen); - } - - rootHelper.deposit(user, rootToken, amount, gasAmt); - - vm.selectFork(original); - } - - function depositTo( - uint256 userIndexSeed, - uint256 recipientIndexSeed, - uint256 tokenIndexSeed, - uint256 amount, - uint256 gasAmt - ) public { - uint256 original = vm.activeFork(); - - // Switch to root chain - vm.selectFork(rootId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - address recipient = users[bound(recipientIndexSeed, 0, users.length - 1)]; - address rootToken = rootTokens[bound(tokenIndexSeed, 0, rootTokens.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get child token - address childToken = rootHelper.rootBridge().rootTokenToChildToken(rootToken); - - // Get current balance - uint256 currentBalance = ChildERC20(rootToken).balanceOf(user); - - if (currentBalance < amount) { - // Fund difference - uint256 previousLen = rootHelper.getQueueSize(user); - vm.selectFork(childId); - childHelper.withdraw(user, childToken, amount - currentBalance, gasAmt); - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(user, previousLen); - } - - rootHelper.depositTo(user, recipient, rootToken, amount, gasAmt); - - // If recipient is different, transfer back - if (user != recipient) { - vm.selectFork(childId); - vm.prank(recipient); - ChildERC20(childToken).transfer(user, amount); - vm.selectFork(rootId); - } - - vm.selectFork(original); - } - - function depositIMX(uint256 userIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to root chain - vm.selectFork(rootId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get current balance - uint256 currentBalance = ChildERC20(rootHelper.rootBridge().rootIMXToken()).balanceOf(user); - - if (currentBalance < amount) { - // Fund difference - uint256 previousLen = rootHelper.getQueueSize(user); - vm.selectFork(childId); - childHelper.withdrawIMX(user, amount - currentBalance, gasAmt); - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(user, previousLen); - } - - rootHelper.depositIMX(user, amount, gasAmt); - - vm.selectFork(original); - } - - function depositIMXTo(uint256 userIndexSeed, uint256 recipientIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to root chain - vm.selectFork(rootId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - address recipient = users[bound(recipientIndexSeed, 0, users.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get current balance - uint256 currentBalance = ChildERC20(rootHelper.rootBridge().rootIMXToken()).balanceOf(user); - - if (currentBalance < amount) { - // Fund difference - uint256 previousLen = rootHelper.getQueueSize(user); - vm.selectFork(childId); - childHelper.withdrawIMX(user, amount - currentBalance, gasAmt); - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(user, previousLen); - } - - rootHelper.depositIMXTo(user, recipient, amount, gasAmt); - - // If recipient is different, transfer back - if (user != recipient) { - vm.selectFork(childId); - vm.prank(recipient); - user.call{value: amount}(""); - vm.selectFork(rootId); - } - - vm.selectFork(original); - } - - function depositETH(uint256 userIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to root chain - vm.selectFork(rootId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get current balance - uint256 currentBalance = user.balance; - - if (currentBalance < amount) { - // Fund difference - uint256 previousLen = rootHelper.getQueueSize(user); - vm.selectFork(childId); - childHelper.withdrawETH(user, amount - currentBalance, gasAmt); - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(user, previousLen); - } - - rootHelper.depositETH(user, amount, gasAmt); - - vm.selectFork(original); - } - - function depositETHTo(uint256 userIndexSeed, uint256 recipientIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to root chain - vm.selectFork(rootId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - address recipient = users[bound(recipientIndexSeed, 0, users.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get current balance - uint256 currentBalance = user.balance; - - if (currentBalance < amount) { - // Fund difference - uint256 previousLen = rootHelper.getQueueSize(user); - vm.selectFork(childId); - childHelper.withdrawETH(user, amount - currentBalance, gasAmt); - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(user, previousLen); - } - - rootHelper.depositETHTo(user, recipient, amount, gasAmt); - - // If recipient is different, transfer back - if (user != recipient) { - vm.selectFork(childId); - address eth = childHelper.childBridge().childETHToken(); - vm.prank(recipient); - ChildERC20(eth).transfer(user, amount); - } - vm.selectFork(childId); - - vm.selectFork(original); - } - - function depositWETH(uint256 userIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to root chain - vm.selectFork(rootId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get current balance - uint256 currentBalance = user.balance; - - if (currentBalance < amount) { - // Fund difference - uint256 previousLen = rootHelper.getQueueSize(user); - vm.selectFork(childId); - childHelper.withdrawETH(user, amount - currentBalance, gasAmt); - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(user, previousLen); - } - - // Wrap ETH - address payable wETH = payable(rootHelper.rootBridge().rootWETHToken()); - vm.prank(user); - WETH(wETH).deposit{value: amount}(); - - rootHelper.depositWETH(user, amount, gasAmt); - - vm.selectFork(original); - } - - function depositWETHTo(uint256 userIndexSeed, uint256 recipientIndexSeed, uint256 amount, uint256 gasAmt) public { - uint256 original = vm.activeFork(); - - // Switch to root chain - vm.selectFork(rootId); - - // Bound - address user = users[bound(userIndexSeed, 0, users.length - 1)]; - address recipient = users[bound(recipientIndexSeed, 0, users.length - 1)]; - amount = bound(amount, 1, MAX_AMOUNT); - gasAmt = bound(gasAmt, 1, MAX_GAS); - - // Get current balance - uint256 currentBalance = user.balance; - - if (currentBalance < amount) { - // Fund difference - uint256 previousLen = rootHelper.getQueueSize(user); - vm.selectFork(childId); - childHelper.withdrawETH(user, amount - currentBalance, gasAmt); - vm.selectFork(rootId); - rootHelper.finaliseWithdrawal(user, previousLen); - } - - // Wrap ETH - address payable wETH = payable(rootHelper.rootBridge().rootWETHToken()); - vm.prank(user); - WETH(wETH).deposit{value: amount}(); - - rootHelper.depositWETHTo(user, recipient, amount, gasAmt); - - // If recipient is different, transfer back - if (user != recipient) { - vm.selectFork(childId); - address eth = childHelper.childBridge().childETHToken(); - vm.prank(recipient); - ChildERC20(eth).transfer(user, amount); - vm.selectFork(rootId); - } - - vm.selectFork(original); - } -} diff --git a/test/invariant/root/RootHelper.sol b/test/invariant/root/RootHelper.sol deleted file mode 100644 index 6f0521c7..00000000 --- a/test/invariant/root/RootHelper.sol +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: Apache 2.0 -pragma solidity 0.8.19; - -import {Test} from "forge-std/Test.sol"; -import {ChildERC20} from "../../../src/child/ChildERC20.sol"; -import {WIMX as WETH} from "../../../src/child/WIMX.sol"; -import {RootERC20BridgeFlowRate} from "../../../src/root/flowrate/RootERC20BridgeFlowRate.sol"; -import {IERC20Metadata} from "../../../src/root/RootERC20Bridge.sol"; - -contract RootHelper is Test { - address admin; - RootERC20BridgeFlowRate public rootBridge; - - uint256 public totalGas; - - constructor(address _admin, address payable _rootBridge) { - admin = _admin; - rootBridge = RootERC20BridgeFlowRate(_rootBridge); - } - - function deposit(address user, address rootToken, uint256 amount, uint256 gasAmt) public { - vm.prank(user); - ChildERC20(rootToken).approve(address(rootBridge), amount); - - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - rootBridge.deposit{value: gasAmt}(IERC20Metadata(rootToken), amount); - } - - function depositTo(address user, address recipient, address rootToken, uint256 amount, uint256 gasAmt) public { - vm.prank(user); - ChildERC20(rootToken).approve(address(rootBridge), amount); - - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - rootBridge.depositTo{value: gasAmt}(IERC20Metadata(rootToken), recipient, amount); - } - - function depositIMX(address user, uint256 amount, uint256 gasAmt) public { - address IMX = rootBridge.rootIMXToken(); - - vm.prank(user); - ChildERC20(IMX).approve(address(rootBridge), amount); - - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - rootBridge.deposit{value: gasAmt}(IERC20Metadata(IMX), amount); - } - - function depositIMXTo(address user, address recipient, uint256 amount, uint256 gasAmt) public { - address IMX = rootBridge.rootIMXToken(); - - vm.prank(user); - ChildERC20(IMX).approve(address(rootBridge), amount); - - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - rootBridge.depositTo{value: gasAmt}(IERC20Metadata(IMX), recipient, amount); - } - - function depositETH(address user, uint256 amount, uint256 gasAmt) public { - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - rootBridge.depositETH{value: gasAmt + amount}(amount); - } - - function depositETHTo(address user, address recipient, uint256 amount, uint256 gasAmt) public { - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - rootBridge.depositToETH{value: gasAmt + amount}(recipient, amount); - } - - function depositWETH(address user, uint256 amount, uint256 gasAmt) public { - address payable wETH = payable(rootBridge.rootWETHToken()); - - vm.prank(user); - WETH(wETH).approve(address(rootBridge), amount); - - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - rootBridge.deposit{value: gasAmt}(IERC20Metadata(wETH), amount); - } - - function depositWETHTo(address user, address recipient, uint256 amount, uint256 gasAmt) public { - address payable wETH = payable(rootBridge.rootWETHToken()); - - vm.prank(user); - WETH(wETH).approve(address(rootBridge), amount); - - vm.deal(user, gasAmt + user.balance); - totalGas += gasAmt; - - vm.prank(user); - rootBridge.depositTo{value: gasAmt}(IERC20Metadata(wETH), recipient, amount); - } - - function getQueueSize(address user) public view returns (uint256) { - return rootBridge.getPendingWithdrawalsLength(user); - } - - function finaliseWithdrawal(address user, uint256 previousLen) public { - // Check if this withdrawal has hit rate limit - if (rootBridge.getPendingWithdrawalsLength(user) > previousLen) { - skip(86401); - vm.prank(user); - rootBridge.finaliseQueuedWithdrawal(user, previousLen); - } - - if (rootBridge.withdrawalQueueActivated()) { - vm.prank(admin); - rootBridge.deactivateWithdrawalQueue(); - } - } -}