Skip to content

Trustless-Work/TW-V2-AUDIT-SCRIPTS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Trustless Work — v2 Escrow API Integration Audit Scripts

These scripts demonstrate, end-to-end and on-chain, that the trustless-work-core API correctly integrates with the v2 Soroban escrow contracts. Each public contract function is reached through its corresponding API endpoint, the returned transaction is signed by a real wallet, and the result is submitted and verified on Stellar testnet.

They are written so an auditor can read them and follow exactly what happens: every HTTP request, the unsigned XDR returned by the API, the local signature, and the full send-transaction response are printed to the terminal.

Scope: single-release v2 (single-release-v2/) and multi-release v2 (multi-release-v2/). Both cover all 14 public contract functions.


What it proves

The API never holds keys. For every operation the integration is a three-step loop, and these scripts exercise all three steps against the live service:

   build                     sign                       send
┌────────────┐   unsigned  ┌────────────┐  signed   ┌──────────────────────┐
│  POST       │──── XDR ───▶│  wallet     │── XDR ───▶│ POST /stellar/        │──▶ on-chain
│  /escrow/...│             │ (stellar-cli)│           │      send-transaction │
└────────────┘             └────────────┘           └──────────────────────┘

If a flow completes and its assertions pass, it proves the API builds a transaction the contract accepts, that the contract executes the intended state transition, and that send-transaction reports it back correctly.


Coverage matrix

All 14 public functions of the single-release v2 contract, each mapped 1:1 to an endpoint and proven by at least one script:

API endpoint Method Contract function Proven by
/escrow/single-release/v2/deploy POST tw_new_single_release_escrow + initialize_escrow 01,02,03,04,05,06
/escrow/single-release/v2/fund POST fund_escrow 01,02,03,05,06
/escrow/single-release/v2/change-milestone-status POST change_milestone_status 01
/escrow/single-release/v2/approve-milestones POST approve_milestones 01
/escrow/single-release/v2/approve-and-release-milestones POST approve_and_release_milestones 02
/escrow/single-release/v2/release-funds POST release_funds 01
/escrow/single-release/v2/dispute POST dispute_escrow 03,05
/escrow/single-release/v2/resolve-dispute POST resolve_dispute 03,05
/escrow/single-release/v2/withdraw-remaining-funds POST withdraw_remaining_funds 05
/escrow/single-release/v2/update PUT update_escrow 04
/escrow/single-release/v2/manage-milestones POST manage_milestones 04
/escrow/single-release/v2/extend-ttl POST extend_contract_ttl 04
/escrow/single-release/v2/{contractId} GET get_escrow all
/escrow/single-release/v2/escrow-balances GET get_multiple_escrow_balances 06

Multi-release v2 (multi-release-v2/) covers the same 14 functions under /escrow/multi-release/v2/…, with per-milestone semantics: each milestone has its own amount + receiver, and release-funds, dispute-milestones and resolve-dispute take a milestoneIndexes array so milestones are released/disputed/resolved independently. The flow scripts (01–06) mirror the single-release ones; dispute-milestones replaces dispute.


Layout

tw-v2-audit-scripts/
├── README.md
├── .env.example                 # copy to .env and fill in
├── lib/
│   ├── common.sh                # config, HTTP, build→sign→send, logging, assertions
│   └── stellar.sh               # wallets, friendbot, XLM→USDC swap, SAC, deploy payload
├── single-release-v2/
│   ├── 00_setup_check.sh        # run first — verifies tooling, key, DEX liquidity
│   ├── 01_release_funds.sh           # deploy→fund→status→approve→release
│   ├── 02_approve_and_release.sh     # deploy→fund→approve-and-release
│   ├── 03_dispute_and_resolve.sh     # deploy→fund→dispute→resolve
│   ├── 04_admin_management.sh        # update, manage-milestones, extend-ttl
│   ├── 05_withdraw_remaining_funds.sh# residual sweep → withdraw-remaining-funds
│   ├── 06_reads.sh                   # get-escrow, escrow-balances
│   └── run_all.sh               # runs 01→06 in order
└── multi-release-v2/            # same 6 flows, per-milestone (release/dispute/resolve by index)
    ├── 00_setup_check.sh
    ├── 01_release_funds.sh … 06_reads.sh
    └── run_all.sh

Each flow ends with a summary listing every escrow contract it created, in order, with its stellar.expert link and the operations executed on it.


