The gasless transaction relay, session key orchestrator, and social recovery engine for the Rayos smart wallet on Stellar/Soroban.
- What Is This?
- Features
- Architecture
- API Reference
- Tech Stack
- Quick Start
- Environment Variables
- Deployment
- Documentation
- Contributing
- License
The Rayos Relay Backend is a NestJS-based infrastructure layer for the Rayos smart wallet ecosystem on the Stellar/Soroban blockchain network.
It sits between the client application and the Soroban network, abstracting away all blockchain complexity. Users interact with a standard REST API β the relay handles gas sponsorship, passkey ceremony coordination, session tracking, and multi-guardian recovery orchestration completely in the background.
Trustless by Design: The relay never holds private keys, never stores seed phrases, and cannot alter transaction payloads without invalidating the user's cryptographic signature. Read the full Trust Model β
| Feature | Description |
|---|---|
| π Passkey (WebAuthn) Orchestration | Registers and verifies passkey ceremonies (Face ID, Touch ID, YubiKey) via WebAuthn/FIDO2, caching challenges in Redis with a strict TTL |
| β½ Gasless Transactions | A relay-owned sponsor account is the source of every transaction: the passkey signs the wallet's Soroban auth entry, the relay re-simulates, signs the envelope and pays the fee. Also deploys wallets from the factory and runs the testnet faucet |
| π Session Key Management | Creates and revokes temporary session scopes for seamless dapp logins, with fast off-chain lookups backed by Postgres |
| π‘ Social Recovery | BullMQ-powered orchestration that notifies guardians via email (Resend), aggregates approvals, enforces timelocks, and executes on-chain recovery atomically |
| π‘ Wallet Index | Maps passkey credential IDs to deployed wallet contract addresses (written on deploy, read on sign-in) |
| π¦ Rate Limiting | Redis-backed per-IP and per-wallet rate limiting on all endpoints to protect against abuse and DDoS |
| π Swagger UI | Auto-generated interactive API documentation available at /api/docs |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Client (Wallet / Dapp) β
β (WebAuthn Β· XDR payload Β· Session req) β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β HTTPS REST API
βββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββ
β Rayos Relay Backend β
β β
β ββββββββββββββ ββββββββββββ ββββββββββββ β
β β WebAuthn β β Relay β β Sessions β β
β β Module β β Module β β Module β β
β βββββββ¬βββββββ ββββββ¬ββββββ ββββββ¬ββββββ β
β β β β β
β βββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββ β
β β Recovery Module β β
β β (BullMQ Β· Timelock Β· Resend Email) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Soroban Event Indexer (Polling) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β Redis (Challenges Β· Rate Limits Β· BullMQ) β
β PostgreSQL / Neon (Sessions Β· Proposals Β· DB) β
ββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββ
β
ββββββββββββββββββΌβββββββββββββββββ
β Sponsor account (RELAY_SECRET) β
β signs envelope Β· pays the fee β
ββββββββββββββββββ¬βββββββββββββββββ
β Soroban RPC
ββββββββββββββββββΌβββββββββββββββββ
β Stellar Network β
β (Testnet / Mainnet) β
βββββββββββββββββββββββββββββββββββ
Live Interactive Docs (Swagger UI):
π https://rayos-relay-backend.onrender.com/api/docs
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/webauthn/register/options |
Generate WebAuthn registration options |
POST |
/api/webauthn/register/verify |
Verify passkey registration |
POST |
/api/webauthn/assert/options |
Generate authentication challenge |
POST |
/api/webauthn/assert/verify |
Verify passkey authentication |
GET |
/api/relay/info |
Sponsor address, factory/native contract IDs, faucet amount |
POST |
/api/relay/deploy |
Deploy a passkey wallet from the factory (sponsor pays) |
POST |
/api/relay/submit |
Submit a passkey-signed Soroban tx; sponsor signs the envelope and pays the fee |
POST |
/api/relay/faucet |
Testnet only: send RELAY_FAUCET_XLM to a wallet |
GET |
/api/relay/status/:txHash |
Poll transaction status on Soroban RPC |
GET |
/api/wallets/:credentialId |
Look up the wallet address for a passkey credential |
POST |
/api/sessions |
Create a session key |
DELETE |
/api/sessions/:sessionId |
Revoke a session |
GET |
/api/sessions |
List active sessions for a wallet |
POST |
/api/recovery/propose |
Propose a social recovery |
POST |
/api/recovery/approve |
Guardian approves a recovery proposal |
GET |
/api/recovery/:proposalId/status |
Get proposal status |
| Layer | Technology |
|---|---|
| Framework | NestJS v10 (Node.js / TypeScript) |
| Database | PostgreSQL via Neon Serverless |
| ORM | Drizzle ORM |
| Cache / Queue | Redis + BullMQ via Upstash |
| Validation | Zod with custom ZodValidationPipe |
| Authentication | SimpleWebAuthn (WebAuthn / FIDO2) |
| Blockchain | @stellar/stellar-sdk + @rayos/wallet-sdk |
| Resend | |
| API Docs | Swagger / OpenAPI via @nestjs/swagger |
| Deployment | Render |
| CI/CD | GitHub Actions |
| Package Manager | pnpm v9 |
- Node.js v20+
- pnpm v9 (
npm install -g pnpm@9) - Docker & Docker Compose
git clone https://github.com/Rayos-Org/relay-backend.git
cd relay-backendpnpm installcp .env.example .env
# Edit .env with your credentialsdocker-compose up -dpnpm db:pushpnpm start:devThe API is available at http://localhost:3000/api
Swagger UI is available at http://localhost:3000/api/docs
For the full local setup guide, see docs/SETUP.md β
Copy .env.example to .env and fill in the values.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
β | Neon Postgres connection URL |
REDIS_URL |
β | Redis URL. Upstash needs rediss:// (TLS); a redis:// Upstash URL is auto-upgraded |
SOROBAN_RPC_URL |
β | Soroban RPC endpoint |
STELLAR_NETWORK_PASSPHRASE |
β | Defaults to testnet |
FACTORY_CONTRACT_ID |
β | Wallet factory from wallet-contracts (testnet: CCCAMWJOF7IYTVCU7SR6HFTNH5XRMDMWPYN464NY5BCKUPMUM64RZ5CH) |
NATIVE_TOKEN_CONTRACT_ID |
Native XLM SAC; defaults to the testnet address | |
RELAY_SECRET_KEY |
β | Sponsor account secret (S...). Pays fees, deploys wallets, funds the faucet. Auto-funded from Friendbot on testnet |
RELAY_FAUCET_XLM |
Faucet amount per request (default 100) |
|
RELAY_MIN_BALANCE_XLM |
Sponsor balance below which Friendbot top-up is attempted (default 500) |
|
WEBAUTHN_RP_ID |
β | Registrable domain of the web app (e.g. localhost, app.rayos.dev) |
WEBAUTHN_ORIGIN |
β | Full origin(s) of the web app, comma-separated |
CORS_ORIGINS |
β | Browser origins allowed to call the API, comma-separated (WEBAUTHN_ORIGIN is always allowed) |
RESEND_API_KEY |
Resend API key for guardian email alerts | |
LAUNCHTUBE_API_KEY |
Launchtube fallback for /relay/submit when RELAY_SECRET_KEY is unset |
|
NODE_ENV |
β | development or production |
PORT |
β | HTTP port (default: 3000) |
Note: If
RESEND_API_KEYis not set, guardian emails are logged to the console. WithoutRELAY_SECRET_KEY,/relay/deployand/relay/faucetare unavailable and/relay/submitfalls back to Launchtube.
Generate the sponsor key with the Stellar CLI (never commit it):
stellar keys generate relay-sponsor --network testnet --fund
stellar keys show relay-sponsor # -> RELAY_SECRET_KEYThe backend is deployed on Render and is publicly accessible:
π Live API: https://rayos-relay-backend.onrender.com/api
π Swagger Docs: https://rayos-relay-backend.onrender.com/api/docs
This repo contains a render.yaml Blueprint. To deploy your own instance:
- Fork this repository.
- Go to Render Dashboard β New + β Blueprint.
- Connect the forked repo. Render auto-reads
render.yaml. - Fill in the required environment variables. In particular:
REDIS_URLβ therediss://URL from UpstashRELAY_SECRET_KEYβ the sponsor account secret (see above)WEBAUTHN_RP_ID/WEBAUTHN_ORIGINβ the web dashboard's domain and origin (passkeys are bound to the site the user sees, not the relay)CORS_ORIGINSβ the web dashboard origin
- Click Apply. The start command runs
pnpm db:push, which creates thepasskeystable on first deploy.
π‘ A GitHub Actions workflow (
.github/workflows/keepalive.yml) automatically pings the service every 10 minutes to prevent the free-tier service from sleeping.
| Document | Description |
|---|---|
| docs/SETUP.md | Full local development setup guide |
| docs/TRUST.md | Trust model β why the relay cannot steal funds |
| docs/CONTRIBUTING.md | How to contribute to this project |
| docs/SECURITY.md | Security policy and vulnerability reporting |
Contributions are what make open source great. Any contributions are greatly appreciated.
- Fork the project
- Create your feature branch (
git checkout -b feat/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feat/amazing-feature) - Open a Pull Request
Please read docs/CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.
Distributed under the MIT License. See LICENSE for more information.