Skip to content

Latest commit

Β 

History

44 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Rayos Relay

The gasless transaction relay, session key orchestrator, and social recovery engine for the Rayos smart wallet on Stellar/Soroban.


CI API Status License: MIT Node.js

NestJS TypeScript PostgreSQL Neon DB Redis BullMQ Stellar Soroban Zod Drizzle ORM pnpm Docker Render

πŸ“Œ Table of Contents


🧠 What Is This?

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 β†’


✨ Features

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

πŸ— Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    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)          β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“‘ API Reference

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

πŸ›  Tech Stack

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
Email Resend
API Docs Swagger / OpenAPI via @nestjs/swagger
Deployment Render
CI/CD GitHub Actions
Package Manager pnpm v9

⚑ Quick Start

Prerequisites

  • Node.js v20+
  • pnpm v9 (npm install -g pnpm@9)
  • Docker & Docker Compose

1. Clone the Repository

git clone https://github.com/Rayos-Org/relay-backend.git
cd relay-backend

2. Install Dependencies

pnpm install

3. Configure Environment

cp .env.example .env
# Edit .env with your credentials

4. Start Infrastructure (Postgres + Redis)

docker-compose up -d

5. Push Database Schema

pnpm db:push

6. Run the Backend

pnpm start:dev

The 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 β†’


πŸ” Environment Variables

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 ⚠️ Optional 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 ⚠️ Optional Faucet amount per request (default 100)
RELAY_MIN_BALANCE_XLM ⚠️ Optional 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 ⚠️ Optional Resend API key for guardian email alerts
LAUNCHTUBE_API_KEY ⚠️ Optional 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_KEY is not set, guardian emails are logged to the console. Without RELAY_SECRET_KEY, /relay/deploy and /relay/faucet are unavailable and /relay/submit falls 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_KEY

πŸš€ Deployment

The 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

Deploy Your Own

This repo contains a render.yaml Blueprint. To deploy your own instance:

  1. Fork this repository.
  2. Go to Render Dashboard β†’ New + β†’ Blueprint.
  3. Connect the forked repo. Render auto-reads render.yaml.
  4. Fill in the required environment variables. In particular:
    • REDIS_URL β€” the rediss:// URL from Upstash
    • RELAY_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
  5. Click Apply. The start command runs pnpm db:push, which creates the passkeys table 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.


πŸ“š Documentation

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

🀝 Contributing

Contributions are what make open source great. Any contributions are greatly appreciated.

  1. Fork the project
  2. Create your feature branch (git checkout -b feat/amazing-feature)
  3. Commit your changes (git commit -m 'feat: add amazing feature')
  4. Push to the branch (git push origin feat/amazing-feature)
  5. Open a Pull Request

Please read docs/CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.


πŸ“„ License

Distributed under the MIT License. See LICENSE for more information.


Built with ❀️ by the Rayos Team

About

Gasless transactions, session keys, and social recovery orchestration for Soroban.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages