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

multichain-check.sh · 181 lines · 5.6 KBBash Blame HistoryRaw
Merge 2-multichain-check into main 7c6b16b rickub 5h ago1#!/usr/bin/env bash
2#
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago3# Proves the claim the registry exists to make: LOVE lands at the same address
4# on two chains that have nothing about their wETH in common.
5#
6# Two anvil nodes with different chain ids get different wETH implementations,
7# at different addresses — node A the OP Stack predeploy, node B canonical
8# WETH9 at its mainnet address — using the same runtime bytecode the tests
9# etch. Each node is then brought up the way a real chain would be: registry,
10# registration, token. If the two token addresses match, wETH is genuinely out
11# of the creation code.
12#
13# The previous version of this script gave both nodes the same wETH, because
14# back then the address was a constructor argument and matching was only
15# possible when the argument matched. That is exactly what changed.
Merge 2-multichain-check into main 7c6b16b rickub 5h ago16#
17# Usage: ./script/multichain-check.sh
18#
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago19# Env overrides: PORT_A, PORT_B, CHAIN_ID_A, CHAIN_ID_B, SALT
Merge 2-multichain-check into main 7c6b16b rickub 5h ago20
21set -euo pipefail
22
23PORT_A=${PORT_A:-8545}
24PORT_B=${PORT_B:-8546}
25CHAIN_ID_A=${CHAIN_ID_A:-31337}
26CHAIN_ID_B=${CHAIN_ID_B:-31338}
27
28# First anvil dev account — local only, never use this key anywhere else.
29ANVIL_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
30CREATE2_FACTORY=0x4e59b44847b379578588920cA78FbF26c0B4956C
31
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago32# Node A: the OP Stack predeploy. Node B: canonical WETH9, where it sits on
33# Ethereum. Different implementations, different addresses, both allowlisted.
34WETH_A=0x4200000000000000000000000000000000000006
35WETH_B=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
36
Merge 2-multichain-check into main 7c6b16b rickub 5h ago37ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago38FIXTURE_A="$ROOT/test/fixtures/weth9-op-legacy.hex"
39FIXTURE_B="$ROOT/test/fixtures/weth9-canonical.hex"
40
Merge 2-multichain-check into main 7c6b16b rickub 5h ago41RPC_A="http://127.0.0.1:$PORT_A"
42RPC_B="http://127.0.0.1:$PORT_B"
43TMP=$(mktemp -d)
44PIDS=()
45
46cleanup() {
47 for pid in ${PIDS[@]+"${PIDS[@]}"}; do
48 kill "$pid" 2>/dev/null || true
49 done
50 rm -rf "$TMP"
51 rm -rf "$ROOT/broadcast/Love.s.sol/$CHAIN_ID_A" "$ROOT/broadcast/Love.s.sol/$CHAIN_ID_B"
52 rmdir "$ROOT/broadcast/Love.s.sol" "$ROOT/broadcast" 2>/dev/null || true
53}
54trap cleanup EXIT
55
56start_node() {
57 local port=$1 chain_id=$2 rpc=$3
58 anvil --port "$port" --chain-id "$chain_id" --silent >"$TMP/anvil-$port.log" 2>&1 &
59 PIDS+=($!)
60
61 for _ in $(seq 1 50); do
62 if cast chain-id --rpc-url "$rpc" >/dev/null 2>&1; then
63 return 0
64 fi
65 sleep 0.2
66 done
67
68 echo "anvil on port $port never came up:" >&2
69 cat "$TMP/anvil-$port.log" >&2
70 exit 1
71}
72
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago73# Puts real wETH runtime bytecode at an address, the way the chain itself would
74# have it. The registry checks EXTCODEHASH, so only genuine bytecode passes —
75# there is no test-only path through the allowlist.
76place_weth() {
77 local rpc=$1 addr=$2 fixture=$3 label=$4
78
79 [[ -f $fixture ]] || {
80 echo "missing fixture $fixture" >&2
81 exit 1
82 }
83
84 cast rpc anvil_setCode "$addr" "$(tr -d '\n' <"$fixture")" --rpc-url "$rpc" >/dev/null
85
86 if [[ $(cast code "$addr" --rpc-url "$rpc") == "0x" ]]; then
87 echo "$label: failed to place wETH at $addr" >&2
88 exit 1
89 fi
90}
91
Merge 2-multichain-check into main 7c6b16b rickub 5h ago92deploy() {
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago93 local rpc=$1 label=$2 weth=$3
94
95 WETH=$weth forge script script/Love.s.sol:LoveScript \
Merge 2-multichain-check into main 7c6b16b rickub 5h ago96 --rpc-url "$rpc" \
97 --private-key "$ANVIL_KEY" \
98 --broadcast \
99 --skip-simulation >"$TMP/deploy-$label.log" 2>&1 ||
100 {
101 echo "deploy on $label failed:" >&2
102 cat "$TMP/deploy-$label.log" >&2
103 exit 1
104 }
105
106 grep -oE 'predicted +0x[0-9a-fA-F]{40}' "$TMP/deploy-$label.log" | tail -1 | grep -oE '0x[0-9a-fA-F]{40}'
107}
108
109report() {
110 local rpc=$1 addr=$2 label=$3
111 local code
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago112
Merge 2-multichain-check into main 7c6b16b rickub 5h ago113 code=$(cast code "$addr" --rpc-url "$rpc")
114
115 if [[ ${#code} -le 2 ]]; then
116 echo "$label: no code at $addr" >&2
117 exit 1
118 fi
119
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago120 printf '%s %s %s bytes %s / %s\n' \
Merge 2-multichain-check into main 7c6b16b rickub 5h ago121 "$label" "$addr" "$(((${#code} - 2) / 2))" \
122 "$(cast call "$addr" 'name()(string)' --rpc-url "$rpc")" \
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago123 "$(cast call "$addr" 'symbol()(string)' --rpc-url "$rpc")"
124 printf '%s registry %s\n' "$label" "$(cast call "$addr" 'REGISTRY()(address)' --rpc-url "$rpc")"
125 printf '%s weth %s\n' "$label" "$(cast call "$addr" 'WETH()(address)' --rpc-url "$rpc")"
Merge 2-multichain-check into main 7c6b16b rickub 5h ago126}
127
128cd "$ROOT"
129
130for cmd in anvil cast forge; do
131 command -v "$cmd" >/dev/null || {
132 echo "$cmd not found — install foundry" >&2
133 exit 1
134 }
135done
136
137start_node "$PORT_A" "$CHAIN_ID_A" "$RPC_A"
138start_node "$PORT_B" "$CHAIN_ID_B" "$RPC_B"
139
140for pair in "A|$RPC_A" "B|$RPC_B"; do
141 IFS='|' read -r label rpc <<<"$pair"
142 if [[ $(cast code "$CREATE2_FACTORY" --rpc-url "$rpc") == "0x" ]]; then
143 echo "$label: deterministic deployer missing at $CREATE2_FACTORY" >&2
144 exit 1
145 fi
146done
147
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago148forge build >"$TMP/build.log" 2>&1 || {
149 cat "$TMP/build.log" >&2
150 exit 1
151}
152
153place_weth "$RPC_A" "$WETH_A" "$FIXTURE_A" A
154place_weth "$RPC_B" "$WETH_B" "$FIXTURE_B" B
Merge 2-multichain-check into main 7c6b16b rickub 5h ago155
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago156ADDR_A=$(deploy "$RPC_A" A "$WETH_A")
157ADDR_B=$(deploy "$RPC_B" B "$WETH_B")
Merge 2-multichain-check into main 7c6b16b rickub 5h ago158
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago159echo "chain $CHAIN_ID_A — OP Stack legacy WETH9 at $WETH_A"
Merge 2-multichain-check into main 7c6b16b rickub 5h ago160report "$RPC_A" "$ADDR_A" " A"
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago161echo "chain $CHAIN_ID_B — canonical WETH9 at $WETH_B"
Merge 2-multichain-check into main 7c6b16b rickub 5h ago162report "$RPC_B" "$ADDR_B" " B"
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago163echo
164
165# macOS ships bash 3.2, which has no ${var,,}.
166lower() { printf '%s' "$1" | tr '[:upper:]' '[:lower:]'; }
167
168WETH_ON_A=$(cast call "$ADDR_A" 'WETH()(address)' --rpc-url "$RPC_A")
169WETH_ON_B=$(cast call "$ADDR_B" 'WETH()(address)' --rpc-url "$RPC_B")
170
171if [[ $(lower "$WETH_ON_A") == "$(lower "$WETH_ON_B")" ]]; then
172 echo "FAIL: both chains ended up on the same wETH — this proves nothing" >&2
173 exit 1
174fi
Merge 2-multichain-check into main 7c6b16b rickub 5h ago175
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago176if [[ $(lower "$ADDR_A") != "$(lower "$ADDR_B")" ]]; then
Merge 2-multichain-check into main 7c6b16b rickub 5h ago177 echo "FAIL: addresses differ" >&2
178 exit 1
179fi
180
Merge 5-weth-bytecode-verification into main 2f6da5e rickub 3h ago181echo "OK: same LOVE address on both chains, backed by different wETH"