编译器
0.8.10+commit.fc410830
文件 1 的 16: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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(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) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 16:ArrayUtils.sol
pragma solidity ^0.8.0;
library ArrayUtils {
function hasDuplicate(uint256[] memory self) external pure returns(bool) {
uint256 ivalue;
uint256 jvalue;
for(uint256 i = 0; i < self.length - 1; i ++){
ivalue = self[i];
for(uint256 j = i + 1; j < self.length; j ++){
jvalue = self[j];
if(ivalue == jvalue){
return true;
}
}
}
return false;
}
}
文件 3 的 16: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;
}
}
文件 4 的 16:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 5 的 16: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 的 16:IERC2981.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
interface IERC2981 is IERC165 {
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
returns (address receiver, uint256 royaltyAmount);
}
文件 7 的 16:IERC721.sol
pragma solidity ^0.8.0;
import "./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);
}
文件 8 的 16:IERC721Enumerable.sol
pragma solidity ^0.8.0;
import "./IERC721.sol";
interface IERC721Enumerable is IERC721 {
function totalSupply() external view returns (uint256);
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
function tokenByIndex(uint256 index) external view returns (uint256);
}
文件 9 的 16:IERC721Metadata.sol
pragma solidity ^0.8.0;
import "./IERC721.sol";
interface IERC721Metadata is IERC721 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
文件 10 的 16:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 11 的 16:NFTMasterChef.sol
pragma solidity ^0.8.0;
import "./Ownable.sol";
import "./ReentrancyGuard.sol";
import "./SafeMath.sol";
import "./IERC721Metadata.sol";
import "./IERC20.sol";
import "./SafeERC20.sol";
import "./IERC2981.sol";
import "./wnft_interfaces.sol";
import "./ArrayUtils.sol";
interface IHarvestStrategy {
function canHarvest(uint256 _pid, address _forUser, uint256[] memory _wnfTokenIds) external view returns (bool);
}
interface INFTMasterChef {
event AddPoolInfo(IERC721Metadata nft, IWrappedNFT wnft, uint256 startBlock,
RewardInfo[] rewards, uint256 depositFee, IERC20 dividendToken, bool withUpdate);
event SetStartBlock(uint256 pid, uint256 startBlock);
event UpdatePoolReward(uint256 pid, uint256 rewardIndex, uint256 rewardBlock, uint256 rewardForEachBlock, uint256 rewardPerNFTForEachBlock);
event SetPoolDepositFee(uint256 pid, uint256 depositFee);
event SetHarvestStrategy(IHarvestStrategy harvestStrategy);
event SetPoolDividendToken(uint256 pid, IERC20 dividendToken);
event AddTokenRewardForPool(uint256 pid, uint256 addTokenPerPool, uint256 addTokenPerBlock, bool withTokenTransfer);
event AddDividendForPool(uint256 pid, uint256 addDividend);
event UpdateDevAddress(address payable devAddress);
event EmergencyStop(address user, address to);
event ClosePool(uint256 pid, address payable to);
event Deposit(address indexed user, uint256 indexed pid, uint256[] tokenIds);
event Withdraw(address indexed user, uint256 indexed pid, uint256[] wnfTokenIds);
event WithdrawWithoutHarvest(address indexed user, uint256 indexed pid, uint256[] wnfTokenIds);
event Harvest(address indexed user, uint256 indexed pid, uint256[] wnftTokenIds,
uint256 mining, uint256 dividend);
struct NFTInfo {
bool deposited;
uint256 rewardDebt;
uint256 dividendDebt;
}
struct RewardInfo {
uint256 rewardBlock;
uint256 rewardForEachBlock;
uint256 rewardPerNFTForEachBlock;
}
struct PoolInfo {
IWrappedNFT wnft;
uint256 startBlock;
uint256 currentRewardIndex;
uint256 currentRewardEndBlock;
uint256 amount;
uint256 lastRewardBlock;
uint256 accTokenPerShare;
IERC20 dividendToken;
uint256 accDividendPerShare;
uint256 depositFee;
}
function poolLength() external view returns (uint256);
function poolRewardLength(uint256 _pid) external view returns (uint256);
function poolInfos(uint256 _pid) external view returns (IWrappedNFT _wnft,
uint256 _startBlock, uint256 _currentRewardIndex, uint256 _currentRewardEndBlock, uint256 _amount, uint256 _lastRewardBlock,
uint256 _accTokenPerShare, IERC20 _dividendToken, uint256 _accDividendPerShare, uint256 _depositFee);
function poolsRewardInfos(uint256 _pid, uint256 _rewardInfoId) external view returns (uint256 _rewardBlock, uint256 _rewardForEachBlock, uint256 _rewardPerNFTForEachBlock);
function poolNFTInfos(uint256 _pid, uint256 _nftTokenId) external view returns (bool _deposited, uint256 _rewardDebt, uint256 _dividendDebt);
function getPoolCurrentReward(uint256 _pid) external view returns (RewardInfo memory _rewardInfo, uint256 _currentRewardIndex);
function getPoolEndBlock(uint256 _pid) external view returns (uint256 _poolEndBlock);
function isPoolEnd(uint256 _pid) external view returns (bool);
function pending(uint256 _pid, uint256[] memory _wnftTokenIds) external view returns (uint256 _mining, uint256 _dividend);
function deposit(uint256 _pid, uint256[] memory _tokenIds) external payable;
function withdraw(uint256 _pid, uint256[] memory _wnftTokenIds) external;
function withdrawWithoutHarvest(uint256 _pid, uint256[] memory _wnftTokenIds) external;
function harvest(uint256 _pid, address _forUser, uint256[] memory _wnftTokenIds) external returns (uint256 _mining, uint256 _dividend);
}
contract NFTMasterChef is INFTMasterChef, Ownable, ReentrancyGuard {
using SafeMath for uint256;
using SafeERC20 for IERC20;
using ArrayUtils for uint256[];
uint256 private constant ACC_TOKEN_PRECISION = 1e12;
IWrappedNFTFactory public immutable wnftFactory;
IERC20 public immutable token;
IHarvestStrategy public harvestStrategy;
address payable public devAddress;
PoolInfo[] public poolInfos;
RewardInfo[][] public poolsRewardInfos;
mapping (uint256 => NFTInfo)[] public poolNFTInfos;
modifier validatePoolByPid(uint256 _pid) {
require(_pid < poolInfos.length, "NFTMasterChef: Pool does not exist");
_;
}
constructor(
IWrappedNFTFactory _wnftFactory,
IERC20 _token,
address payable _devAddress
) {
require(address(_wnftFactory) != address(0) && address(_token) != address(0)
&& address(_devAddress) != address(0), "NFTMasterChef: invalid parameters!");
wnftFactory = _wnftFactory;
token = _token;
devAddress = _devAddress;
}
function poolLength() external view returns (uint256) {
return poolInfos.length;
}
function poolRewardLength(uint256 _pid) external view validatePoolByPid(_pid) returns (uint256) {
return poolsRewardInfos[_pid].length;
}
function addPoolInfo(IERC721Metadata _nft, uint256 _startBlock, RewardInfo[] memory _rewards,
uint256 _depositFee, IERC20 _dividendToken, bool _withUpdate) external onlyOwner nonReentrant {
require(address(_nft) != address(0), "NFTMasterChef: wrong _nft or _dividendToken!");
require(_rewards.length > 0, "NFTMasterChef: _rewards must be set!");
uint256 rewardForEachBlock = _rewards[0].rewardForEachBlock;
uint256 rewardPerNFTForEachBlock = _rewards[0].rewardPerNFTForEachBlock;
require((address(_dividendToken) != address(0) && (rewardForEachBlock == 0 && rewardPerNFTForEachBlock == 0)) ||
((rewardForEachBlock == 0 && rewardPerNFTForEachBlock > 0) || (rewardForEachBlock > 0 && rewardPerNFTForEachBlock == 0)),
"NFTMasterChef: rewardForEachBlock or rewardPerNFTForEachBlock must be greater than zero!");
IWrappedNFT wnft = wnftFactory.wnfts(_nft);
require(address(wnft) != address(0) && wnft.nft() == _nft && wnft.factory() == wnftFactory && wnft.delegator() == address(this), "NFTMasterChef: wrong wnft!");
if (_withUpdate) {
massUpdatePools();
}
PoolInfo storage pool = poolInfos.push();
pool.wnft = wnft;
pool.amount = 0;
pool.startBlock = block.number > _startBlock ? block.number : _startBlock;
pool.lastRewardBlock = pool.startBlock;
pool.accTokenPerShare = 0;
pool.depositFee = _depositFee;
pool.dividendToken = _dividendToken;
pool.accDividendPerShare = 0;
RewardInfo[] storage rewards = poolsRewardInfos.push();
_setPoolRewards(poolInfos.length - 1, _rewards);
pool.currentRewardEndBlock = pool.startBlock + rewards[0].rewardBlock;
poolNFTInfos.push();
emit AddPoolInfo(_nft, wnft, _startBlock, _rewards, _depositFee, _dividendToken, _withUpdate);
}
function _setPoolRewards(uint256 _pid, RewardInfo[] memory _rewards) internal {
RewardInfo[] storage rewards = poolsRewardInfos[_pid];
bool rewardForEachBlockSet;
if(_rewards.length > 0){
rewardForEachBlockSet = _rewards[0].rewardForEachBlock > 0;
}
for (uint256 i = 0; i < _rewards.length; i++) {
RewardInfo memory reward = _rewards[i];
require(reward.rewardBlock > 0, "NFTMasterChef: rewardBlock error!");
require(!(reward.rewardForEachBlock > 0 && reward.rewardPerNFTForEachBlock > 0), "NFTMasterChef: reward can only set one!");
require((rewardForEachBlockSet && reward.rewardForEachBlock > 0) || (!rewardForEachBlockSet && reward.rewardPerNFTForEachBlock > 0)
|| (reward.rewardForEachBlock == 0 && reward.rewardPerNFTForEachBlock == 0), "NFTMasterChef: setting error!");
rewards.push(RewardInfo({
rewardBlock: reward.rewardBlock,
rewardForEachBlock: reward.rewardForEachBlock,
rewardPerNFTForEachBlock: reward.rewardPerNFTForEachBlock
}));
}
}
function updatePoolReward(uint256 _pid, uint256 _rewardIndex, uint256 _rewardBlock, uint256 _rewardForEachBlock, uint256 _rewardPerNFTForEachBlock)
external validatePoolByPid(_pid) onlyOwner nonReentrant {
PoolInfo storage pool = poolInfos[_pid];
require(!isPoolEnd(_pid), "NFTMasterChef: pool is end!");
require(_rewardBlock > 0, "NFTMasterChef: rewardBlock error!");
require(_rewardIndex < poolsRewardInfos[_pid].length, "NFTMasterChef: _rewardIndex not exists!");
(, uint256 _currentRewardIndex) = getPoolCurrentReward(_pid);
require(_rewardIndex >= _currentRewardIndex, "NFTMasterChef: _rewardIndex error!");
RewardInfo storage reward = poolsRewardInfos[_pid][_rewardIndex];
require(_rewardBlock >= reward.rewardBlock, "NFTMasterChef: _rewardBlock error!");
require(!(_rewardForEachBlock > 0 && _rewardPerNFTForEachBlock > 0), "NFTMasterChef: reward can only set one!");
require((reward.rewardForEachBlock > 0 && _rewardForEachBlock > 0) || (reward.rewardPerNFTForEachBlock > 0 && _rewardPerNFTForEachBlock > 0)
|| (_rewardForEachBlock == 0 && _rewardPerNFTForEachBlock == 0), "NFTMasterChef: invalid parameters!");
updatePool(_pid);
if(_rewardIndex == _currentRewardIndex){
pool.currentRewardEndBlock = pool.currentRewardEndBlock + _rewardBlock - reward.rewardBlock;
}
reward.rewardBlock = _rewardBlock;
reward.rewardForEachBlock = _rewardForEachBlock;
reward.rewardPerNFTForEachBlock = _rewardPerNFTForEachBlock;
emit UpdatePoolReward(_pid, _rewardIndex, _rewardBlock, _rewardForEachBlock, _rewardPerNFTForEachBlock);
}
function setStartBlock(uint256 _pid, uint256 _startBlock) external validatePoolByPid(_pid) onlyOwner nonReentrant {
PoolInfo storage pool = poolInfos[_pid];
require(block.number < pool.startBlock, "NFTMasterChef: can not change start block of started pool!");
require(block.number < _startBlock, "NFTMasterChef: _startBlock must be less than block.number!");
pool.startBlock = _startBlock;
emit SetStartBlock(_pid, _startBlock);
}
function isPoolEnd(uint256 _pid) public view returns (bool) {
uint256 poolEndBlock = getPoolEndBlock(_pid);
return block.number > poolEndBlock;
}
function getPoolEndBlock(uint256 _pid) public view returns (uint256 _poolEndBlock) {
PoolInfo storage pool = poolInfos[_pid];
_poolEndBlock = pool.currentRewardEndBlock;
RewardInfo[] storage rewards = poolsRewardInfos[_pid];
for(uint256 index = pool.currentRewardIndex + 1; index < rewards.length; index ++){
_poolEndBlock = _poolEndBlock.add(rewards[index].rewardBlock);
}
}
function getPoolCurrentReward(uint256 _pid) public view returns (RewardInfo memory _rewardInfo, uint256 _currentRewardIndex){
PoolInfo storage pool = poolInfos[_pid];
_currentRewardIndex = pool.currentRewardIndex;
uint256 poolCurrentRewardEndBlock = pool.currentRewardEndBlock;
uint256 poolRewardNumber = poolsRewardInfos[_pid].length;
_rewardInfo = poolsRewardInfos[_pid][_currentRewardIndex];
while ((block.number > poolCurrentRewardEndBlock) && (_currentRewardIndex < (poolRewardNumber - 1))) {
_currentRewardIndex ++;
_rewardInfo = poolsRewardInfos[_pid][_currentRewardIndex];
poolCurrentRewardEndBlock = poolCurrentRewardEndBlock.add(_rewardInfo.rewardBlock);
}
}
function setPoolDividendToken(uint256 _pid, IERC20 _dividendToken) external validatePoolByPid(_pid) onlyOwner nonReentrant {
PoolInfo storage pool = poolInfos[_pid];
require(!isPoolEnd(_pid), "NFTMasterChef: pool is end!");
require(address(pool.dividendToken) == address(0) || pool.accDividendPerShare == 0, "NFTMasterChef: dividendToken can not be modified!");
pool.dividendToken = _dividendToken;
emit SetPoolDividendToken(_pid, _dividendToken);
}
function setPoolDepositFee(uint256 _pid, uint256 _depositFee) public validatePoolByPid(_pid) onlyOwner nonReentrant {
PoolInfo storage pool = poolInfos[_pid];
require(!isPoolEnd(_pid), "NFTMasterChef: pool is end!");
pool.depositFee = _depositFee;
emit SetPoolDepositFee(_pid, _depositFee);
}
function setHarvestStrategy(IHarvestStrategy _harvestStrategy) external onlyOwner nonReentrant {
harvestStrategy = _harvestStrategy;
emit SetHarvestStrategy(_harvestStrategy);
}
function getMultiplier(uint256 _from, uint256 _to) public pure returns (uint256) {
if(_to > _from){
return _to.sub(_from);
}
return 0;
}
function _getMultiplier(uint256 _lastRewardBlock, uint256 _currentRewardEndBlock) internal view returns (uint256 _multiplier) {
if(block.number < _lastRewardBlock){
return 0;
}else if (block.number > _currentRewardEndBlock){
_multiplier = getMultiplier(_lastRewardBlock, _currentRewardEndBlock);
}else{
_multiplier = getMultiplier(_lastRewardBlock, block.number);
}
}
function updatePool(uint256 _pid) public validatePoolByPid(_pid) {
PoolInfo storage pool = poolInfos[_pid];
if (block.number <= pool.lastRewardBlock){
return;
}
if (block.number < pool.startBlock){
return;
}
if (pool.lastRewardBlock >= getPoolEndBlock(_pid)){
return;
}
RewardInfo[] storage rewards = poolsRewardInfos[_pid];
if(rewards.length == 0 || pool.currentRewardIndex > (rewards.length - 1)){
return;
}
RewardInfo storage reward = rewards[pool.currentRewardIndex];
if(reward.rewardForEachBlock == 0 && reward.rewardPerNFTForEachBlock == 0){
return;
}
if (pool.lastRewardBlock < pool.startBlock) {
pool.lastRewardBlock = pool.startBlock;
}
if (pool.amount == 0) {
pool.lastRewardBlock = block.number;
while ((pool.lastRewardBlock > pool.currentRewardEndBlock) && (pool.currentRewardIndex < (poolsRewardInfos[_pid].length - 1))) {
pool.currentRewardIndex ++;
pool.currentRewardEndBlock = pool.currentRewardEndBlock.add(reward.rewardBlock);
}
return;
}
uint256 multiplier = _getMultiplier(pool.lastRewardBlock, pool.currentRewardEndBlock);
uint256 rewardForEachBlock = reward.rewardForEachBlock;
if(rewardForEachBlock == 0){
rewardForEachBlock = pool.amount.mul(reward.rewardPerNFTForEachBlock);
}
uint256 poolReward = multiplier.mul(rewardForEachBlock);
uint256 poolRewardNumber = poolsRewardInfos[_pid].length;
while ((block.number > pool.currentRewardEndBlock) && (pool.currentRewardIndex < (poolRewardNumber - 1))) {
pool.currentRewardIndex ++;
uint256 previousEndBlock = pool.currentRewardEndBlock;
reward = poolsRewardInfos[_pid][pool.currentRewardIndex];
pool.currentRewardEndBlock = pool.currentRewardEndBlock.add(reward.rewardBlock);
uint256 newMultiplier = _getMultiplier(previousEndBlock, pool.currentRewardEndBlock);
rewardForEachBlock = reward.rewardForEachBlock;
if(rewardForEachBlock == 0){
rewardForEachBlock = pool.amount.mul(reward.rewardPerNFTForEachBlock);
}
poolReward = poolReward.add(newMultiplier.mul(rewardForEachBlock));
}
if (block.number > pool.currentRewardEndBlock){
pool.lastRewardBlock = pool.currentRewardEndBlock;
}else{
pool.lastRewardBlock = block.number;
}
pool.accTokenPerShare = pool.accTokenPerShare.add(poolReward.mul(ACC_TOKEN_PRECISION).div(pool.amount));
}
function pending(uint256 _pid, uint256[] memory _wnftTokenIds) public view validatePoolByPid(_pid) returns (uint256 _mining, uint256 _dividend) {
_requireTokenIds(_wnftTokenIds);
PoolInfo storage pool = poolInfos[_pid];
mapping(uint256 => NFTInfo) storage nfts = poolNFTInfos[_pid];
RewardInfo[] storage rewards = poolsRewardInfos[_pid];
RewardInfo storage reward = rewards[pool.currentRewardIndex];
uint256 accTokenPerShare = pool.accTokenPerShare;
uint256 rewardForEachBlock = reward.rewardForEachBlock;
if(rewardForEachBlock == 0){
rewardForEachBlock = pool.amount.mul(reward.rewardPerNFTForEachBlock);
}
if(rewardForEachBlock > 0){
uint256 lastRewardBlock = pool.lastRewardBlock;
if (lastRewardBlock < pool.startBlock) {
lastRewardBlock = pool.startBlock;
}
if (block.number > lastRewardBlock && block.number >= pool.startBlock && pool.amount > 0){
uint256 multiplier = _getMultiplier(lastRewardBlock, pool.currentRewardEndBlock);
uint256 poolReward = multiplier.mul(rewardForEachBlock);
uint256 poolRewardNumber = poolsRewardInfos[_pid].length;
uint256 poolCurrentRewardIndex = pool.currentRewardIndex;
uint256 poolEndBlock = pool.currentRewardEndBlock;
while ((block.number > poolEndBlock) && (poolCurrentRewardIndex < (poolRewardNumber - 1))) {
poolCurrentRewardIndex ++;
uint256 previousEndBlock = poolEndBlock;
reward = rewards[poolCurrentRewardIndex];
poolEndBlock = poolEndBlock.add(reward.rewardBlock);
uint256 newMultiplier = getMultiplier(previousEndBlock, poolEndBlock);
rewardForEachBlock = reward.rewardForEachBlock;
if(rewardForEachBlock == 0){
rewardForEachBlock = pool.amount.mul(reward.rewardPerNFTForEachBlock);
}
poolReward = poolReward.add(newMultiplier.mul(rewardForEachBlock));
}
accTokenPerShare = accTokenPerShare.add(poolReward.mul(ACC_TOKEN_PRECISION).div(pool.amount));
}
}
uint256 temp;
NFTInfo storage nft;
for(uint256 i = 0; i < _wnftTokenIds.length; i ++){
uint256 wnftTokenId = _wnftTokenIds[i];
nft = nfts[wnftTokenId];
if(nft.deposited == true){
temp = accTokenPerShare.div(ACC_TOKEN_PRECISION);
_mining = _mining.add(temp.sub(nft.rewardDebt));
if(pool.accDividendPerShare > 0 && address(pool.dividendToken) != address(0)){
_dividend = _dividend.add(pool.accDividendPerShare.div(ACC_TOKEN_PRECISION).sub(nft.dividendDebt));
}
}
}
}
function massUpdatePools() public {
uint256 length = poolInfos.length;
for (uint256 pid = 0; pid < length; ++pid) {
updatePool(pid);
}
}
function deposit(uint256 _pid, uint256[] memory _tokenIds) external validatePoolByPid(_pid) payable nonReentrant {
_requireTokenIds(_tokenIds);
updatePool(_pid);
PoolInfo storage pool = poolInfos[_pid];
require(block.number >= pool.startBlock, "NFTMasterChef: pool is not start!");
require(!isPoolEnd(_pid), "NFTMasterChef: pool is end!");
if(pool.depositFee > 0){
require(msg.value == pool.depositFee, "NFTMasterChef: Fee is not enough or too much!");
devAddress.transfer(pool.depositFee);
}
mapping(uint256 => NFTInfo) storage nfts = poolNFTInfos[_pid];
uint256 tokenId;
NFTInfo storage nft;
uint256 depositNumber;
for(uint256 i = 0; i < _tokenIds.length; i ++){
tokenId = _tokenIds[i];
require(pool.wnft.nft().ownerOf(tokenId) == msg.sender, "NFTMasterChef: can not deposit nft not owned!");
nft = nfts[tokenId];
if(nft.deposited == false){
depositNumber ++;
nft.deposited = true;
}
nft.rewardDebt = pool.accTokenPerShare.div(ACC_TOKEN_PRECISION);
nft.dividendDebt = pool.accDividendPerShare.div(ACC_TOKEN_PRECISION);
}
pool.wnft.deposit(msg.sender, _tokenIds);
pool.amount = pool.amount.add(depositNumber);
emit Deposit(msg.sender, _pid, _tokenIds);
}
function withdraw(uint256 _pid, uint256[] memory _wnftTokenIds) external validatePoolByPid(_pid) nonReentrant {
_harvest(_pid, msg.sender, _wnftTokenIds);
_withdrawWithoutHarvest(_pid, _wnftTokenIds);
emit Withdraw(msg.sender, _pid, _wnftTokenIds);
}
function _withdrawWithoutHarvest(uint256 _pid, uint256[] memory _wnftTokenIds) internal validatePoolByPid(_pid) {
_requireTokenIds(_wnftTokenIds);
PoolInfo storage pool = poolInfos[_pid];
mapping(uint256 => NFTInfo) storage nfts = poolNFTInfos[_pid];
uint256 wnftTokenId;
NFTInfo storage nft;
uint256 withdrawNumber;
for(uint256 i = 0; i < _wnftTokenIds.length; i ++){
wnftTokenId = _wnftTokenIds[i];
require(pool.wnft.ownerOf(wnftTokenId) == msg.sender, "NFTMasterChef: can not withdraw nft now owned!");
nft = nfts[wnftTokenId];
if(nft.deposited == true){
withdrawNumber ++;
nft.deposited = false;
}
nft.rewardDebt = 0;
nft.dividendDebt = 0;
}
pool.wnft.withdraw(msg.sender, _wnftTokenIds);
pool.amount = pool.amount.sub(withdrawNumber);
}
function withdrawWithoutHarvest(uint256 _pid, uint256[] memory _wnftTokenIds) external validatePoolByPid(_pid) nonReentrant {
updatePool(_pid);
_withdrawWithoutHarvest(_pid, _wnftTokenIds);
emit WithdrawWithoutHarvest(msg.sender, _pid, _wnftTokenIds);
}
function harvest(uint256 _pid, address _forUser, uint256[] memory _wnftTokenIds) external validatePoolByPid(_pid) nonReentrant returns (uint256 _mining, uint256 _dividend) {
return _harvest(_pid, _forUser, _wnftTokenIds);
}
function canHarvest(uint256 _pid, address _forUser, uint256[] memory _wnftTokenIds) public view validatePoolByPid(_pid) returns (bool) {
if(address(harvestStrategy) != address(0)){
return harvestStrategy.canHarvest(_pid, _forUser, _wnftTokenIds);
}
return true;
}
function _harvest(uint256 _pid, address _forUser, uint256[] memory _wnftTokenIds) internal validatePoolByPid(_pid) returns (uint256 _mining, uint256 _dividend) {
_requireTokenIds(_wnftTokenIds);
if(_forUser == address(0)){
_forUser = msg.sender;
}
require(canHarvest(_pid, _forUser, _wnftTokenIds), "NFTMasterChef: can not harvest!");
updatePool(_pid);
PoolInfo storage pool = poolInfos[_pid];
mapping(uint256 => NFTInfo) storage nfts = poolNFTInfos[_pid];
uint256 wnftTokenId;
NFTInfo storage nft;
uint256 temp = 0;
for(uint256 i = 0; i < _wnftTokenIds.length; i ++){
wnftTokenId = _wnftTokenIds[i];
nft = nfts[wnftTokenId];
require(pool.wnft.ownerOf(wnftTokenId) == _forUser, "NFTMasterChef: can not harvest nft now owned!");
if(nft.deposited == true){
temp = pool.accTokenPerShare.div(ACC_TOKEN_PRECISION);
_mining = _mining.add(temp.sub(nft.rewardDebt));
nft.rewardDebt = temp;
if(pool.accDividendPerShare > 0 && address(pool.dividendToken) != address(0)){
temp = pool.accDividendPerShare.div(ACC_TOKEN_PRECISION);
_dividend = _dividend.add(temp.sub(nft.dividendDebt));
nft.dividendDebt = temp;
}
}
}
if (_mining > 0) {
_safeTransferTokenFromThis(token, _forUser, _mining);
}
if(_dividend > 0){
_safeTransferTokenFromThis(pool.dividendToken, _forUser, _dividend);
}
emit Harvest(_forUser, _pid, _wnftTokenIds, _mining, _dividend);
}
function emergencyStop(address payable _to) external onlyOwner nonReentrant {
if(_to == address(0)){
_to = payable(msg.sender);
}
uint256 addrBalance = token.balanceOf(address(this));
if(addrBalance > 0){
token.safeTransfer(_to, addrBalance);
}
uint256 length = poolInfos.length;
for (uint256 pid = 0; pid < length; ++ pid) {
closePool(pid, _to);
PoolInfo storage pool = poolInfos[pid];
if(pool.accDividendPerShare > 0 && address(pool.dividendToken) != address(0)){
uint256 bal = pool.dividendToken.balanceOf(address(this));
if(bal > 0){
pool.dividendToken.safeTransfer(_to, bal);
}
}
}
emit EmergencyStop(msg.sender, _to);
}
function closePool(uint256 _pid, address payable _to) public validatePoolByPid(_pid) onlyOwner {
PoolInfo storage pool = poolInfos[_pid];
if(isPoolEnd(_pid)){
return;
}
if(poolsRewardInfos[_pid].length > 0){
pool.currentRewardIndex = poolsRewardInfos[_pid].length - 1;
}
pool.currentRewardEndBlock = block.number;
if(_to == address(0)){
_to = payable(msg.sender);
}
emit ClosePool(_pid, _to);
}
function _safeTransferTokenFromThis(IERC20 _token, address _to, uint256 _amount) internal {
uint256 bal = _token.balanceOf(address(this));
if (_amount > bal) {
_token.safeTransfer(_to, bal);
} else {
_token.safeTransfer(_to, _amount);
}
}
function updateDevAddress(address payable _devAddress) external nonReentrant {
require(msg.sender == devAddress, "NFTMasterChef: dev: wut?");
require(_devAddress != address(0), "NFTMasterChef: address can not be zero!");
devAddress = _devAddress;
emit UpdateDevAddress(_devAddress);
}
function addDividendForPool(uint256 _pid, uint256 _addDividend) external validatePoolByPid(_pid) onlyOwner nonReentrant {
PoolInfo storage pool = poolInfos[_pid];
require(_addDividend > 0, "NFTMasterChef: add token error!");
require(address(pool.dividendToken) != address(0), "NFTMasterChef: no dividend token set!");
require(!isPoolEnd(_pid), "NFTMasterChef: pool is end!");
pool.accDividendPerShare = pool.accDividendPerShare.add(_addDividend.mul(ACC_TOKEN_PRECISION).div(pool.amount));
pool.dividendToken.safeTransferFrom(msg.sender, address(this), _addDividend);
emit AddDividendForPool(_pid, _addDividend);
}
function _requireTokenIds(uint256[] memory _tokenIds) internal pure {
require(_tokenIds.length > 0, "NFTMasterChef: tokenIds can not be empty!");
require(!_tokenIds.hasDuplicate(), "NFTMasterChef: tokenIds can not contain duplicate ones!");
}
}
文件 12 的 16:Ownable.sol
pragma solidity ^0.8.0;
import "./Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
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);
}
}
文件 13 的 16: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() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 14 的 16:SafeERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./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 _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");
}
}
}
文件 15 的 16:SafeMath.sol
pragma solidity ^0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
文件 16 的 16:wnft_interfaces.sol
pragma solidity ^0.8.0;
import "./IERC2981.sol";
import "./IERC721Receiver.sol";
import "./IERC721Metadata.sol";
import "./IERC721Enumerable.sol";
interface IERC2981Mutable is IERC165, IERC2981 {
function setDefaultRoyalty(address _receiver, uint96 _feeNumerator) external;
function deleteDefaultRoyalty() external;
}
interface IBaseWrappedNFT is IERC165, IERC2981Mutable, IERC721Receiver, IERC721, IERC721Metadata {
event DelegatorChanged(address _delegator);
event Deposit(address _forUser, uint256[] _tokenIds);
event Withdraw(address _forUser, uint256[] _wnftTokenIds);
function nft() external view returns (IERC721Metadata);
function factory() external view returns (IWrappedNFTFactory);
function deposit(address _forUser, uint256[] memory _tokenIds) external;
function withdraw(address _forUser, uint256[] memory _wnftTokenIds) external;
function exists(uint256 _tokenId) external view returns (bool);
function delegator() external view returns (address);
function setDelegator(address _delegator) external;
function isEnumerable() external view returns (bool);
}
interface IWrappedNFT is IBaseWrappedNFT {
function totalSupply() external view returns (uint256);
}
interface IWrappedNFTEnumerable is IWrappedNFT, IERC721Enumerable {
function totalSupply() external view override(IWrappedNFT, IERC721Enumerable) returns (uint256);
}
interface IWrappedNFTFactory {
event WrappedNFTDeployed(IERC721Metadata _nft, IWrappedNFT _wnft, bool _isEnumerable);
event WNFTDelegatorChanged(address _wnftDelegator);
function wnftDelegator() external view returns (address);
function deployWrappedNFT(IERC721Metadata _nft, bool _isEnumerable) external returns (IWrappedNFT);
function wnfts(IERC721Metadata _nft) external view returns (IWrappedNFT);
function wnftsNumber() external view returns (uint);
}
{
"compilationTarget": {
"NFTMasterChef.sol": "NFTMasterChef"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IWrappedNFTFactory","name":"_wnftFactory","type":"address"},{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"address payable","name":"_devAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"addDividend","type":"uint256"}],"name":"AddDividendForPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC721Metadata","name":"nft","type":"address"},{"indexed":false,"internalType":"contract IWrappedNFT","name":"wnft","type":"address"},{"indexed":false,"internalType":"uint256","name":"startBlock","type":"uint256"},{"components":[{"internalType":"uint256","name":"rewardBlock","type":"uint256"},{"internalType":"uint256","name":"rewardForEachBlock","type":"uint256"},{"internalType":"uint256","name":"rewardPerNFTForEachBlock","type":"uint256"}],"indexed":false,"internalType":"struct INFTMasterChef.RewardInfo[]","name":"rewards","type":"tuple[]"},{"indexed":false,"internalType":"uint256","name":"depositFee","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"dividendToken","type":"address"},{"indexed":false,"internalType":"bool","name":"withUpdate","type":"bool"}],"name":"AddPoolInfo","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"addTokenPerPool","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"addTokenPerBlock","type":"uint256"},{"indexed":false,"internalType":"bool","name":"withTokenTransfer","type":"bool"}],"name":"AddTokenRewardForPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"address payable","name":"to","type":"address"}],"name":"ClosePool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"EmergencyStop","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"wnftTokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"mining","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dividend","type":"uint256"}],"name":"Harvest","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":"contract IHarvestStrategy","name":"harvestStrategy","type":"address"}],"name":"SetHarvestStrategy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"depositFee","type":"uint256"}],"name":"SetPoolDepositFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"dividendToken","type":"address"}],"name":"SetPoolDividendToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startBlock","type":"uint256"}],"name":"SetStartBlock","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address payable","name":"devAddress","type":"address"}],"name":"UpdateDevAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardBlock","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardForEachBlock","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardPerNFTForEachBlock","type":"uint256"}],"name":"UpdatePoolReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"wnfTokenIds","type":"uint256[]"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"wnfTokenIds","type":"uint256[]"}],"name":"WithdrawWithoutHarvest","type":"event"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_addDividend","type":"uint256"}],"name":"addDividendForPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC721Metadata","name":"_nft","type":"address"},{"internalType":"uint256","name":"_startBlock","type":"uint256"},{"components":[{"internalType":"uint256","name":"rewardBlock","type":"uint256"},{"internalType":"uint256","name":"rewardForEachBlock","type":"uint256"},{"internalType":"uint256","name":"rewardPerNFTForEachBlock","type":"uint256"}],"internalType":"struct INFTMasterChef.RewardInfo[]","name":"_rewards","type":"tuple[]"},{"internalType":"uint256","name":"_depositFee","type":"uint256"},{"internalType":"contract IERC20","name":"_dividendToken","type":"address"},{"internalType":"bool","name":"_withUpdate","type":"bool"}],"name":"addPoolInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_forUser","type":"address"},{"internalType":"uint256[]","name":"_wnftTokenIds","type":"uint256[]"}],"name":"canHarvest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address payable","name":"_to","type":"address"}],"name":"closePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"devAddress","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"_to","type":"address"}],"name":"emergencyStop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_from","type":"uint256"},{"internalType":"uint256","name":"_to","type":"uint256"}],"name":"getMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"getPoolCurrentReward","outputs":[{"components":[{"internalType":"uint256","name":"rewardBlock","type":"uint256"},{"internalType":"uint256","name":"rewardForEachBlock","type":"uint256"},{"internalType":"uint256","name":"rewardPerNFTForEachBlock","type":"uint256"}],"internalType":"struct INFTMasterChef.RewardInfo","name":"_rewardInfo","type":"tuple"},{"internalType":"uint256","name":"_currentRewardIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"getPoolEndBlock","outputs":[{"internalType":"uint256","name":"_poolEndBlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_forUser","type":"address"},{"internalType":"uint256[]","name":"_wnftTokenIds","type":"uint256[]"}],"name":"harvest","outputs":[{"internalType":"uint256","name":"_mining","type":"uint256"},{"internalType":"uint256","name":"_dividend","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"harvestStrategy","outputs":[{"internalType":"contract IHarvestStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"isPoolEnd","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"massUpdatePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256[]","name":"_wnftTokenIds","type":"uint256[]"}],"name":"pending","outputs":[{"internalType":"uint256","name":"_mining","type":"uint256"},{"internalType":"uint256","name":"_dividend","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolInfos","outputs":[{"internalType":"contract IWrappedNFT","name":"wnft","type":"address"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"currentRewardIndex","type":"uint256"},{"internalType":"uint256","name":"currentRewardEndBlock","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"lastRewardBlock","type":"uint256"},{"internalType":"uint256","name":"accTokenPerShare","type":"uint256"},{"internalType":"contract IERC20","name":"dividendToken","type":"address"},{"internalType":"uint256","name":"accDividendPerShare","type":"uint256"},{"internalType":"uint256","name":"depositFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolNFTInfos","outputs":[{"internalType":"bool","name":"deposited","type":"bool"},{"internalType":"uint256","name":"rewardDebt","type":"uint256"},{"internalType":"uint256","name":"dividendDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"poolRewardLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolsRewardInfos","outputs":[{"internalType":"uint256","name":"rewardBlock","type":"uint256"},{"internalType":"uint256","name":"rewardForEachBlock","type":"uint256"},{"internalType":"uint256","name":"rewardPerNFTForEachBlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IHarvestStrategy","name":"_harvestStrategy","type":"address"}],"name":"setHarvestStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_depositFee","type":"uint256"}],"name":"setPoolDepositFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"contract IERC20","name":"_dividendToken","type":"address"}],"name":"setPoolDividendToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_startBlock","type":"uint256"}],"name":"setStartBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_devAddress","type":"address"}],"name":"updateDevAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"updatePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_rewardIndex","type":"uint256"},{"internalType":"uint256","name":"_rewardBlock","type":"uint256"},{"internalType":"uint256","name":"_rewardForEachBlock","type":"uint256"},{"internalType":"uint256","name":"_rewardPerNFTForEachBlock","type":"uint256"}],"name":"updatePoolReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256[]","name":"_wnftTokenIds","type":"uint256[]"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256[]","name":"_wnftTokenIds","type":"uint256[]"}],"name":"withdrawWithoutHarvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wnftFactory","outputs":[{"internalType":"contract IWrappedNFTFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"}]