TideFiAggregatorHook
RobinhoodTideFiAggregatorHook is a Uniswap v4 hook on Robinhood Chain. Runs code on every swap. Can take tokens from swaps. Gates who can add liquidity. Runs at pool creation.
- Contract name
- TideFiAggregatorHook
How this hook works
Trading taxA trading tax hook. It takes a cut of every trade, stops liquidity being added directly and only lets approved callers create pools.
Takes a cut of every trade
On top of the normal pool fee, it keeps a share of each trade.
The code that does this (beforeSwap):function beforeSwap(address sender, PoolKey calldata key, IPoolManager.SwapParams calldata params, bytes calldata) external onlyPoolManager returns (bytes4, BeforeSwapDelta, uint24) { if (params.amountSpecified >= 0) revert TideFiAggregatorHookExactOutputNotSupported(); // forge-lint: disable-next-item(unsafe-typecast) uint256 amountIn = uint256(-params.amountSpecified); (Currency currencyIn, Currency currencyOut) = params.zeroForOne ? (key.currency0, key.currency1) : (key.currency1, key.currency0); poolManager.take(currencyIn, address(this), amountIn); poolManager.sync(currencyOut); (uint256 amountFilled,) = tidefi.swap( Currency.unwrap(currencyIn), Currency.unwrap(currencyOut), amountIn, 0, type(uint256).max, address(poolManager) ); if (amountFilled != amountIn) revert TideFiAggregatorHookPartialFill(amountIn, amountFilled); // The output is what actually landed in the PoolManager, not TideFi's return value. uint256 amountOut = poolManager.settle(); PoolId poolId = key.toId(); (uint24 protocolFee, uint256 protocolFeeAmount) = _takeProtocolFee(poolId, params.zeroForOne, currencyOut, amountOut); int128 specifiedDelta = amountIn.toInt128(); int128 unspecifiedDelta = -(amountOut - protocolFeeAmount).toInt128(); // …Liquidity can’t be added directly
Nobody can add liquidity to its pools through Uniswap directly. Liquidity only comes in through the hook’s own code.
Only approved callers create pools
New pools with this hook can only be created by approved callers, for example its own factory or launcher.
The code that does this (beforeInitialize):function beforeInitialize(address sender, PoolKey calldata key, uint160) external onlyPoolManager returns (bytes4) { if (sender != tidefi.owner()) revert TideFiAggregatorHookOnlyTideFiOwner(); // Currencies are sorted, so native ETH can only be currency0. if (Currency.unwrap(key.currency0) == address(0)) revert TideFiAggregatorHookNativeCurrencyNotSupported(); if (key.fee != POOL_FEE || key.tickSpacing != POOL_TICK_SPACING) { revert TideFiAggregatorHookPoolKeyNotCanonical(); } IERC20(Currency.unwrap(key.currency0)).forceApprove(address(tidefi), type(uint256).max); IERC20(Currency.unwrap(key.currency1)).forceApprove(address(tidefi), type(uint256).max); PoolId poolId = key.toId(); _initializedPools.push(key); _poolIndexPlusOne[poolId] = _initializedPools.length; emit AggregatorPoolRegistered(poolId); return IHooks.beforeInitialize.selector; }Simple trades only
Trades must state the amount going in, not the amount coming out.
The code that does this (beforeSwap):function beforeSwap(address sender, PoolKey calldata key, IPoolManager.SwapParams calldata params, bytes calldata) external onlyPoolManager returns (bytes4, BeforeSwapDelta, uint24) { if (params.amountSpecified >= 0) revert TideFiAggregatorHookExactOutputNotSupported(); // forge-lint: disable-next-item(unsafe-typecast) uint256 amountIn = uint256(-params.amountSpecified); (Currency currencyIn, Currency currencyOut) = params.zeroForOne ? (key.currency0, key.currency1) : (key.currency1, key.currency0); poolManager.take(currencyIn, address(this), amountIn); poolManager.sync(currencyOut); (uint256 amountFilled,) = tidefi.swap( Currency.unwrap(currencyIn), Currency.unwrap(currencyOut), amountIn, 0, type(uint256).max, address(poolManager) ); if (amountFilled != amountIn) revert TideFiAggregatorHookPartialFill(amountIn, amountFilled); // The output is what actually landed in the PoolManager, not TideFi's return value. uint256 amountOut = poolManager.settle(); PoolId poolId = key.toId(); (uint24 protocolFee, uint256 protocolFeeAmount) = _takeProtocolFee(poolId, params.zeroForOne, currencyOut, amountOut); int128 specifiedDelta = amountIn.toInt128(); int128 unspecifiedDelta = -(amountOut - protocolFeeAmount).toInt128(); // …
Who controls it: Nobody. The hook has no admin functions, and the code cannot be changed.
Based on the hook’s published code.
What it can do
Its code executes inside each trade in pools that use it.
It can take or add tokens during a swap. Fees, burns and custom curves work this way, and so do scams.
It checks every deposit before it goes in.
It runs when a pool is created, often to lock in that pool’s settings.
Hook history
Across all its pools, the hook handled a trade: $100.41.
- Handled a trade 1 time, worth $100.41
- Registered an aggregator pool 14 times
Latest transactions
- 0x770cb11b…19609e block 111,819,979
- 0x3f0e16a2…1a05d6 block 111,819,974
- 0x372a946c…4ca878 block 111,819,969
- 0xfd6b487f…f6fd65 block 111,819,964
- 0xdb5bd6f6…24dc09 block 111,819,959
- 0x2f7a142f…1decc9 block 111,819,954
- 0x572865c1…5bb44b block 111,819,948
- 0x3fda4826…eb320e block 111,819,943
- 0xaab53dcb…b37ae4 block 111,819,938
- 0xc1a59012…5ad194 block 111,819,933
Counted from what the hook recorded on-chain across all its pools, for every action in its published code, plus token transfers in and out of it. Dollar values count the amounts paid in ETH, stablecoins, BNB and BTC, at today’s prices.