ETH Price: $2,276.03 (+7.35%)

Transaction Decoder

Block:
10640236 at Aug-11-2020 06:26:32 PM +UTC
Transaction Fee:
0.01153585 ETH $26.26
Gas Used:
121,430 Gas / 95 Gwei

Emitted Events:

126 BaseToken.Transfer( from=[Receiver] AdminUpgradeabilityProxy, to=[Sender] 0xcb4d229f5b3fcbbecc1edb36b95d5648c4bbf03b, value=13003901170351105331 )
127 AdminUpgradeabilityProxy.0xd6d4f5681c246c9f42c203e287975af1601f8df8035a9251f79aab5c8f09e2f8( 0xd6d4f5681c246c9f42c203e287975af1601f8df8035a9251f79aab5c8f09e2f8, 000000000000000000000000b127f9e43689d6e5a93b608445d81e6db0ebc311, 000000000000000000000000cb4d229f5b3fcbbecc1edb36b95d5648c4bbf03b, 000000000000000000000000ed1199093b1abd07a368dd1c0cdc77d8517ba2a0, 0000000000000000000000000000000000000000000000000000000000000000, 000000000000000000000000000000000000000000000000b477233781106533, 0000000000000000000000000000000000000000000000000de0b6b3a7640000 )

Account State Difference:

  Address   Before After State Difference Code
(Spark Pool)
100.492524005887223374 Eth100.504059855887223374 Eth0.01153585
0x73282A63...1ecA3C86A
(Bounce Finance: Bounce Swap Proxy)
0xB127F9E4...DB0ebC311 34.889101692690653488 Eth35.889101692690653488 Eth1
0xCB4D229F...8c4bBf03B
4.682243255 Eth
Nonce: 310
3.670707405 Eth
Nonce: 311
1.01153585
0xEd119909...8517BA2A0

Execution Trace

