How Firth works

Robinhood Chain carries tokenized stocks: ERC-20 tokens, issued by Robinhood, that track shares of listed companies. They trade against USDG in Uniswap pools, and most of them trade in several at once: up to four Uniswap v3 fee tiers and a number of Uniswap v4 pools, each with its own fee and its own depth. At block 75,831,420 there were 227 usable pools across 45 stocks, and NVDA alone traded in 12.

Firth is a web page. It quotes every one of those pools for your order, splits the order where it fills best, and builds one transaction for Uniswap's own Universal Router. It deploys no contract, holds no tokens, runs no server that touches your order, and charges no fee.

How the split works

Each pool's output is a curve: the more you put in, the less each extra dollar buys. Firth asks Uniswap's quoters (QuoterV2 for v3, V4Quoter for v4) what each pool pays at a ladder of sizes: halvings from 1/128 of the order up to 1/8, then eighths up to the whole. Those points make every pool's curve.

Then it water-fills: the next piece of the order goes to whichever pool pays the most for it, piece after piece, until the order is placed. At the end, every pool that was used is filled to the same marginal price, which is what an optimal split means. The finest rungs matter: a small pool can often take the first few hundred dollars of a large order more cheaply than the deep one, and equal slices of a big order are too coarse to give it that.

The legs are then quoted again at exactly the amounts that will be sent. If the split does not beat the single best pool, Firth sends the single best pool. It never does worse than one pool.

The transaction

