Sonic Blaze Testnet

Contract

0xF7c84E72B87Ba9440e4261156d166f99b56bCAB2

Overview

S Balance

Sonic Blaze LogoSonic Blaze LogoSonic Blaze Logo0 S

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FarmLens

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 800 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 27 : FarmLens.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {IERC20Metadata, IERC20} from "openzeppelin/token/ERC20/extensions/IERC20Metadata.sol";
import {IERC721Enumerable, IERC721} from "openzeppelin/token/ERC721/extensions/IERC721Enumerable.sol";
import {ILBPair, ILBToken} from "joe-v2/src/interfaces/ILBPair.sol";
import {ILBHooks} from "joe-v2/src/interfaces/ILBHooks.sol";

import "./interfaces/IBribeRewarder.sol";

import {IVoter} from "./interfaces/IVoter.sol";
import {IMasterChef} from "./interfaces/IMasterChef.sol";
import {IMasterChefRewarder} from "./interfaces/IMasterChefRewarder.sol";
import {IMagicSeaPair} from "./interfaces/IMagicSeaPair.sol";
import {IMlumStaking} from "./interfaces/IMlumStaking.sol";

import "forge-std/console.sol";
/**
 * @author MagicSea / BlueLabs
 * @title FarmLens
 *
 * Readonly functions to get data from the farm contracts
 */

contract FarmLens {
    IMasterChef immutable _masterChef;
    IVoter immutable _voter;
    IMlumStaking immutable _mlumStaking;

    struct FarmData {
        address masterChef;
        uint256 totalVotes;
        uint256 totalAllocPoint;
        uint256 totalLumPerSec;
        uint256 totalNumberOfFarms;
        Farm[] farms;
    }

    struct Farm {
        uint256 pid;
        address token;
        uint256 totalStaked;
        uint256 allocPoint;
        uint256 lastRewardTime;
        uint256 lumPerSecond;
        Rewarder rewarder;
        Pool poolInfo;
        uint256 userAmount;
        uint256 userPendingLumReward;
    }

    struct Token {
        address token;
        uint256 decimals;
        string symbol;
    }

    struct Pool {
        Token lpToken;
        Token token0;
        Token token1;
        uint256 totalSupply;
        uint256 reserve0;
        uint256 reserve1;
        uint256 binStep;
        address lbHook;
        address lbPair;
    }

    struct Rewarder {
        address rewarderAddress;
        bool isStarted;
        bool isEnded;
        uint256 pid;
        uint256 totalDeposited;
        uint256 remainingReward;
        uint256 rewardPerSec;
        uint256 lastUpdateTimestamp;
        uint256 endUpdateTimestamp;
        Token rewardToken;
        uint256 userPendingAmount;
    }

    // General vote data
    struct VoteData {
        address voterAddress;
        uint256 totalVotes;
        VoteInfo[] votes;
    }

    struct VoteInfo {
        address pool;
        uint256 votes;
        Bribe[] bribes;
    }

    // User bribe rewards

    struct UserBribeData {
        address account;
        BribeReward[] userBribeRewards;
    }

    struct Bribe {
        address poolAddress;
        uint256 startPeriodId;
        uint256 lastPeriodId;
        uint256 amountPerPeriod;
        address rewarder;
        Token rewardToken;
    }

    struct BribeReward {
        Bribe bribe;
        uint256 periodId;
        uint256 tokenId;
        uint256 pendingReward;
    }

    // Farm Info

    struct FarmVoteData {
        address voterAddress;
        uint256 currentPeriodId;
        uint256 totalWeight;
        uint256 totalVotes;
        FarmVoteInfo[] farmVotes;
    }

    struct FarmVoteInfo {
        uint256 pid;
        address pool;
        uint256 totalVotesPerPool;
        uint256 totalWeightPerFarm;
    }

    constructor(IMasterChef masterChef, IVoter voter, IMlumStaking mlumStaking) {
        _masterChef = masterChef;
        _voter = voter;
        _mlumStaking = mlumStaking;
    }

    function getFarmData(uint256 start, uint256 nb, address account) external view returns (FarmData memory data) {
        uint256 nbFarms = _masterChef.getNumberOfFarms();

        nb = start >= nbFarms ? 0 : (start + nb > nbFarms ? nbFarms - start : nb);

        data = FarmData({
            masterChef: address(_masterChef),
            totalVotes: 0,
            totalAllocPoint: _voter.getTotalWeight(),
            totalLumPerSec: _masterChef.getMetroPerSecond(),
            totalNumberOfFarms: nbFarms,
            farms: new Farm[](nb)
        });

        for (uint256 i; i < nb; ++i) {
            data.farms[i] = this.getFarmInfo(start + i, account);
            /* try this.getFarmInfo(start + i, account) returns (Farm memory farm) {
                data.farms[i] = farm;
            } catch {} */
        }
    }

    /**
     * @dev returns farm info for a pid. mimics the poolInfo from legacy farm implementation
     */
    function getFarmInfo(uint256 pid, address account) external view returns (Farm memory farm) {
        address lpAddress = address(_masterChef.getToken(pid));
        farm.pid = pid;
        farm.token = lpAddress;
        farm.totalStaked = _masterChef.getTotalDeposit(pid);
        farm.allocPoint = _voter.getWeight(pid);
        farm.lastRewardTime = _masterChef.getLastUpdateTimestamp(pid);
        // farm.lumPerSecond = _masterChef.getLumPerSecondForPid(pid);
        try this.getPoolInfo(lpAddress) returns (Pool memory poolInfo) {
            farm.poolInfo = poolInfo;
        } catch {}

        IMasterChefRewarder rewarder = _masterChef.getExtraRewarder(pid);

        (uint256 lumReward,, uint256 extraReward) = getMasterChefPendingRewardsAt(account, pid);

        farm.userAmount = _masterChef.getDeposit(pid, account);
        farm.userPendingLumReward = lumReward;

        if (address(rewarder) != address(0)) {
            (IERC20 token, uint256 rewardPerSecond, uint256 lastUpdateTimestamp, uint256 endTimestamp) =
                rewarder.getRewarderParameter();

            Token memory rewardToken;
            try this.getRewardToken(address(token)) returns (Token memory rewardToken_) {
                rewardToken = rewardToken_;
            } catch {}

            uint256 remainingReward = _getRemainingReward(address(rewarder));

            farm.rewarder = Rewarder({
                rewarderAddress: address(rewarder),
                isStarted: lastUpdateTimestamp <= block.timestamp,
                isEnded: endTimestamp <= block.timestamp,
                pid: pid,
                totalDeposited: farm.totalStaked,
                rewardToken: rewardToken,
                rewardPerSec: rewardPerSecond,
                remainingReward: remainingReward,
                lastUpdateTimestamp: lastUpdateTimestamp,
                endUpdateTimestamp: endTimestamp,
                userPendingAmount: extraReward
            });
        }
    }

    function getMasterChefPendingRewardsAt(address user, uint256 pid)
        public
        view
        returns (uint256 moeReward, address extraToken, uint256 extraReward)
    {
        uint256[] memory pids = new uint256[](1);
        pids[0] = pid;

        (uint256[] memory lumRewards, IERC20[] memory extraTokens, uint256[] memory extraRewards) =
            _masterChef.getPendingRewards(user, pids);

        return (lumRewards[0], address(extraTokens[0]), extraRewards[0]);
    }

    function getPoolInfo(address lpAddress) external view returns (Pool memory poolInfo) {
        try ILBHooks(lpAddress).getLBPair() returns (ILBPair lbPair) {
            uint16 binStep = lbPair.getBinStep();

            (uint256 reserveX, uint256 reserveY) = lbPair.getReserves();

            address tokenXAddress = address(lbPair.getTokenX());
            address tokenYAddress = address(lbPair.getTokenY());

            uint256 decimalsX = IERC20Metadata(tokenXAddress).decimals();
            uint256 decimalsY = IERC20Metadata(tokenYAddress).decimals();

            poolInfo.lbHook = lpAddress;
            poolInfo.lbPair = address(lbPair);
            poolInfo.binStep = binStep;

            poolInfo.lpToken = Token({
                token: lpAddress,
                symbol: IERC20Metadata(lpAddress).symbol(),
                decimals: IERC20Metadata(lpAddress).decimals()
            });

            poolInfo.totalSupply = IERC20(address(lpAddress)).totalSupply();
            poolInfo.token0 =
                Token({token: tokenXAddress, symbol: IERC20Metadata(tokenXAddress).symbol(), decimals: decimalsX});

            poolInfo.token1 =
                Token({token: tokenYAddress, symbol: IERC20Metadata(tokenYAddress).symbol(), decimals: decimalsY});

            poolInfo.reserve0 = reserveX;
            poolInfo.reserve1 = reserveY;
        } catch {
            IMagicSeaPair pair = IMagicSeaPair(lpAddress);

            (uint256 reserve0, uint256 reserve1,) = pair.getReserves();

            address token0Address = pair.token0();
            address token1Address = pair.token1();

            uint256 decimals0 = IERC20Metadata(token0Address).decimals();
            uint256 decimals1 = IERC20Metadata(token1Address).decimals();

            poolInfo.lpToken = Token({
                token: lpAddress,
                symbol: IERC20Metadata(lpAddress).symbol(),
                decimals: IERC20Metadata(lpAddress).decimals()
            });
            poolInfo.totalSupply = pair.totalSupply();
            poolInfo.token0 =
                Token({token: token0Address, symbol: IERC20Metadata(token0Address).symbol(), decimals: decimals0});

            poolInfo.token1 =
                Token({token: token1Address, symbol: IERC20Metadata(token1Address).symbol(), decimals: decimals1});

            poolInfo.reserve0 = reserve0;
            poolInfo.reserve1 = reserve1;
        }
    }

    function _getRemainingReward(address rewarder) private view returns (uint256 remainingReward) {
        remainingReward = IMasterChefRewarder(rewarder).getRemainingReward();
        // (, bytes memory data) = rewarder.staticcall(abi.encodeWithSelector(IBaseRewarder.getRemainingReward.selector));
        // remainingReward = abi.decode(data, (uint256));
    }

    function getVoteData(uint256 start, uint256 nb) external view returns (VoteData memory voteData) {
        uint256 nbPools = _voter.getVotedPoolsLength();

        nb = start >= nbPools ? 0 : (start + nb > nbPools ? nbPools - start : nb);

        voteData =
            VoteData({voterAddress: address(_voter), totalVotes: _voter.getTotalVotes(), votes: new VoteInfo[](nb)});

        for (uint256 i; i < nb; ++i) {
            try this.getVoteInfoAt(start + i) returns (VoteInfo memory info) {
                voteData.votes[i] = info;
            } catch {}
        }
    }

    function getVoteInfoAt(uint256 index) external view returns (VoteInfo memory voteInfo) {
        (address pool, uint256 votes) = _voter.getVotedPoolsAtIndex(index);

        Bribe[] memory bribes = this.getBribesForPool(_voter.getCurrentVotingPeriod(), pool);

        voteInfo = VoteInfo({pool: pool, votes: votes, bribes: bribes});
    }

    function getBribesForPool(uint256 period, address pool) external view returns (Bribe[] memory bribes) {
        uint256 length = _voter.getBribeRewarderLength(period, pool);
        bribes = new Bribe[](length);

        for (uint256 i = 0; i < length; ++i) {
            IBribeRewarder rewarder = _voter.getBribeRewarderAt(period, pool, i);

            bribes[i] = this.getBribe(rewarder);
        }
    }

    function getBribe(IBribeRewarder rewarder) external view returns (Bribe memory bribe) {
        bribe = Bribe({
            poolAddress: rewarder.getPool(),
            rewarder: address(rewarder),
            startPeriodId: rewarder.getStartVotingPeriodId(),
            lastPeriodId: rewarder.getLastVotingPeriodId(),
            amountPerPeriod: rewarder.getAmountPerPeriod(),
            rewardToken: this.getRewardToken(address(rewarder.getToken()))
        });
    }

    function getRewardToken(address tokenAddress) external view returns (Token memory rewardToken) {
        rewardToken = Token({
            token: tokenAddress,
            symbol: IERC20Metadata(tokenAddress).symbol(),
            decimals: IERC20Metadata(tokenAddress).decimals()
        });
    }

    /// returns user rewards from perod
    function getUserBribeRewards(address account) external view returns (UserBribeData memory userData) {
        userData.account = account;

        // get tokenIds from account
        // uint256 tokenIdLength = IERC721(address(_mlumStaking)).balanceOf(account);

        // get user rewards by last period, pending rewards are accrued
        uint256 lastPeriod;
        try _voter.getLatestFinishedPeriod() returns (uint256 lastPeriod_) {
            lastPeriod = lastPeriod_;
        } catch {
            lastPeriod = 0; // this will give zero rewards anyway
        }

        uint256 numberOfRewards = _voter.getUserBribeRewarderLength(lastPeriod, account);
        userData.userBribeRewards = new BribeReward[](numberOfRewards);
        for (uint256 i; i < numberOfRewards; ++i) {
            // return rewards for each rewarder
            userData.userBribeRewards[i] = this.getUserBribeRewardFor(lastPeriod, account, i);
        }
    }

    function getUserBribeRewardFor(uint256 period, address account, uint256 index)
        external
        view
        returns (BribeReward memory userReward)
    {
        IBribeRewarder rewarder = _voter.getUserBribeRewaderAt(period, account, index);
        userReward.bribe = this.getBribe(rewarder);
        userReward.periodId = period;
        userReward.pendingReward = rewarder.getPendingReward(account);
    }
}

File 2 of 27 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 3 of 27 : IERC721Enumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol)

pragma solidity ^0.8.20;

import {IERC721} from "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

File 4 of 27 : ILBPair.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

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

import {Hooks} from "../libraries/Hooks.sol";
import {ILBFactory} from "./ILBFactory.sol";
import {ILBFlashLoanCallback} from "./ILBFlashLoanCallback.sol";
import {ILBToken} from "./ILBToken.sol";

interface ILBPair is ILBToken {
    error LBPair__ZeroBorrowAmount();
    error LBPair__AddressZero();
    error LBPair__EmptyMarketConfigs();
    error LBPair__FlashLoanCallbackFailed();
    error LBPair__FlashLoanInsufficientAmount();
    error LBPair__InsufficientAmountIn();
    error LBPair__InsufficientAmountOut();
    error LBPair__InvalidInput();
    error LBPair__InvalidStaticFeeParameters();
    error LBPair__OnlyFactory();
    error LBPair__OnlyProtocolFeeRecipient();
    error LBPair__OutOfLiquidity();
    error LBPair__TokenNotSupported();
    error LBPair__ZeroAmount(uint24 id);
    error LBPair__ZeroAmountsOut(uint24 id);
    error LBPair__ZeroShares(uint24 id);
    error LBPair__MaxTotalFeeExceeded();
    error LBPair__InvalidHooks();

    struct MintArrays {
        uint256[] ids;
        bytes32[] amounts;
        uint256[] liquidityMinted;
    }

    event DepositedToBins(address indexed sender, address indexed to, uint256[] ids, bytes32[] amounts);

    event WithdrawnFromBins(address indexed sender, address indexed to, uint256[] ids, bytes32[] amounts);

    event CompositionFees(address indexed sender, uint24 id, bytes32 totalFees, bytes32 protocolFees);

    event CollectedProtocolFees(address indexed feeRecipient, bytes32 protocolFees);

    event Swap(
        address indexed sender,
        address indexed to,
        uint24 id,
        bytes32 amountsIn,
        bytes32 amountsOut,
        uint24 volatilityAccumulator,
        bytes32 totalFees,
        bytes32 protocolFees
    );

    event StaticFeeParametersSet(
        address indexed sender,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator
    );

    event HooksParametersSet(address indexed sender, bytes32 hooksParameters);

    event FlashLoan(
        address indexed sender,
        ILBFlashLoanCallback indexed receiver,
        uint24 activeId,
        bytes32 amounts,
        bytes32 totalFees,
        bytes32 protocolFees
    );

    event OracleLengthIncreased(address indexed sender, uint16 oracleLength);

    event ForcedDecay(address indexed sender, uint24 idReference, uint24 volatilityReference);

