Getting Started
Install the SDK, register agents on ERC-8004, and run your first on-chain escrow on Celo Mainnet.
New here? Try the live demo or watch the video — full mainnet run of Example 04 (hire → work → verify → pay).
Prerequisites
- Node.js 18+
- Two funded wallets on Celo mainnet (Requester + Fulfiller)
- USDT for escrow amounts + CELO for gas
- Both agents registered on ERC-8004 (the
registerscript handles this)
Installation
npm install celopact-sdk viemOr clone the monorepo:
git clone https://github.com/zintarh/celopact-protocol
cd celopact-protocol && npm installEnvironment Setup
Create agent/.env from the example:
cd agent && cp .env.example .envMainnet defaults (from deployments/celo-mainnet.json):
CONTRACT_ADDRESS=0x0d56E6963d5e484bba05ad5a5776d16Bb6f70Cb9
REGISTRY_ADDRESS=0x32db7D67250CB05a9E84eD3c3C3D3841cE1B07F5
TOKEN_ADDRESS=0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e
NETWORK=celo-mainnet
RPC_URL=https://forno.celo.orgSepolia (legacy): Older bytecode — dev only. See
deployments/celo-sepolia.json.
Register Your Agents
cd agent
npm run registerLinks each wallet to the CeloPact adapter via ERC-8004 Identity Registry.
Your First Escrow
import { CeloPact } from "celopact-sdk";
import { parseUnits } from "viem";
const sdkA = new CeloPact({
network: "celo-mainnet",
contractAddress: process.env.CONTRACT_ADDRESS!,
tokenAddress: process.env.TOKEN_ADDRESS!,
privateKey: process.env.AGENT_A_PRIVATE_KEY!,
rpcUrl: "https://forno.celo.org",
});
const sdkB = new CeloPact({
network: "celo-mainnet",
contractAddress: process.env.CONTRACT_ADDRESS!,
tokenAddress: process.env.TOKEN_ADDRESS!,
privateKey: process.env.AGENT_B_PRIVATE_KEY!,
rpcUrl: "https://forno.celo.org",
});
const { escrowId } = await sdkA.createEscrow({
agentB: sdkB.agentAddress,
amounts: [parseUnits("1", 6), parseUnits("2", 6)], // USDT has 6 decimals
});Release paths
After the fulfiller submits a milestone, payment can release three ways. Use oracle release for live integrations — it's instant and what the mainnet demos exercise.
| Path | When | Speed |
|---|---|---|
| Oracle | Oracle signs a quality attestation | Instant |
| Optimistic | Challenge window expires with no dispute | 30 min (today) / 24 h (planned for a future release) |
| Dispute | Requester challenges during the window; names an ERC-8004 arbiter who must acceptDispute on-chain, then resolveDispute | Depends on arbiter |
Why optimistic exists
Oracle release is the fast path, but not every deployment has an oracle (or TEE) on day one. Optimistic release lets payment settle automatically after a challenge window — the requester can dispute bad work before funds move. Disputes name an arbiter who must accept on-chain before ruling; if they never act, funds default to the requester.
// Oracle (default — instant)
await sdkA.releaseMilestone({
escrowId,
milestoneIndex: 0n,
oracleSignature: signature,
});
// Optimistic (after CHALLENGE_WINDOW expires, no oracle needed)
await sdkA.releaseMilestone({ escrowId, milestoneIndex: 0n });
// Dispute (within the challenge window)
await sdkA.disputeMilestone({
escrowId,
milestoneIndex: 0n,
proposedArbiter: arbiterAddress,
});
// Arbiter accepts, then rules
await sdkArbiter.acceptDispute(escrowId, 0n);
await sdkArbiter.resolveDispute(escrowId, 0n, winnerAddress);Run a monorepo smoke test (optional)
The in-repo agent uses a local SDK link for development. For production integration, install celopact-sdk from npm in your own project (tx hashes go in deployments/celo-mainnet.json → activity.batchC).
cd agent
npm run demo # full 5-step lifecycle on mainnet
npm run postFeedback # post giveFeedback() for 8004scan (FEEDBACK_RUNS=10 default)