Skip to content
 
 

Repository files navigation

StarEscrow

CI License: MIT

StarEscrow is a programmable escrow protocol for freelance and marketplace payments on the Stellar network, built with Soroban smart contracts. It locks funds on-chain when a job is created, optionally routes them through a yield protocol while work is in progress, and releases payment to the freelancer upon payer approval — or refunds the payer on cancellation or deadline expiry. A configurable fee (in basis points) is deducted from the released amount and forwarded to a fee collector address.

Architecture

Component Diagram

graph TD
    subgraph Clients
        CLI["star-escrow CLI<br/>(clients/cli)"]
        DAPP["dApp / Web Client"]
    end

    subgraph "Stellar Network"
        CONTRACT["StarEscrow Contract<br/>(contracts/escrow)"]
        TOKEN["Token Contract<br/>(SEP-41 / Stellar Asset)"]
        YIELD["Yield Protocol<br/>(optional, external)"]
    end

    CLI -->|"invoke via stellar CLI"| CONTRACT
    DAPP -->|"Soroban RPC"| CONTRACT
    CONTRACT -->|"transfer / transfer_from"| TOKEN
    CONTRACT -->|"deposit / withdraw"| YIELD

    style CONTRACT fill:#1e3a5f,color:#fff
    style TOKEN fill:#2d6a4f,color:#fff
    style YIELD fill:#6b4c11,color:#fff
Loading

State Machine

stateDiagram-v2
    [*] --> Active : create()

    Active --> WorkSubmitted : submit_work()\n[freelancer]
    Active --> Cancelled : cancel()\n[payer, before submission]
    Active --> Expired : expire()\n[payer, after deadline]

    WorkSubmitted --> Completed : approve()\n[payer]

    Completed --> [*]
    Cancelled --> [*]
    Expired --> [*]

    note right of Active
        Funds locked in contract.
        Yield accruing (if enabled).
    end note

    note right of Completed
        Funds (minus fee) released
        to freelancer.
    end note

    note right of Cancelled
        Full refund + yield
        returned to payer.
    end note

    note right of Expired
        Full refund + yield
        returned to payer after
        deadline has passed.
    end note
Loading

Sequence Diagrams

Happy Path

sequenceDiagram
    actor Payer
    actor Freelancer
    participant Contract as StarEscrow Contract
    participant Token as Token Contract
    participant Yield as Yield Protocol (optional)

    Payer->>Contract: create(payer, freelancer, token, amount, milestone, deadline?, yield_protocol?)
    Contract->>Token: transfer_from(payer → contract, amount)
    alt yield_protocol provided
        Contract->>Yield: deposit(amount)
        Contract-->>Payer: emit yield_deposited
    end
    Contract-->>Payer: emit escrow_created
    Note over Contract: status = Active

    Freelancer->>Contract: submit_work()
    Contract-->>Freelancer: emit work_submitted
    Note over Contract: status = WorkSubmitted

    Payer->>Contract: approve()
    alt yield enabled
        Contract->>Yield: withdraw(principal)
        Yield-->>Contract: (principal, yield_accrued)
    end
    Contract->>Token: transfer(fee → fee_collector)
    Contract->>Token: transfer(amount - fee [+ yield] → freelancer)
    Contract-->>Payer: emit payment_released
    Note over Contract: status = Completed
Loading

Cancel Flow

sequenceDiagram
    actor Payer
    actor Freelancer
    participant Contract as StarEscrow Contract
    participant Token as Token Contract
    participant Yield as Yield Protocol (optional)

    Payer->>Contract: create(payer, freelancer, token, amount, milestone, ...)
    Contract->>Token: transfer_from(payer → contract, amount)
    Contract-->>Payer: emit escrow_created
    Note over Contract: status = Active

    Note over Freelancer: Work not yet submitted

    Payer->>Contract: cancel()
    Note over Contract: Only allowed when status = Active
    alt yield enabled
        Contract->>Yield: withdraw(principal)
        Yield-->>Contract: (principal, yield_accrued)
    end
    Contract->>Token: transfer(amount [+ yield] → payer)
    Contract-->>Payer: emit escrow_cancelled
    Note over Contract: status = Cancelled
Loading

Expire Flow

sequenceDiagram
    actor Payer
    actor Freelancer
    participant Contract as StarEscrow Contract
    participant Token as Token Contract
    participant Yield as Yield Protocol (optional)

    Payer->>Contract: create(..., deadline=T, ...)
    Contract->>Token: transfer_from(payer → contract, amount)
    Contract-->>Payer: emit escrow_created
    Note over Contract: status = Active

    Note over Freelancer: Deadline T passes without work submission

    Payer->>Contract: expire()
    Note over Contract: Requires current_time > deadline<br/>and status = Active
    alt yield enabled
        Contract->>Yield: withdraw(principal)
        Yield-->>Contract: (principal, yield_accrued)
    end
    Contract->>Token: transfer(amount [+ yield] → payer)
    Contract-->>Payer: emit escrow_expired
    Note over Contract: status = Expired
Loading

Documentation


Quick Start

Prerequisites

Build

stellar contract build

Test

cargo test -p escrow

Deploy

See docs/DEPLOYMENT.md for full instructions.

Usage

Set required environment variables:

export ESCROW_CONTRACT_ID=<contract-id>
export ADMIN_SECRET=<admin-secret-key>
export PAYER_SECRET=<payer-secret-key>
export FREELANCER_SECRET=<freelancer-secret-key>

Initialize the protocol (admin, one-time):

star-escrow init \
  --fee-bps 100 \
  --fee-collector <fee-collector-address>

Create an escrow and lock funds:

star-escrow create \
  --freelancer <freelancer-address> \
  --token <token-address> \
  --amount 1000000000 \
  --milestone "Deliver final design assets" \
  --deadline 1800000000

Freelancer submits work, payer approves:

star-escrow submit-work
star-escrow approve

Cancel before work is submitted (payer only):

star-escrow cancel

Run star-escrow --help for the full command reference.

About

Programmable escrow protocol for freelance and marketplace payments on Stellar using Soroban smart contracts.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages