One Book, Three Checks
Read the chain, ask each pool what this order can receive, then have the contract enforce the minimum you signed. Those are the three steps; none requires trusting the interface.
1 · Read the chain
DexScreener tells the engine which pools exist. Prices and liquidity come straight from chain 4663. Concentrated pools are read from their own state; Uniswap v4 prices come from singleton storage because v4 has no separate pool contract.
slot = keccak256(abi.encode(poolId, 6)) sqrtPriceX96 = extsload(slot) & ((1 << 160) - 1)
About half the live pools are v4. An indexer once converted their cross-equity prices through its own rate, creating apparent spreads of three to four percent. Reading the singleton directly reduced the widest observed SPY spread from 4.74% to 1.25%.
2 · Ask the pools
A price means little without an order size. A model that stops at the current tick overstates output by about 0.16% in a one-tick-spacing pool. Venue differences can be around 0.01%, making that modelling error far larger than the spread under study.
Morain quoter asks the pool itself. It invokes the real swap, then reverts from the callback with the quote instead of paying. No transaction settles and no signature is needed. One eth_call prices the entire book, including each pool’s usable depth.
3 · Enforce the fill
The router receives the input, follows the route, and measures the output as a balance change. It deducts the protocol fee before comparing the result with your signed minimum. A shortfall reverts the transaction.
uint256 got = IERC20(tokenOut).balanceOf(address(this)) - outBefore; if (bps != 0) got -= (got * bps) / 10_000; if (got < minOut) revert SlippageLimit(got, minOut);
A concentrated pool may stop accepting input when liquidity runs out. The router rejects an order if any input would remain there. A partial fill is a revert, never a partial success.
Contracts
Deployed at block 50,072,426. The contract caps its protocol fee at 0.30%; the cap cannot be raised. Ownership changes require two steps, preventing a mistyped address from taking control immediately.
Deliberate limits
The caller provides Hop.pool; the router does not check it against a factory. Instead, it guarantees that a pool receives only funds from this call, up to that hop’s amountIn. A bad pool choice can harm only the signer of that route.
Buy or sell through one call
The same call handles buys and sells by reversing the tokens. Routes support up to three hops and can bridge an equity without a direct pool in the chosen currency. A second hop is used only when it improves on the direct route by more than ten basis points, accounting for its extra fee and liquidity risk.
Uniswap v2 pools are intentionally excluded. None are live on this chain, and applying a constant-product formula to a Solidly-style curve would understate its output.
Splitting an order across pools
A large order moves farther along one pool’s curve and receives a worse price at the tail. Distributing that order among pools uses flatter portions of several curves. For an order large enough to exhaust one pool, the difference can approach thirty percent more of the asset for the same spend.
Splits use a separate contract because multiple legs are not the same call as one route. It executes v3 legs before the singleton lock and v4 legs inside it, then measures one combined balance change. minOut applies to the total, not each leg; set it with the least liquid leg in mind, rather than an average.
The allocation creates the improvement. Arbitrary splitting can perform worse than a single route. The engine quotes every pool across a grid of sizes, solves for the shares, and splits only when the result clearly exceeds the best single route.
The contracts have not been audited. They hold no funds between transactions, and the source is public. Those are the limits of the assurance we can give today.
Six Venues, Checked On-Chain
The engine identifies an AMM by querying its pools, not trusting an indexer version label. Two venues have no version tag; treating them as constant-product was wrong. One reports raw balances through getReserves, which are not a price.
Why one execution path works
These v3 descendants share a swap signature and callback structure; only the callback name changes. The router’s fallback handles those selectors, letting Ramses, Giga, and Algebra use the Uniswap execution path. The hop fixes what the callback may pay, regardless of what the pool requests.
What fork tests cannot cover
These tokenised equities are Stylus contracts: WebAssembly rather than EVM bytecode. Foundry’s revm cannot execute them, while Up and Alandale pools are paired only with equities. Fork tests therefore cover ordinary ERC-20 pairs; live-chain simulation covers the venues carrying the actual product:
This script simulates a swap through the deployed router, using one pool from each venue and current mainnet state. State overrides provide balances and allowances. It requires no funds and transfers nothing.
Verify Every Number
Every published figure is derived from a command you can run. If your calculation disagrees with the site, the site is wrong.
The checks cover encoder and keccak output against cast, the canonical registry, venue execution, partial-fill rejection, and a real trade dry-run.
Resolves each ticker to its canonical contract, excludes pools reporting billions in depth against negligible volume, and prints the venue table.
Finds a pool’s input limit, then confirms that the router rejects an order beyond it instead of filling only part of it.
Compares every selector, topic, and calldata payload built here byte for byte with Foundry. A mismatch fails before the app can send malformed data.
A live round trip
A live round trip exchanged 5 USDG for 0.02275283 NVDA, then 0.02 NVDA for 4.392261 USDG. Both directions used the same contract and app routing code. The buy matched its quote exactly; the sell differed by 0.002%. The router retained nothing after either fill.
What remains unproven
There is no audit. We state that explicitly.
Use the HTTP API
Read verified assets, compare executable quotes, build unsigned transactions, and check settled fills through the same public endpoints used by the interface.
Request a quote
GET /api/v1/quote?tokenIn=USDG&tokenOut=SPY&amountIn=10
Verify a fill
GET /api/v1/receipt?tx=0x...
The API returns routes and unsigned transaction data. A wallet remains responsible for review, approval, and signing.
One Layer Across Existing Venues
Morain holds no liquidity. It reads the pools already on Robinhood Chain and presents them as one executable book.
On chain 4663, tokenised equities trade through roughly 170 pools across nine venues. Quotes use dollars, wrapped ether, or other equities, and their prices can differ.
A visible price gap is only a starting point. To trade it, you must know how much each pool can fill and enforce the worst outcome you will accept. That is the protocol’s job.
What exists today
The depth engine reads live pools on-chain. The quoter lets each pool calculate its own output. The router checks the actual fill. All three are deployed, verified, and reproducible from the repository.
What does not
No audit, invented token utility, unsupported partnerships, investor list, or unattributed press quotes. Claims on this site are backed by something you can open.
Release History
Deployments and measurements, newest first. Each entry points to an address, transaction, or reproducible command.
The router and quoter were deployed on chain 4663 at block 50,072,426 and verified on Blockscout. The protocol fee was set to zero.
The fill matched its quote exactly and left no balance in the router.
Reading v4 state on-chain removed the indexer cross-rate from about half the live pools. The widest measured SPY spread moved from 4.74% to 1.25%.
Up and Alandale arrive without version tags and were mistakenly treated as constant-product. Alandale uses Algebra; its getReserves output is not a price.