From Scattered Pools to One Fill
Three steps, none of which asks you to trust the interface: read the chain, ask the pools what they will actually give, then let the contract check the result against what you signed.
1 · Read
The engine asks DexScreener one thing only — which pools exist. Everything else comes from chain 4663 directly. Concentrated pools are priced from their own state; Uniswap v4 has no pool contract at all, so its price is read out of the singleton’s storage.
slot = keccak256(abi.encode(poolId, 6)) sqrtPriceX96 = extsload(slot) & ((1 << 160) - 1)
Half the live pools on this chain are v4. Before this was read on-chain, their prices came from an indexer that converts cross-equity pairs through its own rate, and that produced spreads of three to four percent that did not exist. Reading the singleton cut the widest spread on SPY from 4.74% to 1.25%.
2 · Quote
A price without a size is decoration. Modelling the swap inside the current tick overstates the output by roughly 0.16% on a pool with one-tick spacing — and venues differ from each other by about 0.01%, so the model’s error is an order of magnitude larger than the thing being measured.
VoxQuoter asks the pools instead. It calls their real swap, and in the callback reverts with the numbers rather than paying. Nothing settles, nothing is signed, and one eth_call prices the whole book — including how much input each pool can actually absorb.
3 · Execute
The router pulls, routes, and checks. What landed is measured as a balance delta, the protocol fee is taken before the comparison, and anything short of the signed minimum reverts.
uint256 got = IERC20(tokenOut).balanceOf(address(this)) - outBefore; if (bps != 0) got -= (got * bps) / 10_000; if (got < minOut) revert VoxSlippage(got, minOut);
A concentrated pool takes only as much input as its liquidity allows. If it takes less than the order, the remainder would sit in the router — so a partial fill is a revert, not a partial success.
Contracts
Deployed at block 50,072,426. The protocol fee is 0.30% — the ceiling written into the contract, not a number that can be raised past it. Ownership transfer takes two steps, so a mistyped address cannot take the keys away.
What it deliberately does not do
Hop.pool is supplied by the caller and is not validated against a factory. What the contract enforces is that money leaving for that pool belongs to this call and never exceeds its own amountIn — a route into someone else’s pool can only hurt whoever signed it.
Both directions, one call
Buying and selling are the same call with the tokens the other way round. A route can take up to three hops, so an equity with no direct pool in your currency is reached through the deepest bridge — but a second hop is only taken when it beats the direct route by more than ten basis points, because an extra hop is a second fee and a second pool that can run out.
Uniswap v2 pools are not supported on purpose. There are no live v2 venues on this chain, and the constant-product formula silently understates the output on a Solidly-style curve.
Splitting one order across pools
A large order pays for its own size: the further it walks the curve, the worse the tail. Divided across several pools, each part travels a flatter stretch of its own curve. On an order big enough to exhaust a single pool that is worth close to thirty percent more of the asset for the same money.
The split runs on its own contract, because a route and a set of legs are different calls. It executes legs of both families in one transaction — v3 pools before the singleton lock, v4 pools inside it — and the result is measured as one balance delta. minOut is checked once against the total, not per leg, so the number to sign should be sized against the least liquid pool in the route rather than the average.
What creates the gain is the allocation, not the split itself: an order cut arbitrarily does worse than a single route. The shares come from asking every pool at a grid of sizes and solving over the answers, and the router only splits when the result beats the best single route by a clear margin.
There is no audit. The contracts hold nothing between transactions and the source is public, and that is the whole of what can honestly be said today.
Six Venues, Measured Not Assumed
Which AMM a venue actually runs is determined by asking its pools, not by reading the indexer’s label. Two venues here arrive with no version tag at all and were being read as constant-product — one of them answers getReserves with raw balances that are not a price.
Why forks work without adapters
Every v3 descendant here keeps the same swap signature and the same callback shape, and only renames the callback. The router answers any selector through its fallback, so Ramses, Giga and Algebra pools are executed by the same code path as Uniswap. What the callback pays is fixed by the hop being executed, not by whatever the pool asks for.
Why forge cannot prove this
Tokenised equities on this chain are Stylus contracts — WebAssembly, not EVM bytecode. The revm inside Foundry refuses to execute them, and the Up and Alandale pools are equity-paired only. Fork tests therefore cover the router against ordinary ERC-20 pairs, and the venues that carry the actual product are proven on the live chain instead:
That script simulates a real swap through the deployed router on one pool per venue against live mainnet state. Balances and allowances are supplied by state override, so it needs no funds and moves nothing.
Recompute Everything
Every figure on this site is derived, and each derivation is a command. If what you compute disagrees with what is published here, what is published is wrong.
Encoder against cast, keccak against cast, the canonical registry, venue executability, partial-fill rejection, and a dry-run of a real trade.
Resolves each ticker to the contract carrying the real market, drops pools claiming billions against no volume, and prints the venue table.
Finds where a pool stops absorbing, then shows the router rejecting an order past that point rather than filling it halfway.
Every selector, topic and calldata this site builds, compared byte for byte against foundry. It fails before the app can send nonsense.
A round trip, both directions
Five dollars of USDG into 0.02275283 NVDA, then 0.02 NVDA back out for 4.392261 USDG. Same contract, opposite directions, routed by the same code the app runs. Deviation from the quote was zero on the buy and 0.002% on the sell, and the router held nothing after either.
What is not proven
There is no audit. That is stated here rather than left for someone to discover.
One Install, Verified Addresses
Everything the router needs to be called from your own code: the contract addresses, the ABIs and the canonical token set, published as a package that checks itself against the chain.
npm install binavox-interfaces
What you get
import {
CHAIN_ID, ROUTER, QUOTER, ROUTER_V4, QUOTER_V4,
TOKENS, SYMBOLS, addressOf,
VoxRouterABI,
} from 'binavox-interfaces'
addressOf('NVDA') // 0xd0601ce157db5bdc3162bbac2a2c8af5320d9eec
TOKENS.USDG.decimals // 6
CHAIN_ID // 4663Why a package and not a copied address
A ticker is not an identifier on this chain. Thirty nine contracts answer to a stock symbol that is not theirs, and the deepest of them holds more than half a million dollars of liquidity while trading pennies a day. Resolving a symbol by searching an indexer will eventually hand you the wrong address, and the wrong address takes real money. The full list is on the registry page.
The token set here is generated from the router’s own configuration, so it cannot drift from what we actually execute against, and every entry is called against mainnet before it ships: symbol() and decimals() have to match, and an address with no contract fails the build.
The ABIs are the deployed ones
They come out of the Foundry build artifacts rather than being retyped, which means they describe the same bytecode that is verified on Blockscout. Errors are included, so a revert decodes into VoxSlippage or UnsupportedVenue instead of an opaque string.
Checked on every push
Continuous integration builds the package on Node 18, 20 and 22, imports the built output the way an installer would, and then calls all twenty one addresses against chain 4663. A missing contract, a mismatched symbol or the wrong decimals fails the run, so drift surfaces here and not in your code.
Where the fee goes
The router's fee recipient is a contract, not a person. Everything that reaches it can leave along exactly one path: swapped into BINAVOX and sent to the burn address. There is no withdraw function in it, for the owner or for anyone else, and the routers, the token and the burn address are fixed in the constructor with no setters.
Choosing the route for a buyback is a job for a separate hot wallet, and that wallet can only route through pools the owner has listed. The list is the part that matters. Routers do not check pool addresses, deliberately, because normally the account that signs a route is the account that pays for it; in a treasury it is not, and without a list one fabricated pool would empty the contract in a single transaction while leaving an ordinary-looking buyback in the logs.
That leaves the owner, who keeps the list and appoints the wallet, and so remains a trusted party. Freezing the set of pools forever would remove even that, and would also stop the buyback the day BINAVOX liquidity moves to a pool that is not on the list. We would rather say which part is trusted than claim a guarantee that isn't there.
What the contract constrains is the money that reaches it. Where future fees are directed remains a call the router's owner makes, and that call is visible on chain like any other.
VoxTreasuryV2 0x25A99c317f3125Fc6cd245197028f49CfF56612E
Verified: robinhoodchain.blockscout.com · source and tests: contracts repo
Or call it over HTTP
The same routing, without installing anything. Prices come from the pools through the on-chain quoter, so an answer here can be reproduced with an RPC and nothing else.
curl 'https://www.binavox.tech/api/v1/quote?tokenIn=USDG&tokenOut=SPY&amountIn=10'
/tokens and /venues are the reference set, /quote compares every direct pool that can actually take the size, /swap returns an unsigned transaction, and /verify reads what a fill really did from its receipt.
/receipt goes one step further. It takes a settled swap and re-quotes every pool for the same pair and size at the block before the fill, so the order's own footprint is not in the comparison, and returns the whole board including the losers. When the route taken was not the best one available, it says so. Nothing is stored on our side: the numbers are recomputed from chain state on every request, so an archive node that is not ours reproduces them exactly.
curl 'https://www.binavox.tech/api/v1/receipt?tx=0x...'
/launches and /launch read the launchpad: every coin whose creator fees run a vault, the vault's market, side, margin and BINAVOX burned, and for one coin the whole history decoded from its events. /launch-build returns the unsigned launch transaction. The mechanics are on the launchpad page.
Every fill also has a page: www.binavox.tech/fill/0x401dac…b4650
We hold no keys and cannot broadcast. /swap hands back calldata; signing is yours. minOut is required and never defaulted, because that number is your protection and not ours to pick.
Machine readable spec, including the service level: openapi.json
Or hand it to an agent
The same calls, nine of them, as tools inside any MCP client. One line of configuration, no key, and nothing to write.
{
"mcpServers": {
"binavox": {
"command": "npx",
"args": ["-y", "binavox-mcp"]
}
}
}The tool an agent needs first is list_tokens. A ticker is not an identifier here, and an agent that resolves a symbol by searching an indexer will eventually send funds to a contract that merely answers to the same name.
build_swap returns calldata and the approval it needs, and the server cannot sign or broadcast either of them. An agent that gets it wrong wastes gas; it cannot spend what it was not handed.
Source, issues and the release notes: github.com/Binavoxag/interfaces · package: npmjs.com/package/binavox-interfaces
A Layer, Not a Venue
Binavox does not hold liquidity and does not want any. It reads what already exists on Robinhood Chain and makes it addressable as one book.
Tokenised equities on chain 4663 trade in around 170 pools spread over nine venues and quoted in three different denominations — dollars, wrapped ether, and other equities. Nothing forces those quotes to agree, and they do not.
The gap is not the interesting part on its own; anyone can screenshot two prices. The interesting part is that acting on it requires knowing how much each pool can absorb before it stops, and having something that refuses to fill you at a worse number than you accepted. That is the whole protocol.
What exists today
A depth engine that reads every live pool from the chain. A quoter that makes the pools do their own arithmetic. A router that verifies the fill. All three are deployed, verified, and reproducible from the repository.
What does not
No audit. No token utility that requires anyone to buy anything. No claimed partnerships, no investor list, and no press quotes — if something is not linkable, it is not on this site.
What Actually Shipped
Deploys and measurements, newest first. Anything listed here has an address, a transaction, or a command attached to it.
VoxRouter and VoxQuoter deployed to chain 4663 at block 50,072,426 and verified on Blockscout. Protocol fee set to zero.
Settled at zero deviation from the quote, with nothing left on the router afterwards.
Half the live pools stopped depending on an indexer’s cross-rate. The widest spread on SPY fell from 4.74% to 1.25%.
Up and Alandale were being read as constant-product because they arrive with no version tag. Alandale is Algebra, and its getReserves is not a price.