We need to collect the following information from the grafana dashboard for the offending withdrawal (as specified in the runbooks for this page).

event_tx_hash=0xe276fb2dea106d7cfeb9ed980101d7c64f5c7f75dafd557bcb6c4c322de280df
withdrawal_hash=0xadea6fbd204cce41eb72e0962a8bd9fc1bd02ffd04fc873e14353a12a78bbda7
proof_submitter=0xb47520aEA870C3fB9715C15fDF255C435F08c6c9

Step 2 - verify the withdrawals

Set l1 and l2 below. Examples are l1=”sepolia” l2=”ink”

echo "INITIAL SETUP"
l1="mainnet"
l2="base"

if [ -z "$l1" ] || [ -z "$l2" ]; then
    echo "ERROR: Variables l1 and/or l2 are not set. Please specify the L1 and L2 chains."
else
    echo "Using L1: $l1, L2: $l2"
		l2_rpc_url="<https://$l2-opn-geth-a-rpc-0-op-geth.primary.$l1.prod.oplabs.cloud>"
		l2_rpc_url_node="<https://$l2-opn-geth-a-rpc-0-op-node.primary.$l1.prod.oplabs.cloud>"
		l1_rpc_url="<https://proxyd-l1-consensus.primary.$l1.prod.oplabs.cloud>"
		superchain_file_url="<https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/refs/heads/main/superchain/configs/$l1/$l2.toml>"
		superchain_file_content=$(curl -s -L $superchain_file_url)
		OPTIMISM_PORTAL_PROXY=$(echo "$superchain_file_content" | sed -n 's/.*OptimismPortalProxy = "\\([^"]*\\)".*/\\1/p')
		L2ToL1MessagePasserAddress="0x4200000000000000000000000000000000000016"
		echo "l2_rpc_url=$l2_rpc_url"
		echo "l2_rpc_url_node=$l2_rpc_url_node"
		echo "l1_rpc_url=$l1_rpc_url"
		echo "OPTIMISM_PORTAL_PROXY=$OPTIMISM_PORTAL_PROXY"
		echo "L2ToL1MessagePasserAddress=$L2ToL1MessagePasserAddress"
		
		check_rpc() {
        url=$1
        response=$(curl -s -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' "$url")
        if echo "$response" | grep -q '"result"'; then
            echo "✅ $url is reachable and responded with chainId."
        else
            echo "❌ $url is NOT reachable or didn't return a valid response."
        fi
    }

    echo "Checking RPC endpoints..."
    check_rpc "$l2_rpc_url"
    check_rpc "$l2_rpc_url_node"
    check_rpc "$l1_rpc_url"
fi

<aside> ⚠️

It may happen the the l2_rpc_url or l2_rpc_url_node generated do not work, because for example they do not follow the name convention. In that case you will need to find the nodes url manually. If for example the name is not correct you may need to look directly into the code. For example for base-mainnet you could look at https://github.com/ethereum-optimism/k8s/blob/935d1f78d8ae3ed41356825d8ba1bae8e78d4de6/kustomize/automated-security-monitoring/oplabs-tools-security/faultproof-withdrawals/overlays/base-mainnet/faultproof-withdrawals.env#L2

and you would see that the nodes used are:

l2_rpc_url_node=https://base-opn-geth-a-rpc-2-op-node.tertiary.mainnet.prod.oplabs.cloud l2_rpc_url=https://base-opn-geth-a-rpc-2-op-geth.tertiary.mainnet.prod.oplabs.cloud

so set those instead manually in the shall

</aside>

l2_rpc_url_node=https://base-opn-geth-a-rpc-2-op-node.tertiary.mainnet.prod.oplabs.cloud
l2_rpc_url=https://base-opn-geth-a-rpc-2-op-geth.tertiary.mainnet.prod.oplabs.cloud

Get the dispute game, setting the withdrawal_hash below


event_signature="WithdrawalProvenExtension1(bytes32,address)"
event_topic=$(cast keccak "$event_signature")
receipt=$(cast receipt $event_tx_hash --rpc-url=$l1_rpc_url --json)
logs=$(echo "$receipt" | jq --arg topic "$event_topic" '.logs[] | select(.topics[0] == $topic)')
  
if [ -z "$logs" ]; then
    echo "Error: No WithdrawalProvenExtension1 events found"
else
		withdrawal_hash_from_topic=$(echo "$logs" | jq -r '.topics[1]')
		proof_submitter_from_topic=$(echo "$logs" | jq -r '.topics[2]')
		output=$(cast call $OPTIMISM_PORTAL_PROXY "provenWithdrawals(bytes32,address)(address,uint64)" $withdrawal_hash $proof_submitter --rpc-url $l1_rpc_url)
		
		read game_proxy_address timestamp <<< "$output"
		
		echo "Withdrawal Hash: $withdrawal_hash_from_topic"
		echo "Proof Submitter: $proof_submitter_from_topic"
		echo "Game Proxy Address: $game_proxy_address" 

		l2_block_number=$(cast call $game_proxy_address "l2BlockNumber()(uint256)" --rpc-url $l1_rpc_url | cut -d' ' -f1)
		l2_block_number_hex=$(printf "0x%X" "$l2_block_number")
		echo "L2 Block Number: $l2_block_number"
		echo "L2 Block Number (Hex): $l2_block_number_hex"
		

		root_claim=$(cast call $game_proxy_address "rootClaim()(bytes32)" --rpc-url $l1_rpc_url)
		echo "Root Claim: $root_claim"
		
		sent_message=$(cast call $L2ToL1MessagePasserAddress "sentMessages(bytes32)(bytes32)" $withdrawal_hash_from_topic --rpc-url $l2_rpc_url)
		if [[ "$sent_message" == "0x0000000000000000000000000000000000000000000000000000000000000001" ]]; then
		    echo "Withdrawal is verified on L2 $l2_rpc_url ✅"
		else
		    echo "Withdrawal is NOT verified on L2 $l2_rpc_url ❌"
**		fi
		
		l2_output_root=$(cast rpc optimism_outputAtBlock "$l2_block_number_hex" --rpc-url $l2_rpc_url_node | jq -r .outputRoot)
		if [[ "$l2_output_root" == "$root_claim" ]]; then
		    echo "$l2_output_root == $root_claim Game Claim is good ✅"
		else
		    echo "$l2_output_root != $root_claim Game Claim is NOT good ❌"
		fi
		
fi