Source mirror · commit 369512f · 2026-10-26 · MIT · canonical repo: gitlab.com/jiapunk/upgrade-airlock
git clone https://upgrade-airlock.pages.dev/source/upgrade-airlock.git
upgrade-airlock / scripts / sepolia / clear.sh
scripts/sepolia/clear.sh43 lines · 2675 bytes
1#!/usr/bin/env bash
2# Manual clearance by the human approver (approver.key): the fallback when the CRE workflow cannot give a verdict
3# (both the listener and the sweeper are down, or the providers are unreachable). A veto still wins: a vetoed
4# proposal cannot be cleared, and a guardian can still veto a cleared one until it executes. The CRE keeps judging
5# it too: until the receiver answers (oracleJudged), the sweeper picks the proposal up, and its veto wins.
6#
7# scripts/sepolia/clear.sh <id> ["note"] # live Sepolia (the approver pays the gas)
8# FORK=19631 scripts/sepolia/clear.sh <id> ["note"]
9#
10# The evidence hash is keccak256 of a small canonical JSON (sorted keys) naming the proposal digest, the approver
11# and the note; the JSON is printed so it can be published next to the transaction.
12source "$(dirname "$0")/lib.sh"
13ID=${1:-}
14NOTE=${2:-manual clearance by the approver}
15[[ "$ID" =~ ^[0-9]+$ ]] || die "usage: [FORK=<port>] $0 <proposal id> [note]"
16check_rpc
17GA=$(dep airlockAdmin)
18APPROVER=$(addr_of approver)
19[ "$(lc "$(cast call "$GA" 'approver()(address)' --rpc-url "$RPC")")" = "$(lc "$APPROVER")" ] || die "approver.key is not AirlockAdmin.approver()"
20read -r KIND ST TARGET READY _ _ < <(proposal "$ID")
21case "$ST" in
22 0) die "proposal #$ID does not exist" ;;
23 2) die "#$ID is Vetoed; a veto cannot be overridden by a clearance" ;;
24 3) die "#$ID was already executed" ;;
25esac
26CL=$(clearance "$ID")
27[ "$CL" = "$ZERO32" ] || { say "#$ID is already cleared (evidence $CL)"; exit 0; }
28DIGEST=$(cast call "$GA" 'proposalDigest(uint256)(bytes32)' "$ID" --rpc-url "$RPC")
29EVIDENCE=$(jq -cnS --arg a "$(lc "$GA")" --arg id "$ID" --arg d "$DIGEST" --arg by "$(lc "$APPROVER")" --arg n "$NOTE" \
30 '{airlockAdmin: $a, by: $by, chainId: 11155111, note: $n, proposalDigest: $d, proposalId: $id, verdict: "manual-clear"}')
31EH=$(cast keccak "$EVIDENCE")
32if [ "$MODE" = fork ]; then
33 [ "$(cast balance "$APPROVER" --rpc-url "$RPC")" != 0 ] || cast rpc anvil_setBalance "$APPROVER" 0x56bc75e2d63100000 --rpc-url "$RPC" >/dev/null
34fi
35say "approver $APPROVER clears #$ID (${KIND_NAMES[$KIND]} $(impl_name "$TARGET")) on $NET"
36say " evidence $EVIDENCE"
37RCPT=$(send_as approver "$GA" 'clear(uint256,bytes32)' "$ID" "$EH")
38TX=$(jq -r .transactionHash <<<"$RCPT")
39[ "$(jq -r .status <<<"$RCPT")" = 0x1 ] || die "clear failed: $(tx_ref "$TX")"
40say "CLEARED #$ID by the approver, evidence hash $EH"
41say " tx $(tx_ref "$TX")"
42say " executable from block $READY: ${FORK:+FORK=$FORK }scripts/sepolia/execute.sh $ID"
43[ "$(oracle_judged "$ID")" = true ] || say " the CRE still judges #$ID (the sweeper, or sweep.sh); a CRE veto wins over this clearance"