// File: contracts/msd/MSDControllerV2.sol



// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "@openzeppelin/contracts-upgradeable/utils/EnumerableSetUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";

import "./MSD.sol";

/**
 * @dev Interface for Minters, minters now can be iMSD and MSDS
 */
interface IMinter {
    function totalMint() external returns (uint256);
}

/**
 * @title dForce's Multi-currency Stable Debt Token Controller
 * @author dForce
 */

contract MSDControllerV2 is Initializable, Ownable {
    using SafeMathUpgradeable for uint256;
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;

    /// @dev EnumerableSet of all msdTokens
    EnumerableSetUpgradeable.AddressSet internal msdTokens;

    // @notice Mapping of msd tokens to corresponding minters
    mapping(address => EnumerableSetUpgradeable.AddressSet) internal msdMinters;

    struct TokenData {
        // System earning from borrow interest
        uint256 earning;
        // System debt from saving interest
        uint256 debt;
    }

    // @notice Mapping of msd tokens to corresponding TokenData
    mapping(address => TokenData) public msdTokenData;

    // @notice Mapping of msd minters to corresponding msd token mintage cap
    // @dev Each minter now typically iMSD can only mint 1 msd token
    /*
     *  The mint cap of the msd minter, will be checked in mintMSD()
     *  -1 means there is no limit on the cap
     *  0 means the msd token can not be mint any more
     */
    mapping(address => mapping(address => uint256)) public mintCaps;

    /**
     * @dev Emitted when `token` is added into msdTokens.
     */
    event MSDAdded(address token);

    /**
     * @dev Emitted when `minter` is added into `tokens`'s minters.
     */
    event MinterAdded(address token, address minter);

    /**
     * @dev Emitted when `minter` is removed from `tokens`'s minters.
     */
    event MinterRemoved(address token, address minter);

    /**
     * @dev Emitted when reserve is withdrawn from `token`.
     */
    event ReservesWithdrawn(
        address owner,
        address token,
        uint256 amount,
        uint256 oldTotalReserves,
        uint256 newTotalReserves
    );

    /// @dev Emitted when msd token minter's mint cap is changed
    event NewMintCap(
        address token,
        address minter,
        uint256 oldMintCap,
        uint256 newMintCap
    );

    /**
     * @notice Expects to call only once to initialize the MSD controller.
     */
    function initialize() external initializer {
        __Ownable_init();
    }

    /**
     * @notice Ensure this is a MSD Controller contract.
     */
    function isMSDController() external pure returns (bool) {
        return true;
    }

    /**
     * @dev Throws if token is not in msdTokens
     */
    function _checkMSD(address _token) internal view {
        require(hasMSD(_token), "token is not a valid MSD token");
    }

    /**
     * @dev Throws if token is not a valid MSD token.
     */
    modifier onlyMSD(address _token) {
        _checkMSD(_token);
        _;
    }

    /**
     * @dev Throws if called by any account other than the _token's minters.
     */
    modifier onlyMSDMinter(address _token, address caller) {
        _checkMSD(_token);

        require(
            msdMinters[_token].contains(caller),
            "onlyMinter: caller is not the token's minter"
        );

        _;
    }

    function _addMSDInternal(address _token) internal {
        require(_token != address(0), "MSD token cannot be a zero address");
        if (msdTokens.add(_token)) {
            emit MSDAdded(_token);
        }
    }

    function _addMinterInternal(address _token, address _minter) internal {
        require(_minter != address(0), "minter cannot be a zero address");

        if (msdMinters[_token].add(_minter)) {
            emit MinterAdded(_token, _minter);
        }
    }

    function _removeMinterInternal(address _token, address _minter) internal {
        require(_minter != address(0), "minter cannot be a zero address");

        if (msdMinters[_token].remove(_minter)) {
            emit MinterRemoved(_token, _minter);
        }
    }

    function _setMintCapInternal(
        address _token,
        address _minter,
        uint256 _newMintCap
    ) internal {
        uint256 oldMintCap = mintCaps[_token][_minter];

        if (oldMintCap != _newMintCap) {
            mintCaps[_token][_minter] = _newMintCap;
            emit NewMintCap(_token, _minter, oldMintCap, _newMintCap);
        }
    }

    function _addMintersInternal(
        address _token,
        address[] calldata _minters,
        uint256[] calldata _mintCaps
    ) internal {
        require(
            _minters.length == _mintCaps.length,
            "Length of _minters and _mintCaps mismatch"
        );

        uint256 _len = _minters.length;
        for (uint256 i = 0; i < _len; i++) {
            _addMinterInternal(_token, _minters[i]);
            _setMintCapInternal(_token, _minters[i], _mintCaps[i]);
        }
    }

    /**
     * @notice Add `_token` into msdTokens, and add `_minters` into minters along with `_mintCaps`.
     * If `_token` have not been in msdTokens, emits a `MSDTokenAdded` event.
     * If _minter in `_minters` have not been in msd Token's minters, emits a `MinterAdded` event.
     * If cap in `_mintCaps` has changed, emits a `NewMintCap` event.
     *
     * @param _token The msd token to add
     * @param _minters The addresses to add as msd token's minters
     * @param _mintCaps The mint caps to set for minters
     *
     * Requirements:
     * - the caller must be `owner`.
     */
    function _addMSD(
        address _token,
        address[] calldata _minters,
        uint256[] calldata _mintCaps
    ) external onlyOwner {
        _addMSDInternal(_token);
        _addMintersInternal(_token, _minters, _mintCaps);
    }

    /**
     * @notice Add `_minters` into minters along with `_mintCaps`.
     * If _minter in `_minters` have not been in msd Token's minters, emits a `MinterAdded` event.
     * If cap in `_mintCaps` has changed, emits a `NewMintCap` event.
     *
     * @param _token The msd token to add minters
     * @param _minters The addresses to add as msd token's minters
     * @param _mintCaps The mint caps to set for minters
     *
     * Requirements:
     * - the caller must be `owner`.
     */
    function _addMinters(
        address _token,
        address[] calldata _minters,
        uint256[] calldata _mintCaps
    ) external onlyOwner onlyMSD(_token) {
        _addMintersInternal(_token, _minters, _mintCaps);
    }

    /**
     * @notice Remove `minters` from minters and reset mint cap to 0.
     * If `minter` is minters, emits a `MinterRemoved` event.
     *
     * @param _minters The minters to remove
     *
     * Requirements:
     * - the caller must be `owner`, `_token` must be a MSD Token.
     */
    function _removeMinters(address _token, address[] calldata _minters)
        external
        onlyOwner
        onlyMSD(_token)
    {
        uint256 _len = _minters.length;
        for (uint256 i = 0; i < _len; i++) {
            _removeMinterInternal(_token, _minters[i]);
            _setMintCapInternal(_token, _minters[i], 0);
        }
    }

    /**
     * @notice set `_mintCaps` for `_token`'s `_minters`, emits a `NewMintCap` event.
     *
     * @param _token The msd token to set
     * @param _minters The msd token's minters' addresses to set
     * @param _mintCaps The mint caps to set for minters
     *
     * Requirements:
     * - the caller must be `owner`.
     */
    function _setMintCaps(
        address _token,
        address[] calldata _minters,
        uint256[] calldata _mintCaps
    ) external onlyOwner onlyMSD(_token) {
        require(
            _minters.length == _mintCaps.length,
            "Length of _minters and _mintCaps mismatch"
        );

        uint256 _len = _minters.length;
        for (uint256 i = 0; i < _len; i++) {
            require(
                msdMinters[_token].contains(_minters[i]),
                "minter is not the token's minter"
            );
            _setMintCapInternal(_token, _minters[i], _mintCaps[i]);
        }
    }

    /**
     * @notice Withdraw the reserve of `_token`.
     * @param _token The MSD token to withdraw
     * @param _amount The amount of token to withdraw
     *
     * Requirements:
     * - the caller must be `owner`, `_token` must be a MSD Token.
     */
    function _withdrawReserves(address _token, uint256 _amount)
        external
        onlyOwner
        onlyMSD(_token)
    {
        (uint256 _equity, ) = calcEquity(_token);

        require(_equity >= _amount, "Token do not have enough reserve");

        // Increase the token debt
        msdTokenData[_token].debt = msdTokenData[_token].debt.add(_amount);

        // Directly mint the token to owner
        MSD(_token).mint(owner, _amount);

        emit ReservesWithdrawn(
            owner,
            _token,
            _amount,
            _equity,
            _equity.sub(_amount)
        );
    }

    /**
     * @notice Mint `amount` of `_token` to `_to`.
     * @param _token The MSD token to mint
     * @param _to The account to mint to
     * @param _amount The amount of token to mint
     *
     * Requirements:
     * - the caller must be `minter` of `_token`.
     */
    function mintMSD(
        address _token,
        address _to,
        uint256 _amount
    ) external onlyMSDMinter(_token, msg.sender) {
        _beforeMint(_token, msg.sender, _to, _amount);

        MSD(_token).mint(_to, _amount);
    }

    function _beforeMint(
        address _token,
        address _minter,
        address _to,
        uint256 _amount
    ) internal virtual {
        // Check minter's mint cap, -1 means no limit
        // _amount has been taken account into totalMint/totalBorrows
        require(
            IMinter(_minter).totalMint() <= mintCaps[_token][_minter],
            "Minter mint capacity reached"
        );

        _to;
        _amount;
    }

    /*********************************/
    /******** MSD Token Equity *******/
    /*********************************/

    /**
     * @notice Get the MSD token equity
     * @param _token The MSD token to query
     * @return token equity, token debt, will call `updateInterest()` on its minters
     *
     * Requirements:
     * - `_token` must be a MSD Token.
     *
     */
    function calcEquity(address _token)
        public
        view
        onlyMSD(_token)
        returns (uint256, uint256)
    {
        TokenData storage _tokenData = msdTokenData[_token];

        return
            _tokenData.earning > _tokenData.debt
                ? (_tokenData.earning.sub(_tokenData.debt), uint256(0))
                : (uint256(0), _tokenData.debt.sub(_tokenData.earning));
    }

    /*********************************/
    /****** General Information ******/
    /*********************************/

    /**
     * @notice Return all of the MSD tokens
     * @return _allMSDs The list of MSD token addresses
     */
    function getAllMSDs() public view returns (address[] memory _allMSDs) {
        EnumerableSetUpgradeable.AddressSet storage _msdTokens = msdTokens;

        uint256 _len = _msdTokens.length();
        _allMSDs = new address[](_len);
        for (uint256 i = 0; i < _len; i++) {
            _allMSDs[i] = _msdTokens.at(i);
        }
    }

    /**
     * @notice Check whether a address is a valid MSD
     * @param _token The token address to check for
     * @return true if the _token is a valid MSD otherwise false
     */
    function hasMSD(address _token) public view returns (bool) {
        return msdTokens.contains(_token);
    }

    /**
     * @notice Return all minter of a MSD token
     * @param _token The MSD token address to get minters for
     * @return _minters The list of MSD token minter addresses
     * Will retuen empty if `_token` is not a valid MSD token
     */
    function getMSDMinters(address _token)
        public
        view
        returns (address[] memory _minters)
    {
        EnumerableSetUpgradeable.AddressSet storage _msdMinters =
            msdMinters[_token];

        uint256 _len = _msdMinters.length();
        _minters = new address[](_len);
        for (uint256 i = 0; i < _len; i++) {
            _minters[i] = _msdMinters.at(i);
        }
    }
}

