Overview
ZapStocks looks for price differences of one verified Stock Token across Uniswap pools on Robinhood Chain. It builds closed cycles that start and end in one settlement asset, USDG or WETH, quotes each cycle with the on-chain quoter, itemises every cost and re-runs the full path against the latest block from your address.
The executor that would run a cycle in one transaction launches soon. Until then you can scan, quote and simulate, and nothing asks you to sign. The $ZAPS token launches separately; the app does not use it for anything. Most of the time no route clears its costs, and the scanner tells you so.
Network
| Fact | Value | Source |
|---|---|---|
| Chain | Robinhood Chain · 4663 | docs.robinhood.com/chain/connecting and a live eth_chainId |
| Type | Arbitrum Orbit L2, Ethereum blobs for data availability | same page |
| Gas token | ETH | same page |
| Explorer | robinhoodchain.blockscout.com | same page |
| Public RPC | https://rpc.mainnet.chain.robinhood.com | Rate-limited and not for production. A provider endpoint goes in ZAPS_RPC_URL on the server. |
| Testnet | 46630, not used | Uniswap lists no deployment there, so nothing can be verified |
Blocks arrive about every 0.1 s. ZapStocks leaves cross-chain routes out: a cycle across two chains cannot settle in one transaction.
Assets and pools
Assets. The asset list starts from Robinhood's Stock Token registry at https://api.robinhood.com/rhj/assets. A ticker proves nothing, since the chain carries look-alikes, so each address must also be an ERC-1967 beacon proxy of the issuer beacon 0xe10b6f6B275de231345c20D14Ab812db62151b00 with a matching symbol() and decimals(). Settlement assets: USDG 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 (6 dp) and WETH 0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73 (18 dp).
Pools. The server calls getPool for every Stock Token against USDG and WETH at each fee tier (0.01%, 0.05%, 0.3%, 1%), getPair for V2, and adds the WETH/USDG connectors. Asking the canonical factory is the membership proof. Stock/stock pools come from the factories' creation logs filtered to verified tokens on both sides, and each one gets re-checked against the factory before use.
Depth. A V3 position one tick wide reports huge liquidity and fills almost nothing. ZapStocks measures depth with a real QuoterV2 exact-output swap to the price 1% above spot, so the figure counts every tick the trade would cross. Pools under 25 USDG of +1% depth count as dust. The rest get a test fill of up to 1,000 USDG that must land within 3% impact beyond the pool fee; a pool that fails is marked hollow and stays out of routing.
Uniswap v4. The pool explorer lists v4 pools between verified assets from a census of the PoolManager's initialisation logs. ZapStocks never prices or routes them: hooks can change fees and the swap curve, and no v4 settlement adapter exists.
Prices and quotes
- All pool state in a comparison comes from Multicall3 calls pinned to one block, and the block number travels with the data to the screen.
- Spot prices (V3 from sqrtPriceX96, V2 from reserves) are indicative: before price impact, not an exchange price and not an oracle.
- The raw spread, dearest against cheapest verified pool of one asset, works as a signal and never as a result.
- The scanner ranks candidate cycles of 2 to 4 distinct pools by spot edge and quotes the best 48 hop by hop through QuoterV2 (0x33e885eD0Ec9bF04EcfB19341582aADCb4c8A9E7) at 5%, 15%, 40%, 100% and 250% of the route's shallowest depth. V2 hops use the constant-product formula on same-block reserves.
- Quotes expire after 20 s. The scanner may show a scan up to a few minutes old while it refreshes; each row carries its age, and the route panel re-quotes at the newest block when you open it.
Cost accounting
| Line | How ZapStocks gets it |
|---|---|
| Raw price spread | Product of spot rates after pool fees, minus 1. Used for ranking. |
| Quoted route output | QuoterV2 or the V2 formula, hop by hop. Pool fees and price impact sit inside it. |
| Trading fees | Inside the quote. Never subtracted a second time. |
| Flash-liquidity fee | None on top: a Uniswap flash swap repays the first pool in the settlement asset, and that pool's swap fee inside the quote is the borrowing cost. |
| Protocol fee | 0% in preview. Once the executor ships, the panel reads the live rate from the contract. |
| Gas | QuoterV2's gas estimate for each V3 hop plus a fixed model for the flash callback and transfers, times the current gas price. |
| Gas in the settlement asset | Converted only with the deepest active WETH/USDG pool at the same block, holding at least 10,000 USDG of depth, and only while fresh Chainlink ETH/USD ÷ USDG/USD agrees within 2%. Otherwise gas stays in ETH and the result reads as incomplete. |
| Estimated result after costs | Quoted result minus protocol fee minus gas, when gas converts. |
| Required minimum result | max(floor, estimate × tolerance). The floor defaults to the estimated gas cost. |
Every token amount stays an integer in base units with the token's own decimals until the screen formats it.
Simulation
“Simulate exact path” re-runs the cycle at the latest block. For an all-V3 route the server encodes the path and calls QuoterV2.quoteExactInput, which executes every swap of the cycle in sequence inside one eth_call and reports ticks crossed and swap gas for each hop. Mixed routes run hop by hop at one block. The panel compares the result with the hop-by-hop quote and marks it stale as soon as you change the amount, tolerance, deadline, floor or wallet, or when the quote passes 20 s.
A passing simulation guarantees neither inclusion nor profit. State changes about ten times a second, other traders read the same pools, and a reverted transaction still costs gas.
Executor
No ZapStocks executor is deployed. When it launches, it will follow the flash-swap pattern the scanner already prices:
- It calls swap on the first pool, receives the output first, runs the remaining hops inside Uniswap's callback, repays the first pool and pays you the measured increase.
- You supply no tokens and grant no allowance. Your minimum gets checked after any protocol fee; below it, the transaction reverts.
- Each hop must be the pool the canonical factory returns for its tokens and fee. No arbitrary call targets and no caller calldata.
The status page and this section will list the contract address, its verification checks and the audit state on launch day. Until then the audit state reads “none”, because nothing of ours holds funds.
Transactions and history
After launch, the server and your browser re-quote and re-simulate the call before your wallet opens, and the wallet receives those bytes. History rows will come from the executor's CycleExecuted events and their receipts, each with its confirmation state from the node's block tags: included on L2, batch posted to Ethereum (safe), or finalized there. Today the history page stays empty and says why.
Integrations
| Integration | Status | Address and source |
|---|---|---|
| Uniswap V2 factory | Supported | 0x8bcEaA40B9AcdfAedF85AdF4FF01F5Ad6517937f · developers.uniswap.org/deployments.json |
| Uniswap V3 factory and QuoterV2 | Supported | 0x1f7d7550B1b028f7571E69A784071F0205FD2EfA · 0x33e885eD0Ec9bF04EcfB19341582aADCb4c8A9E7 · same registry, factory() and WETH9() cross-checked |
| Multicall3 | Used for reads | 0xcA11bde05977b3631167028862bE2a173976CA11 |
| Stock Token registry and beacon | Supported | https://api.robinhood.com/rhj/assets · 0xe10b6f6B275de231345c20D14Ab812db62151b00 |
| Chainlink ETH/USD, USDG/USD | Cross-check only | 0x78F3556b67E17Df817D51Ef5a990cDaF09E8d3A9 · 0x61B7e5650328764B076A108EFF5fa7282a1B9aD2 |
| Chainlink sequencer-uptime feed | Not available | Robinhood's docs recommend one; none is listed for chain 4663. |
| Uniswap v4 PoolManager | Listed, not routed | 0x8366a39CC670B4001A1121B8F6A443A643e40951 · hooks can change pricing; no v4 settlement adapter |
| Privy | Wallet login | External EVM wallets only. No email, SMS or social login, and no embedded wallets. |
Token
$ZAPS is the ZapStocks token on Robinhood Chain. Its contract address appears in two places once it exists: the token section of the landing page and GET /api/token. Both read the server setting ZAPS_TOKEN_ADDRESS. Until then both say launch soon, and an address quoted anywhere else is not ours.
The app does not use the token. Scanning, quoting and simulation never read a $ZAPS balance, and there is no staking, treasury, yield, fee discount, reward or governance tied to it. After launch the site shows what the chain reports at a stated block: name, symbol, decimals, total supply and, when a canonical V2 or V3 pool against USDG or WETH holds liquidity, that pool's spot price. Nothing here promises value or a return.
Limitations
- A web interface is slow next to a co-located bot. Expect opportunities to vanish before inclusion.
- Test fills cover up to 1,000 USDG; larger sizes rely on the quoted ladder.
- Sizes come from a five-step ladder, not a continuous optimiser.
- The public RPC throttles and is not archival. The last good read stays on screen, marked stale, with the error.
- Stock Tokens can be paused, blocklisted or upgraded by their issuer, and a cycle that touches one then reverts.
Developer interface
Every endpoint answers JSON shaped as { ok, data, meta }. Amounts are base-unit strings.
| Endpoint | Returns |
|---|---|
GET /api/markets | Pools, prices, depth, test fills, per-stock aggregates, the reference rate and the v4 summary at one block. |
GET /api/routes?settlement=USDG|WETH&maxHops=2..4&token=0x… | Quoted cycles with accounting, verdicts, rejection summary and excluded pools. |
POST /api/quote | A fresh quote for one route; with simulate: true, the full-path simulation and its encoded path. |
GET /api/pools/v4?page=1&extreme=0&asset=0x… | Uniswap v4 pools between verified assets, listed and unsupported, paginated. |
GET /api/status | Network, finality tags, integration checks, data freshness, executor and token state. |
GET /api/registry | The verified Stock Token list with the block it was checked at. |
GET /api/token | $ZAPS: "soon", or the address with contract facts and canonical pools read at one block. |
GET /api/activity | Execution history. Returns not-deployed until the executor launches. |