# LONGFOLIO — bot & API integration **Network:** Robinhood Chain, chainId `4663`. Public RPC: `https://rpc.mainnet.chain.robinhood.com`. ## Addresses | Contract | Address | |---|---| | LONGFOLIO (the coin, 18 decimals) | `0x9A64C06795b254C8aA70086E9FDC0FBE136F0110` | | Zap / hook (buy & sell entry point) | `0x04D9d2cdacDf8E95484eC787E40479B109Bb6888` | | L8NG basket token | `0xE607Ce5825517c0581fb22CB635578b28c2A62b2` | | Uniswap V4 PoolManager | `0x8366a39CC670B4001A1121B8F6A443A643e40951` | | Universal Router | `0x8876789976decbfcbbbe364623c63652db8c0904` | | Permit2 | `0x000000000022D473030F116dDEE9F6B43aC78BA3` | | V4 Quoter | `0x8dc178efb8111bb0973dd9d722ebeff267c98f94` | ## The pool (Uniswap V4, custom curve via hook) ``` PoolKey { currency0: 0x0000000000000000000000000000000000000000 // native ETH currency1: 0x9A64C06795b254C8aA70086E9FDC0FBE136F0110 // LONGFOLIO fee: 0 tickSpacing: 1 hooks: 0x04D9d2cdacDf8E95484eC787E40479B109Bb6888 } poolId = 0xd2adda941c977b675e4a60bba17e84e45ccd110913e1ec206a46da2c1895314d ``` The pool holds **no liquidity of its own**. The hook does the whole trade inside `beforeSwap`: ETH → the 8 basket tokens → mints L8NG → swaps L8NG for LONGFOLIO on the Long pool, and hands the coin back through the PoolManager. Consequences for integrators: - `slot0` and `getLiquidity` are meaningless (price fixed at 1.0, liquidity 0). **Use the Quoter for price.** - The PoolManager `Swap` event for this pool always shows `amount0 = amount1 = 0`. **Use the zap events for trades and volume** (below). - **Exact input only.** Exact-output swaps revert. - A swap costs **5.0–6.0M gas** (8 underlying swaps + mint). Set the gas limit from `eth_estimateGas` or the Quoter's `gasEstimate` × 1.2. A 1M gas limit reverts. - Aggregators (Relay etc.) do not route this pool. Call the PoolManager / Universal Router directly with the PoolKey above. ## Quote `V4Quoter.quoteExactInputSingle((PoolKey, bool zeroForOne, uint128 exactAmount, bytes hookData))` → `(uint256 amountOut, uint256 gasEstimate)`. Selector `0xaa9d21cb`. Buy: `zeroForOne = true`, `exactAmount` = wei of ETH, `hookData = 0x`. Sell: `zeroForOne = false`, `exactAmount` = LONGFOLIO wei. Call it with `eth_call` (it is not declared `view`, but it returns normally). ## Buy with ETH — Universal Router (`execute(bytes commands, bytes[] inputs, uint256 deadline)`, selector `0x3593564c`, send the ETH as `value`) ``` commands = 0x10 // V4_SWAP actions = [0x06, 0x0c, 0x0e] // SWAP_EXACT_IN_SINGLE, SETTLE_ALL, TAKE params[0] (SWAP_EXACT_IN_SINGLE) = abi.encode((PoolKey, true, uint128 amountIn, uint128 minOut, bytes "")) params[1] (SETTLE_ALL) = abi.encode(address(0), uint256 amountIn) params[2] (TAKE) = abi.encode(LONGFOLIO, address recipient, uint256 0) // 0 = take the full credit inputs[0] = abi.encode(actions, params) ``` viem example: ```js const KEY = { currency0: "0x0000000000000000000000000000000000000000", currency1: "0x9A64C06795b254C8aA70086E9FDC0FBE136F0110", fee: 0, tickSpacing: 1, hooks: "0x04D9d2cdacDf8E95484eC787E40479B109Bb6888" }; const KEY_T = { type: "tuple", components: [{name:"currency0",type:"address"},{name:"currency1",type:"address"},{name:"fee",type:"uint24"},{name:"tickSpacing",type:"int24"},{name:"hooks",type:"address"}] }; const swap = encodeAbiParameters([{ type: "tuple", components: [KEY_T, {type:"bool"},{type:"uint128"},{type:"uint128"},{type:"bytes"}] }], [[KEY, true, amountIn, minOut, "0x"]]); const settle = encodeAbiParameters([{type:"address"},{type:"uint256"}], ["0x0000000000000000000000000000000000000000", amountIn]); const take = encodeAbiParameters([{type:"address"},{type:"address"},{type:"uint256"}], [KEY.currency1, recipient, 0n]); const input = encodeAbiParameters([{type:"bytes"},{type:"bytes[]"}], ["0x060c0e", [swap, settle, take]]); await router.write.execute(["0x10", [input], deadline], { value: amountIn, gas: 6_000_000n }); ``` Direct PoolManager integration: `unlock` → `swap(key, {zeroForOne: true, amountSpecified: -int256(amountIn), sqrtPriceLimitX96: 4295128740}, "")` → `settle` the ETH, `take` the coin. Sell: `zeroForOne = false`, limit `1461446703485210103287273052203988822378723970341`. ## Sell — two options 1. **Universal Router**, same structure with `zeroForOne = false`, `SETTLE_ALL(LONGFOLIO, amountIn)` and `TAKE(address(0), recipient, 0)`. Needs `LONGFOLIO.approve(Permit2, max)` and `Permit2.approve(LONGFOLIO, UniversalRouter, amount, expiration)` (selector `0x299ec9ee`). 2. **Zap directly:** `sell(uint256 coinIn, uint256 minEthOut, uint256 deadline)` (selector `0xd3c9727c`) after `LONGFOLIO.approve(zap, amount)`. ETH is sent to the caller. ## Simplest buy path (no router): the zap `buy(uint256 minCoinOut, uint256 deadline)` payable, selector `0xd6febde8`, on `0x04D9d2cdacDf8E95484eC787E40479B109Bb6888`. Send ETH as value; the coin goes to `msg.sender`. Gas ≈ 5M. ## Price, trades and volume - **Price:** Quoter (above). `1 L8NG` in ETH = sum of `spotSplit()` (selector `0x80d84b0d`, `uint256[]` wei per 1e18 L8NG) on the zap; LONGFOLIO priced in L8NG lives on the Long pool below. - **Trades:** index these events on the zap `0x04D9…6888`: | Event | topic0 | |---|---| | `HookBought(address indexed router, uint256 ethIn, uint256 basketMinted, uint256 coinOut)` — buys through the PoolManager / any router | `0x18da56f4ab10a2ade66d651ee18224cfa82d3581722faa4e401270e41ac3a66f` | | `HookSold(address indexed router, uint256 coinIn, uint256 basketOut, uint256 ethOut)` | `0xb315275ffd13ef67d85701c2113ee48e84997f7f67c8f91ab5d38435c2c731de` | | `Bought(address indexed user, uint256 ethIn, uint256 basketMinted, uint256 coinOut, uint256[] refunded)` — `zap.buy` | `0x41c6893c9c9b0ea553f4bc3bd6586a0adfe88ac8a5301b1d7cef460799197f6d` | | `Sold(address indexed user, uint256 coinIn, uint256 basketOut, uint256 ethOut)` — `zap.sell` | `0xe029f26dbcf8c42dd2f352c10214a7fc26773dc62482c6241334a0402ac09a80` | - **Long pool (LONGFOLIO / L8NG)**, real V4 `Swap` events with real amounts, price in L8NG: `PoolKey(LONGFOLIO, L8NG, 0x800000, 8, 0x4e3468951D49f2EEa976eD0D6e75fFCb44a9a544)` (currencies sorted by address). LP fee 2.1%. ## Reverts you may see | Selector | Meaning | What to do | |---|---|---| | `0x90bfb865` `WrappedError(...)` | the hook reverted; the inner selector is inside | decode the inner reason | | `0x590f58a9` `PartialFill(member, hop, consumed, wanted)` | one basket leg's pool could not absorb the leg | retry with a smaller amount | | `0x2746152a` `Slippage(got, min)` | `minOut` not met | re-quote | | `0x203d82d8` `Expired()` | deadline passed | new deadline | | out of gas at ~1M | gas limit too low | 6M gas limit | Notes: buys through a router may return small amounts of basket member tokens to `tx.origin` (leftovers above 0.5% of a leg are refunded to the buyer). Every trade pays the 2.1% pool fee plus the basket routes (≈1.8%); there is no anti-snipe fee anymore.