// File: contracts/msd/MSD.sol



// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "@openzeppelin/contracts-upgradeable/utils/EnumerableSetUpgradeable.sol";

import "../library/Initializable.sol";
import "../library/Ownable.sol";
import "../library/ERC20.sol";

/**
 * @title dForce's Multi-currency Stable Debt Token
 * @author dForce
 */
contract MSD is Initializable, Ownable, ERC20 {
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;

    bytes32 public DOMAIN_SEPARATOR;
    // keccak256("Permit(address owner,address spender,uint256 chainId, uint256 value,uint256 nonce,uint256 deadline)");
    bytes32 public constant PERMIT_TYPEHASH =
        0x576144ed657c8304561e56ca632e17751956250114636e8c01f64a7f2c6d98cf;
    mapping(address => uint256) public nonces;

    /// @dev EnumerableSet of minters
    EnumerableSetUpgradeable.AddressSet internal minters;

    /**
     * @dev Emitted when `minter` is added as `minter`.
     */
    event MinterAdded(address minter);

    /**
     * @dev Emitted when `minter` is removed from `minters`.
     */
    event MinterRemoved(address minter);

    /**
     * @notice Expects to call only once to initialize the MSD token.
     * @param _name Token name.
     * @param _symbol Token symbol.
     */
    function initialize(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) external initializer {
        __Ownable_init();
        __ERC20_init(_name, _symbol, _decimals);

        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                keccak256(
                    "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                ),
                keccak256(bytes(_name)),
                keccak256(bytes("1")),
                _getChainId(),
                address(this)
            )
        );
    }

    /**
     * @dev Throws if called by any account other than the minters.
     */
    modifier onlyMinter() {
        require(
            minters.contains(msg.sender),
            "onlyMinter: caller is not minter"
        );
        _;
    }

    /**
     * @notice Add `minter` into minters.
     * If `minter` have not been a minter, emits a `MinterAdded` event.
     *
     * @param _minter The minter to add
     *
     * Requirements:
     * - the caller must be `owner`.
     */
    function _addMinter(address _minter) external onlyOwner {
        require(_minter != address(0), "_addMinter: _minter the zero address");
        if (minters.add(_minter)) {
            emit MinterAdded(_minter);
        }
    }

    /**
     * @notice Remove `minter` from minters.
     * If `minter` is a minter, emits a `MinterRemoved` event.
     *
     * @param _minter The minter to remove
     *
     * Requirements:
     * - the caller must be `owner`.
     */
    function _removeMinter(address _minter) external onlyOwner {
        require(
            _minter != address(0),
            "_removeMinter: _minter the zero address"
        );
        if (minters.remove(_minter)) {
            emit MinterRemoved(_minter);
        }
    }

    function mint(address to, uint256 amount) external onlyMinter {
        _mint(to, amount);
    }

    function burn(address from, uint256 amount) external {
        _burnFrom(from, amount);
    }

    function _getChainId() internal pure returns (uint256) {
        uint256 chainId;
        assembly {
            chainId := chainid()
        }
        return chainId;
    }

    /**
     * @dev EIP2612 permit function. For more details, please look at here:
     * https://eips.ethereum.org/EIPS/eip-2612
     * @param _owner The owner of the funds.
     * @param _spender The spender.
     * @param _value The amount.
     * @param _deadline The deadline timestamp, type(uint256).max for max deadline.
     * @param _v Signature param.
     * @param _s Signature param.
     * @param _r Signature param.
     */
    function permit(
        address _owner,
        address _spender,
        uint256 _value,
        uint256 _deadline,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) external {
        require(_deadline >= block.timestamp, "permit: EXPIRED!");
        uint256 _currentNonce = nonces[_owner];
        bytes32 _digest =
            keccak256(
                abi.encodePacked(
                    "\x19\x01",
                    DOMAIN_SEPARATOR,
                    keccak256(
                        abi.encode(
                            PERMIT_TYPEHASH,
                            _owner,
                            _spender,
                            _getChainId(),
                            _value,
                            _currentNonce,
                            _deadline
                        )
                    )
                )
            );
        address _recoveredAddress = ecrecover(_digest, _v, _r, _s);
        require(
            _recoveredAddress != address(0) && _recoveredAddress == _owner,
            "permit: INVALID_SIGNATURE!"
        );
        nonces[_owner] = _currentNonce.add(1);
        _approve(_owner, _spender, _value);
    }

    /**
     * @notice Return all minters of this MSD token
     * @return _minters The list of minter addresses
     */
    function getMinters() public view returns (address[] memory _minters) {
        uint256 _len = minters.length();
        _minters = new address[](_len);
        for (uint256 i = 0; i < _len; i++) {
            _minters[i] = minters.at(i);
        }
    }
}

