Changelog
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
[Unreleased]
Changed
Love's constructor no longer takes wETH. It reads it fromWETHRegistryat
a fixed address and reverts withRegistryNotDeployedorWethNotRegistered
if there is nothing to read. The creation code is therefore byte-identical on
every chain, so CREATE2 gives LOVE one address everywhere rather than one per
wETH deployment — the previous behaviour, where the wETH argument was part of
the creation code, is gone. Breaking: the deployment interface and the
resulting address both change.script/Love.s.solbrings a chain up in three steps — deploy the registry,
register wETH, deploy the token — skipping whichever has already happened.
predict()andinitCode()no longer take a wETH argument.script/multichain-check.shnow gives its two anvil nodes different wETH
implementations at different addresses, which is what makes a matching LOVE
address meaningful; it also fails if both nodes end up on the same wETH.- Tests run against real WETH9 runtime bytecode etched from live chains rather
than againstMockWETH, since a mock's codehash is not on the allowlist and
adding it would mean testing a different allowlist from the one that ships.
MockWETHis now the "correct behaviour, wrong bytecode" rejection case.
Added
WETHRegistry, naming the wETH LOVE pegs to on a chain.register()is
permissionless and payable, takes exactly 1 wei, and accepts a candidate only
if itsEXTCODEHASHis one of ten reviewed wETH implementations and a
deposit/withdraw round trip of that wei succeeds. Ownerless, no setter,
write-once, so nothing can move the token under a live peg. The allowlist is
compile-time, so extending it means publishing a new registry and no key can
revoke an entry. The probe wei is kept rather than refunded, so a registrar
with no payable fallback can still register.receive()reverts outside a
probe, keeping the registry from becoming ether it cannot move.IWETH, the narrow wrapper interface the registry probes against.script/weth-codehashes.shandscript/weth-chains.tsv, surveying the wETH
on 27 chains and grouping them by implementation, so every allowlist entry is
reproducible from chain state. The survey found 23 distinct codehashes across
those chains, collapsing to 5 implementations over 14 chains once bridged-ETH
tokens, upgradeable proxies and non-EVM bytecode are excluded.test/fixtures/, real WETH9 runtime bytecode from Base and Ethereum, with
test/Fixtures.solto stage a chain: registry, wETH, registration.WETHRegistryTest, covering both gates, the write-once rule, the exact probe
value, ether sent outside a probe, and all ten allowlist entries.- Foundry project scaffolding (
forge-std, CI workflow,.gitignore). Love, an ERC-20 token (LOVE, 18 decimals) on OpenZeppelin v5, pegged to
wETH at 100000 LOVE per wETH. No mint function and no owner: supply moves
only through the permissionlessdeposit(uint256)andwithdraw(uint256),
so circulating LOVE is always backed by wETH held by the contract.
withdrawreverts withAmountNotDivisibleByRateunless the amount is a
multiple of the rate, keeping the peg free of rounding dust.MockWETH, a test-only WETH9 stand-in, and tests covering deposit, withdraw,
the divisibility revert, backing invariants, round-trips, transfers,
approve/transferFrom, reverts and fuzzing.- Deployment script
script/Love.s.sol, deploying with CREATE2 through the
canonical deterministic deployer; salt defaults tokeccak256("LOVE")and is
overridable viaSALT, the wETH to register defaults to the OP-Stack address
and is overridable viaWETH. Neither contract takes constructor arguments,
so both land at the same address on every chain. predict()entrypoint printing the deployment address without broadcasting,
and CREATE2 tests pinning address determinism across chain IDs, including
that two chains with different wETH still give LOVE one address.foundry.tomlwith pinned solc 0.8.30, optimizer, fmt rules, fuzz/invariant
defaults, and Base Sepolia RPC/Etherscan endpoints driven by env vars.script/multichain-check.sh, deployingLoveon two local anvil nodes with
different chain IDs and failing if the two addresses don't match.remappings.txtfor@openzeppelin/contracts/andforge-std/..env.exampledocumenting required environment variables, includingWETH.
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 |
|