Integration

RAIL20 for Agents

Give any autonomous agent a private balance and private payments on Base. Integration is an HTTP API plus one signature - no circuit knowledge, no client-side proving, no new wallet.

Why agents need this

Agents that hold and move value on public chains broadcast everything: treasury size, payment timing, and the full counterparty graph. That leaks strategy, invites front-running, and exposes agent-to-agent (A2A) relationships. RAIL20 shields the balance and the payment while keeping the agent's normal signing key.

The integration model

An agent never handles zero-knowledge proofs. It signs a message, and the RAIL20 relayer derives the account, builds the proof, pays gas, and broadcasts. On-chain, only a commitment and a nullifier appear - no sender, recipient, or amount.

Three steps to integrate

1Derive the private account

The agent signs the fixed RAIL20 message once with its existing key. That signature deterministically derives the agent's private account keys. Cache the signature for the session; it is the only secret the agent needs.

1-derive.ts
// The exact message string is fixed. Sign it once, cache the result.
const RAIL20_SIGN_MSG =
  "RAIL20 Private Account Sign-in\n\nSigning this message derives your account keys.\nNo transaction will be sent."

const signature = await agent.signMessage(RAIL20_SIGN_MSG)

2Fund the private balance

Either deposit ETH/USDC into the pool, or simply receive private notes from another agent. To deposit, request an unsigned transaction from the relayer and broadcast it from the agent's wallet.

2-deposit.ts
const prep = await post("/api/deposit/prepare", {
  signature, address: agent.address, amount: "50", pool: "usdc"
})
// prep = { to, data, value, approveTx? } - sign & broadcast from the agent wallet
if (prep.approveTx) await agent.sendTransaction(prep.approveTx)
await agent.sendTransaction({ to: prep.to, data: prep.data, value: prep.value })

3Transact privately

Read the private balance any time (reconstructed locally, nothing hits the chain), then pay another agent, swap, or bridge with one signed API call. The relayer builds the proof and broadcasts.

3-pay.ts
// Read private balance - derived from on-chain notes, no tx
const { balance } = await post("/api/balance", {
  signature, address: agent.address, pool: "usdc"
})

// Pay a peer agent privately. Relayer broadcasts; agent pays no gas.
await post("/api/withdraw", {
  signature,
  recipient: peerAgent.address,
  amount: "25",        // amount hidden on-chain
  pool: "usdc"
})
// On-chain: one commitment + one nullifier. No sender, recipient, or amount.

API reference

All endpoints are served from https://api.rail20.org and accept a JSON body containing the agent's signature.

EndpointMethodPurpose
/api/balancePOSTReconstruct the agent's private balance from its notes
/api/deposit/preparePOSTBuild an unsigned deposit (shield) transaction
/api/withdrawPOSTPrivate send to any address (up to 2 recipients)
/api/swap-privatePOSTSame-chain swap into a burner (step 1 of private swap)
/api/burner-gasPOSTRelayer gas top-up for a burner mid-swap
/api/swapPOSTCross-chain bridge via NEAR Intents 1Click
/api/bridge/quotePOSTQuote a swap or bridge (dry or real)
/api/intent-statusGETPoll cross-chain intent settlement

Common agent patterns

Private treasury

An agent receives funds to its public wallet, deposits into the pool, and from then on manages balance privately. Withdraw to a fresh address when spending publicly - an observer sees deposits into the pool and withdrawals from the pool, but cannot connect the two.

Agent-to-agent (A2A) payments

Agents pay each other directly from private balance via /api/withdraw. Amount and counterparties stay hidden, so recurring A2A relationships and payment sizes never appear on-chain.

Private swap & rebalance

An agent rebalances ETH into USDC (or back) via /api/swap-private, which routes through a one-time burner and Uniswap V3 on-chain, then re-shields the result. Strategy shifts never leak.

Considerations

ConsiderationDetail
SigningOne personal_sign over the fixed message. Cache per session; it derives all account keys.
GasRelayer pays gas for withdrawals and private transactions. Deposits are broadcast by the agent wallet.
FeesFlat + 0.35% in the transacted token. Flat: 0.00025 ETH (ETH pool) or 1 USDC (USDC pool).
MinimumsUSDC pool has a 1 USDC minimum on withdrawals. Keep transacted amounts above the fee + minimum.
RecoveryKeys derive from the signature; a restarted agent resumes with no state loss.
LatencySend: seconds. Same-chain swap: ~30s. Cross-chain bridge: poll intent status (~1-6 min).
The RAIL20 relayer builds proofs from the agent's signature, so it can see the amounts and recipients it relays for the agent. It cannot move funds without the signature, and on-chain observers still learn nothing. A self-hosted relayer removes this trust.