Stellar Soroban smart contracts for the BlueCollar protocol, written in Rust.
| Contract | Description |
|---|---|
registry |
On-chain worker registrations, curator management, staking, badges |
market |
Token tips, escrow payments, arbitration, protocol fee |
dispute |
Full dispute lifecycle — file → evidence → arbitrator decision → settle |
fee_distribution |
Protocol fee collection and percentage-based distribution to multiple recipients |
insurance_pool |
On-chain insurance pool for worker payments — contributions, claims, rebalancing |
Every public function on every contract is documented with rustdoc (///) comments in
its lib.rs. The consolidated, per-contract reference — function signatures, storage
maps, event catalogue, and the common auth/TTL/upgrade patterns shared across all five
contracts — lives in docs/CONTRACTS.md. See
VERSIONING.md for how interface changes are versioned across
releases (distinct from the WASM upgrade mechanics below).
| Tool | Minimum version | Notes |
|---|---|---|
| Rust (stable) | 1.74.0 | Soroban SDK 26.x requires this edition and feature set |
| soroban-sdk | 26.1.0 | All contracts pin to this version for ABI consistency |
| Stellar CLI | 21.x | Used for stellar contract deploy / invoke / install |
| wasm32v1-none | (bundled with Rust) | Added via rustup target add wasm32v1-none |
All member crates in the workspace declare
soroban-sdk = "26.1.0"(except thefuzzcrate which also accepts"26.1.0"). Do not mix SDK versions across contracts — the Soroban host environment enforces ABI compatibility and mismatched versions cause silent runtime panics.
# Rust + wasm target
rustup target add wasm32v1-none
# Stellar CLI
cargo install --locked stellar-cli
# Fund a testnet account (one-time)
stellar keys generate --global deployer
stellar keys fund deployer --network testnetcd packages/contracts
# Build both contracts
make build
# Or individually
make build-registry
make build-marketWASM outputs land in target/wasm32v1-none/release/.
Run contract coverage locally from packages/contracts:
rustup component add llvm-tools-preview
cargo install --locked cargo-llvm-cov
cargo llvm-cov --workspace --lcov --output-path target/coverage/lcov.info --fail-under-lines 80The CI job uploads the generated coverage report as an artifact from packages/contracts/target/coverage.
Run the standard test suite:
cd packages/contracts
cargo test --workspacePer-contract tests live in each crate's src/test.rs and cover that contract alone. Tests that
chain two or more contracts together live in contracts/integration/tests/, run against the
in-process Soroban testnet, and deploy fresh instances per test. Shared deployment helpers are in
tests/common/mod.rs; add new ones there rather than duplicating setup per file.
| File | Flow covered |
|---|---|
e2e.rs |
Registry worker registration and status toggling; market tips with fee split; market escrow create and release; register a worker then tip them |
dispute_flow.rs |
Dispute filed on locked funds, evidence from both parties, arbitrator decides a split, settlement pays each side its share; market escrow arbitration driven by the dispute contract's ruling; escrow contract dispute resolved against the worker refunds the depositor |
insurance_flow.rs |
Escrowed job lost at arbitration, the covered party files an insurance claim, the claims manager approves and pays it, pool balance and claim totals reconcile |
reputation_flow.rs |
Completed escrow jobs feed reviews that raise a worker's score and earn a badge; a dispute resolved against the worker slashes the score and revokes the badge |
Run one flow at a time with:
cargo test -p bluecollar-integration --test dispute_flowWhen adding a cross-contract scenario, extend the matching file if the flow fits an existing area,
or add a new *_flow.rs file plus a row in this table.
The fuzz crate includes property-based tests using proptest that verify critical contract invariants
with randomly generated inputs. These tests focus on amount validation, authorization edge cases,
and state transitions for payment, escrow, and registry contracts.
Run property-based fuzz tests:
cd packages/contracts/contracts/fuzz
cargo test --test "*_fuzz" --features testutilsTest coverage includes:
payment_fuzz.rs— Lock/release/refund payments, fee deduction, amount safetyescrow_fuzz.rs— Create/release/cancel escrow, expiry handling, state transitionsregistry_fuzz.rs— Worker registration, reputation updates, delegationmarket_fuzz.rs— Tip transfers, escrow creation, fee calculationsupgrade_fuzz.rs— Contract upgrade mechanics
Key invariants tested:
- ✓ Amounts never overflow or underflow
- ✓ Zero amounts are rejected
- ✓ Fee calculations remain correct across all fee rates (0–500 bps)
- ✓ Authorization checks prevent unauthorized actions
- ✓ State transitions preserve invariants (e.g., locked payments cannot be double-released)
make deploy-testnet \
SOURCE=deployer \
ADMIN=<your-stellar-address> \
FEE_RECIPIENT=<treasury-address> \
FEE_BPS=100This runs deploy-registry.sh then deploy-market.sh and writes both contract IDs
to deployments.json.
make deploy-mainnet \
SOURCE=<mainnet-key-alias> \
ADMIN=<admin-address> \
FEE_RECIPIENT=<treasury-address> \
FEE_BPS=100# Registry
./scripts/deploy-registry.sh \
--network testnet \
--source deployer \
--admin <admin-address>
# Market
./scripts/deploy-market.sh \
--network testnet \
--source deployer \
--admin <admin-address> \
--fee-bps 100 \
--fee-recipient <treasury-address>After each deploy the contract IDs are stored in deployments.json:
{
"testnet": {
"registry": {
"contract_id": "C...",
"admin": "G...",
"deployed_at": "2026-01-01T00:00:00Z"
},
"market": {
"contract_id": "C...",
"admin": "G...",
"fee_bps": 100,
"fee_recipient": "G...",
"deployed_at": "2026-01-01T00:00:00Z"
}
}
}Upgrades preserve the contract ID and all storage.
# 1. Install new WASM, get its hash
stellar contract install \
--wasm target/wasm32v1-none/release/bluecollar_registry.wasm \
--source <admin-key> \
--network testnet
# → <new_wasm_hash>
# 2. Invoke upgrade
stellar contract invoke \
--id <contract-id> \
--source <admin-key> \
--network testnet \
-- upgrade \
--new_wasm_hash <new_wasm_hash>
# 3. If the storage schema changed, run migrate
stellar contract invoke \
--id <contract-id> \
--source <admin-key> \
--network testnet \
-- migrate \
--admin <admin-address> \
--expected_version <N>See SECURITY.md for the full migration pattern.
Soroban persistent entries expire after a TTL measured in ledgers.
| Constant | Value | Approx. duration |
|---|---|---|
TTL_EXTEND_TO |
535,000 ledgers | ~1 year |
TTL_THRESHOLD |
267,500 ledgers | ~6 months |
Every write automatically extends the TTL. A public extend_worker_ttl(id) function
lets anyone refresh a worker entry without special permissions.
See SECURITY.md for the full threat model, auth table, overflow analysis, and migration pattern.
| Document | Covers |
|---|---|
| docs/CONTRACTS.md | Full interface reference: functions, storage, events, per-contract |
| VERSIONING.md | Interface/semver versioning policy for public functions |
| UPGRADE_GUIDE.md | WASM upgrade runbook (build → install → invoke upgrade/migrate) |
| INTEGRATION_GUIDE.md | Integrating against the deployed contracts |
| SECURITY.md | Threat model, auth table, overflow analysis |
| CERTIFICATION_TRACKING.md | Registry's certification sub-API in depth |
| ADR 0001: Monorepo Package Boundaries | Architectural decision on monorepo package boundaries |
| ADR 0002: Soroban Smart Contract Upgrade Strategy | Architectural decision on Soroban in-place WASM upgrades and governance |