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

add multichain deployment check script

julienbrg committed 2026-09-17T21:18:51+02:00 Browse files
201cd45 parent: dded29a
modified .gitignore +1 -0
@@ -5,6 +5,7 @@ out/
55 # Ignores development broadcast logs
66 !/broadcast
77 /broadcast/*/31337/
8+/broadcast/*/31338/
89 /broadcast/**/dry-run/
910
1011 # Docs
@@ -5,6 +5,7 @@ out/
5 # Ignores development broadcast logs5 # Ignores development broadcast logs
6 !/broadcast6 !/broadcast
7 /broadcast/*/31337/7 /broadcast/*/31337/
8+/broadcast/*/31338/
8 /broadcast/**/dry-run/9 /broadcast/**/dry-run/
9 10
10 # Docs11 # Docs
added script/multichain-check.sh +121 -0
new file mode 100755
@@ -0,0 +1,121 @@
1+#!/usr/bin/env bash
2+#
3+# Deploys Love on two local anvil nodes with different chain ids and checks
4+# that CREATE2 gives the token the same address on both.
5+#
6+# Usage: ./script/multichain-check.sh
7+#
8+# Env overrides: PORT_A, PORT_B, CHAIN_ID_A, CHAIN_ID_B, SALT
9+
10+set -euo pipefail
11+
12+PORT_A=${PORT_A:-8545}
13+PORT_B=${PORT_B:-8546}
14+CHAIN_ID_A=${CHAIN_ID_A:-31337}
15+CHAIN_ID_B=${CHAIN_ID_B:-31338}
16+
17+# First anvil dev account — local only, never use this key anywhere else.
18+ANVIL_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
19+CREATE2_FACTORY=0x4e59b44847b379578588920cA78FbF26c0B4956C
20+
21+ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
22+RPC_A="http://127.0.0.1:$PORT_A"
23+RPC_B="http://127.0.0.1:$PORT_B"
24+TMP=$(mktemp -d)
25+PIDS=()
26+
27+cleanup() {
28+ for pid in ${PIDS[@]+"${PIDS[@]}"}; do
29+ kill "$pid" 2>/dev/null || true
30+ done
31+ rm -rf "$TMP"
32+ rm -rf "$ROOT/broadcast/Love.s.sol/$CHAIN_ID_A" "$ROOT/broadcast/Love.s.sol/$CHAIN_ID_B"
33+ rmdir "$ROOT/broadcast/Love.s.sol" "$ROOT/broadcast" 2>/dev/null || true
34+}
35+trap cleanup EXIT
36+
37+start_node() {
38+ local port=$1 chain_id=$2 rpc=$3
39+ anvil --port "$port" --chain-id "$chain_id" --silent >"$TMP/anvil-$port.log" 2>&1 &
40+ PIDS+=($!)
41+
42+ for _ in $(seq 1 50); do
43+ if cast chain-id --rpc-url "$rpc" >/dev/null 2>&1; then
44+ return 0
45+ fi
46+ sleep 0.2
47+ done
48+
49+ echo "anvil on port $port never came up:" >&2
50+ cat "$TMP/anvil-$port.log" >&2
51+ exit 1
52+}
53+
54+deploy() {
55+ local rpc=$1 label=$2
56+ forge script script/Love.s.sol:LoveScript \
57+ --rpc-url "$rpc" \
58+ --private-key "$ANVIL_KEY" \
59+ --broadcast \
60+ --skip-simulation >"$TMP/deploy-$label.log" 2>&1 ||
61+ {
62+ echo "deploy on $label failed:" >&2
63+ cat "$TMP/deploy-$label.log" >&2
64+ exit 1
65+ }
66+
67+ grep -oE 'predicted +0x[0-9a-fA-F]{40}' "$TMP/deploy-$label.log" | tail -1 | grep -oE '0x[0-9a-fA-F]{40}'
68+}
69+
70+report() {
71+ local rpc=$1 addr=$2 label=$3
72+ local code
73+ code=$(cast code "$addr" --rpc-url "$rpc")
74+
75+ if [[ ${#code} -le 2 ]]; then
76+ echo "$label: no code at $addr" >&2
77+ exit 1
78+ fi
79+
80+ printf '%s %s %s bytes %s / %s\n' \
81+ "$label" "$addr" "$(((${#code} - 2) / 2))" \
82+ "$(cast call "$addr" 'name()(string)' --rpc-url "$rpc")" \
83+ "$(cast call "$addr" 'symbol()(string)' --rpc-url "$rpc")"
84+}
85+
86+cd "$ROOT"
87+
88+for cmd in anvil cast forge; do
89+ command -v "$cmd" >/dev/null || {
90+ echo "$cmd not found — install foundry" >&2
91+ exit 1
92+ }
93+done
94+
95+start_node "$PORT_A" "$CHAIN_ID_A" "$RPC_A"
96+start_node "$PORT_B" "$CHAIN_ID_B" "$RPC_B"
97+
98+for pair in "A|$RPC_A" "B|$RPC_B"; do
99+ IFS='|' read -r label rpc <<<"$pair"
100+ if [[ $(cast code "$CREATE2_FACTORY" --rpc-url "$rpc") == "0x" ]]; then
101+ echo "$label: deterministic deployer missing at $CREATE2_FACTORY" >&2
102+ exit 1
103+ fi
104+done
105+
106+forge build >/dev/null
107+
108+ADDR_A=$(deploy "$RPC_A" A)
109+ADDR_B=$(deploy "$RPC_B" B)
110+
111+echo "chain $CHAIN_ID_A"
112+report "$RPC_A" "$ADDR_A" " A"
113+echo "chain $CHAIN_ID_B"
114+report "$RPC_B" "$ADDR_B" " B"
115+
116+if [[ "$ADDR_A" != "$ADDR_B" ]]; then
117+ echo "FAIL: addresses differ" >&2
118+ exit 1
119+fi
120+
121+echo "OK: same address on both chains"
new file mode 100755
@@ -0,0 +1,121 @@
1+#!/usr/bin/env bash
2+#
3+# Deploys Love on two local anvil nodes with different chain ids and checks
4+# that CREATE2 gives the token the same address on both.
5+#
6+# Usage: ./script/multichain-check.sh
7+#
8+# Env overrides: PORT_A, PORT_B, CHAIN_ID_A, CHAIN_ID_B, SALT
9+
10+set -euo pipefail
11+
12+PORT_A=${PORT_A:-8545}
13+PORT_B=${PORT_B:-8546}
14+CHAIN_ID_A=${CHAIN_ID_A:-31337}
15+CHAIN_ID_B=${CHAIN_ID_B:-31338}
16+
17+# First anvil dev account — local only, never use this key anywhere else.
18+ANVIL_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
19+CREATE2_FACTORY=0x4e59b44847b379578588920cA78FbF26c0B4956C
20+
21+ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
22+RPC_A="http://127.0.0.1:$PORT_A"
23+RPC_B="http://127.0.0.1:$PORT_B"
24+TMP=$(mktemp -d)
25+PIDS=()
26+
27+cleanup() {
28+ for pid in ${PIDS[@]+"${PIDS[@]}"}; do
29+ kill "$pid" 2>/dev/null || true
30+ done
31+ rm -rf "$TMP"
32+ rm -rf "$ROOT/broadcast/Love.s.sol/$CHAIN_ID_A" "$ROOT/broadcast/Love.s.sol/$CHAIN_ID_B"
33+ rmdir "$ROOT/broadcast/Love.s.sol" "$ROOT/broadcast" 2>/dev/null || true
34+}
35+trap cleanup EXIT
36+
37+start_node() {
38+ local port=$1 chain_id=$2 rpc=$3
39+ anvil --port "$port" --chain-id "$chain_id" --silent >"$TMP/anvil-$port.log" 2>&1 &
40+ PIDS+=($!)
41+
42+ for _ in $(seq 1 50); do
43+ if cast chain-id --rpc-url "$rpc" >/dev/null 2>&1; then
44+ return 0
45+ fi
46+ sleep 0.2
47+ done
48+
49+ echo "anvil on port $port never came up:" >&2
50+ cat "$TMP/anvil-$port.log" >&2
51+ exit 1
52+}
53+
54+deploy() {
55+ local rpc=$1 label=$2
56+ forge script script/Love.s.sol:LoveScript \
57+ --rpc-url "$rpc" \
58+ --private-key "$ANVIL_KEY" \
59+ --broadcast \
60+ --skip-simulation >"$TMP/deploy-$label.log" 2>&1 ||
61+ {
62+ echo "deploy on $label failed:" >&2
63+ cat "$TMP/deploy-$label.log" >&2
64+ exit 1
65+ }
66+
67+ grep -oE 'predicted +0x[0-9a-fA-F]{40}' "$TMP/deploy-$label.log" | tail -1 | grep -oE '0x[0-9a-fA-F]{40}'
68+}
69+
70+report() {
71+ local rpc=$1 addr=$2 label=$3
72+ local code
73+ code=$(cast code "$addr" --rpc-url "$rpc")
74+
75+ if [[ ${#code} -le 2 ]]; then
76+ echo "$label: no code at $addr" >&2
77+ exit 1
78+ fi
79+
80+ printf '%s %s %s bytes %s / %s\n' \
81+ "$label" "$addr" "$(((${#code} - 2) / 2))" \
82+ "$(cast call "$addr" 'name()(string)' --rpc-url "$rpc")" \
83+ "$(cast call "$addr" 'symbol()(string)' --rpc-url "$rpc")"
84+}
85+
86+cd "$ROOT"
87+
88+for cmd in anvil cast forge; do
89+ command -v "$cmd" >/dev/null || {
90+ echo "$cmd not found — install foundry" >&2
91+ exit 1
92+ }
93+done
94+
95+start_node "$PORT_A" "$CHAIN_ID_A" "$RPC_A"
96+start_node "$PORT_B" "$CHAIN_ID_B" "$RPC_B"
97+
98+for pair in "A|$RPC_A" "B|$RPC_B"; do
99+ IFS='|' read -r label rpc <<<"$pair"
100+ if [[ $(cast code "$CREATE2_FACTORY" --rpc-url "$rpc") == "0x" ]]; then
101+ echo "$label: deterministic deployer missing at $CREATE2_FACTORY" >&2
102+ exit 1
103+ fi
104+done
105+
106+forge build >/dev/null
107+
108+ADDR_A=$(deploy "$RPC_A" A)
109+ADDR_B=$(deploy "$RPC_B" B)
110+
111+echo "chain $CHAIN_ID_A"
112+report "$RPC_A" "$ADDR_A" " A"
113+echo "chain $CHAIN_ID_B"
114+report "$RPC_B" "$ADDR_B" " B"
115+
116+if [[ "$ADDR_A" != "$ADDR_B" ]]; then
117+ echo "FAIL: addresses differ" >&2
118+ exit 1
119+fi
120+
121+echo "OK: same address on both chains"