Robinhood Chain · 4663 · deployed 2026-09-10
Two contracts of our own.
Everything else KUDARO publishes is a website, and a website is a thing you have to trust. These answer from inside the chain, to anyone, without going through us. One enforces the floor on a trade instead of promising it. The other exists because of a mistake we made, and makes that mistake impossible to repeat without being caught.
KUDAROExecutorours
Coming soonthe floor, enforced · a fixed SOUNDER burn on every fill · holds nothing between transactions
KUDAROLensours
Coming soonthe reading, checkable · view only · it cannot hold a token
01
Why there are contracts at all
A number on a page is a claim. A number a contract will act on is a commitment.
KUDARO spent its first weeks measuring: reading four pool geometries out of their own storage, walking depth tick by tick, and publishing what each venue could actually absorb. All of that ran on a server we control, behind a domain we own. Every figure on this site could have been made up, and you would have had no way to tell short of rebuilding the whole thing.
These two contracts close that gap from opposite ends. The lens lets anyone take the same reading without asking us. The executor makes the reading binding: it will not let a trade settle for less than was promised, and it does not take our word for what arrived: it counts.
02
KUDAROExecutor
The floor, enforced rather than promised.
A router will accept your transaction and hand back less than it quoted. Its own minimum is real, but it is checked inside the same contract that decides what you got, which is fine right up until it is not. This one sits outside that loop.
| Address | Coming soon |
|---|---|
| Router it calls | 0x8876789976dEcBfCbBbe364623C63652db8C0904 |
| Allowance system | 0x000000000022D473030F116dDEE9F6B43aC78BA3 |
| Burns | Coming soon |
| Burn per fill | 0 SOUNDER per fill — set after token launch |
| The peg | target $2.00 · drift +0.0% · inside the band, nothing to do |
| Burn goes to | 0x000000000000000000000000000000000000dEaD |
| Size | 4,843 bytes of runtime code |
| Compiler | solc 0.8.26, optimizer on, 400 runs |
| Second deployment | 0x23bba991850892d78B5c6802BaD59BDBeFBBc3c4 |
| First deployment | 0xf4ab80f0b773a41907c365a77a73628f73750aba |
The router, the allowance system and the token it burns are fixed at deployment and there is no function that can change them. It can only ever call one address, with one function selector. Calldata that is not the router’s own execute is rejected before anything moves.
Every fill burns a fixed quantity of SOUNDER, pulled from the caller straight to the dead address before the route runs. If the caller cannot pay it, there is no fill. It is a quantity of tokens rather than a dollar figure, because a contract cannot price SOUNDER honestly, and the address that deployed it can re-peg the quantity as the price moves.
The burn is re-pegged by a rule rather than a mood: the quantity targets two dollars, and when its value drifts more than twenty percent either way the keeper sets a new one. Every change is a BurnSet event on the contract; the drift, the quantity that would hold the target today, and every re-peg so far are read live at /api/peg. Nobody has to be believed about it.
This third deployment exists for selling. Buying needed two input tokens, the money legs, and their ceilings could be written once at construction. Selling makes every ticker on this chain an input token, and a new asset must not mean a new address and everyone re-approving. So the ceiling for an input token is set by the keeper, per token, on this one address. A token with no ceiling is refused outright. That and the burn are the two adjustable things on it; there is still no pause, no upgrade and no fee recipient, and no way to touch anyone’s balance: a ceiling only bounds what one call may move through here. The earlier deployments stay on chain and still work. The page no longer writes to them.
02b
KUDAROOrders
Orders that wait, and anyone may execute.
Leave what you pay and the least you will accept back. The contract holds the input and the burn until the chain can fill the order or the owner takes it back; nobody else can touch either. Execution is permissionless: whoever sends the fill supplies the router instruction, the contract measures its own balance of the output before and after, and reverts the whole transaction if the count is below the floor. The output goes to the owner, never to the executor; the unspent input goes back to the owner; the escrowed SOUNDER goes to the dead address in the same transaction. A route may spend only the order it is filling, never another order’s escrow.
| Address | 0x4CF73434058FdBd27a96477B4378FDcFFef3f2bB |
|---|---|
| Router it calls | 0x8876789976dEcBfCbBbe364623C63652db8C0904 |
| Holds | each open order’s input and its burn, nothing else |
| Can execute | anyone; the output always goes to the order’s owner |
| Adjustable | the burn quantity and the per-token ceiling, keeper-set, logged |
03
How the floor is enforced
By counting, which is the only method that does not require anyone to be honest.
The contract records its own balance of the token you are buying, runs the route, and records it again. The difference is what actually arrived. If that number is below the floor you set, the whole transaction reverts and nothing has moved.
uint256 before = IERC20(tokenOut).balanceOf(address(this)); (bool ok, bytes memory reason) = router.call(routerCalldata); if (!ok) revert RouterReverted(reason); received = IERC20(tokenOut).balanceOf(address(this)) - before; if (received < floor) revert TooLittleReceived(received, floor);
That check does not depend on the router being honest, on the pool being what we think it is, or on KUDARO having read the depth correctly. It depends only on arithmetic the contract performs on its own balance.
04
What it refuses, and by name
A refusal that cannot say why is indistinguishable from a bug.
| Error | What happened |
|---|---|
TooLittleReceived | the trade came up short of the floor you set |
DeadlinePassed | the reading it was built from is stale |
NotTheRouterFunction | the calldata is not the router’s own execute |
RouterReverted | the route itself failed, and the router’s own reason is passed back |
NothingReceived | the route ran and delivered nothing at all |
TransferFailed | the token would not hand the proceeds on |
Reentered | something tried to call back in mid-trade |
05
KUDAROLens
The reading, taken from inside the chain.
A v4 pool has no contract of its own: its state lives in a singleton’s raw storage, which is why most tools quote v4 badly or not at all. The lens reads that storage directly and hands back price, tick, liquidity and, crucially, the fee a swap is actually charged.
| Address | Coming soon |
|---|---|
| Singleton it reads | 0x8366a39CC670B4001A1121B8F6A443A643e40951 |
| Storage slot | 6 |
| Size | 3,249 bytes of runtime code |
| Compiler | solc 0.8.26, optimizer on, 400 runs |
What it answers
| Function | What it gives you |
|---|---|
swapFee(protocolFeePips, lpFeePips) | the fee a swap actually pays, composed the way v4 composes it |
readV4(poolId) | price, tick, liquidity, both fees and the composition |
readV4ByKey(key) | the same reading, which also proves the key is that pool |
readV3(pool) | price, tick, liquidity, fee, spacing and both tokens |
readManyV4(poolIds) | one reading per pool, because a router asks about all of them |
06
The fee we got wrong
This contract is the correction, published where it can be checked.
A Uniswap v4 pool keeps two fees in the same storage word. There is the LP fee it advertises, and beside it a protocol fee taken off the input before the LP’s share is charged. The two do not add, and charging only the first understates what a swap costs.
KUDARO charged only the LP fee and read about five basis points rich on every v4 pool it quoted, for weeks, and nobody noticed, including us. It surfaced when the chain was finally asked to run one of KUDARO’s own transactions and disagreed by 6.83 basis points. Composed properly, the disagreement is under one.
protocol first, off the input; the LP's share on what is left
swapFee = protocolFee + (lpFee * (1_000_000 - protocolFee)) / 1_000_000
for the NVDA pool: 500 + (3000 * 999_500) / 1_000_000 = 3,498 pips
not 3,000, and not 3,500the composition, as the contract performs it
07
What they cannot do
The absences are the design, not an oversight.
| Neither contract has | Which means |
|---|---|
| an owner or admin | there is no function on them we can call and you cannot |
| a pause | we cannot stop your trade once it is in flight |
| an upgrade path | the code you read today is the code that runs tomorrow |
| a fee | there is nowhere for one to go |
| a treasury | the executor sweeps both tokens back to the caller before returning |
The lens goes further: every function on it is view, so it cannot hold a token or move one under any circumstances. The executor holds your tokens only for the length of a single call, and a balance left in it afterwards is a bug rather than a policy.
08
Call them yourself
Neither of these needs our permission, our frontend, or our uptime.
cast call SOON \ "swapFee(uint24,uint24)(uint24)" 500 3000 \ --rpc-url https://robinhood-rpc.publicnode.com # 3498
cast call SOON \ "readV4(bytes32)((bool,uint160,int24,uint128,uint24,uint24,uint24,uint24,uint24))" \ 0x3bb34a44f1b2b5f32c034c38a53065a521a47b199700fa9bd19d60985ff24bf1 \ --rpc-url https://robinhood-rpc.publicnode.com
The executor takes the route KUDARO writes and the floor you are willing to accept. Spending your tokens needs an approval to Permit2 and a Permit2 allowance to the executor: neither is requested by the contract itself, because an allowance is yours to give and a contract that asks for one on your behalf is a contract that can spend it later.
09
Reproduce the bytecode
Constructor arguments are published so the deployed code can be rebuilt exactly.
| Contract | Constructor arguments |
|---|---|
KUDAROLens | 0x8366a39CC670B4001A1121B8F6A443A643e40951, 6 |
KUDAROExecutor | 0x8876789976dEcBfCbBbe364623C63652db8C0904, 0x000000000022D473030F116dDEE9F6B43aC78BA3 |
Both were compiled with Coming soon. The router address was not taken from a deployment list: the canonical Universal Router address exists on this chain but its pool manager points at an address with no code, so it is a copy that cannot execute. This one was found by reading which contract the chain’s own swap traffic passes through, and confirmed against its bytecode: the v3 factory, the v4 singleton, Permit2 and the v3 init code hash are all baked into it as immutables.
The published source
Both contracts are verified on the chain’s explorer, so the code that runs can be read beside the bytecode rather than taken from us. The match is partial: the runtime bytecode is identical, and what differs is the metadata hash, which carries build paths rather than logic.
- Coming soon
- Coming soon
| Baked into the router | Address |
|---|---|
| v3 factory | 0x1f7d7550B1b028f7571E69A784071F0205FD2EfA |
| v4 singleton | 0x8366a39CC670B4001A1121B8F6A443A643e40951 |
| Permit2 | 0x000000000022D473030F116dDEE9F6B43aC78BA3 |
| v3 init code hash | 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54 |
10
What is not safe yet
Said plainly, because the alternative is finding out later.
These contracts are new and they have not been audited. Code that has not been attacked is not code that is known to be safe, and no amount of testing against live chain state changes that. The executor is the one that touches money, and it is the one to be careful with.
What comes next is an audit, and only then an invitation for anyone else to use it. That order is deliberate, and it is the last item on the roadmap.
Read the source.
Both contracts are short on purpose: three thousand bytes each, no libraries, no inheritance, nothing that has to be traced through four files to understand. If something in here is wrong, it should be possible to see that in an afternoon.