ETH Price: $3,042.77 (+1.99%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Execute Buyback241339162025-12-31 16:51:1143 hrs ago1767199871IN
0x5d966451...C0ea940cc
0 ETH0.000299392.03688885
Configure Snowba...241302762025-12-31 4:39:232 days ago1767155963IN
0x5d966451...C0ea940cc
0 ETH0.000001020.0268372
Execute Buyback241275832025-12-30 19:37:472 days ago1767123467IN
0x5d966451...C0ea940cc
0 ETH0.000301212.03688885
Execute Buyback241229472025-12-30 4:03:233 days ago1767067403IN
0x5d966451...C0ea940cc
0 ETH0.000300232.03065688
Execute Buyback241223682025-12-30 2:06:353 days ago1767060395IN
0x5d966451...C0ea940cc
0 ETH0.000300742.03274431
Execute Buyback241204482025-12-29 19:40:113 days ago1767037211IN
0x5d966451...C0ea940cc
0 ETH0.000301292.03688885
Execute Buyback241184602025-12-29 12:59:353 days ago1767013175IN
0x5d966451...C0ea940cc
0 ETH0.000301222.03688885
Execute Buyback241179412025-12-29 11:15:474 days ago1767006947IN
0x5d966451...C0ea940cc
0 ETH0.000300962.03688885
Execute Buyback241178682025-12-29 11:00:594 days ago1767006059IN
0x5d966451...C0ea940cc
0 ETH0.000299392.03688885
Execute Buyback241174122025-12-29 9:29:354 days ago1767000575IN
0x5d966451...C0ea940cc
0 ETH0.000087620.59293953
Execute Buyback241159172025-12-29 4:29:234 days ago1766982563IN
0x5d966451...C0ea940cc
0 ETH0.000299392.03688885
Execute Buyback241148162025-12-29 0:48:114 days ago1766969291IN
0x5d966451...C0ea940cc
0 ETH0.000301332.03550719
Execute Buyback241147172025-12-29 0:28:234 days ago1766968103IN
0x5d966451...C0ea940cc
0 ETH0.000301282.03688885
Execute Buyback241145542025-12-28 23:55:234 days ago1766966123IN
0x5d966451...C0ea940cc
0 ETH0.000301222.03688885
Execute Buyback241142202025-12-28 22:48:234 days ago1766962103IN
0x5d966451...C0ea940cc
0 ETH0.000300342.03189481
Execute Buyback241141492025-12-28 22:33:594 days ago1766961239IN
0x5d966451...C0ea940cc
0 ETH0.000299952.02787678
Execute Buyback241118422025-12-28 14:51:114 days ago1766933471IN
0x5d966451...C0ea940cc
0 ETH0.000301162.03688885
Configure Snowba...241086462025-12-28 4:09:355 days ago1766894975IN
0x5d966451...C0ea940cc
0 ETH0.000001050.02763935
Execute Buyback241083012025-12-28 3:00:235 days ago1766890823IN
0x5d966451...C0ea940cc
0 ETH0.000299372.02533344
Execute Buyback241082062025-12-28 2:41:115 days ago1766889671IN
0x5d966451...C0ea940cc
0 ETH0.000300122.02859612
Execute Buyback241070152025-12-27 22:41:355 days ago1766875295IN
0x5d966451...C0ea940cc
0 ETH0.000300352.03103875
Execute Buyback240984612025-12-26 18:01:356 days ago1766772095IN
0x5d966451...C0ea940cc
0 ETH0.000300492.03247631
Execute Buyback240967942025-12-26 12:26:236 days ago1766751983IN
0x5d966451...C0ea940cc
0 ETH0.000299912.02808766
Execute Buyback240964322025-12-26 11:13:357 days ago1766747615IN
0x5d966451...C0ea940cc
0 ETH0.000299892.02876978
Set Platform Fee...240961582025-12-26 10:18:357 days ago1766744315IN
0x5d966451...C0ea940cc
0 ETH0.000002880.09310272
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x60c03462240940152025-12-26 3:07:477 days ago1766718467  Contract Creation0 ETH
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SnowballHookV2

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 100 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../interfaces/IPoolManager.sol";
import "../interfaces/IHooks.sol";
import "../interfaces/ICurrency.sol";
import "../interfaces/IUnlockCallback.sol";

/**
 * @title SnowballHookV2
 * @notice Uniswap V4 hook with buy/sell taxes, buyback/burn, and platform fees
 * 
 * Tax Collection Strategy:
 * - For BUYS (WETH → Token): Take WETH fee during beforeSwap
 * - For SELLS (Token → WETH): Track WETH fee during afterSwap
 * 
 * Fee Distribution on Buyback:
 * - 20% of collected fees → Platform fee collector (in WETH) [default, adjustable by controller]
 * - 80% of collected fees → Buyback and burn tokens
 * 
 * Tax Limits:
 * - Max buy tax: 15% (1500 bps)
 * - Max sell tax: 15% (1500 bps)
 * - Platform fee: 0-50% of collected tax (adjustable by controller only)
 * 
 * Required hook flags: 0x00CC
 * - beforeSwap = 0x0080 (bit 7)
 * - afterSwap = 0x0040 (bit 6)
 * - beforeSwapReturnDelta = 0x0008 (bit 3)
 * - afterSwapReturnDelta = 0x0004 (bit 2)
 * 
 * TAX APPROACH:
 * - BUY: Take WETH fee in beforeSwap (from input)
 * - SELL: Take WETH fee in afterSwap (from output) - user receives WETH minus tax
 */
contract SnowballHookV2 is IHooks, IUnlockCallback {
    using SafeERC20 for IERC20;
    using CurrencyLibrary for Currency;

    // ============================================================
    // CONSTANTS
    // ============================================================
    
    uint256 public constant FEE_DENOMINATOR = 10000;
    uint256 public constant MAX_TAX_BPS = 1500; // Max 15% buy/sell tax
    uint256 public constant MAX_PLATFORM_FEE_BPS = 5000; // Max 50% of fees to platform
    
    // ============================================================
    // STATE
    // ============================================================
    
    address public immutable poolManager;
    address public immutable weth;
    address public controller;
    address public platformFeeCollector;
    address public factory; // Factory can auto-configure snowball for new tokens
    uint256 public platformFeeBps; // Platform's share of collected fees (default 10%)
    
    struct TaxConfig {
        uint16 buyTaxBps;       // Tax on buys (0-15%)
        uint16 sellTaxBps;      // Tax on sells (0-15%)
        uint256 threshold;       // WETH threshold for buyback
        uint256 accumulated;     // WETH accumulated (total)
        address tokenAddress;    // Token being traded
        bool enabled;
    }
    
    mapping(bytes32 => TaxConfig) public taxConfigs;
    
    uint256 public totalBuybacks;
    uint256 public totalBurned;
    uint256 public totalPlatformFees; // Total WETH sent to platform
    
    // Track pending sell tax to apply in afterSwap (legacy, now unused)
    mapping(bytes32 => uint256) private pendingSellTax;
    
    // Track accumulated token fees from sells (to be converted to WETH during buyback)
    mapping(bytes32 => uint256) public tokenFeesAccumulated;
    
    // ============================================================
    // EVENTS
    // ============================================================
    
    event TaxTaken(bytes32 indexed poolId, uint256 amount, bool isBuy);
    event BuybackExecuted(bytes32 indexed poolId, uint256 wethSpent, uint256 tokensBurned);
    event PlatformFeeSent(bytes32 indexed poolId, uint256 wethAmount, address recipient);
    event TokensConvertedToWeth(bytes32 indexed poolId, uint256 tokensSpent, uint256 wethReceived);
    event ThresholdReached(bytes32 indexed poolId, uint256 accumulated);
    event PlatformFeeCollectorUpdated(address oldCollector, address newCollector);
    event PlatformFeeBpsUpdated(uint256 oldBps, uint256 newBps);
    
    // ============================================================
    // ERRORS
    // ============================================================
    
    error NotPoolManager();
    error NotController();
    error InvalidTax();
    error InvalidThreshold();
    error InvalidAddress();
    error InvalidPlatformFee();
    
    // ============================================================
    // CONSTRUCTOR
    // ============================================================
    
    constructor(address _poolManager, address _weth, address _controller, address _platformFeeCollector) {
        poolManager = _poolManager;
        weth = _weth;
        controller = _controller;
        platformFeeCollector = _platformFeeCollector;
        platformFeeBps = 2000; // Default 20% of fees to platform
    }
    
    // ============================================================
    // ADMIN FUNCTIONS
    // ============================================================
    
    function configureSnowball(
        bytes32 poolId,
        address tokenAddress,
        uint16 buyTaxBps,
        uint16 sellTaxBps,
        uint256 threshold
    ) external {
        // Allow both controller and factory to configure
        if (msg.sender != controller && msg.sender != factory) revert NotController();
        if (buyTaxBps > MAX_TAX_BPS) revert InvalidTax();
        if (sellTaxBps > MAX_TAX_BPS) revert InvalidTax();
        if (threshold == 0) revert InvalidThreshold();
        
        taxConfigs[poolId] = TaxConfig({
            buyTaxBps: buyTaxBps,
            sellTaxBps: sellTaxBps,
            threshold: threshold,
            accumulated: taxConfigs[poolId].accumulated,
            tokenAddress: tokenAddress,
            enabled: true
        });
    }
    
    function updateTaxRates(bytes32 poolId, uint16 buyTaxBps, uint16 sellTaxBps) external {
        if (msg.sender != controller) revert NotController();
        if (buyTaxBps > MAX_TAX_BPS) revert InvalidTax();
        if (sellTaxBps > MAX_TAX_BPS) revert InvalidTax();
        
        taxConfigs[poolId].buyTaxBps = buyTaxBps;
        taxConfigs[poolId].sellTaxBps = sellTaxBps;
    }
    
    function setEnabled(bytes32 poolId, bool enabled) external {
        if (msg.sender != controller) revert NotController();
        taxConfigs[poolId].enabled = enabled;
    }
    
    function setController(address newController) external {
        if (msg.sender != controller) revert NotController();
        if (newController == address(0)) revert InvalidAddress();
        controller = newController;
    }
    
    function setFactory(address newFactory) external {
        if (msg.sender != controller) revert NotController();
        factory = newFactory;
    }
    
    function setPlatformFeeCollector(address newCollector) external {
        if (msg.sender != controller) revert NotController();
        if (newCollector == address(0)) revert InvalidAddress();
        address oldCollector = platformFeeCollector;
        platformFeeCollector = newCollector;
        emit PlatformFeeCollectorUpdated(oldCollector, newCollector);
    }
    
    /**
     * @notice Update the platform fee percentage
     * @param newPlatformFeeBps New platform fee in basis points (0-5000, i.e., 0-50%)
     * @dev Only callable by controller. Max 50% to ensure buyback always has funds.
     */
    function setPlatformFeeBps(uint256 newPlatformFeeBps) external {
        if (msg.sender != controller) revert NotController();
        if (newPlatformFeeBps > MAX_PLATFORM_FEE_BPS) revert InvalidPlatformFee();
        uint256 oldBps = platformFeeBps;
        platformFeeBps = newPlatformFeeBps;
        emit PlatformFeeBpsUpdated(oldBps, newPlatformFeeBps);
    }
    
    // ============================================================
    // HOOK PERMISSIONS - Must match address flags 0x00C8
    // ============================================================
    
    function getHookPermissions() external pure returns (Hooks.Permissions memory) {
        return Hooks.Permissions({
            beforeInitialize: false,
            afterInitialize: false,
            beforeAddLiquidity: false,
            afterAddLiquidity: false,
            beforeRemoveLiquidity: false,
            afterRemoveLiquidity: false,
            beforeSwap: true,           // Take WETH fee on buys
            afterSwap: true,            // Track WETH fee on sells
            beforeDonate: false,
            afterDonate: false,
            beforeSwapReturnDelta: true,  // Return delta for buy fee
            afterSwapReturnDelta: true,   // Return delta for sell fee (take WETH from output)
            afterAddLiquidityReturnDelta: false,
            afterRemoveLiquidityReturnDelta: false
        });
    }
    
    // ============================================================
    // HOOK CALLBACKS
    // ============================================================
    
    function beforeInitialize(address, PoolKey calldata, uint160) external pure returns (bytes4) {
        return IHooks.beforeInitialize.selector;
    }
    
    function afterInitialize(address, PoolKey calldata, uint160, int24) external pure returns (bytes4) {
        return IHooks.afterInitialize.selector;
    }
    
    function beforeAddLiquidity(address, PoolKey calldata, ModifyLiquidityParams calldata, bytes calldata) 
        external pure returns (bytes4) 
    {
        return IHooks.beforeAddLiquidity.selector;
    }
    
    function afterAddLiquidity(address, PoolKey calldata, ModifyLiquidityParams calldata, BalanceDelta, BalanceDelta, bytes calldata) 
        external pure returns (bytes4, BalanceDelta) 
    {
        return (IHooks.afterAddLiquidity.selector, BalanceDelta.wrap(0));
    }
    
    function beforeRemoveLiquidity(address, PoolKey calldata, ModifyLiquidityParams calldata, bytes calldata) 
        external pure returns (bytes4) 
    {
        return IHooks.beforeRemoveLiquidity.selector;
    }
    
    function afterRemoveLiquidity(address, PoolKey calldata, ModifyLiquidityParams calldata, BalanceDelta, BalanceDelta, bytes calldata) 
        external pure returns (bytes4, BalanceDelta) 
    {
        return (IHooks.afterRemoveLiquidity.selector, BalanceDelta.wrap(0));
    }
    
    /**
     * @notice Called BEFORE each swap - take fee on BOTH buys and sells
     * 
     * For buys (WETH → Token): Take WETH fee from input
     * For sells (Token → WETH): Take token fee from input, store for later WETH conversion
     */
    function beforeSwap(
        address,
        PoolKey calldata key,
        SwapParams calldata params,
        bytes calldata
    ) external returns (bytes4, BeforeSwapDelta, uint24) {
        if (msg.sender != poolManager) revert NotPoolManager();
        
        bytes32 poolId = _getPoolId(key);
        TaxConfig storage config = taxConfigs[poolId];
        
        if (!config.enabled) {
            return (IHooks.beforeSwap.selector, BeforeSwapDelta.wrap(0), 0);
        }
        
        // Determine trade direction
        address currency1Addr = Currency.unwrap(key.currency1);
        bool wethIsCurrency1 = currency1Addr == weth;
        
        // Determine if this is a buy or sell
        bool isBuy;
        if (wethIsCurrency1) {
            isBuy = !params.zeroForOne;
        } else {
            isBuy = params.zeroForOne;
        }
        
        if (isBuy) {
            // BUY: WETH → Token - Take WETH fee now
            uint16 taxBps = config.buyTaxBps;
            if (taxBps == 0) {
                return (IHooks.beforeSwap.selector, BeforeSwapDelta.wrap(0), 0);
            }
            
            // Get WETH amount being spent
            uint256 wethAmount;
            if (params.amountSpecified < 0) {
                wethAmount = uint256(uint128(-int128(params.amountSpecified)));
            } else {
                wethAmount = uint256(uint128(int128(params.amountSpecified)));
            }
            
            uint256 feeAmount = (wethAmount * taxBps) / FEE_DENOMINATOR;
            
            if (feeAmount > 0) {
                Currency wethCurrency = wethIsCurrency1 ? key.currency1 : key.currency0;
                
                // Take WETH to this contract
                IPoolManager(poolManager).take(wethCurrency, address(this), feeAmount);
                
                config.accumulated += feeAmount;
                emit TaxTaken(poolId, feeAmount, true);
                
                // Return delta: caller pays more
                bool exactInput = params.amountSpecified < 0;
                int128 specifiedDelta = exactInput ? int128(uint128(feeAmount)) : int128(0);
                int128 unspecifiedDelta = exactInput ? int128(0) : int128(uint128(feeAmount));
                
                BeforeSwapDelta hookDelta = BeforeSwapDelta.wrap(
                    int256(int128(specifiedDelta)) << 128 | int256(int128(unspecifiedDelta))
                );
                
                return (IHooks.beforeSwap.selector, hookDelta, 0);
            }
        }
        // SELL: Handled in afterSwap - we take WETH from the output
        
        return (IHooks.beforeSwap.selector, BeforeSwapDelta.wrap(0), 0);
    }
    
    /**
     * @notice Called AFTER each swap - collect sell tax from WETH output
     * 
     * For sells (Token → WETH):
     * - Calculate the WETH the user would receive
     * - Take X% as tax (collected as WETH)
     * - Return positive delta to reduce user's WETH output
     */
    function afterSwap(
        address,
        PoolKey calldata key,
        SwapParams calldata params,
        BalanceDelta delta,
        bytes calldata
    ) external returns (bytes4, int128) {
        if (msg.sender != poolManager) revert NotPoolManager();
        
        bytes32 poolId = _getPoolId(key);
        TaxConfig storage config = taxConfigs[poolId];
        
        if (!config.enabled) {
            return (IHooks.afterSwap.selector, 0);
        }
        
        // Determine trade direction
        address currency1Addr = Currency.unwrap(key.currency1);
        bool wethIsCurrency1 = currency1Addr == weth;
        
        // Determine if this is a sell (Token → WETH)
        bool isSell;
        if (wethIsCurrency1) {
            isSell = params.zeroForOne; // Selling token0 for token1 (WETH)
        } else {
            isSell = !params.zeroForOne; // Selling token1 for token0 (WETH)
        }
        
        int128 hookDelta = 0;
        
        if (isSell && config.sellTaxBps > 0) {
            // Calculate WETH output from the swap
            // delta represents changes from the swap caller's (swapper's) perspective
            // For a sell, they receive WETH so WETH delta should be positive for them
            int128 amount0 = int128(int256(BalanceDelta.unwrap(delta)) >> 128);
            int128 amount1 = int128(int256(BalanceDelta.unwrap(delta)));
            
            // WETH delta: positive means swapper receives WETH
            int128 wethDelta = wethIsCurrency1 ? amount1 : amount0;
            
            // Check both positive and negative - try to understand the actual output
            uint256 wethOutput;
            if (wethDelta > 0) {
                // Positive: swapper is receiving WETH 
                wethOutput = uint256(uint128(wethDelta));
            } else if (wethDelta < 0) {
                // Negative: this shouldn't happen for a sell, but handle it
                wethOutput = uint256(uint128(-wethDelta));
            } else {
                wethOutput = 0;
            }
            
            if (wethOutput > 0) {
                uint256 feeAmount = (wethOutput * config.sellTaxBps) / FEE_DENOMINATOR;
                
                if (feeAmount > 0) {
                    // Take WETH to this contract
                    Currency wethCurrency = wethIsCurrency1 ? key.currency1 : key.currency0;
                    IPoolManager(poolManager).take(wethCurrency, address(this), feeAmount);
                    
                    // Add to accumulated WETH (same as buy tax)
                    config.accumulated += feeAmount;
                    emit TaxTaken(poolId, feeAmount, false);
                    
                    // Return positive delta = user receives less WETH (reduces their output)
                    hookDelta = int128(uint128(feeAmount));
                }
            }
        }
        
        // Check threshold for buyback
        if (config.accumulated >= config.threshold) {
            emit ThresholdReached(poolId, config.accumulated);
        }
        
        return (IHooks.afterSwap.selector, hookDelta);
    }
    
    function beforeDonate(address, PoolKey calldata, uint256, uint256, bytes calldata) 
        external pure returns (bytes4) 
    {
        return IHooks.beforeDonate.selector;
    }
    
    function afterDonate(address, PoolKey calldata, uint256, uint256, bytes calldata) 
        external pure returns (bytes4) 
    {
        return IHooks.afterDonate.selector;
    }
    
    // ============================================================
    // BUYBACK FUNCTIONS
    // ============================================================
    
    /**
     * @notice Execute buyback and burn, sending platform fee first
     * @dev Can be called by anyone when threshold is met
     * 
     * Flow:
     * 1. First convert any accumulated tokens (from sells) to WETH
     * 2. Calculate platform fee from total WETH
     * 3. Send platform fee to collector
     * 4. Use remaining WETH to buyback tokens
     * 5. Burn the purchased tokens
     */
    function executeBuyback(PoolKey calldata key) external {
        bytes32 poolId = _getPoolId(key);
        TaxConfig storage config = taxConfigs[poolId];
        
        require(config.enabled, "Not enabled");
        
        // All taxes (buy and sell) are now collected as WETH directly
        // Check threshold on WETH accumulated
        require(config.accumulated >= config.threshold, "Threshold not reached");
        
        // Get actual WETH balance in this contract
        uint256 wethBalance = IERC20(weth).balanceOf(address(this));
        require(wethBalance > 0, "No WETH to buyback");
        
        uint256 totalAmount = wethBalance < config.accumulated ? wethBalance : config.accumulated;
        config.accumulated = config.accumulated > totalAmount ? config.accumulated - totalAmount : 0;
        
        // Calculate platform fee (adjustable, default 20% of total)
        uint256 platformFee = (totalAmount * platformFeeBps) / FEE_DENOMINATOR;
        uint256 buybackAmount = totalAmount - platformFee;
        
        // Send platform fee to collector
        if (platformFee > 0 && platformFeeCollector != address(0)) {
            IERC20(weth).safeTransfer(platformFeeCollector, platformFee);
            totalPlatformFees += platformFee;
            emit PlatformFeeSent(poolId, platformFee, platformFeeCollector);
        }
        
        // Execute buyback with remaining amount
        if (buybackAmount > 0) {
            // Approve PoolManager
            IERC20(weth).approve(poolManager, buybackAmount);
            
            // Execute buyback via unlock
            bytes memory data = abi.encode(key, buybackAmount, config.tokenAddress, poolId);
            IPoolManager(poolManager).unlock(data);
        }
    }
    
    function unlockCallback(bytes calldata data) external override returns (bytes memory) {
        require(msg.sender == poolManager, "Not PoolManager");
        
        (PoolKey memory key, uint256 buybackAmount, address tokenAddress, bytes32 poolId) = 
            abi.decode(data, (PoolKey, uint256, address, bytes32));
        
        // Determine currencies
        address currency1Addr = Currency.unwrap(key.currency1);
        bool wethIsCurrency1 = currency1Addr == weth;
        Currency wethCurrency = wethIsCurrency1 ? key.currency1 : key.currency0;
        Currency tokenCurrency = wethIsCurrency1 ? key.currency0 : key.currency1;
        
        // BUYBACK MODE: Buy tokens with WETH and burn
        // zeroForOne = true if buying token0 with token1 (WETH)
        bool zeroForOne = !wethIsCurrency1;
        
        SwapParams memory swapParams = SwapParams({
            zeroForOne: zeroForOne,
            amountSpecified: -int256(buybackAmount), // Exact input (WETH)
            sqrtPriceLimitX96: zeroForOne ? 4295128740 : 1461446703485210103287273052203988822378723970341
        });
        
        BalanceDelta swapDelta = IPoolManager(poolManager).swap(key, swapParams, "");
        
        // Calculate tokens received
        int128 amount0 = int128(int256(BalanceDelta.unwrap(swapDelta)) >> 128);
        int128 amount1 = int128(int256(BalanceDelta.unwrap(swapDelta)));
        int128 tokenDelta = wethIsCurrency1 ? amount0 : amount1;
        uint256 tokensReceived = tokenDelta > 0 ? uint256(uint128(tokenDelta)) : 0;
        
        // Settle WETH (we owe to the pool)
        IPoolManager(poolManager).sync(wethCurrency);
        IERC20(weth).transfer(poolManager, buybackAmount);
        IPoolManager(poolManager).settle();
        
        // Take tokens and burn
        if (tokensReceived > 0) {
            IPoolManager(poolManager).take(tokenCurrency, address(this), tokensReceived);
            
            // Burn by sending to dead address
            IERC20(tokenAddress).transfer(address(0xdead), tokensReceived);
            totalBurned += tokensReceived;
        }
        
        totalBuybacks++;
        emit BuybackExecuted(poolId, buybackAmount, tokensReceived);
        
        return "";
    }
    
    // ============================================================
    // VIEW FUNCTIONS
    // ============================================================
    
    function getPoolId(PoolKey calldata key) external pure returns (bytes32) {
        return _getPoolId(key);
    }
    
    function _getPoolId(PoolKey calldata key) internal pure returns (bytes32) {
        return keccak256(abi.encode(
            Currency.unwrap(key.currency0),
            Currency.unwrap(key.currency1),
            key.fee,
            key.tickSpacing,
            address(key.hooks)
        ));
    }
    
    function getAccumulated(bytes32 poolId) external view returns (uint256) {
        return taxConfigs[poolId].accumulated;
    }
    
    function isThresholdReached(bytes32 poolId) external view returns (bool) {
        return taxConfigs[poolId].accumulated >= taxConfigs[poolId].threshold;
    }
    
    function getWethBalance() external view returns (uint256) {
        return IERC20(weth).balanceOf(address(this));
    }
    
    function getPlatformFeeCollector() external view returns (address) {
        return platformFeeCollector;
    }
    
    function getTotalPlatformFees() external view returns (uint256) {
        return totalPlatformFees;
    }
    
    function getPlatformFeeBps() external view returns (uint256) {
        return platformFeeBps;
    }
    
    receive() external payable {}
}

// ============================================================
// HOOKS LIBRARY
// ============================================================

library Hooks {
    struct Permissions {
        bool beforeInitialize;
        bool afterInitialize;
        bool beforeAddLiquidity;
        bool afterAddLiquidity;
        bool beforeRemoveLiquidity;
        bool afterRemoveLiquidity;
        bool beforeSwap;
        bool afterSwap;
        bool beforeDonate;
        bool afterDonate;
        bool beforeSwapReturnDelta;
        bool afterSwapReturnDelta;
        bool afterAddLiquidityReturnDelta;
        bool afterRemoveLiquidityReturnDelta;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)

pragma solidity >=0.6.2;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

File 3 of 11 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

import {IERC165} from "../utils/introspection/IERC165.sol";

File 4 of 11 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)

pragma solidity >=0.4.16;

import {IERC20} from "../token/ERC20/IERC20.sol";

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// Qian Exchange - https://qian.ag
pragma solidity ^0.8.24;

/// @notice Currency type for Uniswap V4
/// Wraps an address to represent a token or native ETH
type Currency is address;

/// @notice Currency library for V4
library CurrencyLibrary {
    /// @notice Wrap an address as Currency
    function wrap(address token) internal pure returns (Currency) {
        return Currency.wrap(token);
    }
    
    /// @notice Unwrap Currency to address
    function unwrap(Currency currency) internal pure returns (address) {
        return Currency.unwrap(currency);
    }
    
    /// @notice Native ETH currency
    function native() internal pure returns (Currency) {
        return Currency.wrap(address(0));
    }
    
    /// @notice Check if currency is native ETH
    function isNative(Currency currency) internal pure returns (bool) {
        return Currency.unwrap(currency) == address(0);
    }
}

// SPDX-License-Identifier: MIT
// Qian Exchange - https://qian.ag
pragma solidity ^0.8.24;

import "./IPoolManager.sol";

/// @notice Swap parameters for hook callbacks
struct SwapParams {
    bool zeroForOne;
    int256 amountSpecified;
    uint160 sqrtPriceLimitX96;
}

/// @notice Uniswap V4 Hooks interface
/// Hooks can implement various callbacks to customize pool behavior
interface IHooks {
    /// @notice Called before a pool is initialized
    function beforeInitialize(address sender, PoolKey calldata key, uint160 sqrtPriceX96) external returns (bytes4);
    
    /// @notice Called after a pool is initialized
    function afterInitialize(address sender, PoolKey calldata key, uint160 sqrtPriceX96, int24 tick) external returns (bytes4);
    
    /// @notice Called before a swap
    function beforeSwap(address sender, PoolKey calldata key, SwapParams calldata params, bytes calldata hookData) external returns (bytes4, BeforeSwapDelta, uint24);
    
    /// @notice Called after a swap
    function afterSwap(address sender, PoolKey calldata key, SwapParams calldata params, BalanceDelta delta, bytes calldata hookData) external returns (bytes4, int128);
    
    /// @notice Called before liquidity is added
    function beforeAddLiquidity(address sender, PoolKey calldata key, ModifyLiquidityParams calldata params, bytes calldata hookData) external returns (bytes4);
    
    /// @notice Called after liquidity is added
    function afterAddLiquidity(address sender, PoolKey calldata key, ModifyLiquidityParams calldata params, BalanceDelta delta, BalanceDelta feesAccrued, bytes calldata hookData) external returns (bytes4, BalanceDelta);
    
    /// @notice Called before liquidity is removed
    function beforeRemoveLiquidity(address sender, PoolKey calldata key, ModifyLiquidityParams calldata params, bytes calldata hookData) external returns (bytes4);
    
    /// @notice Called after liquidity is removed
    function afterRemoveLiquidity(address sender, PoolKey calldata key, ModifyLiquidityParams calldata params, BalanceDelta delta, BalanceDelta feesAccrued, bytes calldata hookData) external returns (bytes4, BalanceDelta);
    
    /// @notice Called before a donate
    function beforeDonate(address sender, PoolKey calldata key, uint256 amount0, uint256 amount1, bytes calldata hookData) external returns (bytes4);
    
    /// @notice Called after a donate
    function afterDonate(address sender, PoolKey calldata key, uint256 amount0, uint256 amount1, bytes calldata hookData) external returns (bytes4);
}

/// @notice Before swap delta type - encodes (specifiedDelta, unspecifiedDelta)
type BeforeSwapDelta is int256;

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "./ICurrency.sol";
import "./IHooks.sol";

// BalanceDelta is a packed int256 where:
// - Upper 128 bits = amount0 (int128)
// - Lower 128 bits = amount1 (int128)
type BalanceDelta is int256;

/// @notice Library for getting amount0/amount1 from BalanceDelta
library BalanceDeltaLibrary {
    function amount0(BalanceDelta balanceDelta) internal pure returns (int128 _amount0) {
        assembly ("memory-safe") {
            _amount0 := sar(128, balanceDelta)
        }
    }

    function amount1(BalanceDelta balanceDelta) internal pure returns (int128 _amount1) {
        assembly ("memory-safe") {
            _amount1 := signextend(15, balanceDelta)
        }
    }
}

/// @notice PoolKey identifies a V4 pool
struct PoolKey {
    Currency currency0;
    Currency currency1;
    uint24 fee;
    int24 tickSpacing;
    IHooks hooks;
}

/// @notice Parameters for modifyLiquidity
struct ModifyLiquidityParams {
    int24 tickLower;
    int24 tickUpper;
    int256 liquidityDelta;
    bytes32 salt;
}

/// @notice Interface for Uniswap V4 PoolManager
interface IPoolManager {
    /// @notice Initialize the state for a given pool
    function initialize(PoolKey memory key, uint160 sqrtPriceX96) external returns (int24 tick);

    /// @notice Modify the liquidity for the given pool
    function modifyLiquidity(PoolKey memory key, ModifyLiquidityParams memory params, bytes calldata hookData)
        external
        returns (BalanceDelta callerDelta, BalanceDelta feesAccrued);

    /// @notice All interactions on the contract that account deltas require unlocking
    function unlock(bytes calldata data) external returns (bytes memory);

    /// @notice Sync the currency to its current balance in the PoolManager
    function sync(Currency currency) external;

    /// @notice Settle the currency, paying what is owed
    function settle() external payable returns (uint256 paid);
    
    /// @notice Take currency from the PoolManager
    /// @param currency The currency to take
    /// @param to The address to receive the currency
    /// @param amount The amount to take
    function take(Currency currency, address to, uint256 amount) external;
    
    /// @notice Execute a swap
    /// @param key The pool key
    /// @param params The swap parameters
    /// @param hookData Any data to be passed to hooks
    function swap(PoolKey memory key, SwapParams memory params, bytes calldata hookData)
        external
        returns (BalanceDelta swapDelta);
}

// SPDX-License-Identifier: MIT
// Qian Exchange - https://qian.ag
pragma solidity ^0.8.24;

/// @notice Interface for the callback executed when an address unlocks the pool manager
interface IUnlockCallback {
    /// @notice Called by the pool manager on `msg.sender` when the manager is unlocked
    /// @param data The data that was passed to the call to unlock
    /// @return Any data that you want to be returned from the unlock call
    function unlockCallback(bytes calldata data) external returns (bytes memory);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 100
  },
  "viaIR": true,
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_poolManager","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_controller","type":"address"},{"internalType":"address","name":"_platformFeeCollector","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidPlatformFee","type":"error"},{"inputs":[],"name":"InvalidTax","type":"error"},{"inputs":[],"name":"InvalidThreshold","type":"error"},{"inputs":[],"name":"NotController","type":"error"},{"inputs":[],"name":"NotPoolManager","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"wethSpent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensBurned","type":"uint256"}],"name":"BuybackExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldBps","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBps","type":"uint256"}],"name":"PlatformFeeBpsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldCollector","type":"address"},{"indexed":false,"internalType":"address","name":"newCollector","type":"address"}],"name":"PlatformFeeCollectorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"wethAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"PlatformFeeSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isBuy","type":"bool"}],"name":"TaxTaken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"accumulated","type":"uint256"}],"name":"ThresholdReached","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"tokensSpent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"wethReceived","type":"uint256"}],"name":"TokensConvertedToWeth","type":"event"},{"inputs":[],"name":"FEE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PLATFORM_FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_TAX_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"components":[{"internalType":"Currency","name":"currency0","type":"address"},{"internalType":"Currency","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"contract IHooks","name":"hooks","type":"address"}],"internalType":"struct PoolKey","name":"","type":"tuple"},{"components":[{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"int256","name":"liquidityDelta","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct ModifyLiquidityParams","name":"","type":"tuple"},{"internalType":"BalanceDelta","name":"","type":"int256"},{"internalType":"BalanceDelta","name":"","type":"int256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"afterAddLiquidity","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"},{"internalType":"BalanceDelta","name":"","type":"int256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"components":[{"internalType":"Currency","name":"currency0","type":"address"},{"internalType":"Currency","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"contract IHooks","name":"hooks","type":"address"}],"internalType":"struct PoolKey","name":"","type":"tuple"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"afterDonate","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"components":[{"internalType":"Currency","name":"currency0","type":"address"},{"internalType":"Currency","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"contract IHooks","name":"hooks","type":"address"}],"internalType":"struct PoolKey","name":"","type":"tuple"},{"internalType":"uint160","name":"","type":"uint160"},{"internalType":"int24","name":"","type":"int24"}],"name":"afterInitialize","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"components":[{"internalType":"Currency","name":"currency0","type":"address"},{"internalType":"Currency","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"contract IHooks","name":"hooks","type":"address"}],"internalType":"struct PoolKey","name":"","type":"tuple"},{"components":[{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"int256","name":"liquidityDelta","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct ModifyLiquidityParams","name":"","type":"tuple"},{"internalType":"BalanceDelta","name":"","type":"int256"},{"internalType":"BalanceDelta","name":"","type":"int256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"afterRemoveLiquidity","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"},{"internalType":"BalanceDelta","name":"","type":"int256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"components":[{"internalType":"Currency","name":"currency0","type":"address"},{"internalType":"Currency","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"contract IHooks","name":"hooks","type":"address"}],"internalType":"struct PoolKey","name":"key","type":"tuple"},{"components":[{"internalType":"bool","name":"zeroForOne","type":"bool"},{"internalType":"int256","name":"amountSpecified","type":"int256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct SwapParams","name":"params","type":"tuple"},{"internalType":"BalanceDelta","name":"delta","type":"int256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"afterSwap","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"},{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"components":[{"internalType":"Currency","name":"currency0","type":"address"},{"internalType":"Currency","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"contract IHooks","name":"hooks","type":"address"}],"internalType":"struct PoolKey","name":"","type":"tuple"},{"components":[{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"int256","name":"liquidityDelta","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct ModifyLiquidityParams","name":"","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"beforeAddLiquidity","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"components":[{"internalType":"Currency","name":"currency0","type":"address"},{"internalType":"Currency","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"contract IHooks","name":"hooks","type":"address"}],"internalType":"struct PoolKey","name":"","type":"tuple"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"beforeDonate","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"components":[{"internalType":"Currency","name":"currency0","type":"address"},{"internalType":"Currency","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"contract IHooks","name":"hooks","type":"address"}],"internalType":"struct PoolKey","name":"","type":"tuple"},{"internalType":"uint160","name":"","type":"uint160"}],"name":"beforeInitialize","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"components":[{"internalType":"Currency","name":"currency0","type":"address"},{"internalType":"Currency","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"contract IHooks","name":"hooks","type":"address"}],"internalType":"struct PoolKey","name":"","type":"tuple"},{"components":[{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"int256","name":"liquidityDelta","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct ModifyLiquidityParams","name":"","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"beforeRemoveLiquidity","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"components":[{"internalType":"Currency","name":"currency0","type":"address"},{"internalType":"Currency","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"contract IHooks","name":"hooks","type":"address"}],"internalType":"struct PoolKey","name":"key","type":"tuple"},{"components":[{"internalType":"bool","name":"zeroForOne","type":"bool"},{"internalType":"int256","name":"amountSpecified","type":"int256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct SwapParams","name":"params","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"beforeSwap","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"},{"internalType":"BeforeSwapDelta","name":"","type":"int256"},{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint16","name":"buyTaxBps","type":"uint16"},{"internalType":"uint16","name":"sellTaxBps","type":"uint16"},{"internalType":"uint256","name":"threshold","type":"uint256"}],"name":"configureSnowball","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"Currency","name":"currency0","type":"address"},{"internalType":"Currency","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"contract IHooks","name":"hooks","type":"address"}],"internalType":"struct PoolKey","name":"key","type":"tuple"}],"name":"executeBuyback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"}],"name":"getAccumulated","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHookPermissions","outputs":[{"components":[{"internalType":"bool","name":"beforeInitialize","type":"bool"},{"internalType":"bool","name":"afterInitialize","type":"bool"},{"internalType":"bool","name":"beforeAddLiquidity","type":"bool"},{"internalType":"bool","name":"afterAddLiquidity","type":"bool"},{"internalType":"bool","name":"beforeRemoveLiquidity","type":"bool"},{"internalType":"bool","name":"afterRemoveLiquidity","type":"bool"},{"internalType":"bool","name":"beforeSwap","type":"bool"},{"internalType":"bool","name":"afterSwap","type":"bool"},{"internalType":"bool","name":"beforeDonate","type":"bool"},{"internalType":"bool","name":"afterDonate","type":"bool"},{"internalType":"bool","name":"beforeSwapReturnDelta","type":"bool"},{"internalType":"bool","name":"afterSwapReturnDelta","type":"bool"},{"internalType":"bool","name":"afterAddLiquidityReturnDelta","type":"bool"},{"internalType":"bool","name":"afterRemoveLiquidityReturnDelta","type":"bool"}],"internalType":"struct Hooks.Permissions","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getPlatformFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPlatformFeeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"Currency","name":"currency0","type":"address"},{"internalType":"Currency","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"contract IHooks","name":"hooks","type":"address"}],"internalType":"struct PoolKey","name":"key","type":"tuple"}],"name":"getPoolId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTotalPlatformFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWethBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"}],"name":"isThresholdReached","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformFeeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newController","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFactory","type":"address"}],"name":"setFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPlatformFeeBps","type":"uint256"}],"name":"setPlatformFeeBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newCollector","type":"address"}],"name":"setPlatformFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"taxConfigs","outputs":[{"internalType":"uint16","name":"buyTaxBps","type":"uint16"},{"internalType":"uint16","name":"sellTaxBps","type":"uint16"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"uint256","name":"accumulated","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"bool","name":"enabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenFeesAccumulated","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBurned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBuybacks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPlatformFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"unlockCallback","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"uint16","name":"buyTaxBps","type":"uint16"},{"internalType":"uint16","name":"sellTaxBps","type":"uint16"}],"name":"updateTaxRates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c0346200015f57601f6200251938819003918201601f19168301916001600160401b0383118484101762000164578084926080946040528339810103126200015f576200004d816200017a565b6200005b602083016200017a565b6200007760606200006f604086016200017a565b94016200017a565b9160805260a05260018060a01b03908160018060a01b03199316836000541617600055169060015416176001556107d0600355604051612389908162000190823960805181818161054d01528181610b3601528181610daa01528181610e2b01528181610e8401528181610eca01528181610f570152818161102c015281816110820152818161167701528181611d740152611fcc015260a051818181610a1701528181610c1501528181610c4001528181610c8a01528181610cef01528181610ddd01528181610f0b015281816114d8015281816115cf01528181611dd6015261202f0152f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036200015f5756fe608080604052600436101561001d575b50361561001b57600080fd5b005b600090813560e01c90816321d0ee7014611a405750806322dcd13e1461152457806322ebb0f814611567578063259982e51461154257806326e3c685146115245780632c597de91461150757806331521d57146105e15780633fc8cef3146114c25780634c1a69001461148d578063575e24b4146114095780635bb47808146113c7578063602cf5731461136a5780636c2bbe7e1461133d5780636fe7e6eb146112ee578063853a65f91461084d5780638d01513c146112d157806391dd734614610b0357806392eefe9b14610abc5780639c6b88a814610a985780639dd58b58146109ea5780639f063efc146109bd578063a97edea81461094b578063ade41d501461091e578063b47b2fb11461089c578063b6a8b0fa14610876578063bb1f60d01461084d578063c45a015514610824578063c4e833ce14610699578063c580c9421461061d578063cb371f83146105ff578063d3631fa5146105e1578063d427ceaa146105b7578063d73792a91461059a578063d89135cd1461057c578063dc4c90d314610537578063dc98354e146104f5578063dd98d7c11461037a578063dfc90cf2146102eb578063e1b4af69146102c5578063eb9912e0146102125763f77c47910361000f573461020f578060031936011261020f57546040516001600160a01b039091168152602090f35b80fd5b503461020f57606036600319011261020f5760243561ffff8082168092036102c05761023c611c59565b83549091906001600160a01b031633036102ae576105dc9081841161029c5782161161029c5760048035845260205260408320805463ffff00001990931663ffffffff199093169290921760109190911b63ffff00001617905580f35b80f35b6040516337d4ed5b60e01b8152600490fd5b6040516323019e6760e01b8152600490fd5b600080fd5b503461020f576102d436611c02565b505050505050602060405163e1b4af6960e01b8152f35b503461020f57602036600319011261020f57610305611a64565b81546001600160a01b039190821633036102ae5781168015610368577fb4e31e50e03f47b5be13be5942bd3a5b1b6048e886cfd1ce1932910251b2958e91604091600154918160018060a01b03198416176001558351921682526020820152a180f35b60405163e6c4247b60e01b8152600490fd5b503461020f5760a036600319011261020f57600435610397611a7a565b61039f611c59565b916064359261ffff8085168095036102c05785546001600160a01b039260843592918416331415806104e7575b6102ae578116916105dc80841161029c57871161029c5780156104d55784885260046020526002604089200154906040519260c08401908482106001600160401b038311176104bf576102999960039661048293604052865260208601908152604086019384526060860194855287608087019a168a5260a086019860018a528c5260046020528160408d2096511661ffff198754161786555116849063ffff000082549160101b169063ffff00001916179055565b516001830155516002820155935193018054925160ff60a01b90151560a01b166001600160a81b03199093169190931660ff60a01b191617179055565b634e487b7160e01b600052604160045260246000fd5b60405163aabd5a0960e01b8152600490fd5b5083600254163314156103cc565b503461020f5760e036600319011261020f5761050f611a64565b5060a036602319011261020f57610524611b9d565b50604051636e4c1aa760e11b8152602090f35b503461020f578060031936011261020f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461020f578060031936011261020f576020600654604051908152f35b503461020f578060031936011261020f5760206040516127108152f35b503461020f57602036600319011261020f5760406020916004358152600983522054604051908152f35b503461020f578060031936011261020f576020600754604051908152f35b503461020f578060031936011261020f576020600554604051908152f35b503461020f57602036600319011261020f578054600435906001600160a01b031633036102ae5761138881116106875760407fb7cf940f291738114d642ccbcbdedeeeddc0bb17e043b90365614d7159129d7191600354908060035582519182526020820152a180f35b60405163183440b760e31b8152600490fd5b503461020f578060031936011261020f57806101c0916101a06040516106be81611c7d565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201528261012082015282610140820152826101608201528261018082015201526101a060405161071f81611c7d565b8281528260208201528260408201528260608201528260808201528260a0820152600160c0820152600160e082015282610100820152826101208201526001610140820152600161016082015282610180820152828282015260405192835260208101511515602084015260408101511515604084015260608101511515606084015260808101511515608084015260a0810151151560a084015260c0810151151560c084015260e0810151151560e084015261010081015115156101008401526101208101511515610120840152610140810151151561014084015261016081015115156101608401526101808101511515610180840152015115156101a0820152f35b503461020f578060031936011261020f576002546040516001600160a01b039091168152602090f35b503461020f578060031936011261020f576001546040516001600160a01b039091168152602090f35b503461020f5761088536611c02565b5050505050506020604051635b54587d60e11b8152f35b503461020f5761016036600319011261020f576108b7611a64565b5060a036602319011261020f5760603660c319011261020f57610144356001600160401b03811161091a576108f0903690600401611aa4565b5050604061090061012435611fc1565b82516001600160e01b03199092168252600f0b6020820152f35b5080fd5b503461020f57602036600319011261020f5760026040602092600435815260048452200154604051908152f35b503461020f57602036600319011261020f57604060c091600435815260046020522060ff81549161ffff906001810154600360028301549201549260405195818116875260101c1660208601526040850152606084015260018060a01b038116608084015260a01c16151560a0820152f35b503461020f576109cc36611b34565b50505050505050604080516327c18fbf60e21b815260006020820152f35b503461020f578060031936011261020f576040516370a0823160e01b8152306004820152906020826024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610a8c5790610a59575b602090604051908152f35b506020813d602011610a84575b81610a7360209383611cb4565b810103126102c05760209051610a4e565b3d9150610a66565b604051903d90823e3d90fd5b503461020f5760a036600319011261020f576020610ab4612255565b604051908152f35b503461020f57602036600319011261020f57610ad6611a64565b8154906001600160a01b039081831633036102ae5716908115610368576001600160a01b03191617815580f35b503461020f57602036600319011261020f576004356001600160401b03811161091a57610b34903690600401611aa4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316330361129a57819081010361010081126111555760a01361091a576040519060a082018281106001600160401b0382111761128657604052610b9f81611a90565b91828152610baf60208301611a90565b806020830152604083013562ffffff811681036111d657604083015260608301358060020b81036111d6576060830152610beb60808401611a90565b608083015260c0830135906001600160a01b03821682036111d6576001600160a01b0390811692907f00000000000000000000000000000000000000000000000000000000000000001683036112765782945b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316840361126f576001600160a01b0316925b60a0850135600160ff1b1461125b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168114611241576401000276a45b604051908160608101106001600160401b0360608401111761122d57606082810160409081526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116861415855260a08a01358c0360208087019182529482168387019081528351633cf3645360e21b815289518416600482015289870151841660248201529389015162ffffff1660448501529388015160020b6064840152608090970151811660848301529351151560a4820152945160c486015251821660e485015261012061010485015261012484018990529083906101449082908b907f0000000000000000000000000000000000000000000000000000000000000000165af19182156112225787926111ea575b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316036111e25760801d600f0b5b8581600f0b136000146111da576001600160801b0316935b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163b156111d657604051632961046560e21b81526001600160a01b0391821660048201529086908290602490829084907f0000000000000000000000000000000000000000000000000000000000000000165af180156111cb576111b6575b5060405163a9059cbb60e01b8082526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016600483015260a08501356024830152869390929160208180604481010381887f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1801561118c57611197575b50604051630476982d60e21b8152602081600481887f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1801561118c5761115d575b508561102a575b5050505060055460001981146110165760e07f9ff78e7c440e5fcb39d1e846ff16b1e3ab6ba799bf89e6e5b33cab8fe5df891a9260016040930160055582519460a082013586526020860152013592a260405160208101918183106001600160401b038411176104bf5761101292604052815260405191829182611bd6565b0390f35b634e487b7160e01b84526011600452602484fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163b1561115957838661107d926040519384928392630b0d9c0960e01b8452309060048501611d48565b0381837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1908115611136578491611141575b505060446020926040519485938492835261dead600484015288602484015260018060a01b03165af1801561113657611107575b506110fb82600654611d0b565b60065582388080610f93565b6111289060203d60201161112f575b6111208183611cb4565b810190611d18565b50386110ee565b503d611116565b6040513d86823e3d90fd5b61114a90611c6a565b6111555782386110ba565b8280fd5b8380fd5b6020809295503d8311611185575b6111758183611cb4565b810103126102c057859238610f8c565b503d61116b565b6040513d87823e3d90fd5b6111af9060203d60201161112f576111208183611cb4565b5038610f40565b6111c39095919295611c6a565b939038610eb1565b6040513d88823e3d90fd5b8580fd5b508493610e29565b600f0b610e11565b9091506020813d60201161121a575b8161120660209383611cb4565b8101031261121657519038610dda565b8680fd5b3d91506111f9565b6040513d89823e3d90fd5b634e487b7160e01b89526041600452602489fd5b73fffd8963efd1fc6a506488495d951d5263988d25610cbf565b634e487b7160e01b87526011600452602487fd5b5082610c79565b6001600160a01b03851694610c3e565b634e487b7160e01b84526041600452602484fd5b60405162461bcd60e51b815260206004820152600f60248201526e2737ba102837b7b626b0b730b3b2b960891b6044820152606490fd5b503461020f578060031936011261020f5760206040516113888152f35b503461020f5761010036600319011261020f57611309611a64565b5060a036602319011261020f5761131e611b9d565b5060e4358060020b0361020f57604051636fe7e6eb60e01b8152602090f35b503461020f5760409061134f36611b34565b50505050505050815190633615df3f60e11b82526020820152f35b503461020f57604036600319011261020f57602435801515810361091a5781546001600160a01b031633036102ae5760048035835260205260408220600301805460ff60a01b191691151560a01b60ff60a01b1691909117905580f35b503461020f57602036600319011261020f576113e1611a64565b81546001600160a01b039190821633036102ae571660018060a01b0319600254161760025580f35b503461020f5761014036600319011261020f57611424611a64565b5060a036602319011261020f5760603660c319011261020f57610124356001600160401b03811161091a5761145d903690600401611aa4565b5050606062ffffff61146d611d6a565b906040939293519363ffffffff60e01b1684526020840152166040820152f35b503461020f57602036600319011261020f57604060209160043581526004835220600160028201549101541115604051908152f35b503461020f578060031936011261020f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461020f578060031936011261020f5760206040516105dc8152f35b503461020f578060031936011261020f576020600354604051908152f35b503461020f5761155136611ad1565b5050505050602060405163259982e560e01b8152f35b503461020f5760a036600319011261020f57611581612255565b80825260206004815260408320600381019260ff845460a01c1615611a0d5760028201926001845493015483106119d1576040516370a0823160e01b81523060048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811696602496919492909190848189818c5afa9081156119c6578a91611999575b508015611960578681101561195957955b86808211156119505761163291611cd5565b905b5561164f61271061164760035488611cf8565b048096611cd5565b9480151580611943575b611869575b5084611668578780f35b60405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038116600483015260248201879052979091908490839060449082908d905af191821561185e578592611841575b50541660405194846116db611a64565b1684870152846116e9611a7a565b16604087015260443562ffffff811680910361183d5760608701526064358060020b80910361183d57608087015260843585811680910361183d5760a087015260c086015260e08501526101009081850152835261012092838101956001600160401b03938288108589111761182a57889188838193826040526348c8949160e01b835261011f1987611780816101248101611bd6565b030193165af180156112225761179557808780f35b3d8088883e6117a48188611cb4565b81019582828689019803126118265751908382116118265701928561013f8501121561121657830151936101409285116118145750604051946117f0601f8601601f1916830187611cb4565b8486528285850101116111d65761180994019101611bb3565b388080808080808780f35b634e487b7160e01b8752604160045286fd5b8780fd5b634e487b7160e01b895260416004528689fd5b8980fd5b61185790853d871161112f576111208183611cb4565b50386116cb565b6040513d8b823e3d90fd5b6001546040805163a9059cbb60e01b8782019081529288166001600160a01b03168a82019081526020810185905287938d939092916118b39183910103601f198101835282611cb4565b5190828c5af1156119385788513d61192f5750873b155b611917577f57982d28adf5212b25ddfe8de7bc312243fa25e94b54db636b0371290f648fcc6040826118ff8694600754611d0b565b6007558760015416825191825287820152a23861165e565b604051635274afe760e01b8152600481018990528790fd5b600114156118ca565b6040513d8a823e3d90fd5b5084600154161515611659565b50508890611634565b5085611620565b60405162461bcd60e51b8152600481018690526012818a0152714e6f205745544820746f206275796261636b60701b6044820152606490fd5b90508481813d83116119bf575b6119b08183611cb4565b8101031261183d57513861160f565b503d6119a6565b6040513d8c823e3d90fd5b6064906040519062461bcd60e51b825260048201526015602482015274151a1c995cda1bdb19081b9bdd081c995858da1959605a1b6044820152fd5b60405162461bcd60e51b815260048101849052600b60248201526a139bdd08195b98589b195960aa1b6044820152606490fd5b90503461091a57602090611a5336611ad1565b505063021d0ee760e41b8452505050f35b600435906001600160a01b03821682036102c057565b602435906001600160a01b03821682036102c057565b35906001600160a01b03821682036102c057565b9181601f840112156102c0578235916001600160401b0383116102c057602083818601950101116102c057565b906101606003198301126102c0576004356001600160a01b03811681036102c0579160a06023198201126102c057602491608060c3198301126102c05760c49161014435906001600160401b0382116102c057611b3091600401611aa4565b9091565b906101a06003198301126102c0576004356001600160a01b03811681036102c0579160a06023198201126102c057602491608060c3198301126102c05760c4916101443591610164359161018435906001600160401b0382116102c057611b3091600401611aa4565b60c435906001600160a01b03821682036102c057565b60005b838110611bc65750506000910152565b8181015183820152602001611bb6565b60409160208252611bf68151809281602086015260208686019101611bb3565b601f01601f1916010190565b6101206003198201126102c0576004356001600160a01b03811681036102c0579160a06023198301126102c05760249160c4359160e4359161010435906001600160401b0382116102c057611b3091600401611aa4565b6044359061ffff821682036102c057565b6001600160401b0381116104bf57604052565b6101c081019081106001600160401b038211176104bf57604052565b60c081019081106001600160401b038211176104bf57604052565b90601f801991011681019081106001600160401b038211176104bf57604052565b91908203918211611ce257565b634e487b7160e01b600052601160045260246000fd5b81810292918115918404141715611ce257565b91908201809211611ce257565b908160209103126102c0575180151581036102c05790565b600f0b60016001607f1b03198114611ce25760000390565b6001600160a01b03918216815291166020820152604081019190915260600190565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169033829003611faf57611da66122d7565b9160009280845260046020526040842060ff600382015460a01c1615611f9d5760443592848416808503611216577f0000000000000000000000000000000000000000000000000000000000000000861614938415611f8d5760c435801590811503611826575b611e26575b506315d7892d60e21b968695509350505050565b61ffff835416958615611f7857612710611e6460e435988a8a12998a600014611f6a576001600160801b0390611e5e90600f0b611d30565b16611cf8565b049586611e72575050611e12565b96989615611f5957505b813b156112165784611ea992889283604051809681958294630b0d9c0960e01b8452309060048501611d48565b03925af180156111cb57611f45575b50600201611ec7838254611d0b565b90557f9cae4344a2aa90b3dbc6528a3f2ffaed048544717fac552b75ee12618278d7076040805184815260016020820152a28315611f3e576001600160801b038116600f0b935b15611f2c575081925b6315d7892d60e21b93600f0b9060801b179190565b6001600160801b0316600f0b92611f17565b8293611f0e565b94611f5260029296611c6a565b9490611eb8565b602435915081168114611e7c578680fd5b6001600160801b0316611cf8565b506315d7892d60e21b97879650945050505050565b60c4358015158114611e0d578780fd5b506315d7892d60e21b94849350915050565b60405163570c108560e11b8152600490fd5b906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811633819003611faf57611ffd6122d7565b9160009083825260046020526040918281209360ff600386015460a01c161561224257604435838116808203611159577f000000000000000000000000000000000000000000000000000000000000000085161493841561222f5760c435801515810361222b57995b849a8061221a575b6120cd575b5050505050506001600283015492015482101561209b575b5063b47b2fb160e01b9392915050565b7fed9753748c66ee1df3e83ee8ba5d83244f01c004097e0e4eebd94e5fd6fea5f19160209151908152a238808061208b565b851561220f57600f0b5b8481600f0b8181136000146121ea5750506001600160801b03165b80156120735761210e6127109161ffff8a5460101c1690611cf8565b0494851561207357909192938095969a50506000146121d957505b813b156111555783612155928492838b51809681958294630b0d9c0960e01b8452309060048501611d48565b03925af180156121cf5785927f9cae4344a2aa90b3dbc6528a3f2ffaed048544717fac552b75ee12618278d7079289926121c0575b506002860161219a868254611d0b565b90558151908582526020820152a26001600160801b0316600f0b93388080808080612073565b6121c990611c6a565b3861218a565b87513d84823e3d90fd5b602435915081168114612129578280fd5b1215612208576001600160801b039061220290611d30565b166120f2565b50836120f2565b60801d600f0b6120d7565b5061ffff885460101c16151561206e565b8480fd5b60c43580159081150361222b5799612066565b5063b47b2fb160e01b9650949350505050565b6004356001600160a01b03818116918290036102c057602435908082168092036102c05760443562ffffff81168091036102c057606435908160020b8092036102c0576084359283168093036102c057604051936020850195865260408501526060840152608083015260a082015260a081526122d181611c99565b51902090565b6024356001600160a01b03818116918290036102c057604435908082168092036102c05760643562ffffff81168091036102c057608435908160020b8092036102c05760a4359283168093036102c057604051936020850195865260408501526060840152608083015260a082015260a081526122d181611c9956fea264697066735822122036240c439e054a2d62db11ec63ce0c528819d19cea890dab69bf7ebaaddcaf6164736f6c63430008180033000000000000000000000000000000000004444c5dc75cb358380d2e3de08a90000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000b80c866bb98944e967ac61b6665fbb5225f0d587000000000000000000000000a80a932f626c484898b851e681dbe2c9b279fbed

Deployed Bytecode

0x608080604052600436101561001d575b50361561001b57600080fd5b005b600090813560e01c90816321d0ee7014611a405750806322dcd13e1461152457806322ebb0f814611567578063259982e51461154257806326e3c685146115245780632c597de91461150757806331521d57146105e15780633fc8cef3146114c25780634c1a69001461148d578063575e24b4146114095780635bb47808146113c7578063602cf5731461136a5780636c2bbe7e1461133d5780636fe7e6eb146112ee578063853a65f91461084d5780638d01513c146112d157806391dd734614610b0357806392eefe9b14610abc5780639c6b88a814610a985780639dd58b58146109ea5780639f063efc146109bd578063a97edea81461094b578063ade41d501461091e578063b47b2fb11461089c578063b6a8b0fa14610876578063bb1f60d01461084d578063c45a015514610824578063c4e833ce14610699578063c580c9421461061d578063cb371f83146105ff578063d3631fa5146105e1578063d427ceaa146105b7578063d73792a91461059a578063d89135cd1461057c578063dc4c90d314610537578063dc98354e146104f5578063dd98d7c11461037a578063dfc90cf2146102eb578063e1b4af69146102c5578063eb9912e0146102125763f77c47910361000f573461020f578060031936011261020f57546040516001600160a01b039091168152602090f35b80fd5b503461020f57606036600319011261020f5760243561ffff8082168092036102c05761023c611c59565b83549091906001600160a01b031633036102ae576105dc9081841161029c5782161161029c5760048035845260205260408320805463ffff00001990931663ffffffff199093169290921760109190911b63ffff00001617905580f35b80f35b6040516337d4ed5b60e01b8152600490fd5b6040516323019e6760e01b8152600490fd5b600080fd5b503461020f576102d436611c02565b505050505050602060405163e1b4af6960e01b8152f35b503461020f57602036600319011261020f57610305611a64565b81546001600160a01b039190821633036102ae5781168015610368577fb4e31e50e03f47b5be13be5942bd3a5b1b6048e886cfd1ce1932910251b2958e91604091600154918160018060a01b03198416176001558351921682526020820152a180f35b60405163e6c4247b60e01b8152600490fd5b503461020f5760a036600319011261020f57600435610397611a7a565b61039f611c59565b916064359261ffff8085168095036102c05785546001600160a01b039260843592918416331415806104e7575b6102ae578116916105dc80841161029c57871161029c5780156104d55784885260046020526002604089200154906040519260c08401908482106001600160401b038311176104bf576102999960039661048293604052865260208601908152604086019384526060860194855287608087019a168a5260a086019860018a528c5260046020528160408d2096511661ffff198754161786555116849063ffff000082549160101b169063ffff00001916179055565b516001830155516002820155935193018054925160ff60a01b90151560a01b166001600160a81b03199093169190931660ff60a01b191617179055565b634e487b7160e01b600052604160045260246000fd5b60405163aabd5a0960e01b8152600490fd5b5083600254163314156103cc565b503461020f5760e036600319011261020f5761050f611a64565b5060a036602319011261020f57610524611b9d565b50604051636e4c1aa760e11b8152602090f35b503461020f578060031936011261020f576040517f000000000000000000000000000000000004444c5dc75cb358380d2e3de08a906001600160a01b03168152602090f35b503461020f578060031936011261020f576020600654604051908152f35b503461020f578060031936011261020f5760206040516127108152f35b503461020f57602036600319011261020f5760406020916004358152600983522054604051908152f35b503461020f578060031936011261020f576020600754604051908152f35b503461020f578060031936011261020f576020600554604051908152f35b503461020f57602036600319011261020f578054600435906001600160a01b031633036102ae5761138881116106875760407fb7cf940f291738114d642ccbcbdedeeeddc0bb17e043b90365614d7159129d7191600354908060035582519182526020820152a180f35b60405163183440b760e31b8152600490fd5b503461020f578060031936011261020f57806101c0916101a06040516106be81611c7d565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201528261012082015282610140820152826101608201528261018082015201526101a060405161071f81611c7d565b8281528260208201528260408201528260608201528260808201528260a0820152600160c0820152600160e082015282610100820152826101208201526001610140820152600161016082015282610180820152828282015260405192835260208101511515602084015260408101511515604084015260608101511515606084015260808101511515608084015260a0810151151560a084015260c0810151151560c084015260e0810151151560e084015261010081015115156101008401526101208101511515610120840152610140810151151561014084015261016081015115156101608401526101808101511515610180840152015115156101a0820152f35b503461020f578060031936011261020f576002546040516001600160a01b039091168152602090f35b503461020f578060031936011261020f576001546040516001600160a01b039091168152602090f35b503461020f5761088536611c02565b5050505050506020604051635b54587d60e11b8152f35b503461020f5761016036600319011261020f576108b7611a64565b5060a036602319011261020f5760603660c319011261020f57610144356001600160401b03811161091a576108f0903690600401611aa4565b5050604061090061012435611fc1565b82516001600160e01b03199092168252600f0b6020820152f35b5080fd5b503461020f57602036600319011261020f5760026040602092600435815260048452200154604051908152f35b503461020f57602036600319011261020f57604060c091600435815260046020522060ff81549161ffff906001810154600360028301549201549260405195818116875260101c1660208601526040850152606084015260018060a01b038116608084015260a01c16151560a0820152f35b503461020f576109cc36611b34565b50505050505050604080516327c18fbf60e21b815260006020820152f35b503461020f578060031936011261020f576040516370a0823160e01b8152306004820152906020826024817f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03165afa908115610a8c5790610a59575b602090604051908152f35b506020813d602011610a84575b81610a7360209383611cb4565b810103126102c05760209051610a4e565b3d9150610a66565b604051903d90823e3d90fd5b503461020f5760a036600319011261020f576020610ab4612255565b604051908152f35b503461020f57602036600319011261020f57610ad6611a64565b8154906001600160a01b039081831633036102ae5716908115610368576001600160a01b03191617815580f35b503461020f57602036600319011261020f576004356001600160401b03811161091a57610b34903690600401611aa4565b7f000000000000000000000000000000000004444c5dc75cb358380d2e3de08a906001600160a01b0316330361129a57819081010361010081126111555760a01361091a576040519060a082018281106001600160401b0382111761128657604052610b9f81611a90565b91828152610baf60208301611a90565b806020830152604083013562ffffff811681036111d657604083015260608301358060020b81036111d6576060830152610beb60808401611a90565b608083015260c0830135906001600160a01b03821682036111d6576001600160a01b0390811692907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21683036112765782945b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316840361126f576001600160a01b0316925b60a0850135600160ff1b1461125b577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168114611241576401000276a45b604051908160608101106001600160401b0360608401111761122d57606082810160409081526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28116861415855260a08a01358c0360208087019182529482168387019081528351633cf3645360e21b815289518416600482015289870151841660248201529389015162ffffff1660448501529388015160020b6064840152608090970151811660848301529351151560a4820152945160c486015251821660e485015261012061010485015261012484018990529083906101449082908b907f000000000000000000000000000000000004444c5dc75cb358380d2e3de08a90165af19182156112225787926111ea575b507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316036111e25760801d600f0b5b8581600f0b136000146111da576001600160801b0316935b7f000000000000000000000000000000000004444c5dc75cb358380d2e3de08a906001600160a01b03163b156111d657604051632961046560e21b81526001600160a01b0391821660048201529086908290602490829084907f000000000000000000000000000000000004444c5dc75cb358380d2e3de08a90165af180156111cb576111b6575b5060405163a9059cbb60e01b8082526001600160a01b037f000000000000000000000000000000000004444c5dc75cb358380d2e3de08a9016600483015260a08501356024830152869390929160208180604481010381887f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03165af1801561118c57611197575b50604051630476982d60e21b8152602081600481887f000000000000000000000000000000000004444c5dc75cb358380d2e3de08a906001600160a01b03165af1801561118c5761115d575b508561102a575b5050505060055460001981146110165760e07f9ff78e7c440e5fcb39d1e846ff16b1e3ab6ba799bf89e6e5b33cab8fe5df891a9260016040930160055582519460a082013586526020860152013592a260405160208101918183106001600160401b038411176104bf5761101292604052815260405191829182611bd6565b0390f35b634e487b7160e01b84526011600452602484fd5b7f000000000000000000000000000000000004444c5dc75cb358380d2e3de08a906001600160a01b03163b1561115957838661107d926040519384928392630b0d9c0960e01b8452309060048501611d48565b0381837f000000000000000000000000000000000004444c5dc75cb358380d2e3de08a906001600160a01b03165af1908115611136578491611141575b505060446020926040519485938492835261dead600484015288602484015260018060a01b03165af1801561113657611107575b506110fb82600654611d0b565b60065582388080610f93565b6111289060203d60201161112f575b6111208183611cb4565b810190611d18565b50386110ee565b503d611116565b6040513d86823e3d90fd5b61114a90611c6a565b6111555782386110ba565b8280fd5b8380fd5b6020809295503d8311611185575b6111758183611cb4565b810103126102c057859238610f8c565b503d61116b565b6040513d87823e3d90fd5b6111af9060203d60201161112f576111208183611cb4565b5038610f40565b6111c39095919295611c6a565b939038610eb1565b6040513d88823e3d90fd5b8580fd5b508493610e29565b600f0b610e11565b9091506020813d60201161121a575b8161120660209383611cb4565b8101031261121657519038610dda565b8680fd5b3d91506111f9565b6040513d89823e3d90fd5b634e487b7160e01b89526041600452602489fd5b73fffd8963efd1fc6a506488495d951d5263988d25610cbf565b634e487b7160e01b87526011600452602487fd5b5082610c79565b6001600160a01b03851694610c3e565b634e487b7160e01b84526041600452602484fd5b60405162461bcd60e51b815260206004820152600f60248201526e2737ba102837b7b626b0b730b3b2b960891b6044820152606490fd5b503461020f578060031936011261020f5760206040516113888152f35b503461020f5761010036600319011261020f57611309611a64565b5060a036602319011261020f5761131e611b9d565b5060e4358060020b0361020f57604051636fe7e6eb60e01b8152602090f35b503461020f5760409061134f36611b34565b50505050505050815190633615df3f60e11b82526020820152f35b503461020f57604036600319011261020f57602435801515810361091a5781546001600160a01b031633036102ae5760048035835260205260408220600301805460ff60a01b191691151560a01b60ff60a01b1691909117905580f35b503461020f57602036600319011261020f576113e1611a64565b81546001600160a01b039190821633036102ae571660018060a01b0319600254161760025580f35b503461020f5761014036600319011261020f57611424611a64565b5060a036602319011261020f5760603660c319011261020f57610124356001600160401b03811161091a5761145d903690600401611aa4565b5050606062ffffff61146d611d6a565b906040939293519363ffffffff60e01b1684526020840152166040820152f35b503461020f57602036600319011261020f57604060209160043581526004835220600160028201549101541115604051908152f35b503461020f578060031936011261020f576040517f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168152602090f35b503461020f578060031936011261020f5760206040516105dc8152f35b503461020f578060031936011261020f576020600354604051908152f35b503461020f5761155136611ad1565b5050505050602060405163259982e560e01b8152f35b503461020f5760a036600319011261020f57611581612255565b80825260206004815260408320600381019260ff845460a01c1615611a0d5760028201926001845493015483106119d1576040516370a0823160e01b81523060048201526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2811696602496919492909190848189818c5afa9081156119c6578a91611999575b508015611960578681101561195957955b86808211156119505761163291611cd5565b905b5561164f61271061164760035488611cf8565b048096611cd5565b9480151580611943575b611869575b5084611668578780f35b60405163095ea7b360e01b81527f000000000000000000000000000000000004444c5dc75cb358380d2e3de08a906001600160a01b038116600483015260248201879052979091908490839060449082908d905af191821561185e578592611841575b50541660405194846116db611a64565b1684870152846116e9611a7a565b16604087015260443562ffffff811680910361183d5760608701526064358060020b80910361183d57608087015260843585811680910361183d5760a087015260c086015260e08501526101009081850152835261012092838101956001600160401b03938288108589111761182a57889188838193826040526348c8949160e01b835261011f1987611780816101248101611bd6565b030193165af180156112225761179557808780f35b3d8088883e6117a48188611cb4565b81019582828689019803126118265751908382116118265701928561013f8501121561121657830151936101409285116118145750604051946117f0601f8601601f1916830187611cb4565b8486528285850101116111d65761180994019101611bb3565b388080808080808780f35b634e487b7160e01b8752604160045286fd5b8780fd5b634e487b7160e01b895260416004528689fd5b8980fd5b61185790853d871161112f576111208183611cb4565b50386116cb565b6040513d8b823e3d90fd5b6001546040805163a9059cbb60e01b8782019081529288166001600160a01b03168a82019081526020810185905287938d939092916118b39183910103601f198101835282611cb4565b5190828c5af1156119385788513d61192f5750873b155b611917577f57982d28adf5212b25ddfe8de7bc312243fa25e94b54db636b0371290f648fcc6040826118ff8694600754611d0b565b6007558760015416825191825287820152a23861165e565b604051635274afe760e01b8152600481018990528790fd5b600114156118ca565b6040513d8a823e3d90fd5b5084600154161515611659565b50508890611634565b5085611620565b60405162461bcd60e51b8152600481018690526012818a0152714e6f205745544820746f206275796261636b60701b6044820152606490fd5b90508481813d83116119bf575b6119b08183611cb4565b8101031261183d57513861160f565b503d6119a6565b6040513d8c823e3d90fd5b6064906040519062461bcd60e51b825260048201526015602482015274151a1c995cda1bdb19081b9bdd081c995858da1959605a1b6044820152fd5b60405162461bcd60e51b815260048101849052600b60248201526a139bdd08195b98589b195960aa1b6044820152606490fd5b90503461091a57602090611a5336611ad1565b505063021d0ee760e41b8452505050f35b600435906001600160a01b03821682036102c057565b602435906001600160a01b03821682036102c057565b35906001600160a01b03821682036102c057565b9181601f840112156102c0578235916001600160401b0383116102c057602083818601950101116102c057565b906101606003198301126102c0576004356001600160a01b03811681036102c0579160a06023198201126102c057602491608060c3198301126102c05760c49161014435906001600160401b0382116102c057611b3091600401611aa4565b9091565b906101a06003198301126102c0576004356001600160a01b03811681036102c0579160a06023198201126102c057602491608060c3198301126102c05760c4916101443591610164359161018435906001600160401b0382116102c057611b3091600401611aa4565b60c435906001600160a01b03821682036102c057565b60005b838110611bc65750506000910152565b8181015183820152602001611bb6565b60409160208252611bf68151809281602086015260208686019101611bb3565b601f01601f1916010190565b6101206003198201126102c0576004356001600160a01b03811681036102c0579160a06023198301126102c05760249160c4359160e4359161010435906001600160401b0382116102c057611b3091600401611aa4565b6044359061ffff821682036102c057565b6001600160401b0381116104bf57604052565b6101c081019081106001600160401b038211176104bf57604052565b60c081019081106001600160401b038211176104bf57604052565b90601f801991011681019081106001600160401b038211176104bf57604052565b91908203918211611ce257565b634e487b7160e01b600052601160045260246000fd5b81810292918115918404141715611ce257565b91908201809211611ce257565b908160209103126102c0575180151581036102c05790565b600f0b60016001607f1b03198114611ce25760000390565b6001600160a01b03918216815291166020820152604081019190915260600190565b6001600160a01b037f000000000000000000000000000000000004444c5dc75cb358380d2e3de08a9081169033829003611faf57611da66122d7565b9160009280845260046020526040842060ff600382015460a01c1615611f9d5760443592848416808503611216577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2861614938415611f8d5760c435801590811503611826575b611e26575b506315d7892d60e21b968695509350505050565b61ffff835416958615611f7857612710611e6460e435988a8a12998a600014611f6a576001600160801b0390611e5e90600f0b611d30565b16611cf8565b049586611e72575050611e12565b96989615611f5957505b813b156112165784611ea992889283604051809681958294630b0d9c0960e01b8452309060048501611d48565b03925af180156111cb57611f45575b50600201611ec7838254611d0b565b90557f9cae4344a2aa90b3dbc6528a3f2ffaed048544717fac552b75ee12618278d7076040805184815260016020820152a28315611f3e576001600160801b038116600f0b935b15611f2c575081925b6315d7892d60e21b93600f0b9060801b179190565b6001600160801b0316600f0b92611f17565b8293611f0e565b94611f5260029296611c6a565b9490611eb8565b602435915081168114611e7c578680fd5b6001600160801b0316611cf8565b506315d7892d60e21b97879650945050505050565b60c4358015158114611e0d578780fd5b506315d7892d60e21b94849350915050565b60405163570c108560e11b8152600490fd5b906001600160a01b037f000000000000000000000000000000000004444c5dc75cb358380d2e3de08a90811633819003611faf57611ffd6122d7565b9160009083825260046020526040918281209360ff600386015460a01c161561224257604435838116808203611159577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc285161493841561222f5760c435801515810361222b57995b849a8061221a575b6120cd575b5050505050506001600283015492015482101561209b575b5063b47b2fb160e01b9392915050565b7fed9753748c66ee1df3e83ee8ba5d83244f01c004097e0e4eebd94e5fd6fea5f19160209151908152a238808061208b565b851561220f57600f0b5b8481600f0b8181136000146121ea5750506001600160801b03165b80156120735761210e6127109161ffff8a5460101c1690611cf8565b0494851561207357909192938095969a50506000146121d957505b813b156111555783612155928492838b51809681958294630b0d9c0960e01b8452309060048501611d48565b03925af180156121cf5785927f9cae4344a2aa90b3dbc6528a3f2ffaed048544717fac552b75ee12618278d7079289926121c0575b506002860161219a868254611d0b565b90558151908582526020820152a26001600160801b0316600f0b93388080808080612073565b6121c990611c6a565b3861218a565b87513d84823e3d90fd5b602435915081168114612129578280fd5b1215612208576001600160801b039061220290611d30565b166120f2565b50836120f2565b60801d600f0b6120d7565b5061ffff885460101c16151561206e565b8480fd5b60c43580159081150361222b5799612066565b5063b47b2fb160e01b9650949350505050565b6004356001600160a01b03818116918290036102c057602435908082168092036102c05760443562ffffff81168091036102c057606435908160020b8092036102c0576084359283168093036102c057604051936020850195865260408501526060840152608083015260a082015260a081526122d181611c99565b51902090565b6024356001600160a01b03818116918290036102c057604435908082168092036102c05760643562ffffff81168091036102c057608435908160020b8092036102c05760a4359283168093036102c057604051936020850195865260408501526060840152608083015260a082015260a081526122d181611c9956fea264697066735822122036240c439e054a2d62db11ec63ce0c528819d19cea890dab69bf7ebaaddcaf6164736f6c63430008180033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000000000000004444c5dc75cb358380d2e3de08a90000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000b80c866bb98944e967ac61b6665fbb5225f0d587000000000000000000000000a80a932f626c484898b851e681dbe2c9b279fbed

-----Decoded View---------------
Arg [0] : _poolManager (address): 0x000000000004444c5dc75cB358380D2e3dE08A90
Arg [1] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : _controller (address): 0xb80C866bb98944E967aC61b6665FBb5225f0D587
Arg [3] : _platformFeeCollector (address): 0xa80a932F626c484898B851E681dbE2c9B279FBEd

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000004444c5dc75cb358380d2e3de08a90
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 000000000000000000000000b80c866bb98944e967ac61b6665fbb5225f0d587
Arg [3] : 000000000000000000000000a80a932f626c484898b851e681dbe2c9b279fbed


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.