// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {Test, console} from "forge-std/Test.sol"; import "../../../contracts/bridge/trustless/BondManager.sol"; import "../../../contracts/bridge/trustless/ChallengeManager.sol"; import "../../../contracts/bridge/trustless/InboxETH.sol"; import "../../../contracts/bridge/trustless/LiquidityPoolETH.sol"; /** * @title GasBenchmarkTest * @notice Gas benchmarking for bridge operations */ contract GasBenchmarkTest is Test { BondManager public bondManager; ChallengeManager public challengeManager; InboxETH public inbox; LiquidityPoolETH public liquidityPool; address public constant WETH = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); address public relayer = address(0x1111); address public challenger = address(0x2222); address public recipient = address(0x3333); function setUp() public { bondManager = new BondManager(11000, 1 ether); challengeManager = new ChallengeManager(address(bondManager), 30 minutes); liquidityPool = new LiquidityPoolETH(WETH, 5, 11000); inbox = new InboxETH(address(bondManager), address(challengeManager), address(liquidityPool)); liquidityPool.authorizeRelease(address(inbox)); vm.deal(relayer, 100 ether); vm.deal(challenger, 100 ether); // Set initial timestamp to avoid cooldown issues with uninitialized lastClaimTime vm.warp(1000); } function test_GasBenchmark_SubmitClaim() public { uint256 gasBefore = gasleft(); vm.warp(block.timestamp + 1); // Advance time vm.prank(relayer); inbox.submitClaim{value: bondManager.getRequiredBond(1 ether)}( 5001, address(0), 1 ether, recipient, "" ); uint256 gasUsed = gasBefore - gasleft(); console.log("Gas used for submitClaim:", gasUsed); // Target: < 500k gas (adjusted for via-ir compilation) assertLt(gasUsed, 500000, "Gas should be reasonable"); } function test_GasBenchmark_ChallengeClaim() public { // Submit claim first vm.warp(block.timestamp + 1); // Advance time vm.prank(relayer); inbox.submitClaim{value: bondManager.getRequiredBond(1 ether)}( 5002, address(0), 1 ether, recipient, "" ); // Generate fraud proof (simplified - will be invalid) bytes memory proof = abi.encode("fraud_proof"); uint256 gasBefore = gasleft(); vm.prank(challenger); // Expect revert since proof is invalid vm.expectRevert(); // Expect revert (InvalidFraudProof) challengeManager.challengeClaim( 5002, ChallengeManager.FraudProofType.NonExistentDeposit, proof ); uint256 gasUsed = gasBefore - gasleft(); console.log("Gas used for challengeClaim (invalid proof):", gasUsed); // Target: < 300k gas even for invalid proof rejection assertLt(gasUsed, 300000, "Gas should be reasonable"); } function test_GasBenchmark_FinalizeClaim() public { // Submit claim vm.warp(block.timestamp + 1); // Advance time vm.prank(relayer); inbox.submitClaim{value: bondManager.getRequiredBond(1 ether)}( 5003, address(0), 1 ether, recipient, "" ); // Wait for challenge window vm.warp(block.timestamp + 30 minutes + 1); uint256 gasBefore = gasleft(); challengeManager.finalizeClaim(5003); uint256 gasUsed = gasBefore - gasleft(); console.log("Gas used for finalizeClaim:", gasUsed); // Target: < 80k gas assertLt(gasUsed, 100000, "Gas should be reasonable"); } function test_GasBenchmark_BatchFinalize() public { // Submit 5 claims - start at 1001 uint256 currentTime = 1001; for (uint256 i = 0; i < 5; i++) { vm.deal(relayer, 100 ether); // Advance time to respect cooldown (61 seconds between claims) vm.warp(currentTime); vm.prank(relayer); inbox.submitClaim{value: bondManager.getRequiredBond(1 ether)}( 6000 + i, address(0), 1 ether, recipient, "" ); currentTime += 61 seconds; } vm.warp(block.timestamp + 30 minutes + 1); uint256[] memory depositIds = new uint256[](5); for (uint256 i = 0; i < 5; i++) { depositIds[i] = 6000 + i; } uint256 gasBefore = gasleft(); challengeManager.finalizeClaimsBatch(depositIds); uint256 gasUsed = gasBefore - gasleft(); console.log("Gas used for batch finalize (5 claims):", gasUsed); console.log("Average gas per claim:", gasUsed / 5); // Batch should save gas vs individual calls assertLt(gasUsed, 500000, "Batch should be efficient"); } }