Soroban smart contracts for the RemitLend decentralized lending platform on Stellar. These contracts handle NFT minting, loan management, and lending pool operations.
RemitLend uses three core smart contracts:
- Remittance NFT - Stores credit scores and remittance history as NFTs
- Loan Manager - Manages the complete loan lifecycle
- Lending Pool - Handles liquidity deposits and withdrawals
- Rust Toolchain (latest stable)
- Soroban CLI
- wasm32-unknown-unknown target
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Add wasm32 target
rustup target add wasm32-unknown-unknown
# Install Soroban CLI
cargo install --locked soroban-clicontracts/
├── remittance_nft/ # NFT contract for credit scores
│ ├── src/
│ │ ├── lib.rs # Main contract logic
│ │ └── test.rs # Contract tests
│ ├── test_snapshots/ # Test snapshots
│ └── Cargo.toml
├── loan_manager/ # Loan lifecycle management
│ ├── src/
│ │ ├── lib.rs
│ │ └── test.rs
│ ├── test_snapshots/
│ └── Cargo.toml
├── lending_pool/ # Liquidity pool management
│ ├── src/
│ │ ├── lib.rs
│ │ └── test.rs
│ ├── test_snapshots/
│ └── Cargo.toml
├── Cargo.toml # Workspace configuration
├── Cargo.lock
└── README.md
# From contracts directory
cargo build --target wasm32-unknown-unknown --release# Build only NFT contract
cargo build -p remittance_nft --target wasm32-unknown-unknown --release
# Build only Loan Manager
cargo build -p loan_manager --target wasm32-unknown-unknown --release
# Build only Lending Pool
cargo build -p lending_pool --target wasm32-unknown-unknown --releaseCompiled WASM files are located at:
target/wasm32-unknown-unknown/release/
├── remittance_nft.wasm
├── loan_manager.wasm
└── lending_pool.wasm
cargo test# Test NFT contract
cargo test -p remittance_nft
# Test Loan Manager
cargo test -p loan_manager
# Test Lending Pool
cargo test -p lending_pool# Show println! output
cargo test -- --nocapture
# Show test names
cargo test -- --test-threads=1 --nocapture# Install tarpaulin
cargo install cargo-tarpaulin
# Generate coverage report
cargo tarpaulin --out HtmlPurpose: Mint and manage NFTs representing borrower credit scores.
Key Functions:
// Initialize the contract
pub fn initialize(env: Env, admin: Address)
// Mint a new NFT
pub fn mint_nft(env: Env, owner: Address, score: u32) -> u64
// Update credit score
pub fn update_score(env: Env, nft_id: u64, new_score: u32)
// Update remittance history hash
pub fn update_history_hash(env: Env, nft_id: u64, hash: BytesN<32>)
// Get NFT score
pub fn get_score(env: Env, nft_id: u64) -> u32
// Lock NFT (for loan collateral)
pub fn lock_nft(env: Env, nft_id: u64)
// Unlock NFT (after loan repayment)
pub fn unlock_nft(env: Env, nft_id: u64)Storage Keys:
NFT_COUNTER- Total NFTs mintedNFT_OWNER_{id}- NFT ownership mappingNFT_SCORE_{id}- Credit score storageNFT_HASH_{id}- Remittance history hashNFT_LOCKED_{id}- Lock status
Tests:
- ✅ Mint NFT flow
- ✅ Update score
- ✅ Update history hash
- ✅ Lock/unlock NFT
- ✅ Unauthorized access prevention
- ✅ Migration compatibility
Purpose: Coordinate loan requests, approvals, and repayments.
Key Functions:
// Initialize the contract
pub fn initialize(env: Env, admin: Address, pool_address: Address)
// Request a loan
pub fn request_loan(
env: Env,
borrower: Address,
nft_id: u64,
amount: i128
) -> u64
// Approve a loan
pub fn approve_loan(env: Env, loan_id: u64)
// Repay loan
pub fn repay_loan(env: Env, loan_id: u64, amount: i128)
// Get loan details
pub fn get_loan(env: Env, loan_id: u64) -> Loan
// Check loan status
pub fn get_loan_status(env: Env, loan_id: u64) -> LoanStatusLoan States:
pub enum LoanStatus {
Requested, // Loan requested, awaiting approval
Approved, // Approved, funds disbursed
Active, // Repayment in progress
Repaid, // Fully repaid
Defaulted, // Payment missed
}Business Logic:
- Minimum credit score: 600
- Maximum loan-to-value: 80%
- Interest rate: Based on credit score
- Repayment period: Configurable
Tests:
- ✅ Loan request flow
- ✅ Loan approval flow
- ✅ Repayment flow
- ✅ Low score rejection
- ✅ Unauthorized repayment prevention
- ✅ Access controls
Purpose: Manage lender deposits and loan fund allocation.
Key Functions:
// Initialize the contract
pub fn initialize(env: Env, admin: Address)
// Deposit funds
pub fn deposit(env: Env, lender: Address, amount: i128)
// Withdraw funds
pub fn withdraw(env: Env, lender: Address, amount: i128)
// Get available liquidity
pub fn get_available_liquidity(env: Env) -> i128
// Allocate funds for loan (called by Loan Manager)
pub fn allocate_funds(env: Env, loan_id: u64, amount: i128)
// Return funds from repayment (called by Loan Manager)
pub fn return_funds(env: Env, loan_id: u64, amount: i128)
// Get lender balance
pub fn get_lender_balance(env: Env, lender: Address) -> i128Pool Mechanics:
- Proportional share tracking
- Interest distribution
- Reserve ratio maintenance
- Withdrawal limits
Tests:
- ✅ Deposit flow
- ✅ Withdrawal flow
- ✅ Liquidity tracking
- ✅ Unauthorized access prevention
- ✅ Fund allocation
# Set up Soroban identity
soroban keys generate --global alice --network testnet
# Deploy NFT contract
soroban contract deploy \
--wasm target/wasm32-unknown-unknown/release/remittance_nft.wasm \
--source alice \
--rpc-url https://soroban-testnet.stellar.org \
--network-passphrase "Test SDF Network ; September 2015"
# Save the contract ID
export NFT_CONTRACT_ID=<contract_id>
# Initialize the contract
soroban contract invoke \
--id $NFT_CONTRACT_ID \
--source alice \
--rpc-url https://soroban-testnet.stellar.org \
--network-passphrase "Test SDF Network ; September 2015" \
-- initialize \
--admin <admin_address># Deploy and initialize all three contracts
./scripts/deploy.sh testnet# Check contract info
soroban contract info \
--id $NFT_CONTRACT_ID \
--rpc-url https://soroban-testnet.stellar.org# Mint an NFT
soroban contract invoke \
--id $NFT_CONTRACT_ID \
--source alice \
-- mint_nft \
--owner <owner_address> \
--score 750
# Get NFT score
soroban contract invoke \
--id $NFT_CONTRACT_ID \
-- get_score \
--nft_id 1
# Request a loan
soroban contract invoke \
--id $LOAN_MANAGER_ID \
--source alice \
-- request_loan \
--borrower <borrower_address> \
--nft_id 1 \
--amount 1000000000import { Contract, SorobanRpc } from '@stellar/stellar-sdk';
const contract = new Contract(contractId);
const server = new SorobanRpc.Server('https://soroban-testnet.stellar.org');
// Call contract method
const result = await contract.call('get_score', [nftId]);
console.log('Score:', result);# Format code
cargo fmt
# Check code quality
cargo clippy
# Fix clippy warnings
cargo clippy --fix- Use
Resulttypes for error handling - Avoid panics in production code
- Write comprehensive tests
- Document public functions
- Use descriptive variable names
- Keep functions small and focused
# Generate documentation
cargo doc --open
# Generate docs for all contracts
cargo doc --workspace --open- Admin-only functions protected
- Owner verification for sensitive operations
- Contract-to-contract authentication
- Input parameter validation
- Score range checks (0-1000)
- Amount validation (positive values)
- NFT existence verification
Soroban provides built-in reentrancy protection through its execution model.
Rust's type system prevents integer overflow in debug mode. Use checked arithmetic in production.
// Good
let result = amount.checked_add(interest)?;
// Avoid
let result = amount + interest;Soroban contracts can be upgraded using the upgrade mechanism:
# Build new version
cargo build --target wasm32-unknown-unknown --release
# Upgrade contract
soroban contract upgrade \
--id $CONTRACT_ID \
--wasm target/wasm32-unknown-unknown/release/contract.wasm \
--source admin- Test upgrades on testnet first
- Implement data migration functions
- Maintain backward compatibility
- Document breaking changes
# Clean build artifacts
cargo clean
# Update dependencies
cargo update
# Rebuild
cargo build --target wasm32-unknown-unknown --release# Run tests with verbose output
cargo test -- --nocapture
# Run specific test
cargo test test_name -- --nocapture# Check Soroban CLI version
soroban --version
# Verify network connectivity
curl https://soroban-testnet.stellar.org
# Check account balance
soroban keys address aliceSee CONTRIBUTING.md for guidelines.
cargo fmt
cargo clippy
cargo test
cargo build --target wasm32-unknown-unknown --releaseISC License - See LICENSE file for details.
- Open an issue for bug reports
- Check existing issues before creating new ones
- Provide error messages and logs
- Include contract IDs for deployment issues