Reference implementation of ERC-8183 — a Job primitive for trustless agent commerce. Its core features are a job escrow protocol with evaluator attestation and an optional hook system for extensibility.
Requires Foundry.
forge install
forge build
forge testERC-8183 defines a minimal on-chain job escrow between three roles:
- Client — creates and funds jobs
- Provider — delivers work
- Evaluator — attests to completion or rejects
The core state machine:
Open → Funded → Submitted → Completed | Rejected | Expired
Each transition enforces role-based access control, and funds are held in escrow until the evaluator completes or the job is rejected/expired.
Jobs can optionally attach a hook contract (IERC8183Hook) to extend behavior without modifying the core:
beforeAction— called before state changes, can revert to gate transitionsafterAction— called after state changes, for bookkeeping and side effects
When hook == address(0), the contract operates as a standalone job escrow with no callbacks. See docs/02-hook-system.md for the full design.
contracts/
├── ERC8183.sol # Core state machine, escrow, fees, hooks
├── ERC8183WithAuthorization.sol # EIP-712 authorization extension for relayed calls
├── IDisburser.sol # Optional payout receiver callback interface
├── IERC8183Hook.sol # Hook interface (beforeAction/afterAction)
└── mocks/
├── MockUSDC.sol # Test ERC20, 6 decimals
├── MockCBBTC.sol # Test ERC20, 8 decimals
├── MockDisburser.sol # Test payout receiver and reentrancy callbacks
├── MockFeeOnTransferToken.sol # Test ERC20 that takes a transfer fee (used to verify rejection)
└── MockERC1271NonceObserver.sol # Test ERC-1271 signer helpers
- Upgradeable — UUPS proxy pattern via OpenZeppelin
- Access control — role-based admin for fees, hook whitelisting, and payment token allowlisting
- Pausable — admin can pause user-facing lifecycle functions and use
emergencyWithdrawwhile paused - CEI pattern — checks, effects, interactions throughout
- Reentrancy protection — transient storage guard on fund-moving and hook-calling lifecycle functions
- Payment token allowlist — only admin-vetted ERC-20s can be used as payment tokens
- Fee-on-transfer / rebasing rejection —
fundsnapshots the contract balance and reverts if the received amount differs from the budget - Evaluator grace period — after expiry, a Submitted job cannot be force-refunded for
EVALUATION_GRACE_PERIOD(1 hour), giving the evaluator time to complete or reject - Claim settlement fees — direct settlements and approved claims both use the configured platform/evaluator fee split for the settled delta
- Streaming settlement independence — direct
settleClaimcalls can continue while a provider milestone claim is pending; the pending claim stays open until explicitly resolved - Pending claim resolution — after expiry, a Funded job with a pending provider claim cannot be force-refunded until the claim is approved, rejected, or withdrawn; if all parties stay idle, escrow remains parked
- Claim replay guard — rejected claim hashes stay consumed, so providers must vary
cumulativeAmount, the deliverable, oroptParamsto refile - Authorization extension —
ERC8183WithAuthorizationuses the baseERC8183EIP-712 domain so relayed entrypoints extend the same protocol identity; signers can callcancelAuthorizationdirectly to burn one of their own outstanding nonces - Hook safety —
claimRefundis intentionally not hookable; pending claims must be resolved before refund
See docs/01-architecture.md for state machine and sequence diagrams.
- Architecture & Diagrams — state machine, sequence flows
- Hook System Design — IERC8183Hook interface, safety model, invocation pattern
- Demo Flows — end-to-end example scenarios
This is the reference implementation for ERC-8183. Contributions, feedback, and discussion are welcome - please see CONTRIBUTING.md for guidelines on how to get started.
MIT