| Merge 2-multichain-check into main 7c6b16b rickub 9h ago | 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" |