Docs · Robinhood Chain · chain id 4663
Goo Exchange
A permissionless concentrated-liquidity DEX on Robinhood Chain. Every pool is a Uniswap V3 pool: the same maths, storage, interface, events and swap callback. Anyone can open a pool for any pair. The main pool is GOO/WETH, and GOO/stock pools pair GOO with Robinhood's tokenized stocks.
For an aggregator, a Goo Exchange pool behaves like any Uniswap V3 pool with one difference: pools are
deployed by a separate pool deployer contract, so an address computed with CREATE2 must use
the pool deployer and our init code hash, not the factory. Everything else, including discovery from the
factory's PoolCreated logs, works unchanged.
Quick reference
- DEX type
- Uniswap V3 fork (v3-core and v3-periphery)
- Chain
- Robinhood Chain, id 4663
- Factory
- 0x221A6239E40709792b0d4bdc140fA36158CD41C7
- Factory deploy block
- 73266708 start log scans here
- Pool deployer
- 0x9eF8bfae948B012EDD9e902Beb0d55F475631396
- Pool init code hash
- 0x361074a657704920539a5187a0873cfbb0bf83771a463c46c98e615554bf9264
- Swap callback
uniswapV3SwapCallback(int256,int256,bytes)- Fee tiers
- 0.05%, 0.25%, 0.3%, 0.9%, 1%, 10%, 20% (tick spacings)
- Main pool
- GOO/WETH 1%: 0x841f00216A273641eD583916e668e24b4A89d1e7
- Launchpad
- 0xb4883BD311F837Fb68086a0e41C9B7917feb631e (details)
- Public RPC
- https://rpc.mainnet.chain.robinhood.com
- Source
- Verified on Sourcify for every listed contract and the main pool
- Explorer
- robinhoodchain.blockscout.com
Contracts
Deployed on Robinhood Chain (4663) on 26 September 2026, factory block 73266708, the launchpad on 30 September and the shielded pools on 23 October. Every contract below, the main pool included, has its source verified on Sourcify: repo.sourcify.dev/4663/<address>.
| Contract | Address |
|---|---|
| GOO (Grey Goo)ERC-20, 18 decimals | 0x6572EADe9Fb17F4027baF92FEAC222B9AA746bd0 |
| WETHRobinhood Chain's wrapped ETH | 0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73 |
| GOO/WETH 1% poolmain pool | 0x841f00216A273641eD583916e668e24b4A89d1e7 |
| V3 factoryemits PoolCreated, FeeAmountEnabled | 0x221A6239E40709792b0d4bdc140fA36158CD41C7 |
| Pool deployerCREATE2 parent of every pool | 0x9eF8bfae948B012EDD9e902Beb0d55F475631396 |
| SwapRouterv3-periphery | 0x16E5Ec75431AccB65bFcC7aEfFC1d2aeB44069b0 |
| QuoterV2v3-periphery | 0xc50FFD91B3876bB28557fCd419Bf7405f68a11Eb |
| TickLenspopulated ticks per word | 0xB65FCbb1C7964B5Ddd1EF528818Ded9A19EBf959 |
| NonfungiblePositionManagerv3-periphery, LP positions | 0xdc504c2DE9C26846AfdAC56385673B039c2e27cb |
| Goo routermulti-hop, ETH in and out; used by the app. v2: the arbitrage a swap opens on its last pool is taken in the same transaction, for the protocol (the POL vault) | 0x63A51222Ab5800d920511af60e09967e73d9E42D |
| FactoryControllerowns the factory; collects protocol fees | 0x189e56e559d0d08F9d582637eFc94f2b1dee5419 |
| FeeJarauctions protocol fees for GOO and burns it | 0xb82028EBb8254E0Cc349A6D1B633FfD6908f52B1 |
| GooLaunchpadlaunches tokens paired with GOO; deployed 30 September 2026 | 0xb4883BD311F837Fb68086a0e41C9B7917feb631e |
| Shielded EntrypointPrivacy Pools v1.2.1 (proxy); deposits, relays and the approved list; deployed 23 October 2026 | 0xdB5F75533C6c8e9a97661264B76D588A01255B50 |
| Shielded ETH poolPrivacyPoolSimple | 0x759B1cDd26466c1907F200e32ED934A856F6c190 |
| Shielded GOO poolPrivacyPoolComplex | 0x76003F90E92ed9b9810d03f580cC9EfEF9Aee96c |
| GooSwapAdapterprivate GOO buys from the shielded ETH pool | 0x1B83A15697B89da21a58a3317d8ac30a66935c9f |
| Multicall3canonical | 0xcA11bde05977b3631167028862bE2a173976CA11 |
Pools and addresses
Pool maths, storage and swap callbacks follow Uniswap V3. The fork also applies the factory's configured
protocol-fee default during initialization. Pools are CREATE2 children of the
pool deployer (factory.poolDeployer()), not of the factory, so the address is:
pool = address(keccak256(0xff ++ poolDeployer ++ keccak256(abi.encode(token0, token1, fee)) ++ initCodeHash))[12:]
poolDeployer = 0x9eF8bfae948B012EDD9e902Beb0d55F475631396
initCodeHash = 0x361074a657704920539a5187a0873cfbb0bf83771a463c46c98e615554bf9264
Check your implementation against the main pool:
token0 = 0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73 // WETH
token1 = 0x6572EADe9Fb17F4027baF92FEAC222B9AA746bd0 // GOO
fee = 10000 // 1%
pool = 0x841f00216A273641eD583916e668e24b4A89d1e7
factory.getPool(tokenA, tokenB, fee)returns the same address, in either token order.pool.factory()returns the factory, as upstream.-
Discovery: scan the factory's
PoolCreated(token0, token1, fee, tickSpacing, pool)logs from block 73266708. The pool address comes from the event, so log-based discovery needs no init code hash.
Fee tiers
| Fee | fee (uint24) | Tick spacing |
|---|---|---|
| 0.05% | 500 | 10 |
| 0.25% non-standard | 2500 | 50 |
| 0.3% | 3000 | 60 |
| 0.9% non-standard | 9000 | 180 |
| 1% | 10000 | 200 |
| 10% non-standard | 100000 | 1000 |
| 20% non-standard | 200000 | 2000 |
Four tiers are not Uniswap's standard ones, so a hard-coded 500/3000/10000 list misses pools. The factory's
FeeAmountEnabled(fee, tickSpacing) events are the source of truth; any tier added later
emits one, after three days' public notice in the FactoryController.
Routing and execution
-
Swaps. Call
pool.swap(recipient, zeroForOne, amountSpecified, sqrtPriceLimitX96, data)directly; the pool callsuniswapV3SwapCallbackon the caller, exactly as upstream. -
Callback checks. If your executor authenticates the callback by recomputing the pool
address, compute it from the pool deployer and the init code hash above. Computing it
from the factory gives the wrong address and the check fails. Checking
factory.getPool(token0, token1, fee) == msg.senderalso works. -
Quotes. QuoterV2 (
quoteExactInputSingle,quoteExactInputand the exact-output variants) quotes against our pools. -
Tick data. There is no subgraph. Read populated ticks with
TickLens.getPopulatedTicksInWord(pool, wordIndex), and pool state withslot0()andliquidity(), batched through Multicall3. - Simulation. Pool maths are upstream's: a Uniswap V3 simulator gives exact outputs. The protocol fee changes nothing in swap amounts (see Fees).
- Tokens. Pools are permissionless and can hold any ERC-20. GOO itself has no transfer fee and no rebase.
Fees
- Swap fee. The pool's fee tier, paid by the trader, as in Uniswap V3.
- Protocol fee. At the source block 78146108, factory default denominators were 4/4, and the main pool's were 4/4. A denominator of 4 means one quarter of the swap fee; 0 disables it. New pools receive the configured default from initialization. Existing pools may have different settings: inspect the selected pool. Fee policy and source methods. It comes out of the liquidity providers' share, so swap output is identical to an upstream pool with the same fee tier.
- Where protocol fees go. Anyone can collect them through the FactoryController, to two fixed recipients: half to the FeeJar, which auctions it for GOO and burns the GOO, and half to the dev fund.
- Changes. Changing a protocol fee, adding a fee tier or transferring the factory takes three days' public notice in the FactoryController.
The GOO token
- Name, symbol
- Grey Goo, GOO
- Address
- 0x6572EADe9Fb17F4027baF92FEAC222B9AA746bd0
- Decimals
- 18
- Original mint
- 1,000,000,000 GOO, minted once at deployment.
- Total supply at block 78146108
- 999,514,518.429808 GOO
- Retired relative to original mint
- 485,481.570191 GOO, across all burns rather than FeeJar-only burns.
- Behaviour
- A plain ERC-20: no owner, no minting, no rebase, no transfer fee, no blacklist. Transfers move exact amounts.
Onchain snapshot: , Robinhood Chain block 78146108. This is an observation at that block, not a continuously updated quote. Read current protocol facts.
Launchpad
The GooLaunchpad launches tokens paired with GOO, in one transaction. A launch pool is an ordinary 1% pool of
the factory above: it appears in PoolCreated, trades through the same swap callback and needs no
separate integration. Route it through GOO, for example ETH → WETH/GOO → GOO/token.
- Contract
- 0xb4883BD311F837Fb68086a0e41C9B7917feb631e
- Deploy block
- 76415695 scan
Launchedlogs from here - Launchpad owner
- None. No launchpad admin can change its LP-fee splits, move liquidity or pause launches. The factory controller can change a pool's protocol-fee share through its notice process.
- Source
- Verified on Sourcify (exact match), with
LaunchToken's source included - Pair and tier
- GOO, 1% (
fee10000, tick spacing 200) - Launch price
- tick -50000: 1.0001-50000 ≈ 0.006738 GOO per token, in either token order
What a launch creates
-
A token. A
LaunchToken: a plain ERC-20 with 18 decimals and a fixed supply of 1,000,000,000, deployed by CREATE2 from the launchpad with saltkeccak256(abi.encode(caller, salt)). No owner, no minting, no tax, no rebase, no transfer restrictions. Holders can burn their own tokens, sototalSupplyonly falls. - A pool. The token/GOO pool at 1%, started at the launch price.
- The whole supply as liquidity. Ten token-only positions whose lower edges step up 4,600 ticks at a time from the launch price, each running to the tier's top tick. The launchpad holds them for good: nothing can withdraw, decrease, transfer or approve them away.
- An optional first buy. The creator can buy with GOO in the launch transaction, before anyone else can trade.
Fees
Traders pay the pool's 1%. With protocol denominator 4, the protocol fee is a quarter of it (see Fees). The rest is the launch positions' LP fee, which the launchpad collects and splits:
| LP fee paid in | Split |
|---|---|
| GOO (buys) | 33.33% to the launch's fee recipient, 33.33% placed as a GOO-only bid, 33.34% burned |
| The launch token (sells) | Burned |
- Bids. Each bid is a GOO-only position 1,000 ticks wide at the highest level wholly under the current price, on a grid counted from the launch price and never below it. Bids stay in the pool for good. When no level can be reached yet, or after 32 levels, that share is burned instead.
-
Collection. Anyone can call
collect(token), orcollectMany(tokens, gasEach)for several. The protocol's keeper collects every launch that has earned fees about every 30 seconds. -
Fee recipient. The creator unless they name another address at launch. Only the current
recipient can hand it on, with
setFeeRecipient(token, recipient).
Interface
struct LaunchParams {
string name; // at most 128 bytes
string symbol; // at most 32 bytes
string metadata; // at most 2,048 bytes: ipfs://<cid> of the metadata JSON
bytes32 salt; // CREATE2 salt, hashed with the caller
address feeRecipient; // zero means the caller
uint256 creatorBuy; // GOO to buy with in the same transaction (approve the launchpad first); 0 for none
uint256 minTokensOut; // slippage limit for that buy
}
function launch(LaunchParams params) returns (address token, address pool)
function collect(address token) returns (uint256 gooBurned, uint256 gooToCreator, uint256 gooToDeepen, uint256 tokenBurned)
function collectMany(address[] tokens, uint256 gasEach)
function setFeeRecipient(address token, address feeRecipient)
function launchOf(address token) view returns (address pool, address feeRecipient, bool tokenIsToken0,
uint256[] positionIds, uint256 bandCount, uint256 pendingDeepen)
event Launched(address indexed token, address indexed pool, address indexed creator, address feeRecipient,
string name, string symbol, string metadata, uint256 creatorBuy, uint256 tokensBought)
event Collected(address indexed token, uint256 gooBurned, uint256 gooToCreator, uint256 gooToDeepen, uint256 tokenBurned)
event Deepened(address indexed token, uint256 indexed positionId, int24 tickLower, int24 tickUpper, uint256 goo)
event DeepenBurned(address indexed token, uint256 goo)
event DeepenFailed(address indexed token, int24 tickLower, int24 tickUpper)
event CollectionSkipped(address indexed token)
event FeeRecipientSet(address indexed token, address indexed feeRecipient)
Metadata. Launches made on goo.exchange point metadata at a JSON file on IPFS:
{"name", "symbol", "image": "ipfs://<cid>", "description"?, "twitter"?, "telegram"?, "website"?}.
The contract only emits the string; treat it as untrusted, since anyone can launch directly.
Vaults
A vault holds two tokens as liquidity in a pool of its own. Only the protocol's arbitrage executor can trade that pool. When the two tokens' prices move on other venues, the executor trades the vault's pool back toward the market and keeps the difference as profit. The pool charges no swap fee, so that profit is what a vault earns.
- Vault factory
- 0xB4FE65D4A7Fa5Fe40A58e78eF3B5eE34a0059643
- Zapper
- 0x55D6BC4493Af9d5a89006829708dBA3Efc38cE7b verified on Sourcify (exact match)
- Executor
- 0x054Ce461b727508dec1b7edDbA3D8bC2aB3F1646 trades the vaults' pools, since 7 November 2026 (before: 0xAd1A457fEC264d1a46D985d891C2dE23F2F6d868)
- Shares
- An ERC-20 token at the vault's own address: gooVAULT, 18 decimals
- Fees
- None to deposit or withdraw. A zap pays its swaps' route costs and price impact.
- Lock-up
- None. Withdraw any time.
- Cap
- Each vault caps its shares. Vaults launch capped at about $100k at their launch prices, and the protocol can raise or lower a cap. A cap only stops new deposits, never withdrawals.
Each trade's profit
The executor pays every trade's profit through the vault's own splitter, on chain:
| Share of each trade's profit | Goes to |
|---|---|
| 75% | The vault: added back to its liquidity, so it compounds for every holder |
| 25% | The protocol: half to the FeeJar, which auctions it for GOO and burns the GOO, and half to the dev fund |
Depositing
- Both tokens, in the vault's proportion. You set the most of each token you'll put in. The vault takes both in the proportion it already holds them and mints shares for your part. Whatever it doesn't need stays in your wallet.
- Zap in. Deposit with ETH or a single token: the zapper buys the vault's two tokens through KyberSwap and deposits them in one transaction. Your minimum shares and a deadline protect the zap, and anything left over comes back to you.
- Price band. A deposit can name the range the vault's pool price must be in, and reverts outside it. The app sets it from market prices.
Withdrawing
- Any time. Burning shares pays your part of everything the vault holds, in both tokens: its liquidity, profit not yet added back and any idle tokens.
- Zap out. Withdraw and sell both tokens into one, or into ETH, in one transaction, with a minimum out you set.
-
Paused or frozen tokens. A tokenized stock's issuer can pause it or freeze an address. If
one token can't be paid out, the vault records it as yours to collect later with
claim, and pays the other token as normal.
When a vault is off the market
Between the executor's trades, a vault's price can sit away from the market. The app shows how far. Deposits and withdrawals still work: they go in and out at the vault's own price and proportion. When the executor trades the vault back, the profit goes to the vault, so it counts for every holder, including new deposits.
Range and re-centring
Each vault keeps its liquidity in a range around the price, set when the protocol launches it: a base position around the price and a limit order with what the base can't hold. If the price nears the edge of that range, the vault can be re-centred around the price, without swapping anything. Anyone can trigger a re-centre once it's due. The price source a vault re-centres by can only be replaced with two days' public notice.
Risks
- You hold both tokens. As prices move, the vault sells the token that rises and buys the one that falls, so after a large move you hold more of the weaker token. In a strong move one way you can end with less than if you had simply held the two tokens, and the vault's share of trading profit may not make up for it.
- Small tokens can fall fast. A vault with a low-cap token carries that token's full risk, including losing most of its value.
- Tokenized stocks can be paused or frozen by their issuer (see Withdrawing).
- Price at deposit. Only the executor can move a vault pool's price. Deposit with a price band, as the app does, so a deposit only goes in near the market price.
- Smart contracts. The vaults are new contracts. Only put in what you can afford to lose.
Live vaults
Shielded
Shielded pools let you hold ETH or GOO with no on-chain link to the wallet you deposited from, then send it to any address or buy GOO into a fresh wallet. They are 0xbow's Privacy Pools v1.2.1, unmodified, plus one adapter of our own for private GOO buys. In the app: the Shielded switch on the Trade page, or goo.exchange/shielded.
- Entrypoint
- 0xdB5F75533C6c8e9a97661264B76D588A01255B50
- ETH pool
- 0x759B1cDd26466c1907F200e32ED934A856F6c190
- GOO pool
- 0x76003F90E92ed9b9810d03f580cC9EfEF9Aee96c
- Private-buy adapter
- 0x1B83A15697B89da21a58a3317d8ac30a66935c9f
- Minimum deposit
- 0.01 ETH, or 10,000 GOO
- Deposit fee
- 0.3%, taken when you deposit. All of it goes to the FeeJar, which burns GOO.
- Send and buy fee
- Network gas at cost, paid from the amount, to the relayer that submits the transaction (for a GOO send, to the FeeJar)
- Source
- Byte-identical to 0xbow's deployment on Arbitrum. Audited by Oxorio (circuits, contracts, Entrypoint upgrade) and Auditware (contracts). Verified on Sourcify.
How it works
- Shield. Deposit ETH or GOO from your wallet. Your shielded keys come from one signature: a Sign-In with Ethereum message for goo.exchange. The same wallet recovers them on any device, so nothing is stored. A wallet that can't sign the same way twice gets a 12-word recovery phrase instead.
- Approval. The approved-deposit list updates at the top of every hour. Once your deposit is on it, you can send or buy privately.
- Send or buy. Your browser makes a zero-knowledge proof that you own an approved deposit, without revealing which one. The relayer submits it, so the receiving wallet needs no gas and has no link to yours. A private buy withdraws ETH, swaps it for GOO in the GOO/WETH pool and sends the GOO, all in one transaction. It reverts as a whole, leaving your deposit untouched, if the price is below your minimum or the pool can't fill the whole amount.
The approved list
Deposits from addresses on a published list of exploit and incident addresses are left off the approved list.
It matches exact addresses only; nothing is traced. A listed deposit can't be withdrawn privately, but it can
always take the public refund. Every list is published under its content hash, which the Entrypoint stores
next to the root. The current one is at /shielded-api/asp/latest.json.
Public refund
Any deposit can go back to the wallet that made it, at any time, approved or not. Only that wallet can do it. The refund shows which deposit it was, so it gives up privacy for that deposit.
Staying private
- Wait. Time between shielding and sending puts more deposits between you and the recipient.
- Avoid unique amounts. Sending exactly what you deposited makes the two easy to match.
- Use a fresh wallet to receive, one with no history tying it to you.
- Refunds link. A public refund of what's left after a private send shows which deposit that send came from.
Risks
- Your signature is your key. Anyone who gets your unlock signature can spend your shielded balance. Only sign it on goo.exchange; wallets that check Sign-In with Ethereum warn when another site asks. Keep your recovery phrase if you were given one.
- The relayer. Private sends and buys go through the protocol's relayer. It can't change the recipient, the amounts or its fee, but if it's down, private withdrawals wait. The public refund always works.
- Upgrades. The Entrypoint is upgradeable by the protocol's Safe, with no delay.
- Smart contracts. The adapter is a new contract, unlike the audited pools. Only put in what you can afford to lose.
For integrators
The pools use 0xbow's Privacy Pools v1 ABI and events (Deposited, Withdrawn,
Ragequit), so the 0xbow SDK works with the addresses above. Scan from deploy block
95909649.
Public API
Read-only HTTP endpoints on https://goo.exchange: GET only, JSON, no key or
sign-up, and open to every origin (CORS *). Token amounts are decimal strings in whole tokens;
fields ending in Raw are integer base units.
GOO supply
| Endpoint | Returns |
|---|---|
| GET /api/supply/ | Circulating supply as {"result": "<GOO>"}. Nothing is locked or vesting, so every unburned GOO is circulating: this equals the total. Also at /supply/circulating. |
| GET /api/supply/ | Total supply as {"result": "<GOO>"}: GOO's ERC-20 totalSupply, which falls with every burn. Also at /supply/total. |
| GET /api/supply/ | Max supply as {"result": "<GOO>"}: the original 1,000,000,000 mint. GOO has no mint function, so this never grows. |
| GET /api/supply | Everything at once: max, total, circulating, burned, and the block the figures were read at. Also at /supply. |
$ curl https://goo.exchange/api/supply/circulating
{"result":"998730242.73551663718998283"}
Read from the GOO contract at the latest block and cached for up to 10 minutes. When the chain cannot be
read the answer is 503, never a guessed figure.
Chain data
| Endpoint | Returns |
|---|---|
| GET /api/public-data? | GOO's identity and supply, the main pool's state, the fee tiers and the protocol settings, all at one block. |
| GET /api/public-data? | Every Goo Exchange pool for a pair: address, fee, tick spacing, price, tick and active liquidity. |
| GET /api/public-data? | An exact-input quote over the native route (ETH or a token address on either side); no external aggregators. |
| GET /api/public-data? | The verified Robinhood stock-token registry. Optional search, cursor and limit (1–100). |
Markets
Goo Exchange is a Uniswap V3 fork: every swap is a standard Swap event on its pool. Prices,
volume and liquidity for every pool are indexed by
GeckoTerminal.
Machine-readable
-
/docs/integration.json: the integration kit, generated from
the chain: factory, pool deployer, init code hash, deploy block, fee tiers and periphery. Its
tokens.gigais GOO. - /robinhood/deployment.json: every contract address the app uses, including
launchpadand itslaunchpadBlock.