You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# Bridgelet SDK
**Backend SDK for ephemeral Stellar account management**
**MVP Stubs**
> 🚧 **The expiresIn → expiry_ledger conversion** — needs verification or explicit documentation of where it happens
> 🚧 **Webhook coverage gaps**
## Overview
The Bridgelet SDK is a NestJS-based backend service that manages the lifecycle of ephemeral Stellar accounts. It handles account creation, claim authentication, webhook notifications, and integration with the bridgelet-core smart contracts.
---
## ⚠️ TEMPORARY DEVELOPMENT WORKAROUNDS (IMPORTANT)
**PLEASE READ THIS SECTION BEFORE DEVELOPMENT**
The following services/imports are currently **commented out** to allow `npm run start:dev` to run without errors. These are **NOT removed** and **MUST be restored** once proper implementations exist.
### Missing Services:
1. **WebhooksService** (referenced in `src/modules/claims/providers/claim-redemption.provider.ts`)
- **Location:** `src/modules/webhooks/` (does not exist yet)
- **What was commented out:**
- Constructor dependency injection (line ~25)
- Webhook trigger for `sweep.completed` event (line ~106)
- Webhook trigger for `sweep.failed` event (line ~137)
- **Why:** Service implementation does not exist, causing TypeScript compilation errors
- **Impact:** Webhook notifications will NOT fire when claims are redeemed or when sweeps fail
- **Restoration required:** Once `WebhooksService` is implemented in `src/modules/webhooks/`, uncomment all marked sections
### How to Find Temporary Changes:
1. Search the codebase for comments containing `TEMPORARY:` to locate all commented-out code that needs restoration..
2. **Ledger Expiry Conversion**
- `CreateAccountDto.expiresIn` (seconds) is not yet converted to
`expiry_ledger` (u32 ledger sequence) required by the contract
- `expiresAt` Date is currently unused in `StellarService`
- Conversion formula: `current_ledger + (expiresIn / 5)`
3. **Sweep Authorization Signature** (`src/modules/sweeps/providers/contract.provider.ts`)
- **Current:** `generateAuthSignature()` produces a fake 64-byte stub signature
- **Works because:** `EphemeralAccount.verify_sweep_authorization()` in `bridgelet-core`
is also a stub that accepts any signature (documented in bridgelet-core README)
- **Impact:** Sweep authorization is not cryptographically enforced in development
- **Guard:** Method throws if called outside `development` or `test` environments
- **Required:** Real Ed25519 signing against the `SweepController`'s `authorized_signer`
once `bridgelet-core` implements real verification.
### Status:
This is a **temporary stabilization** to enable local development and onboarding until missing implementations are complete. **No code was deleted** - all logic remains in place as comments.
---
## Security
Ephemeral Stellar secret keys are encrypted at rest with AES-256-GCM (KMS-backed envelope encryption in production). See [SECURITY.md](SECURITY.md) for the full encryption, key-management, and legacy-data-migration details.
## Tech Stack
- **Framework:** NestJS (Node.js + TypeScript)
- **Database:** PostgreSQL
- **ORM:** TypeORM
- **Blockchain:** Stellar SDK + Soroban RPC
- **API:** REST api
## Features
- Account lifecycle management (create, claim, expire)
- Claim authentication via signed tokens
- Webhook system for payment events
- Integration with bridgelet-core contracts
- Admin dashboard API endpoints
## Project Structure
```
src/
├── modules/
│ ├── accounts/ # Ephemeral account management
│ ├── claims/ # Claim authentication & processing
│ ├── sweeps/ # Fund sweep orchestration
│ ├── webhooks/ # Event notification system
│ └── stellar/ # Stellar/Soroban integration
├── common/
│ ├── guards/ # Auth guards
│ ├── interceptors/ # Logging, transform
│ └── filters/ # Exception filters
├── config/ # Environment configuration
└── database/ # Migrations, entities
scripts/
└── generate-migrations.sh # Regenerates src/database/migrations/ from scratch
```
## Installation
```bash
# Install dependencies
npm install
# Setup environment
cp .env.example .env
# Edit .env with your configuration
# Run database migrations
# DataSource config : src/config/typeorm.config.ts
# Migrations : src/database/migrations/
# 1718100000000-CreateAccountsTable (accounts table, status enum, expiredAt, metadata)
# 1718100001000-CreateClaimsTable (claims table + FK to accounts)
# 1718100002000-AddInitializingToAccountStatus (adds INITIALIZING to account_status enum)
# 1718100003000-CreateWebhooksTable (webhooks table)
# 1718100004000-AddClaimingToAccountStatus (adds CLAIMING to account_status enum)
# 1718100005000-CreateWebhookDeliveriesTable (webhook delivery attempt log table)
# 1718100006000-AddHighTrafficIndexes (accounts composite and range indexes)
# 1718100007000-CreateContractEventsTable (Soroban contract event index table)
# 1718100008000-AddDeletedAtToAccountsTable (soft-delete column + index on accounts)
# 1718100008000-AddPartialSweepToAccountStatus (adds PARTIAL_SWEEP to account_status enum)
# 1718100008000-CreateClaimAuditLogTable (claim attempt audit log table)
npm run migration:run
# Start development server
npm run start:dev
```
### Regenerating the migrations folder
`src/database/migrations/` is scripted rather than hand-maintained. `scripts/generate-migrations.sh` deletes the folder and rewrites every file listed above verbatim, so the folder on disk is always reproducible from the script instead of relying on files someone created by hand.
```bash
# Recreate src/database/migrations/ from the script (prompts for confirmation)
./scripts/generate-migrations.sh
# Same, but skip the confirmation prompt (useful in CI)
./scripts/generate-migrations.sh --yes
# Skip the prompt AND overwrite uncommitted changes in the migrations folder
# (only needed when you deliberately want to discard hand-edited migrations)
./scripts/generate-migrations.sh --yes --force
```
Before deleting anything, the script runs a pre-flight `git status --porcelain` check
against `src/database/migrations/` and aborts if it finds uncommitted changes there
(modified, staged, or untracked files) — the rewrite would otherwise silently destroy
them. Commit or stash your migration work first, or pair `--yes` with `--force` to
overwrite deliberately.
This does **not** apply migrations to a database — it only (re)writes the `.ts` files. Run `npm run migration:run` afterwards as usual. See [`CONTRIBUTING.md`](./CONTRIBUTING.md#database-migrations) for the workflow to follow when adding a _new_ migration.
## Tests
```bash
npm test
## or to run specific tests
npm test -- test_Service_File_Name
## e.g
npm test -- sweeps.service.spec.ts
```
### Coverage
Run the full coverage report (enforces 80% minimum threshold):
```bash
npm run test:cov
```
Coverage reports are generated in the `coverage/` directory. The build will fail if any metric (branches, functions, lines, statements) falls below 80%.
The repository also includes an embedded-Postgres integration test in `src/database/migrations.integration.spec.ts` that starts a fresh PostgreSQL instance, runs all current migrations, verifies the resulting schema matches the TypeORM entities, checks the `account_status_enum` values, confirms the `claims.accountId -> accounts.id` and `webhook_deliveries.subscription_id -> webhooks.id` foreign keys are enforced, verifies the high-traffic `accounts` indexes added by migration `1718100006000`, and verifies the `contract_events` table shape.
To check coverage for a specific file:
```bash
npm test -- sweeps.service.spec.ts --coverage
```
## Environment Variables
```env
# Database
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=bridgelet
DATABASE_USER=postgres
DATABASE_PASSWORD=postgres
# Stellar
STELLAR_NETWORK=testnet
STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org
SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
# Security
JWT_SECRET=your-secret-key
CLAIM_TOKEN_EXPIRY=2592000 # 30 days
# Application
PORT=3000
NODE_ENV=development
```
## API Documentation
Once running, access API docs at:
- Swagger: `http://localhost:3000/api/docs`
## Key Endpoints
POST /accounts # Create ephemeral account (also returns the claim token)
GET /accounts/:id # Get account details
GET /accounts # List accounts (admin, paginated)
POST /claims/verify # Check a claim token is still valid
POST /claims/redeem # Redeem claim and sweep funds
GET /claims/:id # Get a recorded claim
GET /webhooks # List webhook subscriptions (active only, paginated)
POST /webhooks # Subscribe to events
PUT /webhooks/:id # Update webhook subscription (url, events, isActive, secret)
DELETE /webhooks/:id # Soft-delete (deactivate) a webhook subscription
Full request/response documentation: [API Reference](./docs/api-reference.md)
> There is no `POST /claims/initiate` endpoint. The claim token is minted by
> `POST /accounts` and returned once, in that response's `claimUrl`.
## Database Schema
See [Database Schema Documentation](./docs/database-schema.md)
## Development
```bash
# Run tests
npm run test
# Run e2e tests
npm run test:e2e
# Lint
npm run lint
# Format
npm run format
```
# Contributing
## Automated PR Naming Checks
All pull requests are validated automatically for branch naming and PR title format.
- During the initial rollout, checks run in warning mode until **2026-02-27**.
- After that date, pull requests are blocked until naming issues are fixed.
### Branch Name Format
Accepted pattern:
`(fix|feature|test|chore|docs)/issue-NUMBER-brief-description`
Regex used by CI:
`^(fix|feature|test|chore|docs)/issue-[0-9]+-[a-z0-9-]+$`
Examples:
- `fix/issue-42-jwt-error-handling`
- `feature/issue-50-webhook-service`
`main` and `develop` are exempt for release/hotfix workflows.
### PR Title Format
Accepted pattern:
`(Fix|Feature|Test|Chore|Docs): Brief description (#NUMBER)`
Regex used by CI:
`^(Fix|Feature|Test|Chore|Docs): .+ \(#[0-9]+\)$`
Examples:
- `Fix: Handle JWT errors in TokenVerificationProvider (#42)`
- `Test: Add unit tests for ClaimLookupProvider (#43)`
### How To Fix A Branch Name
Rename your local branch and push the new branch:
```bash
git branch -m fix/issue-42-jwt-error-handling
git push origin -u fix/issue-42-jwt-error-handling
```
Then update the PR to use the renamed branch. If needed, close the old PR and open a new one from the renamed branch.
### How To Fix A PR Title
Edit the PR title directly in GitHub:
1. Open the pull request.
2. Click the title field.
3. Update it to the required format.
4. Save changes.
## Deployment
See [Deployment Guide](./docs/deployment.md) for production setup.
## Documentation
- [API Reference](./docs/api-reference.md)
- [Database Schema](./docs/database-schema.md)
- [Webhook Events](./docs/webhook-events.md)
- [Deployment Guide](./docs/deployment.md)
Visit http://localhost:3000/api/docs for API documentation.
See [Getting Started Guide](./docs/getting-started.md) for full setup instructions.
## Support
(Nest)[https://nestjs.com](https://nestjs.com/)
## License
UNLICENSED
# CI trigger
About
Backend service for ephemeral Stellar account management