diff --git a/testdata/default/cheats/AccessList.t.sol b/testdata/default/cheats/AccessList.t.sol index f59e8cdb439c3..d1449a3a06cbf 100644 --- a/testdata/default/cheats/AccessList.t.sol +++ b/testdata/default/cheats/AccessList.t.sol @@ -11,7 +11,7 @@ contract AccessListIsolatedTest is Test { uint256 initial = gasleft(); write.setNumber(1); - assertEq(initial - gasleft(), 26762); + assertEq(initial - gasleft(), 32762); // set access list to anotherWrite address, hence becoming more expensive Vm.AccessListItem[] memory accessList = new Vm.AccessListItem[](1); @@ -21,26 +21,26 @@ contract AccessListIsolatedTest is Test { uint256 initial1 = gasleft(); write.setNumber(2); - assertEq(initial1 - gasleft(), 29162); + assertEq(initial1 - gasleft(), 35162); uint256 initial2 = gasleft(); write.setNumber(3); - assertEq(initial2 - gasleft(), 29162); + assertEq(initial2 - gasleft(), 35162); // reset access list, should take same gas as before setting vm.noAccessList(); uint256 initial4 = gasleft(); write.setNumber(4); - assertEq(initial4 - gasleft(), 26762); + assertEq(initial4 - gasleft(), 32762); uint256 initial5 = gasleft(); write.setNumber(5); - assertEq(initial5 - gasleft(), 26762); + assertEq(initial5 - gasleft(), 32762); vm.accessList(accessList); uint256 initial6 = gasleft(); write.setNumber(6); - assertEq(initial6 - gasleft(), 29162); + assertEq(initial6 - gasleft(), 35162); } } diff --git a/testdata/default/repros/Issue4232.t.sol b/testdata/default/repros/Issue4232.t.sol deleted file mode 100644 index 44f038bfbf28e..0000000000000 --- a/testdata/default/repros/Issue4232.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity ^0.8.18; - -import "utils/Test.sol"; - -// https://github.com/foundry-rs/foundry/issues/4232 -contract Issue4232Test is Test { - function testFork() public { - // Smoke test, worked previously as well - vm.createSelectFork("sepolia", 7215400); - vm.assertFalse(block.prevrandao == 0); - - // Would previously fail with: - // [FAIL: backend: failed while inspecting; header validation error: `prevrandao` not set; `prevrandao` not set; ] setUp() (gas: 0) - // - // Related fix: - // Moonbeam | Moonbase | Moonriver | MoonbeamDev => { - // if env.block.prevrandao.is_none() { - // // - // env.block.prevrandao = Some(B256::random()); - // } - // } - // - // Note: public RPC node used for `moonbeam` discards state quickly so we need to fork against the latest block - vm.createSelectFork("moonbeam"); - vm.assertFalse(block.prevrandao == 0); - } -} diff --git a/testdata/default/repros/Issue4640.t.sol b/testdata/default/repros/Issue4640.t.sol deleted file mode 100644 index 5c445d22b3516..0000000000000 --- a/testdata/default/repros/Issue4640.t.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity ^0.8.18; - -import "utils/Test.sol"; - -// https://github.com/foundry-rs/foundry/issues/4640 -contract Issue4640Test is Test { - function testArbitrumBlockNumber() public { - // - vm.createSelectFork("arbitrum", 394276729); - // L1 block number - assertEq(block.number, 23675778); - } -} diff --git a/testdata/foundry.toml b/testdata/foundry.toml index 0fd8135bbcd22..97978077130e5 100644 --- a/testdata/foundry.toml +++ b/testdata/foundry.toml @@ -58,3 +58,4 @@ bsc = "${RPC_BSC}" avaxTestnet = "https://api.avax-test.network/ext/bc/C/rpc" moonbeam = "https://moonbeam-rpc.publicnode.com" rpcEnvAlias = "${RPC_ENV_ALIAS}" +monad = "https://rpc2.monad.xyz" diff --git a/testdata/paris/cheats/LastCallGas.t.sol b/testdata/paris/cheats/LastCallGas.t.sol index 8c2c20ee8c41e..98823867b43e2 100644 --- a/testdata/paris/cheats/LastCallGas.t.sol +++ b/testdata/paris/cheats/LastCallGas.t.sol @@ -82,7 +82,7 @@ contract LastCallGasIsolatedTest is LastCallGasFixture { function testRecordGasRefund() public { _setup(); _performRefund(); - _assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 21380, gasMemoryUsed: 0, gasRefunded: 4800})); + _assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 27380, gasMemoryUsed: 0, gasRefunded: 4800})); } } diff --git a/testdata/paris/core/BeforeTest.t.sol b/testdata/paris/core/BeforeTest.t.sol index 10acfb53ee88f..7eaf185d11a1d 100644 --- a/testdata/paris/core/BeforeTest.t.sol +++ b/testdata/paris/core/BeforeTest.t.sol @@ -3,28 +3,12 @@ pragma solidity ^0.8.18; import "utils/Test.sol"; -contract SelfDestructor { - function kill() external { - selfdestruct(payable(msg.sender)); - } -} - // https://github.com/foundry-rs/foundry/issues/1543 contract BeforeTestSelfDestructTest is Test { - SelfDestructor killer; uint256 a; uint256 b; - function setUp() public { - killer = new SelfDestructor(); - } - function beforeTestSetup(bytes4 testSelector) public pure returns (bytes[] memory beforeTestCalldata) { - if (testSelector == this.testKill.selector) { - beforeTestCalldata = new bytes[](1); - beforeTestCalldata[0] = abi.encodePacked(this.kill_contract.selector); - } - if (testSelector == this.testA.selector) { beforeTestCalldata = new bytes[](3); beforeTestCalldata[0] = abi.encodePacked(this.testA.selector); @@ -44,27 +28,6 @@ contract BeforeTestSelfDestructTest is Test { } } - function kill_contract() external { - uint256 killer_size = getSize(address(killer)); - assertEq(killer_size, 106); - killer.kill(); - assertEq(killer_size, 106); - } - - /// forge-config: default.evm_version = "paris" - function testKill() public { - uint256 killer_size = getSize(address(killer)); - assertEq(killer_size, 0); - } - - function getSize(address c) internal view returns (uint32) { - uint32 size; - assembly { - size := extcodesize(c) - } - return size; - } - function testA() public { assertLe(a, 3); a += 1; diff --git a/testdata/paris/fork/Transact.t.sol b/testdata/paris/fork/Transact.t.sol index 6f7ca7f03a282..3877735688eed 100644 --- a/testdata/paris/fork/Transact.t.sol +++ b/testdata/paris/fork/Transact.t.sol @@ -4,96 +4,82 @@ pragma solidity ^0.8.18; import "utils/Test.sol"; interface IERC20 { - function transfer(address to, uint256 amount) external returns (bool); - + event Transfer(address indexed from, address indexed to, uint256 value); function balanceOf(address account) external view returns (uint256); } -contract TransactOnForkTest is Test { - IERC20 constant USDT = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); - - event Transfer(address indexed from, address indexed to, uint256 value); - +contract TransactTest is Test { + // Monad mainnet USDC + address constant USDC = 0x754704Bc059F8C67012fEd69BC8A327a5aafb603; + // Sender of the USDC transfer + address constant SENDER = 0x65b1683fA503005EeF709613566F02cE8A621c26; + // Recipient of the USDC transfer + address constant RECIPIENT = 0x240c0AE518EAA5667670d79560F16Fe4D9949d52; + // Transfer amount: 400 USDC (6 decimals) + uint256 constant AMOUNT = 400000000; + // Balances at block 38118706 (before the transfer) + uint256 constant SENDER_BALANCE_BEFORE = 550671950; + uint256 constant RECIPIENT_BALANCE_BEFORE = 0; + + /// forge-config: default.rpc_storage_caching.chains = ["monad"] function testTransact() public { - // A random block https://etherscan.io/block/17134913 - uint256 fork = vm.createFork("mainnet", 17134913); - vm.selectFork(fork); - // a random transfer transaction in the next block: https://etherscan.io/tx/0xaf6201d435b216a858c580e20512a16136916d894aa33260650e164e3238c771 - bytes32 transaction = 0xaf6201d435b216a858c580e20512a16136916d894aa33260650e164e3238c771; + // Fork at block 38118706 + vm.createSelectFork("monad", 38118706); - address sender = address(0x9B315A70FEe05a70A9F2c832E93a7095FEb32Bfe); - address recipient = address(0xDB358B93157Df9b3B1eE9Ea5CDB7D0aE9a1D8110); + // Verify balances before transact + assertEq(IERC20(USDC).balanceOf(SENDER), SENDER_BALANCE_BEFORE); + assertEq(IERC20(USDC).balanceOf(RECIPIENT), RECIPIENT_BALANCE_BEFORE); - assertEq(sender.balance, 110231651357268209); - assertEq(recipient.balance, 892860016357511); + // Replay the USDC transfer transaction from block 38118707 + // tx: 0x62068873ff1d3681a117c13563584226126bccc22c4d1f47fc4367d475d9e824 + vm.transact(0x62068873ff1d3681a117c13563884226126bccc22c4d1f47fc4367d475d9e824); - // transfer amount: 0.015 Ether - uint256 transferAmount = 15000000000000000; - uint256 expectedRecipientBalance = recipient.balance + transferAmount; - uint256 expectedSenderBalance = sender.balance - transferAmount; - - // execute the transaction - vm.transact(transaction); - - // recipient received transfer - assertEq(recipient.balance, expectedRecipientBalance); - - // decreased by transferAmount and gas - assert(sender.balance < expectedSenderBalance); + // Verify balances after transact + assertEq(IERC20(USDC).balanceOf(SENDER), SENDER_BALANCE_BEFORE - AMOUNT); + assertEq(IERC20(USDC).balanceOf(RECIPIENT), RECIPIENT_BALANCE_BEFORE + AMOUNT); } + /// forge-config: default.rpc_storage_caching.chains = ["monad"] function testTransactCooperatesWithCheatcodes() public { - // A random block https://etherscan.io/block/16260609 - uint256 fork = vm.createFork("mainnet", 16260609); - vm.selectFork(fork); - - // a random ERC20 USDT transfer transaction in the next block: https://etherscan.io/tx/0x33350512fec589e635865cbdb38fa3a20a2aa160c52611f1783d0ba24ad13c8c - bytes32 transaction = 0x33350512fec589e635865cbdb38fa3a20a2aa160c52611f1783d0ba24ad13c8c; + // Fork at block 38118706 + vm.createSelectFork("monad", 38118706); - address sender = address(0x2e09BB78B3D64d98Da44D1C776fa77dcd133ED54); - address recipient = address(0x23a6B9711B711b1d404F2AA740bde350c67a6F06); + // Verify balances before transact + assertEq(IERC20(USDC).balanceOf(SENDER), SENDER_BALANCE_BEFORE); + assertEq(IERC20(USDC).balanceOf(RECIPIENT), RECIPIENT_BALANCE_BEFORE); - uint256 senderBalance = USDT.balanceOf(sender); - uint256 recipientBalance = USDT.balanceOf(recipient); + // Expect the Transfer event + vm.expectEmit(true, true, false, true, USDC); + emit IERC20.Transfer(SENDER, RECIPIENT, AMOUNT); - assertEq(senderBalance, 20041000000); - assertEq(recipientBalance, 66000000); - - // transfer amount: 14000 USDT - uint256 transferAmount = 14000000000; - uint256 expectedRecipientBalance = recipientBalance + transferAmount; - uint256 expectedSenderBalance = senderBalance - transferAmount; - - // expect a call to USDT's transfer - // With the current expect call behavior, in which we expect calls to be matched in the next call's subcalls, - // expecting calls on vm.transact is impossible. This is because transact essentially creates another call context - // that operates independently of the current one, meaning that depths won't match and will trigger a panic on REVM, - // as the transact storage is not persisted as well and can't be checked. - // vm.expectCall(address(USDT), abi.encodeWithSelector(IERC20.transfer.selector, recipient, transferAmount)); - - // expect a Transfer event to be emitted - vm.expectEmit(true, true, false, true, address(USDT)); - emit Transfer(address(sender), address(recipient), transferAmount); - - // start recording logs + // Start recording logs vm.recordLogs(); - // execute the transaction - vm.transact(transaction); + // Replay the USDC transfer transaction + vm.transact(0x62068873ff1d3681a117c13563884226126bccc22c4d1f47fc4367d475d9e824); - // extract recorded logs + // Verify the recorded logs contain the Transfer event Vm.Log[] memory logs = vm.getRecordedLogs(); - - senderBalance = USDT.balanceOf(sender); - recipientBalance = USDT.balanceOf(recipient); - - // recipient received transfer - assertEq(recipientBalance, expectedRecipientBalance); - - // decreased by transferAmount - assertEq(senderBalance, expectedSenderBalance); - - // recorded a `Transfer` log - assertEq(logs.length, 1); + assertGt(logs.length, 0); + + // Find the Transfer event in logs + bool foundTransfer = false; + bytes32 transferTopic = keccak256("Transfer(address,address,uint256)"); + for (uint256 i = 0; i < logs.length; i++) { + if (logs[i].topics[0] == transferTopic && logs[i].emitter == USDC) { + foundTransfer = true; + // Verify indexed parameters (from, to) + assertEq(address(uint160(uint256(logs[i].topics[1]))), SENDER); + assertEq(address(uint160(uint256(logs[i].topics[2]))), RECIPIENT); + // Verify amount from data + assertEq(abi.decode(logs[i].data, (uint256)), AMOUNT); + break; + } + } + assertTrue(foundTransfer, "Transfer event not found"); + + // Verify balances after transact + assertEq(IERC20(USDC).balanceOf(SENDER), SENDER_BALANCE_BEFORE - AMOUNT); + assertEq(IERC20(USDC).balanceOf(RECIPIENT), RECIPIENT_BALANCE_BEFORE + AMOUNT); } }