document create2 deployment
1c407d3 parent: 9056150 modified
CHANGELOG.md +5 -1 | @@ -13,7 +13,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | ||
| 13 | 13 | - `Love`, an ERC-20 token (`LOVE`, 18 decimals) on OpenZeppelin v5, with an |
| 14 | 14 | unrestricted public `mint(address,uint256)` — anyone can mint any amount. |
| 15 | 15 | - Metadata, mint, transfer, approve/`transferFrom`, revert and fuzz tests. |
| 16 | -- Deployment script `script/Love.s.sol`. | |
| 16 | +- Deployment script `script/Love.s.sol`, deploying with CREATE2 through the | |
| 17 | + canonical deterministic deployer so `Love` gets the same address on every EVM | |
| 18 | + network; salt defaults to `keccak256("LOVE")` and is overridable via `SALT`. | |
| 19 | +- `predict()` entrypoint printing the deployment address without broadcasting, | |
| 20 | + and CREATE2 tests pinning address determinism across chain IDs. | |
| 17 | 21 | - `foundry.toml` with pinned solc 0.8.30, optimizer, fmt rules, fuzz/invariant |
| 18 | 22 | defaults, and Base Sepolia RPC/Etherscan endpoints driven by env vars. |
| 19 | 23 | - `remappings.txt` for `@openzeppelin/contracts/` and `forge-std/`. |
| @@ -13,7 +13,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 13 | - `Love`, an ERC-20 token (`LOVE`, 18 decimals) on OpenZeppelin v5, with an | 13 | - `Love`, an ERC-20 token (`LOVE`, 18 decimals) on OpenZeppelin v5, with an |
| 14 | unrestricted public `mint(address,uint256)` — anyone can mint any amount. | 14 | unrestricted public `mint(address,uint256)` — anyone can mint any amount. |
| 15 | - Metadata, mint, transfer, approve/`transferFrom`, revert and fuzz tests. | 15 | - Metadata, mint, transfer, approve/`transferFrom`, revert and fuzz tests. |
| 16 | -- Deployment script `script/Love.s.sol`. | 16 | +- Deployment script `script/Love.s.sol`, deploying with CREATE2 through the |
| 17 | + canonical deterministic deployer so `Love` gets the same address on every EVM | ||
| 18 | + network; salt defaults to `keccak256("LOVE")` and is overridable via `SALT`. | ||
| 19 | +- `predict()` entrypoint printing the deployment address without broadcasting, | ||
| 20 | + and CREATE2 tests pinning address determinism across chain IDs. | ||
| 17 | - `foundry.toml` with pinned solc 0.8.30, optimizer, fmt rules, fuzz/invariant | 21 | - `foundry.toml` with pinned solc 0.8.30, optimizer, fmt rules, fuzz/invariant |
| 18 | defaults, and Base Sepolia RPC/Etherscan endpoints driven by env vars. | 22 | defaults, and Base Sepolia RPC/Etherscan endpoints driven by env vars. |
| 19 | - `remappings.txt` for `@openzeppelin/contracts/` and `forge-std/`. | 23 | - `remappings.txt` for `@openzeppelin/contracts/` and `forge-std/`. |
modified
README.md +35 -1 | @@ -35,6 +35,20 @@ anvil # local node | ||
| 35 | 35 | |
| 36 | 36 | ## Deploy |
| 37 | 37 | |
| 38 | +`Love` is deployed with CREATE2 through the canonical | |
| 39 | +[deterministic deployer](https://github.com/Arachnid/deterministic-deployment-proxy) | |
| 40 | +at `0x4e59b44847b379578588920cA78FbF26c0B4956C`, so it gets **the same address on | |
| 41 | +every EVM network**. The address derives from the salt and the creation code | |
| 42 | +only — not from the deployer account or its nonce. | |
| 43 | + | |
| 44 | +Check the address before spending gas: | |
| 45 | + | |
| 46 | +```shell | |
| 47 | +forge script script/Love.s.sol:LoveScript --sig 'predict()' | |
| 48 | +``` | |
| 49 | + | |
| 50 | +Then deploy: | |
| 51 | + | |
| 38 | 52 | ```shell |
| 39 | 53 | forge script script/Love.s.sol:LoveScript \ |
| 40 | 54 | --rpc-url base_sepolia \ |
| @@ -43,7 +57,27 @@ forge script script/Love.s.sol:LoveScript \ | ||
| 43 | 57 | --verify |
| 44 | 58 | ``` |
| 45 | 59 | |
| 46 | -Drop `--broadcast` for a dry run. | |
| 60 | +Drop `--broadcast` for a dry run. Re-running against a network where the token | |
| 61 | +already exists is a no-op. | |
| 62 | + | |
| 63 | +The salt defaults to `keccak256("LOVE")`; override it — to mine a vanity address, | |
| 64 | +say — with `SALT=0x… forge script …`. The same salt must be used on every | |
| 65 | +network. | |
| 66 | + | |
| 67 | +### Keeping the address stable | |
| 68 | + | |
| 69 | +The creation code, and therefore the address, changes if any of these change: | |
| 70 | + | |
| 71 | +- the contract source (`src/Love.sol`) or its OpenZeppelin version, | |
| 72 | +- `solc` (pinned to 0.8.30 in `foundry.toml`), | |
| 73 | +- optimizer settings (`optimizer = true`, `optimizer_runs = 200`, `via_ir = false`), | |
| 74 | +- `bytecode_hash` (set to `none`, which keeps the metadata hash out of the | |
| 75 | + bytecode so paths and compiler metadata don't leak into the address). | |
| 76 | + | |
| 77 | +Treat those as frozen once the token is deployed anywhere. | |
| 78 | + | |
| 79 | +Chains lacking the deterministic deployer — zkSync-style chains in particular, | |
| 80 | +where CREATE2 addresses are computed differently — cannot match this address. | |
| 47 | 81 | |
| 48 | 82 | ## Layout |
| 49 | 83 | |
| @@ -35,6 +35,20 @@ anvil # local node | |||
| 35 | 35 | ||
| 36 | ## Deploy | 36 | ## Deploy |
| 37 | 37 | ||
| 38 | +`Love` is deployed with CREATE2 through the canonical | ||
| 39 | +[deterministic deployer](https://github.com/Arachnid/deterministic-deployment-proxy) | ||
| 40 | +at `0x4e59b44847b379578588920cA78FbF26c0B4956C`, so it gets **the same address on | ||
| 41 | +every EVM network**. The address derives from the salt and the creation code | ||
| 42 | +only — not from the deployer account or its nonce. | ||
| 43 | + | ||
| 44 | +Check the address before spending gas: | ||
| 45 | + | ||
| 46 | +```shell | ||
| 47 | +forge script script/Love.s.sol:LoveScript --sig 'predict()' | ||
| 48 | +``` | ||
| 49 | + | ||
| 50 | +Then deploy: | ||
| 51 | + | ||
| 38 | ```shell | 52 | ```shell |
| 39 | forge script script/Love.s.sol:LoveScript \ | 53 | forge script script/Love.s.sol:LoveScript \ |
| 40 | --rpc-url base_sepolia \ | 54 | --rpc-url base_sepolia \ |
| @@ -43,7 +57,27 @@ forge script script/Love.s.sol:LoveScript \ | |||
| 43 | --verify | 57 | --verify |
| 44 | ``` | 58 | ``` |
| 45 | 59 | ||
| 46 | -Drop `--broadcast` for a dry run. | 60 | +Drop `--broadcast` for a dry run. Re-running against a network where the token |
| 61 | +already exists is a no-op. | ||
| 62 | + | ||
| 63 | +The salt defaults to `keccak256("LOVE")`; override it — to mine a vanity address, | ||
| 64 | +say — with `SALT=0x… forge script …`. The same salt must be used on every | ||
| 65 | +network. | ||
| 66 | + | ||
| 67 | +### Keeping the address stable | ||
| 68 | + | ||
| 69 | +The creation code, and therefore the address, changes if any of these change: | ||
| 70 | + | ||
| 71 | +- the contract source (`src/Love.sol`) or its OpenZeppelin version, | ||
| 72 | +- `solc` (pinned to 0.8.30 in `foundry.toml`), | ||
| 73 | +- optimizer settings (`optimizer = true`, `optimizer_runs = 200`, `via_ir = false`), | ||
| 74 | +- `bytecode_hash` (set to `none`, which keeps the metadata hash out of the | ||
| 75 | + bytecode so paths and compiler metadata don't leak into the address). | ||
| 76 | + | ||
| 77 | +Treat those as frozen once the token is deployed anywhere. | ||
| 78 | + | ||
| 79 | +Chains lacking the deterministic deployer — zkSync-style chains in particular, | ||
| 80 | +where CREATE2 addresses are computed differently — cannot match this address. | ||
| 47 | 81 | ||
| 48 | ## Layout | 82 | ## Layout |
| 49 | 83 | ||