#!/usr/bin/env bash # # Deploys Love on two local anvil nodes with different chain ids and checks # that CREATE2 gives the token the same address on both. The address embeds the # wETH address, so this only holds for chains sharing one wETH deployment — # both nodes here are given the same WETH. # # Usage: ./script/multichain-check.sh # # Env overrides: PORT_A, PORT_B, CHAIN_ID_A, CHAIN_ID_B, SALT, WETH set -euo pipefail PORT_A=${PORT_A:-8545} PORT_B=${PORT_B:-8546} CHAIN_ID_A=${CHAIN_ID_A:-31337} CHAIN_ID_B=${CHAIN_ID_B:-31338} # First anvil dev account — local only, never use this key anywhere else. ANVIL_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 CREATE2_FACTORY=0x4e59b44847b379578588920cA78FbF26c0B4956C ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) RPC_A="http://127.0.0.1:$PORT_A" RPC_B="http://127.0.0.1:$PORT_B" TMP=$(mktemp -d) PIDS=() cleanup() { for pid in ${PIDS[@]+"${PIDS[@]}"}; do kill "$pid" 2>/dev/null || true done rm -rf "$TMP" rm -rf "$ROOT/broadcast/Love.s.sol/$CHAIN_ID_A" "$ROOT/broadcast/Love.s.sol/$CHAIN_ID_B" rmdir "$ROOT/broadcast/Love.s.sol" "$ROOT/broadcast" 2>/dev/null || true } trap cleanup EXIT start_node() { local port=$1 chain_id=$2 rpc=$3 anvil --port "$port" --chain-id "$chain_id" --silent >"$TMP/anvil-$port.log" 2>&1 & PIDS+=($!) for _ in $(seq 1 50); do if cast chain-id --rpc-url "$rpc" >/dev/null 2>&1; then return 0 fi sleep 0.2 done echo "anvil on port $port never came up:" >&2 cat "$TMP/anvil-$port.log" >&2 exit 1 } deploy() { local rpc=$1 label=$2 forge script script/Love.s.sol:LoveScript \ --rpc-url "$rpc" \ --private-key "$ANVIL_KEY" \ --broadcast \ --skip-simulation >"$TMP/deploy-$label.log" 2>&1 || { echo "deploy on $label failed:" >&2 cat "$TMP/deploy-$label.log" >&2 exit 1 } grep -oE 'predicted +0x[0-9a-fA-F]{40}' "$TMP/deploy-$label.log" | tail -1 | grep -oE '0x[0-9a-fA-F]{40}' } report() { local rpc=$1 addr=$2 label=$3 local code code=$(cast code "$addr" --rpc-url "$rpc") if [[ ${#code} -le 2 ]]; then echo "$label: no code at $addr" >&2 exit 1 fi printf '%s %s %s bytes %s / %s weth %s\n' \ "$label" "$addr" "$(((${#code} - 2) / 2))" \ "$(cast call "$addr" 'name()(string)' --rpc-url "$rpc")" \ "$(cast call "$addr" 'symbol()(string)' --rpc-url "$rpc")" \ "$(cast call "$addr" 'weth()(address)' --rpc-url "$rpc")" } cd "$ROOT" for cmd in anvil cast forge; do command -v "$cmd" >/dev/null || { echo "$cmd not found — install foundry" >&2 exit 1 } done start_node "$PORT_A" "$CHAIN_ID_A" "$RPC_A" start_node "$PORT_B" "$CHAIN_ID_B" "$RPC_B" for pair in "A|$RPC_A" "B|$RPC_B"; do IFS='|' read -r label rpc <<<"$pair" if [[ $(cast code "$CREATE2_FACTORY" --rpc-url "$rpc") == "0x" ]]; then echo "$label: deterministic deployer missing at $CREATE2_FACTORY" >&2 exit 1 fi done forge build >/dev/null ADDR_A=$(deploy "$RPC_A" A) ADDR_B=$(deploy "$RPC_B" B) echo "chain $CHAIN_ID_A" report "$RPC_A" "$ADDR_A" " A" echo "chain $CHAIN_ID_B" report "$RPC_B" "$ADDR_B" " B" if [[ "$ADDR_A" != "$ADDR_B" ]]; then echo "FAIL: addresses differ" >&2 exit 1 fi echo "OK: same address on both chains"