A production-ready, gas-optimized implementation of ERC-8183: Agentic Commerce — trustless job escrow with evaluator attestation for autonomous agent commerce.
ERC-8183 defines a protocol where a client locks funds, a provider submits work, and an evaluator attests completion or rejection. This contract manages the full job lifecycle with strict state machine enforcement, optional hook extensibility, and snapshot-based fee distribution.
stateDiagram-v2
[*] --> Open: createJob
Open --> Funded: fund (client)
Open --> Rejected: reject (client)
Funded --> Submitted: submit (provider)
Funded --> Rejected: reject (evaluator)
Funded --> Expired: claimRefund (anyone, after expiry)
Submitted --> Completed: complete (evaluator)
Submitted --> Rejected: reject (evaluator)
Submitted --> Expired: claimRefund (anyone, after expiry)
Completed --> [*]: payment released to provider
Rejected --> [*]: refund to client
Expired --> [*]: refund to client
| Chain | Address | Payment Token | Explorer |
|---|---|---|---|
| Monad | 0xE8c4FFb4A6F7B8040a7AE39F6651290E06A40725 |
USDC | Socialscan · MonadVision |
- ERC-8183 compliant — strict adherence to the specification interface (
IERC8183) - Single ERC-20 escrow — immutable
PAYMENT_TOKENper deployment - Evaluator attestation — only the evaluator can complete or reject submitted work
- Front-running protection —
fund()requiresexpectedBudgetto match current budget - Expiry enforcement — cannot fund already-expired jobs;
claimRefundalways available after expiry
- Storage packing —
JobStoragestruct optimized to 8 slots with packed fields (hook + status + expiredAt + feesin a single slot) - ReentrancyGuardTransient — EIP-1153 transient storage for cheaper reentrancy protection
- Immutable variables —
PAYMENT_TOKENstored in bytecode, zero SLOAD cost
- Ownable2Step — two-step ownership transfer prevents accidental transfers;
renounceOwnership()is permanently disabled - SafeERC20 — safe token transfers with return value checks
- Fee snapshot —
platformFeeBp,evaluatorFeeBp, andtreasurycaptured atfund()time, immune to admin changes - Hook gas limit — 500k gas cap prevents griefing attacks via malicious hooks
- Non-hookable
claimRefund— funds are always recoverable after expiry, even if the hook is malicious
- Optional hooks —
IACPHookinterface forbeforeAction/afterActioncallbacks on 6 core operations - Hook whitelist — admin-controlled allowlist with ERC-165 interface validation
- BaseACPHook — abstract router that decodes calldata and dispatches to named virtual functions
| Constant | Value | Description |
|---|---|---|
MAX_FEE_BP |
5000 |
Maximum total fee: 50% (platform + evaluator) |
BP_DENOMINATOR |
10_000 |
Basis point denominator |
HOOK_GAS_LIMIT |
500_000 |
Max gas forwarded to each hook call |
MIN_EXPIRY_DURATION |
5 minutes |
Minimum job time-to-live |
MAX_DESCRIPTION_LENGTH |
1024 |
Max job description size in bytes |
- Foundry (forge ≥ 0.3.0)
- Solidity 0.8.28+
- EVM target: Cancun (EIP-1153 transient storage support required)
forge buildforge test -vvvAll 126 tests passing across 4 test suites covering state transitions, role checks, fee calculations, hook interactions, reentrancy protection, gas limits, edge cases, and fuzz testing.
export PAYMENT_TOKEN=0x... # ERC-20 token address
export TREASURY=0x... # Platform fee recipient
export PLATFORM_FEE_BP=250 # 2.5% platform fee
export EVALUATOR_FEE_BP=100 # 1% evaluator fee
forge script script/DeployAgenticCommerce.s.sol:DeployAgenticCommerce \
--rpc-url $RPC_URL --broadcast --verifySee Deployment Guide for full instructions including hardware wallet, Gnosis Safe, multi-chain, and post-deployment verification.
This implementation covers all MUST/SHALL requirements of ERC-8183:
| Requirement | Status |
|---|---|
| 6 states (Open, Funded, Submitted, Completed, Rejected, Expired) | ✅ |
| 8 valid state transitions, no others | ✅ |
| 8 core functions with correct role checks | ✅ |
| 8 events emitted on corresponding transitions | ✅ |
| Hook gas limits (500k) | ✅ |
Non-hookable claimRefund |
✅ |
| SafeERC20 + ReentrancyGuard | ✅ |
- Fee snapshot at fund time — prevents admin fee changes from affecting funded jobs
- Expiry check in
fund()— cannot fund already-expired jobs - Hook whitelist with ERC-165 — only validated hooks can be attached
- Disabled
renounceOwnership()— prevents irreversible loss of admin control
Install as a Foundry dependency:
forge install qntx/market-contractAdd the remapping to your foundry.toml:
remappings = [
"market-contract/=lib/market-contract/src/",
]Import in your contracts:
import {AgenticCommerce} from "market-contract/AgenticCommerce.sol";
import {BaseACPHook} from "market-contract/BaseACPHook.sol";
import {IERC8183} from "market-contract/interfaces/IERC8183.sol";
import {IACPHook} from "market-contract/interfaces/IACPHook.sol";Extend protocol functionality by implementing IACPHook via BaseACPHook:
import {BaseACPHook} from "market-contract/BaseACPHook.sol";
contract MyHook is BaseACPHook {
constructor(address acp) BaseACPHook(acp) {}
function _preFund(uint256 jobId, bytes memory optParams) internal override {
// Custom validation — revert to block the fund operation
}
function _postComplete(
uint256 jobId, bytes32 reason, bytes memory optParams
) internal override {
// Post-completion logic — state and transfers already finalized
}
}Register hooks via setHookWhitelist(address, true) before attaching to jobs.
See Hook Development Guide for the complete reference including cookbook patterns, security guidelines, and advanced topics.
This project is licensed under the MIT License — see the LICENSE file for details.