diff --git a/.gas-snapshot b/.gas-snapshot index 09eea30..2232958 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -3,6 +3,20 @@ OrderOriginPermit2Test:test_fillPermit2() (gas: 174723) OrderOriginPermit2Test:test_fillPermit2_multi() (gas: 510586) OrderOriginPermit2Test:test_initiatePermit2() (gas: 187081) OrderOriginPermit2Test:test_initiatePermit2_multi() (gas: 470943) +OrdersForkTest:test_fill_ERC20() (gas: 74581) +OrdersForkTest:test_fill_ETH() (gas: 71687) +OrdersForkTest:test_fill_both() (gas: 175984) +OrdersForkTest:test_fill_multiETH() (gas: 138365) +OrdersForkTest:test_fill_underflowETH() (gas: 118654) +OrdersForkTest:test_initiate_ERC20() (gas: 87520) +OrdersForkTest:test_initiate_ETH() (gas: 49955) +OrdersForkTest:test_initiate_both() (gas: 126223) +OrdersForkTest:test_initiate_multiERC20() (gas: 183468) +OrdersForkTest:test_initiate_multiETH() (gas: 82210) +OrdersForkTest:test_orderExpired() (gas: 30996) +OrdersForkTest:test_sweepERC20() (gas: 61825) +OrdersForkTest:test_sweepETH() (gas: 85828) +OrdersForkTest:test_underflowETH() (gas: 66905) OrdersTest:test_fill_ERC20() (gas: 76273) OrdersTest:test_fill_ETH() (gas: 73740) OrdersTest:test_fill_both() (gas: 179143) @@ -17,6 +31,19 @@ OrdersTest:test_orderExpired() (gas: 32846) OrdersTest:test_sweepERC20() (gas: 62965) OrdersTest:test_sweepETH() (gas: 89995) OrdersTest:test_underflowETH() (gas: 69404) +PassageForkTest:test_configureEnter() (gas: 141651) +PassageForkTest:test_disallowedEnter() (gas: 58928) +PassageForkTest:test_enter() (gas: 26523) +PassageForkTest:test_enterToken() (gas: 66880) +PassageForkTest:test_enterToken_defaultChain() (gas: 65384) +PassageForkTest:test_enter_defaultChain() (gas: 24949) +PassageForkTest:test_fallback() (gas: 22784) +PassageForkTest:test_onlyTokenAdmin() (gas: 19145) +PassageForkTest:test_receive() (gas: 22222) +PassageForkTest:test_setUp() (gas: 23289) +PassageForkTest:test_withdraw() (gas: 64486) +PassagePermit2ForkTest:test_disallowedEnterPermit2() (gas: 1133422) +PassagePermit2ForkTest:test_enterTokenPermit2() (gas: 150565) PassagePermit2Test:test_disallowedEnterPermit2() (gas: 1130187) PassagePermit2Test:test_enterTokenPermit2() (gas: 150794) PassageTest:test_configureEnter() (gas: 141651) @@ -30,11 +57,28 @@ PassageTest:test_onlyTokenAdmin() (gas: 19145) PassageTest:test_receive() (gas: 22222) PassageTest:test_setUp() (gas: 23289) PassageTest:test_withdraw() (gas: 64486) +Permit2OrdersForkTest:test_fillPermit2() (gas: 168424) +Permit2OrdersForkTest:test_fillPermit2_multi() (gas: 500785) +Permit2OrdersForkTest:test_initiatePermit2() (gas: 179960) +Permit2OrdersForkTest:test_initiatePermit2_multi() (gas: 465362) +RollupPassageForkTest:test_exit() (gas: 22860) +RollupPassageForkTest:test_exitToken() (gas: 53288) +RollupPassageForkTest:test_fallback() (gas: 20803) +RollupPassageForkTest:test_receive() (gas: 20286) +RollupPassagePermit2ForkTest:test_exitTokenPermit2() (gas: 131368) RollupPassagePermit2Test:test_exitTokenPermit2() (gas: 135717) RollupPassageTest:test_exit() (gas: 23114) RollupPassageTest:test_exitToken() (gas: 53266) RollupPassageTest:test_fallback() (gas: 20910) RollupPassageTest:test_receive() (gas: 20393) +TransactForkTest:test_configureGas() (gas: 27486) +TransactForkTest:test_enterTransact() (gas: 127464) +TransactForkTest:test_onlyGasAdmin() (gas: 9895) +TransactForkTest:test_setUp() (gas: 23757) +TransactForkTest:test_transact() (gas: 107567) +TransactForkTest:test_transact_defaultChain() (gas: 106574) +TransactForkTest:test_transact_globalGasLimit() (gas: 117828) +TransactForkTest:test_transact_perTransactGasLimit() (gas: 34574) TransactTest:test_configureGas() (gas: 27486) TransactTest:test_enterTransact() (gas: 127464) TransactTest:test_onlyGasAdmin() (gas: 9895) @@ -43,6 +87,15 @@ TransactTest:test_transact() (gas: 107567) TransactTest:test_transact_defaultChain() (gas: 106574) TransactTest:test_transact_globalGasLimit() (gas: 117828) TransactTest:test_transact_perTransactGasLimit() (gas: 34574) +ZenithForkTest:test_addSequencer() (gas: 81516) +ZenithForkTest:test_badSignature() (gas: 46355) +ZenithForkTest:test_incorrectHostBlock() (gas: 42276) +ZenithForkTest:test_notSequencer() (gas: 39566) +ZenithForkTest:test_notSequencerAdmin() (gas: 11279) +ZenithForkTest:test_onePerBlock() (gas: 61287) +ZenithForkTest:test_removeSequencer() (gas: 50114) +ZenithForkTest:test_setUp() (gas: 8035) +ZenithForkTest:test_submitBlock() (gas: 53334) ZenithTest:test_addSequencer() (gas: 98616) ZenithTest:test_badSignature() (gas: 46355) ZenithTest:test_incorrectHostBlock() (gas: 42276) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7ddf018..7aa136c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,9 +11,22 @@ permissions: checks: read contents: read repository-projects: read - + jobs: solidity-base: uses: init4tech/actions/.github/workflows/solidity-base.yml@main with: gas-diff-tolerance: 2 # setting the gas diff tolerance to 2% + fork-rollup: + uses: init4tech/actions/.github/workflows/solidity-base.yml@main + with: + gas-diff-tolerance: 2 # setting the gas diff tolerance to 2% + foundry-profile: rollup + fork-url: ${{ vars.RU_RPC_URL }} + fork-host: + uses: init4tech/actions/.github/workflows/solidity-base.yml@main + with: + gas-diff-tolerance: 2 # setting the gas diff tolerance to 2% + foundry-profile: host + fork-url: ${{ vars.HOST_RPC_URL }} + diff --git a/foundry.toml b/foundry.toml index 19d478a..99703aa 100644 --- a/foundry.toml +++ b/foundry.toml @@ -4,4 +4,10 @@ out = "out" libs = ["lib"] evm_version = "cancun" -# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options +[profile.rollup] +test= "test/rollup" + +[profile.host] +test= "test/host" + +# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options \ No newline at end of file diff --git a/test/Passage.t.sol b/test/host/Passage.t.sol similarity index 75% rename from test/Passage.t.sol rename to test/host/Passage.t.sol index 1687b0a..e986f63 100644 --- a/test/Passage.t.sol +++ b/test/host/Passage.t.sol @@ -2,15 +2,15 @@ pragma solidity 0.8.26; // test contracts -import {Passage} from "../src/passage/Passage.sol"; -import {RollupPassage} from "../src/passage/RollupPassage.sol"; +import {Passage} from "../../src/passage/Passage.sol"; +import {RollupPassage} from "../../src/passage/RollupPassage.sol"; // utils -import {TestERC20} from "./Helpers.t.sol"; +import {TestERC20} from "../Helpers.t.sol"; +import {SignetStdTest} from "../SignetStdTest.t.sol"; import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; import {ERC20Burnable} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import {Address} from "openzeppelin-contracts/contracts/utils/Address.sol"; import {Test, console2} from "forge-std/Test.sol"; -import {SignetStdTest} from "./SignetStdTest.t.sol"; import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; contract PassageTest is SignetStdTest { @@ -153,55 +153,3 @@ contract PassageTest is SignetStdTest { target.withdraw(token, recipient, amount); } } - -contract RollupPassageTest is SignetStdTest { - using Address for address payable; - - RollupPassage public target; - address token; - address recipient = address(0x123); - uint256 amount = 200; - - event Exit(address indexed hostRecipient, uint256 amount); - - event ExitToken(address indexed hostRecipient, address indexed token, uint256 amount); - - function setUp() public virtual { - // setup target - target = ROLLUP_PASSAGE; - - // setup token - token = address(ROLLUP_WETH); - vm.prank(ROLLUP_MINTER); - TestERC20(token).mint(address(this), amount * 10000); - TestERC20(token).approve(address(target), amount * 10000); - } - - function test_receive() public { - vm.expectEmit(); - emit Exit(address(this), amount); - payable(address(target)).sendValue(amount); - } - - function test_fallback() public { - vm.expectEmit(); - emit Exit(address(this), amount); - payable(address(target)).functionCallWithValue("0xabcd", amount); - } - - function test_exit() public { - vm.expectEmit(); - emit Exit(recipient, amount); - target.exit{value: amount}(recipient); - } - - function test_exitToken() public { - vm.expectEmit(); - emit ExitToken(recipient, token, amount); - vm.expectCall( - token, abi.encodeWithSelector(ERC20.transferFrom.selector, address(this), address(target), amount) - ); - vm.expectCall(token, abi.encodeWithSelector(ERC20Burnable.burn.selector, amount)); - target.exitToken(recipient, token, amount); - } -} diff --git a/test/Permit2Passage.t.sol b/test/host/Permit2Passage.t.sol similarity index 59% rename from test/Permit2Passage.t.sol rename to test/host/Permit2Passage.t.sol index 8af9bdd..89a6951 100644 --- a/test/Permit2Passage.t.sol +++ b/test/host/Permit2Passage.t.sol @@ -2,11 +2,11 @@ pragma solidity 0.8.26; // test contracts -import {Passage} from "../src/passage/Passage.sol"; -import {RollupPassage} from "../src/passage/RollupPassage.sol"; -import {UsesPermit2} from "../src/UsesPermit2.sol"; +import {Passage} from "../../src/passage/Passage.sol"; +import {RollupPassage} from "../../src/passage/RollupPassage.sol"; +import {UsesPermit2} from "../../src/UsesPermit2.sol"; // utils -import {Permit2Helpers, ISinglePermit, TestERC20} from "./Helpers.t.sol"; +import {Permit2Helpers, ISinglePermit, TestERC20} from "../Helpers.t.sol"; import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol"; import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; import {ERC20Burnable} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol"; @@ -98,65 +98,3 @@ contract PassagePermit2Test is Permit2Helpers { target.enterTokenPermit2(ROLLUP_CHAIN_ID, recipient, singlePermit); } } - -contract RollupPassagePermit2Test is Permit2Helpers { - RollupPassage public target; - - // token consts - address token; - uint256 amount = 200; - address recipient = address(0x123); - - event ExitToken(address indexed hostRecipient, address indexed token, uint256 amount); - - function setUp() public virtual { - // setup RollupPassage - target = ROLLUP_PASSAGE; - vm.label(address(target), "rollup_passage"); - vm.label(address(PERMIT2), "permit2"); - vm.label(owner, "owner"); - - // setup token - token = address(ROLLUP_WBTC); - // mint tokens to owner - vm.prank(ROLLUP_MINTER); - TestERC20(token).mint(owner, amount * 10000); - // approve permit2 from owner - vm.prank(owner); - TestERC20(token).approve(address(PERMIT2), amount * 10000); - - // set basic permit details - singlePermit.permit.nonce = 0; - singlePermit.permit.deadline = block.timestamp; - singlePermit.owner = owner; - singlePermit.permit.permitted = ISignatureTransfer.TokenPermissions({token: token, amount: amount}); - singleTransferDetails = - ISignatureTransfer.SignatureTransferDetails({to: address(target), requestedAmount: amount}); - - // construct Exit witness - witness = target.exitWitness(recipient); - - // sign permit + witness - singlePermit.signature = signPermit(ownerKey, address(target), singlePermit.permit, witness); - } - - function test_exitTokenPermit2() public { - vm.expectEmit(); - emit ExitToken(recipient, token, amount); - vm.expectCall( - address(PERMIT2), - abi.encodeWithSelector( - ISinglePermit.permitWitnessTransferFrom.selector, - singlePermit.permit, - singleTransferDetails, - owner, - witness.witnessHash, - witness.witnessTypeString, - singlePermit.signature - ) - ); - vm.expectCall(token, abi.encodeWithSelector(ERC20.transferFrom.selector, owner, address(target), amount)); - vm.expectCall(token, abi.encodeWithSelector(ERC20Burnable.burn.selector, amount)); - target.exitTokenPermit2(recipient, singlePermit); - } -} diff --git a/test/Transactor.t.sol b/test/host/Transactor.t.sol similarity index 96% rename from test/Transactor.t.sol rename to test/host/Transactor.t.sol index 5d6e3aa..324c61e 100644 --- a/test/Transactor.t.sol +++ b/test/host/Transactor.t.sol @@ -2,10 +2,10 @@ pragma solidity 0.8.26; // test contracts -import {Transactor} from "../src/Transactor.sol"; -import {Passage} from "../src/passage/Passage.sol"; +import {Transactor} from "../../src/Transactor.sol"; +import {Passage} from "../../src/passage/Passage.sol"; // utils -import {SignetStdTest} from "./SignetStdTest.t.sol"; +import {SignetStdTest} from "../SignetStdTest.t.sol"; import {Test, console2} from "forge-std/Test.sol"; contract TransactTest is SignetStdTest { diff --git a/test/Zenith.t.sol b/test/host/Zenith.t.sol similarity index 95% rename from test/Zenith.t.sol rename to test/host/Zenith.t.sol index 50392a0..5eefef7 100644 --- a/test/Zenith.t.sol +++ b/test/host/Zenith.t.sol @@ -2,9 +2,9 @@ pragma solidity 0.8.26; // test contracts -import {Zenith} from "../src/Zenith.sol"; +import {Zenith} from "../../src/Zenith.sol"; // utils -import {SignetStdTest} from "./SignetStdTest.t.sol"; +import {SignetStdTest} from "../SignetStdTest.t.sol"; import {Test, console2} from "forge-std/Test.sol"; contract ZenithTest is SignetStdTest { @@ -35,6 +35,10 @@ contract ZenithTest is SignetStdTest { vm.prank(SEQUENCER_ADMIN); target.addSequencer(vm.addr(sequencerKey)); + // advance to next block number to avoid the possibility during fork testing + // that a rollup block was already submitted in the current block + vm.roll(block.number + 1); + // set default block values header.rollupChainId = ROLLUP_CHAIN_ID; header.hostBlockNumber = block.number; diff --git a/test/Orders.t.sol b/test/rollup/Orders.t.sol similarity index 96% rename from test/Orders.t.sol rename to test/rollup/Orders.t.sol index 51c599d..df10eb0 100644 --- a/test/Orders.t.sol +++ b/test/rollup/Orders.t.sol @@ -2,14 +2,14 @@ pragma solidity 0.8.26; // test contracts -import {IOrders} from "../src/orders/IOrders.sol"; -import {RollupOrders} from "../src/orders/RollupOrders.sol"; -import {OrderOrigin} from "../src/orders/OrderOrigin.sol"; +import {IOrders} from "../../src/orders/IOrders.sol"; +import {RollupOrders} from "../../src/orders/RollupOrders.sol"; +import {OrderOrigin} from "../../src/orders/OrderOrigin.sol"; // utils -import {TestERC20} from "./Helpers.t.sol"; +import {TestERC20} from "../Helpers.t.sol"; +import {SignetStdTest} from "../SignetStdTest.t.sol"; import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; import {Test, console2} from "forge-std/Test.sol"; -import {SignetStdTest} from "./SignetStdTest.t.sol"; contract OrdersTest is SignetStdTest { RollupOrders public target; diff --git a/test/Permit2Orders.t.sol b/test/rollup/Permit2Orders.t.sol similarity index 96% rename from test/Permit2Orders.t.sol rename to test/rollup/Permit2Orders.t.sol index 5b65fab..a55643e 100644 --- a/test/Permit2Orders.t.sol +++ b/test/rollup/Permit2Orders.t.sol @@ -2,15 +2,15 @@ pragma solidity 0.8.26; // test contracts -import {RollupOrders} from "../src/orders/RollupOrders.sol"; -import {IOrders} from "../src/orders/IOrders.sol"; -import {UsesPermit2} from "../src/UsesPermit2.sol"; +import {RollupOrders} from "../../src/orders/RollupOrders.sol"; +import {IOrders} from "../../src/orders/IOrders.sol"; +import {UsesPermit2} from "../../src/UsesPermit2.sol"; // utils -import {Permit2Helpers, IBatchPermit, TestERC20} from "./Helpers.t.sol"; +import {Permit2Helpers, IBatchPermit, TestERC20} from "../Helpers.t.sol"; import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol"; import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; -import {Test, console2} from "forge-std/Test.sol"; import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; +import {Test, console2} from "forge-std/Test.sol"; contract OrderOriginPermit2Test is Permit2Helpers { RollupOrders public target; diff --git a/test/rollup/RollupPassage.t.sol b/test/rollup/RollupPassage.t.sol new file mode 100644 index 0000000..f845a78 --- /dev/null +++ b/test/rollup/RollupPassage.t.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity 0.8.26; + +// test contracts +import {Passage} from "../../src/passage/Passage.sol"; +import {RollupPassage} from "../../src/passage/RollupPassage.sol"; +// utils +import {TestERC20} from "../Helpers.t.sol"; +import {SignetStdTest} from "../SignetStdTest.t.sol"; +import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; +import {ERC20Burnable} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import {Address} from "openzeppelin-contracts/contracts/utils/Address.sol"; +import {Test, console2} from "forge-std/Test.sol"; +import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; + +contract RollupPassageTest is SignetStdTest { + using Address for address payable; + + RollupPassage public target; + address token; + address recipient = address(0x123); + uint256 amount = 200; + + event Exit(address indexed hostRecipient, uint256 amount); + + event ExitToken(address indexed hostRecipient, address indexed token, uint256 amount); + + function setUp() public virtual { + // setup target + target = ROLLUP_PASSAGE; + + // setup token + token = address(ROLLUP_WETH); + vm.prank(ROLLUP_MINTER); + TestERC20(token).mint(address(this), amount * 10000); + TestERC20(token).approve(address(target), amount * 10000); + } + + function test_receive() public { + vm.expectEmit(); + emit Exit(address(this), amount); + payable(address(target)).sendValue(amount); + } + + function test_fallback() public { + vm.expectEmit(); + emit Exit(address(this), amount); + payable(address(target)).functionCallWithValue("0xabcd", amount); + } + + function test_exit() public { + vm.expectEmit(); + emit Exit(recipient, amount); + target.exit{value: amount}(recipient); + } + + function test_exitToken() public { + vm.expectEmit(); + emit ExitToken(recipient, token, amount); + vm.expectCall( + token, abi.encodeWithSelector(ERC20.transferFrom.selector, address(this), address(target), amount) + ); + vm.expectCall(token, abi.encodeWithSelector(ERC20Burnable.burn.selector, amount)); + target.exitToken(recipient, token, amount); + } +} diff --git a/test/rollup/RollupPassagePermit2Test.t.sol b/test/rollup/RollupPassagePermit2Test.t.sol new file mode 100644 index 0000000..f6f8af0 --- /dev/null +++ b/test/rollup/RollupPassagePermit2Test.t.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity 0.8.26; + +// test contracts +import {Passage} from "../../src/passage/Passage.sol"; +import {RollupPassage} from "../../src/passage/RollupPassage.sol"; +import {UsesPermit2} from "../../src/UsesPermit2.sol"; +// utils +import {Permit2Helpers, ISinglePermit, TestERC20} from "../Helpers.t.sol"; +import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol"; +import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; +import {ERC20Burnable} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import {Test, console2} from "forge-std/Test.sol"; +import {Address} from "openzeppelin-contracts/contracts/utils/Address.sol"; + +contract RollupPassagePermit2Test is Permit2Helpers { + RollupPassage public target; + + // token consts + address token; + uint256 amount = 200; + address recipient = address(0x123); + + event ExitToken(address indexed hostRecipient, address indexed token, uint256 amount); + + function setUp() public virtual { + // setup RollupPassage + target = ROLLUP_PASSAGE; + vm.label(address(target), "rollup_passage"); + vm.label(address(PERMIT2), "permit2"); + vm.label(owner, "owner"); + + // setup token + token = address(ROLLUP_WBTC); + // mint tokens to owner + vm.prank(ROLLUP_MINTER); + TestERC20(token).mint(owner, amount * 10000); + // approve permit2 from owner + vm.prank(owner); + TestERC20(token).approve(address(PERMIT2), amount * 10000); + + // set basic permit details + singlePermit.permit.nonce = 0; + singlePermit.permit.deadline = block.timestamp; + singlePermit.owner = owner; + singlePermit.permit.permitted = ISignatureTransfer.TokenPermissions({token: token, amount: amount}); + singleTransferDetails = + ISignatureTransfer.SignatureTransferDetails({to: address(target), requestedAmount: amount}); + + // construct Exit witness + witness = target.exitWitness(recipient); + + // sign permit + witness + singlePermit.signature = signPermit(ownerKey, address(target), singlePermit.permit, witness); + } + + function test_exitTokenPermit2() public { + vm.expectEmit(); + emit ExitToken(recipient, token, amount); + vm.expectCall( + address(PERMIT2), + abi.encodeWithSelector( + ISinglePermit.permitWitnessTransferFrom.selector, + singlePermit.permit, + singleTransferDetails, + owner, + witness.witnessHash, + witness.witnessTypeString, + singlePermit.signature + ) + ); + vm.expectCall(token, abi.encodeWithSelector(ERC20.transferFrom.selector, owner, address(target), amount)); + vm.expectCall(token, abi.encodeWithSelector(ERC20Burnable.burn.selector, amount)); + target.exitTokenPermit2(recipient, singlePermit); + } +}