julien/lovepublic Fork 0
1c407d31e7da917c5d28adfdef1299af24795bd2
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.

document create2 deployment 1c407d3 · on 1c407d31e7da917c5d28adfdef1299af24795bd2 · julienbrg · 8h ago
README.md · 97 lines · 2.8 KBmarkdown
Blame HistoryOpen raw

love

A Foundry project.

Love (LOVE, 18 decimals) is a basic ERC-20 built on
OpenZeppelin, with one
deliberate twist: mint has no access control.

function mint(address to, uint256 amount) external;

Anyone can mint any amount to any address. Supply starts at zero and is
unbounded, so the token carries no economic value — it is a faucet / demo token.
Do not deploy it to mainnet expecting otherwise.

Setup

forge install
cp .env.example .env

Usage

forge build            # compile
forge test             # run tests
forge test -vvv        # with traces
forge fmt              # format
forge coverage         # coverage report
forge snapshot         # gas snapshot
anvil                  # local node

Deploy

Love is deployed with CREATE2 through the canonical
deterministic deployer
at 0x4e59b44847b379578588920cA78FbF26c0B4956C, so it gets the same address on
every EVM network
. The address derives from the salt and the creation code
only — not from the deployer account or its nonce.

Check the address before spending gas:

forge script script/Love.s.sol:LoveScript --sig 'predict()'

Then deploy:

forge script script/Love.s.sol:LoveScript \
  --rpc-url base_sepolia \
  --account "$DEPLOYER_ACCOUNT" \
  --broadcast \
  --verify

Drop --broadcast for a dry run. Re-running against a network where the token
already exists is a no-op.

The salt defaults to keccak256("LOVE"); override it — to mine a vanity address,
say — with SALT=0x… forge script …. The same salt must be used on every
network.

Keeping the address stable

The creation code, and therefore the address, changes if any of these change:

  • the contract source (src/Love.sol) or its OpenZeppelin version,
  • solc (pinned to 0.8.30 in foundry.toml),
  • optimizer settings (optimizer = true, optimizer_runs = 200, via_ir = false),
  • bytecode_hash (set to none, which keeps the metadata hash out of the
    bytecode so paths and compiler metadata don't leak into the address).

Treat those as frozen once the token is deployed anywhere.

Chains lacking the deterministic deployer — zkSync-style chains in particular,
where CREATE2 addresses are computed differently — cannot match this address.

Layout

Path Contents
src/ Contracts
test/ Tests
script/ Deployment scripts
lib/ Dependencies

Mint

cast send <LOVE_ADDRESS> "mint(address,uint256)" <RECIPIENT> 1000000000000000000 \
  --rpc-url base_sepolia \
  --account "$DEPLOYER_ACCOUNT"
 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
# love

A [Foundry](https://getfoundry.sh) project.

`Love` (`LOVE`, 18 decimals) is a basic ERC-20 built on
[OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts), with one
deliberate twist: `mint` has **no access control**.

```solidity
function mint(address to, uint256 amount) external;
```

Anyone can mint any amount to any address. Supply starts at zero and is
unbounded, so the token carries no economic value — it is a faucet / demo token.
Do not deploy it to mainnet expecting otherwise.

## Setup

```shell
forge install
cp .env.example .env
```

## Usage

```shell
forge build            # compile
forge test             # run tests
forge test -vvv        # with traces
forge fmt              # format
forge coverage         # coverage report
forge snapshot         # gas snapshot
anvil                  # local node
```

## Deploy

`Love` is deployed with CREATE2 through the canonical
[deterministic deployer](https://github.com/Arachnid/deterministic-deployment-proxy)
at `0x4e59b44847b379578588920cA78FbF26c0B4956C`, so it gets **the same address on
every EVM network**. The address derives from the salt and the creation code
only — not from the deployer account or its nonce.

Check the address before spending gas:

```shell
forge script script/Love.s.sol:LoveScript --sig 'predict()'
```

Then deploy:

```shell
forge script script/Love.s.sol:LoveScript \
  --rpc-url base_sepolia \
  --account "$DEPLOYER_ACCOUNT" \
  --broadcast \
  --verify
```

Drop `--broadcast` for a dry run. Re-running against a network where the token
already exists is a no-op.

The salt defaults to `keccak256("LOVE")`; override it — to mine a vanity address,
say — with `SALT=0x… forge script …`. The same salt must be used on every
network.

### Keeping the address stable

The creation code, and therefore the address, changes if any of these change:

- the contract source (`src/Love.sol`) or its OpenZeppelin version,
- `solc` (pinned to 0.8.30 in `foundry.toml`),
- optimizer settings (`optimizer = true`, `optimizer_runs = 200`, `via_ir = false`),
- `bytecode_hash` (set to `none`, which keeps the metadata hash out of the
  bytecode so paths and compiler metadata don't leak into the address).

Treat those as frozen once the token is deployed anywhere.

Chains lacking the deterministic deployer — zkSync-style chains in particular,
where CREATE2 addresses are computed differently — cannot match this address.

## Layout

| Path      | Contents            |
| --------- | ------------------- |
| `src/`    | Contracts           |
| `test/`   | Tests               |
| `script/` | Deployment scripts  |
| `lib/`    | Dependencies        |

## Mint

```shell
cast send <LOVE_ADDRESS> "mint(address,uint256)" <RECIPIENT> 1000000000000000000 \
  --rpc-url base_sepolia \
  --account "$DEPLOYER_ACCOUNT"
```