julien/lovepublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/julien/love.git
git clone ssh://git@rickub.com/julien/love.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Fixtures.sol · 78 lines · 3.7 KBSolidity Blame HistoryRaw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import {IWETH} from "../src/IWETH.sol";
import {WETHRegistry} from "../src/WETHRegistry.sol";
import {CommonBase} from "forge-std/Base.sol";
import {StdCheats} from "forge-std/StdCheats.sol";

/// @title Fixtures
/// @author Julien Béranger
/// @notice Brings a chain up the way a real one comes up: the registry at its
///         deterministic address, a genuine wETH at some address, registered.
/// @dev The wETH here is real runtime bytecode lifted off a live chain, etched
///      into place. A mock would need its codehash added to the allowlist to
///      be registrable, which would mean testing a different allowlist from
///      the one that ships. Etching real code keeps the test and the product
///      honest about the same ten hashes.
abstract contract Fixtures is CommonBase, StdCheats {
    /// @notice Salt the registry is deployed with, here and in the script.
    bytes32 internal constant REGISTRY_SALT = keccak256("LOVE.WETHRegistry");

    /// @notice OP Stack legacy WETH9, as deployed on Base, Mode and Zora.
    string internal constant WETH9_OP_LEGACY = "test/fixtures/weth9-op-legacy.hex";

    /// @notice Canonical WETH9, as deployed on Ethereum mainnet.
    string internal constant WETH9_CANONICAL = "test/fixtures/weth9-canonical.hex";

    /// @notice Put real wETH runtime bytecode at `where`.
    /// @dev Reads the fixture rather than embedding it, so refreshing a
    ///      fixture from chain state does not mean editing Solidity.
    /// @param where The address to place it at.
    /// @param fixture Path to the runtime bytecode, `WETH9_*` above.
    /// @return The wETH now living at `where`.
    function etchWeth(address where, string memory fixture) internal returns (IWETH) {
        vm.etch(where, vm.parseBytes(vm.trim(vm.readFile(fixture))));
        vm.label(where, "WETH");
        return IWETH(where);
    }

    /// @notice Deploy the registry to the address `Love` expects.
    /// @dev Through the canonical deterministic deployer with `REGISTRY_SALT`,
    ///      exactly as the deploy script does, so the address it lands at is
    ///      the one compiled into `Love.REGISTRY` rather than one arranged for
    ///      the test.
    /// @return The registry.
    function deployRegistry() internal returns (WETHRegistry) {
        (bool ok, bytes memory ret) =
            CREATE2_FACTORY.call(abi.encodePacked(REGISTRY_SALT, type(WETHRegistry).creationCode));
        require(ok, "registry deployment failed");

        // casting to 'bytes20' is safe because the deployer returns the 20-byte address, raw
        // forge-lint: disable-next-line(unsafe-typecast)
        WETHRegistry registry = WETHRegistry(payable(address(bytes20(ret))));
        vm.label(address(registry), "WETHRegistry");

        return registry;
    }

    /// @notice Register `weth`, funding the one-wei probe.
    /// @param registry The registry to register with.
    /// @param weth The wETH to register.
    function register(WETHRegistry registry, IWETH weth) internal {
        uint256 probe = registry.PROBE();
        deal(address(this), address(this).balance + probe);
        registry.register{value: probe}(weth);
    }

    /// @notice The whole chain in one call: registry, wETH, registration.
    /// @param wethAt The address to etch wETH at.
    /// @param fixture Which implementation to etch.
    /// @return registry The registry, with `wethAt` registered.
    /// @return weth The wETH now backing any `Love` deployed here.
    function setUpChain(address wethAt, string memory fixture) internal returns (WETHRegistry registry, IWETH weth) {
        registry = deployRegistry();
        weth = etchWeth(wethAt, fixture);
        register(registry, weth);
    }
}