Skip to content
 
 

Repository files navigation

Stellar PocketPay — Savings Vault Contract

CHANGELOG

Project Status and Scope

This project is currently intended for development, learning, and Stellar testnet usage. It is not production-ready or mainnet-ready.

The savings vault currently uses internal balance tracking: deposit, withdraw, and locking operations update accounting records stored by the contract, but they do not move or custody XLM or other tokens. The contract should therefore not be treated as a real token custody contract.

Supporting real asset deposits and withdrawals in the future may require integration with a Stellar Asset Contract (SAC), including explicit token transfer and custody behavior. See Known Limitations for other current constraints.

Security Considerations

This contract is for educational and testnet use. Review the following before any mainnet deployment.

See the Admin Role document for details on what the initialize(admin) value records, what the admin can and cannot do today, and future admin design considerations.

Features

Function Description
initialize(admin) One-time setup; records the admin address
deposit(user, amount) Add funds to a user's vault
withdraw(user, amount) Remove funds from a user's vault
get_balance(user) Query available (unlocked) balance
lock_funds(user, amount, unlock_time) Lock funds until a Unix timestamp
get_locked_balance(user) Query locked balance
can_withdraw(user) Check if locked funds are withdrawable

Deposit and custody limitation

Deposits currently update internal contract storage only. Calling deposit increases the user's recorded balance for the vault's accounting, but it does not move real XLM, a Stellar Asset Contract (SAC) asset, or any other token into contract custody.

An internal balance is a number maintained by this contract and used by its deposit, withdrawal, and locking logic. Real token custody requires an on-chain asset transfer that moves tokens between addresses and ensures the recorded balance is backed by assets held for the user. That transfer and custody layer is not implemented yet, so the current internal balances must not be treated as proof of deposited or custodied assets.

Future SAC integration is planned to support real asset transfers and custody-backed balances.


Prerequisites

Install the following before you begin:

  1. Rust (latest stable)

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  2. Soroban CLI

    cargo install --locked soroban-cli
  3. WASM target

    rustup target add wasm32-unknown-unknown

Build

Compile the contract to a WASM binary:

# Debug build
cargo build --target wasm32-unknown-unknown

# Optimized release build (recommended for deployment)
cargo build --target wasm32-unknown-unknown --release

# Optimized release build with an immediate WASM size report
make build-release

The compiled .wasm file will be at:

target/wasm32-unknown-unknown/release/savings_vault.wasm

Contract size report

Soroban contract size affects upload and deployment costs and can reveal unexpected binary growth. Use the release wrapper above to build and print the artifact size in both human-readable units and exact bytes:

WASM artifact: target/wasm32-unknown-unknown/release/savings_vault.wasm
WASM size: 5.73 KiB (5871 bytes)

To report the size of an existing release artifact without rebuilding it, run:

make wasm-size

The reporting command exits with an error and identifies the expected path when the WASM file is missing. CI pipelines should run make build-release (or make wasm-size after their release build) so contract-size changes remain visible in build logs.


Test

Run the full unit test suite:

cargo test

All tests run natively (no WASM needed) using the Soroban SDK test utilities.


Task Runner

Common tasks are available via make:

make test        # Run all tests
make build-wasm  # Build the contract WASM in release mode
make clean       # Clean build artifacts

Deploy to Testnet

1. Configure the Stellar Testnet

soroban network add \
  --global testnet \
  --rpc-url https://soroban-testnet.stellar.org:443 \
  --network-passphrase "Test SDF Network ; September 2015"

2. Create & Fund an Identity

soroban keys generate --global deployer --network testnet
soroban keys address deployer

Fund the account at Stellar Friendbot.

  1. Deploy the Contract

Use the automated deployment script to build the release WASM and deploy it to the network. Pass your configured identity (e.g., deployer) as the first argument:

./scripts/deploy-testnet.sh deployer

The script will verify prerequisites, compile the contract, deploy it, and print your new Contract ID. Save the returned Contract ID — you'll need it to invoke functions.

See the deployment output example to learn what successful output looks like and which Contract ID value to copy.

4. Initialize the Contract

soroban contract invoke \
  --id YOUR_CONTRACT_ID \
  --source deployer \
  --network testnet \
  -- \
  initialize \
  --admin deployer

