Skip to content

Latest commit

 

History

History
251 lines (181 loc) · 8.21 KB

File metadata and controls

251 lines (181 loc) · 8.21 KB

Deploy & environment variables

Sub Rosa does not require a committed .env file. Secrets stay out of git; you inject them where each layer runs.

Three layers

Layer Needs env? When vars are read
Hosted pilot UI (apps/web) Optional Build time (VITE_* baked into static JS)
Keeper / appraisal API Yes (secrets) Runtime (shell, systemd, Fly/Railway secrets)
One-off scripts (deploy, e2e) Yes Runtime (inline VAR=… command or CI secrets)

1. Hosted pilot UI - ship without any env

The demo works from embedded DEMO_TRACE (demo-trace.generated.ts from pnpm agents:e2e). No .env needed.

pnpm install
pnpm web:build
# static output → apps/web/dist

Host dist/ on Vercel, Netlify, Cloudflare Pages, GitHub Pages, S3, etc.

Build settings (generic):

Setting Value
Install pnpm install
Build pnpm web:build
Output directory apps/web/dist
Node 22+

2. Hosted pilot UI - optional live contract poll

Only if you want “Poll live contract” on the deployed site, set these before pnpm web:build in the hosting UI (Vercel → Settings → Environment Variables, etc.).

Copy from apps/web/.env.example:

VITE_STELLAR_NETWORK=testnet
VITE_RPC_URL=https://soroban-testnet.stellar.org
VITE_NETWORK_PASSPHRASE="Test SDF Network ; September 2015"
VITE_CONTRACT_ID=CCOVGOQQZJKZ2R55GRWBLTJTGBAMSHXZVN3ICPG3WRVMLMM6RHISC5OV

Core v2 mainnet example:

VITE_STELLAR_NETWORK=mainnet
VITE_RPC_URL=https://mainnet.sorobanrpc.com
VITE_NETWORK_PASSPHRASE="Public Global Stellar Network ; September 2015"
VITE_CONTRACT_ID=CDQOFNCJE5Z4ZZL76DU5652FOUKJVEIZWHFGCZVWH63UYBGPSZIPC325
VITE_ROUND_ID=1

Do not use the legacy v1 mainnet proof as the Core v2 UI contract. Named network configuration validates this boundary at build time.

Important: Vite only exposes vars prefixed with VITE_. They are public in the browser bundle — never put secret keys here.

Local dev (optional)

cp apps/web/.env.example apps/web/.env.local
# edit VITE_* then:
pnpm web:dev

.env.local is gitignored; not required for production.


3. Keeper watch mode (runtime secrets)

Runs on a server/VM, not in the static site. No .env file required — export vars in the process manager:

export KEEPER_SECRET="S…"
export STELLAR_NETWORK=testnet
export WATCH_POLL_MS=15000
export WATCH_ROUND_IDS=1

pnpm keeper:watch

Or one line:

KEEPER_SECRET=S… ROUND_CONTRACT_ID=C… pnpm keeper:watch

For a read-only preflight of one round, no signing secret is required:

KEEPER_DRY_RUN=true ROUND_CONTRACT_ID=C… ROUND_ID=1 pnpm --filter @sub-rosa/keeper start

The command prints a structured JSON summary with the round status, Drand round, bidder/revealed counts, current phase, and next action. It exits without submitting open, reveal, clear, settle, or void transactions.

On Fly.io / Railway / GitHub Actions: put the same names in Secrets, not in the web build.

See root .env.example for the full keeper variable list.


4. Deploy & settle scripts (runtime, inline)

Scripts read env at invocation — no .env file on disk:

pnpm mainnet:v2:prepare # local/read-only; sends no transaction

MAINNET_CONFIRM=SUB_ROSA_MAINNET OPERATOR_IDENTITY=sub-rosa-mainnet-v2-operator \
  pnpm mainnet:v2:deploy

MAINNET_CONFIRM=SUB_ROSA_MAINNET \
  OPERATOR_IDENTITY=sub-rosa-mainnet-v2-operator \
  BIDDER_IDENTITY=sub-rosa-mainnet-v2-bidder \
  ROUND_CONTRACT_ID=C… pnpm mainnet:v2:smoke -- --execute

The named identities can be generated with stellar keys generate NAME --secure-store. Secure-store identities intentionally do not reveal an S... secret; these scripts ask Stellar CLI to sign with the Keychain identity directly. Headless CI may use OPERATOR_SECRET and BIDDER_SECRET instead, but each role must set exactly one identity or secret source.

# Headless CI alternative; inject these from the CI secret store.
OPERATOR_SECRET=S…
BIDDER_SECRET=S…

