Title: feat: Stellar SDK Integration — Wire Transaction Service to Soroban RPC
Labels: backend, blockchain, core, priority-high
Description:
VaultLink has a complete off-chain foundation — the NestJS backend,
PostgreSQL data layer, and authentication are all working. However,
the transaction service currently calls stub methods like
this.transactionService.createInvoiceToken(invoice) that do not
actually submit anything to the Stellar network.
This issue connects the working API to the actual Stellar network
by implementing real Soroban RPC calls inside
src/transaction/transaction.service.ts, making VaultLink a
fully functioning decentralized financing protocol.
What Needs to Be Done:
Stellar SDK Integration (src/transaction/transaction.service.ts):
- Replace all stub/mock transaction calls with real Stellar SDK logic
- Implement buildAndSubmitTransaction() helper:
- Build Soroban contract invocation transaction using stellar-sdk
- Sign with server keypair from environment
- Submit to Soroban RPC endpoint
- Handle simulation before submission (simulateTransaction)
- Handle fee bumping for failed submissions
- Return transaction hash on success
- Implement the following real contract calls:
createInvoiceToken(invoice) — calls invoice_registry
register_invoice() on-chain
fundEscrow(offer) — calls escrow fund_invoice() on-chain
releaseEscrow(invoiceId, yieldAmount) — calls escrow
release_to_lender() on-chain
reclaimEscrow(invoiceId) — calls escrow reclaim() on-chain
- Error handling:
Distinguish between simulation errors and submission errors
Retry on transient RPC failures (max 3 attempts)
Never update DB status if on-chain call fails
Environment Configuration (.env):
- Add the following to .env.example:
SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
SOROBAN_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
INVOICE_REGISTRY_CONTRACT_ID=
ESCROW_CONTRACT_ID=
YIELD_ORACLE_CONTRACT_ID=
SERVER_SIGNING_KEY=
- Update ConfigService to validate all contract IDs at startup
- App refuses to start if CONTRACT_IDs are missing in production
StellarService (src/stellar/stellar.service.ts):
- invokeContract(contractId, method, args) — generic contract
invocation wrapper
- getContractValue(contractId, key) — read contract storage
- simulateAndSubmit(transaction) — simulate first, then submit
- parseContractError(error) — extract human-readable error from
Soroban diagnostic events
Key Files:
- apps/backend/src/transaction/transaction.service.ts (update)
- apps/backend/src/stellar/stellar.service.ts (update)
- apps/backend/src/config/config.service.ts (update)
- apps/backend/.env.example (update)
Acceptance Criteria:
- createInvoiceToken() submits a real transaction to Stellar testnet
- fundEscrow() locks real USDC in escrow contract on testnet
- releaseEscrow() transfers funds to lender wallet on testnet
- reclaimEscrow() returns funds to lender on default on testnet
- All contract IDs loaded from environment — never hardcoded
- Simulation runs before every submission — no wasted fees
- App startup fails with clear message if CONTRACT_IDs not set
- Transaction hash returned and stored for every on-chain call
- DB status never updated if on-chain call fails
- Unit tests mock Stellar SDK and test success and failure paths
- Integration test submits a real transaction to Stellar testnet
Security Notes:
- SERVER_SIGNING_KEY loaded from environment only — never hardcoded
- Signing key never logged or included in error responses
- Simulation used before every submission to catch errors early
- Retry logic has maximum 3 attempts to prevent fee drain
- All contract addresses validated as valid Stellar contract IDs
at startup
Branch: feat/stellar-sdk-transaction-integration
Commit: feat(transaction): wire transaction service to Soroban RPC with real contract invocations
Title: feat: Stellar SDK Integration — Wire Transaction Service to Soroban RPC
Labels: backend, blockchain, core, priority-high
Description:
VaultLink has a complete off-chain foundation — the NestJS backend,
PostgreSQL data layer, and authentication are all working. However,
the transaction service currently calls stub methods like
this.transactionService.createInvoiceToken(invoice) that do not
actually submit anything to the Stellar network.
This issue connects the working API to the actual Stellar network
by implementing real Soroban RPC calls inside
src/transaction/transaction.service.ts, making VaultLink a
fully functioning decentralized financing protocol.
What Needs to Be Done:
Stellar SDK Integration (src/transaction/transaction.service.ts):
createInvoiceToken(invoice) — calls invoice_registry
register_invoice() on-chain
fundEscrow(offer) — calls escrow fund_invoice() on-chain
releaseEscrow(invoiceId, yieldAmount) — calls escrow
release_to_lender() on-chain
reclaimEscrow(invoiceId) — calls escrow reclaim() on-chain
Distinguish between simulation errors and submission errors
Retry on transient RPC failures (max 3 attempts)
Never update DB status if on-chain call fails
Environment Configuration (.env):
SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
SOROBAN_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
INVOICE_REGISTRY_CONTRACT_ID=
ESCROW_CONTRACT_ID=
YIELD_ORACLE_CONTRACT_ID=
SERVER_SIGNING_KEY=
StellarService (src/stellar/stellar.service.ts):
invocation wrapper
Soroban diagnostic events
Key Files:
Acceptance Criteria:
Security Notes:
at startup
Branch: feat/stellar-sdk-transaction-integration
Commit: feat(transaction): wire transaction service to Soroban RPC with real contract invocations