The settlement layer for AI agents.
| π Live site | https://www.riveprotocol.tech |
| π¬ Demo video | https://www.youtube.com/watch?v=Dk71vqM9bo0 |
Problem. Agent-to-agent payments today are raw ERC-20 transfers. There is no escrow, no double-entry audit trail, and no way to settle high-frequency micropayments between many agents without paying gas on every leg. As soon as you have more than two agents transacting in a tight loop β a common pattern in any non-trivial agent workflow β the per-tx overhead and lack of accountability make on-chain settlement economically and operationally unworkable.
Solution. Rive is a settlement layer that sits between agents and the chain, organised around three pillars:
- Trustless Escrow. Funds are locked on-chain in
Escrow.soland only released against a cryptographically signed delivery proof of the formdeliver:<orderID>:<deliveryHash>. Agents sign their own proofs β Rive's backend never holds an agent's private key for escrow operations. - Double-entry Bookkeeping Engine. Every state change emits a journal entry. Canonical-JSON (RFC 8785) hashes of each entry, each work-order spec, and each settlement manifest are persisted as canonical-JSON records in Postgres. The result is a complete, replayable ledger.
- Netting Engine. Per-window batching compresses N logical payment intents between many agents into a single multi-transfer settlement transaction, executed by
NettingSettlement.settleBatch()over arrays of net debtors and creditors.
ββββββββββββββββββββ
β Agents β
β (EOA wallets, β
β sign proofs) β
ββββββββββ¬ββββββββββ
β HTTP API + signed proofs
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Rive Backend (Go, port :8080) β
β work-orders Β· netting engine Β· double-entry ledger β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β PostgreSQL β journal, intents, orders, batches, β β
β β storage_contents β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββ
β settleBatch() /
β delivery proofs
βΌ
βββββββββββββββββββββββ
β EVM Chain β
β Escrow.sol β
β NettingSettlement β
β RiveUSD.sol β
βββββββββββββββββββββββ
Stack
| Layer | Tech |
|---|---|
| Backend | Go 1.26, chi v5 router, pgx β PostgreSQL. Strict Clean Architecture: cmd β app β delivery β usecase β domain β repository β infrastructure. |
| Smart contracts | Solidity 0.8.33 + Foundry. OpenZeppelin SafeERC20 + ReentrancyGuard. |
| Frontend | Next.js 16 + React 19 + TypeScript + Tailwind 4 (in web/). |
| Off-chain plumbing | QuickNode webhooks β escrow event ingestion (HMAC-SHA256 verified). Goose migrations on Postgres. |
The Rive backend never holds an agent's private key for escrow operations.
- Agents sign their own proofs β escrow funding (
transferFromfrom the agent's wallet) and delivery proofs (deliver:<orderID>:<deliveryHash>, verified via ECDSA recovery). - The backend holds exactly one signing key β
NETTING_SETTLER_PRIVATE_KEY, used only to call the permissionedsettleBatch()function. - Even
settleBatchcannot move funds unilaterally β it usestransferFrom, so each debtor agent must have explicitlyapprove()dNettingSettlementfor the relevant amount before settlement.
Every agent wallet must be registered once before it can create work orders or submit payment intents. The demo CLIs (make demo-escrow / make demo-netting) handle this automatically via direct DB seeding. When integrating directly against the API, call the onboard endpoint first:
curl -X POST http://localhost:8080/api/agents/onboard \
-H "Content-Type: application/json" \
-d '{"wallet_address": "0xYOUR_AGENT_WALLET"}'
# β 201 Created { "id": "...", "wallet_address": "0x...", ... }Full endpoint reference:
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/agents/onboard |
Register an agent wallet β prerequisite for all write operations |
POST |
/api/work-orders |
Create a work order and persist spec to storage |
GET |
/api/work-orders/{onchainOrderID} |
Fetch work order status |
POST |
/api/work-orders/{onchainOrderID}/delivery |
Submit a signed delivery proof |
POST |
/api/payments/intent |
Submit a payment intent (netting flow) |
GET |
/api/ledger/{walletAddress}/pnl |
Get agent PnL report from the double-entry ledger |
POST |
/api/webhooks/quicknode/escrow-events |
QuickNode webhook for on-chain escrow event ingestion |
GET |
/api/health/ |
Health check |
rive/
βββ contracts/ # Foundry project: Escrow, NettingSettlement, RiveUSD (mock)
βββ backend/ # Go REST API + demo CLIs (Clean Architecture)
β βββ cmd/api/ # HTTP server entrypoint (:8080)
β βββ cmd/demo-escrow/ # Escrow end-to-end demo CLI
β βββ cmd/demo-netting/ # Netting end-to-end demo CLI
β βββ internal/ # app / delivery / usecase / domain / repository / infrastructure
β βββ migrations/ # Goose SQL migrations
βββ web/ # Next.js dashboard (PnL report, audit trail, batches)
βββ demo/ # YAML configs for the demo CLIs (escrow.*.yaml, netting.*.yaml)
βββ docs/ # Protocol walkthroughs (escrow-demo, netting-demo, work-order-lifecycle)
βββ Makefile # demo-escrow / demo-netting targets
TL;DR β once
.envfiles anddemo/*.local.yamlare filled in (see steps 2-3):make demo-escrow # 1 escrow lifecycle end-to-end make demo-netting # 20 intents β 1 settleBatch() txFull setup details below.
- Go 1.26+
- Node 20+ and pnpm 10+
- Foundry (
forge,cast) - PostgreSQL 14+ (local or Dockerised)
- A deployed instance of
Escrow.solandNettingSettlement.solon an EVM-compatible chain
git clone https://github.com/harundarat/rive.git
cd rive
cd backend && go mod download && cd ..
cd web && pnpm install && cd ..
cd contracts && forge install && cd ..cp backend/.env.example backend/.env
cp contracts/.env.example contracts/.envKey variables to fill in backend/.env:
| Variable | Purpose |
|---|---|
NETTING_EVM_RPC |
EVM RPC endpoint for the settlement chain |
DB_* |
Postgres connection (host / port / user / password / name) |
ESCROW_CONTRACT_ADDRESS |
Deployed address of Escrow.sol |
NETTING_SETTLEMENT_ADDRESS |
Deployed address of NettingSettlement.sol |
NETTING_SETTLER_PRIVATE_KEY |
Backend's settler EOA (only key the backend holds) |
NETTING_WINDOW_SECONDS |
Batch close interval (5 for demo, 60 default) |
QUICKNODE_WEBHOOK_SECRET |
HMAC secret for webhook verification |
CORS_ALLOWED_ORIGINS |
Comma-separated origins for the dashboard |
cp demo/escrow.example.yaml demo/escrow.local.yaml
cp demo/netting.example.yaml demo/netting.local.yamlFill in private_key for each agent.
Agent registration: The demo CLIs automatically register each configured wallet into the database at startup β no manual step required. If you are calling the API directly (outside of the demo CLIs), register each agent wallet first via
POST /api/agents/onboardbefore creating work orders or submitting payment intents (see API Reference above).
# Apply migrations (goose)
cd backend
goose -dir migrations postgres "$DATABASE_URL" up
# Start API server on :8080
go run ./cmd/apicd web
pnpm dev # http://localhost:3000From the repo root:
make demo-escrow # 1 escrow lifecycle: Buyer β Processor
make demo-netting # 5 agents, 20 intents β 1 settlement txTwo agents: a Data Buyer and a Data Processor.
- Buyer creates a work order; spec is persisted to storage and
specHashcommitted on-chain. - Buyer funds the order on
Escrow.sol(rUSD locked,transferFromfrom buyer's wallet). - Processor signs
deliver:<orderID>:<deliveryHash>and submits the proof. - Escrow verifies the signature and releases payment to the processor.
- Backend writes a double-entry journal entry per state change, persisted in Postgres.
Five agents: scout, analyst, data, verifier, router. They submit 20 cross-paying payment intents to POST /api/payments/intent.
Stage 1 β Off-chain netting:
20 logical intents β 5 net positions (one per agent, debit or credit)
Stage 2 β On-chain settlement:
5 net positions β 1 settleBatch() transaction
(Solidity for-loop over debtor and creditor arrays)
Result:
Gross volume: 79 rUSD across 20 intents
Net settlement amount: 23 rUSD moved on-chain
On-chain transactions: 1 (vs 20 individual transfers without netting)
The CLI polls Postgres until the batch is settled and prints the settlement tx hash.
V2
- Real USDC settlement (replaces rUSD mock).
- On-chain dispute resolution module.
- TEE-attested delivery verification (replace signature-only proofs).
V3
- Multi-asset settlement (any ERC-20 / native).
- Cross-chain settlement with bridge integrations.
- Agent-side SDK in Go and TypeScript.
Built by Harun (@harundarat).