backend/src/stellar/
├── index.ts # Public API exports
├── stellar.module.ts # NestJS module configuration
├── stellar.service.ts # Main service with Horizon API integration
├── stellar.service.spec.ts # Unit tests
├── usage-examples.ts # Integration examples
├── README.md # Usage documentation
├── IMPLEMENTATION_SUMMARY.md # Implementation details
├── ARCHITECTURE.md # This file
│
├── dto/
│ └── stellar.dto.ts # Data Transfer Objects
│ ├── AccountBalanceDto
│ ├── AccountDetailsDto
│ ├── PaymentDto
│ ├── PaymentVerificationDto
│ └── TransactionDto
│
├── exceptions/
│ └── stellar.exceptions.ts # Custom exception hierarchy
│ ├── StellarException (base)
│ ├── StellarAccountNotFoundException
│ ├── StellarPaymentNotFoundException
│ ├── StellarAddressInvalidException
│ ├── HorizonApiException
│ ├── SorobanRpcException
│ ├── StellarNetworkConfigException
│ └── StellarExceptionFilter
│
└── utils/
└── stellar.validator.ts # Validation utilities
├── isValidPublicKey()
├── isValidContractAddress()
├── isValidSecretKey()
├── generateKeypair()
└── ... (8 validation methods)
┌─────────────────────────────────────────────────────────┐
│ Application Layer │
│ (InvoicesModule, AuthModule, UsersModule, etc.) │
└────────────────────┬────────────────────────────────────┘
│ imports & uses
▼
┌─────────────────────────────────────────────────────────┐
│ StellarModule │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Providers: │ │
│ │ - StellarService │ │
│ │ - STELLAR_VALIDATOR (StellarValidator) │ │
│ │ │ │
│ │ Exports: │ │
│ │ - StellarService │ │
│ │ - All Exception Classes │ │
│ │ - StellarExceptionFilter │ │
│ │ - StellarValidator │ │
│ └─────────────────────────────────────────────────┘ │
└────────────────────┬────────────────────────────────────┘
│
┌───────────┼───────────┐
│ │ │
▼ ▼ ▼
┌────────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ stellar.dto.ts │ │stellar.validator│ │stellar.exceptions│
│ │ │ │ │ │
│ - Account DTOs │ │ - Address Valid│ │ - Exceptions │
│ - Payment DTOs │ │ - Keypair Gen │ │ - Exception Filter
│ - Transaction │ │ - Memo Valid │ │ │
└────────────────┘ └─────────────────┘ └──────────────────┘
│ │
└──────────────────┬────────────────┘
│
▼
┌──────────────────┐
│ StellarService │
│ │
│ Core Methods: │
│ - getAccountDet..│
│ - verifyPayment │
│ - watchPayments │
│ - getTxByHash │
│ - generateMemo │
│ - validation │
└────────┬─────────┘
│ uses
▼
┌──────────────────┐
│ @stellar/stellar-│
│ sdk │
│ │
│ - Horizon.Server │
│ - StrKey │
│ - Keypair │
│ - Networks │
└──────────────────┘
│
▼
┌──────────────────┐
│ Horizon API │
│ (Stellar Network)│
└──────────────────┘
User/Service
│
│ 1. Call getAccountDetails(publicKey)
▼
StellarService
│
│ 2. Validate publicKey
▼
StellarValidator.isValidPublicKey()
│
│ 3. If invalid → throw StellarAddressInvalidException
│
│ 4. If valid → call Horizon API
▼
StellarSdk.Horizon.Server.loadAccount()
│
│ 5. Horizon returns account data
│
│ 6. Map to AccountDetailsDto
▼
Return AccountDetailsDto {
id, publicKey, sequence,
balances[], subentryCount,
minimumBalance
}
Horizon API Error (e.g., 404 Not Found)
│
▼
StellarService catches error
│
│ Check error type
├─→ isAxiosError && status === 404
│ └─→ throw StellarAccountNotFoundException
│
├─→ isAxiosError && status === 429
│ └─→ throw HorizonApiException (429)
│
├─→ isAxiosError && status >= 500
│ └─→ throw HorizonApiException (502)
│
└─→ Other error
└─→ throw StellarException
│
▼
StellarExceptionFilter (if registered globally)
│
│ Transform to JSON response
▼
HTTP Response {
statusCode: 404,
code: "STELLAR_ACCOUNT_NOT_FOUND",
message: "Account not found: G...",
timestamp: "2026-03-03T..."
}
Service calls watchPayments(callback)
│
▼
StellarService.watchPayments()
│
│ 1. Get merchant public key
│ 2. Create payments call builder
│ 3. Set cursor to "now"
│
▼
server.payments()
.forAccount(merchantKey)
.cursor("now")
.stream({ onmessage, onerror })
│
│ Wait for incoming payments...
│
├─→ Payment received
│ │
│ ▼
│ onmessage(paymentRecord)
│ │
│ ▼
│ callback(paymentRecord)
│ │
│ ▼
│ Service processes payment
│
└─→ Stream error
│
▼
onerror(error)
│
▼
throw HorizonApiException
┌──────────────────────────────────────────────────────┐
│ Dependencies │
├──────────────────────────────────────────────────────┤
│ │
│ @nestjs/common │
│ @nestjs/config │
│ @stellar/stellar-sdk │
│ class-validator (optional, removed from DTOs) │
│ │
└──────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ StellarModule Providers │
├──────────────────────────────────────────────────────┤
│ │
│ StellarService ──► Uses ConfigService │
│ │
│ STELLAR_VALIDATOR (value provider) │
│ │
└──────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ Consuming Modules (Examples) │
├──────────────────────────────────────────────────────┤
│ │
│ InvoicesModule ──► Payment verification │
│ AuthModule ──────► Address validation │
│ UsersModule ─────► Key generation │
│ PaymentsModule ─► Payment watching │
│ │
└──────────────────────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Environment (.env) │
│ HORIZON_URL=... │
│ STELLAR_NETWORK_PASSPHRASE=... │
│ MERCHANT_PUBLIC_KEY=... │
│ USDC_ISSUER=... │
│ MEMO_PREFIX=... │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Config Module (NestJS) │
│ - Loads .env │
│ - Validates with Joi │
│ - Registers stellar config │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Stellar Config (stellar.config) │
│ registerAs('stellar', () => ({ │
│ horizonUrl, networkPassphrase, │
│ merchantPublicKey, usdcIssuer, │
│ memoPrefix │
│ })) │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ StellarService │
│ constructor(ConfigService) │
│ getConfig() → stellar config │
└─────────────────────────────────────┘
getAccountDetails(publicKey)→ Full account infogetAccountBalance(publicKey)→ All balancesgetXlmBalance(publicKey)→ XLM onlygetUsdcBalance(publicKey)→ USDC only
verifyPayment(memo, destination?)→ Verify by memowatchPayments(callback, memo?)→ Real-time streamgetTransactionByHash(hash)→ Transaction lookup
isValidPublicKey(publicKey)→ Validate G-addressisValidContractAddress(address)→ Validate C-addressassertValidPublicKey(publicKey)→ Validate or throwassertValidContractAddress(address)→ Validate or throw
generateMemo(invoiceId)→ Create memoparseMemo(memo)→ Extract invoice IDgenerateKeypair()→ Create new keypair (validator)getPublicKeyFromSecret(secretKey)→ Derive public key
getConfig()→ All Stellar configgetHorizonUrl()→ Horizon endpointgetMerchantPublicKey()→ Merchant keygetNetworkPassphrase()→ Network identifierisTestnet()→ Network type checkgetServer()→ Horizon Server instance
┌─────────────────────────────────────────┐
│ StellarService (Singleton) │
│ │
│ Private: server (Horizon.Server) │
│ - Immutable after initialization │
│ - Thread-safe (no mutable state) │
│ │
│ Methods are stateless │
│ - Safe for concurrent calls │
│ - No shared mutable state │
└─────────────────────────────────────────┘
-
Soroban RPC Integration
SorobanService (new) ├── submitTransaction() ├── simulateTransaction() ├── getContractData() └── invokeContract() -
Transaction Building
TransactionBuilderService ├── createPaymentTx() ├── createTrustlineTx() ├── signTransaction() └── submitTransaction() -
Caching Layer
CacheService (Redis) ├── getCachedAccount(publicKey) ├── setCachedAccount(account) └── invalidateCache(publicKey) -
Rate Limiting
RateLimiterService ├── checkLimit() ├── waitAndRetry() └── exponentialBackoff()
This architecture provides a solid foundation for Stellar blockchain integration in Invoisio.