# Spare Change > A pay-through router for AI agents on Robinhood Chain (chain id 4663). An agent pays through the router instead of paying directly. The payment goes straight from the agent's wallet to the recipient, and the router rounds it up: a 13.40 USDG payment with a 1.00 unit sends 13.40 to the recipient and 0.60 to the savings wallet the agent's owner chose. Round-ups are switched on by a plan that burns $CHANGE. The router never holds tokens or ETH. Status: not launched yet. The router address is published when $CHANGE launches on Pons. Until then /api/plan, /api/payments and /api/stats return 503 {"error":"not_launched"}; /api/tokens works now. ## How it works 1. The payer (your agent's wallet) calls `setup(savings, tokens[], units[])` once: where round-ups go, and the unit per token in its smallest units. `address(0)` stands for ETH. 2. Someone buys a plan: `subscribe(periods)` for yourself, or `subscribeFor(account, periods, maxBurn)` to pay for your agent's wallet from yours. Each period is 30 days and burns 25,000 $CHANGE (live value: `planFee()`), sent straight to the dead address. 1 to 12 periods at once; time adds to an active plan. 3. The payer approves the router once per token (`approve(router, amount)` on the token). 4. The payer calls `pay(token, to, amount)`, `payMany(token, to[], amounts[])` or `payETH(to, amount)`. `amount` goes straight to `to`. With an active plan, a savings wallet and a unit, the round-up `(unit - amount % unit) % unit` goes straight to savings in the same transaction. Rules the contract enforces: - The round-up is computed by the contract, never by the caller. Read it first with `roundUp(payer, token, amount)`. - Savings go to the wallet the payer set with `setSavings` or `setup`. Only the payer can change it, and it cannot be the payer itself or the router. - The router only ever pulls from `msg.sender`. Nobody else, including the owner, can move a payer's funds through it. - An expired plan never blocks a payment: the payment goes through and the round-up is skipped. A round-up that cannot move (not enough balance or allowance left, or a token that refuses the savings wallet) is skipped too; the payment still goes through and `Paid.saved` is 0. - `payETH`: send `amount + roundUp(payer, address(0), amount)` to save the round-up. Anything above `amount` that the round-up does not use is returned to you in the same call, so sending exactly `amount` always works. - Pausing only stops new plans. Payments and settings always work. - Every payment emits `Paid(payer, token, to, amount, saved)`; `saved` is what actually reached the savings wallet. - The router has no withdraw function and no upgrade path. The owner can only set the plan fee (capped at 10,000,000 $CHANGE per period) and pause new plans. ## Agent SDK https://sparechange.space/sdk.js is one small ESM file with no dependencies of its own. Pass it viem 2.x clients. ```js // npm i viem; curl -O https://sparechange.space/sdk.js import { createPublicClient, createWalletClient, http } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { spareChange, routerAddress, TOKENS, ETH } from './sdk.js'; const chain = { id: 4663, name: 'Robinhood Chain', nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, rpcUrls: { default: { http: ['https://rpc.mainnet.chain.robinhood.com'] } } }; const publicClient = createPublicClient({ chain, transport: http() }); const walletClient = createWalletClient({ chain, transport: http(), account: privateKeyToAccount(process.env.AGENT_KEY) }); const sc = spareChange({ publicClient, walletClient, router: await routerAddress('https://sparechange.space') }); await sc.setup({ savings: '0xYourSavingsWallet', units: { [TOKENS.USDG.address]: 1_000_000n, [ETH]: 10n ** 15n } }); // 1.00 USDG, 0.001 ETH await sc.approve(TOKENS.USDG.address); // approve once (max by default) const { saved } = await sc.pay(TOKENS.USDG.address, '0xSeller', 13_400_000n); // 13.40 USDG, saves 0.60 await sc.payMany(TOKENS.USDG.address, ['0xA', '0xB'], [1_250_000n, 990_000n]); // saves 0.75 + 0.01 await sc.payETH('0xSeller', 12_300_000_000_000_000n); // 0.0123 ETH + its round-up console.log(await sc.plan()); // { active, end, endsAt, savings } ``` ## Read API (JSON, CORS *, no key) - GET https://sparechange.space/api/plan?payer=0x…: plan end, days left, savings wallet, units per verified token, plan fee. - GET https://sparechange.space/api/payments?payer=0x…&limit=50: the payer's payments through the router, newest first, with totals per token (from `Paid` events). - GET https://sparechange.space/api/stats: payments routed, routed and saved per verified token, active plans, $CHANGE burned and % of supply. - GET https://sparechange.space/api/tokens: the stablecoins and wrapped ETH checked onchain, with suggested units. Works before launch. ```bash curl "https://sparechange.space/api/plan?payer=0xYourAgentWallet" curl "https://sparechange.space/api/stats" ``` ## Tokens on Robinhood Chain (checked onchain on 14 Nov 2026) - USDG: 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168, 6 decimals, suggested unit 1000000 (1.00 USDG). The most-used stablecoin on the chain, about 630M supply. - USDe: 0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34, 18 decimals, suggested unit 1000000000000000000 (1.00 USDe). About 363M supply on the chain. - frxUSD: 0x00000000D61733e7A393A10A5B48c311AbE8f1E5, 18 decimals, suggested unit 1000000000000000000 (1.00 frxUSD). Small supply on the chain so far, about 253K. - WETH: 0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73, 18 decimals, suggested unit 1000000000000000 (0.001 WETH). About 39.6K supply, backed 1:1 by ETH held in the contract. - ETH: 0x0000000000000000000000000000000000000000, 18 decimals, suggested unit 1000000000000000 (0.001 ETH). Native gas token. Use payETH, not pay. Copycat tokens with the same symbols exist (for example 18-decimal "USDG" and "USDT" with a 1B supply). Match the address. ## With cast ```bash R= RPC=https://rpc.mainnet.chain.robinhood.com # Where round-ups go, and a 1.00 USDG unit cast send $R "setup(address,address[],uint256[])" 0xYourSavingsWallet "[0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168]" "[1000000]" --rpc-url $RPC # Buy 3 periods (90 days) of round-ups: approve the burn, then subscribe cast send <$CHANGE token address, published at launch> "approve(address,uint256)" $R $(cast to-wei $((25000 * 3))) --rpc-url $RPC cast send $R "subscribe(uint256)" 3 --rpc-url $RPC # Approve USDG once, then pay 13.40 USDG (0.60 goes to savings) cast send 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 "approve(address,uint256)" $R 115792089237316195423570985008687907853269984665640564039457584007913129639935 --rpc-url $RPC cast call $R "roundUp(address,address,uint256)(uint256)" 0xYourAgentWallet 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 13400000 --rpc-url $RPC cast send $R "pay(address,address,uint256)" 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 0xSeller 13400000 --rpc-url $RPC # ETH: value = amount + roundUp(payer, address(0), amount) cast send $R "payETH(address,uint256)" 0xSeller 12300000000000000 --value 13000000000000000 --rpc-url $RPC cast call $R "planOf(address)(uint256,bool,address)" 0xYourAgentWallet --rpc-url $RPC ``` Other reads: `planEnd(address)`, `planActive(address)`, `savingsOf(address)`, `unitOf(address,address)`, `changeFor(uint256 amount, uint256 unit)` (the pure maths), `planFee()`, `totalBurned()`, `totalPayments()`, `totalSubscribers()`, `totalRouted(address token)`, `totalSaved(address token)`, `paused()`. ## Never - Never send tokens or ETH to the router address directly. It has no receive function and no withdraw function, so ERC-20s sent there by plain transfer are stuck for good. - Burned $CHANGE is gone. A plan buys round-ups for its time and nothing else. ## Contracts - Chain: Robinhood Chain, chain id 4663, RPC https://rpc.mainnet.chain.robinhood.com - Router: - $CHANGE token: <$CHANGE token address, published at launch> - Buy $CHANGE: https://www.ponsfamily.com/launchpad - Explorer: https://robinhoodchain.blockscout.com ## ERC-8004 agent identity Spare Change Router is an ERC-8004 agent. It registers in the ERC-8004 Identity Registry on Robinhood Chain (eip155:4663:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432) at launch. - Registration file: https://sparechange.space/.well-known/agent-registration.json - Identity Registry: https://robinhoodchain.blockscout.com/address/0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 - Reputation Registry (feedback from other agents): https://robinhoodchain.blockscout.com/address/0x8004BAa17C55a88189AE136b182e5fdA19dE9b63 - Sitemap: https://sparechange.space/sitemap.xml