ETH Price: $2,770.68 (+6.93%)

Transaction Decoder

Block:
14351124 at Mar-09-2022 06:52:35 AM +UTC
Transaction Fee:
0.00234371766457125 ETH $6.49
Gas Used:
58,750 Gas / 39.893066631 Gwei

Emitted Events:

69 Fei.Transfer( from=[Receiver] EIP173Proxy, to=[Sender] 0x1e3882aff34c1eaf5507e77026f215085bda1e19, value=400000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x1E3882aF...85bda1e19
6.590410289625328364 Eth
Nonce: 733
6.588066571960757114 Eth
Nonce: 734
0.00234371766457125
0x57a7a432...5c13940b7
(Gelato Whitehat Contract)
(F2Pool Old)
2,575.814272362388993375 Eth2,575.814715517549217125 Eth0.00044315516022375
0x956F47F5...73E7f87CA

Execution Trace

EIP173Proxy.318d9e5d( )
  • 0xd340b134146c6fe879b00cc0a19011c4941c00c8.318d9e5d( )
    • Fei.allowance( owner=0x1E3882aFF34C1eaF5507e77026F215085bda1e19, spender=0x14E6D67F824C3a7b4329d3228807f8654294e4bd ) => ( 0 )
    • Fei.transfer( recipient=0x1E3882aFF34C1eaF5507e77026F215085bda1e19, amount=400000000000000000000 ) => ( True )
      File 1 of 2: EIP173Proxy
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.7.0;
      import "./Proxy.sol";
      interface ERC165 {
          function supportsInterface(bytes4 id) external view returns (bool);
      }
      ///@notice Proxy implementing EIP173 for ownership management
      contract EIP173Proxy is Proxy {
          // ////////////////////////// EVENTS ///////////////////////////////////////////////////////////////////////
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
          // /////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////
          constructor(
              address implementationAddress,
              address ownerAddress,
              bytes memory data
          ) payable {
              _setImplementation(implementationAddress, data);
              _setOwner(ownerAddress);
          }
          // ///////////////////// EXTERNAL ///////////////////////////////////////////////////////////////////////////
          function owner() external view returns (address) {
              return _owner();
          }
          function supportsInterface(bytes4 id) external view returns (bool) {
              if (id == 0x01ffc9a7 || id == 0x7f5828d0) {
                  return true;
              }
              if (id == 0xFFFFFFFF) {
                  return false;
              }
              ERC165 implementation;
              // solhint-disable-next-line security/no-inline-assembly
              assembly {
                  implementation := sload(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc)
              }
              // Technically this is not standard compliant as ERC-165 require 30,000 gas which that call cannot ensure
              // because it is itself inside `supportsInterface` that might only get 30,000 gas.
              // In practise this is unlikely to be an issue.
              try implementation.supportsInterface(id) returns (bool support) {
                  return support;
              } catch {
                  return false;
              }
          }
          function transferOwnership(address newOwner) external onlyOwner {
              _setOwner(newOwner);
          }
          function upgradeTo(address newImplementation) external onlyOwner {
              _setImplementation(newImplementation, "");
          }
          function upgradeToAndCall(address newImplementation, bytes calldata data) external payable onlyOwner {
              _setImplementation(newImplementation, data);
          }
          // /////////////////////// MODIFIERS ////////////////////////////////////////////////////////////////////////
          modifier onlyOwner() {
              require(msg.sender == _owner(), "NOT_AUTHORIZED");
              _;
          }
          // ///////////////////////// INTERNAL //////////////////////////////////////////////////////////////////////
          function _owner() internal view returns (address adminAddress) {
              // solhint-disable-next-line security/no-inline-assembly
              assembly {
                  adminAddress := sload(0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103)
              }
          }
          function _setOwner(address newOwner) internal {
              address previousOwner = _owner();
              // solhint-disable-next-line security/no-inline-assembly
              assembly {
                  sstore(0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103, newOwner)
              }
              emit OwnershipTransferred(previousOwner, newOwner);
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.7.0;
      // EIP-1967
      abstract contract Proxy {
          // /////////////////////// EVENTS ///////////////////////////////////////////////////////////////////////////
          event ProxyImplementationUpdated(address indexed previousImplementation, address indexed newImplementation);
          // ///////////////////// EXTERNAL ///////////////////////////////////////////////////////////////////////////
          receive() external payable virtual {
              revert("ETHER_REJECTED"); // explicit reject by default
          }
          fallback() external payable {
              _fallback();
          }
          // ///////////////////////// INTERNAL //////////////////////////////////////////////////////////////////////
          function _fallback() internal {
              // solhint-disable-next-line security/no-inline-assembly
              assembly {
                  let implementationAddress := sload(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc)
                  calldatacopy(0x0, 0x0, calldatasize())
                  let success := delegatecall(gas(), implementationAddress, 0x0, calldatasize(), 0, 0)
                  let retSz := returndatasize()
                  returndatacopy(0, 0, retSz)
                  switch success
                      case 0 {
                          revert(0, retSz)
                      }
                      default {
                          return(0, retSz)
                      }
              }
          }
          function _setImplementation(address newImplementation, bytes memory data) internal {
              address previousImplementation;
              // solhint-disable-next-line security/no-inline-assembly
              assembly {
                  previousImplementation := sload(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc)
              }
              // solhint-disable-next-line security/no-inline-assembly
              assembly {
                  sstore(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc, newImplementation)
              }
              emit ProxyImplementationUpdated(previousImplementation, newImplementation);
              if (data.length > 0) {
                  (bool success, ) = newImplementation.delegatecall(data);
                  if (!success) {
                      assembly {
                          // This assembly ensure the revert contains the exact string data
                          let returnDataSize := returndatasize()
                          returndatacopy(0, 0, returnDataSize)
                          revert(0, returnDataSize)
                      }
                  }
              }
          }
      }
      

      File 2 of 2: Fei
      pragma solidity ^0.6.0;
      pragma experimental ABIEncoderV2;
      import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol";
      import "@openzeppelin/contracts/utils/Address.sol";
      import "./IIncentive.sol";
      import "./IFei.sol";
      import "../refs/CoreRef.sol";
      /// @title FEI stablecoin
      /// @author Fei Protocol
      contract Fei is IFei, ERC20Burnable, CoreRef {
          
          /// @notice get associated incentive contract, 0 address if N/A
          mapping(address => address) public override incentiveContract;
          // solhint-disable-next-line var-name-mixedcase
          bytes32 public DOMAIN_SEPARATOR;
          // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
          bytes32 public constant PERMIT_TYPEHASH =
              0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
          mapping(address => uint256) public nonces;
          /// @notice Fei token constructor
          /// @param core Fei Core address to reference
          constructor(address core) public ERC20("Fei USD", "FEI") CoreRef(core) {
              uint256 chainId;
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  chainId := chainid()
              }
              DOMAIN_SEPARATOR = keccak256(
                  abi.encode(
                      keccak256(
                          "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                      ),
                      keccak256(bytes(name())),
                      keccak256(bytes("1")),
                      chainId,
                      address(this)
                  )
              );
          }
          /// @param account the account to incentivize
          /// @param incentive the associated incentive contract
          function setIncentiveContract(address account, address incentive)
              external
              override
              onlyGovernor
          {
              incentiveContract[account] = incentive;
              emit IncentiveContractUpdate(account, incentive);
          }
          /// @notice mint FEI tokens
          /// @param account the account to mint to
          /// @param amount the amount to mint
          function mint(address account, uint256 amount)
              external
              override
              onlyMinter
              whenNotPaused
          {
              _mint(account, amount);
              emit Minting(account, msg.sender, amount);
          }
          /// @notice burn FEI tokens from caller
          /// @param amount the amount to burn
          function burn(uint256 amount) public override(IFei, ERC20Burnable) {
              super.burn(amount);
              emit Burning(msg.sender, msg.sender, amount);
          }
          /// @notice burn FEI tokens from specified account
          /// @param account the account to burn from
          /// @param amount the amount to burn
          function burnFrom(address account, uint256 amount)
              public
              override(IFei, ERC20Burnable)
              onlyBurner
              whenNotPaused
          {
              _burn(account, amount);
              emit Burning(account, msg.sender, amount);
          }
          function _transfer(
              address sender,
              address recipient,
              uint256 amount
          ) internal override {
              super._transfer(sender, recipient, amount);
              _checkAndApplyIncentives(sender, recipient, amount);
          }
          function _checkAndApplyIncentives(
              address sender,
              address recipient,
              uint256 amount
          ) internal {
              // incentive on sender
              address senderIncentive = incentiveContract[sender];
              if (senderIncentive != address(0)) {
                  IIncentive(senderIncentive).incentivize(
                      sender,
                      recipient,
                      msg.sender,
                      amount
                  );
              }
              // incentive on recipient
              address recipientIncentive = incentiveContract[recipient];
              if (recipientIncentive != address(0)) {
                  IIncentive(recipientIncentive).incentivize(
                      sender,
                      recipient,
                      msg.sender,
                      amount
                  );
              }
              // incentive on operator
              address operatorIncentive = incentiveContract[msg.sender];
              if (
                  msg.sender != sender &&
                  msg.sender != recipient &&
                  operatorIncentive != address(0)
              ) {
                  IIncentive(operatorIncentive).incentivize(
                      sender,
                      recipient,
                      msg.sender,
                      amount
                  );
              }
              // all incentive, if active applies to every transfer
              address allIncentive = incentiveContract[address(0)];
              if (allIncentive != address(0)) {
                  IIncentive(allIncentive).incentivize(
                      sender,
                      recipient,
                      msg.sender,
                      amount
                  );
              }
          }
          /// @notice permit spending of FEI
          /// @param owner the FEI holder
          /// @param spender the approved operator
          /// @param value the amount approved
          /// @param deadline the deadline after which the approval is no longer valid
          function permit(
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) external override {
              // solhint-disable-next-line not-rely-on-time
              require(deadline >= block.timestamp, "Fei: EXPIRED");
              bytes32 digest =
                  keccak256(
                      abi.encodePacked(
                          "\\x19\\x01",
                          DOMAIN_SEPARATOR,
                          keccak256(
                              abi.encode(
                                  PERMIT_TYPEHASH,
                                  owner,
                                  spender,
                                  value,
                                  nonces[owner]++,
                                  deadline
                              )
                          )
                      )
                  );
              address recoveredAddress = ecrecover(digest, v, r, s);
              require(
                  recoveredAddress != address(0) && recoveredAddress == owner,
                  "Fei: INVALID_SIGNATURE"
              );
              _approve(owner, spender, value);
          }
      }
      pragma solidity ^0.6.2;
      /// @title incentive contract interface
      /// @author Fei Protocol
      /// @notice Called by FEI token contract when transferring with an incentivized address
      /// @dev should be appointed as a Minter or Burner as needed
      interface IIncentive {
          // ----------- Fei only state changing api -----------
          /// @notice apply incentives on transfer
          /// @param sender the sender address of the FEI
          /// @param receiver the receiver address of the FEI
          /// @param operator the operator (msg.sender) of the transfer
          /// @param amount the amount of FEI transferred
          function incentivize(
              address sender,
              address receiver,
              address operator,
              uint256 amount
          ) external;
      }
      pragma solidity ^0.6.2;
      import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
      /// @title FEI stablecoin interface
      /// @author Fei Protocol
      interface IFei is IERC20 {
          // ----------- Events -----------
          event Minting(
              address indexed _to,
              address indexed _minter,
              uint256 _amount
          );
          event Burning(
              address indexed _to,
              address indexed _burner,
              uint256 _amount
          );
          event IncentiveContractUpdate(
              address indexed _incentivized,
              address indexed _incentiveContract
          );
          // ----------- State changing api -----------
          function burn(uint256 amount) external;
          function permit(
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) external;
          // ----------- Burner only state changing api -----------
          function burnFrom(address account, uint256 amount) external;
          // ----------- Minter only state changing api -----------
          function mint(address account, uint256 amount) external;
          // ----------- Governor only state changing api -----------
          function setIncentiveContract(address account, address incentive) external;
          // ----------- Getters -----------
          function incentiveContract(address account) external view returns (address);
      }
      pragma solidity ^0.6.0;
      pragma experimental ABIEncoderV2;
      import "./ICoreRef.sol";
      import "@openzeppelin/contracts/utils/Pausable.sol";
      import "@openzeppelin/contracts/utils/Address.sol";
      /// @title A Reference to Core
      /// @author Fei Protocol
      /// @notice defines some modifiers and utilities around interacting with Core
      abstract contract CoreRef is ICoreRef, Pausable {
          ICore private _core;
          /// @notice CoreRef constructor
          /// @param core Fei Core to reference
          constructor(address core) public {
              _core = ICore(core);
          }
          modifier ifMinterSelf() {
              if (_core.isMinter(address(this))) {
                  _;
              }
          }
          modifier ifBurnerSelf() {
              if (_core.isBurner(address(this))) {
                  _;
              }
          }
          modifier onlyMinter() {
              require(_core.isMinter(msg.sender), "CoreRef: Caller is not a minter");
              _;
          }
          modifier onlyBurner() {
              require(_core.isBurner(msg.sender), "CoreRef: Caller is not a burner");
              _;
          }
          modifier onlyPCVController() {
              require(
                  _core.isPCVController(msg.sender),
                  "CoreRef: Caller is not a PCV controller"
              );
              _;
          }
          modifier onlyGovernor() {
              require(
                  _core.isGovernor(msg.sender),
                  "CoreRef: Caller is not a governor"
              );
              _;
          }
          modifier onlyGuardianOrGovernor() {
              require(
                  _core.isGovernor(msg.sender) ||
                  _core.isGuardian(msg.sender),
                  "CoreRef: Caller is not a guardian or governor"
              );
              _;
          }
          modifier onlyFei() {
              require(msg.sender == address(fei()), "CoreRef: Caller is not FEI");
              _;
          }
          modifier onlyGenesisGroup() {
              require(
                  msg.sender == _core.genesisGroup(),
                  "CoreRef: Caller is not GenesisGroup"
              );
              _;
          }
          modifier postGenesis() {
              require(
                  _core.hasGenesisGroupCompleted(),
                  "CoreRef: Still in Genesis Period"
              );
              _;
          }
          modifier nonContract() {
              require(!Address.isContract(msg.sender), "CoreRef: Caller is a contract");
              _;
          }
          /// @notice set new Core reference address
          /// @param core the new core address
          function setCore(address core) external override onlyGovernor {
              _core = ICore(core);
              emit CoreUpdate(core);
          }
          /// @notice set pausable methods to paused
          function pause() public override onlyGuardianOrGovernor {
              _pause();
          }
          /// @notice set pausable methods to unpaused
          function unpause() public override onlyGuardianOrGovernor {
              _unpause();
          }
          /// @notice address of the Core contract referenced
          /// @return ICore implementation address
          function core() public view override returns (ICore) {
              return _core;
          }
          /// @notice address of the Fei contract referenced by Core
          /// @return IFei implementation address
          function fei() public view override returns (IFei) {
              return _core.fei();
          }
          /// @notice address of the Tribe contract referenced by Core
          /// @return IERC20 implementation address
          function tribe() public view override returns (IERC20) {
              return _core.tribe();
          }
          /// @notice fei balance of contract
          /// @return fei amount held
          function feiBalance() public view override returns (uint256) {
              return fei().balanceOf(address(this));
          }
          /// @notice tribe balance of contract
          /// @return tribe amount held
          function tribeBalance() public view override returns (uint256) {
              return tribe().balanceOf(address(this));
          }
          function _burnFeiHeld() internal {
              fei().burn(feiBalance());
          }
          function _mintFei(uint256 amount) internal {
              fei().mint(address(this), amount);
          }
      }
      pragma solidity ^0.6.0;
      pragma experimental ABIEncoderV2;
      import "../core/ICore.sol";
      /// @title CoreRef interface
      /// @author Fei Protocol
      interface ICoreRef {
          // ----------- Events -----------
          event CoreUpdate(address indexed _core);
          // ----------- Governor only state changing api -----------
          function setCore(address core) external;
          function pause() external;
          function unpause() external;
          // ----------- Getters -----------
          function core() external view returns (ICore);
          function fei() external view returns (IFei);
          function tribe() external view returns (IERC20);
          function feiBalance() external view returns (uint256);
          function tribeBalance() external view returns (uint256);
      }
      pragma solidity ^0.6.0;
      pragma experimental ABIEncoderV2;
      import "./IPermissions.sol";
      import "../token/IFei.sol";
      /// @title Core Interface
      /// @author Fei Protocol
      interface ICore is IPermissions {
          // ----------- Events -----------
          event FeiUpdate(address indexed _fei);
          event TribeUpdate(address indexed _tribe);
          event GenesisGroupUpdate(address indexed _genesisGroup);
          event TribeAllocation(address indexed _to, uint256 _amount);
          event GenesisPeriodComplete(uint256 _timestamp);
          // ----------- Governor only state changing api -----------
          function init() external;
          // ----------- Governor only state changing api -----------
          function setFei(address token) external;
          function setTribe(address token) external;
          function setGenesisGroup(address _genesisGroup) external;
          function allocateTribe(address to, uint256 amount) external;
          // ----------- Genesis Group only state changing api -----------
          function completeGenesisGroup() external;
          // ----------- Getters -----------
          function fei() external view returns (IFei);
          function tribe() external view returns (IERC20);
          function genesisGroup() external view returns (address);
          function hasGenesisGroupCompleted() external view returns (bool);
      }
      pragma solidity ^0.6.0;
      pragma experimental ABIEncoderV2;
      /// @title Permissions interface
      /// @author Fei Protocol
      interface IPermissions {
          // ----------- Governor only state changing api -----------
          function createRole(bytes32 role, bytes32 adminRole) external;
          function grantMinter(address minter) external;
          function grantBurner(address burner) external;
          function grantPCVController(address pcvController) external;
          function grantGovernor(address governor) external;
          function grantGuardian(address guardian) external;
          function revokeMinter(address minter) external;
          function revokeBurner(address burner) external;
          function revokePCVController(address pcvController) external;
          function revokeGovernor(address governor) external;
          function revokeGuardian(address guardian) external;
          // ----------- Revoker only state changing api -----------
          function revokeOverride(bytes32 role, address account) external;
          // ----------- Getters -----------
          function isBurner(address _address) external view returns (bool);
          function isMinter(address _address) external view returns (bool);
          function isGovernor(address _address) external view returns (bool);
          function isGuardian(address _address) external view returns (bool);
          function isPCVController(address _address) external view returns (bool);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity >=0.6.0 <0.8.0;
      import "../../utils/Context.sol";
      import "./ERC20.sol";
      /**
       * @dev Extension of {ERC20} that allows token holders to destroy both their own
       * tokens and those that they have an allowance for, in a way that can be
       * recognized off-chain (via event analysis).
       */
      abstract contract ERC20Burnable is Context, ERC20 {
          using SafeMath for uint256;
          /**
           * @dev Destroys `amount` tokens from the caller.
           *
           * See {ERC20-_burn}.
           */
          function burn(uint256 amount) public virtual {
              _burn(_msgSender(), amount);
          }
          /**
           * @dev Destroys `amount` tokens from `account`, deducting from the caller's
           * allowance.
           *
           * See {ERC20-_burn} and {ERC20-allowance}.
           *
           * Requirements:
           *
           * - the caller must have allowance for ``accounts``'s tokens of at least
           * `amount`.
           */
          function burnFrom(address account, uint256 amount) public virtual {
              uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance");
              _approve(account, _msgSender(), decreasedAllowance);
              _burn(account, amount);
          }
      }
      // 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;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity >=0.6.0 <0.8.0;
      import "../../utils/Context.sol";
      import "./IERC20.sol";
      import "../../math/SafeMath.sol";
      /**
       * @dev Implementation of the {IERC20} interface.
       *
       * This implementation is agnostic to the way tokens are created. This means
       * that a supply mechanism has to be added in a derived contract using {_mint}.
       * For a generic mechanism see {ERC20PresetMinterPauser}.
       *
       * TIP: For a detailed writeup see our guide
       * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
       * to implement supply mechanisms].
       *
       * We have followed general OpenZeppelin guidelines: functions revert instead
       * of returning `false` on failure. This behavior is nonetheless conventional
       * and does not conflict with the expectations of ERC20 applications.
       *
       * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
       * This allows applications to reconstruct the allowance for all accounts just
       * by listening to said events. Other implementations of the EIP may not emit
       * these events, as it isn't required by the specification.
       *
       * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
       * functions have been added to mitigate the well-known issues around setting
       * allowances. See {IERC20-approve}.
       */
      contract ERC20 is Context, IERC20 {
          using SafeMath for uint256;
          mapping (address => uint256) private _balances;
          mapping (address => mapping (address => uint256)) private _allowances;
          uint256 private _totalSupply;
          string private _name;
          string private _symbol;
          uint8 private _decimals;
          /**
           * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
           * a default value of 18.
           *
           * To select a different value for {decimals}, use {_setupDecimals}.
           *
           * All three of these values are immutable: they can only be set once during
           * construction.
           */
          constructor (string memory name_, string memory symbol_) public {
              _name = name_;
              _symbol = symbol_;
              _decimals = 18;
          }
          /**
           * @dev Returns the name of the token.
           */
          function name() public view virtual returns (string memory) {
              return _name;
          }
          /**
           * @dev Returns the symbol of the token, usually a shorter version of the
           * name.
           */
          function symbol() public view virtual 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 virtual returns (uint8) {
              return _decimals;
          }
          /**
           * @dev See {IERC20-totalSupply}.
           */
          function totalSupply() public view virtual 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 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 Sets {decimals} to a value other than the default one of 18.
           *
           * WARNING: This function should only be called from the constructor. Most
           * applications that interact with token contracts will not expect
           * {decimals} to ever change, and may work incorrectly if it does.
           */
          function _setupDecimals(uint8 decimals_) internal virtual {
              _decimals = decimals_;
          }
          /**
           * @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 { }
      }
      // 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);
      }
      // 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;
          }
      }
      // 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);
                  }
              }
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity >=0.6.0 <0.8.0;
      import "./Context.sol";
      /**
       * @dev Contract module which allows children to implement an emergency stop
       * mechanism that can be triggered by an authorized account.
       *
       * This module is used through inheritance. It will make available the
       * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
       * the functions of your contract. Note that they will not be pausable by
       * simply including this module, only once the modifiers are put in place.
       */
      abstract contract Pausable is Context {
          /**
           * @dev Emitted when the pause is triggered by `account`.
           */
          event Paused(address account);
          /**
           * @dev Emitted when the pause is lifted by `account`.
           */
          event Unpaused(address account);
          bool private _paused;
          /**
           * @dev Initializes the contract in unpaused state.
           */
          constructor () internal {
              _paused = false;
          }
          /**
           * @dev Returns true if the contract is paused, and false otherwise.
           */
          function paused() public view virtual returns (bool) {
              return _paused;
          }
          /**
           * @dev Modifier to make a function callable only when the contract is not paused.
           *
           * Requirements:
           *
           * - The contract must not be paused.
           */
          modifier whenNotPaused() {
              require(!paused(), "Pausable: paused");
              _;
          }
          /**
           * @dev Modifier to make a function callable only when the contract is paused.
           *
           * Requirements:
           *
           * - The contract must be paused.
           */
          modifier whenPaused() {
              require(paused(), "Pausable: not paused");
              _;
          }
          /**
           * @dev Triggers stopped state.
           *
           * Requirements:
           *
           * - The contract must not be paused.
           */
          function _pause() internal virtual whenNotPaused {
              _paused = true;
              emit Paused(_msgSender());
          }
          /**
           * @dev Returns to normal state.
           *
           * Requirements:
           *
           * - The contract must be paused.
           */
          function _unpause() internal virtual whenPaused {
              _paused = false;
              emit Unpaused(_msgSender());
          }
      }