Skip to content

Stellar SDK Integration — Wire Transaction Service to Soroban RPC #24

@samjay8

Description

@samjay8

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions