/***
* ██████╗ ███████╗ ██████╗ ██████╗
* ██╔══██╗██╔════╝██╔════╝ ██╔═══██╗
* ██║ ██║█████╗ ██║ ███╗██║ ██║
* ██║ ██║██╔══╝ ██║ ██║██║ ██║
* ██████╔╝███████╗╚██████╔╝╚██████╔╝
* ╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝
*
* https://dego.finance
* MIT License
* ===========
*
* Copyright (c) 2020 dego
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/// File: @openzeppelin/contracts/math/Math.sol
pragma solidity ^0.5.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow, so we distribute
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
// File: @openzeppelin/contracts/math/SafeMath.sol
pragma solidity ^0.5.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*
* _Available since v2.4.0._
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
// File: @openzeppelin/contracts/introspection/IERC165.sol
pragma solidity ^0.5.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// File: @openzeppelin/contracts/token/ERC721/IERC721.sol
pragma solidity ^0.5.0;
/**
* @dev Required interface of an ERC721 compliant contract.
*/
contract 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);
/**
* @dev Returns the number of NFTs in `owner`'s account.
*/
function balanceOf(address owner) public view returns (uint256 balance);
/**
* @dev Returns the owner of the NFT specified by `tokenId`.
*/
function ownerOf(uint256 tokenId) public view returns (address owner);
/**
* @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
* another (`to`).
*
*
*
* Requirements:
* - `from`, `to` cannot be zero.
* - `tokenId` must be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this
* NFT by either {approve} or {setApprovalForAll}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public;
/**
* @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
* another (`to`).
*
* Requirements:
* - If the caller is not `from`, it must be approved to move this NFT by
* either {approve} or {setApprovalForAll}.
*/
function transferFrom(address from, address to, uint256 tokenId) public;
function approve(address to, uint256 tokenId) public;
function getApproved(uint256 tokenId) public view returns (address operator);
function setApprovalForAll(address operator, bool _approved) public;
function isApprovedForAll(address owner, address operator) public view returns (bool);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
}
// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
pragma solidity ^0.5.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
contract IERC721Receiver {
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a {IERC721-safeTransferFrom}. This function MUST return the function selector,
* otherwise the caller will revert the transaction. The selector to be
* returned can be obtained as `this.onERC721Received.selector`. This
* function MAY throw to revert and reject the transfer.
* Note: the ERC721 contract address is always the message sender.
* @param operator The address which called `safeTransferFrom` function
* @param from The address which previously owned the token
* @param tokenId The NFT identifier which is being transferred
* @param data Additional data with no specified format
* @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
*/
function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
public returns (bytes4);
}
// File: contracts/interface/IERC20.sol
pragma solidity ^0.5.5;
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see {ERC20Detailed}.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
// add mint interface by dego
function mint(address account, uint amount) external;
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// File: contracts/interface/IUniswapV2Router01.sol
pragma solidity ^0.5.5;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
// File: contracts/interface/IUniswapV2Pair.sol
pragma solidity >=0.5.0;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
// File: contracts/library/UniswapV2Library.sol
pragma solidity >=0.5.0;
library UniswapV2Library {
using SafeMath for uint256;
// returns sorted token addresses, used to handle return values from pairs sorted in this order
function sortTokens(address tokenA, address tokenB)
internal
pure
returns (address token0, address token1)
{
require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES');
(token0, token1) = tokenA < tokenB
? (tokenA, tokenB)
: (tokenB, tokenA);
require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS');
}
// calculates the CREATE2 address for a pair without making any external calls
function pairFor(
address factory,
address tokenA,
address tokenB
) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(
uint256(
keccak256(
abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'd0d4c4cd0848c93cb4fd1f498d7013ee6bfb25783ea21593d5834f5d250ece66' // init code hash
)
)
)
);
}
// fetches and sorts the reserves for a pair
function getReserves(
address factory,
address tokenA,
address tokenB
) internal view returns (uint256 reserveA, uint256 reserveB) {
(address token0, ) = sortTokens(tokenA, tokenB);
(uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(
pairFor(factory, tokenA, tokenB)
)
.getReserves();
(reserveA, reserveB) = tokenA == token0
? (reserve0, reserve1)
: (reserve1, reserve0);
}
// given some amount of an asset and pair reserves, returns an equivalent amount of the other asset
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) internal pure returns (uint256 amountB) {
require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT');
require(
reserveA > 0 && reserveB > 0,
'UniswapV2Library: INSUFFICIENT_LIQUIDITY'
);
amountB = amountA.mul(reserveB) / reserveA;
}
// given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
function getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) internal pure returns (uint256 amountOut) {
require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT');
require(
reserveIn > 0 && reserveOut > 0,
'UniswapV2Library: INSUFFICIENT_LIQUIDITY'
);
uint256 amountInWithFee = amountIn.mul(997);
uint256 numerator = amountInWithFee.mul(reserveOut);
uint256 denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
// given an output amount of an asset and pair reserves, returns a required input amount of the other asset
function getAmountIn(
uint256 amountOut,
uint256 reserveIn,
uint256 reserveOut
) internal pure returns (uint256 amountIn) {
require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT');
require(
reserveIn > 0 && reserveOut > 0,
'UniswapV2Library: INSUFFICIENT_LIQUIDITY'
);
uint256 numerator = reserveIn.mul(amountOut).mul(1000);
uint256 denominator = reserveOut.sub(amountOut).mul(997);
amountIn = (numerator / denominator).add(1);
}
// performs chained getAmountOut calculations on any number of pairs
function getAmountsOut(
address factory,
uint256 amountIn,
address[] memory path
) internal view returns (uint256[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint256[](path.length);
amounts[0] = amountIn;
for (uint256 i; i < path.length - 1; i++) {
(uint256 reserveIn, uint256 reserveOut) = getReserves(
factory,
path[i],
path[i + 1]
);
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
}
}
// performs chained getAmountIn calculations on any number of pairs
function getAmountsIn(
address factory,
uint256 amountOut,
address[] memory path
) internal view returns (uint256[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint256[](path.length);
amounts[amounts.length - 1] = amountOut;
for (uint256 i = path.length - 1; i > 0; i--) {
(uint256 reserveIn, uint256 reserveOut) = getReserves(
factory,
path[i - 1],
path[i]
);
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
}
}
}
// File: @openzeppelin/contracts/utils/Address.sol
pragma solidity ^0.5.5;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
/**
* @dev Converts an `address` into `address payable`. Note that this is
* simply a type cast: the actual underlying value is not changed.
*
* _Available since v2.4.0._
*/
function toPayable(address account) internal pure returns (address payable) {
return address(uint160(account));
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*
* _Available since v2.4.0._
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-call-value
(bool success, ) = recipient.call.value(amount)("");
require(success, "Address: unable to send value, recipient may have reverted");
}
}
// File: contracts/library/SafeERC20.sol
pragma solidity ^0.5.5;
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
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 {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
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));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves.
// A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data.
// solhint-disable-next-line max-line-length
require(address(token).isContract(), "SafeERC20: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
// File: contracts/library/ReentrancyGuard.sol
pragma solidity ^0.5.0;
contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() internal {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
function initReentrancyStatus() internal {
_status = _NOT_ENTERED;
}
}
// File: contracts/market/NFTMarketV2.sol
pragma solidity ^0.5.5;
pragma experimental ABIEncoderV2;
contract NFTMarketV2 is IERC721Receiver, ReentrancyGuard {
using SafeERC20 for IERC20;
using SafeMath for uint256;
// --- Data ---
bool private initialized; // Flag of initialize data
IERC20 public _dandy = IERC20(0x0);
struct SalesObject {
uint256 id;
uint256 tokenId;
uint256 startTime;
uint256 durationTime;
uint256 maxPrice;
uint256 minPrice;
uint256 finalPrice;
uint8 status;
address payable seller;
address payable buyer;
IERC721 nft;
}
uint256 public _salesAmount = 0;
SalesObject[] _salesObjects;
uint256 public _minDurationTime = 5 minutes;
mapping(address => bool) public _seller;
mapping(address => bool) public _verifySeller;
mapping(address => bool) public _supportNft;
bool public _isStartUserSales;
bool public _isRewardSellerDandy = false;
bool public _isRewardBuyerDandy = false;
uint256 public _sellerRewardDandy = 1e15;
uint256 public _buyerRewardDandy = 1e15;
uint256 public _tipsFeeRate = 20;
uint256 public _baseRate = 1000;
address payable _tipsFeeWallet;
event eveSales(
uint256 indexed id,
uint256 tokenId,
address buyer,
uint256 finalPrice,
uint256 tipsFee
);
event eveNewSales(
uint256 indexed id,
uint256 tokenId,
address seller,
address nft,
address buyer,
uint256 startTime,
uint256 durationTime,
uint256 maxPrice,
uint256 minPrice,
uint256 finalPrice
);
event eveCancelSales(
uint256 indexed id,
uint256 tokenId
);
event eveNFTReceived(address operator, address from, uint256 tokenId, bytes data);
address public _governance;
event GovernanceTransferred(address indexed previousOwner, address indexed newOwner);
mapping(uint256 => address) public _saleOnCurrency;
mapping(address => bool) public _supportCurrency;
mapping(address => SupportBuyCurrency) public _supportBuyCurrency;
mapping(uint256=>uint256) public deflationBaseRates;
mapping(uint256=>address) public routers;
// IUniswapV2Router01[] public routers;
struct SupportBuyCurrency {
bool status;
bool isDeflation;
uint256 deflationRate;
}
event eveSupportCurrency(
address currency,
bool support
);
event eveSupportBuyCurrency(
address currency,
bool status,
bool isDeflation,
uint256 deflationRate
);
event eveDeflationBaseRate(
uint256 deflationBaseRate
);
constructor() public {
_governance = tx.origin;
}
function() external payable {}
// --- Init ---
function initialize(
address payable tipsFeeWallet,
uint256 minDurationTime,
uint256 tipsFeeRate,
uint256 baseRate
) public {
require(!initialized, "initialize: Already initialized!");
_governance = msg.sender;
_tipsFeeWallet = tipsFeeWallet;
_minDurationTime = minDurationTime;
_tipsFeeRate = tipsFeeRate;
_baseRate = baseRate;
initReentrancyStatus();
initialized = true;
}
modifier onlyGovernance {
require(msg.sender == _governance, "not governance");
_;
}
function setGovernance(address governance) public onlyGovernance
{
require(governance != address(0), "new governance the zero address");
emit GovernanceTransferred(_governance, governance);
_governance = governance;
}
/**
* check address
*/
modifier validAddress( address addr ) {
require(addr != address(0x0));
_;
}
modifier checkindex(uint index) {
require(index <= _salesObjects.length, "overflow");
_;
}
modifier checkSupportBuyCurrendy(address currency) {
SupportBuyCurrency memory supportBuyCurrency = _supportBuyCurrency[currency];
require(supportBuyCurrency.status == true, "not support currency");
_;
}
modifier checkTime(uint index) {
require(index <= _salesObjects.length, "overflow");
SalesObject storage obj = _salesObjects[index];
require(obj.startTime <= now, "!open");
_;
}
modifier mustNotSellingOut(uint index) {
require(index <= _salesObjects.length, "overflow");
SalesObject storage obj = _salesObjects[index];
require(obj.buyer == address(0x0) && obj.status == 0, "sry, selling out");
_;
}
modifier onlySalesOwner(uint index) {
require(index <= _salesObjects.length, "overflow");
SalesObject storage obj = _salesObjects[index];
require(obj.seller == msg.sender || msg.sender == _governance, "author & governance");
_;
}
function seize(IERC20 asset) external onlyGovernance returns (uint256 balance) {
balance = asset.balanceOf(address(this));
asset.safeTransfer(_governance, balance);
}
function setIUniswapV2Router01(address router_) public onlyGovernance {
routers[0] = router_;
}
function setSellerRewardDandy(uint256 rewardDandy) public onlyGovernance {
_sellerRewardDandy = rewardDandy;
}
function setBuyerRewardDandy(uint256 rewardDandy) public onlyGovernance {
_buyerRewardDandy = rewardDandy;
}
function addSupportNft(address nft) public onlyGovernance validAddress(nft) {
_supportNft[nft] = true;
}
function removeSupportNft(address nft) public onlyGovernance validAddress(nft) {
_supportNft[nft] = false;
}
function addSeller(address seller) public onlyGovernance validAddress(seller) {
_seller[seller] = true;
}
function removeSeller(address seller) public onlyGovernance validAddress(seller) {
_seller[seller] = false;
}
function addSupportCurrency(address erc20) public onlyGovernance {
require(_supportCurrency[erc20] == false, "the currency have support");
_supportCurrency[erc20] = true;
emit eveSupportCurrency(erc20, true);
}
function removeSupportCurrency(address erc20) public onlyGovernance {
require(_supportCurrency[erc20], "the currency can not remove");
_supportCurrency[erc20] = false;
emit eveSupportCurrency(erc20, false);
}
function setSupportBuyCurrency(address erc20,bool status,bool isDeflation,uint256 deflationRate ) public onlyGovernance {
if (isDeflation) {
require(deflationRate >0, "deflationRate 0");
}
_supportBuyCurrency[erc20] = SupportBuyCurrency(status,isDeflation,deflationRate);
emit eveSupportBuyCurrency(erc20,status,isDeflation,deflationRate);
}
function setDeflationBaseRate(uint256 deflationRate_) public onlyGovernance {
deflationBaseRates[0] = deflationRate_;
emit eveDeflationBaseRate(deflationRate_);
}
function addVerifySeller(address seller) public onlyGovernance validAddress(seller) {
_verifySeller[seller] = true;
}
function removeVerifySeller(address seller) public onlyGovernance validAddress(seller) {
_verifySeller[seller] = false;
}
function setIsStartUserSales(bool isStartUserSales) public onlyGovernance {
_isStartUserSales = isStartUserSales;
}
function setIsRewardSellerDandy(bool isRewardSellerDandy) public onlyGovernance {
_isRewardSellerDandy = isRewardSellerDandy;
}
function setIsRewardBuyerDandy(bool isRewardBuyerDandy) public onlyGovernance {
_isRewardBuyerDandy = isRewardBuyerDandy;
}
function setMinDurationTime(uint256 durationTime) public onlyGovernance {
_minDurationTime = durationTime;
}
function setTipsFeeWallet(address payable wallet) public onlyGovernance {
_tipsFeeWallet = wallet;
}
function setDandyAddress(address addr) external onlyGovernance validAddress(addr) {
_dandy = IERC20(addr);
}
function setBaseRate(uint256 rate) external onlyGovernance {
_baseRate = rate;
}
function setTipsFeeRate(uint256 rate) external onlyGovernance {
_tipsFeeRate = rate;
}
function getSalesEndTime(uint index)
external
view
checkindex(index)
returns (uint256)
{
SalesObject storage obj = _salesObjects[index];
return obj.startTime.add(obj.durationTime);
}
function getSales(uint index) external view checkindex(index) returns(SalesObject memory) {
return _salesObjects[index];
}
function getSalesPrice(uint index)
external
view
checkindex(index)
returns (uint256)
{
SalesObject storage obj = _salesObjects[index];
if(obj.buyer != address(0x0) || obj.status == 1) {
return obj.finalPrice;
} else {
if(obj.startTime.add(obj.durationTime) < now) {
return obj.minPrice;
} else if (obj.startTime >= now) {
return obj.maxPrice;
} else {
uint256 per = obj.maxPrice.sub(obj.minPrice).div(obj.durationTime);
return obj.maxPrice.sub(now.sub(obj.startTime).mul(per));
}
}
}
function isVerifySeller(uint index) public view checkindex(index) returns(bool) {
SalesObject storage obj = _salesObjects[index];
return _verifySeller[obj.seller];
}
function cancelSales(uint index) external checkindex(index) onlySalesOwner(index) mustNotSellingOut(index) nonReentrant {
require(_isStartUserSales || _seller[msg.sender] == true, "cannot sales");
SalesObject storage obj = _salesObjects[index];
obj.status = 2;
obj.nft.safeTransferFrom(address(this), obj.seller, obj.tokenId);
emit eveCancelSales(index, obj.tokenId);
}
function startSales(uint256 tokenId,
uint256 maxPrice,
uint256 minPrice,
uint256 startTime,
uint256 durationTime,
address nft,
address currency)
external
nonReentrant
validAddress(nft)
returns(uint)
{
require(tokenId != 0, "invalid token");
require(startTime.add(durationTime) > now, "invalid start time");
require(durationTime >= _minDurationTime, "invalid duration");
require(maxPrice >= minPrice, "invalid price");
require(_isStartUserSales || _seller[msg.sender] == true || _supportNft[nft] == true, "cannot sales");
require(_supportCurrency[currency] == true, "not support currency");
IERC721(nft).safeTransferFrom(msg.sender, address(this), tokenId);
_salesAmount++;
SalesObject memory obj;
obj.id = _salesAmount;
obj.tokenId = tokenId;
obj.seller = msg.sender;
obj.nft = IERC721(nft);
obj.buyer = address(0x0);
obj.startTime = startTime;
obj.durationTime = durationTime;
obj.maxPrice = maxPrice;
obj.minPrice = minPrice;
obj.finalPrice = 0;
obj.status = 0;
_saleOnCurrency[obj.id] = currency;
if (_salesObjects.length == 0) {
SalesObject memory zeroObj;
zeroObj.tokenId = 0;
zeroObj.seller = address(0x0);
zeroObj.nft = IERC721(0x0);
zeroObj.buyer = address(0x0);
zeroObj.startTime = 0;
zeroObj.durationTime = 0;
zeroObj.maxPrice = 0;
zeroObj.minPrice = 0;
zeroObj.finalPrice = 0;
zeroObj.status = 2;
_salesObjects.push(zeroObj);
}
_salesObjects.push(obj);
if(_isRewardSellerDandy || _verifySeller[msg.sender]) {
_dandy.mint(msg.sender, _sellerRewardDandy);
}
uint256 tmpMaxPrice = maxPrice;
uint256 tmpMinPrice = minPrice;
emit eveNewSales(obj.id, tokenId, msg.sender, nft, address(0x0), startTime, durationTime, tmpMaxPrice, tmpMinPrice, 0);
return _salesAmount;
}
function buy(uint index, address currency_)
public
nonReentrant
mustNotSellingOut(index)
checkTime(index)
checkSupportBuyCurrendy(currency_)
payable
{
SalesObject storage obj = _salesObjects[index];
require(_isStartUserSales || _seller[msg.sender] == true, "cannot sales");
address currencyAddr = _saleOnCurrency[obj.id];
uint256 price = this.getSalesPrice(index);
uint256 tipsFee = price.mul(_tipsFeeRate).div(_baseRate);
uint256 purchase = price.sub(tipsFee);
if (address(currencyAddr) == currency_){
if (currencyAddr == address(0x0)){
require (msg.value >= this.getSalesPrice(index), "umm..... your price is too low");
uint256 returnBack = msg.value.sub(price);
if(returnBack > 0) {
msg.sender.transfer(returnBack);
}
if(tipsFee > 0) {
_tipsFeeWallet.transfer(tipsFee);
}
obj.seller.transfer(purchase);
}else{
IERC20(currencyAddr).safeTransferFrom(msg.sender, _tipsFeeWallet, tipsFee);
IERC20(currencyAddr).safeTransferFrom(msg.sender, obj.seller, purchase);
}
}else{
if (currencyAddr == address(0x0)){
uint256 ethAmount = tokenToEth(currency_, price);
// uint256 ethAmount = 0;
// SupportBuyCurrency memory supportBuyCurrency = _supportBuyCurrency[currency_];
// if (supportBuyCurrency.isDeflation) {
// ethAmount = exactTokenToEth(currency_, price);
// } else {
// ethAmount = tokenToExactEth(currency_, price);
// }
require (ethAmount >= price, "umm..... your price is too low");
uint256 returnBack = ethAmount.sub(price).add(msg.value);
if(returnBack > 0) {
msg.sender.transfer(returnBack);
}
if(tipsFee > 0) {
_tipsFeeWallet.transfer(tipsFee);
}
obj.seller.transfer(purchase);
}else{
// transfer
require(false, "not support token");
}
}
if(_isRewardBuyerDandy || _verifySeller[obj.seller]) {
_dandy.mint(msg.sender, _buyerRewardDandy);
}
obj.nft.safeTransferFrom(address(this), msg.sender, obj.tokenId);
obj.buyer = msg.sender;
obj.finalPrice = price;
obj.status = 1;
// fire event
emit eveSales(index, obj.tokenId, msg.sender, price, tipsFee);
}
function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) public returns (bytes4) {
//only receive the _nft staff
if(address(this) != operator) {
//invalid from nft
return 0;
}
//success
emit eveNFTReceived(operator, from, tokenId, data);
return bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
}
// function exactTokenToEth(address erc20Token_, uint256 amountOutMin) internal returns (uint256) {
// address erc20Token = erc20Token_;
// SupportBuyCurrency memory supportBuyCurrency = _supportBuyCurrency[erc20Token];
// address[] memory path = new address[](2);
// path[0] = erc20Token;
// path[1] = getRouter().WETH();
// uint256[] memory amounts = UniswapV2Library.getAmountsIn(getRouter().factory(), amountOutMin, path);
// uint256 amountInMax = amounts[0];
// uint256 amountIn = amountInMax.mul(getDeflationBaseRate()).div(supportBuyCurrency.deflationRate).mul(getDeflationBaseRate()).div(supportBuyCurrency.deflationRate);
// uint256 balanceBefore = IERC20(erc20Token).balanceOf(address(this));
// IERC20(erc20Token).safeTransferFrom(msg.sender, address(this), amountIn);
// uint256 balanceAfter = IERC20(erc20Token).balanceOf(address(this));
// amountIn = balanceAfter.sub(balanceBefore);
// IERC20(erc20Token).approve(address(getRouter()), amountIn);
// uint256 ethBefore = address(this).balance;
// getRouter().swapExactTokensForETHSupportingFeeOnTransferTokens(amountIn, 0, path, address(this), block.timestamp);
// uint256 ethAfter = address(this).balance;
// uint256 balanceLast = IERC20(erc20Token).balanceOf(address(this));
// uint256 supAmount = balanceLast.sub(balanceBefore);
// if (supAmount>0){
// IERC20(erc20Token).safeTransfer(msg.sender, supAmount);
// }
// return ethAfter.sub(ethBefore);
// }
// function tokenToExactEth(address erc20Token, uint256 amountOut) internal returns (uint256) {
// address[] memory path = new address[](2);
// path[0] = erc20Token;
// path[1] = getRouter().WETH();
// uint256[] memory amounts = UniswapV2Library.getAmountsIn(getRouter().factory(), amountOut, path);
// uint256 amountInMax = amounts[0];
// uint256 balanceBefore = IERC20(erc20Token).balanceOf(address(this));
// IERC20(erc20Token).safeTransferFrom(msg.sender, address(this), amountInMax);
// uint256 balanceAfter = IERC20(erc20Token).balanceOf(address(this));
// amountInMax = balanceAfter.sub(balanceBefore);
// IERC20(erc20Token).approve(address(getRouter()), amountInMax);
// uint256 ethBefore = address(this).balance;
// getRouter().swapTokensForExactETH(amountOut, amountInMax, path, address(this), block.timestamp);
// uint256 ethAfter = address(this).balance;
// uint256 balanceLast = IERC20(erc20Token).balanceOf(address(this));
// uint256 supAmount = balanceLast.sub(balanceBefore);
// if (supAmount>0){
// IERC20(erc20Token).safeTransfer(msg.sender, supAmount);
// }
// return ethAfter.sub(ethBefore);
// }
function tokenToEth(address erc20Token, uint256 amountOut) private returns(uint256) {
address[] memory path = new address[](2);
path[0] = erc20Token;
path[1] = getRouter().WETH();
uint256[] memory amounts = UniswapV2Library.getAmountsIn(getRouter().factory(), amountOut, path);
uint256 amountIn = amounts[0];
SupportBuyCurrency memory supportBuyCurrency = _supportBuyCurrency[erc20Token];
if (supportBuyCurrency.isDeflation) {
amountIn = amountIn.mul(getDeflationBaseRate()).div(supportBuyCurrency.deflationRate).mul(getDeflationBaseRate()).div(supportBuyCurrency.deflationRate);
}
uint256 balanceBefore = IERC20(erc20Token).balanceOf(address(this));
IERC20(erc20Token).safeTransferFrom(msg.sender, address(this), amountIn);
uint256 balanceAfter = IERC20(erc20Token).balanceOf(address(this));
amountIn = balanceAfter.sub(balanceBefore);
IERC20(erc20Token).approve(address(getRouter()), amountIn);
uint256 ethBefore = address(this).balance;
if (supportBuyCurrency.isDeflation) {
getRouter().swapExactTokensForETHSupportingFeeOnTransferTokens(amountIn, 0, path, address(this), block.timestamp);
} else {
getRouter().swapTokensForExactETH(amountOut, amountIn, path, address(this), block.timestamp);
}
uint256 ethAfter = address(this).balance;
uint256 balanceLast = IERC20(erc20Token).balanceOf(address(this));
uint256 supAmount = balanceLast.sub(balanceBefore);
if (supAmount>0){
IERC20(erc20Token).safeTransfer(msg.sender, supAmount);
}
return ethAfter.sub(ethBefore);
}
function getDeflationBaseRate() public view returns(uint256) {
return deflationBaseRates[0];
}
function getRouter() public view returns(IUniswapV2Router01) {
return IUniswapV2Router01(routers[0]);
}
}
{
"compilationTarget": {
"NFTMarketV2.sol": "NFTMarketV2"
},
"evmVersion": "petersburg",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":false,"inputs":[{"name":"router_","type":"address"}],"name":"setIUniswapV2Router01","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"_sellerRewardDandy","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"isRewardSellerDandy","type":"bool"}],"name":"setIsRewardSellerDandy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"erc20","type":"address"}],"name":"removeSupportCurrency","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"operator","type":"address"},{"name":"from","type":"address"},{"name":"tokenId","type":"uint256"},{"name":"data","type":"bytes"}],"name":"onERC721Received","outputs":[{"name":"","type":"bytes4"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"_buyerRewardDandy","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_governance","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"rate","type":"uint256"}],"name":"setBaseRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"_supportNft","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_isRewardBuyerDandy","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"rate","type":"uint256"}],"name":"setTipsFeeRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"durationTime","type":"uint256"}],"name":"setMinDurationTime","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"_supportBuyCurrency","outputs":[{"name":"status","type":"bool"},{"name":"isDeflation","type":"bool"},{"name":"deflationRate","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_isRewardSellerDandy","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"isRewardBuyerDandy","type":"bool"}],"name":"setIsRewardBuyerDandy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"routers","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"tipsFeeWallet","type":"address"},{"name":"minDurationTime","type":"uint256"},{"name":"tipsFeeRate","type":"uint256"},{"name":"baseRate","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"index","type":"uint256"}],"name":"getSalesPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"_supportCurrency","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"deflationBaseRates","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"_seller","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"rewardDandy","type":"uint256"}],"name":"setSellerRewardDandy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"index","type":"uint256"}],"name":"getSales","outputs":[{"components":[{"name":"id","type":"uint256"},{"name":"tokenId","type":"uint256"},{"name":"startTime","type":"uint256"},{"name":"durationTime","type":"uint256"},{"name":"maxPrice","type":"uint256"},{"name":"minPrice","type":"uint256"},{"name":"finalPrice","type":"uint256"},{"name":"status","type":"uint8"},{"name":"seller","type":"address"},{"name":"buyer","type":"address"},{"name":"nft","type":"address"}],"name":"","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_isStartUserSales","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"nft","type":"address"}],"name":"removeSupportNft","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"seller","type":"address"}],"name":"removeSeller","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"_minDurationTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"index","type":"uint256"},{"name":"currency_","type":"address"}],"name":"buy","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"rewardDandy","type":"uint256"}],"name":"setBuyerRewardDandy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"_baseRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"index","type":"uint256"}],"name":"cancelSales","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"_salesAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"setDandyAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wallet","type":"address"}],"name":"setTipsFeeWallet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"erc20","type":"address"}],"name":"addSupportCurrency","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getDeflationBaseRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"seller","type":"address"}],"name":"addVerifySeller","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"governance","type":"address"}],"name":"setGovernance","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"erc20","type":"address"},{"name":"status","type":"bool"},{"name":"isDeflation","type":"bool"},{"name":"deflationRate","type":"uint256"}],"name":"setSupportBuyCurrency","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRouter","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"_saleOnCurrency","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"seller","type":"address"}],"name":"removeVerifySeller","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"_tipsFeeRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"isStartUserSales","type":"bool"}],"name":"setIsStartUserSales","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"nft","type":"address"}],"name":"addSupportNft","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"_verifySeller","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"deflationRate_","type":"uint256"}],"name":"setDeflationBaseRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"seller","type":"address"}],"name":"addSeller","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"index","type":"uint256"}],"name":"isVerifySeller","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"tokenId","type":"uint256"},{"name":"maxPrice","type":"uint256"},{"name":"minPrice","type":"uint256"},{"name":"startTime","type":"uint256"},{"name":"durationTime","type":"uint256"},{"name":"nft","type":"address"},{"name":"currency","type":"address"}],"name":"startSales","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"index","type":"uint256"}],"name":"getSalesEndTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_dandy","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"asset","type":"address"}],"name":"seize","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"id","type":"uint256"},{"indexed":false,"name":"tokenId","type":"uint256"},{"indexed":false,"name":"buyer","type":"address"},{"indexed":false,"name":"finalPrice","type":"uint256"},{"indexed":false,"name":"tipsFee","type":"uint256"}],"name":"eveSales","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"id","type":"uint256"},{"indexed":false,"name":"tokenId","type":"uint256"},{"indexed":false,"name":"seller","type":"address"},{"indexed":false,"name":"nft","type":"address"},{"indexed":false,"name":"buyer","type":"address"},{"indexed":false,"name":"startTime","type":"uint256"},{"indexed":false,"name":"durationTime","type":"uint256"},{"indexed":false,"name":"maxPrice","type":"uint256"},{"indexed":false,"name":"minPrice","type":"uint256"},{"indexed":false,"name":"finalPrice","type":"uint256"}],"name":"eveNewSales","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"id","type":"uint256"},{"indexed":false,"name":"tokenId","type":"uint256"}],"name":"eveCancelSales","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"operator","type":"address"},{"indexed":false,"name":"from","type":"address"},{"indexed":false,"name":"tokenId","type":"uint256"},{"indexed":false,"name":"data","type":"bytes"}],"name":"eveNFTReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"GovernanceTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"currency","type":"address"},{"indexed":false,"name":"support","type":"bool"}],"name":"eveSupportCurrency","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"currency","type":"address"},{"indexed":false,"name":"status","type":"bool"},{"indexed":false,"name":"isDeflation","type":"bool"},{"indexed":false,"name":"deflationRate","type":"uint256"}],"name":"eveSupportBuyCurrency","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"deflationBaseRate","type":"uint256"}],"name":"eveDeflationBaseRate","type":"event"}]