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
|
// 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";
/// @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 {
bytes32 public constant DEFAULT_SALT = keccak256("LOVE");
/// @dev wETH on Base, Optimism and every other OP-Stack chain.
address public constant DEFAULT_WETH = 0x4200000000000000000000000000000000000006;
Love public love;
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.
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);
}
function predict(bytes32 s, address w) public pure returns (address) {
return vm.computeCreate2Address(s, initCodeHash(w), CREATE2_FACTORY);
}
function initCode(address w) public pure returns (bytes memory) {
return abi.encodePacked(type(Love).creationCode, abi.encode(w));
}
function initCodeHash(address w) public pure returns (bytes32) {
return keccak256(initCode(w));
}
/// @dev `SALT` overrides the default, e.g. to mine a vanity address.
function salt() public view returns (bytes32) {
return vm.envOr("SALT", DEFAULT_SALT);
}
/// @dev `WETH` overrides the default, which only holds on OP-Stack chains.
function wethAddress() public view returns (address) {
return vm.envOr("WETH", DEFAULT_WETH);
}
}
|