// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IHooks} from "v4-core/src/interfaces/IHooks.sol";
import {IPoolManager} from "v4-core/src/interfaces/IPoolManager.sol";
import {PoolKey} from "v4-core/src/types/PoolKey.sol";
import {PoolId, PoolIdLibrary} from "v4-core/src/types/PoolId.sol";
import {Currency} from "v4-core/src/types/Currency.sol";
import {BalanceDelta} from "v4-core/src/types/BalanceDelta.sol";
import {BeforeSwapDelta, toBeforeSwapDelta} from "v4-core/src/types/BeforeSwapDelta.sol";
import {SwapParams, ModifyLiquidityParams} from "v4-core/src/types/PoolOperation.sol";
import {Hooks} from "v4-core/src/libraries/Hooks.sol";
import {IUnlockCallback} from "v4-core/src/interfaces/callback/IUnlockCallback.sol";
import {IFomo4DHook} from "./IFomo4DHook.sol";
// The exact set of hook permission bits this hook must carry (0xACC).
// Shared by the constructor assertion, the deploy script's salt mining and the test harness.
uint160 constant HOOK_REQUIRED_FLAGS = Hooks.BEFORE_ADD_LIQUIDITY_FLAG | Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG
| Hooks.BEFORE_SWAP_FLAG | Hooks.AFTER_SWAP_FLAG | Hooks.BEFORE_SWAP_RETURNS_DELTA_FLAG
| Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG;
/// @title Fomo4DHook
/// @notice Uniswap v4 hook for a one-sided TOKEN/ETH pool: charges a flat 2% fee on the ETH side of
/// swaps in both directions and permanently locks liquidity.
/// The hook never calls out to the Game. Fees are split into the `teamFees` / `potFees`
/// buckets at accrual time and sit here until the Game pulls them via `collectTeam()` /
/// `collectPot()`.
/// `beforeSwap` / `afterSwap` are total: they are defined for any input and never revert on
/// shared state.
/// @dev ETH = currency0, TOKEN = currency1; `zeroForOne == true` is ETH -> TOKEN.
/// Fees only cover exactIn; exactOut is rejected. See DESIGN.md.
contract Fomo4DHook is IFomo4DHook, IUnlockCallback {
using PoolIdLibrary for PoolKey;
IPoolManager public immutable poolManager;
address public immutable deployer; // may call `setGame` once; has no power afterwards
address public game; // set once at deploy time; the only address allowed to collect / bind / lock
/// @notice Immutable dead-on-arrival fallback recipient. No owner, no setter.
/// @dev Not the post-endgame fee recipient: both fee buckets flow to `Game.teamVault`.
/// This hook never reads the variable; its only consumer system-wide is the DOA branch of
/// `Fomo4DGame.finalize()`, which pushes `potVault` here.
address public immutable feeReceiver;
uint24 internal constant BASE_FEE_BPS = 200; // 2%, constant for the life of the pool
uint256 internal constant BPS = 10_000;
uint256 internal constant FEE_TEAM_BPS = 2000; // team's share of the fee; remainder goes to the pot
Currency internal constant CURRENCY0 = Currency.wrap(address(0)); // ETH
PoolId internal poolId;
bool internal poolBound; // set by the Game's explicit `bindPool` call, not by the first swap
/// @dev Fees are split 20/80 at accrual time, so the two buckets are independent of each other
/// and of the order in which they are pulled.
uint256 public teamFees; // 20% team share
uint256 public potFees; // 80% pot share
bool public liquidityLocked; // once true, every add/remove is rejected
error OnlyPoolManager();
error OnlyGame();
error LiquidityLocked();
error ExactOutNotSupported();
event FeeAccrued(uint256 amount);
event Collected(uint256 amount);
modifier onlyPoolManager() {
if (msg.sender != address(poolManager)) revert OnlyPoolManager();
_;
}
/// @notice Deploys the hook. Reverts unless the hook's own address carries exactly
/// `HOOK_REQUIRED_FLAGS`, so a mis-mined CREATE2 salt fails at deploy time.
/// @param _pm The Uniswap v4 pool manager.
/// @param _feeReceiver Immutable DOA fallback recipient.
/// @param _deployer The only address allowed to call `setGame`; must be non-zero and must be
/// passed explicitly, since under CREATE2 `msg.sender` is the deterministic factory.
constructor(IPoolManager _pm, address _feeReceiver, address _deployer) {
require(uint160(address(this)) & Hooks.ALL_HOOK_MASK == HOOK_REQUIRED_FLAGS, "hook flags");
require(_deployer != address(0), "zero deployer");
poolManager = _pm;
deployer = _deployer;
feeReceiver = _feeReceiver;
}
/// @notice Sets the Game address once, breaking the Game/Hook circular dependency.
/// @param _game The Fomo4DGame address; must be non-zero.
/// @dev Only `deployer` may call this, and only while `game` is unset.
function setGame(address _game) external {
require(msg.sender == deployer, "only deployer");
require(game == address(0), "game set");
require(_game != address(0), "zero game");
game = _game;
}
/// @notice Binds the single pool this hook serves.
/// @param key The pool key to bind.
/// @dev Only the game may call this, and only once.
function bindPool(PoolKey calldata key) external {
require(msg.sender == game, "only game");
require(!poolBound, "bound");
poolId = key.toId();
poolBound = true;
}
/// @dev True only for the bound pool; anything before binding counts as a foreign pool.
function _isOwnPool(PoolKey calldata key) internal view returns (bool) {
return poolBound && PoolId.unwrap(key.toId()) == PoolId.unwrap(poolId);
}
// This contract deliberately has no `receive()`: ETH sent directly to it reverts.
// ───────────────────────── Fee rate ─────────────────────────
/// @notice The current fee rate in bps. Constant 2%, independent of time.
/// @return The fee rate in basis points.
function currentFeeBps() public pure returns (uint24) {
return BASE_FEE_BPS;
}
// ───────────────────────── Swap callbacks ─────────────────────────
/// @notice v4 `beforeSwap` callback. On a buy (ETH -> TOKEN, exactIn) it takes the ETH fee off
/// the input side and returns it as a specified-side delta.
/// @return The selector, the hook's beforeSwap delta and a zero LP-fee override.
/// @dev Only the pool manager may call this. Reverts with `ExactOutNotSupported` when
/// `amountSpecified > 0`. Foreign pools get a zero delta rather than a revert.
function beforeSwap(address, PoolKey calldata key, SwapParams calldata params, bytes calldata)
external
onlyPoolManager
returns (bytes4, BeforeSwapDelta, uint24)
{
if (!_isOwnPool(key)) return (IHooks.beforeSwap.selector, toBeforeSwapDelta(0, 0), 0);
if (params.amountSpecified > 0) revert ExactOutNotSupported();
// ETH is the specified input here, so the fee is taken from the input side.
if (params.zeroForOne && params.amountSpecified < 0) {
uint256 ethIn = uint256(-params.amountSpecified);
uint256 fee = (ethIn * currentFeeBps()) / BPS;
if (fee > 0) {
// `mint` an ERC-6909 claim rather than `take`: the input has not landed yet.
poolManager.mint(address(this), key.currency0.toId(), fee);
_accrue(fee); // emits FeeAccrued; do not emit again here
return (IHooks.beforeSwap.selector, toBeforeSwapDelta(int128(int256(fee)), 0), 0);
}
}
return (IHooks.beforeSwap.selector, toBeforeSwapDelta(0, 0), 0);
}
/// @notice v4 `afterSwap` callback. On a sell (TOKEN -> ETH, exactIn) it takes the ETH fee off
/// the output side and returns it as an unspecified-side delta.
/// @return The selector and the hook's unspecified-currency delta.
/// @dev Only the pool manager may call this. Foreign pools get a zero delta rather than a revert.
function afterSwap(address, PoolKey calldata key, SwapParams calldata params, BalanceDelta delta, bytes calldata)
external
onlyPoolManager
returns (bytes4, int128)
{
if (!_isOwnPool(key)) return (IHooks.afterSwap.selector, int128(0));
if (!params.zeroForOne && params.amountSpecified < 0) {
int128 ethOut = delta.amount0(); // ETH owed to the swapper (positive)
if (ethOut > 0) {
uint256 fee = (uint256(int256(ethOut)) * currentFeeBps()) / BPS;
if (fee > 0) {
poolManager.mint(address(this), key.currency0.toId(), fee);
_accrue(fee); // emits FeeAccrued; do not emit again here
return (IHooks.afterSwap.selector, int128(int256(fee)));
}
}
}
return (IHooks.afterSwap.selector, int128(0));
}
// ───────────────────────── Liquidity lock ─────────────────────────
/// @notice v4 `beforeAddLiquidity` callback.
/// @return The selector.
/// @dev Only the pool manager may call this. Reverts with `LiquidityLocked` unless the sender is
/// the game and liquidity is not yet locked, i.e. only the genesis mint passes.
function beforeAddLiquidity(address sender, PoolKey calldata, ModifyLiquidityParams calldata, bytes calldata)
external
view
onlyPoolManager
returns (bytes4)
{
if (liquidityLocked || sender != game) revert LiquidityLocked();
return IHooks.beforeAddLiquidity.selector;
}
/// @notice v4 `beforeRemoveLiquidity` callback. Always reverts: liquidity is permanently locked.
/// @dev Only the pool manager may call this.
function beforeRemoveLiquidity(address, PoolKey calldata, ModifyLiquidityParams calldata, bytes calldata)
external
view
onlyPoolManager
returns (bytes4)
{
revert LiquidityLocked();
}
// ───────────────────────── Game interface (one-way) ─────────────────────────
/// @dev Splits the fee 20/80 into the team and pot buckets at accrual time; the remainder after
/// integer division goes to the pot. Sole emission point of `FeeAccrued`.
function _accrue(uint256 fee) internal {
uint256 t = (fee * FEE_TEAM_BPS) / BPS;
teamFees += t;
potFees += fee - t;
emit FeeAccrued(fee);
}
/// @notice Total unsettled fees, i.e. both buckets summed. Read-only.
/// @return The sum of `teamFees` and `potFees`.
function accruedFees() external view returns (uint256) {
return teamFees + potFees;
}
/// @notice Pulls the team bucket to the game.
/// @return sent The amount forwarded, or 0 if the bucket was empty or the transfer failed.
/// @dev Only the game may call this. Best-effort: on failure the bucket is restored and 0 is
/// returned rather than reverting.
function collectTeam() external returns (uint256 sent) {
if (msg.sender != game) revert OnlyGame();
uint256 amount = teamFees;
if (amount == 0) return 0;
teamFees = 0;
try this.redeemTo(game, amount) {
emit Collected(amount);
return amount;
} catch {
teamFees = amount;
return 0;
}
}
/// @notice Pulls the pot bucket to the game.
/// @return sent The amount forwarded, or 0 if the bucket was empty or the transfer failed.
/// @dev Only the game may call this. Best-effort: on failure the bucket is restored and 0 is
/// returned rather than reverting.
function collectPot() external returns (uint256 sent) {
if (msg.sender != game) revert OnlyGame();
uint256 amount = potFees;
if (amount == 0) return 0;
potFees = 0;
try this.redeemTo(game, amount) {
emit Collected(amount);
return amount;
} catch {
potFees = amount;
return 0;
}
}
/// @notice Redeems the hook's ERC-6909 ETH claims and sends real ETH to `to`.
/// @param to Recipient of the ETH.
/// @param amount Amount of ETH to redeem.
/// @dev Only this contract may call it; the collect functions wrap it in try/catch.
function redeemTo(address to, uint256 amount) external {
require(msg.sender == address(this), "self only");
poolManager.unlock(abi.encode(to, amount));
}
/// @notice Pool manager unlock callback for `redeemTo`.
/// @param data ABI-encoded `(address to, uint256 amount)`.
/// @return Empty bytes.
/// @dev Only the pool manager may call this. Burns the 6909 ETH claim, then takes the real ETH.
function unlockCallback(bytes calldata data) external returns (bytes memory) {
require(msg.sender == address(poolManager), "only pm");
(address to, uint256 amount) = abi.decode(data, (address, uint256));
poolManager.burn(address(this), CURRENCY0.toId(), amount);
poolManager.take(CURRENCY0, to, amount);
return "";
}
/// @notice Permanently locks liquidity; called once after the genesis mint.
/// @dev Only the game may call this.
function lockLiquidity() external {
if (msg.sender != game) revert OnlyGame();
liquidityLocked = true;
}
}[
{
"type": "constructor",
"inputs": [
{
"name": "_pm",
"type": "address",
"internalType": "contract IPoolManager"
},
{
"name": "_feeReceiver",
"type": "address",
"internalType": "address"
},
{
"name": "_deployer",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "nonpayable"
},
{
"name": "ExactOutNotSupported",
"type": "error",
"inputs": []
},
{
"name": "LiquidityLocked",
"type": "error",
"inputs": []
},
{
"name": "OnlyGame",
"type": "error",
"inputs": []
},
{
"name": "OnlyPoolManager",
"type": "error",
"inputs": []
},
{
"name": "Collected",
"type": "event",
"inputs": [
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "FeeAccrued",
"type": "event",
"inputs": [
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "accruedFees",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "afterSwap",
"type": "function",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
},
{
"name": "key",
"type": "tuple",
"components": [
{
"name": "currency0",
"type": "address",
"internalType": "Currency"
},
{
"name": "currency1",
"type": "address",
"internalType": "Currency"
},
{
"name": "fee",
"type": "uint24",
"internalType": "uint24"
},
{
"name": "tickSpacing",
"type": "int24",
"internalType": "int24"
},
{
"name": "hooks",
"type": "address",
"internalType": "contract IHooks"
}
],
"internalType": "struct PoolKey"
},
{
"name": "params",
"type": "tuple",
"components": [
{
"name": "zeroForOne",
"type": "bool",
"internalType": "bool"
},
{
"name": "amountSpecified",
"type": "int256",
"internalType": "int256"
},
{
"name": "sqrtPriceLimitX96",
"type": "uint160",
"internalType": "uint160"
}
],
"internalType": "struct SwapParams"
},
{
"name": "delta",
"type": "int256",
"internalType": "BalanceDelta"
},
{
"name": "",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [
{
"name": "",
"type": "bytes4",
"internalType": "bytes4"
},
{
"name": "",
"type": "int128",
"internalType": "int128"
}
],
"stateMutability": "nonpayable"
},
{
"name": "beforeAddLiquidity",
"type": "function",
"inputs": [
{
"name": "sender",
"type": "address",
"internalType": "address"
},
{
"name": "",
"type": "tuple",
"components": [
{
"name": "currency0",
"type": "address",
"internalType": "Currency"
},
{
"name": "currency1",
"type": "address",
"internalType": "Currency"
},
{
"name": "fee",
"type": "uint24",
"internalType": "uint24"
},
{
"name": "tickSpacing",
"type": "int24",
"internalType": "int24"
},
{
"name": "hooks",
"type": "address",
"internalType": "contract IHooks"
}
],
"internalType": "struct PoolKey"
},
{
"name": "",
"type": "tuple",
"components": [
{
"name": "tickLower",
"type": "int24",
"internalType": "int24"
},
{
"name": "tickUpper",
"type": "int24",
"internalType": "int24"
},
{
"name": "liquidityDelta",
"type": "int256",
"internalType": "int256"
},
{
"name": "salt",
"type": "bytes32",
"internalType": "bytes32"
}
],
"internalType": "struct ModifyLiquidityParams"
},
{
"name": "",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [
{
"name": "",
"type": "bytes4",
"internalType": "bytes4"
}
],
"stateMutability": "view"
},
{
"name": "beforeRemoveLiquidity",
"type": "function",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
},
{
"name": "",
"type": "tuple",
"components": [
{
"name": "currency0",
"type": "address",
"internalType": "Currency"
},
{
"name": "currency1",
"type": "address",
"internalType": "Currency"
},
{
"name": "fee",
"type": "uint24",
"internalType": "uint24"
},
{
"name": "tickSpacing",
"type": "int24",
"internalType": "int24"
},
{
"name": "hooks",
"type": "address",
"internalType": "contract IHooks"
}
],
"internalType": "struct PoolKey"
},
{
"name": "",
"type": "tuple",
"components": [
{
"name": "tickLower",
"type": "int24",
"internalType": "int24"
},
{
"name": "tickUpper",
"type": "int24",
"internalType": "int24"
},
{
"name": "liquidityDelta",
"type": "int256",
"internalType": "int256"
},
{
"name": "salt",
"type": "bytes32",
"internalType": "bytes32"
}
],
"internalType": "struct ModifyLiquidityParams"
},
{
"name": "",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [
{
"name": "",
"type": "bytes4",
"internalType": "bytes4"
}
],
"stateMutability": "view"
},
{
"name": "beforeSwap",
"type": "function",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
},
{
"name": "key",
"type": "tuple",
"components": [
{
"name": "currency0",
"type": "address",
"internalType": "Currency"
},
{
"name": "currency1",
"type": "address",
"internalType": "Currency"
},
{
"name": "fee",
"type": "uint24",
"internalType": "uint24"
},
{
"name": "tickSpacing",
"type": "int24",
"internalType": "int24"
},
{
"name": "hooks",
"type": "address",
"internalType": "contract IHooks"
}
],
"internalType": "struct PoolKey"
},
{
"name": "params",
"type": "tuple",
"components": [
{
"name": "zeroForOne",
"type": "bool",
"internalType": "bool"
},
{
"name": "amountSpecified",
"type": "int256",
"internalType": "int256"
},
{
"name": "sqrtPriceLimitX96",
"type": "uint160",
"internalType": "uint160"
}
],
"internalType": "struct SwapParams"
},
{
"name": "",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [
{
"name": "",
"type": "bytes4",
"internalType": "bytes4"
},
{
"name": "",
"type": "int256",
"internalType": "BeforeSwapDelta"
},
{
"name": "",
"type": "uint24",
"internalType": "uint24"
}
],
"stateMutability": "nonpayable"
},
{
"name": "bindPool",
"type": "function",
"inputs": [
{
"name": "key",
"type": "tuple",
"components": [
{
"name": "currency0",
"type": "address",
"internalType": "Currency"
},
{
"name": "currency1",
"type": "address",
"internalType": "Currency"
},
{
"name": "fee",
"type": "uint24",
"internalType": "uint24"
},
{
"name": "tickSpacing",
"type": "int24",
"internalType": "int24"
},
{
"name": "hooks",
"type": "address",
"internalType": "contract IHooks"
}
],
"internalType": "struct PoolKey"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "collectPot",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "sent",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "collectTeam",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "sent",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "currentFeeBps",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint24",
"internalType": "uint24"
}
],
"stateMutability": "pure"
},
{
"name": "deployer",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "feeReceiver",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "game",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "liquidityLocked",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "bool",
"internalType": "bool"
}
],
"stateMutability": "view"
},
{
"name": "lockLiquidity",
"type": "function",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "poolManager",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "contract IPoolManager"
}
],
"stateMutability": "view"
},
{
"name": "potFees",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "redeemTo",
"type": "function",
"inputs": [
{
"name": "to",
"type": "address",
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "setGame",
"type": "function",
"inputs": [
{
"name": "_game",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "teamFees",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "unlockCallback",
"type": "function",
"inputs": [
{
"name": "data",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [
{
"name": "",
"type": "bytes",
"internalType": "bytes"
}
],
"stateMutability": "nonpayable"
}
]0x608060405234801561000f575f80fd5b5060043610610126575f3560e01c806391dd7346116100a9578063c3fe3e281161006e578063c3fe3e28146102d6578063d5f39488146102e8578063d7200dac1461030f578063dc4c90d314610318578063f99e7f481461033f575f80fd5b806391dd73461461022a578063975f8f461461024a578063b3f0067414610259578063b47b2fb114610298578063bb2f7199146102ce575f80fd5b8063575e24b4116100ef578063575e24b4146101a157806357976fb4146101df578063682c2058146101fc57806373ed8a5114610204578063819912a214610217575f80fd5b80627edce41461012a57806321d0ee7014610145578063259982e5146101715780632f7605fb1461018457806334e3566214610199575b5f80fd5b610132610348565b6040519081526020015b60405180910390f35b610158610153366004610f1a565b610427565b6040516001600160e01b0319909116815260200161013c565b61015861017f366004610f1a565b61048a565b610197610192366004610f9b565b610522565b005b61013261062a565b6101b46101af366004610fd5565b6106d4565b604080516001600160e01b03199094168452602084019290925262ffffff169082015260600161013c565b6005546101ec9060ff1681565b604051901515815260200161013c565b6101326108a4565b61019761021236600461102f565b6108ba565b610197610225366004611050565b610968565b61023d61023836600461106b565b610a76565b60405161013c91906110aa565b60405160c8815260200161013c565b6102807f0000000000000000000000004b3ad373d4776f7ef310851409147cc03d8c1d4e81565b6040516001600160a01b03909116815260200161013c565b6102ab6102a63660046110df565b610c1b565b604080516001600160e01b03199093168352600f9190910b60208301520161013c565b610197610dbb565b5f54610280906001600160a01b031681565b6102807f000000000000000000000000c87b7c65efc4b4b291b0d64a71d834afc05b19a681565b61013260035481565b6102807f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e4095181565b61013260045481565b5f80546001600160a01b0316331461037357604051636200df7d60e11b815260040160405180910390fd5b6003545f819003610385575f91505090565b5f600381905554604051632f7605fb60e01b81526001600160a01b039091166004820152602481018290523090632f7605fb906044015f604051808303815f87803b1580156103d2575f80fd5b505af19250505080156103e3575060015b6103ef57600355505f90565b6040518181527f278111f058fcc15883749957935fb9630ea32a108dd40081364d762353441ccb9060200160405180910390a1919050565b5f336001600160a01b037f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e4095116146104715760405163f655705d60e01b815260040160405180910390fd5b6040516347a73ad960e11b815260040160405180910390fd5b5f336001600160a01b037f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e4095116146104d45760405163f655705d60e01b815260040160405180910390fd5b60055460ff16806104f257505f546001600160a01b03878116911614155b15610510576040516347a73ad960e11b815260040160405180910390fd5b5063259982e560e01b95945050505050565b3330146105625760405162461bcd60e51b815260206004820152600960248201526873656c66206f6e6c7960b81b60448201526064015b60405180910390fd5b7f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e409516001600160a01b03166348c8949183836040516020016105b89291906001600160a01b03929092168252602082015260400190565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016105e391906110aa565b5f604051808303815f875af11580156105fe573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261062591908101906111ce565b505050565b5f80546001600160a01b0316331461065557604051636200df7d60e11b815260040160405180910390fd5b6004545f819003610667575f91505090565b5f60048181559054604051632f7605fb60e01b81526001600160a01b0390911691810191909152602481018290523090632f7605fb906044015f604051808303815f87803b1580156106b7575f80fd5b505af19250505080156106c8575060015b6103ef57600455505f90565b5f8080336001600160a01b037f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e4095116146107205760405163f655705d60e01b815260040160405180910390fd5b61072987610df4565b61074157506315d7892d60e21b91505f905080610899565b5f86602001351315610766576040516333d0438960e11b815260040160405180910390fd5b6107736020870187611262565b801561078257505f8660200135125b15610889575f6107956020880135611295565b90505f6127106107a660c8846112af565b6107b091906112c6565b90508015610886576001600160a01b037f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e409511663156e29f6306108046107f860208e018e611050565b6001600160a01b031690565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604481018490526064015f604051808303815f87803b15801561084e575f80fd5b505af1158015610860573d5f803e3d5ffd5b5050505061086d81610e1f565b6315d7892d60e21b945060801b92505f91506108999050565b50505b506315d7892d60e21b91505f9050805b955095509592505050565b5f6004546003546108b591906112e5565b905090565b5f546001600160a01b031633146108ff5760405162461bcd60e51b81526020600482015260096024820152686f6e6c792067616d6560b81b6044820152606401610559565b60025460ff161561093a5760405162461bcd60e51b8152602060048201526005602482015264189bdd5b9960da1b6044820152606401610559565b61095361094c36839003830183611308565b60a0902090565b60019081556002805460ff1916909117905550565b336001600160a01b037f000000000000000000000000c87b7c65efc4b4b291b0d64a71d834afc05b19a616146109d05760405162461bcd60e51b815260206004820152600d60248201526c37b7363c903232b83637bcb2b960991b6044820152606401610559565b5f546001600160a01b031615610a135760405162461bcd60e51b815260206004820152600860248201526719d85b59481cd95d60c21b6044820152606401610559565b6001600160a01b038116610a555760405162461bcd60e51b81526020600482015260096024820152687a65726f2067616d6560b81b6044820152606401610559565b5f80546001600160a01b0319166001600160a01b0392909216919091179055565b6060336001600160a01b037f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e409511614610ada5760405162461bcd60e51b81526020600482015260076024820152666f6e6c7920706d60c81b6044820152606401610559565b5f80610ae884860186610f9b565b90925090507f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e409516001600160a01b031663f5298aca305f6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604481018490526064015f604051808303815f87803b158015610b68575f80fd5b505af1158015610b7a573d5f803e3d5ffd5b5050604051630b0d9c0960e01b81525f60048201526001600160a01b038581166024830152604482018590527f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e40951169250630b0d9c0991506064015f604051808303815f87803b158015610beb575f80fd5b505af1158015610bfd573d5f803e3d5ffd5b5050505060405180602001604052805f815250925050505b92915050565b5f80336001600160a01b037f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e409511614610c665760405163f655705d60e01b815260040160405180910390fd5b610c6f87610df4565b610c84575063b47b2fb160e01b90505f610db0565b610c916020870187611262565b158015610ca157505f8660200135125b15610da3575f610cb18660801d90565b90505f81600f0b1315610da1575f612710610cd160c8600f85900b6112af565b610cdb91906112c6565b90508015610d9f576001600160a01b037f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e409511663156e29f630610d236107f860208e018e611050565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604481018490526064015f604051808303815f87803b158015610d6d575f80fd5b505af1158015610d7f573d5f803e3d5ffd5b50505050610d8c81610e1f565b63b47b2fb160e01b93509150610db09050565b505b505b5063b47b2fb160e01b90505f5b965096945050505050565b5f546001600160a01b03163314610de557604051636200df7d60e11b815260040160405180910390fd5b6005805460ff19166001179055565b6002545f9060ff168015610c155750600154610e1861094c36859003850185611308565b1492915050565b5f612710610e2f6107d0846112af565b610e3991906112c6565b90508060035f828254610e4c91906112e5565b90915550610e5c9050818361138d565b60045f828254610e6c91906112e5565b90915550506040518281527fb42056c053e059683baf30e86a45ffb4bfb6763f140678f37f03d70b184d93759060200160405180910390a15050565b6001600160a01b0381168114610ebc575f80fd5b50565b5f60a08284031215610ecf575f80fd5b50919050565b5f8083601f840112610ee5575f80fd5b50813567ffffffffffffffff811115610efc575f80fd5b602083019150836020828501011115610f13575f80fd5b9250929050565b5f805f805f858703610160811215610f30575f80fd5b8635610f3b81610ea8565b9550610f4a8860208901610ebf565b9450608060bf1982011215610f5d575f80fd5b5060c08601925061014086013567ffffffffffffffff811115610f7e575f80fd5b610f8a88828901610ed5565b969995985093965092949392505050565b5f8060408385031215610fac575f80fd5b8235610fb781610ea8565b946020939093013593505050565b5f60608284031215610ecf575f80fd5b5f805f805f6101408688031215610fea575f80fd5b8535610ff581610ea8565b94506110048760208801610ebf565b93506110138760c08801610fc5565b925061012086013567ffffffffffffffff811115610f7e575f80fd5b5f60a0828403121561103f575f80fd5b6110498383610ebf565b9392505050565b5f60208284031215611060575f80fd5b813561104981610ea8565b5f806020838503121561107c575f80fd5b823567ffffffffffffffff811115611092575f80fd5b61109e85828601610ed5565b90969095509350505050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f805f805f8061016087890312156110f5575f80fd5b863561110081610ea8565b955061110f8860208901610ebf565b945061111e8860c08901610fc5565b9350610120870135925061014087013567ffffffffffffffff811115611142575f80fd5b61114e89828a01610ed5565b979a9699509497509295939492505050565b634e487b7160e01b5f52604160045260245ffd5b60405160a0810167ffffffffffffffff8111828210171561119757611197611160565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156111c6576111c6611160565b604052919050565b5f602082840312156111de575f80fd5b815167ffffffffffffffff8111156111f4575f80fd5b8201601f81018413611204575f80fd5b805167ffffffffffffffff81111561121e5761121e611160565b611231601f8201601f191660200161119d565b818152856020838501011115611245575f80fd5b8160208401602083015e5f91810160200191909152949350505050565b5f60208284031215611272575f80fd5b81358015158114611049575f80fd5b634e487b7160e01b5f52601160045260245ffd5b5f600160ff1b82016112a9576112a9611281565b505f0390565b8082028115828204841417610c1557610c15611281565b5f826112e057634e487b7160e01b5f52601260045260245ffd5b500490565b80820180821115610c1557610c15611281565b803561130381610ea8565b919050565b5f60a0828403128015611319575f80fd5b50611322611174565b823561132d81610ea8565b8152602083013561133d81610ea8565b6020820152604083013562ffffff81168114611357575f80fd5b60408201526060830135600281900b8114611370575f80fd5b6060820152611381608084016112f8565b60808201529392505050565b81810381811115610c1557610c1561128156fea2646970667358221220d2679a1845a7669a673deab75ae5b852ee84a95c562b4a881bd74c7900002af464736f6c634300081a0033
| Token | Symbol | Balance | Price | Value |
|---|---|---|---|---|
| no token holdings | ||||
| Type | Age | Block | Details |
|---|---|---|---|
| no cross-chain L1↔L2 transactions for this address | |||
| Transaction Hash | Method | Block | Age | From | To | Type | Item | ||
|---|---|---|---|---|---|---|---|---|---|
| no NFT transfers for this address yet | |||||||||
| Transaction Hash | Method | Block | Age | From | To | Amount | Token | ||
|---|---|---|---|---|---|---|---|---|---|
| no token transfers for this address yet | |||||||||
| Txn Hash | Age | Event | Topics / Data |
|---|---|---|---|
| 0x2e9676…a76671 | 2 mins agoMon, 17 Aug 2026 21:48:30 UTC | 0xb42056…9375 | data: 0x000000000000000000…aff6ad91 |
| 0x60512f…52d327 | 2 hrs agoMon, 17 Aug 2026 19:09:58 UTC | 0xb42056…9375 | data: 0x000000000000000000…1b3afab5 |
| 0x827d4c…fe3bff | 3 hrs agoMon, 17 Aug 2026 18:46:01 UTC | 0xb42056…9375 | data: 0x000000000000000000…bd97f9e2 |
| 0xa97560…1836ab | 5 hrs agoMon, 17 Aug 2026 16:51:16 UTC | 0xb42056…9375 | data: 0x000000000000000000…ad0f6e9b |
| 0x595f1d…03e4ab | 5 hrs agoMon, 17 Aug 2026 16:04:49 UTC | 0xb42056…9375 | data: 0x000000000000000000…7def3000 |
| 0x72a8b8…ffc925 | 5 hrs agoMon, 17 Aug 2026 16:04:48 UTC | 0xb42056…9375 | data: 0x000000000000000000…c3c1ecc9 |
| 0xee8b15…e2e08d | 6 hrs agoMon, 17 Aug 2026 15:34:56 UTC | 0xb42056…9375 | data: 0x000000000000000000…30f650ee |
| 0x385a02…0773da | 7 hrs agoMon, 17 Aug 2026 14:04:25 UTC | 0xb42056…9375 | data: 0x000000000000000000…bbbadb88 |
| 0xe2d8cc…260b58 | 8 hrs agoMon, 17 Aug 2026 13:50:50 UTC | 0xb42056…9375 | data: 0x000000000000000000…0d07c29d |
| 0xb72389…d18acc | 8 hrs agoMon, 17 Aug 2026 13:36:13 UTC | 0xb42056…9375 | data: 0x000000000000000000…aff1b57d |
| 0x84ad88…cd003a | 8 hrs agoMon, 17 Aug 2026 13:36:13 UTC | 0xb42056…9375 | data: 0x000000000000000000…a6622a82 |
| 0x78c81d…a741ea | 8 hrs agoMon, 17 Aug 2026 13:26:53 UTC | 0xb42056…9375 | data: 0x000000000000000000…8f913beb |
| 0x765775…6477a8 | 8 hrs agoMon, 17 Aug 2026 13:26:51 UTC | 0xb42056…9375 | data: 0x000000000000000000…73537c8a |
| 0xd73bea…570728 | 9 hrs agoMon, 17 Aug 2026 12:47:37 UTC | 0xb42056…9375 | data: 0x000000000000000000…d7a959dc |
| 0x3a0ba2…275ece | 9 hrs agoMon, 17 Aug 2026 12:23:56 UTC | 0xb42056…9375 | data: 0x000000000000000000…f038927d |
| 0x1a66af…d522ca | 9 hrs agoMon, 17 Aug 2026 12:15:25 UTC | 0xb42056…9375 | data: 0x000000000000000000…54ab2678 |
| 0x63a019…257c39 | 10 hrs agoMon, 17 Aug 2026 11:11:51 UTC | 0xb42056…9375 | data: 0x000000000000000000…6ed792dd |
| 0x8db1a0…2f0a5c | 10 hrs agoMon, 17 Aug 2026 10:57:11 UTC | 0xb42056…9375 | data: 0x000000000000000000…66ff2000 |
| 0xb1baf2…cde697 | 10 hrs agoMon, 17 Aug 2026 10:57:11 UTC | 0xb42056…9375 | data: 0x000000000000000000…d8da93d2 |
| 0x53c47c…27aaf4 | 12 hrs agoMon, 17 Aug 2026 09:08:12 UTC | 0xb42056…9375 | data: 0x000000000000000000…4cad1258 |
| 0x49fe79…cbb628 | 12 hrs agoMon, 17 Aug 2026 09:08:12 UTC | 0xb42056…9375 | data: 0x000000000000000000…57138467 |
| 0x7d7ae6…fb07fb | 12 hrs agoMon, 17 Aug 2026 09:08:12 UTC | 0xb42056…9375 | data: 0x000000000000000000…24f8da97 |
| 0x5eb819…12f215 | 12 hrs agoMon, 17 Aug 2026 09:08:12 UTC | 0xb42056…9375 | data: 0x000000000000000000…93e8f49f |
| 0xdd4f5a…9e236c | 12 hrs agoMon, 17 Aug 2026 09:08:12 UTC | 0xb42056…9375 | data: 0x000000000000000000…49e2e073 |
| 0x46bb9d…f17f13 | 12 hrs agoMon, 17 Aug 2026 09:08:12 UTC | 0xb42056…9375 | data: 0x000000000000000000…4ffeb3cb |
| Transaction Hash | Method ? | Block | Age | From | To | Amount | Txn Fee ? | ||
|---|---|---|---|---|---|---|---|---|---|
| 0xffa5ee…3a0b59 | setGame | 35,460,580 | 4 days agoThu, 13 Aug 2026 14:25:38 UTC | 0xc87b…19a6 | IN | Fomo4DHook | $0.000 ETH | 0.00000195 |
| Block | Age | Parent Transaction Hash | Type | Method | From | To | Value | |
|---|---|---|---|---|---|---|---|---|
| 35,457,996 | 4 days agoThu, 13 Aug 2026 14:21:19 UTC | 0x21381b…3723b4 | CREATE2 | optimized_routeFill921336808 | 0x4e59…956c | IN | 0x195c…cacc | 0 ETH |