From d431c28864fcff3eabeb8abd1db399acbc153ca0 Mon Sep 17 00:00:00 2001 From: qedk <1994constant@gmail.com> Date: Sun, 14 Jan 2024 03:49:21 +0400 Subject: [PATCH] feat: add full test coverage --- foundry.toml | 2 +- script/Deploy.s.sol | 2 +- script/GetProofMockScript.s.sol | 2 +- src/AvailBridge.sol | 26 +++++++++++++---- test/AvailBridgeTest.t.sol | 51 ++++++++++++++++++++++++++++++--- 5 files changed, 70 insertions(+), 13 deletions(-) diff --git a/foundry.toml b/foundry.toml index 9b47d90..4a4d4ac 100644 --- a/foundry.toml +++ b/foundry.toml @@ -7,8 +7,8 @@ optimizer_runs = 999999 via_ir = true [profile.intense.fuzz] -runs = 10000 max_test_rejects = 999999 +runs = 10000 [rpc_endpoints] sepolia = "https://ethereum-sepolia.publicnode.com" diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index c4e59a6..3ef810c 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -19,7 +19,7 @@ contract GetProofMockScript is Script { AvailBridge bridge = AvailBridge(address(new TransparentUpgradeableProxy(impl, address(proxyAdmin), ""))); WrappedAvail avail = new WrappedAvail(address(bridge)); bridge.initialize( - IWrappedAvail(address(avail)), admin, admin, IVectorx(0x5ac10644a873AAcd288775A90d6D0303496A4304) + 1000000000000, IWrappedAvail(address(avail)), admin, admin, IVectorx(0x5ac10644a873AAcd288775A90d6D0303496A4304) ); vm.stopBroadcast(); } diff --git a/script/GetProofMockScript.s.sol b/script/GetProofMockScript.s.sol index 120f41d..bd52aa7 100644 --- a/script/GetProofMockScript.s.sol +++ b/script/GetProofMockScript.s.sol @@ -18,7 +18,7 @@ contract GetProofMockScript is Script { address impl = address(new AvailBridge()); AvailBridge bridge = AvailBridge(address(new TransparentUpgradeableProxy(impl, address(admin), ""))); ERC20Mock avail = new ERC20Mock(); - bridge.initialize(IWrappedAvail(address(avail)), msg.sender, msg.sender, IVectorx(vectorx)); + bridge.initialize(1000000000000, IWrappedAvail(address(avail)), msg.sender, msg.sender, IVectorx(vectorx)); avail.mint(msg.sender, 1 ether); bridge.sendAVL(bytes32(uint256(1)), 1 ether); vm.stopBroadcast(); diff --git a/src/AvailBridge.sol b/src/AvailBridge.sol index fcbf8ee..1fec001 100644 --- a/src/AvailBridge.sol +++ b/src/AvailBridge.sol @@ -77,7 +77,7 @@ contract AvailBridge is IVectorx public vectorx; IWrappedAvail public avail; uint256 public messageId; - uint256 public feePerByte = 10000000000000; + uint256 public feePerByte; // map store spent message hashes, used for Avail -> Ethereum messages mapping(bytes32 => bool) public isBridged; @@ -95,7 +95,7 @@ contract AvailBridge is error BridgeRootEmpty(); error DataRootCommitmentEmpty(); error ExceedsMaxDataLength(); - error FeeOutsideRange(); + error FeeTooLow(); error InvalidAssetId(); error InvalidDataRootProof(); error InvalidDomain(); @@ -134,10 +134,11 @@ contract AvailBridge is * @param pauser Address of the pauser multisig * @param newVectorx Address of the VectorX contract */ - function initialize(IWrappedAvail newAvail, address governance, address pauser, IVectorx newVectorx) + function initialize(uint256 newFeePerByte, IWrappedAvail newAvail, address governance, address pauser, IVectorx newVectorx) external initializer { + feePerByte = newFeePerByte; vectorx = newVectorx; avail = newAvail; __AccessControlDefaultAdminRules_init(0, governance); @@ -187,6 +188,15 @@ contract AvailBridge is } } + /** + * @notice Function to update the fee per byte value + * @dev Only callable by governance + * @param newFeePerByte New fee per byte value + */ + function updateFeePerByte(uint256 newFeePerByte) external onlyRole(DEFAULT_ADMIN_ROLE) { + feePerByte = newFeePerByte; + } + /** * @notice Takes an arbitrary message and its proof of inclusion, verifies and executes it (if valid) * @dev This function is used for passing arbitrary data from Avail to Ethereum @@ -311,9 +321,9 @@ contract AvailBridge is if (length >= MAX_DATA_LENGTH) { revert ExceedsMaxDataLength(); } - // ensure that fee is within range - if (msg.value < (length * feePerByte) || msg.value > (4 * length * feePerByte)) { - revert FeeOutsideRange(); + // ensure that fee is above minimum amount + if (msg.value < getFee(length)) { + revert FeeTooLow(); } uint256 id; unchecked { @@ -456,6 +466,10 @@ contract AvailBridge is return input.leafProof.verify(input.bridgeRoot, input.leafIndex, input.leaf); } + function getFee(uint256 length) public view returns (uint256) { + return length * feePerByte; + } + /** * @notice Takes a message and its proof of inclusion, verifies and marks it as spent (if valid) * @dev This function is used for verifying a message and marking it as spent (if valid) diff --git a/test/AvailBridgeTest.t.sol b/test/AvailBridgeTest.t.sol index 1f752fd..fc493e4 100644 --- a/test/AvailBridgeTest.t.sol +++ b/test/AvailBridgeTest.t.sol @@ -11,7 +11,7 @@ import {VectorxMock, IVectorx} from "src/mocks/VectorxMock.sol"; import {ERC20Mock} from "src/mocks/ERC20Mock.sol"; import {MessageReceiverMock} from "src/mocks/MessageReceiverMock.sol"; import {MurkyBase} from "lib/murky/src/common/MurkyBase.sol"; -import {Vm, Test} from "forge-std/Test.sol"; +import {Vm, Test, console} from "forge-std/Test.sol"; contract AvailBridgeTest is Test, MurkyBase { AvailBridge public bridge; @@ -29,13 +29,19 @@ contract AvailBridgeTest is Test, MurkyBase { address impl = address(new AvailBridge()); bridge = AvailBridge(address(new TransparentUpgradeableProxy(impl, address(admin), ""))); avail = new WrappedAvail(address(bridge)); - bridge.initialize(IWrappedAvail(address(avail)), msg.sender, pauser, IVectorx(vectorx)); + bridge.initialize(1000000000000, IWrappedAvail(address(avail)), msg.sender, pauser, IVectorx(vectorx)); owner = msg.sender; } function test_owner() external { - assertEq(bridge.owner() != address(0), true); - assertEq(bridge.owner() == owner, true); + assertNotEq(bridge.owner(), address(0)); + assertEq(bridge.owner(), owner); + } + + function test_setFeePerByte(uint256 feePerByte) external { + vm.prank(owner); + bridge.updateFeePerByte(feePerByte); + assertEq(bridge.feePerByte(), feePerByte); } function test_updateVectorx(IVectorx newVectorx) external { @@ -408,6 +414,43 @@ contract AvailBridgeTest is Test, MurkyBase { assertEq(newBalance, balance + amount); } + function testRevertExceedsMaxDataLength_sendMessage(bytes32 to, bytes[102_400] calldata c_data, uint256 amount) external { + bytes memory data = new bytes(c_data.length); + for (uint256 i = 0; i < c_data.length;) { + data[i] = bytes1(c_data[i]); + unchecked { + ++i; + } + } + address from = makeAddr("from"); + vm.prank(from); + vm.deal(from, amount); + vm.expectRevert(AvailBridge.ExceedsMaxDataLength.selector); + bridge.sendMessage{value: amount}(to, data); + assertEq(bridge.isSent(0), 0x0); + } + + function testRevertFeeTooLow_sendMessage(bytes32 to, bytes calldata data, uint256 amount) external { + vm.assume(data.length < 102_400 && amount < bridge.getFee(data.length)); + address from = makeAddr("from"); + vm.prank(from); + vm.deal(from, amount); + vm.expectRevert(AvailBridge.FeeTooLow.selector); + bridge.sendMessage{value: amount}(to, data); + assertEq(bridge.isSent(0), 0x0); + } + + function test_sendMessage(bytes32 to, bytes calldata data, uint256 amount) external { + vm.assume(data.length < 102_400 && amount >= 100000000000 * data.length); + address from = makeAddr("from"); + AvailBridge.Message memory message = + AvailBridge.Message(0x01, bytes32(bytes20(from)), to, 2, 1, data, 0); + vm.prank(from); + vm.deal(from, amount); + bridge.sendMessage{value: amount}(to, data); + assertEq(bridge.isSent(0), keccak256(abi.encode(message))); + } + function test_sendAVL(bytes32 to, uint256 amount) external { vm.assume(to != bytes32(0) && amount != 0); address from = makeAddr("from");