ETH Price: $3,419.56 (-2.68%)
Gas: 6 Gwei

Transaction Decoder

Block:
13727583 at Dec-02-2021 01:23:10 PM +UTC
Transaction Fee:
0.00802332158184432 ETH $27.44
Gas Used:
100,080 Gas / 80.169080554 Gwei

Emitted Events:

201 TransparentUpgradeableProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000d9ca818d8db735fde245afaf55821ed7fa582d6c, 0x000000000000000000000000247ce2d69bd61a772a0f8dd92cc842577aa75a8e, 0000000000000000000000000000000000000000000005d7c028508b5a3ed7c0 )
202 RewardPool.Withdrawn( user=[Sender] 0x247ce2d69bd61a772a0f8dd92cc842577aa75a8e, amount=27591728795809575000000 )
203 TransparentUpgradeableProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000d9ca818d8db735fde245afaf55821ed7fa582d6c, 0x000000000000000000000000247ce2d69bd61a772a0f8dd92cc842577aa75a8e, 000000000000000000000000000000000000000000000115739c617f6b0763d7 )
204 RewardPool.RewardPaid( user=[Sender] 0x247ce2d69bd61a772a0f8dd92cc842577aa75a8e, reward=5118078749028158759895 )

Account State Difference:

  Address   Before After State Difference Code
0x247CE2D6...77AA75a8e
0.029129184875675901 Eth
Nonce: 86
0.021105863293831581 Eth
Nonce: 87
0.00802332158184432
0x5a75A093...03518031d
(F2Pool Old)
710.458109952324851028 Eth710.458260072324851028 Eth0.00015012
0xD9ca818D...7FA582d6c

Execution Trace

