A treasury your agents can spend from — but never drain.
On-chain spending infrastructure for autonomous agents, live on Robinhood Chain.
custos.sh · Reserve contract · @trycustos
$CUSTOS — 0xb48d784c213c90d335e740dc60b4f460c7987777
AI agents are starting to move money. Giving an agent your private key means giving it everything. Custos replaces the key with a contract.
Capital sits in a single on-chain reserve. Each agent gets a lane — an isolated allocation with its own balance, spending rules, recipient allowlist, and operating hours. The agent can trigger payments, and nothing else. Every rule is enforced atomically inside executePayment, on-chain, before a single unit of value moves.
No server. No middleware. No key handed to the agent.
| Primitive | What it does | Status |
|---|---|---|
| Reserve | One contract holds the capital. The authority (your wallet) controls it. | Live |
| Lane | One per agent. Isolated balance, isolated rules, isolated ledger. | Live |
| Governance | Per-transaction maximum, rolling daily cap, lifetime ceiling. | Live |
| Roster | On-chain allowlist of recipients per lane. No roster entry, no payment. | Live |
| Hours | UTC operating windows enforced via the block timestamp. | Live |
| Replenish | Lanes refill from the reserve when they drop below a floor. | Phase 02 |
| Quorum | m-of-n approvals for high-value movements. | Phase 02 |
When an agent calls executePayment, the contract runs every check in one atomic call:
- Lane exists and is Active
- Caller is the lane's registered agent
- Recipient is on the roster
- Amount is within the per-transaction maximum
- Amount fits the rolling daily cap
- Amount fits the lifetime ceiling
- Current block time is inside the operating window
- Lane balance covers the amount
Any check fails, the whole call reverts. All checks pass, the token transfers and the ledger updates — in the same transaction.
Everything is operated from custos.sh — a console that talks directly to the contract through your browser wallet. No backend, no accounts, no API keys.
| Address | |
|---|---|
| Reserve contract | 0xc5fa1D747702ae77A8dE3b3188ff1d2a4Cc9599f |
| $CUSTOS token (CA) | 0xb48d784c213c90d335e740dc60b4f460c7987777 |
| Settlement token (USDG) | 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 |
Network: Robinhood Chain mainnet (chain ID 4663).
contracts/
CustosReserve.sol The reserve contract (Solidity ^0.8.24, MIT)
scripts/
compile.mjs Compile with solc (viaIR)
create-deployer.mjs Generate a local deployer wallet into .env.local
deploy-reserve.mjs Deploy the reserve to Robinhood Chain
src/
app/ Next.js App Router — site, docs, console
components/ UI + dashboard components
lib/ Chain config, contract ABI, hooks (useVault, useTokenHolder)
The console (/dashboard) talks directly to the contract with ethers.js through your browser wallet (EIP-6963 discovery — MetaMask, Rabby, and friends). There is no backend.
git clone https://github.com/trycustos/usecustos.git
cd custos
npm install
cp .env.example .env.local
npm run devThe app works read-only against the public RPC out of the box. Connect a wallet on Robinhood Chain to create lanes, set governance, and settle payments.
# Compile
node scripts/compile.mjs
# Deploy your own reserve (writes DEPLOYER_PRIVATE_KEY to .env.local, local only)
node scripts/create-deployer.mjs
node scripts/deploy-reserve.mjsMinimal integration with ethers.js:
import { Contract, BrowserProvider } from "ethers";
import { RESERVE_ABI } from "./src/lib/reserveAbi";
const provider = new BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const reserve = new Contract(RESERVE_ADDRESS, RESERVE_ABI, signer);
// The only call an agent can ever make:
await reserve.executePayment(authority, laneId, recipient, amount, memo);CA: 0xb48d784c213c90d335e740dc60b4f460c7987777
Holding CUSTOS unlocks capacity in the console — lane limits scale with your tier, verified by on-chain balance. No staking contract, no lockups; the balance check is live. Details at custos.sh/holders.
- The authority (deployer wallet of a reserve) is the only address that can open lanes, move capital between reserve and lanes, edit governance, rosters, and hours.
- An agent address can do exactly one thing: call
executePaymenton its own lane, within its rules. - The contract is unaudited. It is intentionally small and dependency-free — read it before you trust it:
contracts/CustosReserve.sol.



