New:Socket for Asana Is Now Available.Learn more
Get Started

@arbitova/sdk

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@arbitova/sdk

Non-custodial USDC escrow for agent-to-agent payments on Base. v3 is a rewrite — see MIGRATION.md.

Source
npmnpm
Version
3.0.0
Version published
Weekly downloads
17
1600%
Maintainers
1
Weekly downloads
 
Created
Source

@arbitova/sdk

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

Why this exists

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:

  • Deterministic state machine. createEscrow → markDelivered → {confirmDelivery | dispute → resolve | cancel}. No hidden branches, no admin override.
  • No auto-release after timeout. Review windows expire into DISPUTED, not into seller payout. Silence is safer than a wrong confirmation.
  • Content-hash pinned on-chain. Sellers can't swap the delivery file after the buyer inspects.
  • Verdict transparency. Every arbiter decision is a signed JSON blob; its 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.

30-second quickstart

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

// 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

// 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
  });
});

Buyer confirms (happy path)

await buyer.confirmDelivery(escrowId);   // seller gets 4.975 USDC, fee 0.025 USDC

Buyer disputes (sad path)

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.

Lifecycle

                      ┌──────────────────┐
                      │     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.

Browser wallet

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.).

Framework integrations

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.

Networks

KeyDescription
base-sepolia (default)Production contract, real Circle USDC
base-sepolia-testTest 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.

Fees

WhenFeePaid by
confirmDelivery / escalateIfExpired0.5%deducted from seller payout
Arbiter resolves a dispute2%split per arbiter verdict

Fees accrue in the contract. The protocol runs on them; there is no subscription.

API

All methods async. Write methods require a signer (private key or browser wallet).

MethodRoleDescription
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 })buyerLock USDC (auto-approves). Returns { escrowId, txHash, receipt }
markDelivered({ escrowId, deliveryPayloadURI, deliveryContentBytes? })sellerCommits keccak256(content) (or URI) on-chain
confirmDelivery(escrowId)buyerHappy path — pays seller (minus 0.5%)
dispute(escrowId, reason)buyer or sellerOpens dispute; reason emitted in event
cancelIfNotDelivered(escrowId)buyerAfter delivery deadline if seller no-showed
escalateIfExpired(escrowId)anyoneAfter 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 / onCancelledEvent subscriptions
explorerTx(hash) / explorerAddr(addr)Basescan URL helpers
Arbitova.keccakURI(uri)staticCompute deliveryHash for an off-chain URI
subscribeEvents({ address, onEvent })Server-sent events push stream (alternative to polling)

Verification specs

Your verificationURI should link to a JSON document defining what "done" means. Two modes:

  • manual — human-readable prose for buyer, seller, and arbiter
  • programmatic — an HTTPS endpoint an arbiter can hit to get a pass/fail

Schema: arbitova.com/schemas/ · Reference: RFC v0.1

Security

Migrating from v2 (custodial)

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.

License

MIT · github.com/jiayuanliang0716-max/Arbitova

Keywords

arbitova

FAQs

Package last updated on 22 Apr 2026

Related posts