julien/lovepublic Fork 0
5a80e08cfd353991faab06ea9599896a86fa55ea
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.

Merge 3-peg-love-to-weth into main ce13509 · on 5a80e08cfd353991faab06ea9599896a86fa55ea · rickub · 8h ago
Love.s.sol · 112 lines · 4.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
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import {Love} from "../src/Love.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Script, console} from "forge-std/Script.sol";

/// @title LoveScript
/// @author Julien Béranger
/// @notice Deploys `Love` with CREATE2 through the canonical deterministic
///         deployer. The address depends on the salt and the creation code, and
///         the creation code embeds the wETH address — so the token only gets
///         the same address on chains where wETH sits at the same address. Keep
///         `solc`, the optimizer settings and `bytecode_hash = "none"` as they
///         are in `foundry.toml`, or the address changes too.
contract LoveScript is Script {
    /// @notice Salt used when `SALT` is not set in the environment.
    bytes32 public constant DEFAULT_SALT = keccak256("LOVE");

    /// @notice wETH address used when `WETH` is not set in the environment.
    /// @dev wETH on Base, Optimism and every other OP-Stack chain.
    address public constant DEFAULT_WETH = 0x4200000000000000000000000000000000000006;

    /// @notice The token, once `run()` has deployed or found it.
    Love public love;

    /// @notice Deploy `Love`, or return it untouched if it is already there.
    /// @dev Reads `SALT` and `WETH` from the environment, falling back to the
    ///      defaults, and asserts the deployed address matches the prediction.
    /// @return The deployed token.
    function run() public returns (Love) {
        bytes32 s = salt();
        address w = wethAddress();
        address predicted = predict(s, w);

        console.log("deployer     ", CREATE2_FACTORY);
        console.log("salt         ", vm.toString(s));
        console.log("weth         ", w);
        console.log("initCodeHash ", vm.toString(initCodeHash(w)));
        console.log("predicted    ", predicted);

        if (predicted.code.length > 0) {
            console.log("already deployed, nothing to do");
            love = Love(predicted);
            return love;
        }

        vm.startBroadcast();
        love = new Love{salt: s}(IERC20(w));
        vm.stopBroadcast();

        require(address(love) == predicted, "LoveScript: address mismatch");

        console.log("Love deployed at", address(love));
        console.log("name         ", love.name());
        console.log("symbol       ", love.symbol());
        console.log("weth         ", address(love.WETH()));
        console.log("rate         ", love.RATE());
        console.log("totalSupply  ", love.totalSupply());

        return love;
    }

    /// @notice Print the address `run()` would deploy to, without broadcasting.
    /// @return predicted The address the current salt and wETH derive to.
    function predict() public view returns (address predicted) {
        bytes32 s = salt();
        address w = wethAddress();
        predicted = predict(s, w);

        console.log("salt         ", vm.toString(s));
        console.log("weth         ", w);
        console.log("initCodeHash ", vm.toString(initCodeHash(w)));
        console.log("predicted    ", predicted);
    }

    /// @notice Derive the deployment address from a salt and a wETH address.
    /// @param s The CREATE2 salt.
    /// @param w The wETH the token would be pegged to.
    /// @return The address `Love` would land at.
    function predict(bytes32 s, address w) public pure returns (address) {
        return vm.computeCreate2Address(s, initCodeHash(w), CREATE2_FACTORY);
    }

    /// @notice The creation code CREATE2 is handed, constructor argument included.
    /// @param w The wETH the token would be pegged to.
    /// @return The creation code, with `w` ABI-encoded onto it.
    function initCode(address w) public pure returns (bytes memory) {
        return abi.encodePacked(type(Love).creationCode, abi.encode(w));
    }

    /// @notice Hash of the creation code, the second input to the address derivation.
    /// @param w The wETH the token would be pegged to.
    /// @return The keccak256 of `initCode(w)`.
    function initCodeHash(address w) public pure returns (bytes32) {
        return keccak256(initCode(w));
    }

    /// @notice The salt to deploy with.
    /// @dev `SALT` overrides the default, e.g. to mine a vanity address.
    /// @return The configured salt, or `DEFAULT_SALT`.
    function salt() public view returns (bytes32) {
        return vm.envOr("SALT", DEFAULT_SALT);
    }

    /// @notice The wETH address to peg the deployment to.
    /// @dev `WETH` overrides the default, which only holds on OP-Stack chains.
    /// @return The configured wETH address, or `DEFAULT_WETH`.
    function wethAddress() public view returns (address) {
        return vm.envOr("WETH", DEFAULT_WETH);
    }
}