One call to UniversalRouter.execute(commands, inputs, deadline), with a deadline twenty minutes out:

  1. PERMIT2_PERMIT (only when needed): your signed Permit2 allowance letting the router pull exactly this order's input, expiring in one hour.
  2. V3_SWAP_EXACT_IN, once per v3 pool used: that leg's input, that leg's minimum output, paid from your wallet through Permit2, output sent to you.
  3. V4_SWAP, once, carrying every v4 leg: a SWAP_EXACT_IN_SINGLE per pool, each with its own minimum, then SETTLE_ALL (capped at the v4 legs' total input) and TAKE_ALL (at least the sum of their minimums) to you.

Each minimum is that leg's quote less your slippage limit (0.3%, 0.5% or 1%). If any pool would pay less, the router reverts everything: you keep your tokens and pay only gas. Before your wallet is asked, the page runs the exact transaction against the chain from your address with eth_estimateGas; a transaction that would fail is explained instead of sent.

What your wallet asks

The first time you trade a token, one approval lets Permit2 move it (Permit2 is Uniswap's allowance contract, the same one the Uniswap app uses). Each trade then needs one EIP-712 signature (token, exact amount, one-hour expiry, the router as spender) and one transaction. While an earlier signature still covers the order, only the transaction.

Which pools

  • Every Uniswap v3 pool pairing the stock with USDG at the 0.01%, 0.05%, 0.3% and 1% tiers that has liquidity at the current price.
  • Every Uniswap v4 pool pairing the stock with USDG that has no hook and a fee of 1% or less. Found from the PoolManager's Initialize events, filtered on both currencies.

Two kinds are left out on purpose. A v4 pool with a hook runs that hook's code during your swap; Firth has not read it, so it does not route through it. And some pools here charge fees of 50% to 90% and still quote happily; a fee cap keeps them out. A pool with no liquidity in range is dropped before quoting, since the quoter would walk its whole tick space.

What was measured

At block 75,831,420 (2026-09-29 17:21 UTC), for every stock and three order sizes, tools/scan.mjs ran the page's own split (the same js/route.js) against the chain and compared it with the single best pool, and with the best v3 pool alone. The table on the front page is that run. At $50,000 the split was used for 41 of 44 stocks; the median gain over the best single pool was 22.2 bp, and over the best v3 pool 22.7 bp.

At $50,000 the split beat the best single pool on 41 of 44 stocks. It barely matters on the deepest names, where one pool takes almost everything: NVDA, META, QQQ, GLD and 1 others gain under half a basis point. It matters most where the depth is spread across pools: 22 stocks gain 20 bp or more, led by MRNA (63.5%), NET (40.5%), JNJ (20.2%). On those, $50,000 is more than any one pool holds: the split stops the order draining a single pool dry, but the fill is still far from the listed price.

These are quotes, not fills: they are what Uniswap's quoters said the pools would pay at that block. The app re-quotes before every trade.

Tests

tools/test.mjs runs real trades against live Robinhood Chain state without broadcasting anything (eth_simulateV1 with a funded test wallet): buys and sells through the router exactly as the page builds them, split and unsplit, with and without a Permit2 signature. Result: 10/10 properties, 134 checks, at block 75,835,929. They check that each trade delivers at least its minimum, that the router keeps nothing, that the input spent is exactly the order, that every leg's floor really refuses a worse fill, and that the split matches an independent reference split that knows nothing of the page's maths.

tools/e2e.mjs drives the real page in a browser with a test wallet whose transactions execute the same way: 7/7.

Risks

  • The tokens are Robinhood's. Robinhood can pause any stock token, block addresses, and burn balances. Their value depends on Robinhood and on the listed share.
  • Pools are not the stock market. A thin pool's price can sit away from the listed share's price, and weekend or overnight quotes can drift. The app shows the Robinhood feed beside the pool price where a feed exists.
  • Slippage. Your limit is per pool leg. A 1% limit allows each leg to fill up to 1% under its quote.
  • Contracts. Firth relies on Uniswap's Universal Router, Permit2, v3 and v4 pools. They are audited and widely used, not risk-free.
  • This page. A page can be changed. Read what your wallet shows before you sign: the spender of a Firth permit is always the Universal Router at 0x8876…0904, and every trade is a call to it.
  • Not financial advice. Nothing here recommends buying or selling anything.

Contracts

All of them are Uniswap's or Robinhood's, already on Robinhood Chain (chain id 4663). None is Firth's.

Uniswap Universal Router (executes every trade)0x8876789976dEcBfCbBbe364623C63652db8C0904
Permit2 (the one-hour allowance)0x000000000022D473030F116dDEE9F6B43aC78BA3
Uniswap v4 PoolManager0x8366a39CC670B4001A1121B8F6A443A643e40951
Uniswap v4 Quoter0x8Dc178eFB8111BB0973Dd9d722ebeFF267c98F94
Uniswap v4 StateView0xF3334192D15450CdD385c8B70e03f9A6bD9E673b
Uniswap v3 QuoterV20x33e885eD0Ec9bF04EcfB19341582aADCb4c8A9E7
Uniswap v3 factory0x1f7d7550B1b028f7571E69A784071F0205FD2EfA
USDG (the dollar side)0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168
Multicall3 (reads)0xcA11bde05977b3631167028862bE2a173976CA11

Stocks

StockTokenRobinhood feed
SGOV0x92FD66527192E3e61d4DDd13322Aa222DE86F9B50xa7a18Ca3F19E17FfA28F92302B817Ca8c1A94b06
NVDA0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC0xCF169363636D73dbBf77733629CB38919d14232d
META0xc0D6457C16Cc70d6790Dd43521C899C87ce02f350x5cBC53D382E56cBb223f118CF8Eefb6c9c2759f5
SPY0x117cc2133c37B721F49dE2A7a74833232B3B4C0C0xa68CA83408bE3f78d1c58a82081c619e9d21486d
QQQ0xD5f3879160bc7c32ebb4dC785F8a4F505888de680x41ed2c58611790af0760e31e80Bb427e4e83D603
SPCX0x4a0E65A3EcceC6dBe60AE065F2e7bb85Fae35eEa0x42a95341ff361e81fd934F39943c5C98F6991844
GLD0xC9a981FEE1F9DEc688bb123ccDeCc63D0deBFC4e0x470A51258068043bd43dC0a56245625C9fE86eB0
AMZN0x12f190a9F9d7D37a250758b26824B97CE941bF540x9244830430bC7D9C9A48dd47603F24AD61f7c56e
GOOGL0x2e0847E8910a9732eB3fb1bb4b70a580ADAD4FE30xA04EE5c4c8827F17e82f93bE9e19DeA221A749a8
MSFT0xe93237C50D904957Cf27E7B1133b510C669c2e740xaD6D88eab22aa4867Efe807a5311Ed64962f740D
USO0xa30FA36Db767ad9eD3f7a60fC79526fB4d56D3440x6D054DECb74Cf8ef3675B0Abc100e02921176EdF
MSTR0xec262a75e413fAfD0dF80480274532C79D42da090x2521a77F42098357e83bDea7fBb2A38745bf9280
AAPL0xaF3D76f1834A1d425780943C99Ea8A608f8a93f90x4bDbb3150014c6Ab2C6D9347B0779c49015a2f3f
COST0x4EA005168D7F09a7A0Ba9D1DEf21a479950E44C2none found
LLY0x8005d266423c7ea827372c9c864491e5786600eanone found
TSLA0x322F0929c4625eD5bAd873c95208D54E1c003b2d0xE4479F01738B4e8C428CD8eB72D47AB9BC3c7de6
CRCL0xdF0992E440dD0be65BD8439b609d6D4366bf1CB50x025Ba3B3569Ca7d15Da7BFC1648F13F06A072851
HIMS0xCceE82fE024c36fA15E1005edE3E9e4787e23D09none found
MU0xfF080c8ce2E5feadaCa0Da81314Ae59D232d4afD0x5b40F4E78FA58B60a4F59b8cc8cB8d2Fb0690467
RDDT0x05b37Fb53A299a1b874A619e1c4C404D52C36F4Cnone found
PLTR0x894E1EC2D74FFE5AEF8Dc8A9e84686acCB964F2A0x8cd1DFC0fc61fcA55FA77b37e008A90f13364Fce
TTWO0x5e81213613b6B86EaB4c6c50d718d34359459786none found
GME0x1b0E319c6A659F002271B69dB8A7df2F911c153E0x42A4652D447A5B0bccF3B265bE8530b85A33b3A2
DJT0x1D11f0496982706C5e14A514D4E79F2e6BdE4516none found
SLV0x411eFb0E7f985935DAec3D4C3ebaEa0d0AD7D89f0xdA81cD9c76F1D3Ea32655dfFc7408ef22BB0Ee2a
INTC0xc72b96e0E48ecd4DC75E1e45396e26300BC396810x127B1DeDeE6269E962a59E6C1295b4002c56c403
DELL0x941AE714EC6D8130c7B75d67160Ca08f1e7d11Dd0xe9B94828424a8Efe6e773c28AB5Fd486851867c8
TSM0x58FfE4a942d3885bAa22D7520691F611EF09e7AA0xB48D6D5729Ca032ca43729F4b605bBf9f257A84d
AMD0x86923f96303D656E4aa86D9d42D1e57ad2023fdC0xF6d57763DFa625F4A413485261Ab2E71Ff4304CF
NFLX0xE0444EF8BF4eD74f74FD73686e2ddF4C1c5591E8none found
AMC0x05a3d1Cd21d0C88145E82600E62e7E496e0F222Bnone found
RBLX0xF0C4BF4C582cb3836e98394b1d4e7B7281101bE8none found
COIN0x6330D8C3178a418788dF01a47479c0ce7CCF450b0xA7F7D79D578fb007384BaDF42c8E1D76a6a63bBD
SNDK0xB90A19fF0Af67f7779afF50A882A9CfF424464000xd1016D9Da414B13D55abe02221A8A145eB89aA0D
RIVN0xB1BF26c1D20ff267A4f93550d1E0d06ac40a114Bnone found
QUBT0x59818904ab4cE163b3cE4FfB64f2D6Ca02c434B4none found
NU0x408c14038a04f7bD235329E26d2bf569ee20e250none found
USAR0xd917B029C761D264c6A312BBbcDA868658eF86a60x451B1295aA84FD6d6b58af1a5002eA1b1A1913A0
AVGO0x156E175DD063a8cE274C50654eF40e0032b3fbcFnone found
JNJ0x03DfbBE0AC4E7bCDaFd08eD41A400326B77D8c80none found
ORCL0xb0992820E760d836549ba69BC7598b4af75dEE030x2a07f8d87d369Bd8Bc36472337ae02d512a7b5e5
NET0x116F00968269B7bfbaD4109cE591d6E74c0601d4none found
MRNA0x43B07D15cE533bEc5476d70C22a78a1B2B662155none found
ASML0x47F93d52cBeC7C6D2CfC080e154002370a60dAEA0x3eFBba343e2b1cF9ed4d4D5768e20B70307Aa8c9
SOUN0x6E3Dfd9f7e1649BaA14D25cac18C94d62dB10A54none found