RewardPool.CALL( )
  • TransparentUpgradeableProxy.a9059cbb( )
    • ESW.transfer( recipient=0x247CE2D69BD61A772a0f8DD92CC842577AA75a8e, amount=27591728795809575000000 ) => ( True )
      • 0x99e401f9f825822f005d68b7d903038cc601c73b.82580805( )
      • TransparentUpgradeableProxy.a9059cbb( )
        • ESW.transfer( recipient=0x247CE2D69BD61A772a0f8DD92CC842577AA75a8e, amount=5118078749028158759895 ) => ( True )
          • 0x99e401f9f825822f005d68b7d903038cc601c73b.82580805( )
            File 1 of 3: RewardPool
            /**
             *Submitted for verification at Etherscan.io on 2021-07-02
            */
            
            // Sources flattened with hardhat v2.4.1 https://hardhat.org
            
            // File @openzeppelin/contracts/math/[email protected]
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity >=0.6.0 <0.8.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/token/ERC20/[email protected]
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity >=0.6.0 <0.8.0;
            
            /**
             * @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);
            }
            
            
            // File @openzeppelin/contracts/utils/[email protected]
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity >=0.6.0 <0.8.0;
            
            /*
             * @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;
                }
            }
            
            
            // File @openzeppelin/contracts/access/[email protected]
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity >=0.6.0 <0.8.0;
            
            /**
             * @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 {transferOwnership}.
             *
             * This module is used through inheritance. It will make available the modifier
             * `onlyOwner`, which can be applied to your functions to restrict their use to
             * the owner.
             */
            abstract contract Ownable is Context {
                address private _owner;
            
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            
                /**
                 * @dev Initializes the contract setting the deployer as the initial owner.
                 */
                constructor () internal {
                    address msgSender = _msgSender();
                    _owner = msgSender;
                    emit OwnershipTransferred(address(0), msgSender);
                }
            
                /**
                 * @dev Returns the address of the current owner.
                 */
                function owner() public view virtual returns (address) {
                    return _owner;
                }
            
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    require(owner() == _msgSender(), "Ownable: caller is not the owner");
                    _;
                }
            
                /**
                 * @dev Leaves the contract without owner. It will not be possible to call
                 * `onlyOwner` functions anymore. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby removing any functionality that is only available to the owner.
                 */
                function renounceOwnership() public virtual onlyOwner {
                    emit OwnershipTransferred(_owner, address(0));
                    _owner = address(0);
                }
            
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual onlyOwner {
                    require(newOwner != address(0), "Ownable: new owner is the zero address");
                    emit OwnershipTransferred(_owner, newOwner);
                    _owner = newOwner;
                }
            }
            
            
            // File contracts/IRewardDistributionRecipient.sol
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity ^0.6.2;
            
            abstract contract IRewardDistributionRecipient is Ownable {
                address rewardDistribution;
            
                function notifyRewardAmount(uint256 reward) external virtual;
            
                modifier onlyRewardDistribution() {
                    require(_msgSender() == rewardDistribution, "Caller is not reward distribution");
                    _;
                }
            
                function setRewardDistribution(address _rewardDistribution)
                    public
                    /* external */
                    onlyOwner
                {
                    rewardDistribution = _rewardDistribution;
                }
            }
            
            
            // File @openzeppelin/contracts/math/[email protected]
            
            // 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 SafeMath {
                /**
                 * @dev Returns the addition of two unsigned integers, with an overflow flag.
                 *
                 * _Available since v3.4._
                 */
                function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                    uint256 c = a + b;
                    if (c < a) return (false, 0);
                    return (true, c);
                }
            
                /**
                 * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                 *
                 * _Available since v3.4._
                 */
                function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                    if (b > a) return (false, 0);
                    return (true, a - b);
                }
            
                /**
                 * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                 *
                 * _Available since v3.4._
                 */
                function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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 (true, 0);
                    uint256 c = a * b;
                    if (c / a != b) return (false, 0);
                    return (true, c);
                }
            
                /**
                 * @dev Returns the division of two unsigned integers, with a division by zero flag.
                 *
                 * _Available since v3.4._
                 */
                function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                    if (b == 0) return (false, 0);
                    return (true, a / b);
                }
            
                /**
                 * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                 *
                 * _Available since v3.4._
                 */
                function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                    if (b == 0) return (false, 0);
                    return (true, a % b);
                }
            
                /**
                 * @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) {
                    require(b <= a, "SafeMath: subtraction overflow");
                    return a - b;
                }
            
                /**
                 * @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) {
                    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, reverting 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) {
                    require(b > 0, "SafeMath: division by zero");
                    return a / b;
                }
            
                /**
                 * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                 * reverting 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) {
                    require(b > 0, "SafeMath: modulo by zero");
                    return a % b;
                }
            
                /**
                 * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                 * overflow (when the result is negative).
                 *
                 * CAUTION: This function is deprecated because it requires allocating memory for the error
                 * message unnecessarily. For custom revert reasons use {trySub}.
                 *
                 * 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);
                    return a - b;
                }
            
                /**
                 * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                 * division by zero. The result is rounded towards zero.
                 *
                 * CAUTION: This function is deprecated because it requires allocating memory for the error
                 * message unnecessarily. For custom revert reasons use {tryDiv}.
                 *
                 * 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);
                    return a / b;
                }
            
                /**
                 * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                 * reverting with custom message when dividing by zero.
                 *
                 * CAUTION: This function is deprecated because it requires allocating memory for the error
                 * message unnecessarily. For custom revert reasons use {tryMod}.
                 *
                 * 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/utils/[email protected]
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity >=0.6.2 <0.8.0;
            
            /**
             * @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) {
                    // This method relies on extcodesize, which returns 0 for contracts in
                    // construction, since the code is only stored at the end of the
                    // constructor execution.
            
                    uint256 size;
                    // solhint-disable-next-line no-inline-assembly
                    assembly { size := extcodesize(account) }
                    return size > 0;
                }
            
                /**
                 * @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");
                    require(isContract(target), "Address: call to non-contract");
            
                    // solhint-disable-next-line avoid-low-level-calls
                    (bool success, bytes memory returndata) = target.call{ value: value }(data);
                    return _verifyCallResult(success, returndata, errorMessage);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a static call.
                 *
                 * _Available since v3.3._
                 */
                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                    return functionStaticCall(target, data, "Address: low-level static call failed");
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                 * but performing a static call.
                 *
                 * _Available since v3.3._
                 */
                function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                    require(isContract(target), "Address: static call to non-contract");
            
                    // solhint-disable-next-line avoid-low-level-calls
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return _verifyCallResult(success, returndata, errorMessage);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a delegate call.
                 *
                 * _Available since v3.4._
                 */
                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                 * but performing a delegate call.
                 *
                 * _Available since v3.4._
                 */
                function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                    require(isContract(target), "Address: delegate call to non-contract");
            
                    // solhint-disable-next-line avoid-low-level-calls
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return _verifyCallResult(success, returndata, errorMessage);
                }
            
                function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                    if (success) {
                        return returndata;
                    } else {
                        // 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);
                        }
                    }
                }
            }
            
            
            // File @openzeppelin/contracts/token/ERC20/[email protected]
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity >=0.6.0 <0.8.0;
            
            
            
            /**
             * @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 IERC20;` 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));
                }
            
                /**
                 * @dev Deprecated. This function has issues similar to the ones found in
                 * {IERC20-approve}, and its usage is discouraged.
                 *
                 * Whenever possible, use {safeIncreaseAllowance} and
                 * {safeDecreaseAllowance} instead.
                 */
                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. We use {Address.functionCall} to perform this call, which verifies that
                    // the target address contains contract code and also asserts for success in the low-level call.
            
                    bytes memory returndata = address(token).functionCall(data, "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/LPTokenWrapper.sol
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity ^0.6.2;
            
            
            
            contract LPTokenWrapper {
                using SafeMath for uint256;
                using SafeERC20 for IERC20;
            
                IERC20 public stakeToken;
            
                uint256 private _totalSupply;
                mapping(address => uint256) private _balances;
            
                function totalSupply() public view returns (uint256) {
                    return _totalSupply;
                }
            
                function balanceOf(address account) public view returns (uint256) {
                    return _balances[account];
                }
            
                function stake(uint256 amount) public virtual {
                    _totalSupply = _totalSupply.add(amount);
                    _balances[msg.sender] = _balances[msg.sender].add(amount);
                    stakeToken.safeTransferFrom(msg.sender, address(this), amount);
                }
            
                function withdraw(uint256 amount) public virtual {
                    _totalSupply = _totalSupply.sub(amount);
                    _balances[msg.sender] = _balances[msg.sender].sub(amount);
                    stakeToken.safeTransfer(msg.sender, amount);
                }
            }
            
            
            // File contracts/interfaces/IEmiswap.sol
            
            // SPDX-License-Identifier: UNLICENSED
            
            pragma solidity ^0.6.2;
            
            interface IEmiswapRegistry {
                function pools(IERC20 token1, IERC20 token2) external view returns (IEmiswap);
            
                function isPool(address addr) external view returns (bool);
            
                function deploy(IERC20 tokenA, IERC20 tokenB) external returns (IEmiswap);
            
                function getAllPools() external view returns (IEmiswap[] memory);
            }
            
            interface IEmiswap {
                function fee() external view returns (uint256);
            
                function tokens(uint256 i) external view returns (IERC20);
            
                function deposit(
                    uint256[] calldata amounts,
                    uint256[] calldata minAmounts,
                    address referral
                ) external payable returns (uint256 fairSupply);
            
                function withdraw(uint256 amount, uint256[] calldata minReturns) external;
            
                function getBalanceForAddition(IERC20 token) external view returns (uint256);
            
                function getBalanceForRemoval(IERC20 token) external view returns (uint256);
            
                function getReturn(
                    IERC20 fromToken,
                    IERC20 destToken,
                    uint256 amount
                ) external view returns (uint256, uint256);
            
                function swap(
                    IERC20 fromToken,
                    IERC20 destToken,
                    uint256 amount,
                    uint256 minReturn,
                    address to,
                    address referral
                ) external payable returns (uint256 returnAmount);
            
                function initialize(IERC20[] calldata assets) external;
            }
            
            
            // File contracts/libraries/EmiswapLib.sol
            
            // SPDX-License-Identifier: UNLICENSED
            
            pragma solidity ^0.6.2;
            
            
            
            library EmiswapLib {
                using SafeMath for uint256;
                uint256 public constant FEE_DENOMINATOR = 1e18;
            
                function previewSwapExactTokenForToken(
                    address factory,
                    address tokenFrom,
                    address tokenTo,
                    uint256 ammountFrom
                ) internal view returns (uint256 ammountTo) {
                    IEmiswap pairContract = IEmiswapRegistry(factory).pools(IERC20(tokenFrom), IERC20(tokenTo));
            
                    if (pairContract != IEmiswap(0)) {
                        (, ammountTo) = pairContract.getReturn(IERC20(tokenFrom), IERC20(tokenTo), ammountFrom);
                    }
                }
            
                /**************************************************************************************
                 * get preview result of virtual swap by route of tokens
                 **************************************************************************************/
                function previewSwapbyRoute(
                    address factory,
                    address[] memory path,
                    uint256 ammountFrom
                ) internal view returns (uint256 ammountTo) {
                    for (uint256 i = 0; i < path.length - 1; i++) {
                        if (path.length >= 2) {
                            ammountTo = previewSwapExactTokenForToken(factory, path[i], path[i + 1], ammountFrom);
            
                            if (i == (path.length - 2)) {
                                return (ammountTo);
                            } else {
                                ammountFrom = ammountTo;
                            }
                        }
                    }
                }
            
                function fee(address factory) internal view returns (uint256) {
                    return IEmiswap(factory).fee();
                }
            
                // given an output amount of an asset and pair reserves, returns a required input amount of the other asset
                function getAmountIn(
                    address factory,
                    uint256 amountOut,
                    uint256 reserveIn,
                    uint256 reserveOut
                ) internal view returns (uint256 amountIn) {
                    require(amountOut > 0, "EmiswapLibrary: INSUFFICIENT_OUTPUT_AMOUNT");
                    require(reserveIn > 0 && reserveOut > 0, "EmiswapLibrary: INSUFFICIENT_LIQUIDITY");
                    uint256 numerator = reserveIn.mul(amountOut).mul(1000);
                    uint256 denominator = reserveOut.sub(amountOut).mul(uint256(1000000000000000000).sub(fee(factory)).div(1e15)); // 997
                    amountIn = (numerator / denominator).add(1);
                }
            
                // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
                function getAmountOut(
                    address factory,
                    uint256 amountIn,
                    uint256 reserveIn,
                    uint256 reserveOut
                ) internal view returns (uint256 amountOut) {
                    if (amountIn == 0 || reserveIn == 0 || reserveOut == 0) {
                        return (0);
                    }
            
                    uint256 amountInWithFee = amountIn.mul(uint256(1000000000000000000).sub(fee(factory)).div(1e15)); //997
                    uint256 numerator = amountInWithFee.mul(reserveOut);
                    uint256 denominator = reserveIn.mul(1000).add(amountInWithFee);
                    amountOut = (denominator == 0 ? 0 : amountOut = numerator / denominator);
                }
            
                // 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, "EmiswapLibrary: INVALID_PATH");
                    amounts = new uint256[](path.length);
                    amounts[amounts.length - 1] = amountOut;
                    for (uint256 i = path.length - 1; i > 0; i--) {
                        IEmiswap pairContract = IEmiswapRegistry(factory).pools(IERC20(IERC20(path[i])), IERC20(path[i - 1]));
            
                        uint256 reserveIn;
                        uint256 reserveOut;
            
                        if (address(pairContract) != address(0)) {
                            reserveIn = IEmiswap(pairContract).getBalanceForAddition(IERC20(path[i - 1]));
                            reserveOut = IEmiswap(pairContract).getBalanceForRemoval(IERC20(path[i]));
                        }
            
                        amounts[i - 1] = getAmountIn(factory, amounts[i], reserveIn, reserveOut);
                    }
                }
            
                // 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, "EmiswapLibrary: INVALID_PATH");
                    amounts = new uint256[](path.length);
                    amounts[0] = amountIn;
                    for (uint256 i = 0; i < path.length - 1; i++) {
                        IEmiswap pairContract = IEmiswapRegistry(factory).pools(IERC20(IERC20(path[i])), IERC20(path[i + 1]));
            
                        uint256 reserveIn;
                        uint256 reserveOut;
            
                        if (address(pairContract) != address(0)) {
                            reserveIn = IEmiswap(pairContract).getBalanceForAddition(IERC20(path[i]));
                            reserveOut = IEmiswap(pairContract).getBalanceForRemoval(IERC20(path[i + 1]));
                        }
            
                        amounts[i + 1] = getAmountOut(factory, amounts[i], reserveIn, reserveOut);
                    }
                }
            
                // 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, "EmiswapLibrary: INSUFFICIENT_AMOUNT");
                    require(reserveA > 0 && reserveB > 0, "EmiswapLibrary: INSUFFICIENT_LIQUIDITY");
                    amountB = amountA.mul(reserveB) / reserveA;
                }
            }
            
            
            
            
            // File contracts/RewardPool.sol
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity ^0.6.2;
            
            
            
            
            
            
            contract RewardPool is LPTokenWrapper, IRewardDistributionRecipient {
                address public emiFactory;
                uint256 public totalStakeLimit; // max value in USD coin (last in route), rememeber decimals!
                address[] public route;
                uint8 marketID;
                uint8 id;
            
                IERC20 public rewardToken;
                uint256 public minPriceAmount;
                uint256 public constant DURATION = 90 days;
            
                uint256 public periodFinish = 0;
                uint256 public periodStop = 0;
                uint256 public rewardRate = 0;
                uint256 public lastUpdateTime;
                uint256 public rewardPerTokenStored;
                uint256 public tokenMode; // 0 = simple ERC20 token, 1 = Emiswap LP-token
                mapping(address => uint256) public userRewardPerTokenPaid;
                mapping(address => uint256) public rewards;
            
                event RewardAdded(uint256 reward);
                event Staked(address indexed user, uint256 amount);
                event Withdrawn(address indexed user, uint256 amount);
                event RewardPaid(address indexed user, uint256 reward);
            
                constructor(
                    address _rewardToken,
                    address _stakeToken,
                    address rewardAdmin,
                    uint256 _tokenMode,
                    uint256 _totalStakeLimit,
                    uint256 _minPriceAmount
                ) public {
                    rewardToken = IERC20(_rewardToken);
                    stakeToken = IERC20(_stakeToken);
                    setRewardDistribution(rewardAdmin);
                    tokenMode = _tokenMode;
                    totalStakeLimit = _totalStakeLimit;
                    minPriceAmount = _minPriceAmount;
                }
            
                modifier updateReward(address account) {
                    rewardPerTokenStored = rewardPerToken();
                    lastUpdateTime = lastTimeRewardApplicable();
                    if (account != address(0)) {
                        rewards[account] = earned(account);
                        userRewardPerTokenPaid[account] = rewardPerTokenStored;
                    }
                    _;
                }
            
                function setEmiPriceData(address _emiFactory, address[] memory _route) public onlyOwner {
                    if (emiFactory != _emiFactory) {
                        emiFactory = _emiFactory;
                    }
                    if (route.length > 0) {
                        delete route;
                    }
                    for (uint256 index = 0; index < _route.length; index++) {
                        route.push(_route[index]);
                    }
                }
            
                function setTotalStakeLimit(uint256 _totalStakeLimit) public onlyOwner {
                    require(totalStakeLimit != _totalStakeLimit);
                    totalStakeLimit = _totalStakeLimit;
                }
            
                function setMinPriceAmount(uint256 newMinPriceAmount) public onlyOwner {
                    minPriceAmount = newMinPriceAmount;
                }
            
                function lastTimeRewardApplicable() public view returns (uint256) {
                    return Math.min(block.timestamp, periodFinish);
                }
            
                function rewardPerToken() public view returns (uint256) {
                    if (totalSupply() == 0) {
                        return rewardPerTokenStored;
                    }
                    return
                        rewardPerTokenStored.add(
                            lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(1e18).div(totalSupply())
                        );
                }
            
                function earned(address account) public view returns (uint256) {
                    return
                        balanceOf(account).mul(rewardPerToken().sub(userRewardPerTokenPaid[account])).div(1e18).add(
                            rewards[account]
                        );
                }
            
                function stake(uint256 amount) public override updateReward(msg.sender) {
                    require(amount > 0, "Cannot stake 0");
                    require(block.timestamp <= periodFinish && block.timestamp <= periodStop, "Cannot stake yet");
                    super.stake(amount);
                    (, uint256 totalStake) = getStakedValuesinUSD(msg.sender);
                    require(totalStake <= totalStakeLimit, "Limit exceeded");
                    emit Staked(msg.sender, amount);
                }
            
                function withdraw(uint256 amount) public override updateReward(msg.sender) {
                    require(amount > 0, "Cannot withdraw 0");
                    super.withdraw(amount);
                    emit Withdrawn(msg.sender, amount);
                }
            
                function exit() external {
                    withdraw(balanceOf(msg.sender));
                    getReward();
                }
            
                function getReward() public updateReward(msg.sender) {
                    uint256 reward = earned(msg.sender);
                    if (reward > 0) {
                        rewards[msg.sender] = 0;
                        rewardToken.safeTransfer(msg.sender, reward);
                        emit RewardPaid(msg.sender, reward);
                    }
                }
            
                // use it after create and approve of reward token
            
                function notifyRewardAmount(uint256 reward) external override onlyRewardDistribution updateReward(address(0)) {
                    if (block.timestamp >= periodFinish) {
                        rewardRate = reward.div(DURATION);
                    } else {
                        uint256 remaining = periodFinish.sub(block.timestamp);
                        uint256 leftover = remaining.mul(rewardRate);
                        rewardRate = reward.add(leftover).div(DURATION);
                    }
                    lastUpdateTime = block.timestamp;
                    periodFinish = block.timestamp.add(DURATION);
                    periodStop = periodFinish;
                    rewardToken.safeTransferFrom(msg.sender, address(this), reward);
                    emit RewardAdded(reward);
                }
            
                function setPeriodStop(uint256 _periodStop) external onlyRewardDistribution {
                    require(periodStop <= periodFinish, "Incorrect stop");
                    periodStop = _periodStop;
                }
            
                function getStakedValuesinUSD(address wallet) public view returns (uint256 senderStake, uint256 totalStake) {
                    uint256 price = getAmountOut(minPriceAmount, route); /*1e18 default value of ESW, first of route always ESW*/
                    // simple ERC-20
                    if (tokenMode == 0) {
                        senderStake = balanceOf(wallet).mul(price).div(minPriceAmount);
                        totalStake = totalSupply().mul(price).div(minPriceAmount);
                    }
                    if (tokenMode == 1) {
                        /*uint256 lpFractionWallet = balanceOf(wallet).mul(1e18).div(stakeToken.totalSupply());
                        uint256 lpFractionTotal = totalSupply().mul(1e18).div(stakeToken.totalSupply());
                        uint256 ESWreserveWallet = IEmiswap(address(stakeToken)).getBalanceForAddition( IERC20(route[0]) ).mul(2).mul(lpFractionWallet).div(1e18);
                        uint256 ESWreserveTotal = IEmiswap(address(stakeToken)).getBalanceForAddition( IERC20(route[0]) ).mul(2).mul(lpFractionTotal).div(1e18);
                        senderStake = ESWreserveWallet.mul(price).div(minPriceAmount);
                        totalStake = ESWreserveTotal.mul(price).div(minPriceAmount);*/
            
                        senderStake = IEmiswap(address(stakeToken))
                        .getBalanceForAddition(IERC20(route[0]))
                        .mul(2)
                        .mul(balanceOf(wallet).mul(1e18).div(stakeToken.totalSupply()))
                        .div(1e18)
                        .mul(price)
                        .div(minPriceAmount);
                        totalStake = IEmiswap(address(stakeToken))
                        .getBalanceForAddition(IERC20(route[0]))
                        .mul(2)
                        .mul(totalSupply().mul(1e18).div(stakeToken.totalSupply()))
                        .div(1e18)
                        .mul(price)
                        .div(minPriceAmount);
                    }
                }
            
                function getAmountOut(uint256 amountIn, address[] memory path) public view returns (uint256) {
                    return EmiswapLib.getAmountsOut(emiFactory, amountIn, path)[path.length - 1];
                }
            
                // ------------------------------------------------------------------------
                //
                // ------------------------------------------------------------------------
                /**
                 * @dev Owner can transfer out any accidentally sent ERC20 tokens
                 * @param tokenAddress Address of ERC-20 token to transfer
                 * @param beneficiary Address to transfer to
                 * @param amount of tokens to transfer
                 */
                function transferAnyERC20Token(
                    address tokenAddress,
                    address beneficiary,
                    uint256 amount
                ) public onlyOwner returns (bool success) {
                    require(tokenAddress != address(0), "address 0!");
                    require(tokenAddress != address(stakeToken), "not staketoken");
            
                    return IERC20(tokenAddress).transfer(beneficiary, amount);
                }
            }

            File 2 of 3: TransparentUpgradeableProxy
            // File: @openzeppelin/contracts/proxy/Proxy.sol
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity ^0.6.0;
            
            /**
             * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
             * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
             * be specified by overriding the virtual {_implementation} function.
             * 
             * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
             * different contract through the {_delegate} function.
             * 
             * The success and return data of the delegated call will be returned back to the caller of the proxy.
             */
            abstract contract Proxy {
                /**
                 * @dev Delegates the current call to `implementation`.
                 * 
                 * This function does not return to its internall call site, it will return directly to the external caller.
                 */
                function _delegate(address implementation) internal {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        // Copy msg.data. We take full control of memory in this inline assembly
                        // block because it will not return to Solidity code. We overwrite the
                        // Solidity scratch pad at memory position 0.
                        calldatacopy(0, 0, calldatasize())
            
                        // Call the implementation.
                        // out and outsize are 0 because we don't know the size yet.
                        let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
            
                        // Copy the returned data.
                        returndatacopy(0, 0, returndatasize())
            
                        switch result
                        // delegatecall returns 0 on error.
                        case 0 { revert(0, returndatasize()) }
                        default { return(0, returndatasize()) }
                    }
                }
            
                /**
                 * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                 * and {_fallback} should delegate.
                 */
                function _implementation() internal virtual view returns (address);
            
                /**
                 * @dev Delegates the current call to the address returned by `_implementation()`.
                 * 
                 * This function does not return to its internall call site, it will return directly to the external caller.
                 */
                function _fallback() internal {
                    _beforeFallback();
                    _delegate(_implementation());
                }
            
                /**
                 * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                 * function in the contract matches the call data.
                 */
                fallback () payable external {
                    _fallback();
                }
            
                /**
                 * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                 * is empty.
                 */
                receive () payable external {
                    _fallback();
                }
            
                /**
                 * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                 * call, or as part of the Solidity `fallback` or `receive` functions.
                 * 
                 * If overriden should call `super._beforeFallback()`.
                 */
                function _beforeFallback() internal virtual {
                }
            }
            
            // File: @openzeppelin/contracts/utils/Address.sol
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity ^0.6.2;
            
            /**
             * @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) {
                    // This method relies in extcodesize, which returns 0 for contracts in
                    // construction, since the code is only stored at the end of the
                    // constructor execution.
            
                    uint256 size;
                    // solhint-disable-next-line no-inline-assembly
                    assembly { size := extcodesize(account) }
                    return size > 0;
                }
            
                /**
                 * @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);
                        }
                    }
                }
            }
            
            // File: @openzeppelin/contracts/proxy/UpgradeableProxy.sol
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity ^0.6.0;
            
            
            
            /**
             * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
             * implementation address that can be changed. This address is stored in storage in the location specified by
             * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
             * implementation behind the proxy.
             * 
             * Upgradeability is only provided internally through {_upgradeTo}. For an externally upgradeable proxy see
             * {TransparentUpgradeableProxy}.
             */
            contract UpgradeableProxy is Proxy {
                /**
                 * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                 * 
                 * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                 * function call, and allows initializating the storage of the proxy like a Solidity constructor.
                 */
                constructor(address _logic, bytes memory _data) public payable {
                    assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                    _setImplementation(_logic);
                    if(_data.length > 0) {
                        // solhint-disable-next-line avoid-low-level-calls
                        (bool success,) = _logic.delegatecall(_data);
                        require(success);
                    }
                }
            
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
            
                /**
                 * @dev Storage slot with the address of the current implementation.
                 * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                 * validated in the constructor.
                 */
                bytes32 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
            
                /**
                 * @dev Returns the current implementation address.
                 */
                function _implementation() internal override view returns (address impl) {
                    bytes32 slot = _IMPLEMENTATION_SLOT;
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        impl := sload(slot)
                    }
                }
            
                /**
                 * @dev Upgrades the proxy to a new implementation.
                 * 
                 * Emits an {Upgraded} event.
                 */
                function _upgradeTo(address newImplementation) internal {
                    _setImplementation(newImplementation);
                    emit Upgraded(newImplementation);
                }
            
                /**
                 * @dev Stores a new address in the EIP1967 implementation slot.
                 */
                function _setImplementation(address newImplementation) private {
                    require(Address.isContract(newImplementation), "UpgradeableProxy: new implementation is not a contract");
            
                    bytes32 slot = _IMPLEMENTATION_SLOT;
            
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        sstore(slot, newImplementation)
                    }
                }
            }
            
            // File: @openzeppelin/contracts/proxy/TransparentUpgradeableProxy.sol
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity ^0.6.0;
            
            
            /**
             * @dev This contract implements a proxy that is upgradeable by an admin.
             * 
             * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
             * clashing], which can potentially be used in an attack, this contract uses the
             * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
             * things that go hand in hand:
             * 
             * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
             * that call matches one of the admin functions exposed by the proxy itself.
             * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
             * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
             * "admin cannot fallback to proxy target".
             * 
             * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
             * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
             * to sudden errors when trying to call a function from the proxy implementation.
             * 
             * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
             * you should think of the `ProxyAdmin` instance as the real administrative inerface of your proxy.
             */
            contract TransparentUpgradeableProxy is UpgradeableProxy {
                /**
                 * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                 * optionally initialized with `_data` as explained in {UpgradeableProxy-constructor}.
                 */
                constructor(address _logic, address _admin, bytes memory _data) public payable UpgradeableProxy(_logic, _data) {
                    assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                    _setAdmin(_admin);
                }
            
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
            
                /**
                 * @dev Storage slot with the admin of the contract.
                 * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                 * validated in the constructor.
                 */
                bytes32 private constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
            
                /**
                 * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                 */
                modifier ifAdmin() {
                    if (msg.sender == _admin()) {
                        _;
                    } else {
                        _fallback();
                    }
                }
            
                /**
                 * @dev Returns the current admin.
                 * 
                 * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
                 * 
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                 * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                 */
                function admin() external ifAdmin returns (address) {
                    return _admin();
                }
            
                /**
                 * @dev Returns the current implementation.
                 * 
                 * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
                 * 
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                 * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                 */
                function implementation() external ifAdmin returns (address) {
                    return _implementation();
                }
            
                /**
                 * @dev Changes the admin of the proxy.
                 * 
                 * Emits an {AdminChanged} event.
                 * 
                 * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
                 */
                function changeAdmin(address newAdmin) external ifAdmin {
                    require(newAdmin != address(0), "TransparentUpgradeableProxy: new admin is the zero address");
                    emit AdminChanged(_admin(), newAdmin);
                    _setAdmin(newAdmin);
                }
            
                /**
                 * @dev Upgrade the implementation of the proxy.
                 * 
                 * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
                 */
                function upgradeTo(address newImplementation) external ifAdmin {
                    _upgradeTo(newImplementation);
                }
            
                /**
                 * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                 * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                 * proxied contract.
                 * 
                 * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
                 */
                function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                    _upgradeTo(newImplementation);
                    // solhint-disable-next-line avoid-low-level-calls
                    (bool success,) = newImplementation.delegatecall(data);
                    require(success);
                }
            
                /**
                 * @dev Returns the current admin.
                 */
                function _admin() internal view returns (address adm) {
                    bytes32 slot = _ADMIN_SLOT;
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        adm := sload(slot)
                    }
                }
            
                /**
                 * @dev Stores a new address in the EIP1967 admin slot.
                 */
                function _setAdmin(address newAdmin) private {
                    bytes32 slot = _ADMIN_SLOT;
            
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        sstore(slot, newAdmin)
                    }
                }
            
                /**
                 * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
                 */
                function _beforeFallback() internal override virtual {
                    require(msg.sender != _admin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                    super._beforeFallback();
                }
            }

            File 3 of 3: ESW
            /**
             *Submitted for verification at Etherscan.io on 2021-07-01
            */
            
            // File: @openzeppelin/contracts/utils/Address.sol
            
            // SPDX-License-Identifier: MIT
            
            pragma solidity >=0.6.2 <0.8.0;
            
            /**
             * @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) {
                    // This method relies on extcodesize, which returns 0 for contracts in
                    // construction, since the code is only stored at the end of the
                    // constructor execution.
            
                    uint256 size;
                    // solhint-disable-next-line no-inline-assembly
                    assembly { size := extcodesize(account) }
                    return size > 0;
                }
            
                /**
                 * @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");
                    require(isContract(target), "Address: call to non-contract");
            
                    // solhint-disable-next-line avoid-low-level-calls
                    (bool success, bytes memory returndata) = target.call{ value: value }(data);
                    return _verifyCallResult(success, returndata, errorMessage);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a static call.
                 *
                 * _Available since v3.3._
                 */
                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                    return functionStaticCall(target, data, "Address: low-level static call failed");
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                 * but performing a static call.
                 *
                 * _Available since v3.3._
                 */
                function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                    require(isContract(target), "Address: static call to non-contract");
            
                    // solhint-disable-next-line avoid-low-level-calls
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return _verifyCallResult(success, returndata, errorMessage);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a delegate call.
                 *
                 * _Available since v3.4._
                 */
                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                 * but performing a delegate call.
                 *
                 * _Available since v3.4._
                 */
                function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                    require(isContract(target), "Address: delegate call to non-contract");
            
                    // solhint-disable-next-line avoid-low-level-calls
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return _verifyCallResult(success, returndata, errorMessage);
                }
            
                function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                    if (success) {
                        return returndata;
                    } else {
                        // 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);
                        }
                    }
                }
            }
            
            // File: @openzeppelin/contracts/proxy/Initializable.sol
            
            
            // solhint-disable-next-line compiler-version
            pragma solidity >=0.4.24 <0.8.0;
            
            
            /**
             * @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 Indicates that the contract is in the process of being initialized.
                 */
                bool private _initializing;
            
                /**
                 * @dev Modifier to protect an initializer function from being invoked twice.
                 */
                modifier initializer() {
                    require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
            
                    bool isTopLevelCall = !_initializing;
                    if (isTopLevelCall) {
                        _initializing = true;
                        _initialized = true;
                    }
            
                    _;
            
                    if (isTopLevelCall) {
                        _initializing = false;
                    }
                }
            
                /// @dev Returns true if and only if the function is running in the constructor
                function _isConstructor() private view returns (bool) {
                    return !Address.isContract(address(this));
                }
            }
            
            // File: contracts/interfaces/IEmiVesting.sol
            
            
            pragma solidity ^0.6.2;
            
            /*************************************************************************
             *    EmiVesting inerface
             *
             ************************************************************************/
            interface IEmiVesting {
                function balanceOf(address beneficiary) external view returns (uint256);
            
                function getCrowdsaleLimit() external view returns (uint256);
            }
            
            // File: contracts/interfaces/IEmiList.sol
            
            
            pragma solidity ^0.6.2;
            
            /*************************************************************************
             *    EmiList inerface
             *
             ************************************************************************/
            interface IEmiList {
                function approveTransfer(address from, address to, uint256 amount) external view returns (bool);
            }
            
            // File: @openzeppelin/contracts/math/SafeMath.sol
            
            
            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 SafeMath {
                /**
                 * @dev Returns the addition of two unsigned integers, with an overflow flag.
                 *
                 * _Available since v3.4._
                 */
                function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                    uint256 c = a + b;
                    if (c < a) return (false, 0);
                    return (true, c);
                }
            
                /**
                 * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                 *
                 * _Available since v3.4._
                 */
                function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                    if (b > a) return (false, 0);
                    return (true, a - b);
                }
            
                /**
                 * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                 *
                 * _Available since v3.4._
                 */
                function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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 (true, 0);
                    uint256 c = a * b;
                    if (c / a != b) return (false, 0);
                    return (true, c);
                }
            
                /**
                 * @dev Returns the division of two unsigned integers, with a division by zero flag.
                 *
                 * _Available since v3.4._
                 */
                function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                    if (b == 0) return (false, 0);
                    return (true, a / b);
                }
            
                /**
                 * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                 *
                 * _Available since v3.4._
                 */
                function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                    if (b == 0) return (false, 0);
                    return (true, a % b);
                }
            
                /**
                 * @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) {
                    require(b <= a, "SafeMath: subtraction overflow");
                    return a - b;
                }
            
                /**
                 * @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) {
                    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, reverting 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) {
                    require(b > 0, "SafeMath: division by zero");
                    return a / b;
                }
            
                /**
                 * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                 * reverting 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) {
                    require(b > 0, "SafeMath: modulo by zero");
                    return a % b;
                }
            
                /**
                 * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                 * overflow (when the result is negative).
                 *
                 * CAUTION: This function is deprecated because it requires allocating memory for the error
                 * message unnecessarily. For custom revert reasons use {trySub}.
                 *
                 * 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);
                    return a - b;
                }
            
                /**
                 * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                 * division by zero. The result is rounded towards zero.
                 *
                 * CAUTION: This function is deprecated because it requires allocating memory for the error
                 * message unnecessarily. For custom revert reasons use {tryDiv}.
                 *
                 * 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);
                    return a / b;
                }
            
                /**
                 * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                 * reverting with custom message when dividing by zero.
                 *
                 * CAUTION: This function is deprecated because it requires allocating memory for the error
                 * message unnecessarily. For custom revert reasons use {tryMod}.
                 *
                 * 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: contracts/libraries/Priviledgeable.sol
            
            pragma solidity ^0.6.2;
            
            
            abstract contract Priviledgeable {
                using SafeMath for uint256;
                using SafeMath for uint256;
            
                event PriviledgeGranted(address indexed admin);
                event PriviledgeRevoked(address indexed admin);
            
                modifier onlyAdmin() {
                    require(
                        _priviledgeTable[msg.sender],
                        "Priviledgeable: caller is not the owner"
                    );
                    _;
                }
            
                mapping(address => bool) private _priviledgeTable;
            
                constructor() internal {
                    _priviledgeTable[msg.sender] = true;
                }
            
                function addAdmin(address _admin) external onlyAdmin returns (bool) {
                    require(_admin != address(0), "Admin address cannot be 0");
                    return _addAdmin(_admin);
                }
            
                function removeAdmin(address _admin) external onlyAdmin returns (bool) {
                    require(_admin != address(0), "Admin address cannot be 0");
                    _priviledgeTable[_admin] = false;
                    emit PriviledgeRevoked(_admin);
            
                    return true;
                }
            
                function isAdmin(address _who) external view returns (bool) {
                    return _priviledgeTable[_who];
                }
            
                //-----------
                // internals
                //-----------
                function _addAdmin(address _admin) internal returns (bool) {
                    _priviledgeTable[_admin] = true;
                    emit PriviledgeGranted(_admin);
                }
            }
            
            // File: @openzeppelin/contracts/utils/Context.sol
            
            
            pragma solidity >=0.6.0 <0.8.0;
            
            /*
             * @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;
                }
            }
            
            // File: @openzeppelin/contracts/GSN/Context.sol
            
            
            pragma solidity >=0.6.0 <0.8.0;
            
            // File: @openzeppelin/contracts/token/ERC20/IERC20.sol
            
            
            pragma solidity >=0.6.0 <0.8.0;
            
            /**
             * @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);
            }
            
            // File: contracts/libraries/ProxiedERC20.sol
            
            
            pragma solidity ^0.6.0;
            
            
            
            
            
            /**
             * @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 ProxiedERC20 is Context, IERC20 {
                using SafeMath for uint256;
                using Address for address;
            
                mapping(address => uint256) private _balances;
            
                mapping(address => mapping(address => uint256)) private _allowances;
            
                uint256 private _totalSupply;
            
                string private _name;
                string private _symbol;
                uint8 private _decimals;
                uint8 private _intialized;
            
                /**
                 * @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 _initialize(
                    string memory name,
                    string memory symbol,
                    uint8 decimals
                ) internal {
                    require(_intialized == 0, "Already intialize");
                    _name = name;
                    _symbol = symbol;
                    _decimals = decimals;
                    _intialized = 1;
                }
            
                /**
                 * @dev Returns the name of the token.
                 */
                function _updateTokenName(string memory newName, string memory newSymbol)
                internal
                {
                    _name = newName;
                    _symbol = newSymbol;
                }
            
                /**
                 * @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,
                            "ERC20: transfer amount exceeds allowance"
                        )
                    );
                    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,
                            "ERC20: decreased allowance below zero"
                        )
                    );
                    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");
            
                    _beforeTokenTransfer(sender, recipient, amount);
            
                    _balances[sender] = _balances[sender].sub(
                        amount,
                        "ERC20: transfer amount exceeds balance"
                    );
                    _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,
                        "ERC20: burn amount exceeds balance"
                    );
                    _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 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 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 {}
            }
            
            // File: contracts/libraries/OracleSign.sol
            
            pragma solidity ^0.6.2;
            
            abstract contract OracleSign {
                function _splitSignature(bytes memory sig)
                internal
                pure
                returns (
                    uint8,
                    bytes32,
                    bytes32
                )
                {
                    require(sig.length == 65, "Incorrect signature length");
            
                    bytes32 r;
                    bytes32 s;
                    uint8 v;
            
                    assembly {
                    //first 32 bytes, after the length prefix
                        r := mload(add(sig, 0x20))
                    //next 32 bytes
                        s := mload(add(sig, 0x40))
                    //final byte, first of next 32 bytes
                        v := byte(0, mload(add(sig, 0x60)))
                    }
            
                    return (v, r, s);
                }
            
                function _recoverSigner(bytes32 message, bytes memory sig)
                internal
                pure
                returns (address)
                {
                    uint8 v;
                    bytes32 r;
                    bytes32 s;
            
                    (v, r, s) = _splitSignature(sig);
            
                    return ecrecover(message, v, r, s);
                }
            
                function _prefixed(bytes32 hash) internal pure returns (bytes32) {
                    return
                    keccak256(
                        abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)
                    );
                }
            }
            
            
            pragma solidity ^0.6.0;
            
            // Exempt from the original UniswapV2Library.
            library UniswapV2Library {
                // 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(bytes32 initCodeHash, address factory, address tokenA, address tokenB) internal pure returns (address pair) {
                    (address token0, address token1) = sortTokens(tokenA, tokenB);
                    pair = address(uint(keccak256(abi.encodePacked(
                            hex'ff',
                            factory,
                            keccak256(abi.encodePacked(token0, token1)),
                            initCodeHash // init code hash
                        ))));
                }
            }
            
            pragma solidity ^0.6.0;
            
            /// @notice based on https://github.com/Uniswap/uniswap-v3-periphery/blob/v1.0.0/contracts/libraries/PoolAddress.sol
            /// @notice changed compiler version and lib name.
            
            /// @title Provides functions for deriving a pool address from the factory, tokens, and the fee
            library UniswapV3Library {
                bytes32 internal constant POOL_INIT_CODE_HASH = 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54;
            
                /// @notice The identifying key of the pool
                struct PoolKey {
                    address token0;
                    address token1;
                    uint24 fee;
                }
            
                /// @notice Returns PoolKey: the ordered tokens with the matched fee levels
                /// @param tokenA The first token of a pool, unsorted
                /// @param tokenB The second token of a pool, unsorted
                /// @param fee The fee level of the pool
                /// @return Poolkey The pool details with ordered token0 and token1 assignments
                function getPoolKey(
                    address tokenA,
                    address tokenB,
                    uint24 fee
                ) internal pure returns (PoolKey memory) {
                    if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA);
                    return PoolKey({token0: tokenA, token1: tokenB, fee: fee});
                }
            
                /// @notice Deterministically computes the pool address given the factory and PoolKey
                /// @param factory The Uniswap V3 factory contract address
                /// @param key The PoolKey
                /// @return pool The contract address of the V3 pool
                function computeAddress(address factory, PoolKey memory key) internal pure returns (address pool) {
                    require(key.token0 < key.token1);
                    pool = address(
                        uint256(
                            keccak256(
                                abi.encodePacked(
                                    hex'ff',
                                    factory,
                                    keccak256(abi.encode(key.token0, key.token1, key.fee)),
                                    POOL_INIT_CODE_HASH
                                )
                            )
                        )
                    );
                }
            }
            
            
            pragma solidity ^0.6.0;
            
            interface IPLPS {
                function LiquidityProtection_beforeTokenTransfer(
                    address _pool, address _from, address _to, uint _amount) external;
                function isBlocked(address _pool, address _who) external view returns(bool);
                function unblock(address _pool, address _who) external;
            }
            
            
            pragma solidity ^0.6.0;
            
            
            abstract contract UsingLiquidityProtectionService {
                bool private protected = true;
                uint64 internal constant HUNDRED_PERCENT = 1e18;
                bytes32 internal constant UNISWAP = 0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f;
                bytes32 internal constant PANCAKESWAP = 0x00fb7f630766e6a796048ea87d01acd3068e8ff67d078148a3fa3f4a84f69bd5;
            
                enum UniswapVersion {
                    V2,
                    V3
                }
            
                enum UniswapV3Fees {
                    _005, // 0.05%
                    _03, // 0.3%
                    _1 // 1%
                }
            
                modifier onlyProtectionAdmin() {
                    protectionAdminCheck();
                    _;
                }
            
                function token_transfer(address from, address to, uint amount) internal virtual;
                function token_balanceOf(address holder) internal view virtual returns(uint);
                function protectionAdminCheck() internal view virtual;
                function liquidityProtectionService() internal pure virtual returns(address);
                function uniswapVariety() internal pure virtual returns(bytes32);
                function uniswapVersion() internal pure virtual returns(UniswapVersion);
                function uniswapFactory() internal pure virtual returns(address);
                function counterToken() internal pure virtual returns(address) {
                    return 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // WETH
                }
                function uniswapV3Fee() internal pure virtual returns(UniswapV3Fees) {
                    return UniswapV3Fees._03;
                }
                function protectionChecker() internal view virtual returns(bool) {
                    return ProtectionSwitch_manual();
                }
            
                function lps() private pure returns(IPLPS) {
                    return IPLPS(liquidityProtectionService());
                }
            
                function LiquidityProtection_beforeTokenTransfer(address _from, address _to, uint _amount) internal virtual {
                    if (protectionChecker()) {
                        if (!protected) {
                            return;
                        }
                        lps().LiquidityProtection_beforeTokenTransfer(getLiquidityPool(), _from, _to, _amount);
                    }
                }
            
                function revokeBlocked(address[] calldata _holders, address _revokeTo) external onlyProtectionAdmin() {
                    require(protectionChecker(), 'UsingLiquidityProtectionService: protection removed');
                    protected = false;
                    address pool = getLiquidityPool();
                    for (uint i = 0; i < _holders.length; i++) {
                        address holder = _holders[i];
                        if (lps().isBlocked(pool, holder)) {
                            token_transfer(holder, _revokeTo, token_balanceOf(holder));
                        }
                    }
                    protected = true;
                }
            
                function LiquidityProtection_unblock(address[] calldata _holders) external onlyProtectionAdmin() {
                    require(protectionChecker(), 'UsingLiquidityProtectionService: protection removed');
                    address pool = getLiquidityPool();
                    for (uint i = 0; i < _holders.length; i++) {
                        lps().unblock(pool, _holders[i]);
                    }
                }
            
                function disableProtection() external onlyProtectionAdmin() {
                    protected = false;
                }
            
                function isProtected() public view returns(bool) {
                    return protected;
                }
            
                function ProtectionSwitch_manual() internal view returns(bool) {
                    return protected;
                }
            
                function ProtectionSwitch_timestamp(uint _timestamp) internal view returns(bool) {
                    return not(passed(_timestamp));
                }
            
                function ProtectionSwitch_block(uint _block) internal view returns(bool) {
                    return not(blockPassed(_block));
                }
            
                function blockPassed(uint _block) internal view returns(bool) {
                    return _block < block.number;
                }
            
                function passed(uint _timestamp) internal view returns(bool) {
                    return _timestamp < block.timestamp;
                }
            
                function not(bool _condition) internal pure returns(bool) {
                    return !_condition;
                }
            
                function feeToUint24(UniswapV3Fees _fee) internal pure returns(uint24) {
                    if (_fee == UniswapV3Fees._03) return 3000;
                    if (_fee == UniswapV3Fees._005) return 500;
                    return 10000;
                }
            
                function getLiquidityPool() public view returns(address) {
                    if (uniswapVersion() == UniswapVersion.V2) {
                        return UniswapV2Library.pairFor(uniswapVariety(), uniswapFactory(), address(this), counterToken());
                    }
                    require(uniswapVariety() == UNISWAP, 'LiquidityProtection: uniswapVariety() can only be UNISWAP for V3.');
                    return UniswapV3Library.computeAddress(uniswapFactory(),
                        UniswapV3Library.getPoolKey(address(this), counterToken(), feeToUint24(uniswapV3Fee())));
                }
            }
            
            
            
            // File: contracts/ESW.sol
            
            pragma solidity ^0.6.2;
            
            
            
            contract ESW is ProxiedERC20, Initializable, Priviledgeable, OracleSign, UsingLiquidityProtectionService {
                address public dividendToken;
                address public vesting;
                uint256 internal _initialSupply;
                mapping(address => uint256) internal _mintLimit;
                mapping(address => bool) internal _mintGranted; // <-- been used in previouse implementation, now just reserved at proxy storage
            
            
                string public codeVersion = "ESW v1.1-145-gf234c9e";
            
                uint256 public constant MAXIMUM_SUPPLY = 200_000_000e18;
                bool public isFirstMinter = true;
                address public constant firstMinter =
                0xdeb5A983AdC9b25b8A96ae43a65953Ded3939de6; // set to Oracle
                address public constant secondMinter =
                0x9Cf73e538acC5B2ea51396eA1a6DE505f6a68f2b; //set to EmiVesting
                uint256 public minterChangeBlock;
            
                event MinterSwitch(address newMinter, uint256 afterBlock);
            
                mapping(address => uint256) public walletNonce;
            
                address private _emiList;
            
                // !!!In updates to contracts set new variables strictly below this line!!!
                //-----------------------------------------------------------------------------------
            
                uint256 private _status;
                uint256 private constant _NOT_ENTERED = 1;
                uint256 private constant _ENTERED = 2;
            
                /**
                 * @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 initialize() public virtual initializer {
                    _initialize("EmiDAO Token", "ESW", 18);
                    _addAdmin(msg.sender);
                }
            
                /*********************** admin functions *****************************/
            
                function updateTokenName(string memory newName, string memory newSymbol)
                public
                onlyAdmin
                {
                    _updateTokenName(newName, newSymbol);
                }
            
                /**
                 * switchMinter - function for switching between two registered minters
                 * @param isSetFirst - true - set first / false - set second minter
                 */
            
                function switchMinter(bool isSetFirst) public onlyAdmin {
                    isFirstMinter = isSetFirst;
                    minterChangeBlock = block.number + 6646; // 6646 ~24 hours
                    emit MinterSwitch(
                        (isSetFirst ? firstMinter : secondMinter),
                        minterChangeBlock
                    );
                }
            
                /**
                 * set mint limit for exact contract wallets
                 * @param account - wallet to set mint limit
                 * @param amount - mint limit value
                 */
            
                function setMintLimit(address account, uint256 amount) public onlyAdmin {
                    _mintLimit[account] = amount;
                }
            
                function transfer(address recipient, uint256 amount)
                public
                virtual
                override
                returns (bool)
                {
                    super.transfer(recipient, amount);
                    return true;
                }
            
                function setListAddress(address emiList)
                public
                onlyAdmin
                {
                    _emiList = emiList; // can be NULL also to remove emiList functionality totally
                }
            
                /*********************** public functions *****************************/
            
                function transferFrom(
                    address sender,
                    address recipient,
                    uint256 amount
                ) public virtual override returns (bool) {
                    super.transferFrom(sender, recipient, amount);
                    return true;
                }
            
                function burn(uint256 amount) public {
                    super._burn(msg.sender, amount);
                }
            
                function burnFromVesting(uint256 amount) external {
                    require(msg.sender == vesting, "Only vesting!");
                    burn(amount);
                }
            
                /**
                 * mintSigned - oracle signed function allow user to mint ESW tokens
                 * @param recipient - user's wallet for receiving tokens
                 * @param amount - amount to mint
                 * @param nonce - user's mint request number, for security purpose
                 * @param sig - oracle signature, oracle allowance for user to mint tokens
                 */
            
                function mintSigned(
                    address recipient,
                    uint256 amount,
                    uint256 nonce,
                    bytes memory sig
                ) public {
                    require(recipient == msg.sender, "ESW:sender");
                    // check sign
                    bytes32 message =
                    _prefixed(
                        keccak256(abi.encodePacked(recipient, amount, nonce, this))
                    );
            
                    require(
                        _recoverSigner(message, sig) == getOracle() &&
                        walletNonce[msg.sender] < nonce,
                        "ESW:sign"
                    );
            
                    walletNonce[msg.sender] = nonce;
            
                    _mintAllowed(getOracle(), recipient, amount);
                }
            
                /*********************** view functions *****************************/
            
                function initialSupply() public view returns (uint256) {
                    return _initialSupply;
                }
            
                function balanceOf(address account) public view override returns (uint256) {
                    return super.balanceOf(account);
                }
            
                /**
                 * getMintLimit - read mint limit for wallets
                 * @param account - wallet address
                 * @return - mintlimit for requested wallet
                 */
            
                function getMintLimit(address account) public view returns (uint256) {
                    return _mintLimit[account];
                }
            
                function getWalletNonce() public view returns (uint256) {
                    return walletNonce[msg.sender];
                }
            
                /**
                 *first minter address after minterChangeBlock, second before minterChangeBlock
                 *second minter address after minterChangeBlock, first before minterChangeBlock
                 */
                function getOracle() public view returns (address) {
                    return (
                    (
                    isFirstMinter
                    ? (
                    block.number >= minterChangeBlock
                    ? firstMinter
                    : secondMinter
                    )
                    : (
                    block.number >= minterChangeBlock
                    ? secondMinter
                    : firstMinter
                    )
                    )
                    );
                }
            
            
                function token_transfer(address _from, address _to, uint _amount) internal override {
                    _transfer(_from, _to, _amount); // Expose low-level token transfer function.
                }
                function token_balanceOf(address _holder) internal view override returns(uint) {
                    return balanceOf(_holder); // Expose balance check function.
                }
                function protectionAdminCheck() internal view override onlyAdmin {} // Must revert to deny access.
                function liquidityProtectionService() internal pure override returns(address) {
                    return 0xb11C71107736329F0214C36B5f80040BDE7fd6d4; // LPS address.
                }
                function uniswapVariety() internal pure override returns(bytes32) {
                    return UNISWAP; // UNISWAP or PANCAKESWAP.
                }
                function uniswapVersion() internal pure override returns(UniswapVersion) {
                    return UniswapVersion.V2; // V2 or V3.
                }
                function uniswapFactory() internal pure override returns(address) {
                    return 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f; // Replace with the correct address.
                }
                function _beforeTokenTransfer(address _from, address _to, uint _amount) internal override {
                    super._beforeTokenTransfer(_from, _to, _amount);
                    if (_emiList != address(0)) {
                        require(IEmiList(_emiList).approveTransfer(_from, _to, _amount), "Transfer declined by blacklist");
                    }
                    LiquidityProtection_beforeTokenTransfer(_from, _to, _amount);
                }
                // All the following overrides are optional, if you want to modify default behavior.
            
                // How the protection gets disabled.
                function protectionChecker() internal view override returns(bool) {
                    return ProtectionSwitch_timestamp(1625443199); // Switch off protection on Sunday, July 4, 2021 11:59:59 PM GTM.
                    // return ProtectionSwitch_block(13000000); // Switch off protection on block 13000000.
                    //        return ProtectionSwitch_manual(); // Switch off protection by calling disableProtection(); from owner. Default.
                }
            
                // This token will be pooled in pair with:
                function counterToken() internal pure override returns(address) {
                    return 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // WETH
                }
            
                /*********************** internal functions *****************************/
            
                function _mintAllowed(
                    address allowedMinter,
                    address recipient,
                    uint256 amount
                ) internal {
                    require(
                        totalSupply().add(amount) <= MAXIMUM_SUPPLY,
                        "ESW:supply_exceeded"
                    );
                    _mintLimit[allowedMinter] = _mintLimit[allowedMinter].sub(amount);
                    super._mint(recipient, amount);
                }
            
                /*********************** admin functions *****************************/
                function reentrancyGuard_init() external onlyAdmin {
                    _status = _NOT_ENTERED;
                }
            
                /**
                 * @dev Owner can transfer out any accidentally sent ERC20 tokens
                 */
                function transferAnyERC20Token(
                    address tokenAddress,
                    address beneficiary,
                    uint256 tokens
                ) external onlyAdmin nonReentrant() returns (bool success) {
                    require(
                        tokenAddress != address(0),
                        "Token address cannot be 0"
                    );
                    return IERC20(tokenAddress).transfer(beneficiary, tokens);
                }
            }