-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy path.env.example
More file actions
314 lines (291 loc) · 16 KB
/
Copy path.env.example
File metadata and controls
314 lines (291 loc) · 16 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
# Supabase Configuration
# You can find these values in your Supabase Dashboard under Project Settings > API
NEXT_PUBLIC_SUPABASE_URL=your-project-url-here.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-here
# Application Configuration
# This is used for OAuth redirects and email confirmation links
# Local development: http://localhost:3000
# Production: https://your-domain.com
NEXT_PUBLIC_SITE_URL=http://localhost:3000
# Email notifications via Resend
# Used for loan approved, loan funded, and payment overdue emails.
RESEND_API_KEY=
RESEND_FROM_EMAIL=TrustLend <notifications@your-domain.com>
RESEND_REPLY_TO_EMAIL=
# Stellar Testnet Configuration
# These values will be used by wallet setup, balance reads, and future Soroban contract interactions.
NEXT_PUBLIC_STELLAR_NETWORK=testnet
NEXT_PUBLIC_STELLAR_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
# ── Mobile wallets via WalletConnect ──────────────────────────────────────────
# Lets users connect a mobile Stellar wallet (LOBSTR, Freighter Mobile, …) by
# scanning a QR code, instead of needing a browser extension.
#
# Create a free project at https://cloud.reown.com (formerly WalletConnect Cloud)
# and paste its Project ID here. Add your deployed origin to the project's
# allowed domains, otherwise the relay rejects the pairing.
#
# Leave blank to hide/disable the WalletConnect option; the extension wallets
# (Freighter, xBull) and Albedo keep working either way.
#
# The WalletConnect session is negotiated on the network implied by
# NEXT_PUBLIC_STELLAR_NETWORK_PASSPHRASE above (pubnet for mainnet, otherwise
# testnet), so keep that value in sync with the network you expect wallets on.
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=
# ── Sign-In with Stellar (SIWS / SEP-0010) ────────────────────────────────────
# Web3-native login: users authenticate by signing a challenge with Freighter
# instead of a password. See lib/auth/siws-*.ts and app/api/auth/siws/*.
#
# Domain the SEP-10 challenge is bound to (home_domain / web_auth_domain).
# Both the challenge builder and verifier must use the same value. Defaults to
# the host of NEXT_PUBLIC_SITE_URL if unset.
NEXT_PUBLIC_SIWS_DOMAIN=localhost:3000
#
# SEP-10 server signing key (S...). SERVER-ONLY — generate a dedicated key,
# never reuse the platform admin key. stellar keys generate trustlend-siws --global
SIWS_SERVER_SECRET=
#
# Secret used to deterministically derive each wallet's Supabase auth password
# (HMAC-SHA256 of the address). SERVER-ONLY — use a long random value and never
# rotate without a migration plan (rotating invalidates existing wallet logins).
SIWS_PASSWORD_SECRET=
NEXT_PUBLIC_STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org
NEXT_PUBLIC_STELLAR_FRIENDBOT_URL=https://friendbot.stellar.org
# Auth Role Persistence
# These keys are used internally to manage role-based redirects
NEXT_PUBLIC_PENDING_ROLE_KEY=trustlend_pending_role
# Comma-separated allowlist for Trade Vault admin panel access
# Example: admin1@tradevault.com,admin2@tradevault.com
TRADE_VAULT_ADMIN_EMAILS=
# ── Soroban RPC ───────────────────────────────────────────────────────────────
# Testnet Soroban RPC endpoint (no API key required for testnet)
NEXT_PUBLIC_SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
# ── Soroban Contract IDs ──────────────────────────────────────────────────────
# These IDs are generated when deploying contracts to the Stellar network.
# One command deploys everything and fills these in automatically:
#
# npm run deploy:testnet
#
# It writes the IDs straight into .env.local (updating these keys in place and
# leaving your other values alone), plus a reference copy in .env.contracts.
# Preview it first with `npm run deploy:testnet:dry`, or see all options with
# npm run deploy:testnet -- --help
NEXT_PUBLIC_REPUTATION_CONTRACT_ID=
NEXT_PUBLIC_ESCROW_CONTRACT_ID=
NEXT_PUBLIC_LENDING_CONTRACT_ID=
NEXT_PUBLIC_DEFAULT_CONTRACT_ID=
# Utilization-based interest-rate pool backing the lender pool screens.
NEXT_PUBLIC_POOLED_LENDING_CONTRACT_ID=
# DAO governance module controlling the platform fee (issue #22).
NEXT_PUBLIC_GOVERNANCE_CONTRACT_ID=
# N-of-M multisig gating rare, high-impact admin config changes (issue #73):
# whitelisting collateral assets, fee tables, linking governance/oracle, and
# moving insurance-fund balances. See docs/contracts/multisig-admin.md.
NEXT_PUBLIC_MULTISIG_ADMIN_CONTRACT_ID=
# TLEND governance token and its distribution contracts (issue #107). Optional —
# the core lending flows work without them.
NEXT_PUBLIC_TLEND_TOKEN_CONTRACT_ID=
NEXT_PUBLIC_TLEND_VESTING_CONTRACT_ID=
NEXT_PUBLIC_TLEND_AIRDROP_CONTRACT_ID=
# ── Admin Stellar Address ─────────────────────────────────────────────────────
# This is the public G... address of the account that has administrative
# privileges on the contracts (e.g., freezing accounts, triggering payouts).
# Obtain this by running `stellar keys address trustlend-admin` or similar.
NEXT_PUBLIC_ADMIN_ADDRESS=
# ── Backend automation: cron jobs ─────────────────────────────────────────────
# Shared secret the serverless crons require in the Authorization header
# (`Bearer <CRON_SECRET>`). Set the same value in your Vercel Cron / scheduler.
CRON_SECRET=
# Admin Stellar SECRET key (S...) used by the Default-Management cron to sign
# mark_defaulted / record_default on-chain, and to PROPOSE (not execute)
# insurance payouts on the MultiSigAdmin contract (issue #73) — this key must
# itself be a registered multisig signer for that proposal to succeed. A human
# still has to gather the remaining approvals and call `execute`.
# SERVER-ONLY — never prefix with NEXT_PUBLIC_ and never commit a real value.
ADMIN_SECRET_KEY=
# Default-Management automation thresholds (days overdue). Optional — these are
# the defaults; the friendly grace window ends day 7, insurance pays at day 60.
DEFAULT_GRACE_PERIOD_DAYS=7
DEFAULT_INSURANCE_PAYOUT_DAYS=60
# Supabase service-role key — required by all crons for trusted DB access.
SUPABASE_SERVICE_ROLE_KEY=
# ── Decentralized Credit Oracle ───────────────────────────────────────────────
# The authorized oracle is the only account allowed to post off-chain credit
# scores on-chain (via `submit_credit_score`). Register it once after deploy:
# stellar contract invoke --id <REPUTATION_ID> -- set_oracle \
# --admin <ADMIN_ADDRESS> --oracle <ORACLE_ADDRESS>
#
# Public G... address of the oracle (safe to expose to the browser).
NEXT_PUBLIC_ORACLE_ADDRESS=
#
# Secret S... key of the oracle — used by scripts/oracle-post-credit-score.mjs
# to sign on-chain posts. SERVER-ONLY. Never prefix with NEXT_PUBLIC_ and never
# commit this. Generate with: stellar keys generate trustlend-oracle --global
ORACLE_SECRET_KEY=
# ── Liquidation Keeper (scripts/liquidation-keeper.ts) ────────────────────────
# Automated bot that liquidates under-collateralized loans. Deployed as a
# background worker that monitors every minute: vercel.json schedules
# POST /api/cron/liquidation on "* * * * *" (authenticated with Bearer CRON_SECRET,
# same as the other crons) — or run `npm run liquidation:keeper:service`
# (--interval=60) self-hosted. One-shot `npm run liquidation:keeper` remains
# available for cron schedulers. Requires ADMIN_SECRET_KEY (above) to sign
# liquidation transactions, plus NEXT_PUBLIC_LENDING_CONTRACT_ID /
# NEXT_PUBLIC_REPUTATION_CONTRACT_ID / NEXT_PUBLIC_ADMIN_ADDRESS.
#
# Where to source open loans from: "db" (Supabase, default) or "chain"
# (iterate the LendingContract directly — no Supabase needed).
LIQUIDATION_SOURCE=db
# Evaluate only; never submit a liquidation transaction. Useful for staging.
LIQUIDATION_DRY_RUN=false
# If set, the keeper loops forever, sleeping this many seconds between runs
# (background-service mode). Leave unset for a single cron-triggered run.
LIQUIDATION_POLL_INTERVAL_SECS=
#
# ── Price oracle ──
# XLM/USD price used to value outstanding debt (always denominated in XLM).
# Since issue #267 this is only a FALLBACK: the keeper asks the live price
# oracle first and uses this value only when the oracle has nothing usable.
LIQUIDATION_XLM_PRICE_USD=0.12
# Set to "false" to ignore the live oracle and always use the value above.
# Automatically disabled under test.
LIQUIDATION_USE_LIVE_PRICES=true
# Collateral asset prices as a JSON map: { "<assetAddress>": { "symbol": "...",
# "priceUsd": <num>, "decimals": <num> } }. Assets missing here are skipped
# (never guessed) — the keeper logs a warning and moves on.
LIQUIDATION_PRICE_TABLE_JSON=
# Fallback asset-volatility input (bps) fed into the contract's dynamic
# liquidation-threshold formula when an asset has no specific override.
LIQUIDATION_DEFAULT_ASSET_VOLATILITY_BPS=2000
#
# ── Alerts ──
# Incoming webhook URLs — the keeper posts on every liquidation and failure.
# Leave blank to disable either channel.
LIQUIDATION_SLACK_WEBHOOK_URL=
LIQUIDATION_DISCORD_WEBHOOK_URL=
# ── Fiat On/Off Ramp (Stellar Anchor, SEP-24) ────────────────────────────────
# Lets borrowers cash loans out to a bank account or mobile-money wallet via an
# anchor's interactive flow. Defaults target the SDF reference TEST anchor so it
# works out-of-the-box on testnet; point these at a regulated anchor for prod.
#
# Anchor home domain hosting /.well-known/stellar.toml (no protocol).
NEXT_PUBLIC_SEP24_ANCHOR_HOME_DOMAIN=testanchor.stellar.org
# Asset the borrower withdraws to fiat (the SDF test anchor exposes SRT & USDC).
NEXT_PUBLIC_SEP24_ASSET_CODE=SRT
# Optional asset issuer (G...). If blank it is resolved from the anchor's
# stellar.toml CURRENCIES list by matching the asset code above.
NEXT_PUBLIC_SEP24_ASSET_ISSUER=
# ── KYC / AML — SumSub Provider (Issues #118, #262) ──────────────────────────
# 3rd-party identity verification for borrowers AND lenders (large-volume
# lender compliance, issue #262). Verified lenders unlock regulated pools and
# higher deposit limits; status updates arrive automatically via webhook.
# Get credentials at https://sumsub.com → Dashboard → Apps & Webhooks.
#
# App Token (public — used to sign API requests from the server).
SUMSUB_APP_TOKEN=
# Secret Key (private — used to sign API request HMAC digests).
SUMSUB_SECRET_KEY=
# Webhook Secret — used to verify X-Payload-Digest on incoming callbacks.
SUMSUB_WEBHOOK_SECRET=
# Base URL (default: https://api.sumsub.com).
SUMSUB_BASE_URL=https://api.sumsub.com
# Verification level name configured in your SumSub dashboard.
SUMSUB_LEVEL_NAME=basic-kyc-level
#
# Webhook URL to register in SumSub dashboard:
# https://<your-domain>/api/kyc/webhook
#
# When these vars are empty the integration runs in DEVELOPMENT MODE:
# a fake applicantId is returned and the widget shows a simulator UI.
# ── API Rate Limiting (Issue #268) ────────────────────────────────────────────
# Every /api/* request is capped at 100 requests per minute per client IP by
# proxy.ts; exceeding it returns 429 with Retry-After and X-RateLimit-* headers.
# Individual routes apply stricter per-route policies on top (lib/rate-limit.ts).
#
# Optional Upstash Redis — enables counters shared across serverless instances.
# Without these the limiter falls back to a bounded in-memory store, which is
# per-instance only and resets on restart (fine for local dev / single node).
# Get credentials at https://console.upstash.com → Redis → REST API.
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=
#
# Optional comma-separated list of IPs that skip rate limiting entirely
# (e.g. your monitoring/uptime prober or Prometheus scraper).
# RATE_LIMIT_WHITELIST=203.0.113.10,198.51.100.4
RATE_LIMIT_WHITELIST=
#
# Requests carrying `Authorization: Bearer <ADMIN_SECRET_KEY>` also bypass the
# limits — see ADMIN_SECRET_KEY above.
# =============================================================================
# Collateral Price Oracle (issue #267)
# =============================================================================
# Long-lived keeper that polls XLM and BTC prices and pushes them on-chain:
# npm run price:oracle # 5-second loop (the issue's requirement)
# npm run price:oracle:once # single cycle, for coarse cron schedulers
# npm run price:oracle:dry # aggregate and log, publish nothing
#
# ── Cadence ──
# Seconds between polls. Defaults to 5. Vercel Cron cannot go below 60s, which
# is why the 5s cadence needs the long-lived keeper rather than the cron route.
ORACLE_POLL_INTERVAL_SECS=5
# Age (ms) beyond which a price is considered unusable. Past this the keeper
# refuses to publish rather than pushing a stale valuation that could trigger a
# wrongful liquidation.
ORACLE_MAX_STALENESS_MS=120000
# Run a single cycle and exit, instead of looping.
ORACLE_RUN_ONCE=false
# Aggregate prices but never write on-chain.
ORACLE_DRY_RUN=false
#
# ── Assets ──
# Contract addresses of the tracked collateral assets. A symbol with no address
# is aggregated and logged but never published.
ORACLE_XLM_ASSET_ADDRESS=
ORACLE_BTC_ASSET_ADDRESS=
#
# ── Sources ──
# Prices are the median across every source that responds, so one dead or
# misbehaving API degrades the feed instead of breaking it. Set any of these to
# "true" to drop that source.
ORACLE_DISABLE_COINGECKO=false
ORACLE_DISABLE_BINANCE=false
ORACLE_DISABLE_STELLAR_DEX=false
# Optional CoinGecko demo API key, for higher rate limits.
COINGECKO_API_KEY=
# USDC issuer used as the USD leg of the Stellar DEX orderbook.
ORACLE_USDC_ISSUER=GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN
#
# ── Alerts ──
# Falls back to the LIQUIDATION_* webhooks when these are unset.
ORACLE_SLACK_WEBHOOK_URL=
ORACLE_DISCORD_WEBHOOK_URL=
# ── Automated database backups (Issue #273) ───────────────────────────────────
# Used by scripts/backup.sh, run nightly at 00:00 UTC by the "Automated DB
# Backup" GitHub Actions workflow (.github/workflows/db-backup.yml).
#
# In CI these are repository *secrets*, not values in this file. Restore
# instructions and bucket setup live in docs/disaster-recovery.md.
#
# Direct Postgres connection string. Use the DIRECT connection (port 5432), not
# the pooled/pgbouncer one — pg_dump needs session-level features the pooler
# does not provide. Supabase: Project Settings → Database → Connection string.
DATABASE_URL=
#
# Passphrase used to encrypt each dump with AES-256 before upload.
# ⚠️ Store this in a password manager as well as in CI. If it is lost, every
# backup ever taken becomes permanently unreadable. Rotating it does NOT
# re-encrypt existing backups — keep the old key as long as you keep old dumps.
BACKUP_ENCRYPTION_KEY=
#
# Destination bucket name, without the s3:// prefix. Should live in a different
# account or at least a different region from the database, and have versioning
# plus a restrictive bucket policy. See docs/disaster-recovery.md.
S3_BUCKET=
#
# Optional. Key prefix within the bucket (default: backups).
BACKUP_S3_PREFIX=backups
# Optional. Days to keep backups before the script prunes them (default: 30).
# An S3 lifecycle policy is preferred; this is a backstop.
BACKUP_RETENTION_DAYS=30
# Optional. Comma-separated schemas to exclude from the dump (default: none).
BACKUP_EXCLUDE_SCHEMAS=
# Optional. Set to 1 to dump, encrypt and verify without writing to S3.
BACKUP_DRY_RUN=0