    function initialize(
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator,
        uint24 activeId
    ) external;

    function implementation() external view returns (address);

    function getFactory() external view returns (ILBFactory factory);

    function getTokenX() external view returns (IERC20 tokenX);

    function getTokenY() external view returns (IERC20 tokenY);

    function getBinStep() external view returns (uint16 binStep);

    function getReserves() external view returns (uint128 reserveX, uint128 reserveY);

    function getActiveId() external view returns (uint24 activeId);

    function getBin(uint24 id) external view returns (uint128 binReserveX, uint128 binReserveY);

    function getNextNonEmptyBin(bool swapForY, uint24 id) external view returns (uint24 nextId);

    function getProtocolFees() external view returns (uint128 protocolFeeX, uint128 protocolFeeY);

    function getStaticFeeParameters()
        external
        view
        returns (
            uint16 baseFactor,
            uint16 filterPeriod,
            uint16 decayPeriod,
            uint16 reductionFactor,
            uint24 variableFeeControl,
            uint16 protocolShare,
            uint24 maxVolatilityAccumulator
        );

    function getLBHooksParameters() external view returns (bytes32 hooksParameters);

    function getVariableFeeParameters()
        external
        view
        returns (uint24 volatilityAccumulator, uint24 volatilityReference, uint24 idReference, uint40 timeOfLastUpdate);

    function getOracleParameters()
        external
        view
        returns (uint8 sampleLifetime, uint16 size, uint16 activeSize, uint40 lastUpdated, uint40 firstTimestamp);

    function getOracleSampleAt(uint40 lookupTimestamp)
        external
        view
        returns (uint64 cumulativeId, uint64 cumulativeVolatility, uint64 cumulativeBinCrossed);

    function getPriceFromId(uint24 id) external view returns (uint256 price);

    function getIdFromPrice(uint256 price) external view returns (uint24 id);

    function getSwapIn(uint128 amountOut, bool swapForY)
        external
        view
        returns (uint128 amountIn, uint128 amountOutLeft, uint128 fee);

    function getSwapOut(uint128 amountIn, bool swapForY)
        external
        view
        returns (uint128 amountInLeft, uint128 amountOut, uint128 fee);

    function swap(bool swapForY, address to) external returns (bytes32 amountsOut);

    function flashLoan(ILBFlashLoanCallback receiver, bytes32 amounts, bytes calldata data) external;

    function mint(address to, bytes32[] calldata liquidityConfigs, address refundTo)
        external
        returns (bytes32 amountsReceived, bytes32 amountsLeft, uint256[] memory liquidityMinted);

    function burn(address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn)
        external
        returns (bytes32[] memory amounts);

    function collectProtocolFees() external returns (bytes32 collectedProtocolFees);

    function increaseOracleLength(uint16 newLength) external;

    function setStaticFeeParameters(
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator
    ) external;

    function setHooksParameters(bytes32 hooksParameters, bytes calldata onHooksSetData) external;

    function forceDecay() external;
}

File 5 of 27 : ILBHooks.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import {ILBPair} from "./ILBPair.sol";

import {Hooks} from "../libraries/Hooks.sol";

interface ILBHooks {
    function getLBPair() external view returns (ILBPair);

    function isLinked() external view returns (bool);

    function onHooksSet(bytes32 hooksParameters, bytes calldata onHooksSetData) external returns (bytes4);

    function beforeSwap(address sender, address to, bool swapForY, bytes32 amountsIn) external returns (bytes4);

    function afterSwap(address sender, address to, bool swapForY, bytes32 amountsOut) external returns (bytes4);

    function beforeFlashLoan(address sender, address to, bytes32 amounts) external returns (bytes4);

    function afterFlashLoan(address sender, address to, bytes32 fees, bytes32 feesReceived) external returns (bytes4);

    function beforeMint(address sender, address to, bytes32[] calldata liquidityConfigs, bytes32 amountsReceived)
        external
        returns (bytes4);

    function afterMint(address sender, address to, bytes32[] calldata liquidityConfigs, bytes32 amountsIn)
        external
        returns (bytes4);

    function beforeBurn(
        address sender,
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amountsToBurn
    ) external returns (bytes4);

    function afterBurn(
        address sender,
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amountsToBurn
    ) external returns (bytes4);

    function beforeBatchTransferFrom(
        address sender,
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts
    ) external returns (bytes4);

    function afterBatchTransferFrom(
        address sender,
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts
    ) external returns (bytes4);
}

File 6 of 27 : IBribeRewarder.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

import {IRewarder} from "./IRewarder.sol";

interface IBribeRewarder is IRewarder {
    error BribeRewarder__OnlyVoter();
    error BribeRewarder__InsufficientFunds();
    error BribeRewarder__WrongStartId();
    error BribeRewarder__WrongEndId();
    error BribeRewarder__ZeroReward();
    error BribeRewarder__NativeTransferFailed();
    error BribeRewarder__NotOwner();
    error BribeRewarder__CannotRenounceOwnership();
    error BribeRewarder__NotNativeRewarder();
    error BribeRewarder__AlreadyInitialized();
    error BribeRewarder__PeriodNotFound();
    error BribeRewarder__AmountTooLow();
    error BribeRewarder__OnlyVoterAdmin();

    event Claimed(address indexed account, address indexed pool, uint256 amount);
    event Deposited(uint256 indexed periodId, address indexed account, address indexed pool, uint256 amount);
    event BribeInit(uint256 indexed startId, uint256 indexed lastId, uint256 amountPerPeriod);
    event Swept(IERC20 indexed token, address indexed account, uint256 amount);

    function bribe(uint256 startId, uint256 lastId, uint256 amountPerPeriod) external;

    function claim(address account) external;

    function deposit(uint256 periodId, address account, uint256 deltaAmount) external;

    function getPool() external view returns (address);

    function getPendingReward(address account) external view returns (uint256);

    function getBribePeriods() external view returns (address pool, uint256[] memory);

    function getStartVotingPeriodId() external view returns (uint256);

    function getLastVotingPeriodId() external view returns (uint256);

    function getAmountPerPeriod() external view returns (uint256);

    function sweep(IERC20 token, address account) external;
}

File 7 of 27 : IVoter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {IBribeRewarder} from "./IBribeRewarder.sol";
import {IMasterChef} from "./IMasterChef.sol";

interface IVoter {
    error IVoter__InvalidLength();
    error IVoter_VotingPeriodNotStarted();
    error IVoter_VotingPeriodEnded();
    error IVoter__AlreadyVoted();
    error IVoter__NotOwner();
    error IVoter__InsufficientVotingPower();
    error IVoter__TooManyPoolIds();
    error IVoter__DuplicatePoolId(uint256 pid);
    error IVoter__InsufficientLockTime();
    error Voter__InvalidRegisterCaller();
    error Voter__PoolNotVotable();
    error IVoter__NoFinishedPeriod();
    error IVoter_ZeroValue();
    error IVoter__EmergencyUnlock();

    event VotingPeriodStarted();
    event Voted(uint256 indexed tokenId, uint256 votingPeriod, address[] votedPools, uint256[] votesDeltaAmounts);
    event TopPoolIdsWithWeightsSet(uint256[] poolIds, uint256[] pidWeights);
    event VoterPoolValidatorUpdated(address indexed validator);
    event VotingDurationUpdated(uint256 duration);
    event MinimumLockTimeUpdated(uint256 lockTime);
    event MinimumVotesPerPoolUpdated(uint256 minimum);
    event OperatorUpdated(address indexed operator);
    event ElevatedRewarderAdded(address indexed rewarder);
    event ElevatedRewarderRemoved(address indexed rewarder);

    struct VotingPeriod {
        uint256 startTime;
        uint256 endTime;
    }

    function getMasterChef() external view returns (IMasterChef);

    function getTotalWeight() external view returns (uint256);

    function getTopPoolIds() external view returns (uint256[] memory);

    function getWeight(uint256 pid) external view returns (uint256);

    function hasVoted(uint256 period, uint256 tokenId) external view returns (bool);

    function getCurrentVotingPeriod() external view returns (uint256);

    function getLatestFinishedPeriod() external view returns (uint256);

    function getPeriodStartTime() external view returns (uint256);

    function getPeriodStartEndtime(uint256 periodId) external view returns (uint256, uint256);

    function getVotesPerPeriod(uint256 periodId, address pool) external view returns (uint256);

    function getVotedPools() external view returns (address[] memory);

    function getVotedPoolsLength() external view returns (uint256);

    function getVotedPoolsAtIndex(uint256 index) external view returns (address, uint256);

    function getTotalVotes() external view returns (uint256);

    function getUserVotes(uint256 tokenId, address pool) external view returns (uint256);

    function getPoolVotesPerPeriod(uint256 periodId, address pool) external view returns (uint256);

    function getUserBribeRewaderAt(uint256 period, address account, uint256 index)
        external
        view
        returns (IBribeRewarder);

    function getUserBribeRewarderLength(uint256 period, address account) external view returns (uint256);

    function getBribeRewarderAt(uint256 period, address pool, uint256 index) external view returns (IBribeRewarder);

    function getBribeRewarderLength(uint256 period, address pool) external view returns (uint256);

    function ownerOf(uint256 tokenId, address account) external view returns (bool);

    function onRegister() external;
}

File 8 of 27 : IMasterChef.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

import {IMasterChefRewarder} from "./IMasterChefRewarder.sol";
import {IMetro} from "./IMetro.sol";
import {IVoter} from "./IVoter.sol";
import {Rewarder} from "../libraries/Rewarder.sol";
import {Amounts} from "../libraries/Amounts.sol";
import {IRewarderFactory} from "./IRewarderFactory.sol";

interface IMasterChef {
    error MasterChef__InvalidShares();
    error MasterChef__InvalidMetroPerSecond();
    error MasterChef__ZeroAddress();
    error MasterChef__NotMasterchefRewarder();
    error MasterChef__CannotRenounceOwnership();
    error MasterChef__MintFailed();
    error MasterChef__TrusteeNotSet();
    error MasterChef__NotTrustedCaller();

    struct Farm {
        Amounts.Parameter amounts;
        Rewarder.Parameter rewarder;
        IERC20 token;
        IMasterChefRewarder extraRewarder;
    }
    // bool depositOnBehalf; // true if v2 pool zap in should be possible
    // uint256 startTime;

    event PositionModified(uint256 indexed pid, address indexed account, int256 deltaAmount, uint256 metroReward);

    event MetroPerSecondSet(uint256 metroPerSecond);

    event FarmAdded(uint256 indexed pid, IERC20 indexed token);

    event ExtraRewarderSet(uint256 indexed pid, IMasterChefRewarder extraRewarder);

    event TreasurySet(address indexed treasury);

    event VoterSet(IVoter indexed newVoter);

    event TrusteeSet(address indexed trustee);

    event MintMetroSet(bool mintMetro);

    event OperatorUpdated(address indexed operator);

    function add(IERC20 token, IMasterChefRewarder extraRewarder) external;

    function claim(uint256[] memory pids) external;

    function deposit(uint256 pid, uint256 amount) external;

    function depositOnBehalf(uint256 pid, uint256 amount, address account) external;

    function emergencyWithdraw(uint256 pid) external;

    function getDeposit(uint256 pid, address account) external view returns (uint256);

    function getLastUpdateTimestamp(uint256 pid) external view returns (uint256);

    function getPendingRewards(address account, uint256[] memory pids)
        external
        view
        returns (uint256[] memory metroRewards, IERC20[] memory extraTokens, uint256[] memory extraRewards);

    function getExtraRewarder(uint256 pid) external view returns (IMasterChefRewarder);

    function getMetro() external view returns (IMetro);

    function getMetroPerSecond() external view returns (uint256);

    function getMetroPerSecondForPid(uint256 pid) external view returns (uint256);

    function getNumberOfFarms() external view returns (uint256);

    function getToken(uint256 pid) external view returns (IERC20);

    function getTotalDeposit(uint256 pid) external view returns (uint256);

    function getTreasury() external view returns (address);

    function getTreasuryShare() external view returns (uint256);

    function getRewarderFactory() external view returns (IRewarderFactory);

    function getLBHooksManager() external view returns (address);

    function getVoter() external view returns (IVoter);

    function setExtraRewarder(uint256 pid, IMasterChefRewarder extraRewarder) external;

    function setMetroPerSecond(uint96 metroPerSecond) external;

    function setTreasury(address treasury) external;

    function setVoter(IVoter voter) external;

    function setTrustee(address trustee) external;

    function updateAll(uint256[] calldata pids) external;

    function withdraw(uint256 pid, uint256 amount) external;
}

File 9 of 27 : IMasterChefRewarder.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IBaseRewarder} from "./IBaseRewarder.sol";

interface IMasterChefRewarder is IBaseRewarder {
    error MasterChefRewarder__AlreadyLinked();
    error MasterChefRewarder__NotLinked();
    error MasterChefRewarder__UseUnlink();

    enum Status {
        Unlinked,
        Linked,
        Stopped
    }

    function link(uint256 pid) external;

    function unlink(uint256 pid) external;

    function onEmergency(address account, uint256 pid, uint256 oldBalance, uint256 newBalance, uint256 oldTotalSupply) external;
}

File 10 of 27 : IMagicSeaPair.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.5.0;

interface IMagicSeaPair {
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Transfer(address indexed from, address indexed to, uint256 value);

    function name() external pure returns (string memory);

    function symbol() external pure returns (string memory);

    function decimals() external pure returns (uint8);

    function totalSupply() external view returns (uint256);

    function balanceOf(address owner) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

    function transfer(address to, uint256 value) external returns (bool);

    function transferFrom(address from, address to, uint256 value) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);

    function PERMIT_TYPEHASH() external pure returns (bytes32);

    function nonces(address owner) external view returns (uint256);

    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        external;

    event FeeAmountUpdated(uint256 prevFeeAmount, uint256 feeAmount);
    event Mint(address indexed sender, uint256 amount0, uint256 amount1);
    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amount0Out,
        uint256 amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint256);

    function factory() external view returns (address);

    function token0() external view returns (address);

    function token1() external view returns (address);

    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);

    function price0CumulativeLast() external view returns (uint256);

    function price1CumulativeLast() external view returns (uint256);

    function kLast() external view returns (uint256);

    function mint(address to) external returns (uint256 liquidity);

    function burn(address to) external returns (uint256 amount0, uint256 amount1);

    function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;

    function skim(address to) external;

    function sync() external;

    function initialize(address, address) external;

    function feeAmount() external view returns (uint256);
}

File 11 of 27 : IMlumStaking.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "openzeppelin/token/ERC20/IERC20.sol";
import "openzeppelin/token/ERC721/IERC721.sol";

interface IMlumStaking is IERC721 {
    // Info of each NFT (staked position).
    struct StakingPosition {
        uint256 amount; // How many lp tokens the user has provided
        uint256 amountWithMultiplier; // Amount + lock bonus faked amount (amount + amount*multiplier)
        uint256 startLockTime; // The time at which the user made his deposit
        uint256 initialLockDuration; // lock duration on creation
        uint256 lockDuration; // The lock duration in seconds
        uint256 lockMultiplier; // Active lock multiplier (times 1e2)
        uint256 rewardDebt; // Reward debt
        uint256 totalMultiplier; // lockMultiplier
    }

    error IMlumStaking_TooMuchTokenDecimals();
    error IMlumStaking_ZeroAddress();
    error IMlumStaking_NotOwner();
    error IMlumStaking_MaxLockMultiplierTooHigh();
    error IMlumStaking_LocksDisabled();
    error IMlumStaking_ZeroAmount();
    error IMlumStaking_PositionStillLocked();
    error IMlumStaking_InvalidLockDuration();
    error IMlumStaking_TransferNotAllowed();
    error IMlumStaking_AmountTooHigh();
    error IMlumStaking_SameAddress();

    // Events

