Type-safe Rust SDK for the ERC-8183 Agentic Commerce Protocol — on-chain job escrow with evaluator attestation for AI agent commerce.
ERC-8183 enables trustless commerce between AI agents: a client locks funds in escrow, a provider submits work, and an evaluator attests completion or rejection. This SDK provides ergonomic, alloy-native bindings for the full job lifecycle with strict type safety and comprehensive documentation.
Note: ERC-8183 is currently a Draft EIP with no official contract deployments yet. Once deployed, update the contract address and the SDK is ready to use.
See SECURITY.md before using in production.
use alloy::{
network::EthereumWallet,
primitives::{Address, U256},
providers::ProviderBuilder,
signers::local::PrivateKeySigner,
};
use erc8183::{Erc8183, types::CreateJobParams};
let signer: PrivateKeySigner = std::env::var("PRIVATE_KEY")?.parse()?;
let wallet = EthereumWallet::from(signer);
let provider = ProviderBuilder::new()
.wallet(wallet)
.connect_http("https://eth.llamarpc.com".parse()?);
// Replace with actual deployed contract address
let client = Erc8183::new(provider)
.with_address("0x1234...".parse()?);
let job_handle = client.job()?;
// Create a job with deferred provider assignment
let params = CreateJobParams::new(
Address::ZERO, // provider (deferred)
"0xEvaluator...".parse()?, // evaluator
U256::from(1_900_000_000u64), // expiredAt (Unix timestamp)
"Build a REST API for payments",
);
let job_id = job_handle.create_job(¶ms).await?;
println!("Created job: {job_id}");// 1. Client creates job (see above)
let job_id = job_handle.create_job(¶ms).await?;
// 2. Client assigns provider
job_handle.set_provider(job_id, provider_address, None).await?;
// 3. Client or provider sets budget
job_handle.set_budget(job_id, U256::from(1000), None).await?;
// 4. Client funds escrow (requires ERC-20 approval)
job_handle.fund(job_id, U256::from(1000), None).await?;
// 5. Provider submits work
let deliverable = FixedBytes::from_slice(&ipfs_cid_hash);
job_handle.submit(job_id, deliverable, None).await?;
// 6. Evaluator completes (releases escrow to provider)
job_handle.complete(job_id, FixedBytes::ZERO, None).await?;
// Or: Evaluator rejects (refunds client)
// job_handle.reject(job_id, reason_hash, None).await?;use alloy::providers::ProviderBuilder;
use erc8183::Erc8183;
let provider = ProviderBuilder::new()
.connect_http("https://eth.llamarpc.com".parse()?);
let client = Erc8183::new(provider)
.with_address("0x1234...".parse()?);
let job = client.job()?.get_job(U256::from(1)).await?;
println!("Status: {}", job.status);
println!("Client: {}", job.client);
println!("Provider: {}", job.provider);
println!("Budget: {}", job.budget);| Module | Description |
|---|---|
Erc8183 |
Top-level client — generic over P: Provider, builder pattern for address configuration |
JobHandle |
Job operations — create_job, set_provider, set_budget, fund, submit, complete, reject, claim_refund |
types |
Domain types — JobStatus, Job, CreateJobParams, SubmitParams, AttestParams |
contracts |
Inline Solidity bindings (sol! macro) — AgenticCommerce contract and IACPHook interface |
error |
Error types — Error enum with thiserror, covers contract/transport/status errors |
networks |
Network configuration — placeholder addresses for future deployments |
stateDiagram-v2
[*] --> Open: createJob
Open --> Funded: fund
Open --> Rejected: reject (client)
Funded --> Submitted: submit
Funded --> Rejected: reject (evaluator)
Funded --> Expired: claimRefund
Submitted --> Completed: complete
Submitted --> Rejected: reject (evaluator)
Submitted --> Expired: claimRefund
Completed --> [*]: payment released
Rejected --> [*]: refund to client
Expired --> [*]: refund to client
| State | Description |
|---|---|
| Open | Created; budget not yet set or not yet funded |
| Funded | Budget escrowed; provider may submit work |
| Submitted | Work submitted; evaluator may complete or reject |
| Completed | Terminal; escrow released to provider |
| Rejected | Terminal; escrow refunded to client |
| Expired | Terminal; refund after expiredAt timestamp |
| Role | Capabilities |
|---|---|
| Client | Creates job, sets provider/budget, funds escrow, rejects (Open only) |
| Provider | Proposes budget, submits work deliverable |
| Evaluator | Completes or rejects (Funded/Submitted states) |
| Function | Caller | Description |
|---|---|---|
createJob |
Client | Create job in Open state |
setProvider |
Client | Assign provider to Open job |
setBudget |
Client/Provider | Set or negotiate budget |
fund |
Client | Fund escrow, transition to Funded |
submit |
Provider | Submit work, transition to Submitted |
complete |
Evaluator | Release escrow to provider |
reject |
Client/Evaluator | Refund escrow to client |
claimRefund |
Anyone | Refund after expiry (not hookable) |
| Event | Parameters |
|---|---|
JobCreated |
jobId, client, provider, evaluator, expiredAt |
ProviderSet |
jobId, provider |
BudgetSet |
jobId, amount |
JobFunded |
jobId, client, amount |
JobSubmitted |
jobId, provider, deliverable |
JobCompleted |
jobId, evaluator, reason |
JobRejected |
jobId, rejector, reason |
JobExpired |
jobId |
PaymentReleased |
jobId, provider, amount |
Refunded |
jobId, client, amount |
The IACPHook interface — the only normative Solidity interface in EIP-8183 — allows extending the protocol with custom logic:
interface IACPHook {
function beforeAction(uint256 jobId, bytes4 selector, bytes calldata data) external;
function afterAction(uint256 jobId, bytes4 selector, bytes calldata data) external;
}Hooks are called before and after core functions (except claimRefund). Use cases include:
- Bidding/auction mechanisms
- Two-phase token transfers
- Reputation integration (ERC-8004)
- Custom validation logic
- Zero
async_trait— pure RPITIT, no trait-object overhead - Inline Solidity bindings —
sol!macro preserves struct names, enums, and visibility; no JSON ABI files - Provider-generic — works with any alloy transport (HTTP, WebSocket, IPC) and any signer configuration
- Strict linting —
pedantic+nursery+correctness(deny), seeclippy.toml - Spec-compliant — all 8 core functions and 10 recommended events strictly match EIP-8183 specification
| Crate | Description |
|---|---|
erc8183 |
Core SDK library |
erc8183-cli |
CLI tool (planned) |
| Example | Description |
|---|---|
basic |
Basic client setup and job parameter preparation |
cargo run --example basic| Standard | Relationship |
|---|---|
| ERC-8004 | Trustless Agents — reputation/identity layer, composable with ERC-8183 |
| ERC-20 | Payment token standard used for escrow |
| ERC-2771 | Meta-transactions — optional gasless execution support |
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or https://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project shall be dual-licensed as above, without any additional terms or conditions.