From 199ea5f1d539fec88e8b45d226a924126ccc5d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=96=B0=E5=88=9A?= <719802264@qq.com> Date: Fri, 29 Jan 2021 16:27:05 +0800 Subject: [PATCH] upload VDODO --- contracts/VDODO/VDODOChef.sol | 1057 +++++++++++++++++++++++++++++++++ 1 file changed, 1057 insertions(+) create mode 100644 contracts/VDODO/VDODOChef.sol diff --git a/contracts/VDODO/VDODOChef.sol b/contracts/VDODO/VDODOChef.sol new file mode 100644 index 0000000..fda7398 --- /dev/null +++ b/contracts/VDODO/VDODOChef.sol @@ -0,0 +1,1057 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +/** + * @title SafeMath + * @author DODO Breeder + * + * @notice Math operations with safety checks that revert on error + */ +library SafeMath { + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) { + return 0; + } + + uint256 c = a * b; + require(c / a == b, "MUL_ERROR"); + + return c; + } + + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "DIVIDING_ERROR"); + return a / b; + } + + function divCeil(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 quotient = div(a, b); + uint256 remainder = a - quotient * b; + if (remainder > 0) { + return quotient + 1; + } else { + return quotient; + } + } + + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SUB_ERROR"); + return a - b; + } + + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "ADD_ERROR"); + return c; + } + + function sqrt(uint256 x) internal pure returns (uint256 y) { + uint256 z = x / 2 + 1; + y = x; + while (z < y) { + y = z; + z = (x / z + z) / 2; + } + } +} + +pragma solidity 0.6.9; +/** + * @title DecimalMath + * @author DODO Breeder + * + * @notice Functions for fixed point number with 18 decimals + */ +library DecimalMath { + using SafeMath for uint256; + + uint256 internal constant ONE = 10**18; + uint256 internal constant ONE2 = 10**36; + + function mulFloor(uint256 target, uint256 d) internal pure returns (uint256) { + return target.mul(d) / (10**18); + } + + function mulCeil(uint256 target, uint256 d) internal pure returns (uint256) { + return target.mul(d).divCeil(10**18); + } + + function divFloor(uint256 target, uint256 d) internal pure returns (uint256) { + return target.mul(10**18).div(d); + } + + function divCeil(uint256 target, uint256 d) internal pure returns (uint256) { + return target.mul(10**18).divCeil(d); + } + + function reciprocalFloor(uint256 target) internal pure returns (uint256) { + return uint256(10**36).div(target); + } + + function reciprocalCeil(uint256 target) internal pure returns (uint256) { + return uint256(10**36).divCeil(target); + } +} +// File: @openzeppelin/contracts/access/Ownable.sol + + + +pragma solidity 0.6.9; +/** + * @title Ownable + * @author DODO Breeder + * + * @notice Ownership related functions + */ +contract Ownable { + address public _OWNER_; + address public _NEW_OWNER_; + + // ============ Events ============ + + event OwnershipTransferPrepared(address indexed previousOwner, address indexed newOwner); + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + // ============ Modifiers ============ + + modifier onlyOwner() { + require(msg.sender == _OWNER_, "NOT_OWNER"); + _; + } + + // ============ Functions ============ + + constructor() internal { + _OWNER_ = msg.sender; + emit OwnershipTransferred(address(0), _OWNER_); + } + + function transferOwnership(address newOwner) external onlyOwner { + emit OwnershipTransferPrepared(_OWNER_, newOwner); + _NEW_OWNER_ = newOwner; + } + + function claimOwnership() external { + require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM"); + emit OwnershipTransferred(_OWNER_, _NEW_OWNER_); + _OWNER_ = _NEW_OWNER_; + _NEW_OWNER_ = address(0); + } +} + + +pragma solidity 0.6.9; + +/** + * @title ReentrancyGuard + * @author DODO Breeder + * + * @notice Protect functions from Reentrancy Attack + */ +contract ReentrancyGuard { + // https://solidity.readthedocs.io/en/latest/control-structures.html?highlight=zero-state#scoping-and-declarations + // zero-state of _ENTERED_ is false + bool private _ENTERED_; + + modifier preventReentrant() { + require(!_ENTERED_, "REENTRANT"); + _ENTERED_ = true; + _; + _ENTERED_ = false; + } +} + +// File: @openzeppelin/contracts/token/ERC20/IERC20.sol + + + +pragma solidity 0.6.9; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +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); + + /** + * @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); +} + +pragma solidity 0.6.9; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address payable) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + +pragma solidity 0.6.9; +/** + * @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; + + 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)); + } + + /** + * @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 + + // 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: @openzeppelin/contracts/utils/Address.sol +pragma solidity 0.6.9; + +/** + * @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 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]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return _functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + 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"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + 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"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +pragma solidity 0.6.9; + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * We have followed general OpenZeppelin guidelines: functions revert instead + * of returning `false` on failure. This behavior is nonetheless conventional + * and does not conflict with the expectations of ERC20 applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +contract ERC20 is Context, IERC20 { + using SafeMath for uint256; + using Address for address; + + bool cantransfer; + uint256 private _totalSupply; + string private _name; + string private _symbol; + uint8 private _decimals; + + mapping (address => uint256) private _balances; + mapping (address => mapping (address => uint256)) private _allowances; + mapping(address => bool) public operater; + // ============ Modifiers ============ + modifier onlyOperater() { + require(cantransfer || operater[msg.sender] , "not allowed transfer"); + _; + } + + /** + * @dev Sets the values for {name} and {symbol}, initializes {decimals} with + * a default value of 18. + * + * To select a different value for {decimals}, use {_setupDecimals}. + * + * All three of these values are immutable: they can only be set once during + * construction. + */ + constructor (string memory name, string memory symbol) public { + _name = name; + _symbol = symbol; + _decimals = 18; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5,05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is + * called. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view returns (uint8) { + return _decimals; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view override returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public view virtual override returns (uint256) { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `recipient` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address recipient, uint256 amount) public virtual override returns (bool) { + _transfer(_msgSender(), recipient, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) public view virtual override returns (uint256) { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) { + _approve(_msgSender(), spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}; + * + * Requirements: + * - `sender` and `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + * - the caller must have allowance for ``sender``'s tokens of at least + * `amount`. + */ + function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { + _transfer(sender, recipient, amount); + _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount)); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { + _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { + _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue)); + return true; + } + + /** + * @dev Moves tokens `amount` from `sender` to `recipient`. + * + * This is internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `sender` cannot be the zero address. + * - `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + */ + function _transfer(address sender, address recipient, uint256 amount) internal onlyOperater virtual { + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(sender, recipient, amount); + + _balances[sender] = _balances[sender].sub(amount); + _balances[recipient] = _balances[recipient].add(amount); + emit Transfer(sender, recipient, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements + * + * - `to` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply = _totalSupply.add(amount); + _balances[account] = _balances[account].add(amount); + emit Transfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + _balances[account] = _balances[account].sub(amount); + _totalSupply = _totalSupply.sub(amount); + emit Transfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. + * + * This is internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve(address owner, address spender, uint256 amount) internal onlyOperater virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Sets {decimals} to a value other than the default one of 18. + * + * WARNING: This function should only be called from the constructor. Most + * applications that interact with token contracts will not expect + * {decimals} to ever change, and may work incorrectly if it does. + */ + function _setupDecimals(uint8 decimals_) internal { + _decimals = decimals_; + } + + function _setCantransfer(bool _cantransfer) internal { + cantransfer = _cantransfer; + } + + function _addOperation(address _operater) internal { + operater[_operater] = true; + } + function _removeOperation(address _operater) internal { + operater[_operater] = false; + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be to transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } +} +pragma solidity 0.6.9; +interface IGovernance { + function governanceCall(address account, uint256 amount,bytes calldata data) external returns (bool); + +} +pragma solidity 0.6.9; +contract SpToken is ERC20("StakingPowerToken", "SPT"), Ownable ,ReentrancyGuard{ + using SafeMath for uint256; + using SafeERC20 for IERC20; + + address govAddr; + IERC20 dodo; + + uint256 public alpha = 1; + uint256 public totalSp; + uint256 public totalOverdraft; + + uint256 public _DODOPERBLOCK_ = 1e18;//TODO + uint256 constant public _MAG_SP_AMOUNT_ = 10; + uint256 constant public _MAG_TOTALSP_AMOUNT_ = 110; + uint256 constant public _BASE_AMOUNT_ = 100; + + struct UserInfo { + uint256 dodoAmount; + address upline; + uint256 spAmount; + uint256 overdraft; + uint256 lastRewardBlock; + uint256 totalRedeem; + bool hasParticipateGov; //是否正在参与治理,是的话就不可以提币 + } + + mapping (address => UserInfo) public userInfo; + +// ============ Events ============ + event ParticipatoryGov(address indexed user, uint256 amount); + event Deposit(address indexed user,address indexed upline, uint256 amount); + event Redeem(address indexed user, uint256 amount); + event SetCantransfer(bool allowed); + event RemoveOperation(address indexed _operater); + event AddOperation(address indexed _operater); + + receive() external payable { + revert(); + } + // ============ Functions ============ + constructor( + address _govAddr, + address _dodo + + ) public { + govAddr = _govAddr; + dodo = IERC20(_dodo); + } + + + function mint(address _to, uint256 _amount) public onlyOwner { + _mint(_to, _amount); + } + function burn(address _to, uint256 amount) public onlyOwner{ + _burn(_to,amount); + } + function setCantransfer(bool _allowed) public onlyOwner { + _setCantransfer(_allowed); + emit SetCantransfer(_allowed); + } + function addOperationAddress(address _operationAddress) public onlyOwner { + _addOperation(_operationAddress); + emit AddOperation(_operationAddress); + } + function removeOperation(address _operationAddress) public onlyOwner { + _removeOperation(_operationAddress); + emit RemoveOperation(_operationAddress); + } + + function participatoryGov( + uint256 _amount, + bytes calldata _data + ) external preventReentrant { + UserInfo storage user = userInfo[msg.sender]; + require(user.spAmount>_amount,"no enough sp"); + if (_data.length > 0) + IGovernance(govAddr).governanceCall(msg.sender, _amount, _data); + user.spAmount = user.spAmount.sub(_amount); + user.hasParticipateGov = true; + emit ParticipatoryGov(msg.sender, _amount); + } + + //TODO _uplineAddress??? deposit again???? + //TODO round up /down + function deposit(uint256 _amount,address _uplineAddress) public preventReentrant{ + require(_amount>0,"must deposit greater than 0"); + + dodo.transferFrom(msg.sender, address(this), _amount); + + UserInfo storage user = userInfo[msg.sender]; + if(user.dodoAmount==0){ + user.lastRewardBlock = block.number; + } + user.dodoAmount = user.dodoAmount.add(_amount); + // accuDODO = _DODOPERBLOCK_*(block-lastRewardBlock) + uint256 accuDODO = _DODOPERBLOCK_ * (block.number.sub(user.lastRewardBlock)); + //TODO FIRST DEPOSIT??? + if(totalSp > 0){ + // alpha = alpha + accuDODO/totalSp (round down) + alpha = alpha.add(accuDODO.div(totalSp)); + } + + // 自己的sp + x/alpha + uint256 newSpAmount = _amount.div(alpha); + + _mint(msg.sender,newSpAmount); + // spToken.mint(msg.sender,newSpAmount); + + user.spAmount = user.spAmount.add(newSpAmount); + if(user.upline==address(0x0)){ + user.upline = _uplineAddress; + } + UserInfo storage uplineUser = userInfo[user.upline]; + // 上级sp +( x/alpha)* 0.1 (round up) + uplineUser.spAmount = uplineUser.spAmount.add( + _amount.mul(alpha) + .mul(_MAG_SP_AMOUNT_).div(_BASE_AMOUNT_)); + + // 上级DODO欠款 + x*0.1 (round up) + uint256 overdraft = _amount.mul(_MAG_SP_AMOUNT_).div(_BASE_AMOUNT_); + uplineUser.overdraft = uplineUser.overdraft.add(overdraft); + + totalOverdraft = totalOverdraft.add(overdraft); + // total sp + x/alpha*1.1 + totalSp = totalSp.add(_amount.div(alpha).mul(_MAG_TOTALSP_AMOUNT_).div(_BASE_AMOUNT_)); + emit Deposit(msg.sender,_uplineAddress, _amount); + } + //TODO round up /down + + function redeem(uint256 _amount) public preventReentrant{ + UserInfo storage user = userInfo[msg.sender]; + require(user.spAmount>_amount,"no enough sp token"); + require(!user.hasParticipateGov,"hasParticipateGov"); + + + // accuDODO = _DODOPERBLOCK_*(block-lastRewardBlock) + uint256 accuDODO = _DODOPERBLOCK_ * (block.number.sub(user.lastRewardBlock)); + // alpha = alpha + accuDODO/totalSp (round down) + alpha = alpha.add(accuDODO.div(totalSp)); + // 自己的sp - x + _burn(msg.sender,_amount); + // spToken.burn(msg.sender,_amount); + + user.spAmount = user.spAmount.sub(_amount); + + UserInfo storage uplineUser = userInfo[user.upline]; + // 上级sp - (x)*0.1(round down) + uplineUser.spAmount = uplineUser.spAmount.sub( + _amount.mul(_MAG_SP_AMOUNT_).div(_BASE_AMOUNT_)); + + // 上级DODO欠款 - x*alpha*0.1 (round down) + uint256 overdraft = _amount.mul(alpha).mul(_MAG_SP_AMOUNT_).div(_BASE_AMOUNT_); + uplineUser.overdraft = uplineUser.overdraft.sub(overdraft); + + totalOverdraft = totalOverdraft.sub(overdraft); + + // total sp - x*1.1 + totalSp = totalSp.sub(_amount.mul(_MAG_TOTALSP_AMOUNT_).div(_BASE_AMOUNT_)); + + user.lastRewardBlock = block.number; + + uint256 feeRatio = checkReward(_amount); + + // x * 80% transfer to user + uint256 receiveAmount = _amount.mul(_BASE_AMOUNT_.sub(feeRatio).div(_BASE_AMOUNT_)); + + dodo.safeTransferFrom(address(this), msg.sender, receiveAmount); + user.dodoAmount = user.dodoAmount.sub(receiveAmount); + user.totalRedeem = user.totalRedeem.add(receiveAmount); + + // alpha = alpha + x * 20% /totalSp + uint256 feeAmount = _amount.mul(feeRatio.div(_BASE_AMOUNT_)); + alpha = alpha.add(feeAmount.div(totalSp)); + + //TODO 3. 这部分税会继续拆成两部分,第一部分销毁,第二部分分给所有vDODO持有人 + + + emit Redeem(msg.sender, _amount); + } + + //TODO + function checkReward(uint256 _amount) internal returns(uint256) { + + // (x - 1)^2 / 81 + (y - 15)^2 / 100 = 1 (5≤ y ≤ 15) + + // y = 5 (x ≤ 1) + + // y = 15 (x ≥ 10) + } + + // balanceOf = sp-DODO欠款/alpha + function balanceOf(address _address) public view override returns (uint256 balance) { + UserInfo memory user = userInfo[_address]; + balance = user.spAmount.sub(user.overdraft.div(alpha)); + } + + function transfer(address recipient, uint256 amount) public virtual override returns (bool) { + _transfer(_msgSender(), recipient, amount); + return true; + } + + function _transfer(address sender, address recipient, uint256 _amount) internal onlyOperater virtual override { + require(sender != address(0), " transfer from the zero address"); + require(recipient != address(0), " transfer to the zero address"); + // require(balanceOf(from)≥amount) + require(balanceOf(sender) >= _amount,"no enough to sp transfer"); + UserInfo storage user = userInfo[sender]; + // sp[msg.sender] -= amount + user.spAmount = user.spAmount.sub(_amount); + + // sp[上级[from]] -= amount*0.1 (round down) + UserInfo storage uplineUser = userInfo[user.upline]; + uplineUser.spAmount = uplineUser.spAmount.sub(_amount.mul(_MAG_SP_AMOUNT_).div(_BASE_AMOUNT_)); + + UserInfo storage recipientUser = userInfo[recipient]; + // sp[to] += amount + recipientUser.spAmount = recipientUser.spAmount.add(_amount); + + UserInfo storage recipientUplineUser = userInfo[recipientUser.upline]; + recipientUplineUser.spAmount =recipientUplineUser.spAmount.add(_amount.mul(_MAG_SP_AMOUNT_).div(_BASE_AMOUNT_)); + emit Transfer(sender, recipient, _amount); + } + + // 可提取DODO数额 = sp*alpha - DODO欠款 + function canWithDraw(address _address) public view returns (uint256 withDrawAmount) { + UserInfo memory user = userInfo[_address]; + withDrawAmount = user.spAmount.mul(alpha).sub(user.overdraft); + } + + function checkUserInfo(address _userAddress) public view returns(uint256,address,uint256,uint256,uint256,uint256,bool) { + UserInfo memory user = userInfo[_userAddress]; + return (user.dodoAmount, user.upline, user.spAmount, user.overdraft,user.lastRewardBlock,user.totalRedeem,user.hasParticipateGov); + + } + + + +} +// deposit 是否需要输入上级地址 +// round up & round down +//vDODO的分红 +// +