Soroban smart contracts for the TalentTrust freelancer escrow protocol on Stellar.
- Escrow contract (
contracts/escrow): Holds funds in escrow, supports milestone-based payments and reputation credential issuance. Token custody is on-chain via a Stellar Asset Contract (SAC) bound at admin setup;deposit_fundsandrelease_milestoneperform realtoken::Client::transfercalls. - Planned escrow fee model: Configurable protocol fee is now wired into
release_milestone(set_protocol_fee_bps); fee retention intoAccumulatedProtocolFeesis implemented. A separatewithdraw_protocol_feesentrypoint remains tracked in #314.
Reviewer-oriented notes live in docs/escrow/README.md, with storage-key details in docs/escrow/state-persistence.md, threat analysis in docs/escrow/SECURITY.md, and release authorization modes in docs/escrow/authorization.md.
| Feature / Entrypoint | Status | Context / Tracking Reference |
|---|---|---|
create_contract |
Implemented | Core initialization and state persistence |
deposit_funds |
Implemented | Escrow fund collection tracking |
release_milestone |
Implemented | Authenticated milestone payouts via caller.require_auth() |
finalize_contract |
Implemented | Freezes contract mutable updates |
cancel_contract |
Implemented | Early termination contract transitions |
issue_reputation |
Implemented | Milestone rating metrics for completed contracts |
| Emergency Circuit Breakers | Implemented | Public administrative pause and emergency flags |
| Protocol Fee Accumulation | Implemented | Logic built directly into milestone releases |
| Protocol Fee Withdrawal | Planned | Entrypoints tracked in #314 |
| Two-step Admin Transfer | Planned | Infrastructure tracked in #318 |
The escrow implementation follows a fail-closed state machine:
- contract creation requires client authorization and rejects invalid participant or milestone metadata before persisting state
- a Stellar Asset Contract (SAC) settlement token is admin-bound exactly once via
bind_settlement_token; each subsequentdeposit_fundsandrelease_milestonecallstoken::Client::transferand updates accounting atomically - deposits pull SAC tokens from the client BEFORE
funded_amountis updated, so a failed transfer leaves accounting untouched - deposits cannot exceed the required escrow total
- releases pay the freelancer (less protocol fee) via SAC transfer BEFORE milestone state is updated, so a failed payout leaves state untouched
- releases require a valid unreleased milestone, caller authorization via
caller.require_auth(), and valid non-expired approvals matching the contract'sReleaseAuthorizationmode - reputation is gated behind contract completion and is issued once per contract
- finalization records immutable close metadata for completed or disputed contracts and blocks later contract-specific mutations
- one-time admin initialization protects pause and emergency controls; two-step admin transfer is planned in #318
- pause and emergency controls block all state-changing escrow operations while active
Planned governance-transfer and migration features are explicitly labeled in the escrow docs until their entrypoints land.
# Run tests (includes 95%+ coverage negative path testing for escrow)
cargo test
# Run escrow performance/gas baseline tests only
cargo test test::performance
# Check formatting
cargo fmt --all -- --check
# Run escrow-specific tests
cargo test -p escrow
# Run escrow performance tests only
cargo test test::performance -p escrowThe escrow contract supports critical-incident response with admin-managed controls:
initialize(admin)(one-time setup)pause()andunpause()activate_emergency_pause()andresolve_emergency()is_paused()andis_emergency()
When paused, all mutating escrow operations (create_contract, deposit_funds, release_milestone, issue_reputation, cancel_contract) are blocked with ContractPaused.
Read-only queries are never blocked.
See docs/escrow/emergency-controls.md for the full flag semantics, event model, and security properties.
finalize_contract(contract_id, finalizer) records immutable close metadata for contracts in Completed or Disputed status.
The finalizer must be the stored client, freelancer, or assigned arbiter and must authorize the call.
After finalization, subsequent contract-specific mutating calls fail with AlreadyFinalized.
- Rust 1.75+
- rustfmt
- Stellar CLI (optional for deployment workflows)
- Fork the repository and create a branch from
main. - Make changes while keeping tests, linting, and formatting checks passing:
cargo fmt --all
cargo clippy --workspace --all-targets -- -D warnings
cargo test
cargo build- Open a pull request.
CI runs verification checks automatically.
On every push and pull request to main, GitHub Actions:
- Checks formatting:
cargo fmt --all -- --check- Lints with warnings denied:
cargo clippy --workspace --all-targets -- -D warnings- Builds the workspace:
cargo build- Runs tests:
cargo testEnsure these pass locally before pushing.
Performance/gas baseline tests for key flows are located at:
contracts/escrow/src/test/performance.rs
Functional and failure-path coverage is split by module:
contracts/escrow/src/test/flows.rs
contracts/escrow/src/test/security.rs
Contract-specific reviewer documentation:
docs/escrow/performance-baselines.md
docs/escrow/SECURITY.md
MIT