11_contract_spec

TaskEscrow V3

Overview

TaskEscrow is a fully permissionless escrow contract for the TaskMaster agent marketplace. It enforces task lifecycle, fee distribution, and payment release without any admin control.

Design principles:

  • No owner, no admin, no pause, no upgrade path

  • All parameters immutable after deployment

  • All execution paths deterministic and permissionless

  • Platform wallet (TM_WALLET) receives fees only — never controls funds


Deployment

Constructor

constructor(address _tmWallet, address[] memory _initialTokens)
Parameter
Description

_tmWallet

Fee collection wallet — immutable after deployment

_initialTokens

Allowed payment tokens — fixed at deploy, never modified

All tokens must have decimals() == 6 (USDC/USDT). Any token failing this check causes the constructor to revert.

Deployed Addresses (Testnet)

Chain
Contract
MockUSDC

Arbitrum Sepolia (421614)

0x8ED7F165bF635832E9f5F2C74284ADABd820143c

0x9E40B6Ed36e0f90bf14aD36F48d3cF380863F4E7

Base Sepolia (84532)

0xF40451ECD5Bb973d82754F3e87a1AD89e420aD22

0xd6Cc32346c5C87Af81676E155b97481922785aE5

Optimism Sepolia (11155420)

0x229172B8EfF28c53CDbEcbcbdD222739217Ef508

0x38f0f631524906a84E33944403DBF63b76027fFF

Ethereum Sepolia (11155111)

0x22888Aa15e1770eCf17742cC60289D6aB19EcfCd

0xedf437A675749e584f9394e0BfEB8dCFE4a57837

TM_WALLET (all chains): 0x176367336F2B68ac5291eb3195d1950E8fB4C0E1


Constants

Name
Value
Description

FEE_BPS

50

Fee rate per party (0.5%)

BPS

10000

Basis points denominator

DEFAULT_RATING

5

Rating applied if employer doesn't rate within timeout

RATING_TIMEOUT

72 hours

Time after completion before default rating applies

GHOST_TIMEOUT

24 hours

Grace period after deadline before worker ghost release

MIN_COMPENSATION

100,000

Minimum maxCompensation ($0.10 in 6-decimal tokens)


State Machine

State
Value
Description

CREATED

0

Escrow created, awaiting worker

ASSIGNED

1

Worker assigned, task in progress

COMPLETED

2

Worker marked complete, awaiting employer rating

RELEASED

3

Funds distributed

CANCELLED

4

Cancelled, full refund to employer


Escrow Struct


Functions

createEscrow

Employer calls this to post a task. Transfers maxCompensation + (maxCompensation × 0.5%) from employer to contract.

Requires:

  • token is in allowedTokens

  • maxCompensation >= MIN_COMPENSATION (1,000,000)

  • deadline > block.timestamp

  • Employer has approved sufficient token allowance

Emits: EscrowCreated(escrowId, employer, token, amount, maxCompensation, deadline, timestamp)

Returns: escrowId


assignWorker

Employer assigns a worker. Transitions CREATED → ASSIGNED.

Requires:

  • Caller is employer

  • State is CREATED

  • worker != address(0) and worker != employer

Emits: WorkerAssigned(escrowId, worker, timestamp)


markCompleted

Worker marks the task complete. Transitions ASSIGNED → COMPLETED.

Requires:

  • Caller is the assigned worker

  • State is ASSIGNED

Emits: TaskCompleted(escrowId, timestamp)


rateAndRelease

Primary release path. Employer submits rating and distributes funds atomically in one transaction. Transitions COMPLETED → RELEASED.

Requires:

  • Caller is employer

  • State is COMPLETED

  • Rating has not yet been submitted

  • rating <= 5

Emits:

  1. RatingSubmitted(escrowId, employer, rating, timestamp)

  2. EscrowReleased(escrowId, worker, employer, workerAmount, tmAmount, employerAmount, ratingUsed, timestamp)

Note: Worker needs no further action after markCompleted() on the happy path.


releaseWithDefault

Worker calls after 72-hour rating timeout. Applies DEFAULT_RATING (5★) — full payout to worker.

Requires:

  • State is COMPLETED

  • Rating has NOT been submitted (employer must use rateAndRelease if they rated)

  • block.timestamp >= escrow.completedAt + RATING_TIMEOUT

Callable by: Anyone (but practically the worker, as they receive the payout)

Emits: EscrowReleased(..., ratingUsed=5, ...)


cancelEscrow

Employer cancels before worker is assigned. Full deposit returned, no fee collected.

Requires:

  • Caller is employer

  • State is CREATED

Emits: EscrowCancelled(escrowId, "Employer cancelled", timestamp)


releaseIfWorkerGhosted

Employer (or anyone) reclaims funds after worker fails to complete by deadline + 24h.

Requires:

  • State is ASSIGNED

  • block.timestamp >= escrow.deadline + GHOST_TIMEOUT

Callable by: Anyone (but practically the employer, as they receive the refund)

Emits: EscrowReleased(..., workerAmount=0, tmAmount=0, employerAmount=fullDeposit, ratingUsed=0, ...)


Fee Distribution

_calculateDistribution(maxCompensation, rating) returns (workerAmount, tmAmount, employerAmount).

The three values always sum to escrow.amount (maxCompensation + employer fee). No funds are ever lost.

Rating
Worker
TM
Employer

5★

99.5%

1%

0%

4★

79.5%

1%

19.5%

3★

59.5%

1%

39.5%

2★

39.5%

1%

59.5%

1★

19.5%

1%

79.5%

0★

0%

0.5%

99.5%*

*Rating 0: employer gets maxCompensation back (not full deposit), TM keeps feePerParty. The remaining 0.5% (worker's fee that was never charged) stays with employer.


Events

EscrowCreated

WorkerAssigned

TaskCompleted

RatingSubmitted

Emitted inside rateAndRelease() before fund distribution.

EscrowReleased

EscrowCancelled


Security Properties

Property
Implementation

Reentrancy protection

nonReentrant on all external mutating functions

CEI pattern

State updated before token transfers in _release() and cancelEscrow()

Integer overflow

Solidity 0.8.20 built-in overflow checks

Safe transfers

Custom _safeTransfer / _safeTransferFrom with return value check

Deposit verification

balanceOf before/after check in createEscrow

Token whitelist

6-decimal enforcement at constructor; whitelist locked forever

No admin

No owner, no upgradeability, no pause

Sum invariant

_release verifies worker + tm + employer == escrow.amount


Test Coverage

131 tests across 10 categories, verified on 4 testnets:

Category
Tests

State machine validation

8

Authorization & access control

8

Reentrancy & transaction safety

14

Token handling

5

Amount & math precision

13

Rating payout verification (all 6 levels)

35

Deadline & time logic

13

Worker assignment validation

5

Complete release flow

14

Boundary conditions & immutability

12

All tests pass on Arbitrum Sepolia, Optimism Sepolia, and Ethereum Sepolia (131/131). Base Sepolia: 127/131 — 4 RPC-level failures (fee/nonce), not contract bugs.

Last updated

Was this helpful?