// File: @openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol



// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.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 SafeMathUpgradeable {
    /**
     * @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.
     */
    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.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        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.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

// File: @openzeppelin/contracts-upgradeable/utils/EnumerableSetUpgradeable.sol



// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSetUpgradeable {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;

        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) { // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        require(set._values.length > index, "EnumerableSet: index out of bounds");
        return set._values[index];
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(value)));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(value)));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(value)));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint256(_at(set._inner, index)));
    }


    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }
}

// File: contracts/library/ERC20.sol



// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";

/**
 * @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 {
    using SafeMathUpgradeable for uint256;

    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;
    uint256 public totalSupply;

    string public name;
    string public symbol;
    uint8 public decimals;

    /**
     * @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
    );

    /**
     * @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.
     */
    function __ERC20_init(
        string memory name_,
        string memory symbol_,
        uint8 decimals_
    ) internal {
        name = name_;
        symbol = symbol_;
        decimals = decimals_;
    }

    /**
     * @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
        returns (bool)
    {
        _transfer(msg.sender, recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount)
        public
        virtual
        returns (bool)
    {
        _approve(msg.sender, 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 returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, msg.sender, allowance[sender][msg.sender].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(
            msg.sender,
            spender,
            allowance[msg.sender][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(
            msg.sender,
            spender,
            allowance[msg.sender][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 virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        balanceOf[sender] = balanceOf[sender].sub(amount);
        balanceOf[recipient] = balanceOf[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");

        totalSupply = totalSupply.add(amount);
        balanceOf[account] = balanceOf[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");

        balanceOf[account] = balanceOf[account].sub(amount);
        totalSupply = totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, deducting from the caller's
     * allowance if caller is not the `account`.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller other than `msg.sender` must have allowance for ``accounts``'s tokens of at least
     * `amount`.
     */
    function _burnFrom(address account, uint256 amount) internal virtual {
        if (msg.sender != account)
            _approve(
                account,
                msg.sender,
                allowance[account][msg.sender].sub(amount)
            );

        _burn(account, amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This 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 virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        allowance[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    uint256[50] private __gap;
}

// File: contracts/library/Ownable.sol



//SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {_setPendingOwner} and {_acceptOwner}.
 */
contract Ownable {
    /**
     * @dev Returns the address of the current owner.
     */
    address payable public owner;

    /**
     * @dev Returns the address of the current pending owner.
     */
    address payable public pendingOwner;

    event NewOwner(address indexed previousOwner, address indexed newOwner);
    event NewPendingOwner(
        address indexed oldPendingOwner,
        address indexed newPendingOwner
    );

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner == msg.sender, "onlyOwner: caller is not the owner");
        _;
    }

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal {
        owner = msg.sender;
        emit NewOwner(address(0), msg.sender);
    }

    /**
     * @notice Base on the inputing parameter `newPendingOwner` to check the exact error reason.
     * @dev Transfer contract control to a new owner. The newPendingOwner must call `_acceptOwner` to finish the transfer.
     * @param newPendingOwner New pending owner.
     */
    function _setPendingOwner(address payable newPendingOwner)
        external
        onlyOwner
    {
        require(
            newPendingOwner != address(0) && newPendingOwner != pendingOwner,
            "_setPendingOwner: New owenr can not be zero address and owner has been set!"
        );

        // Gets current owner.
        address oldPendingOwner = pendingOwner;

        // Sets new pending owner.
        pendingOwner = newPendingOwner;

        emit NewPendingOwner(oldPendingOwner, newPendingOwner);
    }

    /**
     * @dev Accepts the admin rights, but only for pendingOwenr.
     */
    function _acceptOwner() external {
        require(
            msg.sender == pendingOwner,
            "_acceptOwner: Only for pending owner!"
        );

        // Gets current values for events.
        address oldOwner = owner;
        address oldPendingOwner = pendingOwner;

        // Set the new contract owner.
        owner = pendingOwner;

        // Clear the pendingOwner.
        pendingOwner = address(0);

        emit NewOwner(oldOwner, owner);
        emit NewPendingOwner(oldPendingOwner, pendingOwner);
    }

    uint256[50] private __gap;
}

// File: contracts/library/Initializable.sol



// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(
            !_initialized,
            "Initializable: contract is already initialized"
        );

        _;

        _initialized = true;
    }
}