Go to file
2026-05-03 16:09:09 +03:00
src Initial Bank28 reference backend — full neobank-on-AERE integration pattern 2026-05-03 16:09:09 +03:00
package-lock.json Initial Bank28 reference backend — full neobank-on-AERE integration pattern 2026-05-03 16:09:09 +03:00
package.json Initial Bank28 reference backend — full neobank-on-AERE integration pattern 2026-05-03 16:09:09 +03:00
README.md Initial Bank28 reference backend — full neobank-on-AERE integration pattern 2026-05-03 16:09:09 +03:00
tsconfig.json Initial Bank28 reference backend — full neobank-on-AERE integration pattern 2026-05-03 16:09:09 +03:00

Bank28 reference backend

Minimal Express server that demonstrates the full Bank28-class neobank integration with AERE Network, alongside a fiat BaaS provider (Striga, Dipocket, Modulr, Solaris, …).

This is a reference, not a production app. The intent is for the Bank28 build team to copy this skeleton and harden it — replace the in-memory Map with Postgres, replace the env-var private key with KMS-managed signing, add structured logging, etc.

Architecture demonstrated

                Bank28 web/mobile app
                        │
                        │ Privy/Magic provisioned wallet (email/social → EVM address)
                        ▼
┌──────────── this backend ────────────┐    ┌────── BaaS provider ──────┐
│  /signup                              │◄──►│  KYC vendor               │
│  /webhooks/baas/kyc-cleared           │    │  IBAN issuance            │
│   └─► aere.identity.addClaim()        │    │  Card issuance            │
│  /users/:id/portfolio                 │    │  SEPA / SWIFT settlement  │
│   └─► aere.getPortfolio()             │    └───────────────────────────┘
│  /users/:id/earn                      │
│   └─► returns tx instructions for Privy to sign
│  /webhooks/onramp/deposit             │◄── MoonPay / Transak / Ramp
│  Live deposit watcher                 │◄── AERE Network (rpc.aere.network)
└───────────────────────────────────────┘

What it shows

  1. Wallet provisioning is non-custodial. The user's AERE address is created client-side by Privy/Magic (email login). The backend just records it. No seed phrases, no key custody, no Bank28 liability for lost keys.
  2. KYC attestation on-chain. When the BaaS provider clears a user, this backend writes a kyc-tier-1 claim to AereIdentity against the user's address. Smart contracts that gate features by KYC (lending, higher transfer limits, fiat off-ramp) check hasValidClaim() against the Bank28 attestor address.
  3. Portfolio aggregation. Multi-asset balance via aere.getPortfolio() — native AERE + WAERE + AereUSD in one call.
  4. Yield without custody. /users/:id/earn returns transaction instructions for the client to sign via Privy. The backend never holds the user's signing key.
  5. Live deposit watcher. Polls blocks, matches tx.to against the user registry, fires when a user receives AERE — same shape as Stripe webhooks for fiat.

Run

# 1. Build the SDK first (sibling package)
cd ../sdk-js && npm install && npx tsc

# 2. Run this backend
cd ../bank28-reference-backend
npm install
OPS_PRIVATE_KEY=0x… npm run dev

The OPS_PRIVATE_KEY is the Bank28 attestor identity — the address that signs KYC claims on-chain. In production this should be a hardware-backed or KMS-managed key, never an env var.

Endpoints

Method Path Purpose
POST /signup Create a Bank28 user record. Body: {email, aereAddress, baasUserId}.
POST /webhooks/baas/kyc-cleared BaaS provider webhook → writes on-chain KYC attestation. Body: {baasUserId, reportHash, tier}.
GET /users/:id/portfolio Multi-asset balance + KYC status.
POST /users/:id/earn Returns tx instructions for the client to sign (locks AERE in AereStakingV2). Body: {tier, amountAere}.
POST /webhooks/onramp/deposit MoonPay/Transak webhook on fiat→crypto deposit completion.
GET /healthz Health check.

Production checklist

  • Replace the in-memory users Map with Postgres + Drizzle/Prisma.
  • Move OPS_PRIVATE_KEY to AWS KMS / HashiCorp Vault / GCP Cloud KMS — never an env var in production.
  • Verify webhook signatures from the BaaS provider (HMAC) and on-ramp provider before trusting payloads.
  • Add idempotency keys to all webhook handlers to prevent double-processing.
  • Add structured logging (pino) and metrics (Prometheus).
  • Add rate-limit middleware to all public endpoints.
  • Replace polling deposit watcher with WebSocket subscription (aere.watchTransfersTo).
  • Implement Travel Rule (FATF R.16) — Notabene if BaaS provider doesn't include it.
  • Set up monitoring on the ops wallet's gas balance (alert if < 1 AERE).
  • Audit — see aerenew/audit-prep/INVARIANTS.md for the on-chain side; commission a separate web-app audit for this server.