Trustless, milestone-based escrow for freelance and remote work β built on Stellar's Soroban smart contract platform.
Remote work and freelance contracting run on trust that often doesn't exist between strangers across borders. Clients hesitate to pay upfront. Workers hesitate to deliver without payment guarantees. The usual fix β a centralized escrow middleman β adds fees, delays, and a single point of failure.
Trellis removes the middleman. Funds are locked on-chain, released milestone by milestone as work is verified, with a built-in dispute process if either party disagrees. No platform holds your money. The contract does.
This matters everywhere, but especially for contributors in emerging markets β where access to reliable, low-fee, borderless payment infrastructure can be the difference between taking on international work or not.
π‘ Why Soroban?
Contracts are written in real Rust, compiled to WASM, and run on the Stellar network β which has fast finality, low fees (~fractions of a cent), and an established USDC presence via Circle's Stellar Asset Contract. This makes it well-suited for cross-border payment use cases.
A live test agreement exists on-chain and is queryable right now:
trellis status --agreement-id 0101010101010101010101010101010101010101010101010101010101010101| Attribute | Value |
|---|---|
| Contract ID | CAUAO7CYKULE2K4EJMQ6LLRUHP7Y7JYOH6G2VBXKYG7PTETE3UZ3DU7Q |
| Network | Stellar Testnet |
| Explorer | View on Stellar Lab |
Full deployment details, every verified command, and step-by-step deployment instructions are in DEPLOYMENT.md.
Trellis models a freelance engagement as an agreement made up of one or more milestones, each with its own funding, work submission, and release lifecycle.
PENDING FUNDED WORK SUBMITTED COMPLETED DISPUTED REFUNDED CANCELLED lock_funds submit_work approve & release cancel_unfunded raise_dispute raise_dispute resolve (refund) resolve (release) Payer action Payee action Either party Resolver action| Role | Responsibility |
|---|---|
| Payer π§βπΌ | Funds milestones and approves completed work |
| Payee π¨βπ» | Submits proof of completed work and receives payment on approval |
| Dispute Resolver βοΈ | A neutral third party who can rule on disputes, releasing funds to either side |
- β Funds are held by the contract β not by either party or a platform
- β Either party can raise a dispute β neither can unilaterally freeze funds by going silent
- β Unfunded milestones can be cancelled β walk away cleanly with no cost
- β Every state transition emits an on-chain event β off-chain clients track progress in real time without polling
Trellis is a monorepo with three layers:
LAYER 1 Β· ON-CHAIN contracts/trellis_core/ Soroban Smart Contract (Rust β WASM) lib.rs types.rs storage.rs events.rs LAYER 2 Β· OFF-CHAIN cli/trellis_cli/ Command-Line Interface (Rust + clap + reqwest) main.rs config.rs rpc.rs LAYER 3 Β· WEB frontend/ Web Dashboard (React + Vite + TypeScript + Tailwind) App.tsx components/ lib/ Stellar Network| Function | Caller | Effect |
|---|---|---|
init |
Payer | Creates a new agreement with one or more milestones (each amount must be strictly positive) |
lock_funds |
Payer | Deposits funds for a milestone into the contract |
submit_work |
Payee | Submits proof of completed work for a funded milestone |
approve_and_release |
Payer | Approves submitted work, releases funds to payee |
raise_dispute |
Payer or Payee | Flags a milestone for resolver review |
resolve_dispute |
Dispute Resolver | Rules on a dispute β refunds payer or pays payee |
cancel_unfunded_milestone |
Payer | Cancels a milestone that was never funded |
get_agreement |
Anyone | Returns the full current state of an agreement (read-only) |
get_total_amount |
Anyone | Returns the agreement's total value β sum of all milestone amounts (read-only) |
extend_agreement_ttl |
Anyone | Renews an agreement's ledger TTL to avoid archival |
π¦ Storage Lifetime
Soroban archives persistent ledger entries once their TTL expires, so an agreement that is never touched would eventually be lost. Every state-mutating entrypoint renews the agreement's TTL to ~30 days automatically. Agreements that stay idle longer than that β a long delivery window, a stalled dispute β need
extend_agreement_ttl called before the TTL runs out; any address may call it, and the caller pays the rent.
| Category | Technologies |
|---|---|
| Smart Contract | Soroban Β· soroban-sdk 22.x Β· Rust (#![no_std] β WASM) |
| CLI | clap 4 Β· clap_complete Β· reqwest Β· serde + serde_json Β· dotenvy |
| Frontend | React 19 Β· Vite Β· TypeScript Β· Tailwind CSS Β· React Router |
| Stellar SDK | @stellar/stellar-sdk Β· @stellar/freighter-api Β· Soroban RPC |
- Rust (stable toolchain)
wasm32-unknown-unknowntarget:rustup target add wasm32-unknown-unknownstellarCLI 26.x+- Node.js 20+ (for the frontend)
cd frontend
cp .env.example .env
npm install
npm run devOpen http://localhost:5173 to see the animated landing page with the particle network background, typewriter effects, and full agreement management UI.
cd contracts/trellis_core
cargo testAll 9 integration tests run in the Soroban sandbox β happy path, double-init protection, dispute resolution, milestone cancellation (including the state-transition guard on already-funded milestones), positive-amount validation on init, the pre-computed total_amount, and the get_agreement view function.
make buildRuns the contract WASM build, CLI binary build, and frontend bundle in sequence. See make help for all available targets.
cd contracts/trellis_core
cargo rustc --manifest-path=Cargo.toml --crate-type=cdylib --target=wasm32-unknown-unknown --releaseSee DEPLOYMENT.md for the full deployment walkthrough and why this command is used instead of
stellar contract build.
cd cli/trellis_cli
cargo build --release
export STELLAR_RPC_URL="https://soroban-testnet.stellar.org"
export STELLAR_NETWORK_PASSPHRASE="Test SDF Network ; September 2015"
export TRELLIS_CONTRACT_ID="CAUAO7CYKULE2K4EJMQ6LLRUHP7Y7JYOH6G2VBXKYG7PTETE3UZ3DU7Q"
export TRELLIS_SOURCE_KEY="<your stellar identity name>"
# Create a new agreement
trellis init \
--agreement-id <hex-id> \
--payer <payer-address> \
--payee <payee-address> \
--token <token-contract-address> \
--resolver <resolver-address> \
--milestones "1000,2000"
# Check status
trellis status --agreement-id <hex-id>
# Fund the first milestone
trellis lock-funds --agreement-id <hex-id> --milestone-id 0All 8 CLI commands are implemented β init, lock-funds, submit-work, approve-release, raise-dispute, resolve-dispute, cancel-milestone, and status. See DEPLOYMENT.md for the full command reference.
These flags work with every command and can be combined with .env/env-var configuration:
# Preview without submitting
trellis lock-funds --agreement-id <hex-id> --milestone-id 0 --dry-run
# Machine-parseable JSON
trellis status --agreement-id <hex-id> --json
# Suppress everything except final JSON (implies --json)
trellis status --agreement-id <hex-id> --quiet
# Colorized summary
trellis status --agreement-id <hex-id> --human-readable # or -H--json takes priority over --human-readable when both are passed.
# bash
trellis completion bash > /etc/bash_completion.d/trellis
# zsh
trellis completion zsh > "${fpath[1]}/_trellis"
# fish
trellis completion fish > ~/.config/fish/completions/trellis.fishSupported shells: bash, zsh, fish, elvish, powershell.
- Core Soroban escrow contract β all 10 entrypoints implemented and tested
- Full state machine β happy path, dispute resolution, and cancellation paths
- Integration test suite β 9/9 passing in the Soroban sandbox
- Full CLI β all 8 commands wired end-to-end with JSON, dry-run, and human-readable output modes
- Deployed live on Stellar testnet β
initandstatusverified against the live contract - Frontend dashboard β 5 pages, 28 components, 12 custom hooks, animated particle network background
- Wallet connect β Freighter wallet integration with connection states
- Event feed β real-time on-chain event history per agreement
- Shell completions β bash, zsh, fish, elvish, powershell
| Area | Description | Difficulty |
|---|---|---|
| Frontend β Agreement Status page | Polish and edge cases for live agreement state display | Intermediate |
| Frontend β Create Agreement form | Validation UX, milestone builder refinements | Intermediate |
| Frontend β Milestone actions | lock, submit, approve, dispute button workflows | Intermediate |
| Frontend β Event feed enhancements | Real-time updates, filtering, pagination | Intermediate |
| Native RPC client | Replace stellar CLI shell-out with native Rust HTTP client | Advanced |
| Documentation | CONTRIBUTING.md and contributor onboarding guide | Beginner |
See Issues for the full task list β each issue has exact requirements, acceptance criteria, a suggested branch name, and a timeframe.
Trellis is built in the open and welcomes contributors of all experience levels β from documentation and frontend components to contract enhancements and tooling.
- Fork the repo and clone it locally
- Browse open issues tagged
good first issueorhelp wanted - Comment on the issue to claim it β wait for maintainer confirmation before starting
- Branch:
git checkout -b feat/your-feature-name - Verify: run
cargo testincontracts/trellis_core - PR: open a PR referencing the issue with
Closes #X
New to Soroban? Start with the official Soroban docs.
New to React + Stellar? Read throughfrontend/src/lib/config.tsand the Stellar SDK docs.
MIT β see LICENSE for the full text.