The deployer pays the WASM upload and deployment fees. During the capped smoke, the seller/operator pays create and lifecycle calls while the bidder pays its commit. The SDK never charges these fees to a Sub Rosa-owned account. Escrow and the auction lot are separate from network fees.

E2E scripts (lifecycle:e2e, agents:e2e) generate ephemeral keys via Stellar CLI — they do not need a root .env either.


5. Appraisal API (if you host it)

Runtime env for pnpm appraisal:start:

Var Purpose
FACILITATOR_SECRET Signs/submits x402 settle txs
PAY_TO / server key Receives USDC
X402_NETWORK stellar:testnet (default) or stellar:pubnet
NETWORK_PASSPHRASE Optional; when set, must match X402_NETWORK
RPC_URL Soroban RPC; required for pubnet
PAYMENT_ASSET SEP-41 contract; defaults to USDC for the selected network
PRICE Appraisal price (default 0.10)
PORT HTTP port (default 4021)

Minimal local/testnet configuration:

export FACILITATOR_SECRET="S…"
export PAY_TO="G…"
export X402_NETWORK="stellar:testnet"
export NETWORK_PASSPHRASE="Test SDF Network ; September 2015"

pnpm appraisal:start

Testnet defaults to the canonical testnet USDC contract, Soroban testnet RPC, price 0.10, and port 4021. For pubnet, set X402_NETWORK=stellar:pubnet, the public-network passphrase, and an explicit RPC_URL; the default payment asset then changes to pubnet USDC.

Configuration errors fail before the HTTP server starts and name the affected variable, for example:

FACILITATOR_SECRET: missing required env var
PRICE: must be a finite number greater than 0
X402_NETWORK: unsupported network "stellar:mainnet"
NETWORK_PASSPHRASE: does not match X402_NETWORK=stellar:testnet
RPC_URL: is required when X402_NETWORK=stellar:pubnet

Agents point at the public URL via X402_APPRAISAL_URL — not baked into the web UI.


Quick decision tree

Shipping the hosted pilot UI only?
  → pnpm web:build, upload dist/, no env

Want live on-chain overlay on the site?
  → set VITE_* in hosting build env, then build

Running keeper 24/7?
  → KEEPER_SECRET + ROUND_CONTRACT_ID on the server (runtime)

Deploying new contract round?
  → mainnet:v2:prepare first; funded signers only for deploy/smoke execution

Mainnet scripts

pnpm mainnet:v2:prepare           # build/hash/bindings; 0 transactions
ROUND_CONTRACT_ID=C… pnpm mainnet:v2:smoke -- --dry-run
MAINNET_CONFIRM=SUB_ROSA_MAINNET OPERATOR_IDENTITY=sub-rosa-mainnet-v2-operator \
  pnpm mainnet:v2:deploy          # funded deployment
MAINNET_CONFIRM=SUB_ROSA_MAINNET \
  OPERATOR_IDENTITY=sub-rosa-mainnet-v2-operator \
  BIDDER_IDENTITY=sub-rosa-mainnet-v2-bidder \
  ROUND_CONTRACT_ID=C… pnpm mainnet:v2:smoke -- --execute

After deployment, verify the exact on-chain WASM before executing the smoke:

ROUND_CONTRACT_ID=CDQOFNCJE5Z4ZZL76DU5652FOUKJVEIZWHFGCZVWH63UYBGPSZIPC325 pnpm mainnet:v2:verify

The historical mainnet:ready, mainnet:verify, mainnet:micro, and mainnet:settle commands target the frozen legacy v1 proof. They are retained for backward compatibility. Prefer the explicit mainnet:legacy:ready, mainnet:legacy:verify, mainnet:legacy:micro, and mainnet:legacy:settle names for historical evidence; they are not the Core v2 launch path.

Mainnet launch checklist

  1. Run pnpm mainnet:v2:prepare; require the built hash to match the testnet-reviewed Core v2 WASM.
  2. Fund separate mainnet operator and bidder accounts. Keep values capped.
  3. Deploy only with MAINNET_CONFIRM=SUB_ROSA_MAINNET and preserve the local deployment artifact.
  4. Set the resulting Core v2 ROUND_CONTRACT_ID, run the secrets-free pnpm mainnet:v2:verify, then run the smoke dry-run.
  5. Execute the capped lifecycle and publish the six transaction links plus verified receipt.
  6. Promote the address into SUB_ROSA_DEPLOYMENTS.mainnet only after independent review of the artifact and evidence.

Security

  • Never commit .env with secrets (already in .gitignore).
  • Never put S… secret keys in VITE_* — they end up in public JS.
  • Rotate any key that was pasted in chat or logs.