Repository navigation
Expand file tree
/
Copy path.env.testnet.example
More file actions
385 lines (342 loc) · 18.1 KB
/
Copy path.env.testnet.example
File metadata and controls
385 lines (342 loc) · 18.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# ─── Read replicas (#411) ─────────────────────────────────────────────────────
DATABASE_REPLICA_URLS=
MAX_REPLICA_LAG_MS=5000
# ─── Cursor HMAC secret (#412) ────────────────────────────────────────────────
CURSOR_HMAC_SECRET=dev-cursor-hmac-secret-do-not-use-in-prod
# ─── Cold-storage archival (#413) ─────────────────────────────────────────────
ARCHIVAL_ENABLED=false
ARCHIVAL_BUCKET_NAME=vortex-archives-testnet
ARCHIVAL_S3_ENDPOINT=http://localhost:9000
ARCHIVAL_S3_REGION=us-east-1
ARCHIVAL_S3_ACCESS_KEY_ID=minioadmin
ARCHIVAL_S3_SECRET_ACCESS_KEY=minioadmin
ARCHIVAL_RETENTION_DAYS=30
ARCHIVAL_PARTITION_PREFIX=date=
ARCHIVAL_MAX_ROWS_PER_FILE=100000
# .env.testnet.example
#
# Environment template for LOCAL DEVELOPMENT against Stellar TESTNET.
# Copy to .env and fill in any values marked with <CHANGE_ME>.
#
# cp .env.testnet.example .env
#
# Testnet is safe to experiment with — tokens have no real value and contract
# deployments are free via Friendbot. Never reuse testnet keys on mainnet.
#
# Closes #136
# ─── Database ────────────────────────────────────────────────────────────────
# Local Docker Compose default. Adjust if you use a remote or managed DB.
DATABASE_URL=postgresql://vortex:vortex@localhost:5432/vortex?schema=public
# ─── Server ──────────────────────────────────────────────────────────────────
PORT=4000
NODE_ENV=development
# ─── Stellar / Soroban ───────────────────────────────────────────────────────
STELLAR_NETWORK=testnet
INTENTS_PERSISTENCE=prisma
ETHEREUM_RPC_URL=
ETHEREUM_ESCROW_ADDRESS=
BASE_RPC_URL=
BASE_ESCROW_ADDRESS=
POLYGON_RPC_URL=
POLYGON_ESCROW_ADDRESS=
ARBITRUM_RPC_URL=
ARBITRUM_ESCROW_ADDRESS=
OPTIMISM_RPC_URL=
OPTIMISM_ESCROW_ADDRESS=
AVALANCHE_RPC_URL=
AVALANCHE_ESCROW_ADDRESS=
EVM_RPC_ALLOWLIST=
ALLOW_LEGACY_STELLAR_SIGNATURES=false
SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
# Testnet contract IDs — leave blank until you have deployed contracts.
# The service boots without them; on-chain write paths are no-ops when empty.
SETTLEMENT_CONTRACT_ID=
SOLVER_REGISTRY_CONTRACT_ID=
# Testnet signing key — generate a throwaway keypair, fund it with Friendbot,
# and paste the secret seed here. Never reuse this key on mainnet.
#
# # Generate a new key:
# npx @stellar/stellar-cli keys generate local-dev --network testnet
# npx @stellar/stellar-cli keys show local-dev
#
# # Or via the SDK:
# node -e "console.log(require('@stellar/stellar-sdk').Keypair.random().secret())"
#
# # Fund it (testnet only):
# curl "https://friendbot.stellar.org/?addr=<YOUR_PUBLIC_KEY>"
#
# Optional in development — leave blank to skip on-chain writes.
SOROBAN_SIGNING_KEY=
# Fee percentile used when estimating Soroban inclusion fees.
# p50 is a safe default for testnet; raise to p90+ for time-sensitive mainnet txs.
SOROBAN_FEE_PERCENTILE=p50
# ─── CORS ────────────────────────────────────────────────────────────────────
# Wildcard is fine for local development — tighten this in staging/production.
CORS_ORIGIN=*
# ─── WebSocket ───────────────────────────────────────────────────────────────
WS_MAX_CONNECTIONS=1000
QUOTE_AUCTION_WINDOW_MS=300
# WebSocket replay store: 'memory' (default) or 'redis'
WS_REPLAY_STORE=memory
# Maximum number of events to retain in the replay buffer
WS_REPLAY_MAX_COUNT=500
# Maximum age of events in milliseconds (optional, omit to disable)
# WS_REPLAY_MAX_AGE_MS=300000
# ─── Pluggable signer backend (issue #400) ───────────────────────────────────
# SIGNER_BACKEND=local is the default for development.
# In production use SIGNER_BACKEND=vault and supply VAULT_ADDR + VAULT_TOKEN.
SIGNER_BACKEND=local
VAULT_ADDR=
VAULT_TOKEN=
VAULT_TRANSIT_KEY_NAME=vortex-signer
ALLOW_LOCAL_SIGNER_IN_PROD=false
# ─── Resource-exhaustion limits (issue #476) ─────────────────────────────────
# Maximum JSON nesting depth — rejects deeply-nested body attacks (default 10).
JSON_MAX_DEPTH=10
# Maximum chain values in a single WS subscribe message (default 20).
WS_MAX_FILTER_CHAINS=20
# Maximum active subscriptions per WS connection (default 10).
WS_MAX_SUBSCRIPTIONS=10
# Postgres statement_timeout for standard queries in ms (default 5000).
DB_QUERY_TIMEOUT_MS=5000
# Postgres statement_timeout for batch queries in ms (default 10000).
DB_BATCH_QUERY_TIMEOUT_MS=10000
# Postgres statement_timeout for stats queries in ms (default 15000).
DB_STATS_QUERY_TIMEOUT_MS=15000
# Emergency kill-switch (issue #477)
# Postgres-backed so a pause survives a restart and reaches every replica.
KILLSWITCH_OPERATOR_TOKEN=
KILLSWITCH_REDIS_URL=
KILLSWITCH_POLL_MS=2000
KILLSWITCH_PERSISTENCE=prisma
# ─── Observability (optional) ────────────────────────────────────────────────
# Leave blank to disable Sentry error reporting.
SENTRY_DSN=
# ─── Metrics access control (issue #298) ─────────────────────────────────────
# Bearer token required for GET /metrics. Empty = endpoint disabled (403).
# Generate with: openssl rand -hex 32
METRICS_TOKEN=
# debug | info | warn | error (defaults to "debug" in development)
LOG_LEVEL=debug
# Structured JSON logs for the collector (issue #488).
LOG_FORMAT=json
# ── Shadow-mode divergence monitor (issue #401) ─────────────────────────
# Off by default in every environment. It runs read-only `simulateTransaction`
# calls against SETTLEMENT_CONTRACT_ID in parallel with the off-chain intent
# path and never signs or submits anything.
#
# SHADOW_SOURCE_ACCOUNT only has to be a valid Stellar public key: it is used to
# populate the source-account field of the simulated envelope and is never
# signed, never charged a fee and never broadcast. It must still be set, or
# every transition reports "contract_unconfigured".
SHADOW_MODE_ENABLED=false
SHADOW_SAMPLE_RATE=1
SHADOW_QUEUE_MAX=256
SHADOW_CONCURRENCY=4
SHADOW_SOURCE_ACCOUNT=
# ─── Governance / Protocol Parameters ────────────────────────────────────────
# On-chain governance parameters contract ID — leave blank to use code defaults.
PARAMS_CONTRACT_ID=
# Poll interval in ms. 30 000 is fine for testnet.
PARAMS_POLL_INTERVAL_MS=30000
# ─── Leader election ─────────────────────────────────────────────────────────
# Enable for multi-replica testnet deployments.
LEADER_ELECTION_ENABLED=false
LEADER_ELECTION_HEARTBEAT_MS=5000
# ─── Background jobs (issue #494) ────────────────────────────────────────────
# api | worker | all — queue workers only run in "worker" or "all".
PROCESS_ROLE=all
# memory (single-process, dev/test) | bullmq (Redis-backed, uses REDIS_URL)
JOBS_DRIVER=memory
# Grace period for in-flight jobs on SIGTERM before they are returned to the queue.
JOBS_SHUTDOWN_TIMEOUT_MS=25000
# ─── Runtime feature flags (issue #495) ──────────────────────────────────────
# Change propagation across instances: memory (single instance) | redis
FLAGS_PUBSUB=memory
# Safety-net cache reload interval (ms)
FLAGS_REFRESH_MS=30000
# Break-glass pins that win over DB state, e.g. onchain-dry-run=true
FLAG_OVERRIDES=
# ─── Admin RBAC ──────────────────────────────────────────────────────────────
# Comma-separated id:role:secret (role = admin | superadmin, secret >= 16 chars).
# Sent as the x-admin-key header (the secret part). Empty disables admin APIs.
ADMIN_API_KEYS=
# ─── Guardian emergency ingestion (issue #507) ───────────────────────────────
# Guardian / security-council contract ID. Leave blank to disable ingestion.
GUARDIAN_CONTRACT_ID=
# ─── Synthetic canary (issue #496) ───────────────────────────────────────────
# Canary user + solver addresses; excluded from public stats and leaderboards.
CANARY_ADDRESSES=
# Public anonymised datasets (docs/rfcs/0001)
# Master switch for the public dataset publication job.
DATASETS_ENABLED=false
# Hash user addresses with the rotating salt before export.
DATASETS_ANONYMIZE=true
# Base anonymisation salt. Required (>= 32 chars) when datasets are enabled
# and anonymisation is on; generate with `openssl rand -hex 32`.
DATASETS_SALT=
# How often the anonymisation salt rotates, in hours.
DATASETS_SALT_ROTATION_HOURS=24
# How many previous salt windows are retained for continuity.
DATASETS_SALT_RETENTION_WINDOWS=2
# Public bucket/prefix the published datasets live under.
DATASETS_PUBLIC_BUCKET=vortex-public-datasets
# Storage backend: local (writes to disk) | memory (tests only).
DATASETS_STORAGE=local
# Root directory for the local storage backend.
DATASETS_LOCAL_DIR=.datasets
# Widest range, in UTC days, the on-demand admin dataset export accepts.
DATASETS_EXPORT_MAX_DAYS=31
# Secrets Manager (issue #465)
# Provider: env | aws-secrets-manager | vault-kv
SECRETS_PROVIDER=env
# Poll interval for secret rotation (ms)
SECRETS_REFRESH_INTERVAL_MS=60000
# Extra secrets: comma-separated "name:envVar:required"
SECRETS_EXTRA=
# AWS Secrets Manager
AWS_SECRETS_MANAGER_PREFIX=
AWS_SECRETS_MANAGER_POLL_INTERVAL_MS=60000
# Vault KV
VAULT_KV_MOUNT=secret
VAULT_KV_PREFIX=vortex/
VAULT_KV_POLL_INTERVAL_MS=60000
# Extra secret env vars referenced by the default SecretConfig
JWT_SIGNING_KEY=
WEBHOOK_SECRET=
CHANNEL_KEY=
# Egress/SSRF Protection
EGRESS_TIMEOUT_MS=10000
EGRESS_MAX_REDIRECTS=3
EGRESS_MAX_BODY_SIZE_BYTES=10485760
SOROBAN_RPC_ALLOWLIST=soroban-testnet.stellar.org,soroban-rpc.stellar.org
WEBHOOK_ALLOWLIST=hooks.example.com,hooks.trusted.com
ORACLE_ALLOWLIST=oracle.trusted.io
# Oracle minDstAmount gates (issue #434). Slippage/premium in basis points.
MAX_USER_SLIPPAGE_BPS=100
MAX_PREMIUM_BPS=50
ORACLE_FAIL_OPEN_MAX_USD=100
ORACLE_MAX_STALENESS_MS=60000
# ─── WS gateway hardening (issue #455) ───────────────────────────────────────
# Inbound frames larger than this close the socket (1009).
WS_MAX_PAYLOAD_BYTES=16384
# Concurrent WS connections per client IP (0 = unlimited).
WS_MAX_CONNECTIONS_PER_IP=20
# Trusted reverse-proxy hops for X-Forwarded-For (0 = socket address only).
WS_TRUST_PROXY_HOPS=0
# Inbound token bucket per connection; repeat violators are disconnected.
WS_RATE_LIMIT_PER_SEC=10
WS_RATE_LIMIT_BURST=20
WS_RATE_LIMIT_MAX_VIOLATIONS=5
# Outbound backpressure: messages held per slow consumer, socket buffer
# threshold (bytes), and what to do when the queue is full.
WS_OUTBOUND_QUEUE_MAX=1000
WS_OUTBOUND_BUFFER_BYTES=1048576
WS_SLOW_CONSUMER_POLICY=drop_oldest
# HS256 secret for solver JWTs from the SEP-10 auth flow (#442); >= 32 chars.
# Empty disables JWT auth on the WS gateway.
AUTH_JWT_SECRET=
# ─── SEP-10 solver authentication (issue #442) ────────────────────────────────
# Home domain bound into the challenge (`<domain> auth` manage-data operation).
SEP10_HOME_DOMAIN=localhost
# Ed25519 PKCS#8 private key signing the 15-minute session JWTs — REQUIRED in
# production (generate: openssl genpkey -algorithm ed25519). Must be distinct
# from STELLAR_SIGNER_SECRET_KEY.
SEP10_JWT_SIGNING_KEY=
# Comma-separated G-addresses issued role=admin. Empty = nobody.
SEP10_ADMIN_ACCOUNTS=
# Single-use challenge nonce store: memory | redis. Use redis in multi-replica
# deployments so a captured challenge cannot be replayed on another replica.
SEP10_NONCE_STORE=memory
# ─── API keys & distributed rate limiting (issue #441) ─────────────────────────
RATE_LIMIT_LOCAL_PRUNE_MS=60000
# Redis URL for the shared rate-limit window. Empty = bounded local limiter.
RATE_LIMIT_REDIS_URL=
# ─── Scoped solver credentials (issue #443) ───────────────────────────────────
CREDENTIAL_REVOCATION_PUBSUB=memory
# ─── SSE intent feed (issue #433) ─────────────────────────────────────────────
SSE_HEARTBEAT_MS=15000
SSE_MAX_BUFFER_BYTES=1048576
# ─── Public anonymised datasets ──────────────────────────────────────────────
DATASETS_ENABLED=false
DATASETS_ANONYMIZE=true
DATASETS_SALT=
DATASETS_SALT_ROTATION_HOURS=24
DATASETS_SALT_RETENTION_WINDOWS=2
DATASETS_PUBLIC_BUCKET=
DATASETS_STORAGE_KIND=memory
DATASETS_LOCAL_DIR=
# ─── Health probes (issue #492) ──────────────────────────────────────────────
# Roles served by this process (api, ws, worker); readiness checks follow them.
SERVICE_ROLES=api,ws,worker
HEALTH_CHECK_INTERVAL_MS=5000
# Readiness hysteresis: failures before not-ready, successes before ready again.
HEALTH_READY_FAILURE_THRESHOLD=3
HEALTH_READY_SUCCESS_THRESHOLD=2
# Liveness fails when event-loop delay exceeds this.
HEALTH_EVENT_LOOP_MAX_LAG_MS=1000
# Soroban RPC endpoints for the quorum check (default: SOROBAN_RPC_URL).
SOROBAN_RPC_HEALTH_URLS=
# ── Read models & idempotency (issues #414, #416, #418) ───────────────────────
# Multi-replica deploys: shared Redis cache, Postgres-backed idempotency keys.
CACHE_DRIVER=memory
CACHE_TTL_SECONDS=15
CACHE_TTL_JITTER=0.1
STATS_SOURCE=auto
STATS_VIEW_REFRESH_INTERVAL_MS=30000
IDEMPOTENCY_STORE=auto
IDEMPOTENCY_TTL_SECONDS=86400
IDEMPOTENCY_LEASE_SECONDS=30
IDEMPOTENCY_CLEANUP_INTERVAL_MS=3600000
# ── intent_audit_log monthly partitions (issue #407) ─────────────────────────
# The leader creates partitions AUDIT_PARTITION_PREMAKE_MONTHS ahead. With
# AUDIT_RETENTION_MONTHS > 0, older partitions are detached and exported to the
# archival bucket (ARCHIVAL_*), and kept as tables unless
# AUDIT_RETENTION_DROP_AFTER_EXPORT=true. See RUNBOOK_BACKUP_RESTORE.md.
AUDIT_PARTITION_MAINTENANCE_ENABLED=true
AUDIT_PARTITION_INTERVAL_MS=21600000
AUDIT_PARTITION_PREMAKE_MONTHS=3
AUDIT_RETENTION_MONTHS=0
AUDIT_RETENTION_DROP_AFTER_EXPORT=false
# ── Contract-state TTL keeper (issue #395) ───────────────────────────────────
# Extends the TTL of protocol-owned persistent entries (contract instances and
# WASM code, active intents, active solver bonds) before they archive. Submits
# paid ExtendFootprintTTL transactions, so it is off by default. Runs on the
# elected leader only. Ledger counts assume ~5 s ledgers (17,280 per day).
TTL_KEEPER_ENABLED=false
TTL_KEEPER_INTERVAL_MS=3600000
TTL_KEEPER_THRESHOLD_LEDGERS=120960
TTL_KEEPER_EXTEND_TO_LEDGERS=518400
TTL_KEEPER_DAILY_BUDGET_STROOPS=50000000
TTL_KEEPER_MAX_KEYS_PER_TX=20
# Contract DataKey variant names used to derive intent / bond ledger keys.
TTL_KEEPER_INTENT_KEY_VARIANT=Intent
TTL_KEEPER_BOND_KEY_VARIANT=Bond
# ── Epoch → timestamptz migration (issue #409) ───────────────────────────────
# Where epoch timestamps are read from while both columns exist. Switch to
# `timestamptz` only after `npm run db:backfill-timestamps -- --verify` reports
# zero rows out of sync. Writes always go to both columns.
TIMESTAMP_READ_SOURCE=epoch
# ─── Destination preflight (issue #439) ─────────────────────────────────────
# Check the user's Stellar account exists and can receive minDstAmount of the
# destination asset (trustline, authorization, remaining limit) before an
# intent is listed and again at accept time.
DST_PREFLIGHT_ENABLED=true
# Let creation through (logged) when Horizon is unreachable.
DST_PREFLIGHT_FAIL_OPEN=true
DST_PREFLIGHT_CACHE_TTL_MS=30000
# ─── Webhooks (issue #432) ──────────────────────────────────────────────────
# memory (default, dev/test) | prisma (durable; required for multi-replica)
WEBHOOKS_PERSISTENCE=prisma
WEBHOOK_TIMEOUT_MS=5000
WEBHOOK_MAX_RETRIES=5
WEBHOOK_BACKOFF_BASE_MS=30000
WEBHOOK_DISABLE_AFTER_FAILURES=10
WEBHOOK_CONCURRENCY=16
# Permit http:// and private-network targets. Local development only;
# rejected when NODE_ENV=production.
WEBHOOK_ALLOW_INSECURE_URLS=false
# ─── Partial fills (issue #427) ─────────────────────────────────────────────
PARTIAL_FILLS_ENABLED=true
# The settlement contract has no partial-fill entrypoints yet; keep false.
PARTIAL_FILLS_ONCHAIN_ENABLED=false