Production-grade Soroban smart contracts for a risk-free, on-chain trading classroom. PeerX gives users a fully simulated environment to learn market mechanics — AMM swaps, liquidity provision, limit & stop-loss orders, staking, referrals, and portfolio analytics — without exposing real capital.
- Overview
- Why PeerX
- Core Capabilities
- Architecture
- Repository Layout
- Tech Stack
- Getting Started
- Usage Examples
- Security Posture
- Testing & Verification
- Migrations & Versioning
- Operational Runbook
- Performance & Benchmarking
- Experimental Modules
- Contributing
- License
- Contact
PeerX Contracts is the on-chain core of PeerX — a Soroban-based educational trading platform that mirrors real-world decentralized exchange mechanics in a fully sandboxed, zero-capital environment.
Every action executes against deterministic contract state with the same primitives users encounter on production AMMs: constant-product pricing, slippage checks, slippage-aware routing across multiple pools, liquidity-provider (LP) positions, fee tiers, and order books. Because the assets are simulated, learners can experiment with adversarial scenarios (front-running, oracle drift, liquidity crises) that would be unsafe and uneconomic against real funds.
| Problem | PeerX's approach |
|---|---|
| New traders learn by losing real money | Risk-free simulator — failures cost only reputation |
| Most "demo" platforms ignore DEX mechanics | Faithful AMM, LP math, fee curves, oracle slippage |
| Educational tools lack defensive engineering | Hardened contracts with KYC gates, risk limits, circuit breakers, formal invariants |
| Hard to teach advanced order types | Native limit and stop-loss orders on-chain |
- Constant-product AMM swaps (
XLM⇄ simulated issued assets). - Multi-pool registry with admin-managed pool creation and LP shares.
- Multi-hop routing — atomic best-route discovery across registered pools.
- Slippage protection — configurable basis-point ceiling per swap.
- Non-panicking
safe_swap— records failed orders as a counter rather than reverting.
- Limit orders that fill when the oracle price crosses a threshold.
- Stop-loss orders that trigger on adverse price movement.
- Order expiry, cancellation, and per-user lookup.
- Add / remove liquidity with proper LP-token minting using the Babylonian integer-sqrt initialization.
- LP positions are first-class: per-user deposits, share-of-pool, and proportional withdrawals.
- Multi-asset balances with non-negative saturation arithmetic.
- Tier system (Basic → Silver → Gold → Platinum) drives fee discounts and rate-limit budgets.
- Portfolio analytics — PnL, win rate, Sharpe-style ratios, top-traders leaderboard.
- Instance-storage query cache with TTL, hit/miss instrumentation, and admin-controlled invalidation.
- KYC state machine with operators,
Pending/Verified/Rejectedtransitions, and an audit trail. - Governance override path for terminal state changes with a configurable timelock.
- Every sensitive entry point is statically guarded (see
scripts/check_kyc_guards.sh).
- Circuit breaker that auto-pauses when swap volume crosses threshold.
- Concentration limits — no single user can dominate the pool.
- Position limits — per-asset exposure caps.
- Rate limiter — tier-aware per-hour budgets for swaps and LP operations.
- Referral system — register referrer relationships, earn commissions distributed from swap fees paid by the referred user.
- Badges & achievements — on-chain, programmatic, batched emission.
- Pause / resume trading (admin-gated).
- Freeze / unfreeze individual accounts.
- State snapshots for forensic and recovery workflows.
- Governance parameters with proposed-update lifecycle (experimental governance modules suggest design patterns, but stake-weighted voting is not implemented).
- Multi-sig compatible — admin authority is a single transferable
Address. Operations teams are expected to secure it behind a multi-sig wallet off-chain.
- Staking bonus manager with 30 / 60 / 90 / 365-day locks, periodic distributions, and 10% early-unstake penalty.
- Transparent distribution history for auditing.
(feature-gated behind experimental)
- NFT platform — minting, marketplace, fractional ownership, lending.
- ZKP / private transactions — commitments, range proofs, witness manager, balance proofs.
- Dynamic fee adjustment — congestion-aware, history-tracked, with emergency override.
- Predictive analytics — confidence-weighted signals.
- Cross-chain bridge hooks.
┌─────────────────────────────────────────┐
│ CounterContract │
│ (single WASM artifact, all entry pts) │
└──────────────┬──────────────────────────┘
│
┌────────────┬───────────┼────────────┬─────────────┐
▼ ▼ ▼ ▼ ▼
Trading Portfolio Risk Governance Identity
(AMM, LP, (balances, (circuit (params, (KYC,
routing) analytics) breaker, pause, freeze, tiers)
limits) snapshot)
│ │ │ │ │
└────────────┴─────┬─────┴────────────┴─────────────┘
▼
Instance / Persistent Storage on Soroban
(with TTL-scoped query cache)
External modules expose a stable, narrow function surface; internal logic is split into focused files (trading.rs, portfolio.rs, kyc.rs, orders.rs, rate_limit.rs, risk_management/*, governance/*, …) so features can be reasoned about in isolation.
PeerX-Contracts/
├── Cargo.toml # Workspace root (counter, soroban-ping)
├── soroban.toml # Soroban network profiles (testnet/mainnet/local)
├── README.md # ← you are here
├── SECURITY.md # Auditing, invariants, trust model
├── .github/
│ ├── workflows/
│ │ ├── ci.yml # Single canonical CI (quality + build + test)
│ │ └── README.md # Workflow rationale
├── scripts/
│ ├── benchmark_cache.py # Portfolio query cache benchmark runner
│ ├── check_kyc_guards.sh # Static audit: every sensitive fn has a KYC guard
│ ├── regression_detection.py
│ ├── verify_formal.sh
│ └── build_optimized.sh
├── benches/ # Release-mode contract benchmarks
├── market-data-streaming/ # Standalone Rust crate (off-chain HFT-grade feed)
└── peerx-contracts/
├── counter/ # Main contract crate (CounterContract)
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs # Contract entry points
│ ├── trading.rs # AMM swap & multi-hop routing
│ ├── portfolio.rs # Balances, tiers, analytics, caching
│ ├── orders.rs # Limit & stop-loss orders
│ ├── rate_limit.rs # Tier-aware rate limiter
│ ├── kyc.rs # KYC state machine
│ ├── referral_system.rs # Referrals & commissions
│ ├── staking_bonus.rs # Locked staking & distributions
│ ├── emergency.rs # Pause / freeze / snapshot
│ ├── migration.rs # Versioned upgrades
│ ├── events.rs # Batched on-chain events
│ └── risk_management/ # Circuit breaker, concentration, limits
├── soroban-ping/ # Hello-world contract, smoke test
├── trading_test_runner/ # Off-chain trading test driver
├── waitlist/ # Standalone waitlist contract
├── referral/ # Standalone referral contract
├── bounty/ # Standalone bounty contract
└── credit-waitlist/ # Standalone credit-waitlist contract
| Layer | Technology |
|---|---|
| Smart contracts | Soroban (soroban-sdk = "21.7.1") |
| Language | Rust (no_std for WASM targets) |
| Build profile | release: opt-level = "z", lto = "fat", panic = "abort" — small, deterministic WASM |
| Off-chain market data | Standalone Rust crate (market-data-streaming/) — WebSocket / REST feeds, order-book analytics, throughput-limiter protections |
| Tooling | Soroban CLI, cargo, rustfmt, clippy |
| CI | GitHub Actions — quality → build → test |
- Rust toolchain (stable, ≥ 1.74) — install via rustup.
- Soroban CLI — setup guide.
wasm32-unknown-unknowntarget:rustup target add wasm32-unknown-unknown.
git clone https://github.com/<REPO_URL>.git
cd peerx-contracts
# Type-check the workspace
cargo check --workspace
# Build the WASM artifact (release)
# Binary name comes from peerx-contracts/counter/Cargo.toml [package].name = "counter"
cargo build --release --target wasm32-unknown-unknown \
--manifest-path peerx-contracts/counter/Cargo.toml
# Run the full test suite
cargo test --workspace --libsoroban contract deploy \
--wasm target/wasm32-unknown-unknown/release/counter.wasm \
--network testnet \
--source <YOUR_STELLAR_SECRET_KEY>
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
--source <YOUR_STELLAR_SECRET_KEY> \
-- initializeAll calls shown are thin wrappers around the contract — the same calls are invoked from the JS SDK or CLI.
soroban contract invoke --id <CONTRACT_ID> --network testnet \
-- mint --token XLM --to <USER_ADDRESS> --amount 1000000soroban contract invoke --id <CONTRACT_ID> --network testnet \
--source <USER_SECRET> \
-- swap --from XLM --to USDCSIM --amount 1000 --user <USER_ADDRESS>soroban contract invoke --id <CONTRACT_ID> --network testnet \
--source <USER_SECRET> \
-- add_liquidity --xlm_amount 5000 --usdc_amount 5000 --user <USER_ADDRESS>soroban contract invoke --id <CONTRACT_ID> --network testnet \
-- source <USER_SECRET> \
-- place_limit_order \
--token_in XLM --token_out USDCSIM \
--amount_in 100 --limit_price 150 \
--user <USER_ADDRESS># User submits
soroban contract invoke --id <CONTRACT_ID> --network testnet \
--source <USER_SECRET> -- kyc_submit --user <USER_ADDRESS>
# Operator approves after review
soroban contract invoke --id <CONTRACT_ID> --network testnet \
--source <OPERATOR_SECRET> \
-- kyc_update_status --operator <OPERATOR_ADDRESS> \
--user <USER_ADDRESS> --new_status Verifiedsoroban contract invoke --id <CONTRACT_ID> --network testnet \
-- get_portfolio --user <USER_ADDRESS>We treat the contract suite as auditable production code even though assets are simulated.
- Authorization — every privileged function goes through
require_adminorrequire_authenticated_verified_user. CI statically enforces this (scripts/check_kyc_guards.sh). - Arithmetic — all balance and fee math uses
saturating_*operations; divisions guard zero denominators. - Reentrancy — Soroban's deterministic execution model prevents reentrancy by design; the codebase also never makes cross-contract calls mid-mutation.
- Risk controls — circuit breaker, concentration and position limits are evaluated on every swap.
- Invariants — asset conservation, AMM constant-product non-increase, fee-bounds, and LP-token conservation are enforced and exposed via formal property tests (
tests/formal_verification_tests.rs). - Rate limits — tier-aware throttles for both swaps and LP operations, with garbage-collectable per-user state.
- Emergency — admin pause, per-account freeze, on-chain state snapshots for forensic recovery.
- Fuzzing —
cargo test fuzz_ -- --nocaptureexercises edge cases on every entry point.
See SECURITY.md for the full vulnerability checklist, invariant specifications, and authorization matrix.
cargo test --workspace --lib --verbose # Library suites
cargo test --manifest-path peerx-contracts/counter/Cargo.toml \
--lib kyc_tests -- --nocapture # KYC focused
cargo test --manifest-path peerx-contracts/counter/Cargo.toml \
error_code_tests -- --nocapture # Error-code regression
cargo test --manifest-path peerx-contracts/counter/Cargo.toml \
--test formal_verification_tests formal_verification \
-- --nocapture --test-threads=1 # Property-based invariantsCI is a single workflow — .github/workflows/ci.yml — running three jobs in series: quality (fmt + check + KYC-guard audit) → build (full workspace build) → test (the four commands above).
PeerX supports versioned, in-place upgrades with a deterministic migration pipeline.
CONTRACT_VERSIONis declared inlib.rsand persisted in contract storage.initialize()is called on fresh deployments to record the active version.migrate()performs version-to-version data migration; example:migrate_from_v1_to_v2augmentsPortfoliowithmigration_time.
Upgrade checklist
- Bump
CONTRACT_VERSION. - Implement
migrate_from_vN_to_vN+1. - Add tests under
migration_tests.rssimulating the transition. - Verify backward compatibility of every persisted struct.
- Run
migrate()after deploying the new WASM.
For incident response:
| Step | Action | Contract call |
|---|---|---|
| 1 | Investigate | read events, state, snapshots |
| 2 | Halt trading | emergency_pause(admin) |
| 3 | Freeze suspect accounts | freeze_user(admin, user) |
| 4 | Capture forensic state | snapshot_state() |
| 5 | Fix root cause off-chain | deploy new WASM |
| 6 | Migrate & resume | migrate() → emergency_unpause(admin) |
The circuit breaker will auto-pause when swap volume crosses the configured threshold — a safety net, not a substitute for monitoring.
python3 scripts/benchmark_cache.pyMeasures cold-vs-warm latency for get_portfolio and get_top_traders, plus cache hit ratio, against the release-mode ignored test benchmark_cache_latency_and_hit_ratio.
For raw contract benchmarks:
cargo bench --manifest-path benches/Cargo.tomlThe following sit behind the experimental feature flag and are not mainnet-ready yet:
- 🎨 NFT platform — minting, marketplace, fractional ownership, lending (
nft_*modules). - 🔐 ZKP / private transactions — commitments, range proofs, witness manager (
zkp_*modules). - 📈 Dynamic fee adjustment — congestion-aware with
FeeHistoryManagerand emergency override. - 🌉 Bridge — cross-chain hooks.
- 📊 Predictive analytics — confidence-weighted signals.
Each experimental module has its own test suite gated by the same feature flag; CI does not opt into them, so experiments can iterate quickly without breaking the canonical suite.
We welcome pull requests for new educational scenarios, additional test coverage, performance wins, and documentation. Please read CONTRIBUTING.md (when present) and:
- Run
cargo fmt --allbefore pushing. - Add tests for any new entry point.
- Add the entry point to
scripts/check_kyc_guards.shif it touches user funds. - Keep PRs focused — one feature or fix per PR.
MIT. (No LICENSE file is currently committed — add one before publishing. Until then, all rights reserved by default.)
- Issues:
https://github.com/<REPO_URL>/issues - Security disclosures:
<SECURITY_EMAIL> - Project:
https://github.com/<REPO_URL>
PeerX Contracts — learn markets the hard way, without losing money.