文件 1 的 25:Address.sol
pragma solidity >=0.6.2 <0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 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) private 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 的 25:Context.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 3 的 25:Counters.sol
pragma solidity >=0.6.0 <0.8.0;
import "../math/SafeMath.sol";
library Counters {
using SafeMath for uint256;
struct Counter {
uint256 _value;
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
counter._value += 1;
}
function decrement(Counter storage counter) internal {
counter._value = counter._value.sub(1);
}
}
文件 4 的 25:ERC165.sol
pragma solidity >=0.6.0 <0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
mapping(bytes4 => bool) private _supportedInterfaces;
constructor () internal {
_registerInterface(_INTERFACE_ID_ERC165);
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return _supportedInterfaces[interfaceId];
}
function _registerInterface(bytes4 interfaceId) internal virtual {
require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
_supportedInterfaces[interfaceId] = true;
}
}
文件 5 的 25:ERC721.sol
pragma solidity >=0.6.0 <0.8.0;
import "../../utils/Context.sol";
import "./IERC721.sol";
import "./IERC721Metadata.sol";
import "./IERC721Enumerable.sol";
import "./IERC721Receiver.sol";
import "../../introspection/ERC165.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
import "../../utils/EnumerableSet.sol";
import "../../utils/EnumerableMap.sol";
import "../../utils/Strings.sol";
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable {
using SafeMath for uint256;
using Address for address;
using EnumerableSet for EnumerableSet.UintSet;
using EnumerableMap for EnumerableMap.UintToAddressMap;
using Strings for uint256;
bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
mapping (address => EnumerableSet.UintSet) private _holderTokens;
EnumerableMap.UintToAddressMap private _tokenOwners;
mapping (uint256 => address) private _tokenApprovals;
mapping (address => mapping (address => bool)) private _operatorApprovals;
string private _name;
string private _symbol;
mapping (uint256 => string) private _tokenURIs;
string private _baseURI;
bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
constructor (string memory name_, string memory symbol_) public {
_name = name_;
_symbol = symbol_;
_registerInterface(_INTERFACE_ID_ERC721);
_registerInterface(_INTERFACE_ID_ERC721_METADATA);
_registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
}
function balanceOf(address owner) public view virtual override returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _holderTokens[owner].length();
}
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token");
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory _tokenURI = _tokenURIs[tokenId];
string memory base = baseURI();
if (bytes(base).length == 0) {
return _tokenURI;
}
if (bytes(_tokenURI).length > 0) {
return string(abi.encodePacked(base, _tokenURI));
}
return string(abi.encodePacked(base, tokenId.toString()));
}
function baseURI() public view virtual returns (string memory) {
return _baseURI;
}
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
return _holderTokens[owner].at(index);
}
function totalSupply() public view virtual override returns (uint256) {
return _tokenOwners.length();
}
function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
(uint256 tokenId, ) = _tokenOwners.at(index);
return tokenId;
}
function approve(address to, uint256 tokenId) public virtual override {
address owner = ERC721.ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(_msgSender() == owner || ERC721.isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not owner nor approved for all"
);
_approve(to, tokenId);
}
function getApproved(uint256 tokenId) public view virtual override returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved) public virtual override {
require(operator != _msgSender(), "ERC721: approve to caller");
_operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
function transferFrom(address from, address to, uint256 tokenId) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
}
function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransfer(from, to, tokenId, _data);
}
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _tokenOwners.contains(tokenId);
}
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || ERC721.isApprovedForAll(owner, spender));
}
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
_mint(to, tokenId);
require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_holderTokens[to].add(tokenId);
_tokenOwners.set(tokenId, to);
emit Transfer(address(0), to, tokenId);
}
function _burn(uint256 tokenId) internal virtual {
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
_approve(address(0), tokenId);
if (bytes(_tokenURIs[tokenId]).length != 0) {
delete _tokenURIs[tokenId];
}
_holderTokens[owner].remove(tokenId);
_tokenOwners.remove(tokenId);
emit Transfer(owner, address(0), tokenId);
}
function _transfer(address from, address to, uint256 tokenId) internal virtual {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
_approve(address(0), tokenId);
_holderTokens[from].remove(tokenId);
_holderTokens[to].add(tokenId);
_tokenOwners.set(tokenId, to);
emit Transfer(from, to, tokenId);
}
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;
}
function _setBaseURI(string memory baseURI_) internal virtual {
_baseURI = baseURI_;
}
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
private returns (bool)
{
if (!to.isContract()) {
return true;
}
bytes memory returndata = to.functionCall(abi.encodeWithSelector(
IERC721Receiver(to).onERC721Received.selector,
_msgSender(),
from,
tokenId,
_data
), "ERC721: transfer to non ERC721Receiver implementer");
bytes4 retval = abi.decode(returndata, (bytes4));
return (retval == _ERC721_RECEIVED);
}
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { }
}
文件 6 的 25:EnumerableMap.sol
pragma solidity >=0.6.0 <0.8.0;
library EnumerableMap {
struct MapEntry {
bytes32 _key;
bytes32 _value;
}
struct Map {
MapEntry[] _entries;
mapping (bytes32 => uint256) _indexes;
}
function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) {
uint256 keyIndex = map._indexes[key];
if (keyIndex == 0) {
map._entries.push(MapEntry({ _key: key, _value: value }));
map._indexes[key] = map._entries.length;
return true;
} else {
map._entries[keyIndex - 1]._value = value;
return false;
}
}
function _remove(Map storage map, bytes32 key) private returns (bool) {
uint256 keyIndex = map._indexes[key];
if (keyIndex != 0) {
uint256 toDeleteIndex = keyIndex - 1;
uint256 lastIndex = map._entries.length - 1;
MapEntry storage lastEntry = map._entries[lastIndex];
map._entries[toDeleteIndex] = lastEntry;
map._indexes[lastEntry._key] = toDeleteIndex + 1;
map._entries.pop();
delete map._indexes[key];
return true;
} else {
return false;
}
}
function _contains(Map storage map, bytes32 key) private view returns (bool) {
return map._indexes[key] != 0;
}
function _length(Map storage map) private view returns (uint256) {
return map._entries.length;
}
function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) {
require(map._entries.length > index, "EnumerableMap: index out of bounds");
MapEntry storage entry = map._entries[index];
return (entry._key, entry._value);
}
function _tryGet(Map storage map, bytes32 key) private view returns (bool, bytes32) {
uint256 keyIndex = map._indexes[key];
if (keyIndex == 0) return (false, 0);
return (true, map._entries[keyIndex - 1]._value);
}
function _get(Map storage map, bytes32 key) private view returns (bytes32) {
uint256 keyIndex = map._indexes[key];
require(keyIndex != 0, "EnumerableMap: nonexistent key");
return map._entries[keyIndex - 1]._value;
}
function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) {
uint256 keyIndex = map._indexes[key];
require(keyIndex != 0, errorMessage);
return map._entries[keyIndex - 1]._value;
}
struct UintToAddressMap {
Map _inner;
}
function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
}
function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
return _remove(map._inner, bytes32(key));
}
function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
return _contains(map._inner, bytes32(key));
}
function length(UintToAddressMap storage map) internal view returns (uint256) {
return _length(map._inner);
}
function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
(bytes32 key, bytes32 value) = _at(map._inner, index);
return (uint256(key), address(uint160(uint256(value))));
}
function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
(bool success, bytes32 value) = _tryGet(map._inner, bytes32(key));
return (success, address(uint160(uint256(value))));
}
function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
return address(uint160(uint256(_get(map._inner, bytes32(key)))));
}
function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) {
return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage))));
}
}
文件 7 的 25:EnumerableSet.sol
pragma solidity >=0.6.0 <0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping (bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
bytes32 lastvalue = set._values[lastIndex];
set._values[toDeleteIndex] = lastvalue;
set._indexes[lastvalue] = toDeleteIndex + 1;
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
require(set._values.length > index, "EnumerableSet: index out of bounds");
return set._values[index];
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
}
文件 8 的 25:IERC165.sol
pragma solidity >=0.6.0 <0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 9 的 25:IERC20.sol
pragma solidity >=0.6.0 <0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, 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 sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 10 的 25:IERC20Metadata.sol
pragma solidity =0.7.6;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IERC20Metadata is IERC20 {
function decimals() external view returns (uint8);
}
文件 11 的 25:IERC721.sol
pragma solidity >=0.6.2 <0.8.0;
import "../../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) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}
文件 12 的 25:IERC721Enumerable.sol
pragma solidity >=0.6.2 <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 tokenId);
function tokenByIndex(uint256 index) external view returns (uint256);
}
文件 13 的 25:IERC721Metadata.sol
pragma solidity >=0.6.2 <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);
}
文件 14 的 25:IERC721Receiver.sol
pragma solidity >=0.6.0 <0.8.0;
interface IERC721Receiver {
function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);
}
文件 15 的 25:IMasterChef.sol
pragma solidity =0.7.6;
interface IMasterChef {
function wethToken() external view returns (address);
function mainToken() external view returns (address);
function yieldBooster() external view returns (address);
function emergencyUnlock() external view returns (bool);
function isUnlockOperator(address) external view returns (bool);
function getPoolInfo(
address _poolAddress
)
external
view
returns (
address poolAddress,
uint256 allocPointsARX,
uint256 allocPointsWETH,
uint256 lastRewardTime,
uint256 reserve,
uint256 reserveWETH,
uint256 poolEmissionRate,
uint256 poolEmissionRateWETH
);
function claimRewards() external returns (uint256 rewardAmount, uint256 amountWETH);
function owner() external view returns (address);
}
文件 16 的 25:INFTHandler.sol
pragma solidity =0.7.6;
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
interface INFTHandler is IERC721Receiver {
function onNFTHarvest(
address operator,
address to,
uint256 tokenId,
uint256 arxAmount,
uint256 xArxAmount
) external returns (bool);
function onNFTAddToPosition(address operator, uint256 tokenId, uint256 lpAmount) external returns (bool);
function onNFTWithdraw(address operator, uint256 tokenId, uint256 lpAmount) external returns (bool);
}
文件 17 的 25:INFTPool.sol
pragma solidity =0.7.6;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
interface INFTPool is IERC721 {
function exists(uint256 tokenId) external view returns (bool);
function hasDeposits() external view returns (bool);
function getPoolInfo()
external
view
returns (
address lpToken,
address arxToken,
address xToken,
uint256 lastRewardTime,
uint256 accRewardsPerShare,
uint256 accRewardsPerShareWETH,
uint256 lpSupply,
uint256 lpSupplyWithMultiplier,
uint256 allocPointsARX,
uint256 allocPointsWETH
);
function getStakingPosition(
uint256 tokenId
)
external
view
returns (
uint256 amount,
uint256 amountWithMultiplier,
uint256 startLockTime,
uint256 lockDuration,
uint256 lockMultiplier,
uint256 rewardDebt,
uint256 rewardDebtWETH,
uint256 boostPoints,
uint256 totalMultiplier
);
function boost(uint256 userAddress, uint256 amount) external;
function unboost(uint256 userAddress, uint256 amount) external;
}
文件 18 的 25:INFTPoolRewardManager.sol
pragma solidity =0.7.6;
interface INFTPoolRewardManager {
function pendingAdditionalRewards(
uint256 tokenId,
uint256 positionAmountMultiplied,
uint256 lpSupplyWithMultiplier,
uint256 lastRewardTime
) external view returns (address[] memory tokens, uint256[] memory rewardAmounts);
function updateRewardsPerShare(uint256 lpSupplyMultiplied, uint256 lastRewardTime) external;
function updatePositionRewardDebts(uint256 positionAmountMultiplied, uint256 tokenId) external;
function harvestAdditionalRewards(uint256 positionAmountMultiplied, address to, uint256 tokenId) external;
function addPool(address nftPoolAddress) external;
}
文件 19 的 25:IYieldBooster.sol
pragma solidity =0.7.6;
interface IYieldBooster {
function deallocateAllFromPool(address userAddress, uint256 tokenId) external;
function getMultiplier(
address poolAddress,
uint256 maxBoostMultiplier,
uint256 amount,
uint256 totalPoolSupply,
uint256 allocatedAmount
) external view returns (uint256);
}
文件 20 的 25:IxARXToken.sol
pragma solidity =0.7.6;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IxARXToken is IERC20 {
function usageAllocations(address userAddress, address usageAddress) external view returns (uint256 allocation);
function allocateFromUsage(address userAddress, uint256 amount) external;
function convertTo(uint256 amount, address to) external;
function deallocateFromUsage(address userAddress, uint256 amount) external;
function isTransferWhitelisted(address account) external view returns (bool);
}
文件 21 的 25:NFTPool.sol
pragma solidity =0.7.6;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./interfaces/INFTHandler.sol";
import "./interfaces/IMasterChef.sol";
import "./interfaces/INFTPool.sol";
import "./interfaces/IYieldBooster.sol";
import "./interfaces/tokens/IxARXToken.sol";
import "./interfaces/tokens/IERC20Metadata.sol";
import "./interfaces/INFTPoolRewardManager.sol";
contract NFTPool is ReentrancyGuard, INFTPool, ERC721("Arbidex staking position NFT", "spNFT") {
using Address for address;
using Counters for Counters.Counter;
using SafeMath for uint256;
using SafeERC20 for IERC20Metadata;
struct StakingPosition {
uint256 amount;
uint256 amountWithMultiplier;
uint256 startLockTime;
uint256 lockDuration;
uint256 lockMultiplier;
uint256 rewardDebt;
uint256 rewardDebtWETH;
uint256 boostPoints;
uint256 totalMultiplier;
uint256 pendingXTokenRewards;
uint256 pendingArxRewards;
uint256 pendingWETHRewards;
}
Counters.Counter private _tokenIds;
address public operator;
IMasterChef public master;
address public immutable factory;
bool public initialized;
IERC20Metadata private _lpToken;
IERC20Metadata private _arxToken;
IxARXToken private _xToken;
INFTPoolRewardManager public rewardManager;
uint256 private _lpSupply;
uint256 private _lpSupplyWithMultiplier;
uint256 private _accRewardsPerShare;
uint256 private _accRewardsPerShareWETH;
uint256 public constant MAX_GLOBAL_MULTIPLIER_LIMIT = 25000;
uint256 public constant MAX_LOCK_MULTIPLIER_LIMIT = 15000;
uint256 public constant MAX_BOOST_MULTIPLIER_LIMIT = 15000;
uint256 private _maxGlobalMultiplier = 20000;
uint256 private _maxLockDuration = 183 days;
uint256 private _maxLockMultiplier = 10000;
uint256 private _maxBoostMultiplier = 10000;
uint256 private constant _TOTAL_REWARDS_SHARES = 10000;
uint256 public xTokenRewardsShare = 8000;
bool public emergencyUnlock;
mapping(uint256 => StakingPosition) internal _stakingPositions;
event AddToPosition(uint256 indexed tokenId, address user, uint256 amount);
event CreatePosition(uint256 indexed tokenId, uint256 amount, uint256 lockDuration);
event WithdrawFromPosition(uint256 indexed tokenId, uint256 amount);
event EmergencyWithdraw(uint256 indexed tokenId, uint256 amount);
event LockPosition(uint256 indexed tokenId, uint256 lockDuration);
event HarvestPosition(uint256 indexed tokenId, address to, uint256 pending, uint256 pendingWETH);
event SetBoost(uint256 indexed tokenId, uint256 boostPoints);
event PoolUpdated(uint256 lastRewardTime, uint256 accRewardsPerShare, uint256 accRewardsPerShareWETH);
event SetLockMultiplierSettings(uint256 maxLockDuration, uint256 maxLockMultiplier);
event SetBoostMultiplierSettings(uint256 maxGlobalMultiplier, uint256 maxBoostMultiplier);
event SetXTokenRewardsShare(uint256 xTokenRewardsShare);
event SetUnlockOperator(address operator, bool isAdded);
event SetEmergencyUnlock(bool emergencyUnlock);
event SetOperator(address operator);
event SetRewardManager(address manager);
constructor() {
factory = msg.sender;
}
function initialize(
IMasterChef master_,
IERC20Metadata arxToken,
IxARXToken xToken,
IERC20Metadata lpToken,
INFTPoolRewardManager manager
) external {
require(msg.sender == factory && !initialized, "FORBIDDEN");
_lpToken = lpToken;
master = master_;
_arxToken = arxToken;
_xToken = xToken;
rewardManager = manager;
initialized = true;
_arxToken.approve(address(_xToken), type(uint256).max);
}
function _requireOnlyOwner() internal view {
require(msg.sender == owner(), "FORBIDDEN");
}
function _requireOnlyYieldBooster() internal view {
require(msg.sender == yieldBooster(), "FORBIDDEN");
}
function _requireOnlyOperatorOrOwnerOf(uint256 tokenId) internal view {
require(ERC721._isApprovedOrOwner(msg.sender, tokenId), "FORBIDDEN");
}
function _requireOnlyApprovedOrOwnerOf(uint256 tokenId) internal view {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
require(_isOwnerOf(msg.sender, tokenId) || getApproved(tokenId) == msg.sender, "FORBIDDEN");
}
function _requireOnlyOwnerOf(uint256 tokenId) internal view {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
require(_isOwnerOf(msg.sender, tokenId), "not owner");
}
function owner() public view returns (address) {
return master.owner();
}
function yieldBooster() public view returns (address) {
return master.yieldBooster();
}
function exists(uint256 tokenId) external view override returns (bool) {
return ERC721._exists(tokenId);
}
function lastTokenId() external view returns (uint256) {
return _tokenIds.current();
}
function isUnlocked() public view returns (bool) {
return emergencyUnlock || master.emergencyUnlock();
}
function hasDeposits() external view override returns (bool) {
return _lpSupplyWithMultiplier > 0;
}
function getPoolInfo()
external
view
override
returns (
address lpToken,
address arxToken,
address xToken,
uint256 lastRewardTime,
uint256 accRewardsPerShare,
uint256 accRewardsPerShareWETH,
uint256 lpSupply,
uint256 lpSupplyWithMultiplier,
uint256 allocPointsARX,
uint256 allocPointsWETH
)
{
(, allocPointsARX, allocPointsWETH, lastRewardTime, , , , ) = master.getPoolInfo(address(this));
return (
address(_lpToken),
address(_arxToken),
address(_xToken),
lastRewardTime,
_accRewardsPerShare,
_accRewardsPerShareWETH,
_lpSupply,
_lpSupplyWithMultiplier,
allocPointsARX,
allocPointsWETH
);
}
function getMultiplierSettings()
external
view
returns (
uint256 maxGlobalMultiplier,
uint256 maxLockDuration,
uint256 maxLockMultiplier,
uint256 maxBoostMultiplier
)
{
return (_maxGlobalMultiplier, _maxLockDuration, _maxLockMultiplier, _maxBoostMultiplier);
}
function getMultiplierByBoostPoints(uint256 amount, uint256 boostPoints) public view returns (uint256) {
if (boostPoints == 0 || amount == 0) return 0;
address yieldBoosterAddress = yieldBooster();
return
yieldBoosterAddress != address(0)
? IYieldBooster(yieldBoosterAddress).getMultiplier(
address(this),
_maxBoostMultiplier,
amount,
_lpSupply,
boostPoints
)
: 0;
}
function getMultiplierByLockDuration(uint256 lockDuration) public view returns (uint256) {
if (isUnlocked()) return 0;
if (_maxLockDuration == 0 || lockDuration == 0) return 0;
if (lockDuration >= _maxLockDuration) return _maxLockMultiplier;
return _maxLockMultiplier.mul(lockDuration).div(_maxLockDuration);
}
function getStakingPosition(
uint256 tokenId
)
external
view
override
returns (
uint256 amount,
uint256 amountWithMultiplier,
uint256 startLockTime,
uint256 lockDuration,
uint256 lockMultiplier,
uint256 rewardDebt,
uint256 rewardDebtWETH,
uint256 boostPoints,
uint256 totalMultiplier
)
{
StakingPosition storage position = _stakingPositions[tokenId];
return (
position.amount,
position.amountWithMultiplier,
position.startLockTime,
position.lockDuration,
position.lockMultiplier,
position.rewardDebt,
position.rewardDebtWETH,
position.boostPoints,
position.totalMultiplier
);
}
function pendingRewards(uint256 tokenId) external view returns (uint256 mainAmount, uint256 wethAmount) {
(
,
,
,
uint256 lastRewardTime,
uint256 reserve,
uint256 reserveWETH,
uint256 poolEmissionRate,
uint256 poolEmissionRateWETH
) = master.getPoolInfo(address(this));
StakingPosition storage position = _stakingPositions[tokenId];
uint256 positionAmountMultiplied = position.amountWithMultiplier;
uint256 accRewardsPerShare = _accRewardsPerShare;
uint256 accRewardsPerShareWETH = _accRewardsPerShareWETH;
bool timeHasPassed = _currentBlockTimestamp() > lastRewardTime;
bool hasLpDeposits = _lpSupplyWithMultiplier > 0;
if ((reserve > 0 || reserveWETH > 0 || timeHasPassed) && hasLpDeposits) {
uint256 duration = _currentBlockTimestamp().sub(lastRewardTime);
uint256 tokenRewards = duration.mul(poolEmissionRate).add(reserve);
accRewardsPerShare = accRewardsPerShare.add(tokenRewards.mul(1e18).div(_lpSupplyWithMultiplier));
uint256 wethRewards = duration.mul(poolEmissionRateWETH).add(reserveWETH);
accRewardsPerShareWETH = accRewardsPerShareWETH.add(wethRewards.mul(1e18).div(_lpSupplyWithMultiplier));
}
mainAmount = positionAmountMultiplied
.mul(accRewardsPerShare)
.div(1e18)
.sub(position.rewardDebt)
.add(position.pendingXTokenRewards)
.add(position.pendingArxRewards);
wethAmount = positionAmountMultiplied.mul(accRewardsPerShareWETH).div(1e18).sub(position.rewardDebtWETH).add(
position.pendingWETHRewards
);
return (mainAmount, wethAmount);
}
function pendingAdditionalRewards(
uint256 tokenId
) external view returns (address[] memory tokens, uint256[] memory rewardAmounts) {
StakingPosition storage position = _stakingPositions[tokenId];
(, , , uint256 lastRewardTime, , , , ) = master.getPoolInfo(address(this));
(tokens, rewardAmounts) = rewardManager.pendingAdditionalRewards(
tokenId,
position.amountWithMultiplier,
_lpSupplyWithMultiplier,
lastRewardTime
);
}
function setLockMultiplierSettings(uint256 maxLockDuration, uint256 maxLockMultiplier) external {
require(msg.sender == owner() || msg.sender == operator, "FORBIDDEN");
require(
maxLockMultiplier <= MAX_LOCK_MULTIPLIER_LIMIT &&
maxLockMultiplier.add(_maxBoostMultiplier) <= _maxGlobalMultiplier,
"too high"
);
_maxLockDuration = maxLockDuration;
_maxLockMultiplier = maxLockMultiplier;
emit SetLockMultiplierSettings(maxLockDuration, maxLockMultiplier);
}
function setBoostMultiplierSettings(uint256 maxGlobalMultiplier, uint256 maxBoostMultiplier) external {
_requireOnlyOwner();
require(maxGlobalMultiplier <= MAX_GLOBAL_MULTIPLIER_LIMIT, "too high");
require(
maxBoostMultiplier <= MAX_BOOST_MULTIPLIER_LIMIT &&
maxBoostMultiplier.add(_maxLockMultiplier) <= maxGlobalMultiplier,
"too high"
);
_maxGlobalMultiplier = maxGlobalMultiplier;
_maxBoostMultiplier = maxBoostMultiplier;
emit SetBoostMultiplierSettings(maxGlobalMultiplier, maxBoostMultiplier);
}
function setXTokenRewardsShare(uint256 xTokenRewardsShare_) external {
_requireOnlyOwner();
require(xTokenRewardsShare_ <= _TOTAL_REWARDS_SHARES, "too high");
xTokenRewardsShare = xTokenRewardsShare_;
emit SetXTokenRewardsShare(xTokenRewardsShare_);
}
function setEmergencyUnlock(bool emergencyUnlock_) external {
_requireOnlyOwner();
emergencyUnlock = emergencyUnlock_;
emit SetEmergencyUnlock(emergencyUnlock);
}
function setOperator(address operator_) external {
_requireOnlyOwner();
operator = operator_;
emit SetOperator(operator_);
}
function setRewardManager(address manager) external {
_requireOnlyOwner();
rewardManager = INFTPoolRewardManager(manager);
emit SetRewardManager(manager);
}
function transferFrom(address from, address to, uint256 tokenId) public override(ERC721, IERC721) nonReentrant {
ERC721.transferFrom(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public override(ERC721, IERC721) nonReentrant {
ERC721.safeTransferFrom(from, to, tokenId, _data);
}
function updatePool() external nonReentrant {
_updatePool();
}
function createPosition(uint256 amount, uint256 lockDuration) external nonReentrant {
if (isUnlocked()) {
require(lockDuration == 0, "locks disabled");
}
_updatePool();
amount = _transferSupportingFeeOnTransfer(_lpToken, msg.sender, amount);
require(amount != 0, "zero amount");
uint256 currentTokenId = _mintNextTokenId(msg.sender);
uint256 lockMultiplier = getMultiplierByLockDuration(lockDuration);
uint256 amountWithMultiplier = amount.mul(lockMultiplier.add(1e4)).div(1e4);
_stakingPositions[currentTokenId] = StakingPosition({
amount: amount,
rewardDebt: amountWithMultiplier.mul(_accRewardsPerShare).div(1e18),
rewardDebtWETH: amountWithMultiplier.mul(_accRewardsPerShareWETH).div(1e18),
lockDuration: lockDuration,
startLockTime: _currentBlockTimestamp(),
lockMultiplier: lockMultiplier,
amountWithMultiplier: amountWithMultiplier,
boostPoints: 0,
totalMultiplier: lockMultiplier,
pendingArxRewards: 0,
pendingXTokenRewards: 0,
pendingWETHRewards: 0
});
_lpSupply = _lpSupply.add(amount);
_lpSupplyWithMultiplier = _lpSupplyWithMultiplier.add(amountWithMultiplier);
rewardManager.updatePositionRewardDebts(amountWithMultiplier, currentTokenId);
emit CreatePosition(currentTokenId, amount, lockDuration);
}
function addToPosition(uint256 tokenId, uint256 amountToAdd) external nonReentrant {
_requireOnlyOperatorOrOwnerOf(tokenId);
require(amountToAdd > 0, "0 amount");
_updatePool();
address nftOwner = ERC721.ownerOf(tokenId);
_harvestPosition(tokenId, nftOwner);
StakingPosition storage position = _stakingPositions[tokenId];
if (position.lockDuration > 0) {
position.startLockTime = _currentBlockTimestamp();
position.lockMultiplier = getMultiplierByLockDuration(position.lockDuration);
}
amountToAdd = _transferSupportingFeeOnTransfer(_lpToken, msg.sender, amountToAdd);
position.amount = position.amount.add(amountToAdd);
_lpSupply = _lpSupply.add(amountToAdd);
_updateBoostMultiplierInfoAndRewardDebt(position, tokenId);
_checkOnAddToPosition(nftOwner, tokenId, amountToAdd);
emit AddToPosition(tokenId, msg.sender, amountToAdd);
}
function boost(uint256 tokenId, uint256 amount) external override nonReentrant {
_requireOnlyYieldBooster();
require(ERC721._exists(tokenId), "invalid tokenId");
_updatePool();
_harvestPosition(tokenId, address(0));
StakingPosition storage position = _stakingPositions[tokenId];
uint256 boostPoints = position.boostPoints.add(amount);
position.boostPoints = boostPoints;
_updateBoostMultiplierInfoAndRewardDebt(position, tokenId);
emit SetBoost(tokenId, boostPoints);
}
function unboost(uint256 tokenId, uint256 amount) external override nonReentrant {
_requireOnlyYieldBooster();
_updatePool();
_harvestPosition(tokenId, address(0));
StakingPosition storage position = _stakingPositions[tokenId];
uint256 boostPoints = position.boostPoints.sub(amount);
position.boostPoints = boostPoints;
_updateBoostMultiplierInfoAndRewardDebt(position, tokenId);
emit SetBoost(tokenId, boostPoints);
}
function harvestPosition(uint256 tokenId) external nonReentrant {
_requireOnlyApprovedOrOwnerOf(tokenId);
_updatePool();
_harvestPosition(tokenId, ERC721.ownerOf(tokenId));
_updateBoostMultiplierInfoAndRewardDebt(_stakingPositions[tokenId], tokenId);
}
function harvestPositionTo(uint256 tokenId, address to) external nonReentrant {
_requireOnlyApprovedOrOwnerOf(tokenId);
require(ERC721.ownerOf(tokenId).isContract(), "FORBIDDEN");
_updatePool();
_harvestPosition(tokenId, to);
_updateBoostMultiplierInfoAndRewardDebt(_stakingPositions[tokenId], tokenId);
}
function harvestPositionsTo(uint256[] calldata tokenIds, address to) external nonReentrant {
_updatePool();
uint256 length = tokenIds.length;
for (uint256 i = 0; i < length; ++i) {
uint256 tokenId = tokenIds[i];
_requireOnlyApprovedOrOwnerOf(tokenId);
address tokenOwner = ERC721.ownerOf(tokenId);
require((msg.sender == tokenOwner && msg.sender == to) || tokenOwner.isContract(), "FORBIDDEN");
_harvestPosition(tokenId, to);
_updateBoostMultiplierInfoAndRewardDebt(_stakingPositions[tokenId], tokenId);
}
}
function withdrawFromPosition(uint256 tokenId, uint256 amountToWithdraw) external nonReentrant {
_requireOnlyApprovedOrOwnerOf(tokenId);
_updatePool();
address nftOwner = ERC721.ownerOf(tokenId);
_withdrawFromPosition(nftOwner, tokenId, amountToWithdraw);
_checkOnWithdraw(nftOwner, tokenId, amountToWithdraw);
}
function renewLockPosition(uint256 tokenId) external nonReentrant {
_requireOnlyApprovedOrOwnerOf(tokenId);
_updatePool();
_lockPosition(tokenId, _stakingPositions[tokenId].lockDuration);
}
function lockPosition(uint256 tokenId, uint256 lockDuration) external nonReentrant {
_requireOnlyApprovedOrOwnerOf(tokenId);
_updatePool();
_lockPosition(tokenId, lockDuration);
}
function emergencyWithdraw(uint256 tokenId) external nonReentrant {
_requireOnlyOwnerOf(tokenId);
StakingPosition storage position = _stakingPositions[tokenId];
require(
master.isUnlockOperator(msg.sender) ||
position.startLockTime.add(position.lockDuration) <= _currentBlockTimestamp() ||
isUnlocked(),
"locked"
);
uint256 amount = position.amount;
_lpSupply = _lpSupply.sub(amount);
_lpSupplyWithMultiplier = _lpSupplyWithMultiplier.sub(position.amountWithMultiplier);
_destroyPosition(tokenId, 0);
emit EmergencyWithdraw(tokenId, amount);
_lpToken.safeTransfer(msg.sender, amount);
}
function _isOwnerOf(address userAddress, uint256 tokenId) internal view returns (bool) {
return userAddress == ERC721.ownerOf(tokenId);
}
function _updatePool() internal {
uint256 lpSupplyMultiplied = _lpSupplyWithMultiplier;
(, , , uint256 currentLastRewardTime, , , , ) = master.getPoolInfo(address(this));
rewardManager.updateRewardsPerShare(lpSupplyMultiplied, currentLastRewardTime);
(uint256 rewardAmount, uint256 amountWETH) = master.claimRewards();
if (rewardAmount > 0) {
_accRewardsPerShare = _accRewardsPerShare.add(rewardAmount.mul(1e18).div(lpSupplyMultiplied));
}
if (amountWETH > 0) {
_accRewardsPerShareWETH = _accRewardsPerShareWETH.add(amountWETH.mul(1e18).div(lpSupplyMultiplied));
}
emit PoolUpdated(_currentBlockTimestamp(), _accRewardsPerShare, _accRewardsPerShareWETH);
}
function _destroyPosition(uint256 tokenId, uint256 boostPoints) internal {
if (boostPoints > 0) {
IYieldBooster(yieldBooster()).deallocateAllFromPool(msg.sender, tokenId);
}
delete _stakingPositions[tokenId];
ERC721._burn(tokenId);
}
function _mintNextTokenId(address to) internal returns (uint256 tokenId) {
_tokenIds.increment();
tokenId = _tokenIds.current();
_safeMint(to, tokenId);
}
function _withdrawFromPosition(address nftOwner, uint256 tokenId, uint256 amountToWithdraw) internal {
require(amountToWithdraw > 0, "null");
StakingPosition storage position = _stakingPositions[tokenId];
require(
master.isUnlockOperator(nftOwner) ||
position.startLockTime.add(position.lockDuration) <= _currentBlockTimestamp() ||
isUnlocked(),
"locked"
);
require(position.amount >= amountToWithdraw, "invalid");
_harvestPosition(tokenId, nftOwner);
position.amount = position.amount.sub(amountToWithdraw);
_lpSupply = _lpSupply.sub(amountToWithdraw);
if (position.amount == 0) {
_lpSupplyWithMultiplier = _lpSupplyWithMultiplier.sub(position.amountWithMultiplier);
_destroyPosition(tokenId, position.boostPoints);
} else {
_updateBoostMultiplierInfoAndRewardDebt(position, tokenId);
}
emit WithdrawFromPosition(tokenId, amountToWithdraw);
_lpToken.safeTransfer(nftOwner, amountToWithdraw);
}
function _updateBoostMultiplierInfoAndRewardDebt(StakingPosition storage position, uint256 tokenId) internal {
uint256 newTotalMultiplier = getMultiplierByBoostPoints(position.amount, position.boostPoints).add(
position.lockMultiplier
);
if (newTotalMultiplier > _maxGlobalMultiplier) newTotalMultiplier = _maxGlobalMultiplier;
position.totalMultiplier = newTotalMultiplier;
uint256 amountWithMultiplier = position.amount.mul(newTotalMultiplier.add(1e4)).div(1e4);
uint256 lpSupplyMultiplied = _lpSupplyWithMultiplier;
_lpSupplyWithMultiplier = lpSupplyMultiplied.sub(position.amountWithMultiplier).add(amountWithMultiplier);
position.amountWithMultiplier = amountWithMultiplier;
position.rewardDebt = amountWithMultiplier.mul(_accRewardsPerShare).div(1e18);
position.rewardDebtWETH = amountWithMultiplier.mul(_accRewardsPerShareWETH).div(1e18);
rewardManager.updatePositionRewardDebts(amountWithMultiplier, tokenId);
}
function _harvestPosition(uint256 tokenId, address to) internal {
StakingPosition storage position = _stakingPositions[tokenId];
uint256 positionAmountMultiplied = position.amountWithMultiplier;
uint256 pending = positionAmountMultiplied.mul(_accRewardsPerShare).div(1e18).sub(position.rewardDebt);
uint256 pendingWETH = positionAmountMultiplied.mul(_accRewardsPerShareWETH).div(1e18).sub(
position.rewardDebtWETH
);
if (isUnlocked() || position.startLockTime.add(position.lockDuration) <= _currentBlockTimestamp()) {
position.lockDuration = 0;
position.lockMultiplier = 0;
}
if (
pending > 0 ||
pendingWETH > 0 ||
position.pendingXTokenRewards > 0 ||
position.pendingArxRewards > 0 ||
position.pendingWETHRewards > 0
) {
uint256 xTokenRewards = pending.mul(xTokenRewardsShare).div(_TOTAL_REWARDS_SHARES);
uint256 arxAmount = pending.add(position.pendingArxRewards).sub(xTokenRewards);
xTokenRewards = xTokenRewards.add(position.pendingXTokenRewards);
if (address(0) == to) {
position.pendingXTokenRewards = xTokenRewards;
position.pendingArxRewards = arxAmount;
position.pendingWETHRewards = pendingWETH;
} else {
position.pendingXTokenRewards = 0;
position.pendingArxRewards = 0;
position.pendingWETHRewards = 0;
if (xTokenRewards > 0) xTokenRewards = _safeConvertTo(to, xTokenRewards);
arxAmount = _safeRewardsTransfer(address(_arxToken), to, arxAmount);
pendingWETH = _safeRewardsTransfer(master.wethToken(), to, pendingWETH);
_checkOnNFTHarvest(to, tokenId, arxAmount, xTokenRewards);
rewardManager.harvestAdditionalRewards(positionAmountMultiplied, to, tokenId);
}
}
emit HarvestPosition(tokenId, to, pending, pendingWETH);
}
function _lockPosition(uint256 tokenId, uint256 lockDuration) internal {
require(!isUnlocked(), "locks disabled");
StakingPosition storage position = _stakingPositions[tokenId];
uint256 endTime = position.startLockTime.add(position.lockDuration);
uint256 currentBlockTimestamp = _currentBlockTimestamp();
if (endTime > currentBlockTimestamp) {
require(lockDuration >= endTime.sub(currentBlockTimestamp) && lockDuration > 0, "invalid");
}
_harvestPosition(tokenId, msg.sender);
position.lockDuration = lockDuration;
position.lockMultiplier = getMultiplierByLockDuration(lockDuration);
position.startLockTime = currentBlockTimestamp;
_updateBoostMultiplierInfoAndRewardDebt(position, tokenId);
emit LockPosition(tokenId, lockDuration);
}
function _transferSupportingFeeOnTransfer(
IERC20Metadata token,
address user,
uint256 amount
) internal returns (uint256 receivedAmount) {
uint256 previousBalance = token.balanceOf(address(this));
token.safeTransferFrom(user, address(this), amount);
return token.balanceOf(address(this)).sub(previousBalance);
}
function _safeRewardsTransfer(address tokenAddress, address to, uint256 amount) internal returns (uint256) {
IERC20Metadata token = IERC20Metadata(tokenAddress);
uint256 balance = token.balanceOf(address(this));
if (amount > balance) {
amount = balance;
}
if (amount > 0) {
token.safeTransfer(to, amount);
}
return amount;
}
function _safeConvertTo(address to, uint256 amount) internal returns (uint256) {
uint256 balance = _arxToken.balanceOf(address(this));
if (amount > balance) {
amount = balance;
}
if (amount > 0) _xToken.convertTo(amount, to);
return amount;
}
function _checkOnNFTHarvest(address to, uint256 tokenId, uint256 arxAmount, uint256 xTokenAmount) internal {
address nftOwner = ERC721.ownerOf(tokenId);
if (nftOwner.isContract()) {
bytes memory returndata = nftOwner.functionCall(
abi.encodeWithSelector(
INFTHandler(nftOwner).onNFTHarvest.selector,
msg.sender,
to,
tokenId,
arxAmount,
xTokenAmount
),
"non implemented"
);
require(abi.decode(returndata, (bool)), "FORBIDDEN");
}
}
function _checkOnAddToPosition(address nftOwner, uint256 tokenId, uint256 lpAmount) internal {
if (nftOwner.isContract()) {
bytes memory returndata = nftOwner.functionCall(
abi.encodeWithSelector(
INFTHandler(nftOwner).onNFTAddToPosition.selector,
msg.sender,
tokenId,
lpAmount
),
"non implemented"
);
require(abi.decode(returndata, (bool)), "FORBIDDEN");
}
}
function _checkOnWithdraw(address nftOwner, uint256 tokenId, uint256 lpAmount) internal {
if (nftOwner.isContract()) {
bytes memory returndata = nftOwner.functionCall(
abi.encodeWithSelector(INFTHandler(nftOwner).onNFTWithdraw.selector, msg.sender, tokenId, lpAmount),
"non implemented"
);
require(abi.decode(returndata, (bool)), "FORBIDDEN");
}
}
function _beforeTokenTransfer(address from, address , uint256 ) internal view override {
require(!from.isContract() || msg.sender == from, "FORBIDDEN");
}
function _currentBlockTimestamp() internal view virtual returns (uint256) {
return block.timestamp;
}
}
文件 22 的 25:ReentrancyGuard.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () internal {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 23 的 25:SafeERC20.sol
pragma solidity >=0.6.0 <0.8.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
library SafeERC20 {
using SafeMath for uint256;
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).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_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");
}
}
}
文件 24 的 25:SafeMath.sol
pragma solidity >=0.6.0 <0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
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) {
if (b == 0) return (false, 0);
return (true, a / b);
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
文件 25 的 25:Strings.sol
pragma solidity >=0.6.0 <0.8.0;
library Strings {
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
uint256 index = digits - 1;
temp = value;
while (temp != 0) {
buffer[index--] = bytes1(uint8(48 + temp % 10));
temp /= 10;
}
return string(buffer);
}
}
{
"compilationTarget": {
"contracts/NFTPool.sol": "NFTPool"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AddToPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockDuration","type":"uint256"}],"name":"CreatePosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"pending","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pendingWETH","type":"uint256"}],"name":"HarvestPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockDuration","type":"uint256"}],"name":"LockPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lastRewardTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accRewardsPerShare","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accRewardsPerShareWETH","type":"uint256"}],"name":"PoolUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"boostPoints","type":"uint256"}],"name":"SetBoost","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxGlobalMultiplier","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxBoostMultiplier","type":"uint256"}],"name":"SetBoostMultiplierSettings","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"emergencyUnlock","type":"bool"}],"name":"SetEmergencyUnlock","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxLockDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxLockMultiplier","type":"uint256"}],"name":"SetLockMultiplierSettings","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"SetOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"manager","type":"address"}],"name":"SetRewardManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"isAdded","type":"bool"}],"name":"SetUnlockOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"xTokenRewardsShare","type":"uint256"}],"name":"SetXTokenRewardsShare","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawFromPosition","type":"event"},{"inputs":[],"name":"MAX_BOOST_MULTIPLIER_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_GLOBAL_MULTIPLIER_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_LOCK_MULTIPLIER_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amountToAdd","type":"uint256"}],"name":"addToPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","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":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"boost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"lockDuration","type":"uint256"}],"name":"createPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyUnlock","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"boostPoints","type":"uint256"}],"name":"getMultiplierByBoostPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"lockDuration","type":"uint256"}],"name":"getMultiplierByLockDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMultiplierSettings","outputs":[{"internalType":"uint256","name":"maxGlobalMultiplier","type":"uint256"},{"internalType":"uint256","name":"maxLockDuration","type":"uint256"},{"internalType":"uint256","name":"maxLockMultiplier","type":"uint256"},{"internalType":"uint256","name":"maxBoostMultiplier","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPoolInfo","outputs":[{"internalType":"address","name":"lpToken","type":"address"},{"internalType":"address","name":"arxToken","type":"address"},{"internalType":"address","name":"xToken","type":"address"},{"internalType":"uint256","name":"lastRewardTime","type":"uint256"},{"internalType":"uint256","name":"accRewardsPerShare","type":"uint256"},{"internalType":"uint256","name":"accRewardsPerShareWETH","type":"uint256"},{"internalType":"uint256","name":"lpSupply","type":"uint256"},{"internalType":"uint256","name":"lpSupplyWithMultiplier","type":"uint256"},{"internalType":"uint256","name":"allocPointsARX","type":"uint256"},{"internalType":"uint256","name":"allocPointsWETH","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getStakingPosition","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"amountWithMultiplier","type":"uint256"},{"internalType":"uint256","name":"startLockTime","type":"uint256"},{"internalType":"uint256","name":"lockDuration","type":"uint256"},{"internalType":"uint256","name":"lockMultiplier","type":"uint256"},{"internalType":"uint256","name":"rewardDebt","type":"uint256"},{"internalType":"uint256","name":"rewardDebtWETH","type":"uint256"},{"internalType":"uint256","name":"boostPoints","type":"uint256"},{"internalType":"uint256","name":"totalMultiplier","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"harvestPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"harvestPositionTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address","name":"to","type":"address"}],"name":"harvestPositionsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"hasDeposits","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IMasterChef","name":"master_","type":"address"},{"internalType":"contract IERC20Metadata","name":"arxToken","type":"address"},{"internalType":"contract IxARXToken","name":"xToken","type":"address"},{"internalType":"contract IERC20Metadata","name":"lpToken","type":"address"},{"internalType":"contract INFTPoolRewardManager","name":"manager","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isUnlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"lockDuration","type":"uint256"}],"name":"lockPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"master","outputs":[{"internalType":"contract IMasterChef","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","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":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"pendingAdditionalRewards","outputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"rewardAmounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"pendingRewards","outputs":[{"internalType":"uint256","name":"mainAmount","type":"uint256"},{"internalType":"uint256","name":"wethAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"renewLockPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardManager","outputs":[{"internalType":"contract INFTPoolRewardManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxGlobalMultiplier","type":"uint256"},{"internalType":"uint256","name":"maxBoostMultiplier","type":"uint256"}],"name":"setBoostMultiplierSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"emergencyUnlock_","type":"bool"}],"name":"setEmergencyUnlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxLockDuration","type":"uint256"},{"internalType":"uint256","name":"maxLockMultiplier","type":"uint256"}],"name":"setLockMultiplierSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"}],"name":"setOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"manager","type":"address"}],"name":"setRewardManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"xTokenRewardsShare_","type":"uint256"}],"name":"setXTokenRewardsShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unboost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updatePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amountToWithdraw","type":"uint256"}],"name":"withdrawFromPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"xTokenRewardsShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"yieldBooster","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]