Skip to main content

Robinhood Chain Trading Primitives with Quicknode and Relay

Updated on
Sep 23, 2026

21 min read

warning

Unaudited developer example. This is not investment advice. Robinhood Chain launchpad tokens are speculative. They can lack liquidity, block sales, or lose all value. Pools.trade, pons, and long.xyz do not review, verify, or endorse listings. $AI, $FRONG, and $pons are unreviewed examples, never recommendations. Verify availability before you act.

Robinhood Assets (Jersey) Limited issues Stock Tokens: debt securities that track public equities. They grant no shares, no shareholder rights, and no votes. Jurisdictional restrictions apply. Read Robinhood's terms.

Every snippet here is read-only. It reads live mainnet. It never signs and never broadcasts. It cannot move funds. Going live is a separate build with real risk. You remain responsible for local compliance.

Overview

Most "trading bot" posts on X (FKA Twitter) show a busy dashboard with questionable (often faked) success metrics and skip the hard parts. This guide teaches the hard parts: building a Robinhood Chain trade from its primitives. Those primitives decide whether a real trade works.

Robinhood Chain is an EVM L2 (chainId 4663). In this guide, routing goes through Relay, and chain reads and simulation go through Quicknode. You get six small Python snippets. Each one runs against live mainnet and prints a real result. None of them signs anything.

The snippets follow the path from a signal to a settled trade:

The guide stays paper-first on purpose. A starter guide should not put keys near a hot wallet, so the snippets read and simulate only. The final sections cover what a live build must add.

TL;DR
  • Six read-only Python snippets build a Robinhood Chain trade from its primitives: base discovery, routing, sellability, marking, live signals, and new-pool discovery.
  • Routing runs through Relay with keyless quotes. Chain reads and simulation run through Quicknode: RPC, eth_simulateV1, and WebSocket subscriptions.
  • Sellability is the core check. A state-carrying eth_simulateV1 call tests a buy-then-sell round trip on one pinned block, so blocked exits and punitive round-trip friction surface before any trade.
  • Nothing signs or broadcasts. Every snippet is paper-first. The Going Live section lists what a real build needs.

What You Will Do


  • Learn which quote assets a token actually trades against, deepest first, from Dexscreener data.
  • Get Relay's proposed route and know which swap target and approval spender to pin before live use.
  • Prove a token is sellable, not just buyable, with a block-pinned buy-then-sell simulation, and read its round-trip friction.
  • Value a position with an external price, and filter a live trade tape so flagged or malformed buys never reach your signal logic.
  • Catch brand-new pools the moment they are created, and tell a funded pool from an empty one.

What You Will Need


  • A Quicknode account with a Robinhood Chain Mainnet (chainId 4663) endpoint. Copy the HTTP and WSS endpoints.
  • Python 3.11+.
  • No wallet and no funds. The snippets never sign.
  • Familiarity with EVM tokens, RPC, JSON, and the command line.

Install the dependencies and set your endpoint. The endpoint carries a token, so never commit it.

git clone https://github.com/quiknode-labs/qn-guide-examples.git
cd qn-guide-examples/robinhood-chain/qn-rh-trader/python
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

export QUICKNODE_RPC="https://<your-endpoint>.quiknode.pro/<token>/" # HTTP
export QUICKNODE_WS="wss://<your-endpoint>.quiknode.pro/<token>/" # WSS (watch.py only)

Each snippet reads these from the environment, never from a config file or the OS keychain, and checks eth_chainId before it trusts the endpoint. Two snippets need no endpoint at all (mark.py and signals.py), and bases.py uses one only for an optional onchain check.


note

These are educational snippets. They favor a clear, correct core over the defensive hardening a real bot needs. They skip retries, response size caps, per-token storage layouts, and durable state. The "From Snippets to a Bot" section lists what to add before you trust any of this with money.

The outputs below are real captures from 2026-09-19. Your numbers will differ with the live market. Verify each example token is still live before you use it.

Market Landscape

First, how the chain behaves. Robinhood Chain is an Arbitrum Orbit L2 with one sequencer, no public mempool, and a block time near 0.1 s (measured at 0.101 s per block over 2,000 blocks). Ordering is first-come-first-served, so priority gas buys you nothing. Latency comes from getting your request in early, not from a fee auction. Because a block is about 0.1 s, reason in wall-clock seconds, not block counts: a five-block window is only about half a second.

