Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
548 changes: 481 additions & 67 deletions client/src/pages/Stablecoin.tsx

Large diffs are not rendered by default.

359 changes: 359 additions & 0 deletions infra/apisix/stablecoin-routes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,359 @@
# RemitFlow — APISix Stablecoin Route Configuration
#
# Rate limiting, circuit breaking, and WAF integration for all stablecoin
# endpoints. Stricter rate limits on on-ramp (max 10/day) and off-ramp.
# OpenAppSec WAF integration for webhook endpoints.

routes:
# ── On-Ramp (Fiat → Stablecoin) ───────────────────────────────────────────
- uri: /api/trpc/stablecoin.buyWithFiat*
name: stablecoin-onramp
plugins:
limit-count:
count: 10
time_window: 86400 # 10 per day
key: consumer_name
rejected_code: 429
rejected_msg: "Daily on-ramp limit exceeded (max 10/day)"
limit-req:
rate: 5
burst: 2
key: remote_addr
rejected_code: 429
api-breaker:
break_response_code: 503
max_breaker_sec: 60
unhealthy:
http_statuses: [500, 502, 503]
failures: 2
healthy:
http_statuses: [200, 201]
successes: 2
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:3000": 1
checks:
active:
type: http
http_path: /api/health
healthy:
interval: 5
successes: 2
unhealthy:
interval: 2
http_failures: 3
retries: 0 # Never retry fund operations

# ── Off-Ramp (Stablecoin → Fiat) ──────────────────────────────────────────
- uri: /api/trpc/stablecoin.sellToFiat*
name: stablecoin-offramp
plugins:
limit-count:
count: 20
time_window: 86400 # 20 per day
key: consumer_name
rejected_code: 429
api-breaker:
break_response_code: 503
max_breaker_sec: 60
unhealthy:
http_statuses: [500, 502, 503]
failures: 2
healthy:
http_statuses: [200, 201]
successes: 2
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:3000": 1
retries: 0

# ── Bank Withdrawal ────────────────────────────────────────────────────────
- uri: /api/trpc/stablecoin.withdrawToBank*
name: stablecoin-bank-withdrawal
plugins:
limit-count:
count: 5
time_window: 86400 # 5 per day
key: consumer_name
rejected_code: 429
rejected_msg: "Daily bank withdrawal limit exceeded (max 5/day)"
api-breaker:
break_response_code: 503
max_breaker_sec: 120
unhealthy:
http_statuses: [500, 502, 503]
failures: 2
healthy:
http_statuses: [200, 201]
successes: 2
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:3000": 1
retries: 0

# ── Staking / Yield ────────────────────────────────────────────────────────
- uri: /api/trpc/stablecoin.stakeForYield*
name: stablecoin-stake
plugins:
limit-req:
rate: 10
burst: 5
key: remote_addr
rejected_code: 429
api-breaker:
break_response_code: 503
max_breaker_sec: 30
unhealthy:
http_statuses: [500, 502, 503]
failures: 3
healthy:
http_statuses: [200, 201]
successes: 2
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:3000": 1
retries: 0

# ── Bridge (Cross-Chain) ───────────────────────────────────────────────────
- uri: /api/trpc/stablecoin.bridgeChain*
name: stablecoin-bridge
plugins:
limit-req:
rate: 5
burst: 2
key: remote_addr
rejected_code: 429
api-breaker:
break_response_code: 503
max_breaker_sec: 60
unhealthy:
http_statuses: [500, 502, 503]
failures: 2
healthy:
http_statuses: [200, 201]
successes: 2
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:3000": 1
retries: 0

# ── P2P Send ───────────────────────────────────────────────────────────────
- uri: /api/trpc/stablecoin.sendToContact*
name: stablecoin-p2p
plugins:
limit-req:
rate: 20
burst: 5
key: remote_addr
rejected_code: 429
api-breaker:
break_response_code: 503
max_breaker_sec: 30
unhealthy:
http_statuses: [500, 502, 503]
failures: 3
healthy:
http_statuses: [200, 201]
successes: 2
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:3000": 1
retries: 0

# ── Bill Pay ───────────────────────────────────────────────────────────────
- uri: /api/trpc/stablecoin.payBill*
name: stablecoin-bill-pay
plugins:
limit-req:
rate: 10
burst: 3
key: remote_addr
rejected_code: 429
api-breaker:
break_response_code: 503
max_breaker_sec: 30
unhealthy:
http_statuses: [500, 502, 503]
failures: 3
healthy:
http_statuses: [200, 201]
successes: 2
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:3000": 1
retries: 0

# ── Webhook Endpoints (Go Settlement Service) ─────────────────────────────
- uri: /webhook/circle
name: webhook-circle
plugins:
limit-req:
rate: 100
burst: 50
key: remote_addr
rejected_code: 429
ip-restriction:
# Circle webhook IPs (update with production IPs)
whitelist:
- "0.0.0.0/0" # Allow all in dev; restrict in production
openappsec:
enabled: true
mode: prevent
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:8200": 1

- uri: /webhook/yellowcard
name: webhook-yellowcard
plugins:
limit-req:
rate: 100
burst: 50
key: remote_addr
rejected_code: 429
openappsec:
enabled: true
mode: prevent
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:8200": 1

- uri: /webhook/moonpay
name: webhook-moonpay
plugins:
limit-req:
rate: 100
burst: 50
key: remote_addr
rejected_code: 429
openappsec:
enabled: true
mode: prevent
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:8200": 1

- uri: /webhook/transak
name: webhook-transak
plugins:
limit-req:
rate: 100
burst: 50
key: remote_addr
rejected_code: 429
openappsec:
enabled: true
mode: prevent
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:8200": 1

# ── Python Oracle Service ──────────────────────────────────────────────────
- uri: /oracle/fx/*
name: oracle-fx
plugins:
limit-req:
rate: 60
burst: 20
key: remote_addr
rejected_code: 429
proxy-cache:
cache_ttl: 300 # Cache FX rates for 5 minutes
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:8220": 1

- uri: /oracle/depeg/*
name: oracle-depeg
plugins:
limit-req:
rate: 30
burst: 10
key: remote_addr
rejected_code: 429
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:8220": 1

# ── Rust On-Chain Guard ────────────────────────────────────────────────────
- uri: /onchain/*
name: onchain-guard
plugins:
limit-req:
rate: 50
burst: 10
key: remote_addr
rejected_code: 429
api-breaker:
break_response_code: 503
max_breaker_sec: 30
unhealthy:
http_statuses: [500, 502, 503]
failures: 5
healthy:
http_statuses: [200, 201]
successes: 2
prometheus:
prefer_name: true
upstream:
type: roundrobin
nodes:
"127.0.0.1:8210": 1
retries: 0

# ── OpenAppSec WAF Global Config ───────────────────────────────────────────

openappsec:
mode: prevent
practice:
web-attacks:
override-mode: prevent
minimum-confidence: medium
bot-defense:
override-mode: prevent
ip-protection:
override-mode: prevent
log:
level: info
destination: opensearch
opensearch_url: "http://localhost:9200"
index: "remitflow-waf-events"
Loading