    event AddToPosition(uint256 indexed tokenId, address user, uint256 amount);
    event CreatePosition(uint256 indexed tokenId, uint256 amount, uint256 lockDuration);
    event WithdrawFromPosition(uint256 indexed tokenId, uint256 amount);
    event EmergencyWithdraw(uint256 indexed tokenId, uint256 amount);
    event LockPosition(uint256 indexed tokenId, uint256 lockDuration);
    event HarvestPosition(uint256 indexed tokenId, address to, uint256 pending);
    event PoolUpdated(uint256 lastRewardTime, uint256 accRewardsPerShare);
    event SetLockMultiplierSettings(uint256 maxLockDuration, uint256 maxLockMultiplier);
    event SetBoostMultiplierSettings(uint256 maxGlobalMultiplier, uint256 maxBoostMultiplier);
    event SetEmergencyUnlock(bool emergencyUnlock);
    event SetMinimumLockDuration(uint256 minimumLockDuration);

    function exists(uint256 tokenId) external view returns (bool);

    function getStakedToken() external view returns (IERC20);

    function getRewardToken() external view returns (IERC20);

    function getMultiplierSettings() external view returns (uint256, uint256, uint256);

    function getLastRewardBalance() external view returns (uint256);

    function lastTokenId() external view returns (uint256);

    function getStakedSupply() external view returns (uint256);

    function isUnlocked() external view returns (bool);

    function getStakedSupplyWithMultiplier() external view returns (uint256);

    function hasDeposits() external view returns (bool);

    function getStakingPosition(uint256 tokenId) external view returns (StakingPosition memory position);

    function pendingRewards(uint256 tokenId) external view returns (uint256);

    function createPosition(uint256 amount, uint256 lockDuration) external;

    function addToPosition(uint256 tokenId, uint256 amountToAdd) external;

    function harvestPosition(uint256 tokenId) external;

    function harvestPositions(uint256[] calldata tokenIds) external;

    function withdrawFromPosition(uint256 tokenId, uint256 amountToWithdraw) external;

    function emergencyWithdraw(uint256 tokenId) external;

    function setMinimumLockDuration(uint256 minimumLockDuration) external;
}

File 12 of 27 : console.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

library console {
    address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);

    function _sendLogPayload(bytes memory payload) private view {
        uint256 payloadLength = payload.length;
        address consoleAddress = CONSOLE_ADDRESS;
        /// @solidity memory-safe-assembly
        assembly {
            let payloadStart := add(payload, 32)
            let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
        }
    }

    function log() internal view {
        _sendLogPayload(abi.encodeWithSignature("log()"));
    }

    function logInt(int p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(int)", p0));
    }

    function logUint(uint p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
    }

    function logString(string memory p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function logBool(bool p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function logAddress(address p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function logBytes(bytes memory p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
    }

    function logBytes1(bytes1 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
    }

    function logBytes2(bytes2 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
    }

    function logBytes3(bytes3 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
    }

    function logBytes4(bytes4 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
    }

    function logBytes5(bytes5 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
    }

    function logBytes6(bytes6 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
    }

    function logBytes7(bytes7 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
    }

    function logBytes8(bytes8 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
    }

    function logBytes9(bytes9 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
    }

    function logBytes10(bytes10 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
    }

    function logBytes11(bytes11 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
    }

    function logBytes12(bytes12 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
    }

    function logBytes13(bytes13 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
    }

    function logBytes14(bytes14 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
    }

    function logBytes15(bytes15 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
    }

    function logBytes16(bytes16 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
    }

    function logBytes17(bytes17 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
    }

    function logBytes18(bytes18 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
    }

    function logBytes19(bytes19 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
    }

    function logBytes20(bytes20 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
    }

    function logBytes21(bytes21 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
    }

    function logBytes22(bytes22 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
    }

    function logBytes23(bytes23 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
    }

    function logBytes24(bytes24 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
    }

    function logBytes25(bytes25 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
    }

    function logBytes26(bytes26 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
    }

    function logBytes27(bytes27 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
    }

    function logBytes28(bytes28 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
    }

    function logBytes29(bytes29 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
    }

    function logBytes30(bytes30 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
    }

    function logBytes31(bytes31 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
    }

    function logBytes32(bytes32 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
    }

    function log(uint p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
    }

    function log(string memory p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function log(bool p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function log(address p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function log(uint p0, uint p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1));
    }

    function log(uint p0, string memory p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1));
    }

    function log(uint p0, bool p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1));
    }

    function log(uint p0, address p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1));
    }

    function log(string memory p0, uint p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1));
    }

    function log(string memory p0, string memory p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
    }

    function log(string memory p0, bool p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
    }

    function log(string memory p0, address p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
    }

    function log(bool p0, uint p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1));
    }

    function log(bool p0, string memory p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
    }

    function log(bool p0, bool p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
    }

    function log(bool p0, address p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
    }

    function log(address p0, uint p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1));
    }

    function log(address p0, string memory p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
    }

    function log(address p0, bool p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
    }

    function log(address p0, address p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
    }

    function log(uint p0, uint p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2));
    }

    function log(uint p0, uint p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2));
    }

    function log(uint p0, uint p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2));
    }

    function log(uint p0, uint p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2));
    }

    function log(uint p0, string memory p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2));
    }

    function log(uint p0, string memory p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2));
    }

    function log(uint p0, string memory p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2));
    }

    function log(uint p0, string memory p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2));
    }

    function log(uint p0, bool p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2));
    }

    function log(uint p0, bool p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2));
    }

    function log(uint p0, bool p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2));
    }

    function log(uint p0, bool p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2));
    }

    function log(uint p0, address p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2));
    }

    function log(uint p0, address p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2));
    }

    function log(uint p0, address p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2));
    }

    function log(uint p0, address p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2));
    }

    function log(string memory p0, uint p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2));
    }

    function log(string memory p0, uint p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2));
    }

    function log(string memory p0, uint p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2));
    }

    function log(string memory p0, uint p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
    }

    function log(string memory p0, address p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2));
    }

    function log(string memory p0, address p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
    }

    function log(string memory p0, address p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
    }

    function log(string memory p0, address p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
    }

    function log(bool p0, uint p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2));
    }

    function log(bool p0, uint p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2));
    }

    function log(bool p0, uint p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2));
    }

    function log(bool p0, uint p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
    }

    function log(bool p0, bool p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2));
    }

    function log(bool p0, bool p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
    }

    function log(bool p0, bool p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
    }

    function log(bool p0, bool p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
    }

    function log(bool p0, address p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2));
    }

    function log(bool p0, address p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
    }

    function log(bool p0, address p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
    }

    function log(bool p0, address p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
    }

    function log(address p0, uint p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2));
    }

    function log(address p0, uint p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2));
    }

    function log(address p0, uint p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2));
    }

    function log(address p0, uint p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2));
    }

    function log(address p0, string memory p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2));
    }

    function log(address p0, string memory p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
    }

    function log(address p0, string memory p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
    }

    function log(address p0, string memory p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
    }

    function log(address p0, bool p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2));
    }

    function log(address p0, bool p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
    }

    function log(address p0, bool p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
    }

    function log(address p0, bool p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
    }

    function log(address p0, address p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2));
    }

    function log(address p0, address p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
    }

    function log(address p0, address p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
    }

    function log(address p0, address p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
    }

    function log(uint p0, uint p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
    }

}

File 13 of 27 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
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);
}

File 14 of 27 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 15 of 27 : Hooks.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import {ILBHooks} from "../interfaces/ILBHooks.sol";

/**
 * @title Hooks library
 * @notice This library contains functions that should be used to interact with hooks
 */
library Hooks {
    error Hooks__CallFailed();

    bytes32 internal constant BEFORE_SWAP_FLAG = bytes32(uint256(1 << 160));
    bytes32 internal constant AFTER_SWAP_FLAG = bytes32(uint256(1 << 161));
    bytes32 internal constant BEFORE_FLASH_LOAN_FLAG = bytes32(uint256(1 << 162));
    bytes32 internal constant AFTER_FLASH_LOAN_FLAG = bytes32(uint256(1 << 163));
    bytes32 internal constant BEFORE_MINT_FLAG = bytes32(uint256(1 << 164));
    bytes32 internal constant AFTER_MINT_FLAG = bytes32(uint256(1 << 165));
    bytes32 internal constant BEFORE_BURN_FLAG = bytes32(uint256(1 << 166));
    bytes32 internal constant AFTER_BURN_FLAG = bytes32(uint256(1 << 167));
    bytes32 internal constant BEFORE_TRANSFER_FLAG = bytes32(uint256(1 << 168));
    bytes32 internal constant AFTER_TRANSFER_FLAG = bytes32(uint256(1 << 169));

    struct Parameters {
        address hooks;
        bool beforeSwap;
        bool afterSwap;
        bool beforeFlashLoan;
        bool afterFlashLoan;
        bool beforeMint;
        bool afterMint;
        bool beforeBurn;
        bool afterBurn;
        bool beforeBatchTransferFrom;
        bool afterBatchTransferFrom;
    }

    /**
     * @dev Helper function to encode the hooks parameters to a single bytes32 value
     * @param parameters The hooks parameters
     * @return hooksParameters The encoded hooks parameters
     */
    function encode(Parameters memory parameters) internal pure returns (bytes32 hooksParameters) {
        hooksParameters = bytes32(uint256(uint160(address(parameters.hooks))));

        if (parameters.beforeSwap) hooksParameters |= BEFORE_SWAP_FLAG;
        if (parameters.afterSwap) hooksParameters |= AFTER_SWAP_FLAG;
        if (parameters.beforeFlashLoan) hooksParameters |= BEFORE_FLASH_LOAN_FLAG;
        if (parameters.afterFlashLoan) hooksParameters |= AFTER_FLASH_LOAN_FLAG;
        if (parameters.beforeMint) hooksParameters |= BEFORE_MINT_FLAG;
        if (parameters.afterMint) hooksParameters |= AFTER_MINT_FLAG;
        if (parameters.beforeBurn) hooksParameters |= BEFORE_BURN_FLAG;
        if (parameters.afterBurn) hooksParameters |= AFTER_BURN_FLAG;
        if (parameters.beforeBatchTransferFrom) hooksParameters |= BEFORE_TRANSFER_FLAG;
        if (parameters.afterBatchTransferFrom) hooksParameters |= AFTER_TRANSFER_FLAG;
    }

    /**
     * @dev Helper function to decode the hooks parameters from a single bytes32 value
     * @param hooksParameters The encoded hooks parameters
     * @return parameters The hooks parameters
     */
    function decode(bytes32 hooksParameters) internal pure returns (Parameters memory parameters) {
        parameters.hooks = getHooks(hooksParameters);

        parameters.beforeSwap = (hooksParameters & BEFORE_SWAP_FLAG) != 0;
        parameters.afterSwap = (hooksParameters & AFTER_SWAP_FLAG) != 0;
        parameters.beforeFlashLoan = (hooksParameters & BEFORE_FLASH_LOAN_FLAG) != 0;
        parameters.afterFlashLoan = (hooksParameters & AFTER_FLASH_LOAN_FLAG) != 0;
        parameters.beforeMint = (hooksParameters & BEFORE_MINT_FLAG) != 0;
        parameters.afterMint = (hooksParameters & AFTER_MINT_FLAG) != 0;
        parameters.beforeBurn = (hooksParameters & BEFORE_BURN_FLAG) != 0;
        parameters.afterBurn = (hooksParameters & AFTER_BURN_FLAG) != 0;
        parameters.beforeBatchTransferFrom = (hooksParameters & BEFORE_TRANSFER_FLAG) != 0;
        parameters.afterBatchTransferFrom = (hooksParameters & AFTER_TRANSFER_FLAG) != 0;
    }

    /**
     * @dev Helper function to get the hooks address from the encoded hooks parameters
     * @param hooksParameters The encoded hooks parameters
     * @return hooks The hooks address
     */
    function getHooks(bytes32 hooksParameters) internal pure returns (address hooks) {
        hooks = address(uint160(uint256(hooksParameters)));
    }

    /**
     * @dev Helper function to set the hooks address in the encoded hooks parameters
     * @param hooksParameters The encoded hooks parameters
     * @param newHooks The new hooks address
     * @return hooksParameters The updated hooks parameters
     */
    function setHooks(bytes32 hooksParameters, address newHooks) internal pure returns (bytes32) {
        return bytes32(bytes12(hooksParameters)) | bytes32(uint256(uint160(newHooks)));
    }

    /**
     * @dev Helper function to get the flags from the encoded hooks parameters
     * @param hooksParameters The encoded hooks parameters
     * @return flags The flags
     */
    function getFlags(bytes32 hooksParameters) internal pure returns (bytes12 flags) {
        flags = bytes12(hooksParameters);
    }

    /**
     * @dev Helper function call the onHooksSet function on the hooks contract, only if the
     * hooksParameters is not 0
     * @param hooksParameters The encoded hooks parameters
     * @param onHooksSetData The data to pass to the onHooksSet function
     */
    function onHooksSet(bytes32 hooksParameters, bytes calldata onHooksSetData) internal {
        if (hooksParameters != 0) {
            _safeCall(
                hooksParameters, abi.encodeWithSelector(ILBHooks.onHooksSet.selector, hooksParameters, onHooksSetData)
            );
        }
    }

    /**
     * @dev Helper function to call the beforeSwap function on the hooks contract, only if the
     * BEFORE_SWAP_FLAG is set in the hooksParameters
     * @param hooksParameters The encoded hooks parameters
     * @param sender The sender
     * @param to The recipient
     * @param swapForY Whether the swap is for Y
     * @param amountsIn The amounts in
     */
    function beforeSwap(bytes32 hooksParameters, address sender, address to, bool swapForY, bytes32 amountsIn)
        internal
    {
        if ((hooksParameters & BEFORE_SWAP_FLAG) != 0) {
            _safeCall(
                hooksParameters, abi.encodeWithSelector(ILBHooks.beforeSwap.selector, sender, to, swapForY, amountsIn)
            );
        }
    }

    /**
     * @dev Helper function to call the afterSwap function on the hooks contract, only if the
     * AFTER_SWAP_FLAG is set in the hooksParameters
     * @param hooksParameters The encoded hooks parameters
     * @param sender The sender
     * @param to The recipient
     * @param swapForY Whether the swap is for Y
     * @param amountsOut The amounts out
     */
    function afterSwap(bytes32 hooksParameters, address sender, address to, bool swapForY, bytes32 amountsOut)
        internal
    {
        if ((hooksParameters & AFTER_SWAP_FLAG) != 0) {
            _safeCall(
                hooksParameters, abi.encodeWithSelector(ILBHooks.afterSwap.selector, sender, to, swapForY, amountsOut)
            );
        }
    }

    /**
     * @dev Helper function to call the beforeFlashLoan function on the hooks contract, only if the
     * BEFORE_FLASH_LOAN_FLAG is set in the hooksParameters
     * @param hooksParameters The encoded hooks parameters
     * @param sender The sender
     * @param to The recipient
     * @param amounts The amounts
     */
    function beforeFlashLoan(bytes32 hooksParameters, address sender, address to, bytes32 amounts) internal {
        if ((hooksParameters & BEFORE_FLASH_LOAN_FLAG) != 0) {
            _safeCall(hooksParameters, abi.encodeWithSelector(ILBHooks.beforeFlashLoan.selector, sender, to, amounts));
        }
    }

    /**
     * @dev Helper function to call the afterFlashLoan function on the hooks contract, only if the
     * AFTER_FLASH_LOAN_FLAG is set in the hooksParameters
     * @param hooksParameters The encoded hooks parameters
     * @param sender The sender
     * @param to The recipient
     * @param fees The fees
     * @param feesReceived The fees received
     */
    function afterFlashLoan(bytes32 hooksParameters, address sender, address to, bytes32 fees, bytes32 feesReceived)
        internal
    {
        if ((hooksParameters & AFTER_FLASH_LOAN_FLAG) != 0) {
            _safeCall(
                hooksParameters,
                abi.encodeWithSelector(ILBHooks.afterFlashLoan.selector, sender, to, fees, feesReceived)
            );
        }
    }

    /**
     * @dev Helper function to call the beforeMint function on the hooks contract, only if the
     * BEFORE_MINT_FLAG is set in the hooksParameters
     * @param hooksParameters The encoded hooks parameters
     * @param sender The sender
     * @param to The recipient
     * @param liquidityConfigs The liquidity configs
     * @param amountsReceived The amounts received
     */
    function beforeMint(
        bytes32 hooksParameters,
        address sender,
        address to,
        bytes32[] calldata liquidityConfigs,
        bytes32 amountsReceived
    ) internal {
        if ((hooksParameters & BEFORE_MINT_FLAG) != 0) {
            _safeCall(
                hooksParameters,
                abi.encodeWithSelector(ILBHooks.beforeMint.selector, sender, to, liquidityConfigs, amountsReceived)
            );
        }
    }

    /**
     * @dev Helper function to call the afterMint function on the hooks contract, only if the
     * AFTER_MINT_FLAG is set in the hooksParameters
     * @param hooksParameters The encoded hooks parameters
     * @param sender The sender
     * @param to The recipient
     * @param liquidityConfigs The liquidity configs
     * @param amountsIn The amounts in
     */
    function afterMint(
        bytes32 hooksParameters,
        address sender,
        address to,
        bytes32[] calldata liquidityConfigs,
        bytes32 amountsIn
    ) internal {
        if ((hooksParameters & AFTER_MINT_FLAG) != 0) {
            _safeCall(
                hooksParameters,
                abi.encodeWithSelector(ILBHooks.afterMint.selector, sender, to, liquidityConfigs, amountsIn)
            );
        }
    }

    /**
     * @dev Helper function to call the beforeBurn function on the hooks contract, only if the
     * BEFORE_BURN_FLAG is set in the hooksParameters
     * @param hooksParameters The encoded hooks parameters
     * @param sender The sender
     * @param from The sender
     * @param to The recipient
     * @param ids The ids
     * @param amountsToBurn The amounts to burn
     */
    function beforeBurn(
        bytes32 hooksParameters,
        address sender,
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amountsToBurn
    ) internal {
        if ((hooksParameters & BEFORE_BURN_FLAG) != 0) {
            _safeCall(
                hooksParameters,
                abi.encodeWithSelector(ILBHooks.beforeBurn.selector, sender, from, to, ids, amountsToBurn)
            );
        }
    }

    /**
     * @dev Helper function to call the afterBurn function on the hooks contract, only if the
     * AFTER_BURN_FLAG is set in the hooksParameters
     * @param hooksParameters The encoded hooks parameters
     * @param sender The sender
     * @param from The sender
     * @param to The recipient
     * @param ids The ids
     * @param amountsToBurn The amounts to burn
     */
    function afterBurn(
        bytes32 hooksParameters,
        address sender,
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amountsToBurn
    ) internal {
        if ((hooksParameters & AFTER_BURN_FLAG) != 0) {
            _safeCall(
                hooksParameters,
                abi.encodeWithSelector(ILBHooks.afterBurn.selector, sender, from, to, ids, amountsToBurn)
            );
        }
    }

    /**
     * @dev Helper function to call the beforeTransferFrom function on the hooks contract, only if the
     * BEFORE_TRANSFER_FLAG is set in the hooksParameters
     * @param hooksParameters The encoded hooks parameters
     * @param sender The sender
     * @param from The sender
     * @param to The recipient
     * @param ids The list of ids
     * @param amounts The list of amounts
     */
    function beforeBatchTransferFrom(
        bytes32 hooksParameters,
        address sender,
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts
    ) internal {
        if ((hooksParameters & BEFORE_TRANSFER_FLAG) != 0) {
            _safeCall(
                hooksParameters,
                abi.encodeWithSelector(ILBHooks.beforeBatchTransferFrom.selector, sender, from, to, ids, amounts)
            );
        }
    }

    /**
     * @dev Helper function to call the afterTransferFrom function on the hooks contract, only if the
     * AFTER_TRANSFER_FLAG is set in the hooksParameters
     * @param hooksParameters The encoded hooks parameters
     * @param sender The sender
     * @param from The sender
     * @param to The recipient
     * @param ids The list of ids
     * @param amounts The list of amounts
     */
    function afterBatchTransferFrom(
        bytes32 hooksParameters,
        address sender,
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts
    ) internal {
        if ((hooksParameters & AFTER_TRANSFER_FLAG) != 0) {
            _safeCall(
                hooksParameters,
                abi.encodeWithSelector(ILBHooks.afterBatchTransferFrom.selector, sender, from, to, ids, amounts)
            );
        }
    }

    /**
     * @dev Helper function to call the hooks contract and verify the call was successful
     * by matching the expected selector with the returned data
     * @param hooksParameters The encoded hooks parameters
     * @param data The data to pass to the hooks contract
     */
    function _safeCall(bytes32 hooksParameters, bytes memory data) private {
        bool success;

        address hooks = getHooks(hooksParameters);

        assembly {
            let expectedSelector := shr(224, mload(add(data, 0x20)))

            success := call(gas(), hooks, 0, add(data, 0x20), mload(data), 0, 0x20)

            if and(iszero(success), iszero(iszero(returndatasize()))) {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
            }

            success := and(success, and(gt(returndatasize(), 0x1f), eq(shr(224, mload(0)), expectedSelector)))
        }

        if (!success) revert Hooks__CallFailed();
    }
}

