
Security News
White House Authorizes Private Companies to Conduct Offensive Cyber Operations
A new federal program will let vetted U.S. cybersecurity firms help investigate and disrupt foreign cybercrime groups under government direction.
@arbitova/sdk
Advanced tools
Non-custodial USDC escrow for agent-to-agent payments on Base. v3 is a rewrite — see MIGRATION.md.
Non-custodial USDC escrow for agent-to-agent payments on Base.
Two agents lock USDC into a contract, one delivers, the other confirms or disputes, and a neutral arbiter resolves. Arbitova never holds the money — the contract does.
No API keys. No registration. No custody. Your Ethereum address is your identity.
npm install @arbitova/sdk ethers
Contract: 0xA8a031bcaD2f840b451c19db8e43CEAF86a088fC on Base Sepolia (mainnet launching after audit)
Spec: A2A-ESCROW-RFC-v0.1
Live UI: arbitova.com/pay
Every A2A / agent-commerce spec in the wild — MCP, Google's A2A, ERC-7683, Coinbase's Agent Commerce — defines how agents talk. None of them define how money moves when the agents don't trust each other.
Arbitova is the missing settlement primitive:
createEscrow → markDelivered → {confirmDelivery | dispute → resolve | cancel}. No hidden branches, no admin override.DISPUTED, not into seller payout. Silence is safer than a wrong confirmation.keccak256 is stored on-chain. Anyone can audit.This is not a marketplace. There is no Arbitova account, no listing fee, no Arbitova Pro tier. The protocol is the whole product.
Two terminals. Both need a Base Sepolia private key with some test USDC + a pinch of ETH for gas. Faucet: https://faucet.circle.com/ (Base Sepolia USDC) · gas: https://www.alchemy.com/faucets/base-sepolia
// buyer.mjs
import { Arbitova } from '@arbitova/sdk';
const buyer = await Arbitova.fromPrivateKey({ privateKey: process.env.BUYER_PK });
const { escrowId, txHash } = await buyer.createEscrow({
seller: process.env.SELLER_ADDRESS,
amount: '5.00', // USDC
deliveryHours: 24,
reviewHours: 24,
verificationURI: 'https://example.com/spec.json',
});
console.log(`Escrow #${escrowId} locked — ${buyer.explorerTx(txHash)}`);
// seller.mjs
import { Arbitova } from '@arbitova/sdk';
const seller = await Arbitova.fromPrivateKey({ privateKey: process.env.SELLER_PK });
seller.onEscrowCreated(async (ev) => {
if (ev.seller.toLowerCase() !== (await seller.address()).toLowerCase()) return;
console.log(`New escrow #${ev.id}: ${ev.amount} USDC from ${ev.buyer}`);
// ...do the work, then:
const deliveryContent = Buffer.from('hello, buyer');
await seller.markDelivered({
escrowId: ev.id,
deliveryPayloadURI: 'https://example.com/receipt.json',
deliveryContentBytes: deliveryContent, // content-hash pinned on-chain
});
});
await buyer.confirmDelivery(escrowId); // seller gets 4.975 USDC, fee 0.025 USDC
await buyer.dispute(escrowId, 'Delivery incomplete — criterion #2 failed');
// arbiter picks it up, signs a verdict, calls resolve(buyerBps, sellerBps, verdictHash)
That's the whole thing.
┌──────────────────┐
│ CREATED │ buyer locked USDC
└────────┬─────────┘
│
▼ seller.markDelivered()
┌──────────────────┐
│ DELIVERED │ deliveryHash on-chain
└────────┬─────────┘
│
buyer.confirmDelivery()│ │ buyer.dispute()
│ │ or seller.dispute()
▼ ▼
┌─────────────┐ ┌──────────┐
│ RELEASED │ │ DISPUTED │ waiting for arbiter
└─────────────┘ └────┬─────┘
│ arbiter.resolve(bps split + verdictHash)
▼
┌──────────┐
│ RESOLVED │
└──────────┘
Two terminal states not drawn: CANCELLED (buyer calls cancelIfNotDelivered after delivery window) and auto-escalation into DISPUTED if the review window expires without confirmation.
import { Arbitova } from '@arbitova/sdk';
const client = await Arbitova.fromWallet(window.ethereum);
await client.confirmDelivery('17');
Works with any EIP-1193 wallet (MetaMask, Coinbase Wallet, Rainbow, Rabby, etc.).
Three reference A2A demos, all end-to-end on Base Sepolia with a live AI arbiter:
Python agents: pip install arbitova[path_b], then from arbitova import path_b. Same contract surface, same verdicts.
MCP server: npm install @arbitova/mcp-server — six on-chain tools (same contract surface) for any MCP client.
| Key | Description |
|---|---|
base-sepolia (default) | Production contract, real Circle USDC |
base-sepolia-test | Test contract with mock USDC for CI |
const client = await Arbitova.fromPrivateKey({
privateKey: process.env.PK,
network: 'base-sepolia-test',
});
Base mainnet launches after external audit + multisig arbiter migration. Watch Dev Log for the announcement.
| When | Fee | Paid by |
|---|---|---|
confirmDelivery / escalateIfExpired | 0.5% | deducted from seller payout |
| Arbiter resolves a dispute | 2% | split per arbiter verdict |
Fees accrue in the contract. The protocol runs on them; there is no subscription.
All methods async. Write methods require a signer (private key or browser wallet).
| Method | Role | Description |
|---|---|---|
Arbitova.fromPrivateKey({ privateKey, network? }) | — | Client signed by private key |
Arbitova.fromWallet(window.ethereum) | — | Client using an EIP-1193 wallet |
Arbitova.fromReadOnly({ network? }) | — | Read-only (no signing) |
createEscrow({ seller, amount, deliveryHours, reviewHours, verificationURI }) | buyer | Lock USDC (auto-approves). Returns { escrowId, txHash, receipt } |
markDelivered({ escrowId, deliveryPayloadURI, deliveryContentBytes? }) | seller | Commits keccak256(content) (or URI) on-chain |
confirmDelivery(escrowId) | buyer | Happy path — pays seller (minus 0.5%) |
dispute(escrowId, reason) | buyer or seller | Opens dispute; reason emitted in event |
cancelIfNotDelivered(escrowId) | buyer | After delivery deadline if seller no-showed |
escalateIfExpired(escrowId) | anyone | After review deadline — forces DISPUTED, not auto-release |
getEscrow(escrowId) | — | Full on-chain state |
getUsdcBalance(addr?) | — | USDC balance |
listEscrowsForAddress(role, addr?) | — | Scan escrows where address is buyer or seller |
onEscrowCreated / onDelivered / onReleased / onDisputed / onResolved / onCancelled | — | Event subscriptions |
explorerTx(hash) / explorerAddr(addr) | — | Basescan URL helpers |
Arbitova.keccakURI(uri) | static | Compute deliveryHash for an off-chain URI |
subscribeEvents({ address, onEvent }) | — | Server-sent events push stream (alternative to polling) |
Your verificationURI should link to a JSON document defining what "done" means. Two modes:
manual — human-readable prose for buyer, seller, and arbiterprogrammatic — an HTTPS endpoint an arbiter can hit to get a pass/failSchema: arbitova.com/schemas/ · Reference: RFC v0.1
contracts/src/EscrowV1.solSEPOLIA_E2E_REPORT.mdsecurity/bug-bounty-v0.md — live on Immunefi after mainnet deploysecurity@arbitova.com (alias coming; until then jiayuanliang0716@gmail.com)v3 is a rewrite. If you have working v2 code, pin to @arbitova/sdk@^2.3.1 until you're ready — v3 doesn't share any API surface with v2. Migration guide: MIGRATION.md.
FAQs
Non-custodial USDC escrow for agent-to-agent payments on Base. v3 is a rewrite — see MIGRATION.md.
We found that @arbitova/sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
A new federal program will let vetted U.S. cybersecurity firms help investigate and disrupt foreign cybercrime groups under government direction.

Research
/Security News
The campaign amassed more than 75,000 installs by targeting Russian-speaking users seeking access to blocked services.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.