The markets this guide covers trade as Uniswap v4 pools, so a launch usually surfaces as a new v4 pool. Not always, though. An early pons launch uses a v3-style pool, a bonding-curve launch creates its v4 pool only at graduation, and a new pool can pair two existing tokens.

Robinhood Chain hosts several token kinds. Do not treat them as the same.

  • pons launchpad tokens. Early launches use v3-style pools. Later launches run a bonding curve and graduate into a Uniswap v4 pool. The quote asset comes from the launch's pairToken.
  • Pools.trade tokens. Uniswap's launchpad on Robinhood Chain. Each token trades through a Uniswap v4 pool with locked liquidity.
  • Stock Tokens. Debt securities that track a public equity. They grant no shareholder rights and are region-restricted (not available to US persons). Because they are geo-gated, Relay returns UNSUPPORTED_CURRENCY for them, so this guide's Relay-based tools cannot trade them. Robinhood documents other liquidity paths for them, through request-for-quote (RFQ) aggregators such as 0x RFQ, 1inch Fusion, and LiFi, and through AMMs such as Uniswap and Rialto. This guide does not cover those paths.
  • long.xyz anchored tokens. Meme-stock-anchored community tokens. They are never pegged or equivalent to the equity they reference. They can settle against a Stock Token.

One fact drives the first snippet: a single token trades across many pools with different counterpart assets. The same token can have a WETH pool, a USDG pool (USDG is a USD stablecoin), a native-ETH pool, and a Stock-Token pool at once. So never assume what it pairs with. Discover it.

"The base" also means two different things. One is the input asset you spend, such as WETH, USDG, or native ETH. You choose it, and for an EXACT_INPUT quote it sets your funding and your sizing. The other is the set of pools Relay routes through. Relay picks those, so they are informational. Discovery tells you which counterpart assets exist so you can pick a sensible input asset. It does not reveal Relay's route. Let's look at the first snippet.

Discover What a Token Trades Against

bases.py lists the distinct counterpart assets a token trades against, ranked by their largest reported pool, one entry per counterpart. It uses Dexscreener, which needs no key. Dexscreener indexes Robinhood Chain under the slug robinhood; the numeric chain ID returns nothing.

Use the /token-pairs/v1 endpoint, not /tokens/v1. The first returns all of a token's pools (up to 30). The second returns only the primary pair, which hides the other bases.

python snippets/bases.py 0x2E8c31162b855A2ffa90F6F8634643Ad6F111e18
0x2E8c31162b855A2ffa90F6F8634643Ad6F111e18
PRIMARY WETH 0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73
liq $3,533,060 (Dexscreener) [verified onchain, 18 dp]
others (observed counterpart assets; Relay route support unverified):
USDG 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 liq $1,311,155
ETH 0x0000000000000000000000000000000000000000 liq $730,267
CASHCAT 0x020bfC650A365f8BB26819deAAbF3E21291018b4 liq $19,505
NVDA 0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC liq $1,331
PONS 0x39dBED3a2bd333467115dE45665cC57F813C4571 liq $613
note these are Dexscreener pairs, not confirmed routes. Relay picks the actual
settlement path, so the base is informational. Confirm a base with quote.py.
the liq shown is the DIRECT pair only; it can badly UNDERSTATE tradeable depth
because Relay routes through deeper pools (a thin direct pair still trades big),
and some counterparts (e.g. Stock Tokens) may not be Relay-routable at all.

$AI ("Artificial Inu") anchors NVDA. It trades against WETH, USDG, native ETH, and the NVDA Stock Token. The snippet leads with the deepest pool and lists the rest as options.

Discovery itself is keyless. The [verified onchain, 18 dp] tag is the one part that uses your endpoint. Dexscreener's per-pool liquidity can be wrong and under-counts some pools, so when QUICKNODE_RPC is set, the snippet reads the primary quote asset onchain to confirm it is a real contract with valid decimals. Without the endpoint, that line reads (set QUICKNODE_RPC to verify onchain) instead.