File 16 of 27 : ILBFactory.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

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

import {ILBHooks} from "./ILBHooks.sol";
import {ILBPair} from "./ILBPair.sol";

/**
 * @title Liquidity Book Factory Interface
 * @author Trader Joe
 * @notice Required interface of LBFactory contract
 */
interface ILBFactory {
    error LBFactory__IdenticalAddresses(IERC20 token);
    error LBFactory__QuoteAssetNotWhitelisted(IERC20 quoteAsset);
    error LBFactory__QuoteAssetAlreadyWhitelisted(IERC20 quoteAsset);
    error LBFactory__AddressZero();
    error LBFactory__LBPairAlreadyExists(IERC20 tokenX, IERC20 tokenY, uint256 _binStep);
    error LBFactory__LBPairDoesNotExist(IERC20 tokenX, IERC20 tokenY, uint256 binStep);
    error LBFactory__LBPairNotCreated(IERC20 tokenX, IERC20 tokenY, uint256 binStep);
    error LBFactory__FlashLoanFeeAboveMax(uint256 fees, uint256 maxFees);
    error LBFactory__BinStepTooLow(uint256 binStep);
    error LBFactory__PresetIsLockedForUsers(address user, uint256 binStep);
    error LBFactory__LBPairIgnoredIsAlreadyInTheSameState();
    error LBFactory__BinStepHasNoPreset(uint256 binStep);
    error LBFactory__PresetOpenStateIsAlreadyInTheSameState();
    error LBFactory__SameFeeRecipient(address feeRecipient);
    error LBFactory__SameFlashLoanFee(uint256 flashLoanFee);
    error LBFactory__LBPairSafetyCheckFailed(address LBPairImplementation);
    error LBFactory__SameImplementation(address LBPairImplementation);
    error LBFactory__ImplementationNotSet();
    error LBFactory__SameHooksImplementation(address hooksImplementation);
    error LBFactory__SameHooksParameters(bytes32 hooksParameters);
    error LBFactory__InvalidHooksParameters();
    error LBFactory__CannotGrantDefaultAdminRole();

    /**
     * @dev Structure to store the LBPair information, such as:
     * binStep: The bin step of the LBPair
     * LBPair: The address of the LBPair
     * createdByOwner: Whether the pair was created by the owner of the factory
     * ignoredForRouting: Whether the pair is ignored for routing or not. An ignored pair will not be explored during routes finding
     */
    struct LBPairInformation {
        uint16 binStep;
        ILBPair LBPair;
        bool createdByOwner;
        bool ignoredForRouting;
    }

    event LBPairCreated(
        IERC20 indexed tokenX, IERC20 indexed tokenY, uint256 indexed binStep, ILBPair LBPair, uint256 pid
    );

    event FeeRecipientSet(address oldRecipient, address newRecipient);

    event FlashLoanFeeSet(uint256 oldFlashLoanFee, uint256 newFlashLoanFee);

    event LBPairImplementationSet(address oldLBPairImplementation, address LBPairImplementation);

    event LBPairIgnoredStateChanged(ILBPair indexed LBPair, bool ignored);

    event PresetSet(
        uint256 indexed binStep,
        uint256 baseFactor,
        uint256 filterPeriod,
        uint256 decayPeriod,
        uint256 reductionFactor,
        uint256 variableFeeControl,
        uint256 protocolShare,
        uint256 maxVolatilityAccumulator
    );

    event PresetOpenStateChanged(uint256 indexed binStep, bool indexed isOpen);

    event PresetRemoved(uint256 indexed binStep);

    event QuoteAssetAdded(IERC20 indexed quoteAsset);

    event QuoteAssetRemoved(IERC20 indexed quoteAsset);

    function getMinBinStep() external pure returns (uint256);

    function getFeeRecipient() external view returns (address);

    function getMaxFlashLoanFee() external pure returns (uint256);

    function getFlashLoanFee() external view returns (uint256);

    function getLBPairImplementation() external view returns (address);

    function getNumberOfLBPairs() external view returns (uint256);

    function getLBPairAtIndex(uint256 id) external returns (ILBPair);

    function getNumberOfQuoteAssets() external view returns (uint256);

    function getQuoteAssetAtIndex(uint256 index) external view returns (IERC20);

    function isQuoteAsset(IERC20 token) external view returns (bool);

    function getLBPairInformation(IERC20 tokenX, IERC20 tokenY, uint256 binStep)
        external
        view
        returns (LBPairInformation memory);

    function getPreset(uint256 binStep)
        external
        view
        returns (
            uint256 baseFactor,
            uint256 filterPeriod,
            uint256 decayPeriod,
            uint256 reductionFactor,
            uint256 variableFeeControl,
            uint256 protocolShare,
            uint256 maxAccumulator,
            bool isOpen
        );

    function getAllBinSteps() external view returns (uint256[] memory presetsBinStep);

    function getOpenBinSteps() external view returns (uint256[] memory openBinStep);

    function getAllLBPairs(IERC20 tokenX, IERC20 tokenY)
        external
        view
        returns (LBPairInformation[] memory LBPairsBinStep);

    function setLBPairImplementation(address lbPairImplementation) external;

    function createLBPair(IERC20 tokenX, IERC20 tokenY, uint24 activeId, uint16 binStep)
        external
        returns (ILBPair pair);

    function setLBPairIgnored(IERC20 tokenX, IERC20 tokenY, uint16 binStep, bool ignored) external;

    function setPreset(
        uint16 binStep,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator,
        bool isOpen
    ) external;

    function setPresetOpenState(uint16 binStep, bool isOpen) external;

    function removePreset(uint16 binStep) external;

    function setFeesParametersOnPair(
        IERC20 tokenX,
        IERC20 tokenY,
        uint16 binStep,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator
    ) external;

    function setLBHooksParametersOnPair(
        IERC20 tokenX,
        IERC20 tokenY,
        uint16 binStep,
        bytes32 hooksParameters,
        bytes memory onHooksSetData
    ) external;

    function removeLBHooksOnPair(IERC20 tokenX, IERC20 tokenY, uint16 binStep) external;

    function setFeeRecipient(address feeRecipient) external;

    function setFlashLoanFee(uint256 flashLoanFee) external;

    function addQuoteAsset(IERC20 quoteAsset) external;

    function removeQuoteAsset(IERC20 quoteAsset) external;

    function forceDecay(ILBPair lbPair) external;
}

File 17 of 27 : ILBFlashLoanCallback.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

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

/// @title Liquidity Book Flashloan Callback Interface
/// @author Trader Joe
/// @notice Required interface to interact with LB flash loans
interface ILBFlashLoanCallback {
    function LBFlashLoanCallback(
        address sender,
        IERC20 tokenX,
        IERC20 tokenY,
        bytes32 amounts,
        bytes32 totalFees,
        bytes calldata data
    ) external returns (bytes32);
}

File 18 of 27 : ILBToken.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

/**
 * @title Liquidity Book Token Interface
 * @author Trader Joe
 * @notice Interface to interact with the LBToken.
 */
interface ILBToken {
    error LBToken__AddressThisOrZero();
    error LBToken__InvalidLength();
    error LBToken__SelfApproval(address owner);
    error LBToken__SpenderNotApproved(address from, address spender);
    error LBToken__TransferExceedsBalance(address from, uint256 id, uint256 amount);
    error LBToken__BurnExceedsBalance(address from, uint256 id, uint256 amount);

    event TransferBatch(
        address indexed sender, address indexed from, address indexed to, uint256[] ids, uint256[] amounts
    );

    event ApprovalForAll(address indexed account, address indexed sender, bool approved);

    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function totalSupply(uint256 id) external view returns (uint256);

    function balanceOf(address account, uint256 id) external view returns (uint256);

    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    function isApprovedForAll(address owner, address spender) external view returns (bool);

    function approveForAll(address spender, bool approved) external;

    function batchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts) external;
}

File 19 of 27 : IRewarder.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

interface IRewarder {
    function getToken() external view returns (IERC20);

    function getCaller() external view returns (address);

    function initialize(address initialOwner) external;
}

File 20 of 27 : IMetro.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

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

interface IMetro is IERC20 {
    function mint(address account, uint256 amount) external returns (uint256);
}

File 21 of 27 : Rewarder.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Amounts} from "./Amounts.sol";
import {Constants} from "./Constants.sol";

/**
 * @title Rewarder Library
 * @dev A library that defines various functions for calculating rewards.
 * It takes care about the reward debt and the accumulated debt per share.
 */
library Rewarder {
    using Amounts for Amounts.Parameter;

    struct Parameter {
        uint256 lastUpdateTimestamp;
        uint256 accDebtPerShare;
        mapping(address => uint256) debt;
    }

    /**
     * @dev Returns the debt associated with an amount.
     * @param accDebtPerShare The accumulated debt per share.
     * @param deposit The amount.
     * @return The debt associated with the amount.
     */
    function getDebt(uint256 accDebtPerShare, uint256 deposit) internal pure returns (uint256) {
        return (deposit * accDebtPerShare) >> Constants.ACC_PRECISION_BITS;
    }

    /**
     * @dev Returns the debt per share associated with a total deposit and total rewards.
     * @param totalDeposit The total deposit.
     * @param totalRewards The total rewards.
     * @return The debt per share associated with the total deposit and total rewards.
     */
    function getDebtPerShare(uint256 totalDeposit, uint256 totalRewards) internal pure returns (uint256) {
        return totalDeposit == 0 ? 0 : (totalRewards << Constants.ACC_PRECISION_BITS) / totalDeposit;
    }

    /**
     * @dev Returns the total rewards to emit.
     * If the end timestamp is in the past, the rewards are calculated up to the end timestamp.
     * If the last update timestamp is in the future, it will return 0.
     * @param rewarder The storage pointer to the rewarder.
     * @param rewardPerSecond The reward per second.
     * @param endTimestamp The end timestamp.
     * @param totalSupply The total supply.
     * @return The total rewards.
     */
    function getTotalRewards(
        Parameter storage rewarder,
        uint256 rewardPerSecond,
        uint256 endTimestamp,
        uint256 totalSupply
    ) internal view returns (uint256) {
        if (totalSupply == 0) return 0;

        uint256 lastUpdateTimestamp = rewarder.lastUpdateTimestamp;
        uint256 timestamp = block.timestamp > endTimestamp ? endTimestamp : block.timestamp;

        return timestamp > lastUpdateTimestamp ? (timestamp - lastUpdateTimestamp) * rewardPerSecond : 0;
    }

    /**
     * @dev Returns the total rewards to emit.
     * @param rewarder The storage pointer to the rewarder.
     * @param rewardPerSecond The reward per second.
     * @param totalSupply The total supply.
     * @return The total rewards.
     */
    function getTotalRewards(Parameter storage rewarder, uint256 rewardPerSecond, uint256 totalSupply)
        internal
        view
        returns (uint256)
    {
        return getTotalRewards(rewarder, rewardPerSecond, block.timestamp, totalSupply);
    }

    /**
     * @dev Returns the pending reward of an account.
     * @param rewarder The storage pointer to the rewarder.
     * @param amounts The storage pointer to the amounts.
     * @param account The address of the account.
     * @param totalRewards The total rewards.
     * @return The pending reward of the account.
     */
    function getPendingReward(
        Parameter storage rewarder,
        Amounts.Parameter storage amounts,
        address account,
        uint256 totalRewards
    ) internal view returns (uint256) {
        return getPendingReward(rewarder, account, amounts.getAmountOf(account), amounts.getTotalAmount(), totalRewards);
    }

    /**
     * @dev Returns the pending reward of an account.
     * If the balance of the account is 0, it will always return 0.
     * @param rewarder The storage pointer to the rewarder.
     * @param account The address of the account.
     * @param balance The balance of the account.
     * @param totalSupply The total supply.
     * @param totalRewards The total rewards.
     * @return The pending reward of the account.
     */
    function getPendingReward(
        Parameter storage rewarder,
        address account,
        uint256 balance,
        uint256 totalSupply,
        uint256 totalRewards
    ) internal view returns (uint256) {
        uint256 accDebtPerShare = rewarder.accDebtPerShare + getDebtPerShare(totalSupply, totalRewards);

        return balance == 0 ? 0 : getDebt(accDebtPerShare, balance) - rewarder.debt[account];
    }

    /**
     * @dev Updates the rewarder.
     * If the balance of the account is 0, it will always return 0.
     * @param rewarder The storage pointer to the rewarder.
     * @param account The address of the account.
     * @param oldBalance The old balance of the account.
     * @param newBalance The new balance of the account.
     * @param totalSupply The total supply.
     * @param totalRewards The total rewards.
     * @return rewards The rewards of the account.
     */
    function update(
        Parameter storage rewarder,
        address account,
        uint256 oldBalance,
        uint256 newBalance,
        uint256 totalSupply,
        uint256 totalRewards
    ) internal returns (uint256 rewards) {
        uint256 accDebtPerShare = updateAccDebtPerShare(rewarder, totalSupply, totalRewards);

        rewards = oldBalance == 0 ? 0 : getDebt(accDebtPerShare, oldBalance) - rewarder.debt[account];

        rewarder.debt[account] = getDebt(accDebtPerShare, newBalance);
    }

    /**
     * @dev Updates the accumulated debt per share.
     * If the last update timestamp is in the future, it will not update the last update timestamp.
     * @param rewarder The storage pointer to the rewarder.
     * @param totalSupply The total supply.
     * @param totalRewards The total rewards.
     * @return The accumulated debt per share.
     */
    function updateAccDebtPerShare(Parameter storage rewarder, uint256 totalSupply, uint256 totalRewards)
        internal
        returns (uint256)
    {
        uint256 debtPerShare = getDebtPerShare(totalSupply, totalRewards);

        if (block.timestamp > rewarder.lastUpdateTimestamp) rewarder.lastUpdateTimestamp = block.timestamp;

        return debtPerShare == 0 ? rewarder.accDebtPerShare : rewarder.accDebtPerShare += debtPerShare;
    }
}

