// SPDX-License-Identifier: Unlicense pragma solidity >=0.7.0 <0.9.0; import "../Test.sol"; contract StdCheatsTest is Test { Bar test; function setUp() public { test = new Bar(); } function testSkip() public { vm.warp(100); skip(25); assertEq(block.timestamp, 125); } function testRewind() public { vm.warp(100); rewind(25); assertEq(block.timestamp, 75); } function testHoax() public { hoax(address(1337)); test.bar{value: 100}(address(1337)); } function testHoaxOrigin() public { hoax(address(1337), address(1337)); test.origin{value: 100}(address(1337)); } function testHoaxDifferentAddresses() public { hoax(address(1337), address(7331)); test.origin{value: 100}(address(1337), address(7331)); } function testStartHoax() public { startHoax(address(1337)); test.bar{value: 100}(address(1337)); test.bar{value: 100}(address(1337)); vm.stopPrank(); test.bar(address(this)); } function testStartHoaxOrigin() public { startHoax(address(1337), address(1337)); test.origin{value: 100}(address(1337)); test.origin{value: 100}(address(1337)); vm.stopPrank(); test.bar(address(this)); } function testChangePrank() public { vm.startPrank(address(1337)); test.bar(address(1337)); changePrank(address(0xdead)); test.bar(address(0xdead)); changePrank(address(1337)); test.bar(address(1337)); vm.stopPrank(); } function testDeal() public { deal(address(this), 1 ether); assertEq(address(this).balance, 1 ether); } function testDealToken() public { Bar barToken = new Bar(); address bar = address(barToken); deal(bar, address(this), 10000e18); assertEq(barToken.balanceOf(address(this)), 10000e18); } function testDealTokenAdjustTS() public { Bar barToken = new Bar(); address bar = address(barToken); deal(bar, address(this), 10000e18, true); assertEq(barToken.balanceOf(address(this)), 10000e18); assertEq(barToken.totalSupply(), 20000e18); deal(bar, address(this), 0, true); assertEq(barToken.balanceOf(address(this)), 0); assertEq(barToken.totalSupply(), 10000e18); } function testBound() public { assertEq(bound(5, 0, 4), 0); assertEq(bound(0, 69, 69), 69); assertEq(bound(0, 68, 69), 68); assertEq(bound(10, 150, 190), 160); assertEq(bound(300, 2800, 3200), 3100); assertEq(bound(9999, 1337, 6666), 6006); } function testCannotBoundMaxLessThanMin() public { vm.expectRevert(bytes("Test bound(uint256,uint256,uint256): Max is less than min.")); bound(5, 100, 10); } function testBound( uint256 num, uint256 min, uint256 max ) public { if (min > max) (min, max) = (max, min); uint256 bounded = bound(num, min, max); assertGe(bounded, min); assertLe(bounded, max); } function testBoundUint256Max() public { assertEq(bound(0, type(uint256).max - 1, type(uint256).max), type(uint256).max - 1); assertEq(bound(1, type(uint256).max - 1, type(uint256).max), type(uint256).max); } function testCannotBoundMaxLessThanMin( uint256 num, uint256 min, uint256 max ) public { vm.assume(min > max); vm.expectRevert(bytes("Test bound(uint256,uint256,uint256): Max is less than min.")); bound(num, min, max); } function testDeployCode() public { address deployed = deployCode("StdCheats.t.sol:StdCheatsTest", bytes("")); assertEq(string(getCode(deployed)), string(getCode(address(this)))); } function testDeployCodeNoArgs() public { address deployed = deployCode("StdCheats.t.sol:StdCheatsTest"); assertEq(string(getCode(deployed)), string(getCode(address(this)))); } function testDeployCodeFail() public { vm.expectRevert(bytes("Test deployCode(string): Deployment failed.")); this.deployCode("StdCheats.t.sol:RevertingContract"); } function getCode(address who) internal view returns (bytes memory o_code) { /// @solidity memory-safe-assembly assembly { // retrieve the size of the code, this needs assembly let size := extcodesize(who) // allocate output byte array - this could also be done without assembly // by using o_code = new bytes(size) o_code := mload(0x40) // new "memory end" including padding mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) // store length in memory mstore(o_code, size) // actually retrieve the code, this needs assembly extcodecopy(who, add(o_code, 0x20), 0, size) } } } contract Bar { constructor() { /// `DEAL` STDCHEAT totalSupply = 10000e18; balanceOf[address(this)] = totalSupply; } /// `HOAX` STDCHEATS function bar(address expectedSender) public payable { require(msg.sender == expectedSender, "!prank"); } function origin(address expectedSender) public payable { require(msg.sender == expectedSender, "!prank"); require(tx.origin == expectedSender, "!prank"); } function origin(address expectedSender, address expectedOrigin) public payable { require(msg.sender == expectedSender, "!prank"); require(tx.origin == expectedOrigin, "!prank"); } /// `DEAL` STDCHEAT mapping (address => uint256) public balanceOf; uint256 public totalSupply; } contract RevertingContract { constructor() { revert(); } }