编译器
0.8.10+commit.fc410830
文件 1 的 21:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 21:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 21:Enumerable.sol
pragma solidity ^0.8.10;
abstract contract Enumerable {
mapping(address => uint256) private _balances;
mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
mapping(uint256 => uint256) private _ownedTokensIndex;
function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) {
require(index < _balances[owner], "Enumerable: owner index out of bounds");
return _ownedTokens[owner][index];
}
function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0), "Enumerable: address zero is not a valid owner");
return _balances[owner];
}
function addToken(address from, uint256 tokenId) internal {
_addTokenToOwnerEnumeration(from, tokenId);
unchecked {
_balances[from] += 1;
}
}
function removeToken(address from, uint256 tokenId) internal {
_removeTokenFromOwnerEnumeration(from, tokenId);
unchecked {
_balances[from] -= 1;
}
}
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
uint256 length = _balances[to];
_ownedTokens[to][length] = tokenId;
_ownedTokensIndex[tokenId] = length;
}
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
uint256 lastTokenIndex = _balances[from] - 1;
uint256 tokenIndex = _ownedTokensIndex[tokenId];
require(tokenId == _ownedTokens[from][tokenIndex], "Invalid tokenId");
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId;
_ownedTokensIndex[lastTokenId] = tokenIndex;
}
delete _ownedTokensIndex[tokenId];
delete _ownedTokens[from][lastTokenIndex];
}
}
文件 4 的 21:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 5 的 21:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 6 的 21:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool _approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
文件 7 的 21:IFarmBooster.sol
pragma solidity ^0.8.10;
interface IFarmBooster {
function getUserMultiplier(uint256 _tokenId) external view returns (uint256);
function whiteList(uint256 _pid) external view returns (bool);
function updatePositionBoostMultiplier(uint256 _tokenId) external returns (uint256 _multiplier);
function removeBoostMultiplier(address _user, uint256 _tokenId, uint256 _pid) external;
}
文件 8 的 21:ILMPool.sol
pragma solidity ^0.8.10;
interface ILMPool {
function updatePosition(int24 tickLower, int24 tickUpper, int128 liquidityDelta) external;
function getRewardGrowthInside(
int24 tickLower,
int24 tickUpper
) external view returns (uint256 rewardGrowthInsideX128);
function accumulateReward(uint32 currTimestamp) external;
}
文件 9 的 21:ILMPoolDeployer.sol
pragma solidity ^0.8.10;
import "./IPancakeV3Pool.sol";
import "./ILMPool.sol";
interface ILMPoolDeployer {
function deploy(IPancakeV3Pool pool) external returns (ILMPool lmPool);
}
文件 10 的 21:IMasterChefV2.sol
pragma solidity ^0.8.10;
interface IMasterChefV2 {
function deposit(uint256 _pid, uint256 _amount) external;
function withdraw(uint256 _pid, uint256 _amount) external;
function pendingCake(uint256 _pid, address _user) external view returns (uint256);
function userInfo(uint256 _pid, address _user) external view returns (uint256, uint256, uint256);
function emergencyWithdraw(uint256 _pid) external;
function updateBoostMultiplier(address _user, uint256 _pid, uint256 _newBoostMulti) external;
}
文件 11 的 21:INonfungiblePositionManager.sol
pragma solidity ^0.8.10;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "./INonfungiblePositionManagerStruct.sol";
interface INonfungiblePositionManager is INonfungiblePositionManagerStruct, IERC721 {
function positions(
uint256 tokenId
)
external
view
returns (
uint96 nonce,
address operator,
address token0,
address token1,
uint24 fee,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
function increaseLiquidity(
IncreaseLiquidityParams calldata params
) external payable returns (uint128 liquidity, uint256 amount0, uint256 amount1);
function decreaseLiquidity(
DecreaseLiquidityParams calldata params
) external payable returns (uint256 amount0, uint256 amount1);
function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1);
function burn(uint256 tokenId) external payable;
function refundETH() external payable;
}
文件 12 的 21:INonfungiblePositionManagerStruct.sol
pragma solidity ^0.8.10;
interface INonfungiblePositionManagerStruct {
struct IncreaseLiquidityParams {
uint256 tokenId;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
struct DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
}
文件 13 的 21:IPancakeV3Pool.sol
pragma solidity ^0.8.10;
interface IPancakeV3Pool {
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function fee() external view returns (uint24);
function lmPool() external view returns (address);
}
文件 14 的 21:IWETH.sol
pragma solidity ^0.8.10;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}
文件 15 的 21:MasterChefV3.sol
pragma solidity ^0.8.10;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./libraries/SafeCast.sol";
import "./interfaces/INonfungiblePositionManager.sol";
import "./interfaces/INonfungiblePositionManagerStruct.sol";
import "./interfaces/IPancakeV3Pool.sol";
import "./interfaces/IMasterChefV2.sol";
import "./interfaces/ILMPool.sol";
import "./interfaces/ILMPoolDeployer.sol";
import "./interfaces/IFarmBooster.sol";
import "./interfaces/IWETH.sol";
import "./utils/Multicall.sol";
import "./Enumerable.sol";
contract MasterChefV3 is INonfungiblePositionManagerStruct, Multicall, Ownable, ReentrancyGuard, Enumerable {
using SafeERC20 for IERC20;
using SafeCast for uint256;
struct PoolInfo {
uint256 allocPoint;
IPancakeV3Pool v3Pool;
address token0;
address token1;
uint24 fee;
uint256 totalLiquidity;
uint256 totalBoostLiquidity;
}
struct UserPositionInfo {
uint128 liquidity;
uint128 boostLiquidity;
int24 tickLower;
int24 tickUpper;
uint256 rewardGrowthInside;
uint256 reward;
address user;
uint256 pid;
uint256 boostMultiplier;
}
uint256 public poolLength;
mapping(uint256 => PoolInfo) public poolInfo;
mapping(uint256 => UserPositionInfo) public userPositionInfos;
mapping(address => mapping(address => mapping(uint24 => uint256))) v3PoolPid;
mapping(address => uint256) public v3PoolAddressPid;
IERC20 public immutable CAKE;
address public immutable WETH;
address public receiver;
INonfungiblePositionManager public immutable nonfungiblePositionManager;
ILMPoolDeployer public LMPoolDeployer;
IFarmBooster public FARM_BOOSTER;
bool public emergency;
uint256 public totalAllocPoint;
uint256 public latestPeriodNumber;
uint256 public latestPeriodStartTime;
uint256 public latestPeriodEndTime;
uint256 public latestPeriodCakePerSecond;
address public operatorAddress;
uint256 public PERIOD_DURATION = 1 days;
uint256 public constant MAX_DURATION = 30 days;
uint256 public constant MIN_DURATION = 1 days;
uint256 public constant PRECISION = 1e12;
uint256 public constant BOOST_PRECISION = 100 * 1e10;
uint256 public constant MAX_BOOST_PRECISION = 200 * 1e10;
uint256 constant Q128 = 0x100000000000000000000000000000000;
uint256 constant MAX_U256 = type(uint256).max;
uint256 public cakeAmountBelongToMC;
error ZeroAddress();
error NotOwnerOrOperator();
error NoBalance();
error NotPancakeNFT();
error InvalidNFT();
error NotOwner();
error NoLiquidity();
error InvalidPeriodDuration();
error NoLMPool();
error InvalidPid();
error DuplicatedPool(uint256 pid);
error NotEmpty();
error WrongReceiver();
error InconsistentAmount();
error InsufficientAmount();
event AddPool(uint256 indexed pid, uint256 allocPoint, IPancakeV3Pool indexed v3Pool, ILMPool indexed lmPool);
event SetPool(uint256 indexed pid, uint256 allocPoint);
event Deposit(
address indexed from,
uint256 indexed pid,
uint256 indexed tokenId,
uint256 liquidity,
int24 tickLower,
int24 tickUpper
);
event Withdraw(address indexed from, address to, uint256 indexed pid, uint256 indexed tokenId);
event UpdateLiquidity(
address indexed from,
uint256 indexed pid,
uint256 indexed tokenId,
int128 liquidity,
int24 tickLower,
int24 tickUpper
);
event NewOperatorAddress(address operator);
event NewLMPoolDeployerAddress(address deployer);
event NewReceiver(address receiver);
event NewPeriodDuration(uint256 periodDuration);
event Harvest(address indexed sender, address to, uint256 indexed pid, uint256 indexed tokenId, uint256 reward);
event NewUpkeepPeriod(
uint256 indexed periodNumber,
uint256 startTime,
uint256 endTime,
uint256 cakePerSecond,
uint256 cakeAmount
);
event UpdateUpkeepPeriod(
uint256 indexed periodNumber,
uint256 oldEndTime,
uint256 newEndTime,
uint256 remainingCake
);
event UpdateFarmBoostContract(address indexed farmBoostContract);
event SetEmergency(bool emergency);
modifier onlyOwnerOrOperator() {
if (msg.sender != operatorAddress && msg.sender != owner()) revert NotOwnerOrOperator();
_;
}
modifier onlyValidPid(uint256 _pid) {
if (_pid == 0 || _pid > poolLength) revert InvalidPid();
_;
}
modifier onlyReceiver() {
require(receiver == msg.sender, "Not receiver");
_;
}
modifier onlyBoostContract() {
require(address(FARM_BOOSTER) == msg.sender, "Not farm boost contract");
_;
}
constructor(IERC20 _CAKE, INonfungiblePositionManager _nonfungiblePositionManager, address _WETH) {
CAKE = _CAKE;
nonfungiblePositionManager = _nonfungiblePositionManager;
WETH = _WETH;
}
function getLatestPeriodInfoByPid(uint256 _pid) public view returns (uint256 cakePerSecond, uint256 endTime) {
if (totalAllocPoint > 0) {
cakePerSecond = (latestPeriodCakePerSecond * poolInfo[_pid].allocPoint) / totalAllocPoint;
}
endTime = latestPeriodEndTime;
}
function getLatestPeriodInfo(address _v3Pool) public view returns (uint256 cakePerSecond, uint256 endTime) {
if (totalAllocPoint > 0) {
cakePerSecond =
(latestPeriodCakePerSecond * poolInfo[v3PoolAddressPid[_v3Pool]].allocPoint) /
totalAllocPoint;
}
endTime = latestPeriodEndTime;
}
function pendingCake(uint256 _tokenId) external view returns (uint256 reward) {
UserPositionInfo memory positionInfo = userPositionInfos[_tokenId];
if (positionInfo.pid != 0) {
PoolInfo memory pool = poolInfo[positionInfo.pid];
ILMPool LMPool = ILMPool(pool.v3Pool.lmPool());
if (address(LMPool) != address(0)) {
uint256 rewardGrowthInside = LMPool.getRewardGrowthInside(
positionInfo.tickLower,
positionInfo.tickUpper
);
if (
rewardGrowthInside > positionInfo.rewardGrowthInside &&
MAX_U256 / (rewardGrowthInside - positionInfo.rewardGrowthInside) > positionInfo.boostLiquidity
)
reward =
((rewardGrowthInside - positionInfo.rewardGrowthInside) * positionInfo.boostLiquidity) /
Q128;
}
reward += positionInfo.reward;
}
}
function setEmergency(bool _emergency) external onlyOwner {
emergency = _emergency;
emit SetEmergency(emergency);
}
function setReceiver(address _receiver) external onlyOwner {
if (_receiver == address(0)) revert ZeroAddress();
if (CAKE.allowance(_receiver, address(this)) != type(uint256).max) revert();
receiver = _receiver;
emit NewReceiver(_receiver);
}
function setLMPoolDeployer(ILMPoolDeployer _LMPoolDeployer) external onlyOwner {
if (address(_LMPoolDeployer) == address(0)) revert ZeroAddress();
LMPoolDeployer = _LMPoolDeployer;
emit NewLMPoolDeployerAddress(address(_LMPoolDeployer));
}
function add(uint256 _allocPoint, IPancakeV3Pool _v3Pool, bool _withUpdate) external onlyOwner {
if (_withUpdate) massUpdatePools();
ILMPool lmPool = LMPoolDeployer.deploy(_v3Pool);
totalAllocPoint += _allocPoint;
address token0 = _v3Pool.token0();
address token1 = _v3Pool.token1();
uint24 fee = _v3Pool.fee();
if (v3PoolPid[token0][token1][fee] != 0) revert DuplicatedPool(v3PoolPid[token0][token1][fee]);
if (IERC20(token0).allowance(address(this), address(nonfungiblePositionManager)) == 0)
IERC20(token0).safeApprove(address(nonfungiblePositionManager), type(uint256).max);
if (IERC20(token1).allowance(address(this), address(nonfungiblePositionManager)) == 0)
IERC20(token1).safeApprove(address(nonfungiblePositionManager), type(uint256).max);
unchecked {
poolLength++;
}
poolInfo[poolLength] = PoolInfo({
allocPoint: _allocPoint,
v3Pool: _v3Pool,
token0: token0,
token1: token1,
fee: fee,
totalLiquidity: 0,
totalBoostLiquidity: 0
});
v3PoolPid[token0][token1][fee] = poolLength;
v3PoolAddressPid[address(_v3Pool)] = poolLength;
emit AddPool(poolLength, _allocPoint, _v3Pool, lmPool);
}
function set(uint256 _pid, uint256 _allocPoint, bool _withUpdate) external onlyOwner onlyValidPid(_pid) {
uint32 currentTime = uint32(block.timestamp);
PoolInfo storage pool = poolInfo[_pid];
ILMPool LMPool = ILMPool(pool.v3Pool.lmPool());
if (address(LMPool) != address(0)) {
LMPool.accumulateReward(currentTime);
}
if (_withUpdate) massUpdatePools();
totalAllocPoint = totalAllocPoint - pool.allocPoint + _allocPoint;
pool.allocPoint = _allocPoint;
emit SetPool(_pid, _allocPoint);
}
struct DepositCache {
address token0;
address token1;
uint24 fee;
int24 tickLower;
int24 tickUpper;
uint128 liquidity;
}
function onERC721Received(
address,
address _from,
uint256 _tokenId,
bytes calldata
) external nonReentrant returns (bytes4) {
if (msg.sender != address(nonfungiblePositionManager)) revert NotPancakeNFT();
DepositCache memory cache;
(
,
,
cache.token0,
cache.token1,
cache.fee,
cache.tickLower,
cache.tickUpper,
cache.liquidity,
,
,
,
) = nonfungiblePositionManager.positions(_tokenId);
if (cache.liquidity == 0) revert NoLiquidity();
uint256 pid = v3PoolPid[cache.token0][cache.token1][cache.fee];
if (pid == 0) revert InvalidNFT();
PoolInfo memory pool = poolInfo[pid];
ILMPool LMPool = ILMPool(pool.v3Pool.lmPool());
if (address(LMPool) == address(0)) revert NoLMPool();
UserPositionInfo storage positionInfo = userPositionInfos[_tokenId];
positionInfo.tickLower = cache.tickLower;
positionInfo.tickUpper = cache.tickUpper;
positionInfo.user = _from;
positionInfo.pid = pid;
LMPool.accumulateReward(uint32(block.timestamp));
updateLiquidityOperation(positionInfo, _tokenId, 0);
positionInfo.rewardGrowthInside = LMPool.getRewardGrowthInside(cache.tickLower, cache.tickUpper);
addToken(_from, _tokenId);
emit Deposit(_from, pid, _tokenId, cache.liquidity, cache.tickLower, cache.tickUpper);
return this.onERC721Received.selector;
}
function harvest(uint256 _tokenId, address _to) external nonReentrant returns (uint256 reward) {
UserPositionInfo storage positionInfo = userPositionInfos[_tokenId];
if (positionInfo.user != msg.sender) revert NotOwner();
if (positionInfo.liquidity == 0 && positionInfo.reward == 0) revert NoLiquidity();
reward = harvestOperation(positionInfo, _tokenId, _to);
}
function harvestOperation(
UserPositionInfo storage positionInfo,
uint256 _tokenId,
address _to
) internal returns (uint256 reward) {
PoolInfo memory pool = poolInfo[positionInfo.pid];
ILMPool LMPool = ILMPool(pool.v3Pool.lmPool());
if (address(LMPool) != address(0) && !emergency) {
LMPool.accumulateReward(uint32(block.timestamp));
uint256 rewardGrowthInside = LMPool.getRewardGrowthInside(positionInfo.tickLower, positionInfo.tickUpper);
if (
rewardGrowthInside > positionInfo.rewardGrowthInside &&
MAX_U256 / (rewardGrowthInside - positionInfo.rewardGrowthInside) > positionInfo.boostLiquidity
) reward = ((rewardGrowthInside - positionInfo.rewardGrowthInside) * positionInfo.boostLiquidity) / Q128;
positionInfo.rewardGrowthInside = rewardGrowthInside;
}
reward += positionInfo.reward;
if (reward > 0) {
if (_to != address(0)) {
positionInfo.reward = 0;
_safeTransfer(_to, reward);
emit Harvest(msg.sender, _to, positionInfo.pid, _tokenId, reward);
} else {
positionInfo.reward = reward;
}
}
}
function withdraw(uint256 _tokenId, address _to) external nonReentrant returns (uint256 reward) {
if (_to == address(this) || _to == address(0)) revert WrongReceiver();
UserPositionInfo storage positionInfo = userPositionInfos[_tokenId];
if (positionInfo.user != msg.sender) revert NotOwner();
reward = harvestOperation(positionInfo, _tokenId, _to);
uint256 pid = positionInfo.pid;
PoolInfo storage pool = poolInfo[pid];
ILMPool LMPool = ILMPool(pool.v3Pool.lmPool());
if (address(LMPool) != address(0) && !emergency) {
int128 liquidityDelta = -int128(positionInfo.boostLiquidity);
LMPool.updatePosition(positionInfo.tickLower, positionInfo.tickUpper, liquidityDelta);
emit UpdateLiquidity(
msg.sender,
pid,
_tokenId,
liquidityDelta,
positionInfo.tickLower,
positionInfo.tickUpper
);
}
pool.totalLiquidity -= positionInfo.liquidity;
pool.totalBoostLiquidity -= positionInfo.boostLiquidity;
delete userPositionInfos[_tokenId];
removeToken(msg.sender, _tokenId);
if (address(FARM_BOOSTER) != address(0)) FARM_BOOSTER.removeBoostMultiplier(msg.sender, _tokenId, pid);
nonfungiblePositionManager.safeTransferFrom(address(this), _to, _tokenId);
emit Withdraw(msg.sender, _to, pid, _tokenId);
}
function updateLiquidity(uint256 _tokenId) external nonReentrant {
UserPositionInfo storage positionInfo = userPositionInfos[_tokenId];
if (positionInfo.pid == 0) revert InvalidNFT();
harvestOperation(positionInfo, _tokenId, address(0));
updateLiquidityOperation(positionInfo, _tokenId, 0);
}
function updateBoostMultiplier(uint256 _tokenId, uint256 _newMultiplier) external onlyBoostContract {
UserPositionInfo storage positionInfo = userPositionInfos[_tokenId];
if (positionInfo.pid == 0) revert InvalidNFT();
harvestOperation(positionInfo, _tokenId, address(0));
updateLiquidityOperation(positionInfo, _tokenId, _newMultiplier);
}
function updateLiquidityOperation(
UserPositionInfo storage positionInfo,
uint256 _tokenId,
uint256 _newMultiplier
) internal {
(, , , , , int24 tickLower, int24 tickUpper, uint128 liquidity, , , , ) = nonfungiblePositionManager.positions(
_tokenId
);
PoolInfo storage pool = poolInfo[positionInfo.pid];
if (positionInfo.liquidity != liquidity) {
pool.totalLiquidity = pool.totalLiquidity - positionInfo.liquidity + liquidity;
positionInfo.liquidity = liquidity;
}
uint256 boostMultiplier = BOOST_PRECISION;
if (address(FARM_BOOSTER) != address(0) && _newMultiplier == 0) {
boostMultiplier = FARM_BOOSTER.updatePositionBoostMultiplier(_tokenId);
} else if (_newMultiplier != 0) {
boostMultiplier = _newMultiplier;
}
if (boostMultiplier < BOOST_PRECISION) {
boostMultiplier = BOOST_PRECISION;
} else if (boostMultiplier > MAX_BOOST_PRECISION) {
boostMultiplier = MAX_BOOST_PRECISION;
}
positionInfo.boostMultiplier = boostMultiplier;
uint128 boostLiquidity = ((uint256(liquidity) * boostMultiplier) / BOOST_PRECISION).toUint128();
int128 liquidityDelta = int128(boostLiquidity) - int128(positionInfo.boostLiquidity);
if (liquidityDelta != 0) {
pool.totalBoostLiquidity = pool.totalBoostLiquidity - positionInfo.boostLiquidity + boostLiquidity;
positionInfo.boostLiquidity = boostLiquidity;
ILMPool LMPool = ILMPool(pool.v3Pool.lmPool());
if (address(LMPool) == address(0)) revert NoLMPool();
LMPool.updatePosition(tickLower, tickUpper, liquidityDelta);
emit UpdateLiquidity(msg.sender, positionInfo.pid, _tokenId, liquidityDelta, tickLower, tickUpper);
}
}
function increaseLiquidity(
IncreaseLiquidityParams memory params
) external payable nonReentrant returns (uint128 liquidity, uint256 amount0, uint256 amount1) {
UserPositionInfo storage positionInfo = userPositionInfos[params.tokenId];
if (positionInfo.pid == 0) revert InvalidNFT();
PoolInfo memory pool = poolInfo[positionInfo.pid];
pay(pool.token0, params.amount0Desired);
pay(pool.token1, params.amount1Desired);
if (pool.token0 != WETH && pool.token1 != WETH && msg.value > 0) revert();
(liquidity, amount0, amount1) = nonfungiblePositionManager.increaseLiquidity{value: msg.value}(params);
uint256 token0Left = params.amount0Desired - amount0;
uint256 token1Left = params.amount1Desired - amount1;
if (token0Left > 0) {
refund(pool.token0, token0Left);
}
if (token1Left > 0) {
refund(pool.token1, token1Left);
}
harvestOperation(positionInfo, params.tokenId, address(0));
updateLiquidityOperation(positionInfo, params.tokenId, 0);
}
function pay(address _token, uint256 _amount) internal {
if (_token == WETH && msg.value > 0) {
if (msg.value != _amount) revert InconsistentAmount();
} else {
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
}
}
function refund(address _token, uint256 _amount) internal {
if (_token == WETH && msg.value > 0) {
nonfungiblePositionManager.refundETH();
safeTransferETH(msg.sender, address(this).balance);
} else {
IERC20(_token).safeTransfer(msg.sender, _amount);
}
}
function decreaseLiquidity(
DecreaseLiquidityParams memory params
) external nonReentrant returns (uint256 amount0, uint256 amount1) {
UserPositionInfo storage positionInfo = userPositionInfos[params.tokenId];
if (positionInfo.user != msg.sender) revert NotOwner();
(amount0, amount1) = nonfungiblePositionManager.decreaseLiquidity(params);
harvestOperation(positionInfo, params.tokenId, address(0));
updateLiquidityOperation(positionInfo, params.tokenId, 0);
}
function collect(CollectParams memory params) external nonReentrant returns (uint256 amount0, uint256 amount1) {
UserPositionInfo memory positionInfo = userPositionInfos[params.tokenId];
if (positionInfo.user != msg.sender) revert NotOwner();
if (params.recipient == address(0)) params.recipient = address(this);
(amount0, amount1) = nonfungiblePositionManager.collect(params);
}
function collectTo(
CollectParams memory params,
address to
) external nonReentrant returns (uint256 amount0, uint256 amount1) {
UserPositionInfo memory positionInfo = userPositionInfos[params.tokenId];
if (positionInfo.user != msg.sender) revert NotOwner();
if (params.recipient == address(0)) params.recipient = address(this);
(amount0, amount1) = nonfungiblePositionManager.collect(params);
if (params.recipient == address(this)) {
PoolInfo memory pool = poolInfo[positionInfo.pid];
if (to == address(0)) to = msg.sender;
transferToken(pool.token0, to);
transferToken(pool.token1, to);
}
}
function transferToken(address _token, address _to) internal {
uint256 balance = IERC20(_token).balanceOf(address(this));
if (_token == address(CAKE)) {
unchecked {
if (balance >= cakeAmountBelongToMC) {
balance -= cakeAmountBelongToMC;
} else {
cakeAmountBelongToMC = balance;
balance = 0;
}
}
}
if (balance > 0) {
if (_token == WETH) {
IWETH(WETH).withdraw(balance);
safeTransferETH(_to, balance);
} else {
IERC20(_token).safeTransfer(_to, balance);
}
}
}
function unwrapWETH9(uint256 amountMinimum, address recipient) external nonReentrant {
uint256 balanceWETH = IWETH(WETH).balanceOf(address(this));
if (balanceWETH < amountMinimum) revert InsufficientAmount();
if (balanceWETH > 0) {
IWETH(WETH).withdraw(balanceWETH);
safeTransferETH(recipient, balanceWETH);
}
}
function sweepToken(address token, uint256 amountMinimum, address recipient) external nonReentrant {
uint256 balanceToken = IERC20(token).balanceOf(address(this));
if (token == address(CAKE)) {
unchecked {
if (balanceToken >= cakeAmountBelongToMC) {
balanceToken -= cakeAmountBelongToMC;
} else {
cakeAmountBelongToMC = balanceToken;
balanceToken = 0;
}
}
}
if (balanceToken < amountMinimum) revert InsufficientAmount();
if (balanceToken > 0) {
IERC20(token).safeTransfer(recipient, balanceToken);
}
}
function burn(uint256 _tokenId) external nonReentrant {
UserPositionInfo memory positionInfo = userPositionInfos[_tokenId];
if (positionInfo.user != msg.sender) revert NotOwner();
if (positionInfo.reward > 0 || positionInfo.liquidity > 0) revert NotEmpty();
delete userPositionInfos[_tokenId];
removeToken(msg.sender, _tokenId);
if (address(FARM_BOOSTER) != address(0))
FARM_BOOSTER.removeBoostMultiplier(msg.sender, _tokenId, positionInfo.pid);
nonfungiblePositionManager.burn(_tokenId);
emit Withdraw(msg.sender, address(0), positionInfo.pid, _tokenId);
}
function upkeep(uint256 _amount, uint256 _duration, bool _withUpdate) external onlyReceiver {
CAKE.safeTransferFrom(receiver, address(this), _amount);
unchecked {
cakeAmountBelongToMC += _amount;
}
if (_withUpdate) massUpdatePools();
uint256 duration = PERIOD_DURATION;
if (_duration >= MIN_DURATION && _duration <= MAX_DURATION) duration = _duration;
uint256 currentTime = block.timestamp;
uint256 endTime = currentTime + duration;
uint256 cakePerSecond;
uint256 cakeAmount = _amount;
if (latestPeriodEndTime > currentTime) {
uint256 remainingCake = ((latestPeriodEndTime - currentTime) * latestPeriodCakePerSecond) / PRECISION;
emit UpdateUpkeepPeriod(latestPeriodNumber, latestPeriodEndTime, currentTime, remainingCake);
cakeAmount += remainingCake;
}
cakePerSecond = (cakeAmount * PRECISION) / duration;
unchecked {
latestPeriodNumber++;
latestPeriodStartTime = currentTime + 1;
latestPeriodEndTime = endTime;
latestPeriodCakePerSecond = cakePerSecond;
}
emit NewUpkeepPeriod(latestPeriodNumber, currentTime + 1, endTime, cakePerSecond, cakeAmount);
}
function massUpdatePools() internal {
uint32 currentTime = uint32(block.timestamp);
for (uint256 pid = 1; pid <= poolLength; pid++) {
PoolInfo memory pool = poolInfo[pid];
ILMPool LMPool = ILMPool(pool.v3Pool.lmPool());
if (pool.allocPoint != 0 && address(LMPool) != address(0)) {
LMPool.accumulateReward(currentTime);
}
}
}
function updatePools(uint256[] calldata pids) external onlyOwnerOrOperator {
uint32 currentTime = uint32(block.timestamp);
for (uint256 i = 0; i < pids.length; i++) {
PoolInfo memory pool = poolInfo[pids[i]];
ILMPool LMPool = ILMPool(pool.v3Pool.lmPool());
if (pool.allocPoint != 0 && address(LMPool) != address(0)) {
LMPool.accumulateReward(currentTime);
}
}
}
function setOperator(address _operatorAddress) external onlyOwner {
if (_operatorAddress == address(0)) revert ZeroAddress();
operatorAddress = _operatorAddress;
emit NewOperatorAddress(_operatorAddress);
}
function setPeriodDuration(uint256 _periodDuration) external onlyOwner {
if (_periodDuration < MIN_DURATION || _periodDuration > MAX_DURATION) revert InvalidPeriodDuration();
PERIOD_DURATION = _periodDuration;
emit NewPeriodDuration(_periodDuration);
}
function updateFarmBoostContract(address _newFarmBoostContract) external onlyOwner {
FARM_BOOSTER = IFarmBooster(_newFarmBoostContract);
emit UpdateFarmBoostContract(_newFarmBoostContract);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}("");
if (!success) revert();
}
function _safeTransfer(address _to, uint256 _amount) internal {
if (_amount > 0) {
uint256 balance = CAKE.balanceOf(address(this));
if (balance < _amount) {
_amount = balance;
}
unchecked {
if (cakeAmountBelongToMC >= _amount) {
cakeAmountBelongToMC -= _amount;
} else {
cakeAmountBelongToMC = balance - _amount;
}
}
CAKE.safeTransfer(_to, _amount);
}
}
receive() external payable {
if (msg.sender != address(nonfungiblePositionManager) && msg.sender != WETH) revert();
}
}
文件 16 的 21:Multicall.sol
pragma solidity ^0.8.10;
contract Multicall {
function multicall(bytes[] calldata data) public payable returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
(bool success, bytes memory result) = address(this).delegatecall(data[i]);
if (!success) {
if (result.length < 68) revert();
assembly {
result := add(result, 0x04)
}
revert(abi.decode(result, (string)));
}
results[i] = result;
}
}
}
文件 17 的 21:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 18 的 21:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
}
文件 19 的 21:SafeCast.sol
pragma solidity ^0.8.10;
library SafeCast {
function toUint128(uint256 value) internal pure returns (uint128) {
require(value < 2 ** 128, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
}
文件 20 的 21:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 21 的 21:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
{
"compilationTarget": {
"contracts/MasterChefV3.sol": "MasterChefV3"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 999
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IERC20","name":"_CAKE","type":"address"},{"internalType":"contract INonfungiblePositionManager","name":"_nonfungiblePositionManager","type":"address"},{"internalType":"address","name":"_WETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"}],"name":"DuplicatedPool","type":"error"},{"inputs":[],"name":"InconsistentAmount","type":"error"},{"inputs":[],"name":"InsufficientAmount","type":"error"},{"inputs":[],"name":"InvalidNFT","type":"error"},{"inputs":[],"name":"InvalidPeriodDuration","type":"error"},{"inputs":[],"name":"InvalidPid","type":"error"},{"inputs":[],"name":"NoBalance","type":"error"},{"inputs":[],"name":"NoLMPool","type":"error"},{"inputs":[],"name":"NoLiquidity","type":"error"},{"inputs":[],"name":"NotEmpty","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotOwnerOrOperator","type":"error"},{"inputs":[],"name":"NotPancakeNFT","type":"error"},{"inputs":[],"name":"WrongReceiver","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocPoint","type":"uint256"},{"indexed":true,"internalType":"contract IPancakeV3Pool","name":"v3Pool","type":"address"},{"indexed":true,"internalType":"contract ILMPool","name":"lmPool","type":"address"}],"name":"AddPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"},{"indexed":false,"internalType":"int24","name":"tickLower","type":"int24"},{"indexed":false,"internalType":"int24","name":"tickUpper","type":"int24"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"deployer","type":"address"}],"name":"NewLMPoolDeployerAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"NewOperatorAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"periodDuration","type":"uint256"}],"name":"NewPeriodDuration","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"}],"name":"NewReceiver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"periodNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cakePerSecond","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cakeAmount","type":"uint256"}],"name":"NewUpkeepPeriod","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"emergency","type":"bool"}],"name":"SetEmergency","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocPoint","type":"uint256"}],"name":"SetPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"farmBoostContract","type":"address"}],"name":"UpdateFarmBoostContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"int128","name":"liquidity","type":"int128"},{"indexed":false,"internalType":"int24","name":"tickLower","type":"int24"},{"indexed":false,"internalType":"int24","name":"tickUpper","type":"int24"}],"name":"UpdateLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"periodNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldEndTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newEndTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingCake","type":"uint256"}],"name":"UpdateUpkeepPeriod","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"BOOST_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CAKE","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FARM_BOOSTER","outputs":[{"internalType":"contract IFarmBooster","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LMPoolDeployer","outputs":[{"internalType":"contract ILMPoolDeployer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BOOST_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERIOD_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"contract IPancakeV3Pool","name":"_v3Pool","type":"address"},{"internalType":"bool","name":"_withUpdate","type":"bool"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cakeAmountBelongToMC","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"}],"internalType":"struct INonfungiblePositionManagerStruct.CollectParams","name":"params","type":"tuple"}],"name":"collect","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"}],"internalType":"struct INonfungiblePositionManagerStruct.CollectParams","name":"params","type":"tuple"},{"internalType":"address","name":"to","type":"address"}],"name":"collectTo","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct INonfungiblePositionManagerStruct.DecreaseLiquidityParams","name":"params","type":"tuple"}],"name":"decreaseLiquidity","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergency","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_v3Pool","type":"address"}],"name":"getLatestPeriodInfo","outputs":[{"internalType":"uint256","name":"cakePerSecond","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"getLatestPeriodInfoByPid","outputs":[{"internalType":"uint256","name":"cakePerSecond","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"harvest","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount0Desired","type":"uint256"},{"internalType":"uint256","name":"amount1Desired","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct INonfungiblePositionManagerStruct.IncreaseLiquidityParams","name":"params","type":"tuple"}],"name":"increaseLiquidity","outputs":[{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"latestPeriodCakePerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestPeriodEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestPeriodNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestPeriodStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"nonfungiblePositionManager","outputs":[{"internalType":"contract INonfungiblePositionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"operatorAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"pendingCake","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolInfo","outputs":[{"internalType":"uint256","name":"allocPoint","type":"uint256"},{"internalType":"contract IPancakeV3Pool","name":"v3Pool","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"uint256","name":"totalLiquidity","type":"uint256"},{"internalType":"uint256","name":"totalBoostLiquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"receiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"bool","name":"_withUpdate","type":"bool"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_emergency","type":"bool"}],"name":"setEmergency","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ILMPoolDeployer","name":"_LMPoolDeployer","type":"address"}],"name":"setLMPoolDeployer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operatorAddress","type":"address"}],"name":"setOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_periodDuration","type":"uint256"}],"name":"setPeriodDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"}],"name":"setReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAllocPoint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_newMultiplier","type":"uint256"}],"name":"updateBoostMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newFarmBoostContract","type":"address"}],"name":"updateFarmBoostContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"updateLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"pids","type":"uint256[]"}],"name":"updatePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_duration","type":"uint256"},{"internalType":"bool","name":"_withUpdate","type":"bool"}],"name":"upkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"userPositionInfos","outputs":[{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint128","name":"boostLiquidity","type":"uint128"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"rewardGrowthInside","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"boostMultiplier","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"v3PoolAddressPid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]