// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
import {LPFeeLibrary} from "@uniswap/v4-core/src/libraries/LPFeeLibrary.sol";
import {FullMath} from "@uniswap/v4-core/src/libraries/FullMath.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {PoolId} from "@uniswap/v4-core/src/types/PoolId.sol";
import {SwapParams} from "@uniswap/v4-core/src/types/PoolOperation.sol";
import {BalanceDelta, BalanceDeltaLibrary} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {
BeforeSwapDelta,
BeforeSwapDeltaLibrary,
toBeforeSwapDelta
} from "@uniswap/v4-core/src/types/BeforeSwapDelta.sol";
/**
* LittleJohnHook — the v4 hook attached to every LittleJohn launch pool.
*
* v1 scope (hook pack v1): anti-snipe FEE DECAY + creator SELL-LOCK.
* v1.1 (BidWall buy-support, block-delay, volatility fee) extends
* `LaunchFeeConfig` with new fields — append only, never repurpose.
*
* ETH-LEG FEE (operator directive 2026-07-09, "Stack v4"): the pool's own LP
* fee is forced to ZERO and the HOOK takes the trading fee, ALWAYS FROM THE ETH
* LEG, in BOTH swap directions, via the canonical Uniswap v4 hook-delta
* mechanism (return a BeforeSwapDelta / afterSwap delta + settle it with the
* PoolManager). This is the same "take a fee from the swap and hold it as an
* ERC-6909 claim" pattern used by production fee hooks (Flaunch / Clanker /
* Zora coin hooks all take their cut through the hook-delta path rather than a
* hand-rolled transfer):
*
* The rule is direction- AND swap-type-agnostic: ETH (currency0) is the
* SPECIFIED currency exactly when `zeroForOne == exactInput`, and its amount is
* then known in `beforeSwap` (|amountSpecified|); otherwise ETH is the
* UNSPECIFIED currency and its amount is known only in `afterSwap`
* (|delta.amount0()|). The hook takes the fee in whichever callback the ETH leg
* is known, so ALL FOUR swap shapes pay `feeBps` of the ETH leg:
* - exact-input BUY (ETH in, zeroForOne): ETH specified -> beforeSwap, fee of
* the ETH input; pool swaps ETH-minus-fee, trader pays the full input.
* - exact-input SELL (ETH out, !zeroForOne): ETH unspecified -> afterSwap, fee
* of the ETH output; seller receives ETH-minus-fee.
* - exact-output SELL (ETH out, !zeroForOne): ETH specified -> beforeSwap;
* the pool produces requested ETH+fee and the seller receives exactly the
* requested ETH, where fee=floor((requested+fee)*bps/BPS).
* - exact-output BUY (ETH in, zeroForOne): ETH unspecified -> afterSwap; the
* buyer pays pool ETH+fee with the same floor fixed-point equation.
*
* The ERC-6909 claim is minted STRAIGHT TO THE PER-LAUNCH LpLockerV4 (recorded
* at registration). Minting (vs. `take`) is what makes this correct on a
* single-sided launch pool: on a BUY the trader's ETH has not settled into the
* PoolManager yet, so there is no real ETH to `take` — the ERC-6909 claim is a
* deferred credit the locker redeems into real ETH on its (permissionless)
* `collectFees`, where it is split 1/3 protocol + 2/3 creator and AUTO-PUSHED to
* both. There is ONE fee path: hook -> locker claim -> locker distribution. The
* hook holds no ETH and no state; the claim balance IS the accrual.
*
* FEE RATE is the SAME `feeAtElapsed` anti-snipe decay curve and the SAME
* creator sell-lock as before, applied to the ETH-leg fee. `feeAtElapsed`
* mirrors packages/contract/src/schemas.ts EXACTLY: the fee decays LINEARLY from
* `feeStartBps` to `feeEndBps` over `feeDurationSec` from launch, then holds at
* `feeEndBps` forever. `feeDurationSec == 0` means decay off (static
* `feeEndBps`). Time base is block.timestamp (Arbitrum Orbit/Nitro: block.number
* is an L1 estimate and MUST NOT be used for time windows).
*
* Fee is taken on EVERY swap regardless of exact-input vs exact-output
* (operator directive 2026-07-09, exact-output fee): the platform routers, the
* wizard, and the atomic dev-buy produce exact-input, but a UniversalRouter
* exact-output route (or any third-party router) now pays the identical ETH-leg
* `feeBps` too — closing the former exact-output revenue leak. Specified-ETH
* swaps are intentionally atomic/full-fill: a price limit that only partially
* fills them reverts rather than charging a fee against the requested amount.
* Full-fill swaps cannot over-skim past `feeBps` or trap a holder; exact-input
* SELL remains the ordinary always-available exit shape.
*
* RUG-PROOF INVARIANTS (operator directive 2026-07-09; each has a negative
* test, see contracts/README.md "Rug-proof invariants"):
* 1. HARD FEE CAP — `feeEndBps` (the fee that applies outside the decay
* window, i.e. forever) can never exceed MAX_STATIC_FEE_BPS (5%). A fee
* above the cap can only exist inside the bounded decay window.
* 2. IMMUTABLE AT LAUNCH — a pool's config is registered ONCE by the factory
* in the launch transaction. There is no setter, no owner, no upgrade
* path. `register` reverts on re-registration.
* 3. DECAY ONLY GOES DOWN — `feeStartBps >= feeEndBps` is enforced, the
* curve is linear, and the window is bounded at MAX_DECAY_SECONDS (1h).
* The fee is monotonically non-increasing in time for every config.
* 4. SELL-LOCK IS CREATOR-ONLY — the lock can only ever restrict the single
* `creator` address stored at registration. There is no config shape that
* blocks any other holder from selling, and the lock duration is bounded.
* 5. SYMMETRY — the fee RATE does not read the swap direction; buys and sells
* pay the identical `feeBps` at the same instant (the ETH-leg take is
* feeBps of the ETH input on a buy and feeBps of the ETH output on a sell).
* 6. ALWAYS TRADEABLE — for a full-fill swap, the ETH-leg take is a bounded
* fraction (<=40% in the decay window, <=5% settled) of the ETH the trader
* would otherwise receive/pay. Exact-input sells remain available to every
* non-creator; specified-ETH partial fills intentionally revert atomically.
*
* Known limitation (documented, testnet v1): the sell-lock matches on
* `tx.origin`, because `sender` in beforeSwap is the router, not the trader.
* A creator can evade it with a second wallet; it is an anti-fat-finger /
* anti-signal device, not custody (the same limitation every launchpad
* sell-lock has unless tokens are vested in escrow).
*/
interface ILpLockerV4Sink {
/// The locker exposes nothing the hook needs to call; the hook only ever
/// MINTS ERC-6909 claims to the locker's address. This interface exists so
/// the config's `locker` field is typed and documented, not to grant the
/// hook any authority over the locker.
function creator() external view returns (address);
}
contract LittleJohnHook {
using LPFeeLibrary for uint24;
using BalanceDeltaLibrary for BalanceDelta;
// ---------- invariant bounds (compile-time, not config) ----------
/// Invariant 1: the settled fee can never exceed 5%.
uint16 public constant MAX_STATIC_FEE_BPS = 500;
/// Operator revenue invariant: every launch settles at no less than 1%.
uint16 public constant MIN_STATIC_FEE_BPS = 100;
/// GLOBAL FEE CEILING (operator directive 2026-07-09): no fee may ever
/// exceed 40% (4000 bps), not even at second zero of the anti-snipe decay
/// window. The permanent fee cap stays MAX_STATIC_FEE_BPS (500). Matches
/// the zod schema (packages/contract v0.13.0, feeDecay.startBps max 4000).
uint16 public constant MAX_START_FEE_BPS = 4000;
/// Invariant 3: the decay window can never exceed 1 hour.
uint32 public constant MAX_DECAY_SECONDS = 3600;
/// Invariant 4: the creator sell-lock can never exceed 30 days.
uint32 public constant MAX_SELL_LOCK_SECONDS = 30 days;
/// bps denominator for the ETH-leg fee take.
uint16 internal constant BPS_DENOMINATOR = 10_000;
/// ERC-6909 id of native ETH == currency0 == toId(address(0)) == 0. Launch
/// pools pair against native ETH (currency0 == address(0)) on chain 4663.
uint256 internal constant ETH_CLAIM_ID = 0;
IPoolManager public immutable poolManager;
/// The only address that may register configs / initialize our pools.
address public immutable factory;
/// Per-pool launch config. Written ONCE (invariant 2). Extended (append
/// only) by hook pack v1.1: bidWall / blockDelay / dynamicFee fields.
struct LaunchFeeConfig {
address creator; // the launch creator (sell-lock target + fee-split side in the locker)
uint40 launchedAt; // decay t=0; also the "is registered" sentinel (never 0 once set)
uint40 sellLockUntil; // 0 = no sell-lock
uint16 feeStartBps; // decay opening fee; == feeEndBps when decay off
uint16 feeEndBps; // settled base fee, capped at MAX_STATIC_FEE_BPS
uint32 feeDurationSec; // 0 = decay off
address locker; // the per-launch LpLockerV4 the ETH-leg fee claim is minted to
}
mapping(PoolId => LaunchFeeConfig) internal _configs;
event LaunchRegistered(
PoolId indexed poolId,
address indexed creator,
address indexed locker,
uint16 feeStartBps,
uint16 feeEndBps,
uint32 feeDurationSec,
uint40 sellLockUntil
);
/// The ETH-leg fee the hook took on a swap, minted to the locker as an
/// ERC-6909 native-ETH claim (redeemed + distributed on locker.collectFees).
event EthFeeTaken(PoolId indexed poolId, bool indexed isBuy, uint256 ethFee, uint16 feeBps);
error NotPoolManager();
error PartialFillUnsupported();
error FeeRoundsToZero();
error OnlyFactory();
error AlreadyRegistered();
error NotRegistered();
error NotDynamicFee();
error ZeroCreator();
error ZeroLocker();
error FeeAboveCap(uint16 requested, uint16 cap);
error FeeBelowFloor(uint16 requested, uint16 floor);
error DecayGoesUp(uint16 startBps, uint16 endBps);
error DecayTooLong(uint32 requested, uint32 max);
error DecayWithoutWindow();
error SellLockTooLong(uint32 requested, uint32 max);
error CreatorSellLocked(uint40 until);
constructor(IPoolManager poolManager_, address factory_) {
if (address(poolManager_) == address(0) || factory_ == address(0)) revert OnlyFactory();
poolManager = poolManager_;
factory = factory_;
// Fail fast if the mined address does not carry EXACTLY the flag bits
// this hook implements: beforeInitialize + beforeSwap (+ its return
// delta) + afterSwap (+ its return delta). The two return-delta flags
// are what let the hook take the ETH-leg fee in each direction.
Hooks.validateHookPermissions(IHooks(address(this)), _hookPermissions());
}
/// The exact flag set this hook's mined address must carry. `virtual` so
/// the bonding hook (LittleJohnBondingHook) can extend it with its
/// beforeAddLiquidity gate — Solidity dispatches virtual calls made from a
/// base constructor to the most-derived override, so the constructor
/// check above validates the REAL permission set of whichever hook is
/// being deployed. Pure (reads nothing), so calling it before derived
/// state is initialized is safe.
function _hookPermissions() internal pure virtual returns (Hooks.Permissions memory) {
return Hooks.Permissions({
beforeInitialize: true,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: true,
afterSwap: true,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: true,
afterSwapReturnDelta: true,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
});
}
// ---------- factory wiring ----------
/**
* Register a launch pool's immutable config. Factory-only, once-only
* (invariant 2), called in the same transaction that initializes the
* pool. All invariant bounds are enforced HERE, on-chain — the factory
* validates too, but this contract does not trust its caller's checks.
* `locker` is the per-launch LpLockerV4 the ETH-leg fee claim is minted to.
*/
function register(
PoolId poolId,
address creator,
uint16 feeStartBps,
uint16 feeEndBps,
uint32 feeDurationSec,
uint32 sellLockSeconds,
address locker
) external {
if (msg.sender != factory) revert OnlyFactory();
if (creator == address(0)) revert ZeroCreator();
if (locker == address(0)) revert ZeroLocker();
if (_configs[poolId].launchedAt != 0) revert AlreadyRegistered(); // invariant 2
if (feeEndBps < MIN_STATIC_FEE_BPS) revert FeeBelowFloor(feeEndBps, MIN_STATIC_FEE_BPS);
if (feeEndBps > MAX_STATIC_FEE_BPS) revert FeeAboveCap(feeEndBps, MAX_STATIC_FEE_BPS); // invariant 1
if (feeStartBps > MAX_START_FEE_BPS) revert FeeAboveCap(feeStartBps, MAX_START_FEE_BPS);
if (feeStartBps < feeEndBps) revert DecayGoesUp(feeStartBps, feeEndBps); // invariant 3
if (feeDurationSec > MAX_DECAY_SECONDS) revert DecayTooLong(feeDurationSec, MAX_DECAY_SECONDS); // invariant 3
if (feeDurationSec == 0 && feeStartBps != feeEndBps) revert DecayWithoutWindow();
if (sellLockSeconds > MAX_SELL_LOCK_SECONDS) revert SellLockTooLong(sellLockSeconds, MAX_SELL_LOCK_SECONDS); // invariant 4
uint40 nowTs = uint40(block.timestamp);
// Build in memory then store+emit from the struct (memory field reads,
// not 7 live stack params) to stay within stack depth without via-ir.
LaunchFeeConfig memory cfg = LaunchFeeConfig({
creator: creator,
launchedAt: nowTs,
sellLockUntil: sellLockSeconds == 0 ? 0 : nowTs + uint40(sellLockSeconds),
feeStartBps: feeStartBps,
feeEndBps: feeEndBps,
feeDurationSec: feeDurationSec,
locker: locker
});
_configs[poolId] = cfg;
emit LaunchRegistered(
poolId, cfg.creator, cfg.locker, cfg.feeStartBps, cfg.feeEndBps, cfg.feeDurationSec, cfg.sellLockUntil
);
}
// ---------- v4 hook callbacks ----------
/// Only the factory may attach this hook to a pool, the pool must be
/// registered first (same tx), and it must carry the dynamic-fee flag.
function beforeInitialize(address sender, PoolKey calldata key, uint160) external view returns (bytes4) {
if (msg.sender != address(poolManager)) revert NotPoolManager();
if (sender != factory) revert OnlyFactory();
if (_configs[key.toId()].launchedAt == 0) revert NotRegistered();
if (!key.fee.isDynamicFee()) revert NotDynamicFee();
return IHooks.beforeInitialize.selector;
}
/**
* BUY-side ETH-leg fee + creator sell-lock + LP-fee override to 0.
* - LP fee: forced to 0 (override flag), so the pool itself charges nothing
* and 100% of the trading fee is the hook's ETH-leg take.
* - Sell-lock: reverts sells (token in -> ETH out, i.e. !zeroForOne) whose
* tx.origin is the creator, inside the window (invariant 4: hardwired to
* the creator address; no other address can match).
* - Fee: on an exact-input BUY the hook mints `feeBps` of the ETH INPUT to
* the locker as an ERC-6909 native-ETH claim and returns it as the
* specified delta (invariant 5 — `feeBps` is direction-agnostic). The
* atomic factory dev-buy pays the settled base fee, not the t=0 anti-snipe
* fee (Flaunch precedent; only the factory can be `sender` and it only
* buys). Sells take their ETH-leg fee in `afterSwap` (ETH is the output).
*/
function beforeSwap(address sender, PoolKey calldata key, SwapParams calldata params, bytes calldata)
external
returns (bytes4, BeforeSwapDelta, uint24)
{
if (msg.sender != address(poolManager)) revert NotPoolManager();
LaunchFeeConfig storage cfg = _configs[key.toId()];
// sell-lock: a sell of the launch token is token->ETH, i.e. currency1
// in, i.e. zeroForOne == false (ETH is always currency0 on 4663).
if (
!params.zeroForOne && cfg.sellLockUntil != 0 && block.timestamp < cfg.sellLockUntil
&& tx.origin == cfg.creator
) {
revert CreatorSellLocked(cfg.sellLockUntil);
}
// ETH-leg fee is taken HERE whenever ETH (currency0) is the SPECIFIED
// currency, i.e. `zeroForOne == exactInput` — that is exact-input BUYS
// (ETH specified input) and exact-output SELLS (ETH specified output).
// In both, the ETH leg amount is |amountSpecified|, known now. The other
// two shapes (ETH unspecified) take the fee in afterSwap. The pool's own
// LP fee is always forced to 0 (override), so 100% of the fee is the hook
// take. `sender == factory` (the atomic dev-buy) still pays the settled
// base fee, not the t=0 anti-snipe fee (see _feeBpsFor).
bool exactInput = params.amountSpecified < 0;
bool ethIsSpecified = params.zeroForOne == exactInput;
uint256 ethLeg = exactInput ? uint256(-params.amountSpecified) : uint256(params.amountSpecified);
BeforeSwapDelta d = ethIsSpecified
? _takeSpecifiedEthFee(cfg, key.toId(), sender, ethLeg, params.zeroForOne, !exactInput)
: BeforeSwapDeltaLibrary.ZERO_DELTA;
return (IHooks.beforeSwap.selector, d, LPFeeLibrary.OVERRIDE_FEE_FLAG);
}
/// Take `feeBps` of the ETH leg when ETH is the SPECIFIED currency (exact-in
/// BUY: ETH input; exact-out SELL: ETH output). Mint an ERC-6909 native-ETH
/// claim to the locker and return the positive specified delta. On the
/// exact-in buy this reduces the amount the pool swaps (trader pays full
/// input, pool swaps input-minus-fee); on the exact-out sell it raises the
/// pool's ETH output to `ethOut + fee` and skims the fee back, so the seller
/// receives exactly the ETH they asked for. Either way the hook's mint debit
/// nets to zero against the specified-delta credit.
function _takeSpecifiedEthFee(
LaunchFeeConfig storage cfg,
PoolId poolId,
address sender,
uint256 ethLeg,
bool isBuy,
bool grossUp
) private returns (BeforeSwapDelta) {
uint16 bps = _feeBpsFor(cfg, sender);
uint256 fee = _feeAmount(ethLeg, bps, grossUp);
if (bps > 0 && fee == 0) revert FeeRoundsToZero();
poolManager.mint(cfg.locker, ETH_CLAIM_ID, fee);
emit EthFeeTaken(poolId, isBuy, fee, bps);
return toBeforeSwapDelta(int128(int256(fee)), int128(0));
}
/**
* ETH-leg fee for the swaps where ETH (currency0) is the UNSPECIFIED
* currency, i.e. `zeroForOne != exactInput` — exact-input SELL (ETH out) and
* exact-output BUY (ETH in). The ETH leg is only known now, as
* |delta.amount0()| (positive when the pool paid ETH out on a sell, negative
* when it pulled ETH in on an exact-output buy). The hook mints `feeBps` of
* it to the locker and returns the positive unspecified afterSwap delta, so
* the seller receives (grossEthOut - fee) and the exact-output buyer pays
* (grossEthIn + fee). The ETH-specified shapes already took their fee in
* beforeSwap, so they return 0 here.
*/
/// `public virtual` (not `external`): the Bonding stack's derived hook
/// (LittleJohnBondingHook) super-calls this then latches its graduation
/// milestone. Visibility-only change — logic and selector are identical,
/// and already-deployed instances are bytecode-frozen on chain regardless.
function afterSwap(
address sender,
PoolKey calldata key,
SwapParams calldata params,
BalanceDelta delta,
bytes calldata
) public virtual returns (bytes4, int128) {
if (msg.sender != address(poolManager)) revert NotPoolManager();
bool exactInput = params.amountSpecified < 0;
bool ethIsSpecified = params.zeroForOne == exactInput;
int128 fee = int128(0);
if (ethIsSpecified) {
_enforceSpecifiedFullFill(_configs[key.toId()], sender, params, delta);
} else {
int128 a0 = delta.amount0();
if (a0 != 0) {
fee = _takeUnspecifiedEthFee(
_configs[key.toId()], key.toId(), sender, _abs(a0), params.zeroForOne, !exactInput
);
}
}
return (IHooks.afterSwap.selector, fee);
}
/// Take `feeBps` of the ETH leg when ETH is the UNSPECIFIED currency: mint an
/// ERC-6909 native-ETH claim to the locker and return the positive
/// unspecified afterSwap delta. On a sell that reduces the seller's ETH
/// receipt by `fee`; on an exact-output buy it increases the buyer's ETH
/// payment by `fee`. The mint debit nets to zero against the returned credit.
function _takeUnspecifiedEthFee(
LaunchFeeConfig storage cfg,
PoolId poolId,
address sender,
uint256 ethLeg,
bool isBuy,
bool grossUp
) private returns (int128) {
uint16 bps = _feeBpsFor(cfg, sender);
uint256 fee = _feeAmount(ethLeg, bps, grossUp);
if (bps > 0 && fee == 0) revert FeeRoundsToZero();
poolManager.mint(cfg.locker, ETH_CLAIM_ID, fee);
emit EthFeeTaken(poolId, isBuy, fee, bps);
return int128(int256(fee));
}
function _feeAmount(uint256 ethLeg, uint16 bps, bool grossUp) private pure returns (uint256) {
if (bps == 0) return 0;
// Exact-output gross-up is the floor solution to
// fee = floor((netEth + fee) * bps / BPS_DENOMINATOR).
return
grossUp
? FullMath.mulDiv(ethLeg, bps, BPS_DENOMINATOR - bps)
: FullMath.mulDiv(ethLeg, bps, BPS_DENOMINATOR);
}
function _abs(int128 value) private pure returns (uint256) {
int256 widened = int256(value);
return uint256(widened < 0 ? -widened : widened);
}
function _enforceSpecifiedFullFill(
LaunchFeeConfig storage cfg,
address sender,
SwapParams calldata params,
BalanceDelta delta
) private view {
bool exactInput = params.amountSpecified < 0;
uint256 ethLeg = exactInput ? uint256(-params.amountSpecified) : uint256(params.amountSpecified);
uint256 specifiedFee = _feeAmount(ethLeg, _feeBpsFor(cfg, sender), !exactInput);
int256 expectedCoreEth = exactInput ? -int256(ethLeg - specifiedFee) : int256(ethLeg + specifiedFee);
if (int256(delta.amount0()) != expectedCoreEth) revert PartialFillUnsupported();
}
// ---------- fee curve (public so UI/indexer/tests share one source) ----------
/// The ETH-leg fee bps for a swap: the atomic factory dev-buy pays the
/// settled base fee; everyone else pays the live decay fee.
function _feeBpsFor(LaunchFeeConfig storage cfg, address sender) internal view returns (uint16) {
return sender == factory
? cfg.feeEndBps
: feeBpsAtElapsed(cfg.feeStartBps, cfg.feeEndBps, cfg.feeDurationSec, block.timestamp - cfg.launchedAt);
}
/**
* Solidity mirror of `feeAtElapsed` (packages/contract/src/schemas.ts):
* if (elapsedSec <= 0) return startBps;
* if (elapsedSec >= durationSec) return endBps;
* return Math.round(startBps + (endBps - startBps) * (elapsed / duration));
* JS Math.round(start - x) with integer `start` equals start - roundHalfDown(x)
* (Math.round rounds half toward +inf; the subtraction flips it), so the
* integer form is roundHalfDown(delta * elapsed / duration) with
* roundHalfDown(n/d) = (2n + d - 1) / (2d).
* durationSec == 0 means decay off -> always endBps (== startBps, enforced
* at register). Monotonically non-increasing for every valid config
* (invariant 3): delta >= 0 and reduction grows with elapsed.
*/
function feeBpsAtElapsed(uint16 startBps, uint16 endBps, uint32 durationSec, uint256 elapsedSec)
public
pure
returns (uint16)
{
if (durationSec == 0 || elapsedSec >= durationSec) return endBps;
if (elapsedSec == 0) return startBps;
uint256 delta = uint256(startBps) - uint256(endBps);
uint256 reduction = (2 * delta * elapsedSec + durationSec - 1) / (2 * uint256(durationSec));
return uint16(uint256(startBps) - reduction);
}
/// Live fee (bps) for a launch pool right now — the UI's snipe clock and the
/// exact rate the ETH-leg take uses for both buys and sells (invariant 5).
function currentFeeBps(PoolId poolId) external view returns (uint16) {
LaunchFeeConfig storage cfg = _configs[poolId];
if (cfg.launchedAt == 0) revert NotRegistered();
return feeBpsAtElapsed(cfg.feeStartBps, cfg.feeEndBps, cfg.feeDurationSec, block.timestamp - cfg.launchedAt);
}
function configOf(PoolId poolId) external view returns (LaunchFeeConfig memory) {
return _configs[poolId];
}
}[
{
"type": "constructor",
"inputs": [
{
"name": "poolManager_",
"type": "address",
"internalType": "contract IPoolManager"
},
{
"name": "factory_",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "nonpayable"
},
{
"name": "AlreadyRegistered",
"type": "error",
"inputs": []
},
{
"name": "CreatorSellLocked",
"type": "error",
"inputs": [
{
"name": "until",
"type": "uint40",
"internalType": "uint40"
}
]
},
{
"name": "DecayGoesUp",
"type": "error",
"inputs": [
{
"name": "startBps",
"type": "uint16",
"internalType": "uint16"
},
{
"name": "endBps",
"type": "uint16",
"internalType": "uint16"
}
]
},
{
"name": "DecayTooLong",
"type": "error",
"inputs": [
{
"name": "requested",
"type": "uint32",
"internalType": "uint32"
},
{
"name": "max",
"type": "uint32",
"internalType": "uint32"
}
]
},
{
"name": "DecayWithoutWindow",
"type": "error",
"inputs": []
},
{
"name": "FeeAboveCap",
"type": "error",
"inputs": [
{
"name": "requested",
"type": "uint16",
"internalType": "uint16"
},
{
"name": "cap",
"type": "uint16",
"internalType": "uint16"
}
]
},
{
"name": "FeeBelowFloor",
"type": "error",
"inputs": [
{
"name": "requested",
"type": "uint16",
"internalType": "uint16"
},
{
"name": "floor",
"type": "uint16",
"internalType": "uint16"
}
]
},
{
"name": "FeeRoundsToZero",
"type": "error",
"inputs": []
},
{
"name": "NotDynamicFee",
"type": "error",
"inputs": []
},
{
"name": "NotPoolManager",
"type": "error",
"inputs": []
},
{
"name": "NotRegistered",
"type": "error",
"inputs": []
},
{
"name": "OnlyFactory",
"type": "error",
"inputs": []
},
{
"name": "PartialFillUnsupported",
"type": "error",
"inputs": []
},
{
"name": "SellLockTooLong",
"type": "error",
"inputs": [
{
"name": "requested",
"type": "uint32",
"internalType": "uint32"
},
{
"name": "max",
"type": "uint32",
"internalType": "uint32"
}
]
},
{
"name": "ZeroCreator",
"type": "error",
"inputs": []
},
{
"name": "ZeroLocker",
"type": "error",
"inputs": []
},
{
"name": "EthFeeTaken",
"type": "event",
"inputs": [
{
"name": "poolId",
"type": "bytes32",
"indexed": true,
"internalType": "PoolId"
},
{
"name": "isBuy",
"type": "bool",
"indexed": true,
"internalType": "bool"
},
{
"name": "ethFee",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "feeBps",
"type": "uint16",
"indexed": false,
"internalType": "uint16"
}
],
"anonymous": false
},
{
"name": "LaunchRegistered",
"type": "event",
"inputs": [
{
"name": "poolId",
"type": "bytes32",
"indexed": true,
"internalType": "PoolId"
},
{
"name": "creator",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "locker",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "feeStartBps",
"type": "uint16",
"indexed": false,
"internalType": "uint16"
},
{
"name": "feeEndBps",
"type": "uint16",
"indexed": false,
"internalType": "uint16"
},
{
"name": "feeDurationSec",
"type": "uint32",
"indexed": false,
"internalType": "uint32"
},
{
"name": "sellLockUntil",
"type": "uint40",
"indexed": false,
"internalType": "uint40"
}
],
"anonymous": false
},
{
"name": "MAX_DECAY_SECONDS",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint32",
"internalType": "uint32"
}
],
"stateMutability": "view"
},
{
"name": "MAX_SELL_LOCK_SECONDS",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint32",
"internalType": "uint32"
}
],
"stateMutability": "view"
},
{
"name": "MAX_START_FEE_BPS",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint16",
"internalType": "uint16"
}
],
"stateMutability": "view"
},
{
"name": "MAX_STATIC_FEE_BPS",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint16",
"internalType": "uint16"
}
],
"stateMutability": "view"
},
{
"name": "MIN_STATIC_FEE_BPS",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint16",
"internalType": "uint16"
}
],
"stateMutability": "view"
},
{
"name": "afterSwap",
"type": "function",
"inputs": [
{
"name": "sender",
"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": "beforeInitialize",
"type": "function",
"inputs": [
{
"name": "sender",
"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": "",
"type": "uint160",
"internalType": "uint160"
}
],
"outputs": [
{
"name": "",
"type": "bytes4",
"internalType": "bytes4"
}
],
"stateMutability": "view"
},
{
"name": "beforeSwap",
"type": "function",
"inputs": [
{
"name": "sender",
"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": "configOf",
"type": "function",
"inputs": [
{
"name": "poolId",
"type": "bytes32",
"internalType": "PoolId"
}
],
"outputs": [
{
"name": "",
"type": "tuple",
"components": [
{
"name": "creator",
"type": "address",
"internalType": "address"
},
{
"name": "launchedAt",
"type": "uint40",
"internalType": "uint40"
},
{
"name": "sellLockUntil",
"type": "uint40",
"internalType": "uint40"
},
{
"name": "feeStartBps",
"type": "uint16",
"internalType": "uint16"
},
{
"name": "feeEndBps",
"type": "uint16",
"internalType": "uint16"
},
{
"name": "feeDurationSec",
"type": "uint32",
"internalType": "uint32"
},
{
"name": "locker",
"type": "address",
"internalType": "address"
}
],
"internalType": "struct LittleJohnHook.LaunchFeeConfig"
}
],
"stateMutability": "view"
},
{
"name": "currentFeeBps",
"type": "function",
"inputs": [
{
"name": "poolId",
"type": "bytes32",
"internalType": "PoolId"
}
],
"outputs": [
{
"name": "",
"type": "uint16",
"internalType": "uint16"
}
],
"stateMutability": "view"
},
{
"name": "factory",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "feeBpsAtElapsed",
"type": "function",
"inputs": [
{
"name": "startBps",
"type": "uint16",
"internalType": "uint16"
},
{
"name": "endBps",
"type": "uint16",
"internalType": "uint16"
},
{
"name": "durationSec",
"type": "uint32",
"internalType": "uint32"
},
{
"name": "elapsedSec",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "uint16",
"internalType": "uint16"
}
],
"stateMutability": "pure"
},
{
"name": "poolManager",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "contract IPoolManager"
}
],
"stateMutability": "view"
},
{
"name": "register",
"type": "function",
"inputs": [
{
"name": "poolId",
"type": "bytes32",
"internalType": "PoolId"
},
{
"name": "creator",
"type": "address",
"internalType": "address"
},
{
"name": "feeStartBps",
"type": "uint16",
"internalType": "uint16"
},
{
"name": "feeEndBps",
"type": "uint16",
"internalType": "uint16"
},
{
"name": "feeDurationSec",
"type": "uint32",
"internalType": "uint32"
},
{
"name": "sellLockSeconds",
"type": "uint32",
"internalType": "uint32"
},
{
"name": "locker",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
}
]0x608060405234801561000f575f5ffd5b50600436106100e5575f3560e01c8063c45a015511610088578063d281a8ba11610063578063d281a8ba14610386578063dc4c90d31461039b578063dc98354e146103c2578063e5b3af6114610406575f5ffd5b8063c45a015514610328578063c8040e6414610374578063d246637b1461037d575f5ffd5b8063836c336f116100c3578063836c336f1461029f578063a2267724146102b2578063b47b2fb1146102bb578063b53fa52514610309575f5ffd5b80631d8ef3ef146100e9578063575e24b4146101145780636ef616071461016a575b5f5ffd5b6100fc6100f736600461172b565b61040e565b60405161ffff90911681526020015b60405180910390f35b6101276101223660046117e1565b6104ea565b604080517fffffffff000000000000000000000000000000000000000000000000000000009094168452602084019290925262ffffff169082015260600161010b565b61029261017836600461172b565b6040805160e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152505f9081526020818152604091829020825160e081018452815473ffffffffffffffffffffffffffffffffffffffff808216835264ffffffffff74010000000000000000000000000000000000000000830481169584019590955279010000000000000000000000000000000000000000000000000082049094169482019490945261ffff7e0100000000000000000000000000000000000000000000000000000000000090940484166060820152600190910154928316608082015263ffffffff6201000084041660a082015266010000000000009092041660c082015290565b60405161010b9190611858565b6100fc6102ad366004611921565b610730565b6100fc6101f481565b6102ce6102c9366004611969565b6107e4565b604080517fffffffff000000000000000000000000000000000000000000000000000000009093168352600f9190910b60208301520161010b565b61031362278d0081565b60405163ffffffff909116815260200161010b565b61034f7f00000000000000000000000037978084bc37bc0e68f50f2be7213b94fefcd91681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010b565b6100fc610fa081565b610313610e1081565b6103996103943660046119ea565b610953565b005b61034f7f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e4095181565b6103d56103d0366004611a6a565b610faa565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161010b565b6100fc606481565b5f818152602081905260408120805474010000000000000000000000000000000000000000900464ffffffffff168203610474576040517faba4733900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805460018201546104e3917e01000000000000000000000000000000000000000000000000000000000000810461ffff90811692908116916201000090910463ffffffff16906102ad9074010000000000000000000000000000000000000000900464ffffffffff1642611ade565b9392505050565b5f80803373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e40951161461055c576040517fae18210a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8080610578610571368c90038c018c611b14565b60a0902090565b81526020808201929092526040015f20915061059690880188611bc7565b1580156105c757508054790100000000000000000000000000000000000000000000000000900464ffffffffff1615155b80156105f757508054790100000000000000000000000000000000000000000000000000900464ffffffffff1642105b80156106195750805473ffffffffffffffffffffffffffffffffffffffff1632145b1561067d5780546040517ffccb9d6e00000000000000000000000000000000000000000000000000000000815279010000000000000000000000000000000000000000000000000090910464ffffffffff1660048201526024015b60405180910390fd5b5f602088018035821391908290610694908b611bc7565b15151490505f826106a95789602001356106b6565b6106b660208b0135611be6565b90505f826106c4575f6106f7565b6106f7856106dc8e8036038101906105719190611b14565b8f858f5f0160208101906106f09190611bc7565b89156111a0565b7f575e24b4000000000000000000000000000000000000000000000000000000009e909d50624000009c509a5050505050505050505050565b5f63ffffffff8316158061074a57508263ffffffff168210155b156107565750826107dc565b815f036107645750836107dc565b5f61077661ffff808716908816611ade565b90505f61078a63ffffffff86166002611c1c565b600163ffffffff87168661079f866002611c1c565b6107a99190611c1c565b6107b39190611c33565b6107bd9190611ade565b6107c79190611c46565b90506107d78161ffff8916611ade565b925050505b949350505050565b5f803373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e409511614610855576040517fae18210a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60208701803582139190829061086c908a611bc7565b15151490505f81156108a9576108a45f8061088f610571368f90038f018f611b14565b81526020019081526020015f208c8b8b61130e565b610922565b5f6108b48960801d90565b905080600f0b5f146109205761091d5f5f6108d98e8036038101906105719190611b14565b81526020019081526020015f206108fa8d8036038101906105719190611b14565b8e610904856113c6565b8e5f0160208101906109169190611bc7565b89156113e2565b91505b505b7fb47b2fb1000000000000000000000000000000000000000000000000000000009b909a5098505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000037978084bc37bc0e68f50f2be7213b94fefcd91616146109c2576040517f0c6d42ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8616610a0f576040517f58f28cd400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116610a5c576040517f0628c7c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8781526020819052604090205474010000000000000000000000000000000000000000900464ffffffffff1615610ac0576040517f3a81d6fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606461ffff85161015610b0c576040517fa5ecb6a600000000000000000000000000000000000000000000000000000000815261ffff8516600482015260646024820152604401610674565b6101f461ffff85161115610b5a576040517f5ccbf4a500000000000000000000000000000000000000000000000000000000815261ffff851660048201526101f46024820152604401610674565b610fa061ffff86161115610ba8576040517f5ccbf4a500000000000000000000000000000000000000000000000000000000815261ffff86166004820152610fa06024820152604401610674565b8361ffff168561ffff161015610bf8576040517f5145779000000000000000000000000000000000000000000000000000000000815261ffff808716600483015285166024820152604401610674565b610e1063ffffffff84161115610c4a576040517f504d684e00000000000000000000000000000000000000000000000000000000815263ffffffff84166004820152610e106024820152604401610674565b63ffffffff8316158015610c6657508361ffff168561ffff1614155b15610c9d576040517f0849db0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62278d0063ffffffff83161115610cf1576040517fd2417da500000000000000000000000000000000000000000000000000000000815263ffffffff8316600482015262278d006024820152604401610674565b5f4290505f6040518060e001604052808973ffffffffffffffffffffffffffffffffffffffff1681526020018364ffffffffff1681526020018563ffffffff165f14610d4c57610d4763ffffffff871685611c7e565b610d4e565b5f5b64ffffffffff1681526020018861ffff1681526020018761ffff1681526020018663ffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff168152509050805f5f8b81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151815f0160146101000a81548164ffffffffff021916908364ffffffffff1602179055506040820151815f0160196101000a81548164ffffffffff021916908364ffffffffff1602179055506060820151815f01601e6101000a81548161ffff021916908361ffff1602179055506080820151816001015f6101000a81548161ffff021916908361ffff16021790555060a08201518160010160026101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160066101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508060c0015173ffffffffffffffffffffffffffffffffffffffff16815f015173ffffffffffffffffffffffffffffffffffffffff168a7fed2492da8add9b8989d638d4ce0547654d9757234bde28247b6eda82b3a412e0846060015185608001518660a001518760400151604051610f97949392919061ffff948516815292909316602083015263ffffffff16604082015264ffffffffff91909116606082015260800190565b60405180910390a4505050505050505050565b5f3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e40951161461101a576040517fae18210a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000037978084bc37bc0e68f50f2be7213b94fefcd91673ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161461109f576040517f0c6d42ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f806110b361057136879003870187611b14565b815260208101919091526040015f9081205474010000000000000000000000000000000000000000900464ffffffffff16900361111c576040517faba4733900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61114161112f6060850160408601611c9b565b62ffffff1662ffffff16628000001490565b611177576040517fcf587f1400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fdc98354e000000000000000000000000000000000000000000000000000000009392505050565b5f5f6111ac888761154d565b90505f6111ba868386611628565b90505f8261ffff161180156111cd575080155b15611204576040517f75e4ec8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018901546040517f156e29f6000000000000000000000000000000000000000000000000000000008152660100000000000090910473ffffffffffffffffffffffffffffffffffffffff90811660048301525f6024830152604482018390527f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e40951169063156e29f6906064015f604051808303815f87803b1580156112a7575f5ffd5b505af11580156112b9573d5f5f3e3d5ffd5b50506040805184815261ffff8616602082015288151593508b92507fe24de99d45e53bb15f2f041683ce976d9f01cc70b1cb688ecacd367c847eaf2a910160405180910390a360801b98975050505050505050565b5f602083013581139081611326578360200135611333565b6113336020850135611be6565b90505f61134b82611344898961154d565b8515611628565b90505f836113625761135d8284611c33565b611375565b61136c8284611ade565b61137590611be6565b9050806113828660801d90565b600f0b146113bc576040517fd39cf37700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050505050565b5f600f82900b8181126113d957806104e3565b6104e381611be6565b5f5f6113ee888761154d565b90505f6113fc868386611628565b90505f8261ffff1611801561140f575080155b15611446576040517f75e4ec8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018901546040517f156e29f6000000000000000000000000000000000000000000000000000000008152660100000000000090910473ffffffffffffffffffffffffffffffffffffffff90811660048301525f6024830152604482018390527f0000000000000000000000008366a39cc670b4001a1121b8f6a443a643e40951169063156e29f6906064015f604051808303815f87803b1580156114e9575f5ffd5b505af11580156114fb573d5f5f3e3d5ffd5b50506040805184815261ffff8616602082015288151593508b92507fe24de99d45e53bb15f2f041683ce976d9f01cc70b1cb688ecacd367c847eaf2a910160405180910390a398975050505050505050565b5f7f00000000000000000000000037978084bc37bc0e68f50f2be7213b94fefcd91673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146116155782546001840154611610917e01000000000000000000000000000000000000000000000000000000000000810461ffff90811692908116916201000090910463ffffffff16906102ad9074010000000000000000000000000000000000000000900464ffffffffff1642611ade565b61161f565b600183015461ffff165b90505b92915050565b5f8261ffff165f0361163b57505f6104e3565b81611656576116518461ffff8516612710611670565b6107dc565b6107dc8461ffff851661166b86612710611cb4565b61ffff165b5f838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709828110838203039150508084116116ae575f5ffd5b805f036116c0575082900490506104e3565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b5f6020828403121561173b575f5ffd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff81168114611763575f5ffd5b50565b803561177181611742565b919050565b5f60a08284031215611786575f5ffd5b50919050565b5f60608284031215611786575f5ffd5b5f5f83601f8401126117ac575f5ffd5b50813567ffffffffffffffff8111156117c3575f5ffd5b6020830191508360208285010111156117da575f5ffd5b9250929050565b5f5f5f5f5f61014086880312156117f6575f5ffd5b853561180181611742565b94506118108760208801611776565b935061181f8760c0880161178c565b925061012086013567ffffffffffffffff81111561183b575f5ffd5b6118478882890161179c565b969995985093965092949392505050565b5f60e08201905073ffffffffffffffffffffffffffffffffffffffff835116825264ffffffffff602084015116602083015264ffffffffff604084015116604083015261ffff606084015116606083015261ffff608084015116608083015260a08301516118ce60a084018263ffffffff169052565b5060c08301516118f660c084018273ffffffffffffffffffffffffffffffffffffffff169052565b5092915050565b803561ffff81168114611771575f5ffd5b803563ffffffff81168114611771575f5ffd5b5f5f5f5f60808587031215611934575f5ffd5b61193d856118fd565b935061194b602086016118fd565b92506119596040860161190e565b9396929550929360600135925050565b5f5f5f5f5f5f610160878903121561197f575f5ffd5b863561198a81611742565b95506119998860208901611776565b94506119a88860c0890161178c565b9350610120870135925061014087013567ffffffffffffffff8111156119cc575f5ffd5b6119d889828a0161179c565b979a9699509497509295939492505050565b5f5f5f5f5f5f5f60e0888a031215611a00575f5ffd5b873596506020880135611a1281611742565b9550611a20604089016118fd565b9450611a2e606089016118fd565b9350611a3c6080890161190e565b9250611a4a60a0890161190e565b915060c0880135611a5a81611742565b8091505092959891949750929550565b5f5f5f60e08486031215611a7c575f5ffd5b8335611a8781611742565b9250611a968560208601611776565b915060c0840135611aa681611742565b809150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8181038181111561162257611622611ab1565b803562ffffff81168114611771575f5ffd5b8035600281900b8114611771575f5ffd5b5f60a0828403128015611b25575f5ffd5b5060405160a0810167ffffffffffffffff81118282101715611b6e577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604052611b7a83611766565b8152611b8860208401611766565b6020820152611b9960408401611af1565b6040820152611baa60608401611b03565b6060820152611bbb60808401611766565b60808201529392505050565b5f60208284031215611bd7575f5ffd5b813580151581146104e3575f5ffd5b5f7f80000000000000000000000000000000000000000000000000000000000000008203611c1657611c16611ab1565b505f0390565b808202811582820484141761162257611622611ab1565b8082018082111561162257611622611ab1565b5f82611c79577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b64ffffffffff818116838216019081111561162257611622611ab1565b5f60208284031215611cab575f5ffd5b61161f82611af1565b61ffff828116828216039081111561162257611622611ab156fea2646970667358221220de6163a7a34cabe6bd0387dff9999347fae2d12e720b48634cb0e14266efd33964736f6c634300081c0033
| Token | Symbol | Balance | Price | Value |
|---|---|---|---|---|
| no token holdings | ||||
| Transaction Hash | Method | Block | Age | From | To | Type | Item | ||
|---|---|---|---|---|---|---|---|---|---|
| no NFT transfers for this address yet | |||||||||
| Txn Hash | Age | Event | Topics / Data |
|---|---|---|---|
| 0x89fb3b…7c2472 | 12 days agoWed, 05 Aug 2026 06:35:55 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x275d47…ff4f9c | 16 days agoSat, 01 Aug 2026 06:52:33 UTC | 0xe24de9…af2a | [0] 0xb45cd346e2a4…cbb4ce34 [1] 0x000000000000…00000000 data: 0x000000000000000000…000000c8 |
| 0x23a77d…10d914 | 17 days agoFri, 31 Jul 2026 20:55:49 UTC | 0xe24de9…af2a | [0] 0xb45cd346e2a4…cbb4ce34 [1] 0x000000000000…00000000 data: 0x000000000000000000…000000c8 |
| 0x8456fe…e85794 | 20 days agoTue, 28 Jul 2026 22:05:59 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x5925d6…fe0ed9 | 20 days agoTue, 28 Jul 2026 15:49:55 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x70133b…206ffb | 20 days agoTue, 28 Jul 2026 04:38:14 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0xc41a0d…48229c | 23 days agoSat, 25 Jul 2026 08:08:23 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x03545a…d020f0 | 24 days agoSat, 25 Jul 2026 03:00:34 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x87f6ba…e5f5de | 24 days agoFri, 24 Jul 2026 15:51:27 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000001 data: 0x000000000000000000…00000064 |
| 0x705d07…7b3e24 | 25 days agoFri, 24 Jul 2026 01:54:53 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x4acece…24efdf | 25 days agoThu, 23 Jul 2026 15:34:55 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x617a31…4fc736 | 25 days agoThu, 23 Jul 2026 15:20:15 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0xce371e…503a91 | 25 days agoThu, 23 Jul 2026 07:10:56 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x29d53c…c9d6b8 | 25 days agoThu, 23 Jul 2026 06:03:18 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x4efb1e…0d0cf4 | 26 days agoWed, 22 Jul 2026 22:46:15 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0xc48eb1…14f742 | 26 days agoWed, 22 Jul 2026 22:46:15 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0xbf3d57…3c24d8 | 26 days agoWed, 22 Jul 2026 22:42:58 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x473492…291d4d | 26 days agoWed, 22 Jul 2026 22:42:58 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x25703e…27b187 | 26 days agoWed, 22 Jul 2026 14:26:20 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x90105d…d63bb9 | 26 days agoWed, 22 Jul 2026 14:24:50 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0xe315a2…b6b05b | 26 days agoWed, 22 Jul 2026 14:24:50 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0xc2dcae…8708d0 | 26 days agoWed, 22 Jul 2026 14:24:50 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x896ca4…67a656 | 26 days agoWed, 22 Jul 2026 09:50:45 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| 0x88ddb5…54f5e2 | 26 days agoWed, 22 Jul 2026 09:46:54 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000001 data: 0x000000000000000000…00000064 |
| 0x9b98c4…3922e2 | 26 days agoWed, 22 Jul 2026 09:32:08 UTC | 0xe24de9…af2a | [0] 0xd5cd5f376a34…3236574b [1] 0x000000000000…00000000 data: 0x000000000000000000…00000064 |
| Transaction Hash | Method | Block | Age | From | To | Amount | Token | ||
|---|---|---|---|---|---|---|---|---|---|
| no token transfers for this address yet | |||||||||
| Type | Age | Block | Details |
|---|---|---|---|
| no cross-chain L1↔L2 transactions for this address | |||
| Transaction Hash | Method ? | Block | Age | From | To | Amount | Txn Fee ? | ||
|---|---|---|---|---|---|---|---|---|---|
| No direct transactions — this address is only ever reached via internal calls (common for a contract only invoked through a router or proxy). View Internal Transactions → | |||||||||
| Block | Age | Parent Transaction Hash | Type | Method | From | To | Value | |
|---|---|---|---|---|---|---|---|---|
| 7,176,415 | 37 days agoSat, 11 Jul 2026 18:58:11 UTC | 0xadba78…ae04ed | CREATE2 | 0x61016060 | 0x3797…d916 | IN | 0x2373…60cc | 0 ETH |