Read this as a map, not a mandate. "Deepest" means the largest reported USD liquidity in the direct pair, which is a discovery heuristic, not executable depth. In Uniswap v3 and v4, liquidity can sit outside the current price range, and Relay routes through deeper pools, so the direct-pair figure can understate tradeable depth by orders of magnitude. The $AI/CASHCAT pair reads about $20,000 above, yet Relay routes $100,000 of $AI into CASHCAT at roughly 2% impact. The mismatch runs the other way too: the $AI/NVDA pair reads about $1,300, and Relay will not route it at all, because NVDA is a Stock Token. Use these numbers to see which counterparts exist. Confirm real depth with a size-specific quote from quote.py, and trust the route Relay returns over this ranking.

Get a Real Route

quote.py asks Relay for an executable route through its keyless quote API. The client sends no credential.

The snippet discovers the token's quote asset first (the primary from bases.py), then requests a quote-asset to token EXACT_INPUT route on Robinhood Chain and prints the ordered steps.

python snippets/quote.py 0x2E8c31162b855A2ffa90F6F8634643Ad6F111e18
quote asset (discovered, deepest): WETH 0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73
approve approve spender 0xCcC88a9d1B4ED6b0EABA998850414b24f1c315bE
swap target 0xCcC88a9d1B4ED6b0EABA998850414b24f1c315bE
PIN the swap target and the approval spender (verify against Relay's docs) before live use.

Three details matter here.

First, Relay returns an ordered list of steps. An ERC-20 buy commonly needs an approve then a swap, but an existing allowance or a native-ETH input can reduce it to one transaction. Some routes return a signature step instead. The step kind alone does not say what the signature authorizes: it can be a permit (Permit2, EIP-2612, or EIP-3009), a signed order, or a wallet-ownership auth. A signature can move funds with no broadcast, so treat any signature step as potential fund movement and inspect the typed data before signing.

Second, the request pins its own slippage. The client sends slippageTolerance as a string of basis points ("100", or 1%), so Relay cannot pick its own tolerance.

Third, the swap targets a Relay route contract. In this capture it is 0xCcC88a9d...315bE. Before any live use, pin that swap target and the approval spender, and verify each address against Relay's published contract deployments. Relay can rotate this contract, and a rotated address is a new address to verify and pin.

To force a specific quote asset, for example to fund an $AI buy with USDG instead of its deepest WETH pool, pass it as the second argument. This works only for a pair Relay actually routes. A Stock Token returns UNSUPPORTED_CURRENCY from USDG too, so forcing USDG does not make it routable.

python snippets/quote.py 0x2E8c31162b855A2ffa90F6F8634643Ad6F111e18 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 # $AI, funded with USDG

Prove a Token Is Sellable, Not Just Buyable

This is the most important snippet. A buy that succeeds does not prove you can sell. Honeypots, punitive taxes, and hostile v4 hooks block exits, and Pools.trade and pons do not vet tokens.

sellability.py answers the question in two read-only steps, both pinned to one block, using Quicknode's eth_simulateV1. First it simulates the buy alone and measures the tokens actually acquired from the Transfer logs. Then it reverse-quotes a small haircut of that amount and simulates buy-then-sell in one sequence, with state carried across the legs. If the sell leg reverts, sellability is unproven. That is the honeypot signal, though slippage, a deadline, or an approval failure can also revert.

python snippets/sellability.py 0x6245e67affA44a23077f0Ea7f981a8DC743a0c47 # $FRONG
0x6245e67affA44a23077f0Ea7f981a8DC743a0c47
buy sim ok (spent 20000000000000000 raw WETH -> 7291811217773337938271 raw token)
sell sim ok (sold 7145974993417871179505 raw token -> 19453509714157272 raw WETH)
exit the reverse-sell settled for the PROBE ADDRESS at this size (no blocked sell)
friction 75 bps (net per-base round trip, REPORTED not gated; set your own
ceiling: a punitive-tax token settles the sell yet returns almost nothing)
note probe address + same parent block (by number) + this size + head base fee;
log-derived, not authenticated; a simulated gas context (not full ArbOS/L1
fee accounting); a token could permit this address but block other holders

Five design choices make this defensible:

  • Size the reverse-sell from the measured amount, not the quoted estimate. A quote is an estimate. If actual receipt falls short of it, selling the estimate would revert for insufficient balance, and the snippet would call a healthy token a honeypot. So it simulates the buy first on a fixed block, reads the real acquired amount, then sells a 2% haircut of that on the same block.
  • Pin both simulations to one block and the head timestamp. Pinning the block stops a new block between the two legs from shifting the balance. Pinning the timestamp matters too: eth_simulateV1 otherwise runs the simulated block about 12 seconds ahead of the parent, which at this chain's speed is far in the future and could expire a time-gated restriction (an anti-snipe fee decay, a launch cooldown) that is still active at head. The snippet sets blockOverrides.time to the head block's timestamp.
  • Pin the base fee. With validation off and no fee fields, eth_simulateV1 runs the block at a zero gas price. A token that gates exits on tx.gasprice == 0 or reads block.basefee could pass that probe yet block a normal paid sale. Setting blockOverrides.baseFeePerGas to the head base fee, with a matching per-call maxFeePerGas, makes GASPRICE and BASEFEE realistic. This is still a simulated context, not a full reproduction of Arbitrum's L1-data-fee and ArbOS gas accounting, so read the result as conditional on it.
  • Require positive, signed deltas, not just successful calls. A token can emit no Transfer logs, or misleading ones. A successful status with zero measured tokens or zero proceeds proves nothing, so the snippet reports sellability as UNKNOWN and fails closed rather than printing a false pass.
  • Fund through WETH.deposit(), not a storage-slot override. Real Robinhood Chain tokens do not keep balances at a guessable storage slot. WETH is a proxy, and launchpad tokens use custom layouts, so a stateDiff balance override silently misses and the wallet stays unfunded. A native-ETH balance override plus deposit() credits real WETH through the contract's own logic, independent of layout.

The snippet funds WETH-quoted routes only, and it rejects a route that carries native value. When Relay rejects the WETH quote's currency with UNSUPPORTED_CURRENCY or an INVALID_*_CURRENCY code, the snippet does not guess that another funding asset would work. Instead it:

  1. Probes the token's deepest non-WETH Dexscreener counterpart through Relay and reports what it finds.
  2. If Relay rejects that pair too, reports sellability as unknown. Common causes are a region-restricted Stock Token or a pair Relay does not support. UNSUPPORTED_CURRENCY can also mean the pair is temporarily unpriceable, and other funding assets remain untested.
  3. If Relay does route the other counterpart, stops there. Funding that asset in simulation needs a separate, verified per-token storage override, which the snippet does not attempt.

A size or no-route error is handled earlier, as a park: the trade is held, not taken. Here is the Stock Token case:

python snippets/sellability.py 0xD5f3879160bc7c32ebb4dC785F8a4F505888de68 # QQQ, a Stock Token Relay will not route
0xD5f3879160bc7c32ebb4dC785F8a4F505888de68
no usable WETH quote (Relay: UNSUPPORTED_CURRENCY).
Relay also rejects the currency for its deepest non-WETH counterpart (USDG).
neither tested pair produced a usable quote, and UNSUPPORTED_CURRENCY can also mean
the pair is temporarily unpriceable; other funding assets remain untested. common
causes: a region-restricted Stock Token (geo-gated) or a pair Relay does not support.
verify with quote.py against your intended funding asset. sellability UNKNOWN here.

QQQ is the Invesco QQQ Stock Token. Stock Tokens are region-restricted, so Relay geo-gates them and returns UNSUPPORTED_CURRENCY from every funding asset. Probing USDG returns the same rejection, and the "deepest counterpart is USDG" line is a Dexscreener ranking, not a route. The snippet fails loud: it cannot test a token Relay will not route. That does not make the token untradeable in general. Robinhood documents RFQ and AMM paths for Stock Tokens, but their availability for a given token, size, and user must be checked at the venue, outside this guide's tools.

What a pass means, and what it does not
  • It is one probe. The result holds for the probe address, at this size, against that parent block, from these logs. A token can allow that wallet to sell while blocking others.
  • Friction is reported, not gated. The exit code stays 0 whenever the sell settles, even when the snippet prints a SEVERE ROUND-TRIP FRICTION warning above 5,000 bps (a 50% loss). Set and enforce your own friction ceiling for the size you trade.
  • The 75 bps figure is a per-token round trip. It divides WETH out per token sold by WETH in per token bought, using the WETH the buy actually spent. It captures LP fees, price impact, any token tax, and any route or hook fee in the deltas. It excludes gas, and it is not a proven upper bound on the sell tax.
  • Sellable is not valuable. A rugged token that lost most of its value still passes, because a small round trip still settles. Pair a clean exit code with a value and liquidity read from mark.py and bases.py.

Mark a Position

mark.py prices a token with a live Dexscreener mark. It needs no key.

python snippets/mark.py 0x2E8c31162b855A2ffa90F6F8634643Ad6F111e18
0x2E8c31162b855A2ffa90F6F8634643Ad6F111e18
price $0.2874
liq $3,675,030
quote WETH
pair 0xc4a21f9d6485FC5893DD4A491B320a83DAF4Da1D (uniswap)
note external estimate, not an audited mark

Two traps live in this data. priceUsd is a string, so never re-round it. pairCreatedAt is milliseconds, not seconds.

The mark is an external estimate, not an audited number. Use it to value an open position, never as a settlement price. A paper fill comes instead from Relay's simulated deltas, subject to the caveats in the sellability section.

Ingest Live Signals and Gate Planted Buys

signals.py reads the public rhtrenches tape, an unofficial feed of Robinhood Chain fills. Each fill carries a free-form flags list. The tape needs no key.

The number one risk in copy-trading is a planted buy: a wash or airdrop fill staged to look like conviction. So the gate fails closed. A fill is eligible only when its flags are a well-formed list with no hard-reject keyword. Missing or malformed flags count as unknown and drop the fill, exactly like a reject. This is a filter of the tape's own labels, not authentication. It catches labels that use known keywords, and a novel wording or an unlabeled plant passes.

python snippets/signals.py
tape buys: clear=32 reject=70 unknown=0

Alert B firings (>= $10,000 eligible buys):
MOO $35,857 wallet 0x551ee842... token 0xd9db30bb0d2b8d2eae3826a1372117e058791e18

On this tape, 70 of 102 buys carried a label that matched a hard-reject keyword, so the gate dropped them. That is a keyword-match count, not a claim that the other 32 are authentic. A "clear" buy is only unflagged, so keep the downstream checks (sellability.py, size caps) in play.

The rule itself, labeled Alert B in the output, is simple. It sums eligible buy value per wallet and token and surfaces any pair that clears $10,000. That is one signal design. Yours can differ. Keep the fail-closed label filter in front of it, validate the tape, then decide. The snippet prints signals only. It places no trade.

Discover New Pools Yourself

The other snippets act on a token you already have. This one answers a different question: what just launched?

watch.py gives you a live, onchain feed of new pools, so you do not depend on a third-party tape or an indexer. It also covers the brief window right after launch, when a pool exists onchain but Relay has not indexed it yet. Mind the scope: a later pons launch starts on a bonding curve and creates its v4 pool only at graduation, so watching the PoolManager catches the graduation, not the initial launch. To catch pre-graduation launches, watch each launchpad's own factory instead.

The snippet subscribes to the Uniswap v4 PoolManager's Initialize event over a WebSocket eth_subscribe, after verifying the socket is on Robinhood Chain. The event carries both pool currencies in its indexed topics, so the snippet labels each pool by which side is a known base (WETH, USDG, or native ETH) and which side is the token. When neither side is a known base, it flags the pair, because it cannot USD-price it. Confirm Relay routing for any of them with quote.py.

A created pool is not a tradeable pool. In a 30-minute test window of live launches, about a third of new pools had zero active liquidity when screened. A ModifyLiquidity event is a poor screen: 96% of new pools got one in the same block as Initialize, yet a third still read zero active liquidity later, because the add was withdrawn, sits outside the current price range, or the price moved away from it. The signal that matters is in-range active liquidity, and one extsload call reads it directly. watch.py reads it at detect, marks each pool LIVE or EMPTY, then re-checks at the end of the window, because liquidity is often minted a block or two after Initialize. The stream needs QUICKNODE_WS. The liquidity screen needs QUICKNODE_RPC, and without it you still get the labeled discovery list.

QUICKNODE_WS=wss://... QUICKNODE_RPC=https://... python snippets/watch.py 200
watching PoolManager Initialize for 200s (read-only)...
new pool block 67695154 token 0x7510318677cF4C0E02100d76Bb201B1C17ee1E18 vs USDG fee 911000 [LIVE] pool 0x9204c33abcbeb27f9a23b50e0d62cde6f01d68cf4f8a7a3fa5f8718f0e7b2fb5
new pool block 67695400 token 0x827488976525a867A232CD3A2C5f7C046796f2c6 vs ETH fee 10000 [LIVE] pool 0x41707081ca193f13e85910f02be650f8c001cdaec5f07ee628cbea88fa1635a4
new pool block 67695511 no known base 0x2e0847E8910a9732eB3fb1bb4b70a580ADAD4FE3 / 0xf143B5E869eCaD3Bf55EB20C63Cc391b8F2d1e18 (neither side is WETH/USDG/ETH) fee 8388608 [EMPTY] pool 0x59fe824726cf24625e3958ae3f7ea797ecff427d6efb2e120620d6d3ac8016ef
new pool block 67695669 token 0x8dEcFDE3686c6aE7830800CAF4CB2b95FC4C7A7c vs ETH fee 810000 [LIVE] pool 0xc1ab995a02acce85f8cbfe1fd7f40c6a0174444971d04f0d0d8604fb5756ea19
new pool block 67695722 token 0x8dEcFDE3686c6aE7830800CAF4CB2b95FC4C7A7c vs ETH fee 808670 [LIVE] pool 0x3f91ff981f9c4c52a56e2250fcacca42b1e1b433a6333b915714cebf76778a49
... 9 more pools trimmed ...
new pool block 67696945 token 0x133E4AFA3BA9f4A4785561447FE5Bc6fa69f29E6 vs ETH fee 2500 [LIVE] pool 0x70a1ea7923cac05b61c3381a20dd560701bbbb33adbe1611168250bf404c6eb9
15 new pool(s) in 200s (provisional; a reorg can still drop one).
liquidity now: 12 LIVE, 3 EMPTY of 15 (was 11 LIVE at detect).
changed EMPTY->LIVE token 0x9b1a407fB43910e2a689c5216032ff72969D8d09 vs ETH pool 0x7cc0bdb8ef211664a2527c4a411b12d6b282b5b11509656ebdca690e60e61f64
changed EMPTY->LIVE token 0x71bDCa3BAadD7BD5c453918a87307d1CFCB74663 vs ETH pool 0xcc880d23b40ef806032802df5d4acf953cb7cd445b0187b1b1745b9c7de5746e
LIVE means liquidity is live at the tick, NOT that it is deep or exitable. The normal path is
quote.py <token> <base-address> (Relay indexes in seconds); its error codes say why it refuses
(dust prices out at size; a region-gated Stock Token does not price).
Never trade a fresh pool on sight.

Each line carries the pool's fee tier and full poolId. You need both, because a token accretes many pools that differ only by fee and tickSpacing. Here the same token (0x8dEcFDE…7A7c) shows up in two ETH pools at once, at fee 810000 and 808670. The [LIVE] or [EMPTY] tag is each pool's active liquidity at detect. The end-of-window summary re-checks, and two pools that were EMPTY at detect had been funded by then. Pool creation is permissionless, so no single pool's size is a reliable read. Confirm routability with quote.py and run the checks before you trust any of it.

From Snippets to a Bot

The snippets are the hard parts. A bot chains them and adds durability. The full pipeline looks like this:

A production build adds what the snippets skip:

  • Safeguards. Enforce a max slippage, a max position size, and a price-impact ceiling. Reject an over-cap signal. Do not clamp it.
  • A paper ledger. Record each simulated fill and book realized P&L from the simulated deltas. Value 1 USDG at 1 dollar as a stated assumption, and track USDG depeg as a disclosed risk.
  • Idempotency. Give each order a client order ID and reject duplicates. A retry must never double-book.
  • Durability. Persist a cursor for the tape and the pool watch. Dedup events by chain, block, and log index. Replay across a restart.
  • Robustness. Add timeouts, retries with backoff, and response size caps. Fail closed on any parse error.
  • Per-token funding. Resolve a real storage layout per token so the sellability simulation can fund non-WETH routes. Funding is separate from routing: a storage override only helps for a pair Relay actually routes. A Stock Token that Relay refuses has no Relay route to simulate at any funding, so it needs a supported non-Relay execution path.
  • Canonical-pool selection. A token has many pools: decoys, dead pools, and the real launch pool. Selecting the wrong one gives a misleading sellability result. Enumerate every pool the token appears in, drop the decoys (extractive static fee, dead price, unpriceable base), rank the survivors, and cross-check the price against a consensus of the deep pools.
  • Checks beyond sellability. Sellability is not the only rug vector. Three cheap read-only RPC checks cover the rest:
    • owner() via eth_call (selector 0x8da5cb5b): renounced (0x0) versus a live owner.
    • Proxy detection via eth_getCode for the EIP-1167 minimal-proxy prefix, and eth_getStorageAt for the EIP-1967 implementation slot.
    • The fee schedule. A high early fee can be a timed anti-snipe decay, not a permanent tax, so read the schedule before you blacklist.

Keep the fail-closed rule everywhere. An unknown verdict parks the trade. It never guesses. Gate on the exit status of sellability.py, not just its output:

Exit codeMeaningWhat to do
0Proven round trip for the probePass it to your friction ceiling. A punitive-tax token still exits 0.
7Sellability unproven or out of scopePark. Do not trade.
1Infrastructure, usage, or unclassified Relay failureRead the printed reason. A size error suggests a different size, a transient pricing or not-yet-indexed failure suggests a later retry.

Treat anything nonzero as do-not-trade.

Going Live: What a Real Implementation Needs

This guide stops at read-only paper. A live build signs and broadcasts, which is a different risk class. Do not bolt it on casually.

  • Key management is the hard requirement. Never keep a plaintext key on disk. Python cannot reliably zeroize or mlock a decrypted key, because its bytes are immutable and garbage-collected, so the raw key can linger in memory. Use a hardware signer, a remote signer, or a Rust or Go signing core.
  • Simulate against real state. A live pre-sign simulation must run against actual balances and allowances. The paper overrides in sellability.py are for paper only. An override must never hide a missing approval or missing funds.
  • Verify every route address. Pin the Relay swap target and the approval spender, and re-verify them against Relay's docs. A rotated contract is an unverified contract.
  • Treat a signature step as fund movement. A Permit2, EIP-2612, or EIP-3009 permit, a signed order, or an ownership auth can authorize a transfer with no broadcast. Identify what it authorizes and validate its nested effects before you sign.
  • Own your compliance. Stock Tokens are debt securities with jurisdictional limits. You are responsible for local rules.

Conclusion

These six primitives turn a Robinhood Chain trade from a hopeful click into a checked sequence: discover the counterpart assets, inspect Relay's route, prove a round trip for a probe address and size, mark the position, filter the signals you copy, and watch new pools as they launch. Every check is read-only, so the whole path runs against live mainnet without risking funds. Treat a clean result as necessary, not sufficient. Pair the sellability exit code with a friction ceiling and a value read before you trust any token, and read the Going Live section before you sign anything.

Next Steps


Frequently Asked Questions

What is Robinhood Chain?

Robinhood Chain is an Arbitrum Orbit EVM Layer 2. It has one sequencer, no public mempool, and a block time near 0.1 seconds. It hosts Stock Tokens alongside launchpad tokens that trade mostly through Uniswap v4 pools.

What is Robinhood Chain's chain ID?

Robinhood Chain uses chainId 4663 (hex 0x1237). Verify any endpoint with a single eth_chainId call before trusting it, because the same contract addresses on other chains are unrelated.

How do you prove a token is sellable, not just buyable, on Robinhood Chain?

Simulate the buy with eth_simulateV1, measure the tokens acquired from the Transfer logs, then reverse-quote a small haircut and simulate buy-then-sell against the same pinned block. A reverted sell leaves sellability unproven, and the reported round-trip friction exposes punitive losses even when the sell settles. The result holds for the probe address and size in a simulated context.

Why won't Relay route Robinhood Chain Stock Tokens?

Stock Tokens are region-restricted debt securities that are not available to US persons, so Relay geo-gates them and returns UNSUPPORTED_CURRENCY from every funding asset. They trade through RFQ aggregators and AMMs from a permitted jurisdiction, outside this guide's Relay-based tools.

Do these snippets sign or broadcast transactions?

No. All six snippets are read-only. They read live mainnet and simulate, but never sign, broadcast, or move funds. The Going Live section covers what a real signing build must add, starting with key management.

What do you need to run the snippets?

Python 3.11 or newer plus the installed dependencies. sellability.py needs a Quicknode HTTP endpoint that serves eth_simulateV1, and watch.py needs the WSS endpoint plus HTTP for the liquidity screen. mark.py and signals.py need no endpoint, and bases.py and quote.py use one only for optional onchain checks.

Resources