File 22 of 27 : Amounts.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Math} from "./Math.sol";

/**
 * @title Amounts Library
 * @dev A library that defines various functions for manipulating amounts of a key and a total.
 * The key can be bytes32, address, or uint256.
 */
library Amounts {
    using Math for uint256;

    struct Parameter {
        uint256 totalAmount;
        mapping(bytes32 => uint256) amounts;
    }

    /**
     * @dev Returns the amount of a key.
     * @param amounts The storage pointer to the amounts.
     * @param key The key of the amount.
     * @return The amount of the key.
     */
    function getAmountOf(Parameter storage amounts, bytes32 key) internal view returns (uint256) {
        return amounts.amounts[key];
    }

    /**
     * @dev Returns the amount of an address.
     * @param amounts The storage pointer to the amounts.
     * @param account The address of the amount.
     * @return The amount of the address.
     */
    function getAmountOf(Parameter storage amounts, address account) internal view returns (uint256) {
        return getAmountOf(amounts, bytes32(uint256(uint160(account))));
    }

    /**
     * @dev Returns the amount of an id.
     * @param amounts The storage pointer to the amounts.
     * @param id The id of the amount.
     * @return The amount of the id.
     */
    function getAmountOf(Parameter storage amounts, uint256 id) internal view returns (uint256) {
        return getAmountOf(amounts, bytes32(id));
    }

    /**
     * @dev Returns the total amount.
     * @param amounts The storage pointer to the amounts.
     * @return The total amount.
     */
    function getTotalAmount(Parameter storage amounts) internal view returns (uint256) {
        return amounts.totalAmount;
    }

    /**
     * @dev Updates the amount of a key. The delta is added to the key amount and the total amount.
     * @param amounts The storage pointer to the amounts.
     * @param key The key of the amount.
     * @param deltaAmount The delta amount to update.
     * @return oldAmount The old amount of the key.
     * @return newAmount The new amount of the key.
     * @return oldTotalAmount The old total amount.
     * @return newTotalAmount The new total amount.
     */
    function update(Parameter storage amounts, bytes32 key, int256 deltaAmount)
        internal
        returns (uint256 oldAmount, uint256 newAmount, uint256 oldTotalAmount, uint256 newTotalAmount)
    {
        oldAmount = amounts.amounts[key];
        oldTotalAmount = amounts.totalAmount;

        if (deltaAmount == 0) {
            newAmount = oldAmount;
            newTotalAmount = oldTotalAmount;
        } else {
            newAmount = oldAmount.addDelta(deltaAmount);
            newTotalAmount = oldTotalAmount.addDelta(deltaAmount);

            amounts.amounts[key] = newAmount;
            amounts.totalAmount = newTotalAmount;
        }
    }

    /**
     * @dev Updates the amount of an address. The delta is added to the address amount and the total amount.
     * @param amounts The storage pointer to the amounts.
     * @param account The address of the amount.
     * @param deltaAmount The delta amount to update.
     * @return oldAmount The old amount of the key.
     * @return newAmount The new amount of the key.
     * @return oldTotalAmount The old total amount.
     * @return newTotalAmount The new total amount.
     */
    function update(Parameter storage amounts, address account, int256 deltaAmount)
        internal
        returns (uint256 oldAmount, uint256 newAmount, uint256 oldTotalAmount, uint256 newTotalAmount)
    {
        return update(amounts, bytes32(uint256(uint160(account))), deltaAmount);
    }

    /**
     * @dev Updates the amount of an id. The delta is added to the id amount and the total amount.
     * @param amounts The storage pointer to the amounts.
     * @param id The id of the amount.
     * @param deltaAmount The delta amount to update.
     * @return oldAmount The old amount of the key.
     * @return newAmount The new amount of the key.
     * @return oldTotalAmount The old total amount.
     * @return newTotalAmount The new total amount.
     */
    function update(Parameter storage amounts, uint256 id, int256 deltaAmount)
        internal
        returns (uint256 oldAmount, uint256 newAmount, uint256 oldTotalAmount, uint256 newTotalAmount)
    {
        return update(amounts, bytes32(id), deltaAmount);
    }
}

File 23 of 27 : IRewarderFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

import {IRewarder} from "../interfaces/IRewarder.sol";
import {IBribeRewarder} from "../interfaces/IBribeRewarder.sol";
import {IBaseRewarder} from "../interfaces/IBaseRewarder.sol";

interface IRewarderFactory {
    error RewarderFactory__ZeroAddress();
    error RewarderFactory__InvalidRewarderType();
    error RewarderFactory__InvalidPid();
    error RewarderFactory__TokenNotWhitelisted();
    error RewarderFactory__InvalidLength();

    enum RewarderType {
        InvalidRewarder,
        MasterChefRewarder,
        BribeRewarder
    }

    event RewarderCreated(
        RewarderType indexed rewarderType, IERC20 indexed token, uint256 indexed pid, IBaseRewarder rewarder
    );

    event BribeRewarderCreated(
        RewarderType indexed rewarderType, IERC20 indexed token, address indexed pool, IBribeRewarder rewarder
    );

    event RewarderImplementationSet(RewarderType indexed rewarderType, IRewarder indexed implementation);

    function getBribeCreatorFee() external view returns (uint256);

    function getWhitelistedTokenInfo (address token) external view returns (bool, uint256);

    function getRewarderImplementation(RewarderType rewarderType) external view returns (IRewarder);

    function getRewarderCount(RewarderType rewarderType) external view returns (uint256);

    function getRewarderAt(RewarderType rewarderType, uint256 index) external view returns (IRewarder);

    function getRewarderType(IRewarder rewarder) external view returns (RewarderType);

    function setRewarderImplementation(RewarderType rewarderType, IRewarder implementation) external;

    function createRewarder(RewarderType rewarderType, IERC20 token, uint256 pid) external returns (IBaseRewarder);

    function createBribeRewarder(IERC20 token, address pool) external returns (IBribeRewarder);

    function setWhitelist(address[] calldata tokens, uint256[] calldata minBribeAmounts) external;
}

File 24 of 27 : IBaseRewarder.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

import {IRewarder} from "./IRewarder.sol";

interface IBaseRewarder is IRewarder {
    error BaseRewarder__NativeTransferFailed();
    error BaseRewarder__InvalidCaller();
    error BaseRewarder__Stopped();
    error BaseRewarder__AlreadyStopped();
    error BaseRewarder__NotNativeRewarder();
    error BaseRewarder__ZeroAmount();
    error BaseRewarder__ZeroReward();
    error BaseRewarder__InvalidDuration();
    error BaseRewarder__InvalidPid(uint256 pid);
    error BaseRewarder__InvalidStartTimestamp(uint256 startTimestamp);
    error BaseRewarder__CannotRenounceOwnership();

    event Claim(address indexed account, IERC20 indexed token, uint256 reward);

    event RewardParameterUpdated(uint256 rewardPerSecond, uint256 startTimestamp, uint256 endTimestamp);

    event Stopped();

    event Swept(IERC20 indexed token, address indexed account, uint256 amount);

    function getToken() external view returns (IERC20);

    function getCaller() external view returns (address);

    function getPid() external view returns (uint256);

    function getRewarderParameter()
        external
        view
        returns (IERC20 token, uint256 rewardPerSecond, uint256 lastUpdateTimestamp, uint256 endTimestamp);

    function getRemainingReward() external view returns (uint256);

    function getPendingReward(address account, uint256 balance, uint256 totalSupply)
        external
        view
        returns (IERC20 token, uint256 pendingReward);

    function isStopped() external view returns (bool);

    function initialize(address initialOwner) external;

    function setRewardPerSecond(uint256 maxRewardPerSecond, uint256 expectedDuration)
        external
        returns (uint256 rewardPerSecond);

    function setRewarderParameters(uint256 maxRewardPerSecond, uint256 startTimestamp, uint256 expectedDuration)
        external
        returns (uint256 rewardPerSecond);

    function stop() external;

    function sweep(IERC20 token, address account) external;

    function onModify(address account, uint256 pid, uint256 oldBalance, uint256 newBalance, uint256 totalSupply)
        external
        returns (uint256);
}

File 25 of 27 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * 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[EIP 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);
}

File 26 of 27 : Constants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title Constants Library
 * @dev A library that defines various constants used throughout the codebase.
 */
library Constants {
    uint256 internal constant ACC_PRECISION_BITS = 64;
    uint256 internal constant PRECISION = 1e18;

    uint256 internal constant MAX_NUMBER_OF_FARMS = 32;
    uint256 internal constant MAX_NUMBER_OF_REWARDS = 32;

    uint256 internal constant MAX_METRO_PER_SECOND = 10e18;

    uint256 internal constant MAX_BRIBES_PER_POOL = 5;
}

File 27 of 27 : Math.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title Math
 * @dev Library for mathematical operations with overflow and underflow checks.
 */
library Math {
    error Math__UnderOverflow();

    uint256 internal constant MAX_INT256 = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

    /**
     * @dev Adds a signed integer to an unsigned integer with overflow check.
     * The result must be greater than or equal to 0 and less than or equal to MAX_INT256.
     * @param x Unsigned integer to add to.
     * @param delta Signed integer to add.
     * @return y The result of the addition.
     */
    function addDelta(uint256 x, int256 delta) internal pure returns (uint256 y) {
        uint256 success;

        assembly {
            y := add(x, delta)

            success := iszero(or(gt(x, MAX_INT256), gt(y, MAX_INT256)))
        }

        if (success == 0) revert Math__UnderOverflow();
    }

    /**
     * @dev Safely converts an unsigned integer to a signed integer.
     * @param x Unsigned integer to convert.
     * @return y Signed integer result.
     */
    function toInt256(uint256 x) internal pure returns (int256 y) {
        if (x > MAX_INT256) revert Math__UnderOverflow();

        return int256(x);
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "solmate/=lib/solmate/",
    "joe-v2/=lib/joe-v2/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 800
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": false,
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"contract IMasterChef","name":"masterChef","type":"address"},{"internalType":"contract IVoter","name":"voter","type":"address"},{"internalType":"contract IMlumStaking","name":"mlumStaking","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"contract IBribeRewarder","name":"rewarder","type":"address"}],"name":"getBribe","outputs":[{"components":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint256","name":"startPeriodId","type":"uint256"},{"internalType":"uint256","name":"lastPeriodId","type":"uint256"},{"internalType":"uint256","name":"amountPerPeriod","type":"uint256"},{"internalType":"address","name":"rewarder","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"rewardToken","type":"tuple"}],"internalType":"struct FarmLens.Bribe","name":"bribe","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"period","type":"uint256"},{"internalType":"address","name":"pool","type":"address"}],"name":"getBribesForPool","outputs":[{"components":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint256","name":"startPeriodId","type":"uint256"},{"internalType":"uint256","name":"lastPeriodId","type":"uint256"},{"internalType":"uint256","name":"amountPerPeriod","type":"uint256"},{"internalType":"address","name":"rewarder","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"rewardToken","type":"tuple"}],"internalType":"struct FarmLens.Bribe[]","name":"bribes","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"nb","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"getFarmData","outputs":[{"components":[{"internalType":"address","name":"masterChef","type":"address"},{"internalType":"uint256","name":"totalVotes","type":"uint256"},{"internalType":"uint256","name":"totalAllocPoint","type":"uint256"},{"internalType":"uint256","name":"totalLumPerSec","type":"uint256"},{"internalType":"uint256","name":"totalNumberOfFarms","type":"uint256"},{"components":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"totalStaked","type":"uint256"},{"internalType":"uint256","name":"allocPoint","type":"uint256"},{"internalType":"uint256","name":"lastRewardTime","type":"uint256"},{"internalType":"uint256","name":"lumPerSecond","type":"uint256"},{"components":[{"internalType":"address","name":"rewarderAddress","type":"address"},{"internalType":"bool","name":"isStarted","type":"bool"},{"internalType":"bool","name":"isEnded","type":"bool"},{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"totalDeposited","type":"uint256"},{"internalType":"uint256","name":"remainingReward","type":"uint256"},{"internalType":"uint256","name":"rewardPerSec","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"endUpdateTimestamp","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"rewardToken","type":"tuple"},{"internalType":"uint256","name":"userPendingAmount","type":"uint256"}],"internalType":"struct FarmLens.Rewarder","name":"rewarder","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"lpToken","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"token0","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"token1","type":"tuple"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"reserve0","type":"uint256"},{"internalType":"uint256","name":"reserve1","type":"uint256"},{"internalType":"uint256","name":"binStep","type":"uint256"},{"internalType":"address","name":"lbHook","type":"address"},{"internalType":"address","name":"lbPair","type":"address"}],"internalType":"struct FarmLens.Pool","name":"poolInfo","type":"tuple"},{"internalType":"uint256","name":"userAmount","type":"uint256"},{"internalType":"uint256","name":"userPendingLumReward","type":"uint256"}],"internalType":"struct FarmLens.Farm[]","name":"farms","type":"tuple[]"}],"internalType":"struct FarmLens.FarmData","name":"data","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"getFarmInfo","outputs":[{"components":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"totalStaked","type":"uint256"},{"internalType":"uint256","name":"allocPoint","type":"uint256"},{"internalType":"uint256","name":"lastRewardTime","type":"uint256"},{"internalType":"uint256","name":"lumPerSecond","type":"uint256"},{"components":[{"internalType":"address","name":"rewarderAddress","type":"address"},{"internalType":"bool","name":"isStarted","type":"bool"},{"internalType":"bool","name":"isEnded","type":"bool"},{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"totalDeposited","type":"uint256"},{"internalType":"uint256","name":"remainingReward","type":"uint256"},{"internalType":"uint256","name":"rewardPerSec","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"endUpdateTimestamp","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"rewardToken","type":"tuple"},{"internalType":"uint256","name":"userPendingAmount","type":"uint256"}],"internalType":"struct FarmLens.Rewarder","name":"rewarder","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"lpToken","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"token0","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"token1","type":"tuple"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"reserve0","type":"uint256"},{"internalType":"uint256","name":"reserve1","type":"uint256"},{"internalType":"uint256","name":"binStep","type":"uint256"},{"internalType":"address","name":"lbHook","type":"address"},{"internalType":"address","name":"lbPair","type":"address"}],"internalType":"struct FarmLens.Pool","name":"poolInfo","type":"tuple"},{"internalType":"uint256","name":"userAmount","type":"uint256"},{"internalType":"uint256","name":"userPendingLumReward","type":"uint256"}],"internalType":"struct FarmLens.Farm","name":"farm","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"pid","type":"uint256"}],"name":"getMasterChefPendingRewardsAt","outputs":[{"internalType":"uint256","name":"moeReward","type":"uint256"},{"internalType":"address","name":"extraToken","type":"address"},{"internalType":"uint256","name":"extraReward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"lpAddress","type":"address"}],"name":"getPoolInfo","outputs":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"lpToken","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"token0","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"token1","type":"tuple"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"reserve0","type":"uint256"},{"internalType":"uint256","name":"reserve1","type":"uint256"},{"internalType":"uint256","name":"binStep","type":"uint256"},{"internalType":"address","name":"lbHook","type":"address"},{"internalType":"address","name":"lbPair","type":"address"}],"internalType":"struct FarmLens.Pool","name":"poolInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"getRewardToken","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"rewardToken","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"period","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getUserBribeRewardFor","outputs":[{"components":[{"components":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint256","name":"startPeriodId","type":"uint256"},{"internalType":"uint256","name":"lastPeriodId","type":"uint256"},{"internalType":"uint256","name":"amountPerPeriod","type":"uint256"},{"internalType":"address","name":"rewarder","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"rewardToken","type":"tuple"}],"internalType":"struct FarmLens.Bribe","name":"bribe","type":"tuple"},{"internalType":"uint256","name":"periodId","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"pendingReward","type":"uint256"}],"internalType":"struct FarmLens.BribeReward","name":"userReward","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getUserBribeRewards","outputs":[{"components":[{"internalType":"address","name":"account","type":"address"},{"components":[{"components":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint256","name":"startPeriodId","type":"uint256"},{"internalType":"uint256","name":"lastPeriodId","type":"uint256"},{"internalType":"uint256","name":"amountPerPeriod","type":"uint256"},{"internalType":"address","name":"rewarder","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"rewardToken","type":"tuple"}],"internalType":"struct FarmLens.Bribe","name":"bribe","type":"tuple"},{"internalType":"uint256","name":"periodId","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"pendingReward","type":"uint256"}],"internalType":"struct FarmLens.BribeReward[]","name":"userBribeRewards","type":"tuple[]"}],"internalType":"struct FarmLens.UserBribeData","name":"userData","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"nb","type":"uint256"}],"name":"getVoteData","outputs":[{"components":[{"internalType":"address","name":"voterAddress","type":"address"},{"internalType":"uint256","name":"totalVotes","type":"uint256"},{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"votes","type":"uint256"},{"components":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint256","name":"startPeriodId","type":"uint256"},{"internalType":"uint256","name":"lastPeriodId","type":"uint256"},{"internalType":"uint256","name":"amountPerPeriod","type":"uint256"},{"internalType":"address","name":"rewarder","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"rewardToken","type":"tuple"}],"internalType":"struct FarmLens.Bribe[]","name":"bribes","type":"tuple[]"}],"internalType":"struct FarmLens.VoteInfo[]","name":"votes","type":"tuple[]"}],"internalType":"struct FarmLens.VoteData","name":"voteData","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getVoteInfoAt","outputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"votes","type":"uint256"},{"components":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint256","name":"startPeriodId","type":"uint256"},{"internalType":"uint256","name":"lastPeriodId","type":"uint256"},{"internalType":"uint256","name":"amountPerPeriod","type":"uint256"},{"internalType":"address","name":"rewarder","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct FarmLens.Token","name":"rewardToken","type":"tuple"}],"internalType":"struct FarmLens.Bribe[]","name":"bribes","type":"tuple[]"}],"internalType":"struct FarmLens.VoteInfo","name":"voteInfo","type":"tuple"}],"stateMutability":"view","type":"function"}]

60e06040523480156200001157600080fd5b5060405162003cad38038062003cad83398101604081905262000034916200006b565b6001600160a01b0392831660805290821660a0521660c052620000bf565b6001600160a01b03811681146200006857600080fd5b50565b6000806000606084860312156200008157600080fd5b83516200008e8162000052565b6020850151909350620000a18162000052565b6040850151909250620000b48162000052565b809150509250925092565b60805160a05160c051613b3c620001716000396000505060008181610cf401528181610d750152818161126701528181611328015281816113570152818161153701528181611812015281816118ae01528181611a6001528181611b5d01528181611db001526123460152600081816116e301528181611c8901528181611d2801528181611e3d01528181611f3d01528181611feb0152818161224f0152818161231001526123cd0152613b3c6000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c8063956a3efa11610081578063ad508ec81161005b578063ad508ec8146101ed578063bd0460bb1461020d578063f4804a6d1461022d57600080fd5b8063956a3efa14610177578063a017140a14610197578063ac377cac146101cd57600080fd5b80634f733064116100b25780634f73306414610117578063770788721461013757806377a92aee1461015757600080fd5b806306bfa938146100ce57806328e5971a146100f7575b600080fd5b6100e16100dc366004612863565b61024d565b6040516100ee91906129ab565b60405180910390f35b61010a6101053660046129be565b610cb5565b6040516100ee9190612ab6565b61012a610125366004612863565b610e95565b6040516100ee9190612ac9565b61014a610145366004612863565b611141565b6040516100ee9190612adc565b61016a610165366004612aef565b611247565b6040516100ee9190612b11565b61018a610185366004612b99565b6114ff565b6040516100ee9190612c10565b6101aa6101a5366004612c23565b611693565b604080519384526001600160a01b039092166020840152908201526060016100ee565b6101e06101db366004612863565b6117dc565b6040516100ee9190612c4f565b6102006101fb366004612cc0565b611a34565b6040516100ee9190612cf0565b61022061021b366004612cc0565b611c68565b6040516100ee9190612e8c565b61024061023b366004612e9f565b612209565b6040516100ee9190612ed8565b6102556125e2565b816001600160a01b0316635f9c01b16040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156102af575060408051601f3d908101601f191682019092526102ac91810190612f74565b60015b610775576000829050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156102f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061031d9190612faf565b506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff1691506000836001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610382573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a69190612f74565b90506000846001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061040c9190612f74565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561044e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104729190612fff565b60ff1690506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104db9190612fff565b60ff16905060405180606001604052808a6001600160a01b031681526020018a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610538573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055c9190612fff565b60ff1681526020018a6001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156105a2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105ca9190810190613162565b8152508860000181905250866001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610613573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106379190613197565b8860600181815250506040518060600160405280856001600160a01b03168152602001838152602001856001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561069e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106c69190810190613162565b81525088602001819052506040518060600160405280846001600160a01b03168152602001828152602001846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561072f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107579190810190613162565b9052604089015250505050608084019190915260a083015250919050565b6000816001600160a01b03166317f11ecc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d991906131b0565b9050600080836001600160a01b0316630902f1ac6040518163ffffffff1660e01b81526004016040805180830381865afa15801561081b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083f91906131f4565b6fffffffffffffffffffffffffffffffff1691506fffffffffffffffffffffffffffffffff1691506000846001600160a01b03166305e8746d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108cb9190612f74565b90506000856001600160a01b031663da10610c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561090d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109319190612f74565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610973573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109979190612fff565b60ff1690506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a009190612fff565b6001600160a01b03808c1660e08c01819052908a166101008c015261ffff891660c08c015260408051606081018252828152815163313ce56760e01b8152915160ff949094169450926020848101939263313ce56792600480830193928290030181865afa158015610a76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9a9190612fff565b60ff1681526020018b6001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610ae0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b089190810190613162565b8152508960000181905250896001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b759190613197565b8960600181815250506040518060600160405280856001600160a01b03168152602001838152602001856001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610bdc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c049190810190613162565b81525089602001819052506040518060600160405280846001600160a01b03168152602001828152602001846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610c6d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c959190810190613162565b905260408a015250505050608085019190915260a084015250505b919050565b60408051606080820183526000808352602083015291810191909152604051637aa9ba3960e01b81526004810183905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637aa9ba39906024016040805180830381865afa158015610d3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5e9190613227565b915091506000306001600160a01b031663ad508ec87f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ae40bc796040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df59190613197565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b0386166024820152604401600060405180830381865afa158015610e40573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e68919081019061341d565b604080516060810182526001600160a01b0390951685526020850193909352918301919091525092915050565b610e9d6126b1565b6040518060c00160405280836001600160a01b031663026b1d5f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0a9190612f74565b6001600160a01b03168152602001836001600160a01b031663225b08bb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f7a9190613197565b8152602001836001600160a01b031663953582a06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe19190613197565b8152602001836001600160a01b031663d50ff4976040518163ffffffff1660e01b8152600401602060405180830381865afa158015611024573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110489190613197565b8152602001836001600160a01b03168152602001306001600160a01b03166377078872856001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110cd9190612f74565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401600060405180830381865afa158015611111573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111399190810190613452565b905292915050565b604080516060808201835260008083526020830152918101919091526040518060600160405280836001600160a01b03168152602001836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d99190612fff565b60ff168152602001836001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561121f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111399190810190613162565b6040805160608082018352600080835260208301529181019190915260007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636b54ae3e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e79190613197565b90508084101561131657806112fc848661349d565b116113075782611319565b61131184826134b0565b611319565b60005b925060405180606001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639a0e7d666040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d79190613197565b81526020018467ffffffffffffffff8111156113f5576113f5613022565b60405190808252806020026020018201604052801561144257816020015b604080516060808201835260008083526020830152918101919091528152602001906001900390816114135790505b509052915060005b838110156114f757306328e5971a611462838861349d565b6040518263ffffffff1660e01b815260040161148091815260200190565b600060405180830381865afa9250505080156114be57506040513d6000823e601f3d908101601f191682016040526114bb91908101906134c3565b60015b156114e75780846040015183815181106114da576114da61354d565b6020026020010181905250505b6114f081613563565b905061144a565b505092915050565b611507612723565b604051638c5f860360e01b8152600481018590526001600160a01b038481166024830152604482018490526000917f000000000000000000000000000000000000000000000000000000000000000090911690638c5f860390606401602060405180830381865afa158015611580573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a49190612f74565b6040516313dccc1960e21b81526001600160a01b03821660048201529091503090634f73306490602401600060405180830381865afa1580156115eb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611613919081019061357c565b8252602082018590526040516326fceb5d60e11b81526001600160a01b038581166004830152821690634df9d6ba90602401602060405180830381865afa158015611662573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116869190613197565b6060830152509392505050565b604080516001808252818301909252600091829182918291906020808301908036833701905050905084816000815181106116d0576116d061354d565b60200260200101818152505060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663566aff6a8a866040518363ffffffff1660e01b815260040161172f9291906135b1565b600060405180830381865afa15801561174c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526117749190810190613663565b9250925092508260008151811061178d5761178d61354d565b6020026020010151826000815181106117a8576117a861354d565b6020026020010151826000815181106117c3576117c361354d565b6020026020010151965096509650505050509250925092565b60408051808201825260606020808301919091526001600160a01b038481168352835163eaed4f8360e01b8152935192936000937f00000000000000000000000000000000000000000000000000000000000000009092169263eaed4f83926004808401938290030181865afa925050508015611876575060408051601f3d908101601f1916820190925261187391810190613197565b60015b61188257506000611885565b90505b604051631ba65e5760e11b8152600481018290526001600160a01b0384811660248301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063374cbcae90604401602060405180830381865afa1580156118f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191b9190613197565b90508067ffffffffffffffff81111561193657611936613022565b60405190808252806020026020018201604052801561196f57816020015b61195c612723565b8152602001906001900390816119545790505b50602084015260005b81811015611a2c57604051634ab51f7d60e11b8152600481018490526001600160a01b038616602482015260448101829052309063956a3efa90606401600060405180830381865afa1580156119d2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119fa9190810190613749565b84602001518281518110611a1057611a1061354d565b602002602001018190525080611a2590613563565b9050611978565b505050919050565b60405163dad8284960e01b8152600481018390526001600160a01b0382811660248301526060916000917f0000000000000000000000000000000000000000000000000000000000000000169063dad8284990604401602060405180830381865afa158015611aa7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611acb9190613197565b90508067ffffffffffffffff811115611ae657611ae6613022565b604051908082528060200260200182016040528015611b1f57816020015b611b0c6126b1565b815260200190600190039081611b045790505b50915060005b818110156114f757604051632458810560e01b8152600481018690526001600160a01b038581166024830152604482018390526000917f000000000000000000000000000000000000000000000000000000000000000090911690632458810590606401602060405180830381865afa158015611ba6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bca9190612f74565b6040516313dccc1960e21b81526001600160a01b03821660048201529091503090634f73306490602401600060405180830381865afa158015611c11573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c39919081019061357c565b848381518110611c4b57611c4b61354d565b60200260200101819052505080611c6190613563565b9050611b25565b611c70612751565b604051631c96a19760e31b8152600481018490526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e4b50cb890602401602060405180830381865afa158015611cd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfc9190612f74565b8483526001600160a01b03818116602085015260405163691d5cbd60e11b8152600481018790529192507f0000000000000000000000000000000000000000000000000000000000000000169063d23ab97a90602401602060405180830381865afa158015611d6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d939190613197565b6040838101919091525163d851fdfd60e01b8152600481018590527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d851fdfd90602401602060405180830381865afa158015611dff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e239190613197565b606083015260405162b507a760e81b8152600481018590527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b507a70090602401602060405180830381865afa158015611e8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eb09190613197565b608083015260405162d7f52760e31b81526001600160a01b038216600482015230906306bfa93890602401600060405180830381865afa925050508015611f1957506040513d6000823e601f3d908101601f19168201604052611f1691908101906138cd565b60015b15611f245760e08301525b6040516339996d0560e21b8152600481018590526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e665b41490602401602060405180830381865afa158015611f8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb09190612f74565b9050600080611fbf8688611693565b604051634fa44f2760e11b8152600481018b90526001600160a01b038a811660248301529395509093507f000000000000000000000000000000000000000000000000000000000000000090921691639f489e4e9150604401602060405180830381865afa158015612035573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120599190613197565b61010086015261012085018290526001600160a01b038316156121ff57600080600080866001600160a01b03166339cbec9d6040518163ffffffff1660e01b8152600401608060405180830381865afa1580156120ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120de9190613902565b9350935093509350612113604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b604051633b83c43960e11b81526001600160a01b03861660048201523090637707887290602401600060405180830381865afa92505050801561217857506040513d6000823e601f3d908101601f191682016040526121759190810190613452565b60015b156121805790505b600061218b89612578565b90506040518061016001604052808a6001600160a01b03168152602001428611151515815260200142851115151581526020018e81526020018c604001518152602001828152602001868152602001858152602001848152602001838152602001888152508b60c001819052505050505050505b5050505092915050565b61224b6040518060c0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001606081525090565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c7a617836040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122cf9190613197565b9050808510156122fe57806122e4858761349d565b116122ef5783612301565b6122f985826134b0565b612301565b60005b93506040518060c001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600081526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166306aba0e16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c69190613197565b81526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630b909d696040518163ffffffff1660e01b8152600401602060405180830381865afa158015612429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061244d9190613197565b81526020018281526020018567ffffffffffffffff81111561247157612471613022565b6040519080825280602002602001820160405280156124aa57816020015b612497612751565b81526020019060019003908161248f5790505b509052915060005b8481101561256f573063bd0460bb6124ca838961349d565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b0387166024820152604401600060405180830381865afa158015612515573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261253d9190810190613a19565b8360a0015182815181106125535761255361354d565b60200260200101819052508061256890613563565b90506124b2565b50509392505050565b6000816001600160a01b031663c0b5fca06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125dc9190613197565b92915050565b6040805161018081019091526000610120820181815261014083019190915260606101608301528190815260200161263d604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b815260200161266f604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b81526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b031681525090565b6040518060c0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200161271e604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b905290565b60405180608001604052806127366126b1565b81526020016000815260200160008152602001600081525090565b6040518061014001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016127986127b9565b81526020016127a56125e2565b815260200160008152602001600081525090565b60405180610160016040528060006001600160a01b0316815260200160001515815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200161283e604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b8152602001600081525090565b6001600160a01b038116811461286057600080fd5b50565b60006020828403121561287557600080fd5b81356128808161284b565b9392505050565b60005b838110156128a257818101518382015260200161288a565b50506000910152565b6001600160a01b03815116825260208101516020830152600060408201516060604085015280518060608601526128e9816080870160208501612887565b601f01601f1916939093016080019392505050565b60006101208251818552612914828601826128ab565b9150506020830151848203602086015261292e82826128ab565b9150506040830151848203604086015261294882826128ab565b915050606083015160608501526080830151608085015260a083015160a085015260c083015160c085015260e083015161298d60e08601826001600160a01b03169052565b50610100928301516001600160a01b03169390920192909252919050565b60208152600061288060208301846128fe565b6000602082840312156129d057600080fd5b5035919050565b60006001600160a01b038083511684526020830151602085015260408301516040850152606083015160608501528060808401511660808501525060a082015160c060a0850152612a2b60c08501826128ab565b949350505050565b6000606083016001600160a01b0383511684526020808401518186015260408401516060604087015282815180855260808801915060808160051b8901019450838301925060005b81811015612aa957607f19898703018352612a978685516129d7565b95509284019291840191600101612a7b565b5093979650505050505050565b6020815260006128806020830184612a33565b60208152600061288060208301846129d7565b60208152600061288060208301846128ab565b60008060408385031215612b0257600080fd5b50508035926020909101359150565b60006020808352608083016001600160a01b0385511682850152818501516040850152604085015160608086015281815180845260a08701915060a08160051b8801019350848301925060005b81811015612b8c57609f19888603018352612b7a858551612a33565b94509285019291850191600101612b5e565b5092979650505050505050565b600080600060608486031215612bae57600080fd5b833592506020840135612bc08161284b565b929592945050506040919091013590565b6000815160808452612be660808501826129d7565b90506020830151602085015260408301516040850152606083015160608501528091505092915050565b6020815260006128806020830184612bd1565b60008060408385031215612c3657600080fd5b8235612c418161284b565b946020939093013593505050565b60006020808352606083016001600160a01b03855116828501528185015160408086015281815180845260808701915060808160051b8801019350848301925060005b81811015612b8c57607f19888603018352612cae858551612bd1565b94509285019291850191600101612c92565b60008060408385031215612cd357600080fd5b823591506020830135612ce58161284b565b809150509250929050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015612b8c57603f19888603018452612d338583516129d7565b94509285019290850190600101612d17565b80516001600160a01b0316825260006101606020830151612d6a602086018215159052565b506040830151612d7e604086018215159052565b50606083015160608501526080830151608085015260a083015160a085015260c083015160c085015260e083015160e0850152610100808401518186015250610120808401518282870152612dd5838701826128ab565b61014095860151969095019590955250919392505050565b6000610140825184526020830151612e1060208601826001600160a01b03169052565b5060408301516040850152606083015160608501526080830151608085015260a083015160a085015260c08301518160c0860152612e5082860182612d45565b91505060e083015184820360e0860152612e6a82826128fe565b6101008581015190870152610120948501519490950193909352509192915050565b6020815260006128806020830184612ded565b600080600060608486031215612eb457600080fd5b83359250602084013591506040840135612ecd8161284b565b809150509250925092565b6000602080835260e083016001600160a01b03855116828501528185015160408501526040850151606085015260608501516080850152608085015160a085015260a085015160c08086015281815180845261010093508387019150838160051b8801019350848301925060005b81811015612b8c5760ff19888603018352612f62858551612ded565b94509285019291850191600101612f46565b600060208284031215612f8657600080fd5b81516128808161284b565b80516dffffffffffffffffffffffffffff81168114610cb057600080fd5b600080600060608486031215612fc457600080fd5b612fcd84612f91565b9250612fdb60208501612f91565b9150604084015163ffffffff81168114612ecd57600080fd5b8051610cb08161284b565b60006020828403121561301157600080fd5b815160ff8116811461288057600080fd5b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff8111828210171561305b5761305b613022565b60405290565b604051610120810167ffffffffffffffff8111828210171561305b5761305b613022565b604051610160810167ffffffffffffffff8111828210171561305b5761305b613022565b604051610140810167ffffffffffffffff8111828210171561305b5761305b613022565b604051601f8201601f1916810167ffffffffffffffff811182821017156130f6576130f6613022565b604052919050565b600082601f83011261310f57600080fd5b815167ffffffffffffffff81111561312957613129613022565b61313c601f8201601f19166020016130cd565b81815284602083860101111561315157600080fd5b612a2b826020830160208701612887565b60006020828403121561317457600080fd5b815167ffffffffffffffff81111561318b57600080fd5b612a2b848285016130fe565b6000602082840312156131a957600080fd5b5051919050565b6000602082840312156131c257600080fd5b815161ffff8116811461288057600080fd5b80516fffffffffffffffffffffffffffffffff81168114610cb057600080fd5b6000806040838503121561320757600080fd5b613210836131d4565b915061321e602084016131d4565b90509250929050565b6000806040838503121561323a57600080fd5b82516132458161284b565b6020939093015192949293505050565b600067ffffffffffffffff82111561326f5761326f613022565b5060051b60200190565b60006060828403121561328b57600080fd5b613293613038565b905081516132a08161284b565b815260208281015190820152604082015167ffffffffffffffff8111156132c657600080fd5b6132d2848285016130fe565b60408301525092915050565b600060c082840312156132f057600080fd5b60405160c0810167ffffffffffffffff828210818311171561331457613314613022565b81604052829350845191506133288261284b565b818352602085015160208401526040850151604084015260608501516060840152608085015191506133598261284b565b81608084015260a085015191508082111561337357600080fd5b5061338085828601613279565b60a0830152505092915050565b600082601f83011261339e57600080fd5b815160206133b36133ae83613255565b6130cd565b82815260059290921b840181019181810190868411156133d257600080fd5b8286015b8481101561341257805167ffffffffffffffff8111156133f65760008081fd5b6134048986838b01016132de565b8452509183019183016133d6565b509695505050505050565b60006020828403121561342f57600080fd5b815167ffffffffffffffff81111561344657600080fd5b612a2b8482850161338d565b60006020828403121561346457600080fd5b815167ffffffffffffffff81111561347b57600080fd5b612a2b84828501613279565b634e487b7160e01b600052601160045260246000fd5b808201808211156125dc576125dc613487565b818103818111156125dc576125dc613487565b6000602082840312156134d557600080fd5b815167ffffffffffffffff808211156134ed57600080fd5b908301906060828603121561350157600080fd5b613509613038565b82516135148161284b565b81526020838101519082015260408301518281111561353257600080fd5b61353e8782860161338d565b60408301525095945050505050565b634e487b7160e01b600052603260045260246000fd5b60006001820161357557613575613487565b5060010190565b60006020828403121561358e57600080fd5b815167ffffffffffffffff8111156135a557600080fd5b612a2b848285016132de565b6000604082016001600160a01b03851683526020604081850152818551808452606086019150828701935060005b818110156135fb578451835293830193918301916001016135df565b5090979650505050505050565b600082601f83011261361957600080fd5b815160206136296133ae83613255565b82815260059290921b8401810191818101908684111561364857600080fd5b8286015b84811015613412578051835291830191830161364c565b60008060006060848603121561367857600080fd5b835167ffffffffffffffff8082111561369057600080fd5b61369c87838801613608565b94506020915081860151818111156136b357600080fd5b8601601f810188136136c457600080fd5b80516136d26133ae82613255565b81815260059190911b8201840190848101908a8311156136f157600080fd5b928501925b828410156137185783516137098161284b565b825292850192908501906136f6565b60408a015190975094505050508082111561373257600080fd5b5061373f86828701613608565b9150509250925092565b60006020828403121561375b57600080fd5b815167ffffffffffffffff8082111561377357600080fd5b908301906080828603121561378757600080fd5b6040516080810181811083821117156137a2576137a2613022565b6040528251828111156137b457600080fd5b6137c0878286016132de565b82525060208301516020820152604083015160408201526060830151606082015280935050505092915050565b6000610120828403121561380057600080fd5b613808613061565b9050815167ffffffffffffffff8082111561382257600080fd5b61382e85838601613279565b8352602084015191508082111561384457600080fd5b61385085838601613279565b6020840152604084015191508082111561386957600080fd5b5061387684828501613279565b604083015250606082015160608201526080820151608082015260a082015160a082015260c082015160c08201526138b060e08301612ff4565b60e08201526101006138c3818401612ff4565b9082015292915050565b6000602082840312156138df57600080fd5b815167ffffffffffffffff8111156138f657600080fd5b612a2b848285016137ed565b6000806000806080858703121561391857600080fd5b84516139238161284b565b60208601516040870151606090970151919890975090945092505050565b80518015158114610cb057600080fd5b6000610160828403121561396457600080fd5b61396c613085565b905061397782612ff4565b815261398560208301613941565b602082015261399660408301613941565b6040820152606082015160608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015167ffffffffffffffff8111156139f557600080fd5b613a0185828601613279565b82840152505061014080830151818301525092915050565b600060208284031215613a2b57600080fd5b815167ffffffffffffffff80821115613a4357600080fd5b908301906101408286031215613a5857600080fd5b613a606130a9565b82518152613a7060208401612ff4565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015182811115613aaf57600080fd5b613abb87828601613951565b60c08301525060e083015182811115613ad357600080fd5b613adf878286016137ed565b60e0830152506101008381015190820152610120928301519281019290925250939250505056fea264697066735822122047765bd11c7581e1744058c9ad79670b76f3c8782967897761d1def170f0996864736f6c6343000814003300000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc1270000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100c95760003560e01c8063956a3efa11610081578063ad508ec81161005b578063ad508ec8146101ed578063bd0460bb1461020d578063f4804a6d1461022d57600080fd5b8063956a3efa14610177578063a017140a14610197578063ac377cac146101cd57600080fd5b80634f733064116100b25780634f73306414610117578063770788721461013757806377a92aee1461015757600080fd5b806306bfa938146100ce57806328e5971a146100f7575b600080fd5b6100e16100dc366004612863565b61024d565b6040516100ee91906129ab565b60405180910390f35b61010a6101053660046129be565b610cb5565b6040516100ee9190612ab6565b61012a610125366004612863565b610e95565b6040516100ee9190612ac9565b61014a610145366004612863565b611141565b6040516100ee9190612adc565b61016a610165366004612aef565b611247565b6040516100ee9190612b11565b61018a610185366004612b99565b6114ff565b6040516100ee9190612c10565b6101aa6101a5366004612c23565b611693565b604080519384526001600160a01b039092166020840152908201526060016100ee565b6101e06101db366004612863565b6117dc565b6040516100ee9190612c4f565b6102006101fb366004612cc0565b611a34565b6040516100ee9190612cf0565b61022061021b366004612cc0565b611c68565b6040516100ee9190612e8c565b61024061023b366004612e9f565b612209565b6040516100ee9190612ed8565b6102556125e2565b816001600160a01b0316635f9c01b16040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156102af575060408051601f3d908101601f191682019092526102ac91810190612f74565b60015b610775576000829050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156102f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061031d9190612faf565b506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff1691506000836001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610382573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a69190612f74565b90506000846001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061040c9190612f74565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561044e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104729190612fff565b60ff1690506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104db9190612fff565b60ff16905060405180606001604052808a6001600160a01b031681526020018a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610538573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055c9190612fff565b60ff1681526020018a6001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156105a2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105ca9190810190613162565b8152508860000181905250866001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610613573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106379190613197565b8860600181815250506040518060600160405280856001600160a01b03168152602001838152602001856001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561069e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106c69190810190613162565b81525088602001819052506040518060600160405280846001600160a01b03168152602001828152602001846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561072f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107579190810190613162565b9052604089015250505050608084019190915260a083015250919050565b6000816001600160a01b03166317f11ecc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d991906131b0565b9050600080836001600160a01b0316630902f1ac6040518163ffffffff1660e01b81526004016040805180830381865afa15801561081b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083f91906131f4565b6fffffffffffffffffffffffffffffffff1691506fffffffffffffffffffffffffffffffff1691506000846001600160a01b03166305e8746d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108cb9190612f74565b90506000856001600160a01b031663da10610c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561090d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109319190612f74565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610973573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109979190612fff565b60ff1690506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a009190612fff565b6001600160a01b03808c1660e08c01819052908a166101008c015261ffff891660c08c015260408051606081018252828152815163313ce56760e01b8152915160ff949094169450926020848101939263313ce56792600480830193928290030181865afa158015610a76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9a9190612fff565b60ff1681526020018b6001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610ae0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b089190810190613162565b8152508960000181905250896001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b759190613197565b8960600181815250506040518060600160405280856001600160a01b03168152602001838152602001856001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610bdc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c049190810190613162565b81525089602001819052506040518060600160405280846001600160a01b03168152602001828152602001846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610c6d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c959190810190613162565b905260408a015250505050608085019190915260a084015250505b919050565b60408051606080820183526000808352602083015291810191909152604051637aa9ba3960e01b81526004810183905260009081906001600160a01b037f00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc1271690637aa9ba39906024016040805180830381865afa158015610d3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5e9190613227565b915091506000306001600160a01b031663ad508ec87f00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc1276001600160a01b031663ae40bc796040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df59190613197565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b0386166024820152604401600060405180830381865afa158015610e40573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e68919081019061341d565b604080516060810182526001600160a01b0390951685526020850193909352918301919091525092915050565b610e9d6126b1565b6040518060c00160405280836001600160a01b031663026b1d5f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0a9190612f74565b6001600160a01b03168152602001836001600160a01b031663225b08bb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f7a9190613197565b8152602001836001600160a01b031663953582a06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe19190613197565b8152602001836001600160a01b031663d50ff4976040518163ffffffff1660e01b8152600401602060405180830381865afa158015611024573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110489190613197565b8152602001836001600160a01b03168152602001306001600160a01b03166377078872856001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110cd9190612f74565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401600060405180830381865afa158015611111573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111399190810190613452565b905292915050565b604080516060808201835260008083526020830152918101919091526040518060600160405280836001600160a01b03168152602001836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d99190612fff565b60ff168152602001836001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561121f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111399190810190613162565b6040805160608082018352600080835260208301529181019190915260007f00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc1276001600160a01b0316636b54ae3e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e79190613197565b90508084101561131657806112fc848661349d565b116113075782611319565b61131184826134b0565b611319565b60005b925060405180606001604052807f00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc1276001600160a01b031681526020017f00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc1276001600160a01b0316639a0e7d666040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d79190613197565b81526020018467ffffffffffffffff8111156113f5576113f5613022565b60405190808252806020026020018201604052801561144257816020015b604080516060808201835260008083526020830152918101919091528152602001906001900390816114135790505b509052915060005b838110156114f757306328e5971a611462838861349d565b6040518263ffffffff1660e01b815260040161148091815260200190565b600060405180830381865afa9250505080156114be57506040513d6000823e601f3d908101601f191682016040526114bb91908101906134c3565b60015b156114e75780846040015183815181106114da576114da61354d565b6020026020010181905250505b6114f081613563565b905061144a565b505092915050565b611507612723565b604051638c5f860360e01b8152600481018590526001600160a01b038481166024830152604482018490526000917f00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc12790911690638c5f860390606401602060405180830381865afa158015611580573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a49190612f74565b6040516313dccc1960e21b81526001600160a01b03821660048201529091503090634f73306490602401600060405180830381865afa1580156115eb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611613919081019061357c565b8252602082018590526040516326fceb5d60e11b81526001600160a01b038581166004830152821690634df9d6ba90602401602060405180830381865afa158015611662573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116869190613197565b6060830152509392505050565b604080516001808252818301909252600091829182918291906020808301908036833701905050905084816000815181106116d0576116d061354d565b60200260200101818152505060008060007f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea6001600160a01b031663566aff6a8a866040518363ffffffff1660e01b815260040161172f9291906135b1565b600060405180830381865afa15801561174c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526117749190810190613663565b9250925092508260008151811061178d5761178d61354d565b6020026020010151826000815181106117a8576117a861354d565b6020026020010151826000815181106117c3576117c361354d565b6020026020010151965096509650505050509250925092565b60408051808201825260606020808301919091526001600160a01b038481168352835163eaed4f8360e01b8152935192936000937f00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc1279092169263eaed4f83926004808401938290030181865afa925050508015611876575060408051601f3d908101601f1916820190925261187391810190613197565b60015b61188257506000611885565b90505b604051631ba65e5760e11b8152600481018290526001600160a01b0384811660248301526000917f00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc1279091169063374cbcae90604401602060405180830381865afa1580156118f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191b9190613197565b90508067ffffffffffffffff81111561193657611936613022565b60405190808252806020026020018201604052801561196f57816020015b61195c612723565b8152602001906001900390816119545790505b50602084015260005b81811015611a2c57604051634ab51f7d60e11b8152600481018490526001600160a01b038616602482015260448101829052309063956a3efa90606401600060405180830381865afa1580156119d2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119fa9190810190613749565b84602001518281518110611a1057611a1061354d565b602002602001018190525080611a2590613563565b9050611978565b505050919050565b60405163dad8284960e01b8152600481018390526001600160a01b0382811660248301526060916000917f00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc127169063dad8284990604401602060405180830381865afa158015611aa7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611acb9190613197565b90508067ffffffffffffffff811115611ae657611ae6613022565b604051908082528060200260200182016040528015611b1f57816020015b611b0c6126b1565b815260200190600190039081611b045790505b50915060005b818110156114f757604051632458810560e01b8152600481018690526001600160a01b038581166024830152604482018390526000917f00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc12790911690632458810590606401602060405180830381865afa158015611ba6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bca9190612f74565b6040516313dccc1960e21b81526001600160a01b03821660048201529091503090634f73306490602401600060405180830381865afa158015611c11573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c39919081019061357c565b848381518110611c4b57611c4b61354d565b60200260200101819052505080611c6190613563565b9050611b25565b611c70612751565b604051631c96a19760e31b8152600481018490526000907f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea6001600160a01b03169063e4b50cb890602401602060405180830381865afa158015611cd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfc9190612f74565b8483526001600160a01b03818116602085015260405163691d5cbd60e11b8152600481018790529192507f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea169063d23ab97a90602401602060405180830381865afa158015611d6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d939190613197565b6040838101919091525163d851fdfd60e01b8152600481018590527f00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc1276001600160a01b03169063d851fdfd90602401602060405180830381865afa158015611dff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e239190613197565b606083015260405162b507a760e81b8152600481018590527f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea6001600160a01b03169063b507a70090602401602060405180830381865afa158015611e8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eb09190613197565b608083015260405162d7f52760e31b81526001600160a01b038216600482015230906306bfa93890602401600060405180830381865afa925050508015611f1957506040513d6000823e601f3d908101601f19168201604052611f1691908101906138cd565b60015b15611f245760e08301525b6040516339996d0560e21b8152600481018590526000907f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea6001600160a01b03169063e665b41490602401602060405180830381865afa158015611f8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb09190612f74565b9050600080611fbf8688611693565b604051634fa44f2760e11b8152600481018b90526001600160a01b038a811660248301529395509093507f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea90921691639f489e4e9150604401602060405180830381865afa158015612035573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120599190613197565b61010086015261012085018290526001600160a01b038316156121ff57600080600080866001600160a01b03166339cbec9d6040518163ffffffff1660e01b8152600401608060405180830381865afa1580156120ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120de9190613902565b9350935093509350612113604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b604051633b83c43960e11b81526001600160a01b03861660048201523090637707887290602401600060405180830381865afa92505050801561217857506040513d6000823e601f3d908101601f191682016040526121759190810190613452565b60015b156121805790505b600061218b89612578565b90506040518061016001604052808a6001600160a01b03168152602001428611151515815260200142851115151581526020018e81526020018c604001518152602001828152602001868152602001858152602001848152602001838152602001888152508b60c001819052505050505050505b5050505092915050565b61224b6040518060c0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001606081525090565b60007f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea6001600160a01b031663c7a617836040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122cf9190613197565b9050808510156122fe57806122e4858761349d565b116122ef5783612301565b6122f985826134b0565b612301565b60005b93506040518060c001604052807f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea6001600160a01b03168152602001600081526020017f00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc1276001600160a01b03166306aba0e16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c69190613197565b81526020017f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea6001600160a01b0316630b909d696040518163ffffffff1660e01b8152600401602060405180830381865afa158015612429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061244d9190613197565b81526020018281526020018567ffffffffffffffff81111561247157612471613022565b6040519080825280602002602001820160405280156124aa57816020015b612497612751565b81526020019060019003908161248f5790505b509052915060005b8481101561256f573063bd0460bb6124ca838961349d565b6040516001600160e01b031960e084901b16815260048101919091526001600160a01b0387166024820152604401600060405180830381865afa158015612515573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261253d9190810190613a19565b8360a0015182815181106125535761255361354d565b60200260200101819052508061256890613563565b90506124b2565b50509392505050565b6000816001600160a01b031663c0b5fca06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125dc9190613197565b92915050565b6040805161018081019091526000610120820181815261014083019190915260606101608301528190815260200161263d604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b815260200161266f604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b81526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b031681525090565b6040518060c0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200161271e604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b905290565b60405180608001604052806127366126b1565b81526020016000815260200160008152602001600081525090565b6040518061014001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016127986127b9565b81526020016127a56125e2565b815260200160008152602001600081525090565b60405180610160016040528060006001600160a01b0316815260200160001515815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200161283e604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b8152602001600081525090565b6001600160a01b038116811461286057600080fd5b50565b60006020828403121561287557600080fd5b81356128808161284b565b9392505050565b60005b838110156128a257818101518382015260200161288a565b50506000910152565b6001600160a01b03815116825260208101516020830152600060408201516060604085015280518060608601526128e9816080870160208501612887565b601f01601f1916939093016080019392505050565b60006101208251818552612914828601826128ab565b9150506020830151848203602086015261292e82826128ab565b9150506040830151848203604086015261294882826128ab565b915050606083015160608501526080830151608085015260a083015160a085015260c083015160c085015260e083015161298d60e08601826001600160a01b03169052565b50610100928301516001600160a01b03169390920192909252919050565b60208152600061288060208301846128fe565b6000602082840312156129d057600080fd5b5035919050565b60006001600160a01b038083511684526020830151602085015260408301516040850152606083015160608501528060808401511660808501525060a082015160c060a0850152612a2b60c08501826128ab565b949350505050565b6000606083016001600160a01b0383511684526020808401518186015260408401516060604087015282815180855260808801915060808160051b8901019450838301925060005b81811015612aa957607f19898703018352612a978685516129d7565b95509284019291840191600101612a7b565b5093979650505050505050565b6020815260006128806020830184612a33565b60208152600061288060208301846129d7565b60208152600061288060208301846128ab565b60008060408385031215612b0257600080fd5b50508035926020909101359150565b60006020808352608083016001600160a01b0385511682850152818501516040850152604085015160608086015281815180845260a08701915060a08160051b8801019350848301925060005b81811015612b8c57609f19888603018352612b7a858551612a33565b94509285019291850191600101612b5e565b5092979650505050505050565b600080600060608486031215612bae57600080fd5b833592506020840135612bc08161284b565b929592945050506040919091013590565b6000815160808452612be660808501826129d7565b90506020830151602085015260408301516040850152606083015160608501528091505092915050565b6020815260006128806020830184612bd1565b60008060408385031215612c3657600080fd5b8235612c418161284b565b946020939093013593505050565b60006020808352606083016001600160a01b03855116828501528185015160408086015281815180845260808701915060808160051b8801019350848301925060005b81811015612b8c57607f19888603018352612cae858551612bd1565b94509285019291850191600101612c92565b60008060408385031215612cd357600080fd5b823591506020830135612ce58161284b565b809150509250929050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015612b8c57603f19888603018452612d338583516129d7565b94509285019290850190600101612d17565b80516001600160a01b0316825260006101606020830151612d6a602086018215159052565b506040830151612d7e604086018215159052565b50606083015160608501526080830151608085015260a083015160a085015260c083015160c085015260e083015160e0850152610100808401518186015250610120808401518282870152612dd5838701826128ab565b61014095860151969095019590955250919392505050565b6000610140825184526020830151612e1060208601826001600160a01b03169052565b5060408301516040850152606083015160608501526080830151608085015260a083015160a085015260c08301518160c0860152612e5082860182612d45565b91505060e083015184820360e0860152612e6a82826128fe565b6101008581015190870152610120948501519490950193909352509192915050565b6020815260006128806020830184612ded565b600080600060608486031215612eb457600080fd5b83359250602084013591506040840135612ecd8161284b565b809150509250925092565b6000602080835260e083016001600160a01b03855116828501528185015160408501526040850151606085015260608501516080850152608085015160a085015260a085015160c08086015281815180845261010093508387019150838160051b8801019350848301925060005b81811015612b8c5760ff19888603018352612f62858551612ded565b94509285019291850191600101612f46565b600060208284031215612f8657600080fd5b81516128808161284b565b80516dffffffffffffffffffffffffffff81168114610cb057600080fd5b600080600060608486031215612fc457600080fd5b612fcd84612f91565b9250612fdb60208501612f91565b9150604084015163ffffffff81168114612ecd57600080fd5b8051610cb08161284b565b60006020828403121561301157600080fd5b815160ff8116811461288057600080fd5b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff8111828210171561305b5761305b613022565b60405290565b604051610120810167ffffffffffffffff8111828210171561305b5761305b613022565b604051610160810167ffffffffffffffff8111828210171561305b5761305b613022565b604051610140810167ffffffffffffffff8111828210171561305b5761305b613022565b604051601f8201601f1916810167ffffffffffffffff811182821017156130f6576130f6613022565b604052919050565b600082601f83011261310f57600080fd5b815167ffffffffffffffff81111561312957613129613022565b61313c601f8201601f19166020016130cd565b81815284602083860101111561315157600080fd5b612a2b826020830160208701612887565b60006020828403121561317457600080fd5b815167ffffffffffffffff81111561318b57600080fd5b612a2b848285016130fe565b6000602082840312156131a957600080fd5b5051919050565b6000602082840312156131c257600080fd5b815161ffff8116811461288057600080fd5b80516fffffffffffffffffffffffffffffffff81168114610cb057600080fd5b6000806040838503121561320757600080fd5b613210836131d4565b915061321e602084016131d4565b90509250929050565b6000806040838503121561323a57600080fd5b82516132458161284b565b6020939093015192949293505050565b600067ffffffffffffffff82111561326f5761326f613022565b5060051b60200190565b60006060828403121561328b57600080fd5b613293613038565b905081516132a08161284b565b815260208281015190820152604082015167ffffffffffffffff8111156132c657600080fd5b6132d2848285016130fe565b60408301525092915050565b600060c082840312156132f057600080fd5b60405160c0810167ffffffffffffffff828210818311171561331457613314613022565b81604052829350845191506133288261284b565b818352602085015160208401526040850151604084015260608501516060840152608085015191506133598261284b565b81608084015260a085015191508082111561337357600080fd5b5061338085828601613279565b60a0830152505092915050565b600082601f83011261339e57600080fd5b815160206133b36133ae83613255565b6130cd565b82815260059290921b840181019181810190868411156133d257600080fd5b8286015b8481101561341257805167ffffffffffffffff8111156133f65760008081fd5b6134048986838b01016132de565b8452509183019183016133d6565b509695505050505050565b60006020828403121561342f57600080fd5b815167ffffffffffffffff81111561344657600080fd5b612a2b8482850161338d565b60006020828403121561346457600080fd5b815167ffffffffffffffff81111561347b57600080fd5b612a2b84828501613279565b634e487b7160e01b600052601160045260246000fd5b808201808211156125dc576125dc613487565b818103818111156125dc576125dc613487565b6000602082840312156134d557600080fd5b815167ffffffffffffffff808211156134ed57600080fd5b908301906060828603121561350157600080fd5b613509613038565b82516135148161284b565b81526020838101519082015260408301518281111561353257600080fd5b61353e8782860161338d565b60408301525095945050505050565b634e487b7160e01b600052603260045260246000fd5b60006001820161357557613575613487565b5060010190565b60006020828403121561358e57600080fd5b815167ffffffffffffffff8111156135a557600080fd5b612a2b848285016132de565b6000604082016001600160a01b03851683526020604081850152818551808452606086019150828701935060005b818110156135fb578451835293830193918301916001016135df565b5090979650505050505050565b600082601f83011261361957600080fd5b815160206136296133ae83613255565b82815260059290921b8401810191818101908684111561364857600080fd5b8286015b84811015613412578051835291830191830161364c565b60008060006060848603121561367857600080fd5b835167ffffffffffffffff8082111561369057600080fd5b61369c87838801613608565b94506020915081860151818111156136b357600080fd5b8601601f810188136136c457600080fd5b80516136d26133ae82613255565b81815260059190911b8201840190848101908a8311156136f157600080fd5b928501925b828410156137185783516137098161284b565b825292850192908501906136f6565b60408a015190975094505050508082111561373257600080fd5b5061373f86828701613608565b9150509250925092565b60006020828403121561375b57600080fd5b815167ffffffffffffffff8082111561377357600080fd5b908301906080828603121561378757600080fd5b6040516080810181811083821117156137a2576137a2613022565b6040528251828111156137b457600080fd5b6137c0878286016132de565b82525060208301516020820152604083015160408201526060830151606082015280935050505092915050565b6000610120828403121561380057600080fd5b613808613061565b9050815167ffffffffffffffff8082111561382257600080fd5b61382e85838601613279565b8352602084015191508082111561384457600080fd5b61385085838601613279565b6020840152604084015191508082111561386957600080fd5b5061387684828501613279565b604083015250606082015160608201526080820151608082015260a082015160a082015260c082015160c08201526138b060e08301612ff4565b60e08201526101006138c3818401612ff4565b9082015292915050565b6000602082840312156138df57600080fd5b815167ffffffffffffffff8111156138f657600080fd5b612a2b848285016137ed565b6000806000806080858703121561391857600080fd5b84516139238161284b565b60208601516040870151606090970151919890975090945092505050565b80518015158114610cb057600080fd5b6000610160828403121561396457600080fd5b61396c613085565b905061397782612ff4565b815261398560208301613941565b602082015261399660408301613941565b6040820152606082015160608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015167ffffffffffffffff8111156139f557600080fd5b613a0185828601613279565b82840152505061014080830151818301525092915050565b600060208284031215613a2b57600080fd5b815167ffffffffffffffff80821115613a4357600080fd5b908301906101408286031215613a5857600080fd5b613a606130a9565b82518152613a7060208401612ff4565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015182811115613aaf57600080fd5b613abb87828601613951565b60c08301525060e083015182811115613ad357600080fd5b613adf878286016137ed565b60e0830152506101008381015190820152610120928301519281019290925250939250505056fea264697066735822122047765bd11c7581e1744058c9ad79670b76f3c8782967897761d1def170f0996864736f6c63430008140033

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

00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc1270000000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : masterChef (address): 0x72a42e8a344eB66ACA9eD13d5C633731cF54EeEa
Arg [1] : voter (address): 0x45bD05527C9e49bD88bFE66979F56a95eADdc127
Arg [2] : mlumStaking (address): 0x0000000000000000000000000000000000000000

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea
Arg [1] : 00000000000000000000000045bd05527c9e49bd88bfe66979f56a95eaddc127
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000


Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits

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.