ETH 1 AdminUpgradeabilityProxy.ebeee70c( )
  • ETH 1 0x74e6fc4540ccd6d31eeec1fc3c80dee2f68623b6.ebeee70c( )
    • BaseToken.transfer( to=0xCB4D229F5b3fcbBECc1Edb36b95D5648c4bBf03B, value=13003901170351105331 ) => ( True )
    • ETH 1 0xb127f9e43689d6e5a93b608445d81e6db0ebc311.CALL( )
      File 1 of 2: AdminUpgradeabilityProxy
      // File: @openzeppelin/upgrades/contracts/upgradeability/Proxy.sol
      
      pragma solidity ^0.5.0;
      
      /**
       * @title Proxy
       * @dev Implements delegation of calls to other contracts, with proper
       * forwarding of return values and bubbling of failures.
       * It defines a fallback function that delegates all calls to the address
       * returned by the abstract _implementation() internal function.
       */
      contract Proxy {
        /**
         * @dev Fallback function.
         * Implemented entirely in `_fallback`.
         */
        function () payable external {
          _fallback();
        }
      
        /**
         * @return The Address of the implementation.
         */
        function _implementation() internal view returns (address);
      
        /**
         * @dev Delegates execution to an implementation contract.
         * This is a low level function that doesn't return to its internal call site.
         * It will return to the external caller whatever the implementation returns.
         * @param implementation Address to delegate.
         */
        function _delegate(address implementation) internal {
          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 Function that is run as the first thing in the fallback function.
         * Can be redefined in derived contracts to add functionality.
         * Redefinitions must call super._willFallback().
         */
        function _willFallback() internal {
        }
      
        /**
         * @dev fallback implementation.
         * Extracted to enable manual triggering.
         */
        function _fallback() internal {
          _willFallback();
          _delegate(_implementation());
        }
      }
      
      // File: @openzeppelin/upgrades/contracts/utils/Address.sol
      
      pragma solidity ^0.5.0;
      
      /**
       * Utility library of inline functions on addresses
       *
       * Source https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-solidity/v2.1.3/contracts/utils/Address.sol
       * This contract is copied here and renamed from the original to avoid clashes in the compiled artifacts
       * when the user imports a zos-lib contract (that transitively causes this contract to be compiled and added to the
       * build/artifacts folder) as well as the vanilla Address implementation from an openzeppelin version.
       */
      library OpenZeppelinUpgradesAddress {
          /**
           * Returns whether the target address is a contract
           * @dev This function will return false if invoked during the constructor of a contract,
           * as the code is not actually created until after the constructor finishes.
           * @param account address of the account to check
           * @return whether the target address is a contract
           */
          function isContract(address account) internal view returns (bool) {
              uint256 size;
              // XXX Currently there is no better way to check if there is a contract in an address
              // than to check the size of the code at that address.
              // See https://ethereum.stackexchange.com/a/14016/36603
              // for more details about how this works.
              // TODO Check this again before the Serenity release, because all addresses will be
              // contracts then.
              // solhint-disable-next-line no-inline-assembly
              assembly { size := extcodesize(account) }
              return size > 0;
          }
      }
      
      // File: @openzeppelin/upgrades/contracts/upgradeability/BaseUpgradeabilityProxy.sol
      
      pragma solidity ^0.5.0;
      
      
      
      /**
       * @title BaseUpgradeabilityProxy
       * @dev This contract implements a proxy that allows to change the
       * implementation address to which it will delegate.
       * Such a change is called an implementation upgrade.
       */
      contract BaseUpgradeabilityProxy is Proxy {
        /**
         * @dev Emitted when the implementation is upgraded.
         * @param implementation Address of the new implementation.
         */
        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 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
      
        /**
         * @dev Returns the current implementation.
         * @return Address of the current implementation
         */
        function _implementation() internal view returns (address impl) {
          bytes32 slot = IMPLEMENTATION_SLOT;
          assembly {
            impl := sload(slot)
          }
        }
      
        /**
         * @dev Upgrades the proxy to a new implementation.
         * @param newImplementation Address of the new implementation.
         */
        function _upgradeTo(address newImplementation) internal {
          _setImplementation(newImplementation);
          emit Upgraded(newImplementation);
        }
      
        /**
         * @dev Sets the implementation address of the proxy.
         * @param newImplementation Address of the new implementation.
         */
        function _setImplementation(address newImplementation) internal {
          require(OpenZeppelinUpgradesAddress.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address");
      
          bytes32 slot = IMPLEMENTATION_SLOT;
      
          assembly {
            sstore(slot, newImplementation)
          }
        }
      }
      
      // File: @openzeppelin/upgrades/contracts/upgradeability/UpgradeabilityProxy.sol
      
      pragma solidity ^0.5.0;
      
      
      /**
       * @title UpgradeabilityProxy
       * @dev Extends BaseUpgradeabilityProxy with a constructor for initializing
       * implementation and init data.
       */
      contract UpgradeabilityProxy is BaseUpgradeabilityProxy {
        /**
         * @dev Contract constructor.
         * @param _logic Address of the initial implementation.
         * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
         * It should include the signature and the parameters of the function to be called, as described in
         * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
         * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
         */
        constructor(address _logic, bytes memory _data) public payable {
          assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
          _setImplementation(_logic);
          if(_data.length > 0) {
            (bool success,) = _logic.delegatecall(_data);
            require(success);
          }
        }  
      }
      
      // File: @openzeppelin/upgrades/contracts/upgradeability/BaseAdminUpgradeabilityProxy.sol
      
      pragma solidity ^0.5.0;
      
      
      /**
       * @title BaseAdminUpgradeabilityProxy
       * @dev This contract combines an upgradeability proxy with an authorization
       * mechanism for administrative tasks.
       * All external functions in this contract must be guarded by the
       * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
       * feature proposal that would enable this to be done automatically.
       */
      contract BaseAdminUpgradeabilityProxy is BaseUpgradeabilityProxy {
        /**
         * @dev Emitted when the administration has been transferred.
         * @param previousAdmin Address of the previous admin.
         * @param newAdmin Address of the new admin.
         */
        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 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
      
        /**
         * @dev Modifier to check whether the `msg.sender` is the admin.
         * If it is, it will run the function. Otherwise, it will delegate the call
         * to the implementation.
         */
        modifier ifAdmin() {
          if (msg.sender == _admin()) {
            _;
          } else {
            _fallback();
          }
        }
      
        /**
         * @return The address of the proxy admin.
         */
        function admin() external ifAdmin returns (address) {
          return _admin();
        }
      
        /**
         * @return The address of the implementation.
         */
        function implementation() external ifAdmin returns (address) {
          return _implementation();
        }
      
        /**
         * @dev Changes the admin of the proxy.
         * Only the current admin can call this function.
         * @param newAdmin Address to transfer proxy administration to.
         */
        function changeAdmin(address newAdmin) external ifAdmin {
          require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address");
          emit AdminChanged(_admin(), newAdmin);
          _setAdmin(newAdmin);
        }
      
        /**
         * @dev Upgrade the backing implementation of the proxy.
         * Only the admin can call this function.
         * @param newImplementation Address of the new implementation.
         */
        function upgradeTo(address newImplementation) external ifAdmin {
          _upgradeTo(newImplementation);
        }
      
        /**
         * @dev Upgrade the backing implementation of the proxy and call a function
         * on the new implementation.
         * This is useful to initialize the proxied contract.
         * @param newImplementation Address of the new implementation.
         * @param data Data to send as msg.data in the low level call.
         * It should include the signature and the parameters of the function to be called, as described in
         * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
         */
        function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin {
          _upgradeTo(newImplementation);
          (bool success,) = newImplementation.delegatecall(data);
          require(success);
        }
      
        /**
         * @return The admin slot.
         */
        function _admin() internal view returns (address adm) {
          bytes32 slot = ADMIN_SLOT;
          assembly {
            adm := sload(slot)
          }
        }
      
        /**
         * @dev Sets the address of the proxy admin.
         * @param newAdmin Address of the new proxy admin.
         */
        function _setAdmin(address newAdmin) internal {
          bytes32 slot = ADMIN_SLOT;
      
          assembly {
            sstore(slot, newAdmin)
          }
        }
      
        /**
         * @dev Only fall back when the sender is not the admin.
         */
        function _willFallback() internal {
          require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin");
          super._willFallback();
        }
      }
      
      // File: @openzeppelin/upgrades/contracts/upgradeability/AdminUpgradeabilityProxy.sol
      
      pragma solidity ^0.5.0;
      
      
      /**
       * @title AdminUpgradeabilityProxy
       * @dev Extends from BaseAdminUpgradeabilityProxy with a constructor for 
       * initializing the implementation, admin, and init data.
       */
      contract AdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, UpgradeabilityProxy {
        /**
         * Contract constructor.
         * @param _logic address of the initial implementation.
         * @param _admin Address of the proxy administrator.
         * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
         * It should include the signature and the parameters of the function to be called, as described in
         * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
         * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
         */
        constructor(address _logic, address _admin, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable {
          assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
          _setAdmin(_admin);
        }
      }

      File 2 of 2: BaseToken
      // BUILT FOR FREE ON https://vittominacori.github.io/erc20-generator
      
      // File: @openzeppelin/contracts/GSN/Context.sol
      
      pragma solidity ^0.6.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.
       */
      contract Context {
          // Empty internal constructor, to prevent people from mistakenly deploying
          // an instance of this contract, which should be used via inheritance.
          constructor () internal { }
      
          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/token/ERC20/IERC20.sol
      
      pragma solidity ^0.6.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/math/SafeMath.sol
      
      pragma solidity ^0.6.0;
      
      /**
       * @dev Wrappers over Solidity's arithmetic operations with added overflow
       * checks.
       *
       * Arithmetic operations in Solidity wrap on overflow. This can easily result
       * in bugs, because programmers usually assume that an overflow raises an
       * error, which is the standard behavior in high level programming languages.
       * `SafeMath` restores this intuition by reverting the transaction when an
       * operation overflows.
       *
       * Using this library instead of the unchecked operations eliminates an entire
       * class of bugs, so it's recommended to use it always.
       */
      library SafeMath {
          /**
           * @dev Returns the addition of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a, "SafeMath: addition overflow");
      
              return c;
          }
      
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              return sub(a, b, "SafeMath: subtraction overflow");
          }
      
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b <= a, errorMessage);
              uint256 c = a - b;
      
              return c;
          }
      
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
              // benefit is lost if 'b' is also tested.
              // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
              if (a == 0) {
                  return 0;
              }
      
              uint256 c = a * b;
              require(c / a == b, "SafeMath: multiplication overflow");
      
              return c;
          }
      
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return div(a, b, "SafeMath: division by zero");
          }
      
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              // Solidity only automatically asserts when dividing by 0
              require(b > 0, errorMessage);
              uint256 c = a / b;
              // assert(a == b * c + a % b); // There is no case in which this doesn't hold
      
              return c;
          }
      
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
              return mod(a, b, "SafeMath: modulo by zero");
          }
      
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts with custom message when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b != 0, errorMessage);
              return a % b;
          }
      }
      
      // File: @openzeppelin/contracts/utils/Address.sol
      
      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) {
              // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
              // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
              // for accounts without code, i.e. `keccak256('')`
              bytes32 codehash;
              bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
              // solhint-disable-next-line no-inline-assembly
              assembly { codehash := extcodehash(account) }
              return (codehash != accountHash && codehash != 0x0);
          }
      
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              require(address(this).balance >= amount, "Address: insufficient balance");
      
              // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
              (bool success, ) = recipient.call{ value: amount }("");
              require(success, "Address: unable to send value, recipient may have reverted");
          }
      }
      
      // File: @openzeppelin/contracts/token/ERC20/ERC20.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 {ERC20MinterPauser}.
       *
       * TIP: For a detailed writeup see our guide
       * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
       * to implement supply mechanisms].
       *
       * We have followed general OpenZeppelin guidelines: functions revert instead
       * of returning `false` on failure. This behavior is nonetheless conventional
       * and does not conflict with the expectations of ERC20 applications.
       *
       * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
       * This allows applications to reconstruct the allowance for all accounts just
       * by listening to said events. Other implementations of the EIP may not emit
       * these events, as it isn't required by the specification.
       *
       * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
       * functions have been added to mitigate the well-known issues around setting
       * allowances. See {IERC20-approve}.
       */
      contract ERC20 is Context, IERC20 {
          using SafeMath for uint256;
          using Address for address;
      
          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 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 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 Sets {decimals} to a value other than the default one of 18.
           *
           * WARNING: This function should only be called from the constructor. Most
           * applications that interact with token contracts will not expect
           * {decimals} to ever change, and may work incorrectly if it does.
           */
          function _setupDecimals(uint8 decimals_) internal {
              _decimals = decimals_;
          }
      
          /**
           * @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: @openzeppelin/contracts/token/ERC20/ERC20Capped.sol
      
      pragma solidity ^0.6.0;
      
      
      /**
       * @dev Extension of {ERC20} that adds a cap to the supply of tokens.
       */
      abstract contract ERC20Capped is ERC20 {
          uint256 private _cap;
      
          /**
           * @dev Sets the value of the `cap`. This value is immutable, it can only be
           * set once during construction.
           */
          constructor (uint256 cap) public {
              require(cap > 0, "ERC20Capped: cap is 0");
              _cap = cap;
          }
      
          /**
           * @dev Returns the cap on the token's total supply.
           */
          function cap() public view returns (uint256) {
              return _cap;
          }
      
          /**
           * @dev See {ERC20-_beforeTokenTransfer}.
           *
           * Requirements:
           *
           * - minted tokens must not cause the total supply to go over the cap.
           */
          function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
              super._beforeTokenTransfer(from, to, amount);
      
              if (from == address(0)) { // When minting tokens
                  require(totalSupply().add(amount) <= _cap, "ERC20Capped: cap exceeded");
              }
          }
      }
      
      // File: @openzeppelin/contracts/token/ERC20/ERC20Burnable.sol
      
      pragma solidity ^0.6.0;
      
      
      
      /**
       * @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 {
          /**
           * @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);
          }
      }
      
      // File: @openzeppelin/contracts/introspection/IERC165.sol
      
      pragma solidity ^0.6.0;
      
      /**
       * @dev Interface of the ERC165 standard, as defined in the
       * https://eips.ethereum.org/EIPS/eip-165[EIP].
       *
       * Implementers can declare support of contract interfaces, which can then be
       * queried by others ({ERC165Checker}).
       *
       * For an implementation, see {ERC165}.
       */
      interface IERC165 {
          /**
           * @dev Returns true if this contract implements the interface defined by
           * `interfaceId`. See the corresponding
           * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
           * to learn more about how these ids are created.
           *
           * This function call must use less than 30 000 gas.
           */
          function supportsInterface(bytes4 interfaceId) external view returns (bool);
      }
      
      // File: erc-payable-token/contracts/token/ERC1363/IERC1363.sol
      
      pragma solidity ^0.6.0;
      
      
      
      /**
       * @title IERC1363 Interface
       * @author Vittorio Minacori (https://github.com/vittominacori)
       * @dev Interface for a Payable Token contract as defined in
       *  https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1363.md
       */
      interface IERC1363 is IERC20, IERC165 {
          /*
           * Note: the ERC-165 identifier for this interface is 0x4bbee2df.
           * 0x4bbee2df ===
           *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
           *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
           *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
           *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)'))
           */
      
          /*
           * Note: the ERC-165 identifier for this interface is 0xfb9ec8ce.
           * 0xfb9ec8ce ===
           *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
           *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
           */
      
          /**
           * @notice Transfer tokens from `msg.sender` to another address and then call `onTransferReceived` on receiver
           * @param to address The address which you want to transfer to
           * @param value uint256 The amount of tokens to be transferred
           * @return true unless throwing
           */
          function transferAndCall(address to, uint256 value) external returns (bool);
      
          /**
           * @notice Transfer tokens from `msg.sender` to another address and then call `onTransferReceived` on receiver
           * @param to address The address which you want to transfer to
           * @param value uint256 The amount of tokens to be transferred
           * @param data bytes Additional data with no specified format, sent in call to `to`
           * @return true unless throwing
           */
          function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
      
          /**
           * @notice Transfer tokens from one address to another and then call `onTransferReceived` on receiver
           * @param from address The address which you want to send tokens from
           * @param to address The address which you want to transfer to
           * @param value uint256 The amount of tokens to be transferred
           * @return true unless throwing
           */
          function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
      
          /**
           * @notice Transfer tokens from one address to another and then call `onTransferReceived` on receiver
           * @param from address The address which you want to send tokens from
           * @param to address The address which you want to transfer to
           * @param value uint256 The amount of tokens to be transferred
           * @param data bytes Additional data with no specified format, sent in call to `to`
           * @return true unless throwing
           */
          function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
      
          /**
           * @notice Approve the passed address to spend the specified amount of tokens on behalf of msg.sender
           * and then call `onApprovalReceived` on spender.
           * 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
           * @param spender address The address which will spend the funds
           * @param value uint256 The amount of tokens to be spent
           */
          function approveAndCall(address spender, uint256 value) external returns (bool);
      
          /**
           * @notice Approve the passed address to spend the specified amount of tokens on behalf of msg.sender
           * and then call `onApprovalReceived` on spender.
           * 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
           * @param spender address The address which will spend the funds
           * @param value uint256 The amount of tokens to be spent
           * @param data bytes Additional data with no specified format, sent in call to `spender`
           */
          function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
      }
      
      // File: erc-payable-token/contracts/token/ERC1363/IERC1363Receiver.sol
      
      pragma solidity ^0.6.0;
      
      /**
       * @title IERC1363Receiver Interface
       * @author Vittorio Minacori (https://github.com/vittominacori)
       * @dev Interface for any contract that wants to support transferAndCall or transferFromAndCall
       *  from ERC1363 token contracts as defined in
       *  https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1363.md
       */
      interface IERC1363Receiver {
          /*
           * Note: the ERC-165 identifier for this interface is 0x88a7ca5c.
           * 0x88a7ca5c === bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))
           */
      
          /**
           * @notice Handle the receipt of ERC1363 tokens
           * @dev Any ERC1363 smart contract calls this function on the recipient
           * after a `transfer` or a `transferFrom`. This function MAY throw to revert and reject the
           * transfer. Return of other than the magic value MUST result in the
           * transaction being reverted.
           * Note: the token contract address is always the message sender.
           * @param operator address The address which called `transferAndCall` or `transferFromAndCall` function
           * @param from address The address which are token transferred from
           * @param value uint256 The amount of tokens transferred
           * @param data bytes Additional data with no specified format
           * @return `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))`
           *  unless throwing
           */
          function onTransferReceived(address operator, address from, uint256 value, bytes calldata data) external returns (bytes4); // solhint-disable-line  max-line-length
      }
      
      // File: erc-payable-token/contracts/token/ERC1363/IERC1363Spender.sol
      
      pragma solidity ^0.6.0;
      
      /**
       * @title IERC1363Spender Interface
       * @author Vittorio Minacori (https://github.com/vittominacori)
       * @dev Interface for any contract that wants to support approveAndCall
       *  from ERC1363 token contracts as defined in
       *  https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1363.md
       */
      interface IERC1363Spender {
          /*
           * Note: the ERC-165 identifier for this interface is 0x7b04a2d0.
           * 0x7b04a2d0 === bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))
           */
      
          /**
           * @notice Handle the approval of ERC1363 tokens
           * @dev Any ERC1363 smart contract calls this function on the recipient
           * after an `approve`. This function MAY throw to revert and reject the
           * approval. Return of other than the magic value MUST result in the
           * transaction being reverted.
           * Note: the token contract address is always the message sender.
           * @param owner address The address which called `approveAndCall` function
           * @param value uint256 The amount of tokens to be spent
           * @param data bytes Additional data with no specified format
           * @return `bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))`
           *  unless throwing
           */
          function onApprovalReceived(address owner, uint256 value, bytes calldata data) external returns (bytes4);
      }
      
      // File: @openzeppelin/contracts/introspection/ERC165Checker.sol
      
      pragma solidity ^0.6.2;
      
      /**
       * @dev Library used to query support of an interface declared via {IERC165}.
       *
       * Note that these functions return the actual result of the query: they do not
       * `revert` if an interface is not supported. It is up to the caller to decide
       * what to do in these cases.
       */
      library ERC165Checker {
          // As per the EIP-165 spec, no interface should ever match 0xffffffff
          bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
      
          /*
           * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
           */
          bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
      
          /**
           * @dev Returns true if `account` supports the {IERC165} interface,
           */
          function supportsERC165(address account) internal view returns (bool) {
              // Any contract that implements ERC165 must explicitly indicate support of
              // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
              return _supportsERC165Interface(account, _INTERFACE_ID_ERC165) &&
                  !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);
          }
      
          /**
           * @dev Returns true if `account` supports the interface defined by
           * `interfaceId`. Support for {IERC165} itself is queried automatically.
           *
           * See {IERC165-supportsInterface}.
           */
          function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
              // query support of both ERC165 as per the spec and support of _interfaceId
              return supportsERC165(account) &&
                  _supportsERC165Interface(account, interfaceId);
          }
      
          /**
           * @dev Returns true if `account` supports all the interfaces defined in
           * `interfaceIds`. Support for {IERC165} itself is queried automatically.
           *
           * Batch-querying can lead to gas savings by skipping repeated checks for
           * {IERC165} support.
           *
           * See {IERC165-supportsInterface}.
           */
          function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
              // query support of ERC165 itself
              if (!supportsERC165(account)) {
                  return false;
              }
      
              // query support of each interface in _interfaceIds
              for (uint256 i = 0; i < interfaceIds.length; i++) {
                  if (!_supportsERC165Interface(account, interfaceIds[i])) {
                      return false;
                  }
              }
      
              // all interfaces supported
              return true;
          }
      
          /**
           * @notice Query if a contract implements an interface, does not check ERC165 support
           * @param account The address of the contract to query for support of an interface
           * @param interfaceId The interface identifier, as specified in ERC-165
           * @return true if the contract at account indicates support of the interface with
           * identifier interfaceId, false otherwise
           * @dev Assumes that account contains a contract that supports ERC165, otherwise
           * the behavior of this method is undefined. This precondition can be checked
           * with {supportsERC165}.
           * Interface identification is specified in ERC-165.
           */
          function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
              // success determines whether the staticcall succeeded and result determines
              // whether the contract at account indicates support of _interfaceId
              (bool success, bool result) = _callERC165SupportsInterface(account, interfaceId);
      
              return (success && result);
          }
      
          /**
           * @notice Calls the function with selector 0x01ffc9a7 (ERC165) and suppresses throw
           * @param account The address of the contract to query for support of an interface
           * @param interfaceId The interface identifier, as specified in ERC-165
           * @return success true if the STATICCALL succeeded, false otherwise
           * @return result true if the STATICCALL succeeded and the contract at account
           * indicates support of the interface with identifier interfaceId, false otherwise
           */
          function _callERC165SupportsInterface(address account, bytes4 interfaceId)
              private
              view
              returns (bool, bool)
          {
              bytes memory encodedParams = abi.encodeWithSelector(_INTERFACE_ID_ERC165, interfaceId);
              (bool success, bytes memory result) = account.staticcall{ gas: 30000 }(encodedParams);
              if (result.length < 32) return (false, false);
              return (success, abi.decode(result, (bool)));
          }
      }
      
      // File: @openzeppelin/contracts/introspection/ERC165.sol
      
      pragma solidity ^0.6.0;
      
      
      /**
       * @dev Implementation of the {IERC165} interface.
       *
       * Contracts may inherit from this and call {_registerInterface} to declare
       * their support of an interface.
       */
      contract ERC165 is IERC165 {
          /*
           * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
           */
          bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
      
          /**
           * @dev Mapping of interface ids to whether or not it's supported.
           */
          mapping(bytes4 => bool) private _supportedInterfaces;
      
          constructor () internal {
              // Derived contracts need only register support for their own interfaces,
              // we register support for ERC165 itself here
              _registerInterface(_INTERFACE_ID_ERC165);
          }
      
          /**
           * @dev See {IERC165-supportsInterface}.
           *
           * Time complexity O(1), guaranteed to always use less than 30 000 gas.
           */
          function supportsInterface(bytes4 interfaceId) public view override returns (bool) {
              return _supportedInterfaces[interfaceId];
          }
      
          /**
           * @dev Registers the contract as an implementer of the interface defined by
           * `interfaceId`. Support of the actual ERC165 interface is automatic and
           * registering its interface id is not required.
           *
           * See {IERC165-supportsInterface}.
           *
           * Requirements:
           *
           * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
           */
          function _registerInterface(bytes4 interfaceId) internal virtual {
              require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
              _supportedInterfaces[interfaceId] = true;
          }
      }
      
      // File: erc-payable-token/contracts/token/ERC1363/ERC1363.sol
      
      pragma solidity ^0.6.0;
      
      
      
      
      
      
      
      
      /**
       * @title ERC1363
       * @author Vittorio Minacori (https://github.com/vittominacori)
       * @dev Implementation of an ERC1363 interface
       */
      contract ERC1363 is ERC20, IERC1363, ERC165 {
          using Address for address;
      
          /*
           * Note: the ERC-165 identifier for this interface is 0x4bbee2df.
           * 0x4bbee2df ===
           *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
           *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
           *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
           *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)'))
           */
          bytes4 internal constant _INTERFACE_ID_ERC1363_TRANSFER = 0x4bbee2df;
      
          /*
           * Note: the ERC-165 identifier for this interface is 0xfb9ec8ce.
           * 0xfb9ec8ce ===
           *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
           *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
           */
          bytes4 internal constant _INTERFACE_ID_ERC1363_APPROVE = 0xfb9ec8ce;
      
          // Equals to `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))`
          // which can be also obtained as `IERC1363Receiver(0).onTransferReceived.selector`
          bytes4 private constant _ERC1363_RECEIVED = 0x88a7ca5c;
      
          // Equals to `bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))`
          // which can be also obtained as `IERC1363Spender(0).onApprovalReceived.selector`
          bytes4 private constant _ERC1363_APPROVED = 0x7b04a2d0;
      
          /**
           * @param name Name of the token
           * @param symbol A symbol to be used as ticker
           */
          constructor (
              string memory name,
              string memory symbol
          ) public payable ERC20(name, symbol) {
              // register the supported interfaces to conform to ERC1363 via ERC165
              _registerInterface(_INTERFACE_ID_ERC1363_TRANSFER);
              _registerInterface(_INTERFACE_ID_ERC1363_APPROVE);
          }
      
          /**
           * @dev Transfer tokens to a specified address and then execute a callback on recipient.
           * @param to The address to transfer to.
           * @param value The amount to be transferred.
           * @return A boolean that indicates if the operation was successful.
           */
          function transferAndCall(address to, uint256 value) public override returns (bool) {
              return transferAndCall(to, value, "");
          }
      
          /**
           * @dev Transfer tokens to a specified address and then execute a callback on recipient.
           * @param to The address to transfer to
           * @param value The amount to be transferred
           * @param data Additional data with no specified format
           * @return A boolean that indicates if the operation was successful.
           */
          function transferAndCall(address to, uint256 value, bytes memory data) public override returns (bool) {
              transfer(to, value);
              require(_checkAndCallTransfer(_msgSender(), to, value, data), "ERC1363: _checkAndCallTransfer reverts");
              return true;
          }
      
          /**
           * @dev Transfer tokens from one address to another and then execute a callback on recipient.
           * @param from The address which you want to send tokens from
           * @param to The address which you want to transfer to
           * @param value The amount of tokens to be transferred
           * @return A boolean that indicates if the operation was successful.
           */
          function transferFromAndCall(address from, address to, uint256 value) public override returns (bool) {
              return transferFromAndCall(from, to, value, "");
          }
      
          /**
           * @dev Transfer tokens from one address to another and then execute a callback on recipient.
           * @param from The address which you want to send tokens from
           * @param to The address which you want to transfer to
           * @param value The amount of tokens to be transferred
           * @param data Additional data with no specified format
           * @return A boolean that indicates if the operation was successful.
           */
          function transferFromAndCall(address from, address to, uint256 value, bytes memory data) public override returns (bool) {
              transferFrom(from, to, value);
              require(_checkAndCallTransfer(from, to, value, data), "ERC1363: _checkAndCallTransfer reverts");
              return true;
          }
      
          /**
           * @dev Approve spender to transfer tokens and then execute a callback on recipient.
           * @param spender The address allowed to transfer to
           * @param value The amount allowed to be transferred
           * @return A boolean that indicates if the operation was successful.
           */
          function approveAndCall(address spender, uint256 value) public override returns (bool) {
              return approveAndCall(spender, value, "");
          }
      
          /**
           * @dev Approve spender to transfer tokens and then execute a callback on recipient.
           * @param spender The address allowed to transfer to.
           * @param value The amount allowed to be transferred.
           * @param data Additional data with no specified format.
           * @return A boolean that indicates if the operation was successful.
           */
          function approveAndCall(address spender, uint256 value, bytes memory data) public override returns (bool) {
              approve(spender, value);
              require(_checkAndCallApprove(spender, value, data), "ERC1363: _checkAndCallApprove reverts");
              return true;
          }
      
          /**
           * @dev Internal function to invoke `onTransferReceived` on a target address
           *  The call is not executed if the target address is not a contract
           * @param from address Representing the previous owner of the given token value
           * @param to address Target address that will receive the tokens
           * @param value uint256 The amount mount of tokens to be transferred
           * @param data bytes Optional data to send along with the call
           * @return whether the call correctly returned the expected magic value
           */
          function _checkAndCallTransfer(address from, address to, uint256 value, bytes memory data) internal returns (bool) {
              if (!to.isContract()) {
                  return false;
              }
              bytes4 retval = IERC1363Receiver(to).onTransferReceived(
                  _msgSender(), from, value, data
              );
              return (retval == _ERC1363_RECEIVED);
          }
      
          /**
           * @dev Internal function to invoke `onApprovalReceived` on a target address
           *  The call is not executed if the target address is not a contract
           * @param spender address The address which will spend the funds
           * @param value uint256 The amount of tokens to be spent
           * @param data bytes Optional data to send along with the call
           * @return whether the call correctly returned the expected magic value
           */
          function _checkAndCallApprove(address spender, uint256 value, bytes memory data) internal returns (bool) {
              if (!spender.isContract()) {
                  return false;
              }
              bytes4 retval = IERC1363Spender(spender).onApprovalReceived(
                  _msgSender(), value, data
              );
              return (retval == _ERC1363_APPROVED);
          }
      }
      
      // File: @openzeppelin/contracts/access/Ownable.sol
      
      pragma solidity ^0.6.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.
       */
      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 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: eth-token-recover/contracts/TokenRecover.sol
      
      pragma solidity ^0.6.0;
      
      
      
      /**
       * @title TokenRecover
       * @author Vittorio Minacori (https://github.com/vittominacori)
       * @dev Allow to recover any ERC20 sent into the contract for error
       */
      contract TokenRecover is Ownable {
      
          /**
           * @dev Remember that only owner can call so be careful when use on contracts generated from other contracts.
           * @param tokenAddress The token contract address
           * @param tokenAmount Number of tokens to be sent
           */
          function recoverERC20(address tokenAddress, uint256 tokenAmount) public onlyOwner {
              IERC20(tokenAddress).transfer(owner(), tokenAmount);
          }
      }
      
      // File: @openzeppelin/contracts/utils/EnumerableSet.sol
      
      pragma solidity ^0.6.0;
      
      /**
       * @dev Library for managing
       * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
       * types.
       *
       * Sets have the following properties:
       *
       * - Elements are added, removed, and checked for existence in constant time
       * (O(1)).
       * - Elements are enumerated in O(n). No guarantees are made on the ordering.
       *
       * ```
       * contract Example {
       *     // Add the library methods
       *     using EnumerableSet for EnumerableSet.AddressSet;
       *
       *     // Declare a set state variable
       *     EnumerableSet.AddressSet private mySet;
       * }
       * ```
       *
       * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256`
       * (`UintSet`) are supported.
       */
      library EnumerableSet {
          // To implement this library for multiple types with as little code
          // repetition as possible, we write it in terms of a generic Set type with
          // bytes32 values.
          // The Set implementation uses private functions, and user-facing
          // implementations (such as AddressSet) are just wrappers around the
          // underlying Set.
          // This means that we can only create new EnumerableSets for types that fit
          // in bytes32.
      
          struct Set {
              // Storage of set values
              bytes32[] _values;
      
              // Position of the value in the `values` array, plus 1 because index 0
              // means a value is not in the set.
              mapping (bytes32 => uint256) _indexes;
          }
      
          /**
           * @dev Add a value to a set. O(1).
           *
           * Returns true if the value was added to the set, that is if it was not
           * already present.
           */
          function _add(Set storage set, bytes32 value) private returns (bool) {
              if (!_contains(set, value)) {
                  set._values.push(value);
                  // The value is stored at length-1, but we add 1 to all indexes
                  // and use 0 as a sentinel value
                  set._indexes[value] = set._values.length;
                  return true;
              } else {
                  return false;
              }
          }
      
          /**
           * @dev Removes a value from a set. O(1).
           *
           * Returns true if the value was removed from the set, that is if it was
           * present.
           */
          function _remove(Set storage set, bytes32 value) private returns (bool) {
              // We read and store the value's index to prevent multiple reads from the same storage slot
              uint256 valueIndex = set._indexes[value];
      
              if (valueIndex != 0) { // Equivalent to contains(set, value)
                  // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                  // the array, and then remove the last element (sometimes called as 'swap and pop').
                  // This modifies the order of the array, as noted in {at}.
      
                  uint256 toDeleteIndex = valueIndex - 1;
                  uint256 lastIndex = set._values.length - 1;
      
                  // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
                  // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
      
                  bytes32 lastvalue = set._values[lastIndex];
      
                  // Move the last value to the index where the value to delete is
                  set._values[toDeleteIndex] = lastvalue;
                  // Update the index for the moved value
                  set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based
      
                  // Delete the slot where the moved value was stored
                  set._values.pop();
      
                  // Delete the index for the deleted slot
                  delete set._indexes[value];
      
                  return true;
              } else {
                  return false;
              }
          }
      
          /**
           * @dev Returns true if the value is in the set. O(1).
           */
          function _contains(Set storage set, bytes32 value) private view returns (bool) {
              return set._indexes[value] != 0;
          }
      
          /**
           * @dev Returns the number of values on the set. O(1).
           */
          function _length(Set storage set) private view returns (uint256) {
              return set._values.length;
          }
      
         /**
          * @dev Returns the value stored at position `index` in the set. O(1).
          *
          * Note that there are no guarantees on the ordering of values inside the
          * array, and it may change when more values are added or removed.
          *
          * Requirements:
          *
          * - `index` must be strictly less than {length}.
          */
          function _at(Set storage set, uint256 index) private view returns (bytes32) {
              require(set._values.length > index, "EnumerableSet: index out of bounds");
              return set._values[index];
          }
      
          // AddressSet
      
          struct AddressSet {
              Set _inner;
          }
      
          /**
           * @dev Add a value to a set. O(1).
           *
           * Returns true if the value was added to the set, that is if it was not
           * already present.
           */
          function add(AddressSet storage set, address value) internal returns (bool) {
              return _add(set._inner, bytes32(uint256(value)));
          }
      
          /**
           * @dev Removes a value from a set. O(1).
           *
           * Returns true if the value was removed from the set, that is if it was
           * present.
           */
          function remove(AddressSet storage set, address value) internal returns (bool) {
              return _remove(set._inner, bytes32(uint256(value)));
          }
      
          /**
           * @dev Returns true if the value is in the set. O(1).
           */
          function contains(AddressSet storage set, address value) internal view returns (bool) {
              return _contains(set._inner, bytes32(uint256(value)));
          }
      
          /**
           * @dev Returns the number of values in the set. O(1).
           */
          function length(AddressSet storage set) internal view returns (uint256) {
              return _length(set._inner);
          }
      
         /**
          * @dev Returns the value stored at position `index` in the set. O(1).
          *
          * Note that there are no guarantees on the ordering of values inside the
          * array, and it may change when more values are added or removed.
          *
          * Requirements:
          *
          * - `index` must be strictly less than {length}.
          */
          function at(AddressSet storage set, uint256 index) internal view returns (address) {
              return address(uint256(_at(set._inner, index)));
          }
      
      
          // UintSet
      
          struct UintSet {
              Set _inner;
          }
      
          /**
           * @dev Add a value to a set. O(1).
           *
           * Returns true if the value was added to the set, that is if it was not
           * already present.
           */
          function add(UintSet storage set, uint256 value) internal returns (bool) {
              return _add(set._inner, bytes32(value));
          }
      
          /**
           * @dev Removes a value from a set. O(1).
           *
           * Returns true if the value was removed from the set, that is if it was
           * present.
           */
          function remove(UintSet storage set, uint256 value) internal returns (bool) {
              return _remove(set._inner, bytes32(value));
          }
      
          /**
           * @dev Returns true if the value is in the set. O(1).
           */
          function contains(UintSet storage set, uint256 value) internal view returns (bool) {
              return _contains(set._inner, bytes32(value));
          }
      
          /**
           * @dev Returns the number of values on the set. O(1).
           */
          function length(UintSet storage set) internal view returns (uint256) {
              return _length(set._inner);
          }
      
         /**
          * @dev Returns the value stored at position `index` in the set. O(1).
          *
          * Note that there are no guarantees on the ordering of values inside the
          * array, and it may change when more values are added or removed.
          *
          * Requirements:
          *
          * - `index` must be strictly less than {length}.
          */
          function at(UintSet storage set, uint256 index) internal view returns (uint256) {
              return uint256(_at(set._inner, index));
          }
      }
      
      // File: @openzeppelin/contracts/access/AccessControl.sol
      
      pragma solidity ^0.6.0;
      
      
      
      
      /**
       * @dev Contract module that allows children to implement role-based access
       * control mechanisms.
       *
       * Roles are referred to by their `bytes32` identifier. These should be exposed
       * in the external API and be unique. The best way to achieve this is by
       * using `public constant` hash digests:
       *
       * ```
       * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
       * ```
       *
       * Roles can be used to represent a set of permissions. To restrict access to a
       * function call, use {hasRole}:
       *
       * ```
       * function foo() public {
       *     require(hasRole(MY_ROLE, _msgSender()));
       *     ...
       * }
       * ```
       *
       * Roles can be granted and revoked dynamically via the {grantRole} and
       * {revokeRole} functions. Each role has an associated admin role, and only
       * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
       *
       * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
       * that only accounts with this role will be able to grant or revoke other
       * roles. More complex role relationships can be created by using
       * {_setRoleAdmin}.
       */
      abstract contract AccessControl is Context {
          using EnumerableSet for EnumerableSet.AddressSet;
          using Address for address;
      
          struct RoleData {
              EnumerableSet.AddressSet members;
              bytes32 adminRole;
          }
      
          mapping (bytes32 => RoleData) private _roles;
      
          bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
      
          /**
           * @dev Emitted when `account` is granted `role`.
           *
           * `sender` is the account that originated the contract call, an admin role
           * bearer except when using {_setupRole}.
           */
          event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
      
          /**
           * @dev Emitted when `account` is revoked `role`.
           *
           * `sender` is the account that originated the contract call:
           *   - if using `revokeRole`, it is the admin role bearer
           *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
           */
          event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
      
          /**
           * @dev Returns `true` if `account` has been granted `role`.
           */
          function hasRole(bytes32 role, address account) public view returns (bool) {
              return _roles[role].members.contains(account);
          }
      
          /**
           * @dev Returns the number of accounts that have `role`. Can be used
           * together with {getRoleMember} to enumerate all bearers of a role.
           */
          function getRoleMemberCount(bytes32 role) public view returns (uint256) {
              return _roles[role].members.length();
          }
      
          /**
           * @dev Returns one of the accounts that have `role`. `index` must be a
           * value between 0 and {getRoleMemberCount}, non-inclusive.
           *
           * Role bearers are not sorted in any particular way, and their ordering may
           * change at any point.
           *
           * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
           * you perform all queries on the same block. See the following
           * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
           * for more information.
           */
          function getRoleMember(bytes32 role, uint256 index) public view returns (address) {
              return _roles[role].members.at(index);
          }
      
          /**
           * @dev Returns the admin role that controls `role`. See {grantRole} and
           * {revokeRole}.
           *
           * To change a role's admin, use {_setRoleAdmin}.
           */
          function getRoleAdmin(bytes32 role) public view returns (bytes32) {
              return _roles[role].adminRole;
          }
      
          /**
           * @dev Grants `role` to `account`.
           *
           * If `account` had not been already granted `role`, emits a {RoleGranted}
           * event.
           *
           * Requirements:
           *
           * - the caller must have ``role``'s admin role.
           */
          function grantRole(bytes32 role, address account) public virtual {
              require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");
      
              _grantRole(role, account);
          }
      
          /**
           * @dev Revokes `role` from `account`.
           *
           * If `account` had been granted `role`, emits a {RoleRevoked} event.
           *
           * Requirements:
           *
           * - the caller must have ``role``'s admin role.
           */
          function revokeRole(bytes32 role, address account) public virtual {
              require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");
      
              _revokeRole(role, account);
          }
      
          /**
           * @dev Revokes `role` from the calling account.
           *
           * Roles are often managed via {grantRole} and {revokeRole}: this function's
           * purpose is to provide a mechanism for accounts to lose their privileges
           * if they are compromised (such as when a trusted device is misplaced).
           *
           * If the calling account had been granted `role`, emits a {RoleRevoked}
           * event.
           *
           * Requirements:
           *
           * - the caller must be `account`.
           */
          function renounceRole(bytes32 role, address account) public virtual {
              require(account == _msgSender(), "AccessControl: can only renounce roles for self");
      
              _revokeRole(role, account);
          }
      
          /**
           * @dev Grants `role` to `account`.
           *
           * If `account` had not been already granted `role`, emits a {RoleGranted}
           * event. Note that unlike {grantRole}, this function doesn't perform any
           * checks on the calling account.
           *
           * [WARNING]
           * ====
           * This function should only be called from the constructor when setting
           * up the initial roles for the system.
           *
           * Using this function in any other way is effectively circumventing the admin
           * system imposed by {AccessControl}.
           * ====
           */
          function _setupRole(bytes32 role, address account) internal virtual {
              _grantRole(role, account);
          }
      
          /**
           * @dev Sets `adminRole` as ``role``'s admin role.
           */
          function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
              _roles[role].adminRole = adminRole;
          }
      
          function _grantRole(bytes32 role, address account) private {
              if (_roles[role].members.add(account)) {
                  emit RoleGranted(role, account, _msgSender());
              }
          }
      
          function _revokeRole(bytes32 role, address account) private {
              if (_roles[role].members.remove(account)) {
                  emit RoleRevoked(role, account, _msgSender());
              }
          }
      }
      
      // File: contracts/access/Roles.sol
      
      pragma solidity ^0.6.0;
      
      
      contract Roles is AccessControl {
      
          bytes32 public constant MINTER_ROLE = keccak256("MINTER");
          bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR");
      
          constructor () public {
              _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
              _setupRole(MINTER_ROLE, _msgSender());
              _setupRole(OPERATOR_ROLE, _msgSender());
          }
      
          modifier onlyMinter() {
              require(hasRole(MINTER_ROLE, _msgSender()), "Roles: caller does not have the MINTER role");
              _;
          }
      
          modifier onlyOperator() {
              require(hasRole(OPERATOR_ROLE, _msgSender()), "Roles: caller does not have the OPERATOR role");
              _;
          }
      }
      
      // File: contracts/BaseToken.sol
      
      pragma solidity ^0.6.0;
      
      
      
      
      
      
      /**
       * @title BaseToken
       * @author Vittorio Minacori (https://github.com/vittominacori)
       * @dev Implementation of the BaseToken
       */
      contract BaseToken is ERC20Capped, ERC20Burnable, ERC1363, Roles, TokenRecover {
      
          // indicates if minting is finished
          bool private _mintingFinished = false;
      
          // indicates if transfer is enabled
          bool private _transferEnabled = false;
      
          string public constant BUILT_ON = "https://vittominacori.github.io/erc20-generator";
      
          /**
           * @dev Emitted during finish minting
           */
          event MintFinished();
      
          /**
           * @dev Emitted during transfer enabling
           */
          event TransferEnabled();
      
          /**
           * @dev Tokens can be minted only before minting finished.
           */
          modifier canMint() {
              require(!_mintingFinished, "BaseToken: minting is finished");
              _;
          }
      
          /**
           * @dev Tokens can be moved only after if transfer enabled or if you are an approved operator.
           */
          modifier canTransfer(address from) {
              require(
                  _transferEnabled || hasRole(OPERATOR_ROLE, from),
                  "BaseToken: transfer is not enabled or from does not have the OPERATOR role"
              );
              _;
          }
      
          /**
           * @param name Name of the token
           * @param symbol A symbol to be used as ticker
           * @param decimals Number of decimals. All the operations are done using the smallest and indivisible token unit
           * @param cap Maximum number of tokens mintable
           * @param initialSupply Initial token supply
           * @param transferEnabled If transfer is enabled on token creation
           * @param mintingFinished If minting is finished after token creation
           */
          constructor(
              string memory name,
              string memory symbol,
              uint8 decimals,
              uint256 cap,
              uint256 initialSupply,
              bool transferEnabled,
              bool mintingFinished
          )
              public
              ERC20Capped(cap)
              ERC1363(name, symbol)
          {
              require(
                  mintingFinished == false || cap == initialSupply,
                  "BaseToken: if finish minting, cap must be equal to initialSupply"
              );
      
              _setupDecimals(decimals);
      
              if (initialSupply > 0) {
                  _mint(owner(), initialSupply);
              }
      
              if (mintingFinished) {
                  finishMinting();
              }
      
              if (transferEnabled) {
                  enableTransfer();
              }
          }
      
          /**
           * @return if minting is finished or not.
           */
          function mintingFinished() public view returns (bool) {
              return _mintingFinished;
          }
      
          /**
           * @return if transfer is enabled or not.
           */
          function transferEnabled() public view returns (bool) {
              return _transferEnabled;
          }
      
          /**
           * @dev Function to mint tokens.
           * @param to The address that will receive the minted tokens
           * @param value The amount of tokens to mint
           */
          function mint(address to, uint256 value) public canMint onlyMinter {
              _mint(to, value);
          }
      
          /**
           * @dev Transfer tokens to a specified address.
           * @param to The address to transfer to
           * @param value The amount to be transferred
           * @return A boolean that indicates if the operation was successful.
           */
          function transfer(address to, uint256 value) public virtual override(ERC20) canTransfer(_msgSender()) returns (bool) {
              return super.transfer(to, value);
          }
      
          /**
           * @dev Transfer tokens from one address to another.
           * @param from The address which you want to send tokens from
           * @param to The address which you want to transfer to
           * @param value the amount of tokens to be transferred
           * @return A boolean that indicates if the operation was successful.
           */
          function transferFrom(address from, address to, uint256 value) public virtual override(ERC20) canTransfer(from) returns (bool) {
              return super.transferFrom(from, to, value);
          }
      
          /**
           * @dev Function to stop minting new tokens.
           */
          function finishMinting() public canMint onlyOwner {
              _mintingFinished = true;
      
              emit MintFinished();
          }
      
          /**
           * @dev Function to enable transfers.
           */
          function enableTransfer() public onlyOwner {
              _transferEnabled = true;
      
              emit TransferEnabled();
          }
      
          /**
           * @dev See {ERC20-_beforeTokenTransfer}.
           */
          function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override(ERC20, ERC20Capped) {
              super._beforeTokenTransfer(from, to, amount);
          }
      }