// SPDX-License-Identifier: MIT pragma solidity 0.8.35; import {Test} from "forge-std/Test.sol"; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import {BankV1} from "../src/BankV1.sol"; import {MockUSDC} from "../src/MockUSDC.sol"; import {CheckState} from "../script/CheckState.s.sol"; import {DemoScript} from "../script/lib/DemoScript.sol"; contract NamedErrorHarness is DemoScript { function assertUint(string calldata label, uint256 expected, uint256 actual) external pure { _assertUint(label, expected, actual); } function writeManifest(string calldata path, Manifest calldata manifest) external { _writeManifest(path, manifest); } } contract NamedErrorExercisesTest is Test { address internal constant OWNER = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; address internal constant ALICE = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8; address internal constant BOB = 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC; NamedErrorHarness internal harness; function setUp() public { vm.chainId(31337); harness = new NamedErrorHarness(); } function testUnexpectedStateExerciseRevertsThroughAssertionBranch() public { vm.expectRevert( abi.encodeWithSelector(DemoScript.UnexpectedState.selector, "reserves", uint256(1_400e6), uint256(1_399e6)) ); harness.assertUint("reserves", 1_400e6, 1_399e6); } function testCheckStateExercisesRevertThroughInsolventAndUnknownStageBranches() public { (MockUSDC token, BankV1 bank) = _deployFixture("insolvent.json"); token.mint(ALICE, 1_400e6); vm.startPrank(ALICE); token.approve(address(bank), 1_400e6); bank.deposit(1_400e6); vm.stopPrank(); deal(address(token), address(bank), 1_399e6); vm.setEnv("DEMO_EXPECTED_STAGE", "invariants"); CheckState checker = new CheckState(); vm.expectRevert(abi.encodeWithSelector(CheckState.Insolvent.selector, uint256(1_399e6), uint256(1_400e6))); checker.run(); _deployFixture("unknown-stage.json"); vm.setEnv("DEMO_EXPECTED_STAGE", "mystery"); checker = new CheckState(); vm.expectRevert(abi.encodeWithSelector(CheckState.UnknownStage.selector, "mystery")); checker.run(); } function _deployFixture(string memory fixtureName) internal returns (MockUSDC token, BankV1 bank) { token = new MockUSDC(address(this)); BankV1 implementation = new BankV1(); ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), abi.encodeCall(BankV1.initialize, (address(token), OWNER))); bank = BankV1(address(proxy)); DemoScript.Actor[] memory actors = new DemoScript.Actor[](3); actors[0] = DemoScript.Actor({label: "owner", address_: OWNER}); actors[1] = DemoScript.Actor({label: "Alice", address_: ALICE}); actors[2] = DemoScript.Actor({label: "Bob", address_: BOB}); DemoScript.Manifest memory manifest = DemoScript.Manifest({ schemaVersion: 1, network: "anvil", chainId: 31337, deploymentBlock: 1, rpcUrl: "http://127.0.0.1:8545", explorerBaseUrl: "", token: address(token), proxy: address(proxy), implementation: address(implementation), owner: OWNER, actors: actors }); string memory fixtureDir = string.concat(vm.projectRoot(), "/deployments/test-named-error-exercises"); vm.createDir(fixtureDir, true); string memory manifestPath = string.concat(fixtureDir, "/", fixtureName); harness.writeManifest(manifestPath, manifest); vm.setEnv("DEPLOYMENT_MANIFEST_PATH", manifestPath); } }