This guide provides an end-to-end walkthrough of creating, managing, and releasing milestone-based escrows on Trustchain Escrow using both the Soroban smart contracts on the Stellar network and the REST API.
- Overview
- Prerequisites
- Escrow Creation Flow
- Milestone Submission Flow
- Milestone Review and Release Flow
- Timelocks and Expiration
- Sequence Diagram
- Cross-References
Trustchain Escrow locks funds into Soroban smart contracts on Stellar until contractual milestones are delivered and approved. Funds are released incrementally per milestone rather than all at once, giving both clients and contractors transparent, audit-verifiable checkpoints.
┌──────────────┐ Deposit Funds ┌──────────────┐ Submit Work ┌──────────────┐
│ Client │ ────────────────────► │ Soroban / │ ◄─────────────────── │ Contractor │
│ │ ◄──────────────────── │ Trustchain │ ───────────────────► │ │
└──────────────┘ Approve & Release └──────────────┘ Deliverables └──────────────┘
Before creating or managing an escrow:
- Stellar Account: Both client and contractor require funded Stellar addresses (Testnet or Mainnet).
- Token Balance & Allowance: The client must hold sufficient XLM or SAC (Stellar Asset Contract) tokens and approve a token allowance for the Soroban escrow contract.
- REST API Auth: API access requires a Bearer JWT obtained via
POST /api/v1/auth/login.
Escrows are initialized on-chain by calling create_escrow on the Soroban escrow contract (contracts/escrow_contract/src/lib.rs).
pub fn create_escrow(
env: Env,
client: Address,
freelancer: Address,
token: Address,
total_amount: i128,
brief_hash: BytesN<32>,
arbiter: Option<Address>,
deadline: Option<u64>,
lock_time: Option<u64>,
) -> Result<u64, EscrowError>client: Stellar address depositing the funds. Must sign the transaction.freelancer: Stellar address receiving milestone releases.token: SAC asset address (e.g. native XLM or custom SEP-41 token).total_amount: Total escrow amount in stroops (1 XLM = 10,000,000 stroops).brief_hash: SHA-256 hash of the escrow contract agreement / statement of work.arbiter: Optional third-party address authorized for dispute resolution.
Alternatively, escrows can be created via the backend API:
POST /api/v1/escrows
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
{
"title": "Web App Development",
"contractorAddress": "GBC...CONTRACTOR",
"tokenAddress": "CDLZ...TOKEN",
"totalAmount": "5000000000",
"arbiterAddress": "GAA...ARBITER",
"milestones": [
{
"title": "Design Mockups",
"amount": "1500000000",
"description": "Figma design system and UI mockups"
},
{
"title": "Frontend Implementation",
"amount": "3500000000",
"description": "React Next.js frontend code delivery"
}
]
}Contractors submit deliverables accompanied by a cryptographic IPFS multihash or SHA-256 hash of the work. This ensures deliverable proof is immutably linked on-chain.
Contractors submit a milestone deliverable by invoking submit_milestone on-chain:
pub fn submit_milestone(
env: Env,
escrow_id: u64,
milestone_index: u32,
deliverable_hash: BytesN<32>,
) -> Result<(), EscrowError>Or via REST API:
POST /api/v1/escrows/42/milestones/0/submit
Authorization: Bearer <CONTRACTOR_JWT>
Content-Type: application/json
{
"ipfsHash": "QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco",
"notes": "Completed initial design system and component hierarchy"
}Upon milestone submission:
- The client receives notification via webhooks or dashboard.
- Client inspects the IPFS deliverable hash and work artifacts.
- If approved, client triggers fund release.
The client signs a transaction executing approve_milestone:
pub fn approve_milestone(
env: Env,
escrow_id: u64,
milestone_index: u32,
) -> Result<(), EscrowError>Or via REST API:
POST /api/v1/escrows/42/release
Authorization: Bearer <CLIENT_JWT>
Content-Type: application/json
{
"milestoneIndex": 0
}- The contract transfers the milestone's assigned amount directly to
freelancer. - The milestone state changes to
Approved. - When all milestones are approved, the escrow state moves to
Completedand emits aReputationEventincrementing both parties' completed escrow tally.
- Lock Time: If
lock_timeis configured, milestone approvals are prevented until the specified Unix timestamp has elapsed. - Deadline Expiration: If
deadlinepasses without milestone completion or dispute, the client can request an automated refund by invokingclaim_expired_refund.
Contractor Client Soroban Escrow Contract REST API / DB
│ │ │ │
│ │──── POST /api/v1/escrows ─────►│ │
│ │ │ ├─ Stores draft
│ │─── create_escrow(args...) ────►│ │
│ │◄── Returns Escrow ID ──────────│ ├─ Status: Active
│ │ │ │
│── submit_milestone(0) ──►│ │ │
│ │ │ ├─ Status: Submitted
│ │──── Review Deliverable ───────►│ │
│ │─── approve_milestone(0) ──────►│ │
│ │ │── Transfer Milestone Amt ─►│ (Contractor Wallet)
│ │ │── Emit MilestoneApproved ──►│
│ │ │ ├─ Status: Completed
- Smart Contract Guide — Technical details of the Soroban Rust contract.
- Dispute Resolution Guide — How to handle disputes when milestone review fails.
- Event Schema Documentation — On-chain events emitted during creation and release.
- Configuration Reference — System limits, timeouts, and network parameters.