5. Invoke Functions

# Deposit 1000 units
soroban contract invoke \
  --id YOUR_CONTRACT_ID \
  --source deployer \
  --network testnet \
  -- \
  deposit \
  --user deployer \
  --amount 1000

# Check balance
soroban contract invoke \
  --id YOUR_CONTRACT_ID \
  --source deployer \
  --network testnet \
  -- \
  get_balance \
  --user deployer

Project Structure

stellar-pocketpay-contracts/
├── Cargo.toml                          # Workspace root
├── .gitignore
├── README.md
└── contracts/
    └── savings_vault/
        ├── Cargo.toml                  # Contract crate
        └── src/
            ├── lib.rs                  # Contract implementation
            └── test.rs                 # Unit tests
└── docs/
    ├── admin-role.md                   # Admin role documentation
    ├── pause-design.md                 # Pause / emergency stop research
    └── upgrade-strategy.md             # Upgrade strategy research

Documentation

  • Deployment Environments — Network configuration for local, testnet, and future mainnet, including RPC URLs, identities, environment variables, and deployment commands.
  • Contract Error Reference - Current savings vault failure conditions and guidance for SDK and mobile callers.
  • Architecture Documentation – Overview of project structure, state management, storage, SDK integration, and future extension points.
  • Event Schema Documentation – Overview of event names, topics, payload schemas, and JSON examples for vault actions.
  • Vault Contract ID Handoff - How to pass a deployed vault contract ID safely to SDK configuration and the mobile app.

Security Considerations

This contract is for educational and testnet use. Review the following before any mainnet deployment.

Authorization

  • Every state-changing function calls require_auth() on the user's address.
  • Only the signing user can deposit, withdraw, or lock their own funds.

Input Validation

  • Zero and negative amounts are rejected for deposits, withdrawals, and locks.
  • Withdrawals exceeding the available balance are rejected.
  • Lock amounts exceeding the available balance are rejected.
  • Unlock times in the past are rejected.

Re-initialization Protection

  • initialize() can only be called once; subsequent calls panic.

Storage Design

  • User balances are stored in persistent storage (survives ledger expiry longer).
  • Admin and initialization flags use instance storage (tied to contract lifetime).

Known Limitations

  • Internal accounting only; no real token custody: Deposits update contract storage but do not transfer real XLM, SAC assets, or other tokens into custody. Internal balances are accounting entries and are not proof that the contract holds corresponding assets. Future SAC integration is planned to support real asset transfers and custody-backed balances.
  • Single unlock time: Locking funds multiple times overwrites the previous unlock timestamp. A production version might use per-lock entries.
  • No admin recovery: There is no mechanism for the admin to recover or migrate funds.
  • No upgrade mechanism: The contract does not implement upgrade(). See docs/upgrade-strategy.md for research into possible upgrade paths.
  • No pause / emergency stop: There is no mechanism to halt operations in an emergency. See docs/pause-design.md for research and trade-offs.

Deployment Notes

  • Testnet RPC: https://soroban-testnet.stellar.org:443
  • Network passphrase: Test SDF Network ; September 2015
  • Friendbot (free testnet XLM): https://friendbot.stellar.org
  • Soroban Explorer: stellar.expert
  • Deployment help: see the troubleshooting guide for common Soroban CLI, Friendbot, WASM, network, and invocation issues. For a full breakdown of environment-specific configuration, see the deployment environments guide.
  • Always test thoroughly on testnet before considering mainnet deployment.
  • Monitor contract storage TTL and extend as needed using soroban contract extend. See the Storage TTL Guide for persistent vs. instance storage details and example commands.

Contributing

Contributions are welcome! This project is intentionally beginner-friendly.

See CONTRIBUTING.md for the full guide, including:

  • How to format code (cargo fmt)
  • How to lint code (cargo clippy -- -D warnings)
  • How to run the test suite (cargo test)
  • PR checklist and commit message conventions

Quick start:

# Fork & clone, then verify everything is green before making changes
cargo fmt --check
cargo clippy --tests -- -D warnings
cargo test

License

MIT

About

No description, website, or topics provided.

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages