creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/FarmBoosterV3.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"@openzeppelin-4.5.0/contracts/access/Ownable.sol\";\nimport \"@openzeppelin-4.5.0/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin-4.5.0/contracts/security/ReentrancyGuard.sol\";\nimport \"./libraries/IterateMapping.sol\";\nimport \"./interfaces/IVECake.sol\";\nimport \"./interfaces/IMasterChefV3.sol\";\nimport \"./interfaces/IPancakeV3Pool.sol\";\nimport \"./interfaces/INonfungiblePositionManager.sol\";\nimport \"./interfaces/IPancakeV3Factory.sol\";\n\n// Vecake user can delegate VECake to another address for boosting in MasterChef V3 in FarmBooster version three.\ncontract FarmBoosterV3 is Ownable, ReentrancyGuard {\n    using IterableMapping for ItMap;\n\n    /// @notice VECake.\n    address public immutable VECake;\n    /// @notice VECake caller, this smart contract will trigger depositFor and unlock.\n    address public VECakeCaller;\n    /// @notice MasterChef V3 contract.\n    IMasterChefV3 public immutable MASTER_CHEF_V3;\n\n    /// @notice NonfungiblePositionManager contract.\n    INonfungiblePositionManager public immutable NonfungiblePositionManager;\n\n    /// @notice PancakeV3Factory contract.\n    IPancakeV3Factory public immutable PancakeV3Factory;\n\n    /// @notice Record user token position liquidity\n    /// @dev Only record the positions which have updated after fram booster set in MasterChef V3.\n    mapping(address => mapping(uint256 => uint256)) public userPositionLiquidity;\n\n    /// @notice Record user total liquidity in MasterChef V3 pool\n    mapping(address => mapping(uint256 => uint256)) public userPoolTotalLiquidity;\n\n    /// @notice limit max boost\n    uint256 public cA;\n    /// @notice include 1e4\n    uint256 public constant MIN_CA = 1e4;\n    /// @notice include 1e5\n    uint256 public constant MAX_CA = 1e5;\n    /// @notice cA precision\n    uint256 public constant CA_PRECISION = 1e5;\n    /// @notice controls difficulties\n    uint256 public cB;\n    /// @notice not include 0\n    uint256 public constant MIN_CB = 0;\n    /// @notice include 50\n    uint256 public constant MAX_CB = 1e8;\n    /// @notice cB precision\n    uint256 public constant CB_PRECISION = 1e4;\n    /// @notice MCV3 basic boost factor, none boosted user\"s boost factor\n    uint256 public constant BOOST_PRECISION = 100 * 1e10;\n    /// @notice MCV3 Hard limit for maximum boost factor\n    uint256 public constant MAX_BOOST_PRECISION = 200 * 1e10;\n\n    /// @notice Override global cB for special pool pid.\n    mapping(uint256 => uint256) public cBOverride;\n\n    /// @notice The whitelist of pools allowed for farm boosting.\n    mapping(uint256 => bool) public whiteList;\n\n    /// @notice Record whether the farm booster has been turned on, in order to save gas.\n    mapping(uint256 => bool) public everBoosted;\n\n    /// @notice Info of each pool user.\n    mapping(address => ItMap) public userInfo;\n\n    /// @notice VECake delegator address in MasterChef V3.\n    /// @dev User can delegate VECake to another address for boosted in MasterChef V3.\n    /// Mapping from VECake account to MasterChef V3 delegator account.\n    mapping(address => address) public delegator;\n\n    /// @notice The MasterChef V3 account which was delegated by VECake account.\n    /// Mapping from MasterChef V3 delegator account to VECake account.\n    mapping(address => address) public delegated;\n\n    /// @notice Gives permission to VECake account.\n    /// @dev Avoid malicious attacks.\n    /// The approval is cleared when the delegator was setted.\n    /// Mapping from MasterChef V3 delegator account to VECake account.\n    mapping(address => address) public delegatorApprove;\n\n    event UpdateCA(uint256 oldCA, uint256 newCA);\n    event UpdateCB(uint256 oldCB, uint256 newCB);\n    event UpdateCBOverride(uint256 pid, uint256 oldCB, uint256 newCB);\n    event UpdateBoostFarms(uint256 pid, bool status);\n    event UpdatePoolBoostMultiplier(\n        address indexed user,\n        uint256 indexed pid,\n        uint256 indexed tokenId,\n        uint256 oldMultiplier,\n        uint256 newMultiplier\n    );\n    event UpdateVECakeCaller(address VECakeCaller);\n    event UpdateDelegator(address indexed user, address indexed oldDelegator, address indexed delegator);\n    event Approve(address indexed delegator, address indexed VECakeUser);\n\n    /// @param _VECake VECake contract address.\n    /// @param _v3 MasterChefV3 contract address.\n    /// @param _cA Limit max boost.\n    /// @param _cB Controls difficulties.\n    constructor(\n        address _VECake,\n        IMasterChefV3 _v3,\n        uint256 _cA,\n        uint256 _cB\n    ) {\n        require(_cA >= MIN_CA && _cA <= MAX_CA && _cB > MIN_CB && _cB <= MAX_CB, \"Invalid parameter\");\n        VECake = _VECake;\n        MASTER_CHEF_V3 = _v3;\n        cA = _cA;\n        cB = _cB;\n\n        NonfungiblePositionManager = INonfungiblePositionManager(MASTER_CHEF_V3.nonfungiblePositionManager());\n\n        PancakeV3Factory = IPancakeV3Factory(NonfungiblePositionManager.factory());\n    }\n\n    /// @notice Checks if the msg.sender is the MasterChef V3.\n    modifier onlyMasterChefV3() {\n        require(msg.sender == address(MASTER_CHEF_V3), \"Not MasterChef V3\");\n        _;\n    }\n\n    /// @notice Checks if the msg.sender is the vecake caller.\n    modifier onlyVECakeCaller() {\n        require(msg.sender == VECakeCaller, \"Not vecake caller\");\n        _;\n    }\n\n    struct DelegatorConfig {\n        address VECakeUser;\n        address delegator;\n    }\n\n    /// @notice set VECake delegators.\n    /// @dev In case VECake partner contract can not upgrade, owner can set delegator.\n    /// The delegator address can not have any position in MasterChef V3.\n    /// The old delegator address can not have any position in MasterChef V3.\n    /// @param _delegatorConfigs VECake delegator config.\n    function setDelegators(DelegatorConfig[] calldata _delegatorConfigs) external onlyOwner {\n        for (uint256 i = 0; i < _delegatorConfigs.length; i++) {\n            DelegatorConfig memory delegatorConfig = _delegatorConfigs[i];\n            require(\n                delegatorConfig.VECakeUser != address(0) && delegatorConfig.delegator != address(0),\n                \"Invalid address\"\n            );\n            // The delegator need to approve VECake contract.\n            require(delegatorApprove[delegatorConfig.delegator] == delegatorConfig.VECakeUser, \"Not approved\");\n\n            address oldDelegator = delegatorConfig.VECakeUser;\n            if (delegator[delegatorConfig.VECakeUser] != address(0)) {\n                oldDelegator = delegator[delegatorConfig.VECakeUser];\n            }\n            // clear old delegated information\n            delegated[oldDelegator] = address(0);\n\n            uint256 oldDelegatorBalanceInMCV3 = MASTER_CHEF_V3.balanceOf(oldDelegator);\n            uint256 delegatorBalanceInMCV3 = MASTER_CHEF_V3.balanceOf(delegatorConfig.delegator);\n            require(\n                oldDelegatorBalanceInMCV3 == 0 && delegatorBalanceInMCV3 == 0,\n                \"Please withdraw all positions in MasterChef V3\"\n            );\n\n            delegator[delegatorConfig.VECakeUser] = delegatorConfig.delegator;\n            delegated[delegatorConfig.delegator] = delegatorConfig.VECakeUser;\n            delegatorApprove[delegatorConfig.delegator] = address(0);\n            emit UpdateDelegator(delegatorConfig.VECakeUser, oldDelegator, delegatorConfig.delegator);\n        }\n    }\n\n    /// @notice Gives permission to VECake account.\n    /// @dev Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n    /// The approval is cleared when the delegator is set.\n    /// @param _VECakeUser VECake account address.\n    function approveToVECakeUser(address _VECakeUser) external nonReentrant {\n        require(delegated[msg.sender] == address(0), \"Delegator already has VECake account\");\n\n        delegatorApprove[msg.sender] = _VECakeUser;\n        emit Approve(msg.sender, _VECakeUser);\n    }\n\n    /// @notice set VECake delegator address for MasterChef V3.\n    /// @dev The delegator address can not have any position in MasterChef V3.\n    /// The old delegator address can not have any position in MasterChef V3.\n    /// @param _delegator MasterChef V3 delegator address.\n    function setDelegator(address _delegator) external nonReentrant {\n        require(_delegator != address(0), \"Invalid address\");\n        // The delegator need to approve VECake contract.\n        require(delegatorApprove[_delegator] == msg.sender, \"Not approved\");\n\n        address oldDelegator = msg.sender;\n        if (delegator[msg.sender] != address(0)) {\n            oldDelegator = delegator[msg.sender];\n        }\n        // clear old delegated information\n        delegated[oldDelegator] = address(0);\n\n        uint256 oldDelegatorBalanceInMCV3 = MASTER_CHEF_V3.balanceOf(oldDelegator);\n        uint256 delegatorBalanceInMCV3 = MASTER_CHEF_V3.balanceOf(_delegator);\n        require(\n            oldDelegatorBalanceInMCV3 == 0 && delegatorBalanceInMCV3 == 0,\n            \"Please withdraw all positions in MasterChef V3\"\n        );\n\n        delegator[msg.sender] = _delegator;\n        delegated[_delegator] = msg.sender;\n        delegatorApprove[_delegator] = address(0);\n\n        emit UpdateDelegator(msg.sender, oldDelegator, _delegator);\n    }\n\n    /// @notice Remove VECake delegator address for MasterChef V3.\n    /// @dev The old delegator address can not have any position in MasterChef V3.\n    function removeDelegator() external nonReentrant {\n        address oldDelegator = delegator[msg.sender];\n        require(oldDelegator != address(0), \"No delegator\");\n        uint256 oldDelegatorBalanceInMCV3 = MASTER_CHEF_V3.balanceOf(oldDelegator);\n        require(oldDelegatorBalanceInMCV3 == 0, \"Please withdraw all positions in MasterChef V3\");\n\n        delegated[oldDelegator] = address(0);\n        delegator[msg.sender] = address(0);\n        emit UpdateDelegator(msg.sender, oldDelegator, address(0));\n    }\n\n    /// @notice set VECake caller.\n    /// @param _VECakeCaller VECake caller.\n    function setVECakeCaller(address _VECakeCaller) external onlyOwner {\n        VECakeCaller = _VECakeCaller;\n        emit UpdateVECakeCaller(_VECakeCaller);\n    }\n\n    struct BoosterFarmConfig {\n        uint256 pid;\n        bool status;\n    }\n\n    /// @notice Only allow whitelisted pids for farm boosting.\n    /// @param _boosterFarms Booster farms config\n    function setBoosterFarms(BoosterFarmConfig[] calldata _boosterFarms) external onlyOwner {\n        for (uint256 i = 0; i < _boosterFarms.length; i++) {\n            BoosterFarmConfig memory farm = _boosterFarms[i];\n            if (farm.status && !everBoosted[farm.pid]) everBoosted[farm.pid] = true;\n            whiteList[farm.pid] = farm.status;\n            emit UpdateBoostFarms(farm.pid, farm.status);\n        }\n    }\n\n    /// @notice Limit max boost.\n    /// @param _cA Max boost.\n    function setCA(uint256 _cA) external onlyOwner {\n        require(_cA >= MIN_CA && _cA <= MAX_CA, \"Invalid cA\");\n        uint256 temp = cA;\n        cA = _cA;\n        emit UpdateCA(temp, cA);\n    }\n\n    /// @notice Controls difficulties.\n    /// @param _cB Difficulties.\n    function setCB(uint256 _cB) external onlyOwner {\n        require(_cB > MIN_CB && _cB <= MAX_CB, \"Invalid cB\");\n        uint256 temp = cB;\n        cB = _cB;\n        emit UpdateCB(temp, cB);\n    }\n\n    /// @notice Set cBOverride.\n    /// @param _pid Pool pid.\n    /// @param _cB Difficulties.\n    function setCBOverride(uint256 _pid, uint256 _cB) external onlyOwner {\n        // Can set cBOverride[pid] 0 when need to remove override value.\n        require((_cB > MIN_CB && _cB <= MAX_CB) || _cB == 0, \"Invalid cB\");\n        uint256 temp = cB;\n        cBOverride[_pid] = _cB;\n        emit UpdateCBOverride(_pid, temp, cB);\n    }\n\n    /// @notice Update user pool liquidity.\n    /// @dev This will update the user total liquidity in pool.\n    /// @param _user User address.\n    /// @param _tokenId token id.\n    /// @param _pid pool id.\n    /// @param _liquidity token liquidity.\n    function updateUserPoolLiquidity(\n        address _user,\n        uint256 _tokenId,\n        uint256 _pid,\n        uint256 _liquidity\n    ) internal {\n        // update total liquidity in this pool\n        userPoolTotalLiquidity[_user][_pid] =\n            userPoolTotalLiquidity[_user][_pid] -\n            userPositionLiquidity[_user][_tokenId] +\n            _liquidity;\n        userPositionLiquidity[_user][_tokenId] = _liquidity;\n    }\n\n    /// @notice Update user boost multiplier, only for MasterChef V3.\n    /// @param _tokenId Token Id of position NFT.\n    function updatePositionBoostMultiplier(uint256 _tokenId) external onlyMasterChefV3 returns (uint256 _multiplier) {\n        (\n            uint128 liquidity,\n            uint128 boostLiquidity,\n            ,\n            ,\n            ,\n            ,\n            address user,\n            uint256 pid,\n            uint256 boostMultiplier\n        ) = MASTER_CHEF_V3.userPositionInfos(_tokenId);\n        // Do not allow user to increase liquidity after removed all liquidity in MasterChef V3.\n        if (boostLiquidity == 0 && boostMultiplier > 0) {\n            revert();\n        }\n        // Set default multiplier\n        _multiplier = BOOST_PRECISION;\n        // In order to save gas, no need to check the farms which have never been boosted.\n        if (everBoosted[pid]) {\n            updateUserPoolLiquidity(user, _tokenId, pid, liquidity);\n\n            ItMap storage itmap = userInfo[user];\n            uint256 prevMultiplier = itmap.data[_tokenId];\n\n            if (!whiteList[pid]) {\n                if (itmap.contains(_tokenId)) {\n                    itmap.remove(_tokenId);\n                }\n            } else {\n                _multiplier = _boostCalculate(user, pid, userPoolTotalLiquidity[user][pid], 0, true);\n                itmap.insert(_tokenId, _multiplier);\n            }\n            emit UpdatePoolBoostMultiplier(user, pid, _tokenId, prevMultiplier, _multiplier);\n        }\n    }\n\n    /// @notice Remove user boost multiplier when user withdraw or burn in MasterChef V3.\n    /// @param _user User address.\n    /// @param _tokenId Token Id of position NFT.\n    /// @param _pid Id of MasterChef V3 farm pool.\n    function removeBoostMultiplier(\n        address _user,\n        uint256 _tokenId,\n        uint256 _pid\n    ) external onlyMasterChefV3 {\n        // In order to save gas, no need to check the farms which have never been boosted.\n        if (everBoosted[_pid]) {\n            updateUserPoolLiquidity(_user, _tokenId, _pid, 0);\n\n            ItMap storage itmap = userInfo[_user];\n            if (itmap.contains(_tokenId)) {\n                itmap.remove(_tokenId);\n            }\n        }\n    }\n\n    /// @notice VECake operation(deposit/withdraw) automatically call this function.\n    /// @param _for User address.\n    /// @param _amount The amount to deposit\n    /// @param _unlockTime New time to unlock Cake. Pass 0 if no change.\n    /// @param _prevLockedAmount Existed locks[_for].amount\n    /// @param _prevLockedEnd Existed locks[_for].end\n    /// @param _actionType The action that user did as this internal function shared among\n    /// @param _isCakePoolUser This user is cake pool user or not\n    function depositFor(\n        address _for,\n        uint256 _amount,\n        uint256 _unlockTime,\n        int128 _prevLockedAmount,\n        uint256 _prevLockedEnd,\n        uint256 _actionType,\n        bool _isCakePoolUser\n    ) external onlyVECakeCaller {\n        _updateUserAllBoostMultiplier(_for);\n    }\n\n    /// @notice Function to perform withdraw and unlock Cake for a user\n    /// @param _user The address to be unlocked\n    /// @param _prevLockedAmount Existed locks[_user].amount\n    /// @param _prevLockedEnd Existed locks[_user].end\n    /// @param _withdrawAmount Cake amount\n    function unlock(\n        address _user,\n        int128 _prevLockedAmount,\n        uint256 _prevLockedEnd,\n        uint256 _withdrawAmount\n    ) external onlyVECakeCaller {\n        _updateUserAllBoostMultiplier(_user);\n    }\n\n    function _updateUserAllBoostMultiplier(address _user) internal {\n        ItMap storage itmap = userInfo[_user];\n        uint256 length = itmap.keys.length;\n        if (length > 0) {\n            for (uint256 i = 0; i < length; i++) {\n                uint256 tokenId = itmap.keys[i];\n                (, address user, uint256 pid, ) = getUserPositionInfo(tokenId);\n                if (_user == user) _updateBoostMultiplier(itmap, user, pid, tokenId);\n            }\n        }\n    }\n\n    /// @param _user user address.\n    /// @param _pid pool id.\n    /// @param _tokenId token id.\n    function _updateBoostMultiplier(\n        ItMap storage itmap,\n        address _user,\n        uint256 _pid,\n        uint256 _tokenId\n    ) internal {\n        // Used to be boosted farm pool and current is not, remove from mapping\n        if (!whiteList[_pid]) {\n            if (itmap.data[_tokenId] > BOOST_PRECISION) {\n                // reset to BOOST_PRECISION\n                MASTER_CHEF_V3.updateBoostMultiplier(_tokenId, BOOST_PRECISION);\n            }\n            itmap.remove(_tokenId);\n            return;\n        }\n\n        (, , , uint256 prevMultiplier) = getUserPositionInfo(_tokenId);\n        uint256 multiplier = _boostCalculate(_user, _pid, userPoolTotalLiquidity[_user][_pid], 0, true);\n\n        if (multiplier < BOOST_PRECISION) {\n            multiplier = BOOST_PRECISION;\n        } else if (multiplier > MAX_BOOST_PRECISION) {\n            multiplier = MAX_BOOST_PRECISION;\n        }\n\n        // Update multiplier to MCV3\n        if (multiplier != prevMultiplier) {\n            MASTER_CHEF_V3.updateBoostMultiplier(_tokenId, multiplier);\n        }\n        itmap.insert(_tokenId, multiplier);\n\n        emit UpdatePoolBoostMultiplier(_user, _pid, _tokenId, prevMultiplier, multiplier);\n    }\n\n    /// @notice Whether position boosted specific farm pool.\n    /// @param _tokenId Token Id of position NFT.\n    function isBoostedPool(uint256 _tokenId) external view returns (bool, uint256) {\n        (, address user, uint256 pid, ) = getUserPositionInfo(_tokenId);\n        return (userInfo[user].contains(_tokenId), pid);\n    }\n\n    /// @notice Actived position list.\n    /// @param _user user address.\n    function activedPositions(address _user) external view returns (uint256[] memory positions) {\n        ItMap storage itmap = userInfo[_user];\n        if (itmap.keys.length == 0) return positions;\n\n        positions = new uint256[](itmap.keys.length);\n        // solidity for-loop not support multiple variables initialized by \",\" separate.\n        for (uint256 index = 0; index < itmap.keys.length; index++) {\n            positions[index] = itmap.keys[index];\n        }\n    }\n\n    function getUserPositionInfo(uint256 _tokenId)\n        internal\n        view\n        returns (\n            uint128 liquidity,\n            address user,\n            uint256 pid,\n            uint256 boostMultiplier\n        )\n    {\n        (liquidity, , , , , , user, pid, boostMultiplier) = MASTER_CHEF_V3.userPositionInfos(_tokenId);\n    }\n\n    /// @notice Anyone can call this function, if you find some guys effected multiplier is not fair\n    /// for other users, just call \"updateLiquidity\" function in MasterChef V3.\n    /// @param _tokenId Token Id of position NFT.\n    /// @dev If return value not in range [BOOST_PRECISION, MAX_BOOST_PRECISION]\n    /// the actual effected multiplier will be the close to side boundry value.\n    function getUserMultiplier(uint256 _tokenId) external view returns (uint256) {\n        (uint256 liquidity, address user, uint256 pid, ) = getUserPositionInfo(_tokenId);\n        // Default is true\n        bool isStaked = true;\n        // positions did not stake in MasterChefV3 when pid is equal to 0.\n        // Check positions in NonfungiblePositionManager\n        if (pid == 0) {\n            (\n                ,\n                ,\n                address token0,\n                address token1,\n                uint24 fee,\n                ,\n                ,\n                uint128 positionLiquidity,\n                ,\n                ,\n                ,\n\n            ) = NonfungiblePositionManager.positions(_tokenId);\n\n            liquidity = uint256(positionLiquidity);\n            user = NonfungiblePositionManager.ownerOf(_tokenId);\n            address v3PoolAddress = PancakeV3Factory.getPool(token0, token1, fee);\n            pid = MASTER_CHEF_V3.v3PoolAddressPid(v3PoolAddress);\n\n            if (pid > 0) {\n                isStaked = false;\n            }\n        }\n        if (!whiteList[pid]) {\n            return BOOST_PRECISION;\n        } else {\n            uint256 totalLiquidityInPool = userPoolTotalLiquidity[user][pid] -\n                userPositionLiquidity[user][_tokenId] +\n                liquidity;\n            return _boostCalculate(user, pid, totalLiquidityInPool, liquidity, isStaked);\n        }\n    }\n\n    /// @notice Get the total liquidity.\n    /// @dev Will use the smaller value between MasterChefV3 pool totalLiquidity and V3 pool liquidity.\n    /// @param _pid pool id(MasterchefV3 pool).\n    /// @param _positionLiquidity Position liquidity of tokenId\n    /// @param _isStaked The position had staked in MasterChefV3 or not\n    function _getTotalLiquidity(\n        uint256 _pid,\n        uint256 _positionLiquidity,\n        bool _isStaked\n    ) internal view returns (uint256) {\n        (, address v3Pool, , , , uint256 totalLiquidity, ) = MASTER_CHEF_V3.poolInfo(_pid);\n        if (!_isStaked) {\n            totalLiquidity += _positionLiquidity;\n        }\n        uint256 v3PoolLiquidity = IPancakeV3Pool(v3Pool).liquidity();\n        if (totalLiquidity > v3PoolLiquidity) {\n            totalLiquidity = v3PoolLiquidity;\n        }\n        return totalLiquidity;\n    }\n\n    /// @param _user user address.\n    /// @param _pid pool id(MasterchefV3 pool).\n    /// @param _userTotalLiquidity User total liquidity in MasterChef V3 pool\n    /// @param _positionLiquidity Position liquidity of tokenId\n    /// @param _isStaked The position had staked in MasterChefV3 or not\n    function _boostCalculate(\n        address _user,\n        uint256 _pid,\n        uint256 _userTotalLiquidity,\n        uint256 _positionLiquidity,\n        bool _isStaked\n    ) internal view returns (uint256) {\n        // If this user has delegator , but the delegator is not the same user in MasterChef V3, use default boost factor.\n        if (delegator[_user] != address(0) && delegator[_user] != _user) {\n            return BOOST_PRECISION;\n        }\n\n        // If MasterChef V3 user has delegated VECake account, use delegated VECake account balance to calculate boost factor.\n        address VEcakeUser = _user;\n        if (delegated[_user] != address(0)) {\n            VEcakeUser = delegated[_user];\n        }\n\n        uint256 dB = (cA * _userTotalLiquidity) / CA_PRECISION;\n        // dB == 0 means _liquidity close to 0\n        if (dB == 0) return BOOST_PRECISION;\n\n        uint256 totalLiquidity = _getTotalLiquidity(_pid, _positionLiquidity, _isStaked);\n\n        // will use cBOverride[pid] If cBOverride[pid] is greater than 0 , or will use global cB.\n        uint256 realCB = cBOverride[_pid] > 0 ? cBOverride[_pid] : cB;\n        uint256 totalSupplyInVECake = IVECake(VECake).totalSupply();\n        if (totalSupplyInVECake == 0) return BOOST_PRECISION;\n\n        uint256 aB = (totalLiquidity * IVECake(VECake).balanceOf(VEcakeUser) * realCB) /\n            totalSupplyInVECake /\n            CB_PRECISION;\n        return ((_userTotalLiquidity <= (dB + aB) ? _userTotalLiquidity : (dB + aB)) * BOOST_PRECISION) / dB;\n    }\n}\n"
      },
      "@openzeppelin-4.5.0/contracts/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
      },
      "@openzeppelin-4.5.0/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"
      },
      "@openzeppelin-4.5.0/contracts/security/ReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    constructor() {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        // On the first call to nonReentrant, _notEntered will be true\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n\n        _;\n\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n}\n"
      },
      "contracts/libraries/IterateMapping.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nstruct ItMap {\n    // pid => boost\n    mapping(uint256 => uint256) data;\n    // pid => index\n    mapping(uint256 => uint256) indexs;\n    // array of pid\n    uint256[] keys;\n    // never use it, just for keep compile success.\n    uint256 size;\n}\n\nlibrary IterableMapping {\n    function insert(\n        ItMap storage self,\n        uint256 key,\n        uint256 value\n    ) internal {\n        uint256 keyIndex = self.indexs[key];\n        self.data[key] = value;\n        if (keyIndex > 0) return;\n        else {\n            self.indexs[key] = self.keys.length + 1;\n            self.keys.push(key);\n            return;\n        }\n    }\n\n    function remove(ItMap storage self, uint256 key) internal {\n        uint256 index = self.indexs[key];\n        if (index == 0) return;\n        uint256 lastKey = self.keys[self.keys.length - 1];\n        if (key != lastKey) {\n            self.keys[index - 1] = lastKey;\n            self.indexs[lastKey] = index;\n        }\n        delete self.data[key];\n        delete self.indexs[key];\n        self.keys.pop();\n    }\n\n    function contains(ItMap storage self, uint256 key) internal view returns (bool) {\n        return self.indexs[key] > 0;\n    }\n}\n"
      },
      "contracts/interfaces/IVECake.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.10;\n\ninterface IVECake {\n    function userInfo(address user)\n        external\n        view\n        returns (\n            address cakePoolProxy, // Proxy Smart Contract for users who had locked in cake pool.\n            uint128 cakeAmount, //  Cake amount locked in cake pool.\n            uint48 lockEndTime, // Record the lockEndTime in cake pool.\n            uint48 migrationTime, // Record the migration time.\n            uint16 cakePoolType, // 1: Migration, 2: Delegation.\n            uint16 withdrawFlag // 0: Not withdraw, 1 : withdrew.\n        );\n\n    function isCakePoolProxy(address _user) external view returns (bool);\n\n    /// @dev Return the max epoch of the given \"_user\"\n    function userPointEpoch(address _user) external view returns (uint256);\n\n    /// @dev Return the max global epoch\n    function epoch() external view returns (uint256);\n\n    /// @dev Trigger global check point\n    function checkpoint() external;\n\n    /// @notice Return the proxy balance of VECake at a given \"_blockNumber\"\n    /// @param _user The proxy owner address to get a balance of VECake\n    /// @param _blockNumber The speicific block number that you want to check the balance of VECake\n    function balanceOfAtForProxy(address _user, uint256 _blockNumber) external view returns (uint256);\n\n    /// @notice Return the balance of VECake at a given \"_blockNumber\"\n    /// @param _user The address to get a balance of VECake\n    /// @param _blockNumber The speicific block number that you want to check the balance of VECake\n    function balanceOfAt(address _user, uint256 _blockNumber) external view returns (uint256);\n\n    /// @notice Return the voting weight of a givne user's proxy\n    /// @param _user The address of a user\n    function balanceOfForProxy(address _user) external view returns (uint256);\n\n    /// @notice Return the voting weight of a givne user\n    /// @param _user The address of a user\n    function balanceOf(address _user) external view returns (uint256);\n\n    /// @notice Calculate total supply of VECake (voting power)\n    function totalSupply() external view returns (uint256);\n}\n"
      },
      "contracts/interfaces/IMasterChefV3.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ninterface IMasterChefV3 {\n    function balanceOf(address user) external view returns (uint256);\n\n    function userPositionInfos(uint256 _tokenId)\n        external\n        view\n        returns (\n            uint128,\n            uint128,\n            int24,\n            int24,\n            uint256,\n            uint256,\n            address,\n            uint256,\n            uint256\n        );\n\n    function poolInfo(uint256 _pid)\n        external\n        view\n        returns (\n            uint256,\n            address,\n            address,\n            address,\n            uint24,\n            uint256,\n            uint256\n        );\n\n    function v3PoolAddressPid(address _pool) external view returns (uint256);\n\n    function updateBoostMultiplier(uint256 _tokenId, uint256 _newMultiplier) external;\n\n    function updateLiquidity(uint256 _tokenId) external;\n\n    function nonfungiblePositionManager() external view returns (address);\n}\n"
      },
      "contracts/interfaces/IPancakeV3Pool.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IPancakeV3Pool {\n    /// @notice The currently in range liquidity available to the pool\n    /// @dev This value has no relationship to the total liquidity across all ticks\n    function liquidity() external view returns (uint128);\n}\n"
      },
      "contracts/interfaces/INonfungiblePositionManager.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ninterface INonfungiblePositionManager {\n    /// @notice Returns the position information associated with a given token ID.\n    /// @dev Throws if the token ID is not valid.\n    /// @param tokenId The ID of the token that represents the position\n    /// @return nonce The nonce for permits\n    /// @return operator The address that is approved for spending\n    /// @return token0 The address of the token0 for a specific pool\n    /// @return token1 The address of the token1 for a specific pool\n    /// @return fee The fee associated with the pool\n    /// @return tickLower The lower end of the tick range for the position\n    /// @return tickUpper The higher end of the tick range for the position\n    /// @return liquidity The liquidity of the position\n    /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position\n    /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position\n    /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation\n    /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation\n    function positions(uint256 tokenId)\n        external\n        view\n        returns (\n            uint96 nonce,\n            address operator,\n            address token0,\n            address token1,\n            uint24 fee,\n            int24 tickLower,\n            int24 tickUpper,\n            uint128 liquidity,\n            uint256 feeGrowthInside0LastX128,\n            uint256 feeGrowthInside1LastX128,\n            uint128 tokensOwed0,\n            uint128 tokensOwed1\n        );\n\n    function ownerOf(uint256 tokenId) external view returns (address);\n\n    function factory() external view returns (address);\n}\n"
      },
      "contracts/interfaces/IPancakeV3Factory.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ninterface IPancakeV3Factory {\n    function getPool(\n        address tokenA,\n        address tokenB,\n        uint24 fee\n    ) external view returns (address pool);\n}\n"
      },
      "@openzeppelin-4.5.0/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 99999
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}