Prerequisites

  • stellar-cli ≥ 22curl -sSf https://stellar.org/install.sh | bash (or brew install stellar-cli)
  • curl and jq
  • A valid API key for the deployed API.
  • Internet access to the API, Horizon, the Soroban RPC and friendbot (all testnet).

Check your stellar-cli version with stellar --version.


Setup (once)

1. Configure

cd tw-v2-audit-scripts
cp .env.example .env

Open .env and paste your API key into API_KEY. That is the only place the key is needed — every script reads it from there and sends it as the x-api-key header.

2. That's it — funding is automatic

There is no treasury and no faucet. Every run generates fresh role wallets, funds them with testnet XLM via friendbot, and then swaps XLM → USDC on the testnet DEX (a path payment) so they hold the USDC needed to fund escrows. All of this happens inside the scripts; the only thing you configure is the API key in step 1.

3. Verify

bash single-release-v2/00_setup_check.sh

Green all the way down means you are ready.


Running

# single-release v2 — one flow, or everything in order
bash single-release-v2/01_release_funds.sh
bash single-release-v2/run_all.sh

# multi-release v2 — same idea
bash multi-release-v2/00_setup_check.sh
bash multi-release-v2/run_all.sh

Each script provisions its own fresh wallets, runs the flow, prints every request/response, and finishes with PASSED (or aborts at the first failed assertion). The escrow contract id is printed so you can inspect it on stellar.expert (testnet).


Roles & wallets

The contract enforces that admin and disputeResolvers never overlap with the other roles, while approver / serviceProvider / releaseSigner / receiver / platform may all be the same address. Each run therefore uses three wallets:

Wallet Roles it holds Signs
MAIN (W1) approver, serviceProvider, releaseSigner, receiver, platform deploy, fund, change-status, approve, release, approve-and-release, dispute
ADMIN (W2) admin update, manage-milestones, extend-ttl
RESOLVER (W3) disputeResolver resolve-dispute, withdraw-remaining-funds

Why USDC (and not a self-issued test asset)

On testnet the Trustless Work fee wallet is a classic Stellar account that holds a USDC trustline only. release_funds, resolve_dispute and withdraw_remaining_funds pay the protocol fee to that wallet via the token's Soroban contract; a transfer to a classic account traps unless that account trusts the asset. A self-issued asset would make those settlement calls fail, so every escrow is denominated in Circle's testnet USDC, which the fee wallet already trusts. This is configurable in .env (USDC_ASSET).


Troubleshooting

  • HTTP 401 / AUTH_API_KEY_MISSINGAPI_KEY is wrong or empty in .env.
  • Deploy did not return a contractId — the indexer was lagging when the deploy confirmed; the response carried STELLAR_TX_SUBMITTED_INDEXER_LAGGING. Re-run; the transaction itself succeeded.
  • Signing produced empty output — stellar-cli too old (need ≥ 22) or the wallet name is unknown to the keystore.
  • XLM->USDC swap failed — testnet DEX liquidity was momentarily thin, or the wallet's friendbot XLM had not settled. Re-run; if it persists, lower ESCROW_AMOUNT / SEED_USDC_AMOUNT in .env.
  • DistributionsMustEqualEscrowBalance — the resolve/withdraw distribution sum must equal the live on-chain balance; the scripts read it just before the call, so this should not happen unless the balance changed underneath.

Notes for reviewers

  • The scripts make no assumptions hidden in code: payloads are built inline with jq and printed before sending.
  • The only thing done off-API is plumbing that the API has no endpoint for: generating + XLM-funding wallets, the USDC trustline, the XLM→USDC swap, and (only in script 05) a direct SAC transfer used to create a residual balance for the withdraw demo. Everything that touches an escrow goes through the API.
  • All on-chain authorization is enforced by the contract's require_auth; the scripts simply sign with the correct role wallet for each call.
  • Balance is verified against on-chain truth. The get-escrow response's balance field is served from an indexer that can lag behind the ledger, so the scripts assert balances against the escrow-balances endpoint instead, which performs a live get_multiple_escrow_balances contract read. Lifecycle flags (released, dispute.*) and milestones come from the live get_escrow contract struct. Every assertion polls until the on-chain state is reflected.

About

Bash + stellar-cli scripts that prove the Trustless Work v2 escrow API integrates correctly with the Soroban contracts on Stellar testnet. Each public contract function is reached via its endpoint, signed by a real wallet, submitted, and verified on-chain. Covers single-release and multi-release v2.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages