// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Test, console} from "forge-std/Test.sol"; import {AtomicExecutor} from "../AtomicExecutor.sol"; contract MockTarget { uint256 public value; function setValue(uint256 _value) external { value = _value; } function revertTest() external pure { revert("Test revert"); } receive() external payable {} } contract AtomicExecutorEdgeCasesTest is Test { AtomicExecutor executor; MockTarget target; address owner = address(1); address user = address(2); function setUp() public { vm.prank(owner); executor = new AtomicExecutor(owner); target = new MockTarget(); vm.prank(owner); executor.setAllowedTarget(address(target), true); } function testEmptyBatch() public { address[] memory targets = new address[](0); bytes[] memory calldatas = new bytes[](0); vm.prank(user); executor.executeBatch(targets, calldatas); // Should succeed (no-op) } function testVeryLargeBatch() public { // Test with 50 calls (near gas limit) address[] memory targets = new address[](50); bytes[] memory calldatas = new bytes[](50); for (uint i = 0; i < 50; i++) { targets[i] = address(target); calldatas[i] = abi.encodeWithSignature("setValue(uint256)", i); } vm.prank(user); executor.executeBatch(targets, calldatas); assertEq(target.value(), 49); // Last value set } function testReentrancyAttempt() public { // Create a contract that tries to reenter ReentrancyAttacker attacker = new ReentrancyAttacker(executor, target); vm.prank(owner); executor.setAllowedTarget(address(attacker), true); address[] memory targets = new address[](1); bytes[] memory calldatas = new bytes[](1); targets[0] = address(attacker); calldatas[0] = abi.encodeWithSignature("attack()"); vm.prank(user); // Should revert due to ReentrancyGuard vm.expectRevert(); executor.executeBatch(targets, calldatas); } function testValueHandling() public { address[] memory targets = new address[](1); bytes[] memory calldatas = new bytes[](1); targets[0] = address(target); calldatas[0] = abi.encodeWithSignature("setValue(uint256)", 100); vm.deal(address(executor), 1 ether); vm.prank(user); executor.executeBatch(targets, calldatas); // Executor should not send value unless explicitly in call assertEq(address(executor).balance, 1 ether); } function testDelegatecallProtection() public { // Attempt delegatecall (should not be possible with standard call) address[] memory targets = new address[](1); bytes[] memory calldatas = new bytes[](1); // Standard call, not delegatecall targets[0] = address(target); calldatas[0] = abi.encodeWithSignature("setValue(uint256)", 100); vm.prank(user); executor.executeBatch(targets, calldatas); // Should succeed (delegatecall protection is implicit with standard call) assertEq(target.value(), 100); } } contract ReentrancyAttacker { AtomicExecutor executor; MockTarget target; constructor(AtomicExecutor _executor, MockTarget _target) { executor = _executor; target = _target; } function attack() external { // Try to reenter executor address[] memory targets = new address[](1); bytes[] memory calldatas = new bytes[](1); targets[0] = address(target); calldatas[0] = abi.encodeWithSignature("setValue(uint256)", 999); executor.executeBatch(targets, calldatas); } }