| Merge 5-weth-bytecode-verification into main 2f6da5e rickub 6h ago | 1 | // SPDX-License-Identifier: MIT |
| 2 | pragma solidity ^0.8.30; |
| 3 | |
| 4 | import {IWETH} from "../src/IWETH.sol"; |
| 5 | import {WETHRegistry} from "../src/WETHRegistry.sol"; |
| 6 | import {CommonBase} from "forge-std/Base.sol"; |
| 7 | import {StdCheats} from "forge-std/StdCheats.sol"; |
| 8 | |
| 9 | /// @title Fixtures |
| 10 | /// @author Julien Béranger |
| 11 | /// @notice Brings a chain up the way a real one comes up: the registry at its |
| 12 | /// deterministic address, a genuine wETH at some address, registered. |
| 13 | /// @dev The wETH here is real runtime bytecode lifted off a live chain, etched |
| 14 | /// into place. A mock would need its codehash added to the allowlist to |
| 15 | /// be registrable, which would mean testing a different allowlist from |
| 16 | /// the one that ships. Etching real code keeps the test and the product |
| 17 | /// honest about the same ten hashes. |
| 18 | abstract contract Fixtures is CommonBase, StdCheats { |
| 19 | /// @notice Salt the registry is deployed with, here and in the script. |
| 20 | bytes32 internal constant REGISTRY_SALT = keccak256("LOVE.WETHRegistry"); |
| 21 | |
| 22 | /// @notice OP Stack legacy WETH9, as deployed on Base, Mode and Zora. |
| 23 | string internal constant WETH9_OP_LEGACY = "test/fixtures/weth9-op-legacy.hex"; |
| 24 | |
| 25 | /// @notice Canonical WETH9, as deployed on Ethereum mainnet. |
| 26 | string internal constant WETH9_CANONICAL = "test/fixtures/weth9-canonical.hex"; |
| 27 | |
| 28 | /// @notice Put real wETH runtime bytecode at `where`. |
| 29 | /// @dev Reads the fixture rather than embedding it, so refreshing a |
| 30 | /// fixture from chain state does not mean editing Solidity. |
| 31 | /// @param where The address to place it at. |
| 32 | /// @param fixture Path to the runtime bytecode, `WETH9_*` above. |
| 33 | /// @return The wETH now living at `where`. |
| 34 | function etchWeth(address where, string memory fixture) internal returns (IWETH) { |
| 35 | vm.etch(where, vm.parseBytes(vm.trim(vm.readFile(fixture)))); |
| 36 | vm.label(where, "WETH"); |
| 37 | return IWETH(where); |
| 38 | } |
| 39 | |
| 40 | /// @notice Deploy the registry to the address `Love` expects. |
| 41 | /// @dev Through the canonical deterministic deployer with `REGISTRY_SALT`, |
| 42 | /// exactly as the deploy script does, so the address it lands at is |
| 43 | /// the one compiled into `Love.REGISTRY` rather than one arranged for |
| 44 | /// the test. |
| 45 | /// @return The registry. |
| 46 | function deployRegistry() internal returns (WETHRegistry) { |
| 47 | (bool ok, bytes memory ret) = |
| 48 | CREATE2_FACTORY.call(abi.encodePacked(REGISTRY_SALT, type(WETHRegistry).creationCode)); |
| 49 | require(ok, "registry deployment failed"); |
| 50 | |
| 51 | // casting to 'bytes20' is safe because the deployer returns the 20-byte address, raw |
| 52 | // forge-lint: disable-next-line(unsafe-typecast) |
| 53 | WETHRegistry registry = WETHRegistry(payable(address(bytes20(ret)))); |
| 54 | vm.label(address(registry), "WETHRegistry"); |
| 55 | |
| 56 | return registry; |
| 57 | } |
| 58 | |
| 59 | /// @notice Register `weth`, funding the one-wei probe. |
| 60 | /// @param registry The registry to register with. |
| 61 | /// @param weth The wETH to register. |
| 62 | function register(WETHRegistry registry, IWETH weth) internal { |
| 63 | uint256 probe = registry.PROBE(); |
| 64 | deal(address(this), address(this).balance + probe); |
| 65 | registry.register{value: probe}(weth); |
| 66 | } |
| 67 | |
| 68 | /// @notice The whole chain in one call: registry, wETH, registration. |
| 69 | /// @param wethAt The address to etch wETH at. |
| 70 | /// @param fixture Which implementation to etch. |
| 71 | /// @return registry The registry, with `wethAt` registered. |
| 72 | /// @return weth The wETH now backing any `Love` deployed here. |
| 73 | function setUpChain(address wethAt, string memory fixture) internal returns (WETHRegistry registry, IWETH weth) { |
| 74 | registry = deployRegistry(); |
| 75 | weth = etchWeth(wethAt, fixture); |
| 76 | register(registry, weth); |
| 77 | } |
| 78 | } |