文件 1 的 17:Address.sol
pragma solidity 0.6.8;
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"
);
return _functionCallWithValue(target, data, value, errorMessage);
}
function _functionCallWithValue(
address target,
bytes memory data,
uint256 weiValue,
string memory errorMessage
) private returns (bytes memory) {
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: weiValue}(
data
);
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 的 17:Context.sol
pragma solidity 0.6.8;
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 的 17:EnumerableSet.sol
pragma solidity 0.6.8;
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 AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value)
internal
returns (bool)
{
return _add(set._inner, bytes32(uint256(value)));
}
function remove(AddressSet storage set, address value)
internal
returns (bool)
{
return _remove(set._inner, bytes32(uint256(value)));
}
function contains(AddressSet storage set, address value)
internal
view
returns (bool)
{
return _contains(set._inner, bytes32(uint256(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(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));
}
}
文件 4 的 17:IERC165.sol
pragma solidity ^0.6.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 5 的 17:IERC20.sol
pragma solidity 0.6.8;
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
);
}
文件 6 的 17:IERC721.sol
pragma solidity ^0.6.2;
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
) 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;
}
文件 7 的 17:ITokenManager.sol
pragma solidity 0.6.8;
interface ITokenManager {
function mint(address _receiver, uint256 _amount) external;
function issue(uint256 _amount) external;
function assign(address _receiver, uint256 _amount) external;
function burn(address _holder, uint256 _amount) external;
function assignVested(
address _receiver,
uint256 _amount,
uint64 _start,
uint64 _cliff,
uint64 _vested,
bool _revokable
) external returns (uint256);
function revokeVesting(address _holder, uint256 _vestingId) external;
}
文件 8 的 17:IXStore.sol
pragma solidity 0.6.8;
import "./EnumerableSet.sol";
import "./Ownable.sol";
import "./SafeMath.sol";
import "./IXToken.sol";
import "./IERC721.sol";
import "./EnumerableSet.sol";
interface IXStore {
struct FeeParams {
uint256 ethBase;
uint256 ethStep;
}
struct BountyParams {
uint256 ethMax;
uint256 length;
}
struct Vault {
address xTokenAddress;
address nftAddress;
address manager;
IXToken xToken;
IERC721 nft;
EnumerableSet.UintSet holdings;
EnumerableSet.UintSet reserves;
mapping(uint256 => address) requester;
mapping(uint256 => bool) isEligible;
mapping(uint256 => bool) shouldReserve;
bool allowMintRequests;
bool flipEligOnRedeem;
bool negateEligibility;
bool isFinalized;
bool isClosed;
FeeParams mintFees;
FeeParams burnFees;
FeeParams dualFees;
BountyParams supplierBounty;
uint256 ethBalance;
uint256 tokenBalance;
bool isD2Vault;
address d2AssetAddress;
IERC20 d2Asset;
uint256 d2Holdings;
}
function isExtension(address addr) external view returns (bool);
function randNonce() external view returns (uint256);
function vaultsLength() external view returns (uint256);
function xTokenAddress(uint256 vaultId) external view returns (address);
function nftAddress(uint256 vaultId) external view returns (address);
function manager(uint256 vaultId) external view returns (address);
function xToken(uint256 vaultId) external view returns (IXToken);
function nft(uint256 vaultId) external view returns (IERC721);
function holdingsLength(uint256 vaultId) external view returns (uint256);
function holdingsContains(uint256 vaultId, uint256 elem)
external
view
returns (bool);
function holdingsAt(uint256 vaultId, uint256 index)
external
view
returns (uint256);
function reservesLength(uint256 vaultId) external view returns (uint256);
function reservesContains(uint256 vaultId, uint256 elem)
external
view
returns (bool);
function reservesAt(uint256 vaultId, uint256 index)
external
view
returns (uint256);
function requester(uint256 vaultId, uint256 id)
external
view
returns (address);
function isEligible(uint256 vaultId, uint256 id)
external
view
returns (bool);
function shouldReserve(uint256 vaultId, uint256 id)
external
view
returns (bool);
function allowMintRequests(uint256 vaultId) external view returns (bool);
function flipEligOnRedeem(uint256 vaultId) external view returns (bool);
function negateEligibility(uint256 vaultId) external view returns (bool);
function isFinalized(uint256 vaultId) external view returns (bool);
function isClosed(uint256 vaultId) external view returns (bool);
function mintFees(uint256 vaultId) external view returns (uint256, uint256);
function burnFees(uint256 vaultId) external view returns (uint256, uint256);
function dualFees(uint256 vaultId) external view returns (uint256, uint256);
function supplierBounty(uint256 vaultId)
external
view
returns (uint256, uint256);
function ethBalance(uint256 vaultId) external view returns (uint256);
function tokenBalance(uint256 vaultId) external view returns (uint256);
function isD2Vault(uint256 vaultId) external view returns (bool);
function d2AssetAddress(uint256 vaultId) external view returns (address);
function d2Asset(uint256 vaultId) external view returns (IERC20);
function d2Holdings(uint256 vaultId) external view returns (uint256);
function setXTokenAddress(uint256 vaultId, address _xTokenAddress) external;
function setNftAddress(uint256 vaultId, address _assetAddress) external;
function setManager(uint256 vaultId, address _manager) external;
function setXToken(uint256 vaultId) external;
function setNft(uint256 vaultId) external;
function holdingsAdd(uint256 vaultId, uint256 elem) external;
function holdingsRemove(uint256 vaultId, uint256 elem) external;
function reservesAdd(uint256 vaultId, uint256 elem) external;
function reservesRemove(uint256 vaultId, uint256 elem) external;
function setRequester(uint256 vaultId, uint256 id, address _requester)
external;
function setIsEligible(uint256 vaultId, uint256 id, bool _bool) external;
function setShouldReserve(uint256 vaultId, uint256 id, bool _shouldReserve)
external;
function setAllowMintRequests(uint256 vaultId, bool isAllowed) external;
function setFlipEligOnRedeem(uint256 vaultId, bool flipElig) external;
function setNegateEligibility(uint256 vaultId, bool negateElig) external;
function setIsFinalized(uint256 vaultId, bool _isFinalized) external;
function setIsClosed(uint256 vaultId, bool _isClosed) external;
function setMintFees(uint256 vaultId, uint256 ethBase, uint256 ethStep)
external;
function setBurnFees(uint256 vaultId, uint256 ethBase, uint256 ethStep)
external;
function setDualFees(uint256 vaultId, uint256 ethBase, uint256 ethStep)
external;
function setSupplierBounty(uint256 vaultId, uint256 ethMax, uint256 length)
external;
function setEthBalance(uint256 vaultId, uint256 _ethBalance) external;
function setTokenBalance(uint256 vaultId, uint256 _tokenBalance) external;
function setIsD2Vault(uint256 vaultId, bool _isD2Vault) external;
function setD2AssetAddress(uint256 vaultId, address _assetAddress) external;
function setD2Asset(uint256 vaultId) external;
function setD2Holdings(uint256 vaultId, uint256 _d2Holdings) external;
function setIsExtension(address addr, bool _isExtension) external;
function setRandNonce(uint256 _randNonce) external;
function addNewVault() external returns (uint256);
}
文件 9 的 17:IXToken.sol
pragma solidity 0.6.8;
import "./IERC20.sol";
interface IXToken is IERC20 {
function owner() external returns (address);
function burn(uint256 amount) external;
function burnFrom(address account, uint256 amount) external;
function mint(address to, uint256 amount) external;
function changeName(string calldata name) external;
function changeSymbol(string calldata symbol) external;
function setVaultAddress(address vaultAddress) external;
function transferOwnership(address newOwner) external;
}
文件 10 的 17:Initializable.sol
pragma solidity >=0.4.24 <0.7.0;
contract Initializable {
bool private initialized;
bool private initializing;
modifier initializer() {
require(
initializing || isConstructor() || !initialized,
"Contract instance has already been initialized"
);
bool isTopLevelCall = !initializing;
if (isTopLevelCall) {
initializing = true;
initialized = true;
}
_;
if (isTopLevelCall) {
initializing = false;
}
}
function isConstructor() private view returns (bool) {
address self = address(this);
uint256 cs;
assembly {
cs := extcodesize(self)
}
return cs == 0;
}
uint256[50] private ______gap;
}
文件 11 的 17:Ownable.sol
pragma solidity 0.6.8;
import "./Context.sol";
import "./Initializable.sol";
contract Ownable is Context, Initializable {
address private _owner;
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
function initOwnable() internal virtual initializer {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(
newOwner != address(0),
"Ownable: new owner is the zero address"
);
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
文件 12 的 17:ReentrancyGuard.sol
pragma solidity 0.6.8;
import "./Initializable.sol";
contract ReentrancyGuard is Initializable {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function initReentrancyGuard() internal {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 13 的 17:SafeERC20.sol
pragma solidity 0.6.8;
import "./IERC20.sol";
import "./SafeMath.sol";
import "./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"
);
}
}
}
文件 14 的 17:SafeMath.sol
pragma solidity 0.6.8;
library SafeMath {
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) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage)
internal
pure
returns (uint256)
{
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
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) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage)
internal
pure
returns (uint256)
{
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage)
internal
pure
returns (uint256)
{
require(b != 0, errorMessage);
return a % b;
}
}
文件 15 的 17:TokenAppController.sol
pragma solidity 0.6.8;
import "./Ownable.sol";
import "./ITokenManager.sol";
contract TokenAppController is Ownable {
ITokenManager public tokenManager;
address public tokenManagerAddr;
function initTAC() internal {
initOwnable();
}
function setTokenManager(address tokenManagerAddress) internal onlyOwner {
tokenManagerAddr = tokenManagerAddress;
tokenManager = ITokenManager(tokenManagerAddr);
}
function callMint(address _receiver, uint256 _amount) internal onlyOwner {
tokenManager.mint(_receiver, _amount);
}
function callIssue(uint256 _amount) internal onlyOwner {
tokenManager.issue(_amount);
}
function callAssign(address _receiver, uint256 _amount) internal onlyOwner {
tokenManager.assign(_receiver, _amount);
}
function callBurn(address _holder, uint256 _amount) internal onlyOwner {
tokenManager.burn(_holder, _amount);
}
function callAssignVested(
address _receiver,
uint256 _amount,
uint64 _start,
uint64 _cliff,
uint64 _vested,
bool _revokable
) internal returns (uint256) {
return
tokenManager.assignVested(
_receiver,
_amount,
_start,
_cliff,
_vested,
_revokable
);
}
function callRevokeVesting(address _holder, uint256 _vestingId)
internal
onlyOwner
{
tokenManager.revokeVesting(_holder, _vestingId);
}
}
文件 16 的 17:XBouties.sol
pragma solidity 0.6.8;
import "./TokenAppController.sol";
import "./IERC20.sol";
import "./IERC721.sol";
import "./IXStore.sol";
import "./SafeMath.sol";
import "./SafeERC20.sol";
import "./ReentrancyGuard.sol";
contract XBounties is TokenAppController, ReentrancyGuard {
using SafeMath for uint256;
using SafeERC20 for IERC20;
uint256 public constant BASE = 10**18;
uint256 public interval = 15 * 60;
uint256 public start = 1608667200;
uint64 public vestedUntil = 1609876800;
IERC20 public nftxToken;
address payable public daoMultiSig;
struct Bounty {
address tokenContract;
uint256 nftxPrice;
uint256 paidOut;
uint256 payoutCap;
}
event NewBountyAdded(uint256 bountyId);
event BountyFilled(
uint256 bountyId,
uint256 nftxAmount,
uint256 assetAmount,
address sender,
uint64 start,
uint64 cliff,
uint64 vested
);
event NftxPriceSet(uint256 bountyId, uint256 newNftxPrice);
event PayoutCapSet(uint256 bountyId, uint256 newCap);
event BountyClosed(uint256 bountyId);
event EthWithdrawn(uint256 amount);
event Erc20Withdrawn(address tokenContract, uint256 amount);
event Erc721Withdrawn(address nftContract, uint256 tokenId);
Bounty[] internal bounties;
constructor(
address _tokenManager,
address payable _daoMultiSig,
address _nftxToken,
address _xStore
) public {
initTAC();
setTokenManager(_tokenManager);
daoMultiSig = _daoMultiSig;
nftxToken = IERC20(_nftxToken);
IXStore xStore = IXStore(_xStore);
createEthBounty(130 * BASE, 65000 * BASE);
createEthBounty(65 * BASE, 65000 * BASE);
createEthBounty(BASE.mul(130).div(3), 65000 * BASE);
createBounty(
xStore.xTokenAddress(0),
390 * BASE,
31200 * BASE
);
createBounty(
xStore.xTokenAddress(15),
520 * BASE,
15600 * BASE
);
createBounty(
xStore.xTokenAddress(1),
585 * BASE,
14625 * BASE
);
createBounty(
xStore.xTokenAddress(2),
1950 * BASE,
15600 * BASE
);
createBounty(
xStore.xTokenAddress(3),
8450 * BASE,
16900 * BASE
);
createBounty(
xStore.xTokenAddress(4),
130 * BASE,
7800 * BASE
);
createBounty(
xStore.xTokenAddress(5),
780 * BASE,
7800 * BASE
);
createBounty(
xStore.xTokenAddress(6),
3900 * BASE,
7800 * BASE
);
createBounty(
xStore.xTokenAddress(7),
325 * BASE.div(10),
6760 * BASE
);
createBounty(
xStore.xTokenAddress(8),
39 * BASE,
6240 * BASE
);
createBounty(
xStore.xTokenAddress(9),
6175 * BASE,
6175 * BASE
);
createBounty(
xStore.xTokenAddress(10),
195 * BASE.div(10),
7800 * BASE
);
createBounty(
xStore.xTokenAddress(11),
26 * BASE,
7800 * BASE
);
createBounty(
xStore.xTokenAddress(12),
195 * BASE,
7800 * BASE
);
createBounty(
xStore.xTokenAddress(13),
1300 * BASE,
23400 * BASE
);
createBounty(
xStore.xTokenAddress(14),
650 * BASE,
11700 * BASE
);
}
function setStart(uint256 newStart) public onlyOwner {
start = newStart;
}
function setInterval(uint256 newInterval) public onlyOwner {
interval = newInterval;
}
function setVestedUntil(uint64 newTime) public onlyOwner {
vestedUntil = newTime;
}
function getBountyInfo(uint256 bountyId)
public
view
returns (address, uint256, uint256, uint256)
{
require(bountyId < bounties.length, "Invalid bountyId");
return (
bounties[bountyId].tokenContract,
bounties[bountyId].nftxPrice,
bounties[bountyId].paidOut,
bounties[bountyId].payoutCap
);
}
function getMaxPayout() public view returns (uint256) {
uint256 tMinus4 = start.sub(interval.mul(4));
uint256 tMinus3 = start.sub(interval.mul(3));
uint256 tMinus2 = start.sub(interval.mul(2));
uint256 tMinus1 = start.sub(interval.mul(1));
uint256 tm4Max = 0;
uint256 tm3Max = 50 * BASE;
uint256 tm2Max = 500 * BASE;
uint256 tm1Max = 5000 * BASE;
uint256 tm0Max = 50000 * BASE;
if (now < tMinus4) {
return 0;
} else if (now < tMinus3) {
uint256 progressBigNum = now.sub(tMinus4).mul(BASE).div(interval);
uint256 addedPayout = tm3Max.sub(tm4Max).mul(progressBigNum).div(
BASE
);
return tm4Max.add(addedPayout);
} else if (now < tMinus2) {
uint256 progressBigNum = now.sub(tMinus3).mul(BASE).div(interval);
uint256 addedPayout = tm2Max.sub(tm3Max).mul(progressBigNum).div(
BASE
);
return tm3Max.add(addedPayout);
} else if (now < tMinus1) {
uint256 progressBigNum = now.sub(tMinus2).mul(BASE).div(interval);
uint256 addedPayout = tm1Max.sub(tm2Max).mul(progressBigNum).div(
BASE
);
return tm2Max.add(addedPayout);
} else if (now < start) {
uint256 progressBigNum = now.sub(tMinus1).mul(BASE).div(interval);
uint256 addedPayout = tm0Max.sub(tm1Max).mul(progressBigNum).div(
BASE
);
return tm1Max.add(addedPayout);
} else {
return tm0Max;
}
}
function getBountiesLength() public view returns (uint256) {
return bounties.length;
}
function getIsEth(uint256 bountyId) public view returns (bool) {
require(bountyId < bounties.length, "Invalid bountyId");
return bounties[bountyId].tokenContract == address(0);
}
function getTokenContract(uint256 bountyId) public view returns (address) {
require(bountyId < bounties.length, "Invalid bountyId");
return bounties[bountyId].tokenContract;
}
function getNftxPrice(uint256 bountyId) public view returns (uint256) {
require(bountyId < bounties.length, "Invalid bountyId");
return bounties[bountyId].nftxPrice;
}
function getPayoutCap(uint256 bountyId) public view returns (uint256) {
require(bountyId < bounties.length, "Invalid bountyId");
return bounties[bountyId].payoutCap;
}
function getPaidOut(uint256 bountyId) public view returns (uint256) {
require(bountyId < bounties.length, "Invalid bountyId");
return bounties[bountyId].paidOut;
}
function setNftxPrice(uint256 bountyId, uint256 newPrice) public onlyOwner {
require(bountyId < bounties.length, "Invalid bountyId");
bounties[bountyId].nftxPrice = newPrice;
emit NftxPriceSet(bountyId, newPrice);
}
function setPayoutCap(uint256 bountyId, uint256 newCap) public onlyOwner {
require(bountyId < bounties.length, "Invalid bountyId");
bounties[bountyId].payoutCap = newCap;
emit PayoutCapSet(bountyId, newCap);
}
function createEthBounty(uint256 nftxPricePerEth, uint256 amountOfEth)
public
onlyOwner
{
createBounty(address(0), nftxPricePerEth, amountOfEth);
}
function createBounty(address token, uint256 nftxPrice, uint256 payoutCap)
public
onlyOwner
{
Bounty memory newBounty;
newBounty.tokenContract = token;
newBounty.nftxPrice = nftxPrice;
newBounty.payoutCap = payoutCap;
bounties.push(newBounty);
uint256 bountyId = bounties.length.sub(1);
emit NewBountyAdded(bountyId);
}
function closeBounty(uint256 bountyId) public onlyOwner {
require(bountyId < bounties.length, "Invalid bountyId");
bounties[bountyId].payoutCap = bounties[bountyId].paidOut;
emit BountyClosed(bountyId);
}
function fillBounty(uint256 bountyId, uint256 amountBeingSent)
public
payable
nonReentrant
{
_fillBountyCustom(
bountyId,
amountBeingSent,
vestedUntil - 2,
vestedUntil - 1,
vestedUntil
);
}
function _fillBountyCustom(
uint256 bountyId,
uint256 donationSize,
uint64 _start,
uint64 cliff,
uint64 vested
) internal {
require(cliff >= vestedUntil - 1 && vested >= vestedUntil, "Not valid");
require(bountyId < bounties.length, "Invalid bountyId");
Bounty storage bounty = bounties[bountyId];
uint256 rewardCap = getMaxPayout();
require(rewardCap > 0, "Must wait for cap to be lifted");
uint256 remainingNftx = bounty.payoutCap.sub(bounty.paidOut);
require(remainingNftx > 0, "Bounty is already finished");
uint256 requestedNftx = donationSize.mul(bounty.nftxPrice).div(BASE);
uint256 willGive = remainingNftx < requestedNftx
? remainingNftx
: rewardCap < requestedNftx
? rewardCap
: requestedNftx;
uint256 willTake = donationSize.mul(willGive).div(requestedNftx);
if (getIsEth(bountyId)) {
require(msg.value >= willTake, "Value sent is insufficient");
if (msg.value > willTake) {
address payable _sender = msg.sender;
_sender.transfer(msg.value.sub(willTake));
}
daoMultiSig.transfer(willTake);
} else {
IERC20 fundToken = IERC20(bounty.tokenContract);
fundToken.safeTransferFrom(msg.sender, daoMultiSig, willTake);
}
if (now > vested) {
nftxToken.safeTransfer(msg.sender, willGive);
} else {
nftxToken.safeTransfer(tokenManagerAddr, willGive);
callAssignVested(
msg.sender,
willGive,
_start,
cliff,
vested,
false
);
}
bounty.paidOut = bounty.paidOut.add(willGive);
emit BountyFilled(
bountyId,
willGive,
willTake,
msg.sender,
_start,
cliff,
vested
);
}
function withdrawEth(uint256 amount) public onlyOwner {
address payable sender = msg.sender;
sender.transfer(amount);
emit EthWithdrawn(amount);
}
function withdrawErc20(address tokenContract, uint256 amount)
public
onlyOwner
{
IERC20 token = IERC20(tokenContract);
token.safeTransfer(msg.sender, amount);
emit Erc20Withdrawn(tokenContract, amount);
}
function withdrawErc721(address nftContract, uint256 tokenId)
public
onlyOwner
{
IERC721 nft = IERC721(nftContract);
nft.safeTransferFrom(address(this), msg.sender, tokenId);
emit Erc721Withdrawn(nftContract, tokenId);
}
}
文件 17 的 17:XBoutiesRinkeby.sol
pragma solidity 0.6.8;
import "./TokenAppController.sol";
import "./IERC20.sol";
import "./IERC721.sol";
import "./IXStore.sol";
import "./SafeMath.sol";
import "./SafeERC20.sol";
import "./ReentrancyGuard.sol";
contract XBountiesRinkeby is TokenAppController, ReentrancyGuard {
using SafeMath for uint256;
using SafeERC20 for IERC20;
uint256 public constant BASE = 10**18;
uint256 public interval = 15 * 60;
uint256 public start = 1608580800;
uint64 public vestedUntil = 1609876800;
IERC20 public nftxToken;
address payable public daoMultiSig;
struct Bounty {
address tokenContract;
uint256 nftxPrice;
uint256 paidOut;
uint256 payoutCap;
}
event NewBountyAdded(uint256 bountyId);
event BountyFilled(
uint256 bountyId,
uint256 nftxAmount,
uint256 assetAmount,
address sender,
uint64 start,
uint64 cliff,
uint64 vested
);
event NftxPriceSet(uint256 bountyId, uint256 newNftxPrice);
event PayoutCapSet(uint256 bountyId, uint256 newCap);
event BountyClosed(uint256 bountyId);
event EthWithdrawn(uint256 amount);
event Erc20Withdrawn(address tokenContract, uint256 amount);
event Erc721Withdrawn(address nftContract, uint256 tokenId);
Bounty[] internal bounties;
constructor(
address _tokenManager,
address payable _daoMultiSig,
address _nftxToken,
address _xStore
) public {
initTAC();
setTokenManager(_tokenManager);
daoMultiSig = _daoMultiSig;
nftxToken = IERC20(_nftxToken);
IXStore xStore = IXStore(_xStore);
createEthBounty(130 * BASE, 65000 * BASE);
createEthBounty(65 * BASE, 65000 * BASE);
createEthBounty(BASE.mul(130).div(3), 65000 * BASE);
createBounty(
xStore.xTokenAddress(0),
390 * BASE,
31200 * BASE
);
createBounty(
xStore.xTokenAddress(1),
585 * BASE,
14625 * BASE
);
createBounty(
xStore.xTokenAddress(2),
1950 * BASE,
15600 * BASE
);
createBounty(
xStore.xTokenAddress(3),
8450 * BASE,
16900 * BASE
);
createBounty(
xStore.xTokenAddress(4),
130 * BASE,
7800 * BASE
);
createBounty(
xStore.xTokenAddress(5),
780 * BASE,
7800 * BASE
);
createBounty(
xStore.xTokenAddress(6),
3900 * BASE,
7800 * BASE
);
createBounty(
xStore.xTokenAddress(7),
26 * BASE,
5850 * BASE
);
createBounty(
xStore.xTokenAddress(8),
39 * BASE,
5850 * BASE
);
createBounty(
xStore.xTokenAddress(9),
6175 * BASE,
6175 * BASE
);
createBounty(
xStore.xTokenAddress(10),
20 * BASE,
6175 * BASE
);
createBounty(
xStore.xTokenAddress(11),
26 * BASE,
6175 * BASE
);
createBounty(
xStore.xTokenAddress(12),
195 * BASE,
6175 * BASE
);
createBounty(
xStore.xTokenAddress(13),
1300 * BASE,
26000 * BASE
);
createBounty(
xStore.xTokenAddress(14),
455 * BASE,
10010 * BASE
);
}
function setStart(uint256 newStart) public onlyOwner {
start = newStart;
}
function setInterval(uint256 newInterval) public onlyOwner {
interval = newInterval;
}
function setVestedUntil(uint64 newTime) public onlyOwner {
vestedUntil = newTime;
}
function getBountyInfo(uint256 bountyId)
public
view
returns (address, uint256, uint256, uint256)
{
require(bountyId < bounties.length, "Invalid bountyId");
return (
bounties[bountyId].tokenContract,
bounties[bountyId].nftxPrice,
bounties[bountyId].paidOut,
bounties[bountyId].payoutCap
);
}
function getMaxPayout() public view returns (uint256) {
uint256 tMinus4 = start.sub(interval.mul(4));
uint256 tMinus3 = start.sub(interval.mul(3));
uint256 tMinus2 = start.sub(interval.mul(2));
uint256 tMinus1 = start.sub(interval.mul(1));
uint256 tm4Max = 0;
uint256 tm3Max = 50 * BASE;
uint256 tm2Max = 500 * BASE;
uint256 tm1Max = 5000 * BASE;
uint256 tm0Max = 50000 * BASE;
if (now < tMinus4) {
return 0;
} else if (now < tMinus3) {
uint256 progressBigNum = now.sub(tMinus4).mul(BASE).div(interval);
uint256 addedPayout = tm3Max.sub(tm4Max).mul(progressBigNum).div(
BASE
);
return tm4Max.add(addedPayout);
} else if (now < tMinus2) {
uint256 progressBigNum = now.sub(tMinus3).mul(BASE).div(interval);
uint256 addedPayout = tm2Max.sub(tm3Max).mul(progressBigNum).div(
BASE
);
return tm3Max.add(addedPayout);
} else if (now < tMinus1) {
uint256 progressBigNum = now.sub(tMinus2).mul(BASE).div(interval);
uint256 addedPayout = tm1Max.sub(tm2Max).mul(progressBigNum).div(
BASE
);
return tm2Max.add(addedPayout);
} else if (now < start) {
uint256 progressBigNum = now.sub(tMinus1).mul(BASE).div(interval);
uint256 addedPayout = tm0Max.sub(tm1Max).mul(progressBigNum).div(
BASE
);
return tm1Max.add(addedPayout);
} else {
return tm0Max;
}
}
function getBountiesLength() public view returns (uint256) {
return bounties.length;
}
function getIsEth(uint256 bountyId) public view returns (bool) {
require(bountyId < bounties.length, "Invalid bountyId");
return bounties[bountyId].tokenContract == address(0);
}
function getTokenContract(uint256 bountyId) public view returns (address) {
require(bountyId < bounties.length, "Invalid bountyId");
return bounties[bountyId].tokenContract;
}
function getNftxPrice(uint256 bountyId) public view returns (uint256) {
require(bountyId < bounties.length, "Invalid bountyId");
return bounties[bountyId].nftxPrice;
}
function getPayoutCap(uint256 bountyId) public view returns (uint256) {
require(bountyId < bounties.length, "Invalid bountyId");
return bounties[bountyId].payoutCap;
}
function getPaidOut(uint256 bountyId) public view returns (uint256) {
require(bountyId < bounties.length, "Invalid bountyId");
return bounties[bountyId].paidOut;
}
function setNftxPrice(uint256 bountyId, uint256 newPrice) public onlyOwner {
require(bountyId < bounties.length, "Invalid bountyId");
bounties[bountyId].nftxPrice = newPrice;
emit NftxPriceSet(bountyId, newPrice);
}
function setPayoutCap(uint256 bountyId, uint256 newCap) public onlyOwner {
require(bountyId < bounties.length, "Invalid bountyId");
bounties[bountyId].payoutCap = newCap;
emit PayoutCapSet(bountyId, newCap);
}
function createEthBounty(uint256 nftxPricePerEth, uint256 amountOfEth)
public
onlyOwner
{
createBounty(address(0), nftxPricePerEth, amountOfEth);
}
function createBounty(address token, uint256 nftxPrice, uint256 payoutCap)
public
onlyOwner
{
Bounty memory newBounty;
newBounty.tokenContract = token;
newBounty.nftxPrice = nftxPrice;
newBounty.payoutCap = payoutCap;
bounties.push(newBounty);
uint256 bountyId = bounties.length.sub(1);
emit NewBountyAdded(bountyId);
}
function closeBounty(uint256 bountyId) public onlyOwner {
require(bountyId < bounties.length, "Invalid bountyId");
bounties[bountyId].payoutCap = bounties[bountyId].paidOut;
emit BountyClosed(bountyId);
}
function fillBounty(uint256 bountyId, uint256 amountBeingSent)
public
payable
nonReentrant
{
_fillBountyCustom(
bountyId,
amountBeingSent,
vestedUntil - 2,
vestedUntil - 1,
vestedUntil
);
}
function _fillBountyCustom(
uint256 bountyId,
uint256 donationSize,
uint64 _start,
uint64 cliff,
uint64 vested
) internal {
require(cliff >= vestedUntil - 1 && vested >= vestedUntil, "Not valid");
require(bountyId < bounties.length, "Invalid bountyId");
Bounty storage bounty = bounties[bountyId];
uint256 rewardCap = getMaxPayout();
require(rewardCap > 0, "Must wait for cap to be lifted");
uint256 remainingNftx = bounty.payoutCap.sub(bounty.paidOut);
require(remainingNftx > 0, "Bounty is already finished");
uint256 requestedNftx = donationSize.mul(bounty.nftxPrice).div(BASE);
uint256 willGive = remainingNftx < requestedNftx
? remainingNftx
: rewardCap < requestedNftx
? rewardCap
: requestedNftx;
uint256 willTake = donationSize.mul(willGive).div(requestedNftx);
if (getIsEth(bountyId)) {
require(msg.value >= willTake, "Value sent is insufficient");
if (msg.value > willTake) {
address payable _sender = msg.sender;
_sender.transfer(msg.value.sub(willTake));
}
daoMultiSig.transfer(willTake);
} else {
IERC20 fundToken = IERC20(bounty.tokenContract);
fundToken.safeTransferFrom(msg.sender, daoMultiSig, willTake);
}
if (now > vested) {
nftxToken.safeTransfer(msg.sender, willGive);
} else {
nftxToken.safeTransfer(tokenManagerAddr, willGive);
callAssignVested(
msg.sender,
willGive,
_start,
cliff,
vested,
false
);
}
bounty.paidOut = bounty.paidOut.add(willGive);
emit BountyFilled(
bountyId,
willGive,
willTake,
msg.sender,
_start,
cliff,
vested
);
}
function withdrawEth(uint256 amount) public onlyOwner {
address payable sender = msg.sender;
sender.transfer(amount);
emit EthWithdrawn(amount);
}
function withdrawErc20(address tokenContract, uint256 amount)
public
onlyOwner
{
IERC20 token = IERC20(tokenContract);
token.safeTransfer(msg.sender, amount);
emit Erc20Withdrawn(tokenContract, amount);
}
function withdrawErc721(address nftContract, uint256 tokenId)
public
onlyOwner
{
IERC721 nft = IERC721(nftContract);
nft.safeTransferFrom(address(this), msg.sender, tokenId);
emit Erc721Withdrawn(nftContract, tokenId);
}
}
{
"compilationTarget": {
"XBouties.sol": "XBounties"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_tokenManager","type":"address"},{"internalType":"address payable","name":"_daoMultiSig","type":"address"},{"internalType":"address","name":"_nftxToken","type":"address"},{"internalType":"address","name":"_xStore","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"bountyId","type":"uint256"}],"name":"BountyClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"bountyId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nftxAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint64","name":"start","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"cliff","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"vested","type":"uint64"}],"name":"BountyFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Erc20Withdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"nftContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Erc721Withdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EthWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"bountyId","type":"uint256"}],"name":"NewBountyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"bountyId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newNftxPrice","type":"uint256"}],"name":"NftxPriceSet","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":"uint256","name":"bountyId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCap","type":"uint256"}],"name":"PayoutCapSet","type":"event"},{"inputs":[],"name":"BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bountyId","type":"uint256"}],"name":"closeBounty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nftxPrice","type":"uint256"},{"internalType":"uint256","name":"payoutCap","type":"uint256"}],"name":"createBounty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftxPricePerEth","type":"uint256"},{"internalType":"uint256","name":"amountOfEth","type":"uint256"}],"name":"createEthBounty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"daoMultiSig","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bountyId","type":"uint256"},{"internalType":"uint256","name":"amountBeingSent","type":"uint256"}],"name":"fillBounty","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getBountiesLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bountyId","type":"uint256"}],"name":"getBountyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bountyId","type":"uint256"}],"name":"getIsEth","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxPayout","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bountyId","type":"uint256"}],"name":"getNftxPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bountyId","type":"uint256"}],"name":"getPaidOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bountyId","type":"uint256"}],"name":"getPayoutCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bountyId","type":"uint256"}],"name":"getTokenContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nftxToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newInterval","type":"uint256"}],"name":"setInterval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bountyId","type":"uint256"},{"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"setNftxPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bountyId","type":"uint256"},{"internalType":"uint256","name":"newCap","type":"uint256"}],"name":"setPayoutCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newStart","type":"uint256"}],"name":"setStart","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newTime","type":"uint64"}],"name":"setVestedUntil","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"start","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManager","outputs":[{"internalType":"contract ITokenManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenManagerAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vestedUntil","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawErc20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"withdrawErc721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawEth","outputs":[],"stateMutability":"nonpayable","type":"function"}]