This guide provides an end-to-end walkthrough for setting up and running the complete Stellar-Spend stack locally — covering the Rust smart contracts toolchain, Soroban CLI, PostgreSQL database, and Next.js frontend dev server, along with common troubleshooting steps for Soroban and Stellar RPC errors.
- Prerequisites & System Requirements
- Step-by-Step Setup
- Contract Development Workflow
- Frontend & API Development Workflow
- Troubleshooting Guide
- Clean Machine Verification Checklist
Before beginning, ensure you have the following installed on your development machine:
| Component | Required Version | Purpose | Installation |
|---|---|---|---|
| Node.js | >= 20.x (LTS recommended) |
Next.js frontend & backend API routes | nodejs.org or nvm install 20 |
| npm | >= 10.x |
Node package manager | Bundled with Node.js |
| Rust | Stable toolchain (>= 1.79.0) |
Compiling Soroban smart contracts | rustup.rs (curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh) |
| wasm32 Target | wasm32-unknown-unknown |
Compiling Rust contracts to WebAssembly | rustup target add wasm32-unknown-unknown |
| Stellar CLI | >= 21.0.0 (Soroban CLI) |
Contract building, deployment, and simulation | cargo install --locked stellar-cli or via Homebrew / binary |
| PostgreSQL | >= 14.x (or Docker) |
Transaction records, idempotency keys, API keys | postgresql.org or docker compose |
| Git | >= 2.30 |
Version control | git-scm.com |
| Stellar Wallet | Browser extension | Freighter or Lobstr wallet for transaction signing | Freighter / Lobstr |
git clone https://github.com/Lex-Studios/Stellar-Spend.git
cd Stellar-SpendInstall all root dependencies:
npm installVerify Node.js version compatibility:
node -v # Must output >= v20.0.0
npm -v # Must output >= 10.0.0-
Install Rust and WebAssembly compilation target:
# Install Rust stable if not installed curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y source "$HOME/.cargo/env" # Add WebAssembly target rustup target add wasm32-unknown-unknown # Install Cargo development tools cargo install cargo-audit --locked
-
Install the Stellar CLI (formerly Soroban CLI):
cargo install --locked stellar-cli --features opt
-
Verify CLI installations:
rustc --version cargo --version stellar --version
Stellar-Spend requires PostgreSQL to store transaction histories, API keys, and notification records.
docker compose up -d postgres# Create local database
createdb stellar_spend
# Apply migration files in numerical sequence
psql stellar_spend < migrations/001_create_transactions.sql
psql stellar_spend < migrations/002_add_transaction_analytics_fields.sql
psql stellar_spend < migrations/003_create_idempotency_keys.sql
psql stellar_spend < migrations/004_create_transaction_notifications.sql
psql stellar_spend < migrations/005_create_api_keys.sql
psql stellar_spend < migrations/006_create_webhook_deliveries.sql
psql stellar_spend < migrations/007_create_user_profiles.sql
psql stellar_spend < migrations/008_create_corridor_overrides.sql
psql stellar_spend < migrations/009_create_settlement_batches.sql
psql stellar_spend < migrations/010_create_escrow_events.sql
psql stellar_spend < migrations/011_create_contract_audit_log.sqlCopy the example environment configuration:
cp .env.example .env.localOpen .env.local and set required configuration keys:
# ==========================================
# Core Application Configuration
# ==========================================
NODE_ENV=development
PORT=3001
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/stellar_spend
# ==========================================
# Stellar & Soroban RPC Configuration
# ==========================================
STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org
STELLAR_SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
STELLAR_NETWORK_PASSPHRASE="Test SDF Network ; September 2015"
# Browser-exposed Stellar settings (Required for Freighter wallet)
NEXT_PUBLIC_STELLAR_SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
NEXT_PUBLIC_STELLAR_NETWORK_PASSPHRASE="Test SDF Network ; September 2015"
NEXT_PUBLIC_STELLAR_USDC_ISSUER=GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5
# ==========================================
# Base Chain & Paycrest Configuration
# ==========================================
BASE_RPC_URL=https://mainnet.base.org
BASE_PRIVATE_KEY=0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
BASE_RETURN_ADDRESS=0x0000000000000000000000000000000000000000
NEXT_PUBLIC_BASE_RETURN_ADDRESS=0x0000000000000000000000000000000000000000
PAYCREST_API_KEY=dev_paycrest_key
PAYCREST_WEBHOOK_SECRET=dev_webhook_secretSecurity Note: Secrets like
BASE_PRIVATE_KEY,PAYCREST_API_KEY, andPAYCREST_WEBHOOK_SECRETmust never use theNEXT_PUBLIC_prefix.
The project contains four Soroban contracts in the contracts/ directory:
escrow— USDC escrow during bridge operationsfee-manager— Calculation and collection of protocol feestreasury— Protocol fee accumulation and payoutsmultisig-authority— Multi-signer administrative authority
Build all smart contracts to WebAssembly:
cd contracts
cargo build --target wasm32-unknown-unknown --release
cd ..Run contract unit and integration tests:
cd contracts
cargo test --workspace
cd ..Start the local development server:
npm run devOpen your browser:
- Application UI: http://localhost:3001
- Interactive Swagger OpenAPI Docs: http://localhost:3001/api/docs
- Health check endpoint:
curl http://localhost:3001/api/health
Run Clippy and Rustfmt checks before committing contract code:
# Format Rust contract code
cargo fmt --workspace --manifest-path contracts/Cargo.toml
# Check for Clippy warnings (strict mode matching CI)
cargo clippy --workspace --manifest-path contracts/Cargo.toml -- -D warnings
# Security audit on Rust dependencies
./scripts/audit-contracts.shTo deploy a contract to Stellar Testnet using the automated deployment script:
# Create a testnet identity if you haven't yet
stellar keys generate --network testnet admin
ADMIN_SECRET=$(stellar keys show admin)
# Run deployment script
./scripts/deploy-contract.sh testnet escrow $ADMIN_SECRETThe script compiles the WASM, deploys the contract to Testnet, and writes the resulting contract ID to contracts/.deployed-testnet.json.
Run checks locally to ensure CI passes:
# ESLint
npm run lint
# TypeScript type check (zero errors required)
npm run type:check
# Prettier formatting check
npm run format:check
# Run Storybook for isolated UI components
npm run storybook- Cause: An outdated dependency pulled in an older
ethnumversion whensoroban-sdkversions are mismatched. - Fix: Stellar-Spend workspace pins
soroban-sdkto version22. Ensure allcontracts/*/Cargo.tomlfiles specifysoroban-sdk = "22"and run:cargo update --manifest-path contracts/Cargo.toml
- Cause: The WebAssembly target is not installed in your Rust toolchain.
- Fix:
rustup target add wasm32-unknown-unknown
- Cause: The deployed contract schema version does not match the expected
SCHEMA_VERSIONin the code. - Fix: When modifying contract storage layouts:
- Call
migrate()on the contract instance using admin authorization. - For tests, ensure
with_legacy_v1_state()seeds matching schemas.
- Call
- Cause: The account sequence number used in
TransactionBuilderis out of date because another transaction was submitted concurrently or cached. - Fix: Always query the latest sequence number from Horizon immediately before building the transaction:
const account = await server.getAccount(publicKey); const tx = new TransactionBuilder(account, ...);
- Cause: The Stellar account does not hold sufficient XLM to cover the base reserve (minimum 2 XLM + 0.5 XLM per sub-entry/trustline) plus the transaction fee, or USDC balance is lower than the transfer amount.
- Fix:
- Fund the testnet account via Friendbot:
curl "https://friendbot.stellar.org?addr=<PUBLIC_KEY>" - Ensure the user has added a USDC trustline (
NEXT_PUBLIC_STELLAR_USDC_ISSUER). - Switch fee payment method from
native(XLM) tostablecoin(USDC) if XLM is low.
- Fund the testnet account via Friendbot:
- Cause: Soroban contract invocation arguments (
ScVal) are malformed or invalid types. - Fix:
- Verify parameter order matches the contract function signature.
- Ensure
Addressobjects are correctly converted usingnew Address(key).toScVal(). - For integers (
i128), usenativeToScVal(BigInt(amount), { type: 'i128' }).
- Cause: Submitting a transaction without assembling the simulation result.
- Fix: Always assemble the transaction with simulation data before sending:
const simResult = await server.simulateTransaction(tx); if (rpc.Api.isSimulationError(simResult)) throw new Error(simResult.error); const preparedTx = rpc.assembleTransaction(tx, simResult).build();
- Cause: The active network in Freighter does not match the network passphrase configured in the app.
- Fix:
- Open the Freighter browser extension → Settings → Network.
- Select the network matching your
.env.local(MainnetorTestnet).
- Cause: Browser extension is locked, not installed, or origin is not HTTPS/localhost.
- Fix:
- Unlock Freighter/Lobstr extension.
- Access the local development server strictly via
http://localhost:3001.
- Cause: Required environment variables are missing from
.env.localor fail schema validation insrc/lib/env.ts. - Fix:
- Compare your
.env.localagainst.env.example. - Ensure all required keys (e.g.,
PAYCREST_API_KEY,BASE_PRIVATE_KEY,STELLAR_SOROBAN_RPC_URL) are populated.
- Compare your
- Cause: PostgreSQL service is not running or port 5432 is blocked.
- Fix:
- If using Docker:
docker compose up -d postgres - If using local service:
sudo service postgresql startorbrew services start postgresql
- If using Docker:
To verify your clean development setup from scratch:
-
git cloneinto an empty directory -
npm installinstalls without peer dependency errors -
rustup target add wasm32-unknown-unknownconfigured -
cargo test --workspacepasses incontracts/ -
docker compose up -d postgres(or local PostgreSQL) active -
cp .env.example .env.localfilled out -
npm run devstarts dev server onhttp://localhost:3001 -
curl http://localhost:3001/api/healthreturns{"status":"ok"} -
http://localhost:3001/api/docsloads Swagger API documentation