ETH Price: $2,177.97 (-4.59%)

Transaction Decoder

Block:
18985985 at Jan-11-2024 08:13:35 PM +UTC
Transaction Fee:
0.00244358219728876 ETH $5.32
Gas Used:
68,357 Gas / 35.74735868 Gwei

Emitted Events:

124 KATA.Transfer( from=[Receiver] PresaleClaim, to=[Sender] 0x2f8ca7a0d757aff095bbbc50fd548d9485567342, value=88940490441219000000000 )

Account State Difference:

  Address   Before After State Difference Code
3.800831083151430174 Eth3.801001975651430174 Eth0.0001708925
0x2e85ae1C...aA222aE15
0x2F8cA7A0...485567342
0.007347892412334686 Eth
Nonce: 46
0.004904310215045926 Eth
Nonce: 47
0.00244358219728876
0xC5c84c5b...a1B36Ea68

Execution Trace

PresaleClaim.CALL( )
  • Presale.buyTokens( 0x2F8cA7A0D757aff095BBbC50fD548d9485567342 ) => ( 319999980000000000000000 )
  • Presale.buyTokens( 0x2F8cA7A0D757aff095BBbC50fD548d9485567342 ) => ( 319999980000000000000000 )
  • KATA.transfer( recipient=0x2F8cA7A0D757aff095BBbC50fD548d9485567342, amount=88940490441219000000000 ) => ( True )
    File 1 of 3: PresaleClaim
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
    import '@openzeppelin/contracts/access/Ownable.sol';
    interface IPresale {
      function buyTokens(address) view external returns (uint256);
    }
    contract PresaleClaim is Ownable {
      IERC20 kataToken;
      IPresale presale;
      mapping(address => uint256) public claimedTokens;
      uint256 public tgeAmount = 15;
      uint256 public tgeCliffTime = 1645617600;
      uint256 public tgeTime = 1640260800;
      uint256 public duration = 60 * 60 * 24 * 30 * 5;    // 5 months
      constructor(uint256 _tgeAmount, uint256 _tgeTime, uint256 _tgeCliffTime, uint256 _duration) {
        tgeAmount = _tgeAmount;
        tgeTime = _tgeTime;
        tgeCliffTime = _tgeCliffTime;
        duration = _duration;
      }
      function getClaimable(uint256 timestamp) public view returns(uint256) {
        uint256 buyTokens = presale.buyTokens(msg.sender);
        if (timestamp < tgeTime) return 0;
        if (timestamp < tgeCliffTime) {
          uint256 claimable = (buyTokens * tgeAmount) / 100;
          if (claimedTokens[msg.sender] > claimable) {
            return 0;
          }
          claimable = claimable - claimedTokens[msg.sender];
          return claimable;
        }
        if (buyTokens <= 0) return 0;
        if (buyTokens <= claimedTokens[msg.sender]) return 0;
        uint256 timeElapsed = timestamp - tgeCliffTime;
        if (timeElapsed > duration)
            timeElapsed = duration;
        uint256 _tge = 100 - tgeAmount;
        uint256 unlockedPercent = (10**6 * _tge * timeElapsed) / duration;
        unlockedPercent = unlockedPercent + tgeAmount * 10**6;
        uint256 unlockedAmount = (buyTokens * unlockedPercent) / (100 * 10**6);
        if (unlockedAmount < claimedTokens[msg.sender]) {
          return 0;
        }
        if (claimedTokens[msg.sender] > unlockedAmount) {
          return 0;
        } else {
          uint256 claimable = unlockedAmount - claimedTokens[msg.sender];
          return claimable;
        }
      }
      function claim() external {
        uint256 buyTokens = presale.buyTokens(msg.sender);
        require(buyTokens > 0, "No token purchased");
        require(buyTokens > claimedTokens[msg.sender], "You already claimed all");
        require(address(kataToken) != address(0), "Not initialised");
        uint256 claimable = getClaimable(block.timestamp);
        require (claimable > 0, "No token to claim");
        kataToken.transfer(msg.sender, claimable);
        claimedTokens[msg.sender] = claimedTokens[msg.sender] + claimable;
      }
      function setVesting(uint256 _tgeAmount, uint256 _tgeTime, uint256 _tgeCliffTime, uint256 _duration) external onlyOwner {
        tgeAmount = _tgeAmount;
        tgeTime = _tgeTime;
        tgeCliffTime = _tgeCliffTime;
        duration = _duration;
      }
      function setKataToken(address _kata) external onlyOwner {
        kataToken = IERC20(_kata);
      }
      function setPresale(address _presale) external onlyOwner {
        presale = IPresale(_presale);
      }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.0 (utils/Context.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP.
     */
    interface IERC20 {
        /**
         * @dev Returns the amount of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
        /**
         * @dev Returns the amount of tokens owned by `account`.
         */
        function balanceOf(address account) external view returns (uint256);
        /**
         * @dev Moves `amount` tokens from the caller's account to `recipient`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address recipient, uint256 amount) external returns (bool);
        /**
         * @dev Returns the remaining number of tokens that `spender` will be
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
         * zero by default.
         *
         * This value changes when {approve} or {transferFrom} are called.
         */
        function allowance(address owner, address spender) external view returns (uint256);
        /**
         * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
         * that someone may use both the old and the new allowance by unfortunate
         * transaction ordering. One possible solution to mitigate this race
         * condition is to first reduce the spender's allowance to 0 and set the
         * desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         *
         * Emits an {Approval} event.
         */
        function approve(address spender, uint256 amount) external returns (bool);
        /**
         * @dev Moves `amount` tokens from `sender` to `recipient` using the
         * allowance mechanism. `amount` is then deducted from the caller's
         * allowance.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(
            address sender,
            address recipient,
            uint256 amount
        ) external returns (bool);
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.0 (access/Ownable.sol)
    pragma solidity ^0.8.0;
    import "../utils/Context.sol";
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * By default, the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    abstract contract Ownable is Context {
        address private _owner;
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor() {
            _transferOwnership(_msgSender());
        }
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            return _owner;
        }
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(owner() == _msgSender(), "Ownable: caller is not the owner");
            _;
        }
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            _transferOwnership(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");
            _transferOwnership(newOwner);
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Internal function without access restriction.
         */
        function _transferOwnership(address newOwner) internal virtual {
            address oldOwner = _owner;
            _owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }
    

    File 2 of 3: KATA
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Implementation of the {IERC20} interface.
     *
     * This implementation is agnostic to the way tokens are created. This means
     * that a supply mechanism has to be added in a derived contract using {_mint}.
     * For a generic mechanism see {ERC20PresetMinterPauser}.
     *
     * TIP: For a detailed writeup see our guide
     * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
     * to implement supply mechanisms].
     *
     * We have followed general OpenZeppelin Contracts guidelines: functions revert
     * instead 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 KATA {
        mapping(address => uint256) private _balances;
        mapping(address => mapping(address => uint256)) private _allowances;
        uint256 private constant _totalSupply = 50 * (10 ** 9) * (10 ** 18);     // 50 Billion
        string private constant _name = "Katana Inu";
        string private constant _symbol = "KATA";
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
        /**
         * @dev Sets the values for {name} and {symbol}.
         *
         * The default value of {decimals} is 18. To select a different value for
         * {decimals} you should overload it.
         *
         * All two of these values are immutable: they can only be set once during
         * construction.
         */
        constructor(address[] memory addrs, uint256[] memory tokens) {
            uint256 totalTokens = 0;
            for (uint256 i = 0; i < addrs.length; i++) {
              totalTokens += tokens[i];
              require(addrs[i] != address(0), "addrs must contain valid addresses");
              _balances[addrs[i]] = tokens[i];
              emit Transfer(address(0), addrs[i], tokens[i]);
            }
            require(totalTokens == _totalSupply, "total tokens must be totalSupply");
        }
        /**
         * @dev Returns the name of the token.
         */
        function name() public pure returns (string memory) {
            return _name;
        }
        /**
         * @dev Returns the symbol of the token, usually a shorter version of the
         * name.
         */
        function symbol() public pure 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 this function is
         * overridden;
         *
         * 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 pure returns (uint8) {
            return 18;
        }
        /**
         * @dev See {IERC20-totalSupply}.
         */
        function totalSupply() public pure returns (uint256) {
            return _totalSupply;
        }
        /**
         * @dev See {IERC20-balanceOf}.
         */
        function balanceOf(address account) public view 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) external returns (bool) {
            _transfer(msg.sender, recipient, amount);
            return true;
        }
        /**
         * @dev See {IERC20-allowance}.
         */
        function allowance(address owner, address spender) public view returns (uint256) {
            return _allowances[owner][spender];
        }
        /**
         * @dev See {IERC20-approve}.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         */
        function approve(address spender, uint256 amount) external returns (bool) {
            _approve(msg.sender, spender, amount);
            return true;
        }
        /**
         * @dev See {IERC20-transferFrom}.
         *
         * Emits an {Approval} event indicating the updated allowance. This is not
         * required by the EIP. See the note at the beginning of {ERC20}.
         *
         * Requirements:
         *
         * - `sender` and `recipient` cannot be the zero address.
         * - `sender` must have a balance of at least `amount`.
         * - the caller must have allowance for ``sender``'s tokens of at least
         * `amount`.
         */
        function transferFrom(
            address sender,
            address recipient,
            uint256 amount
        ) external returns (bool) {
            _transfer(sender, recipient, amount);
            uint256 currentAllowance = _allowances[sender][msg.sender];
            require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
            unchecked {
                _approve(sender, msg.sender, currentAllowance - amount);
            }
            return true;
        }
        /**
         * @dev Atomically increases the allowance granted to `spender` by the caller.
         *
         * This is an alternative to {approve} that can be used as a mitigation for
         * problems described in {IERC20-approve}.
         *
         * Emits an {Approval} event indicating the updated allowance.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         */
        function increaseAllowance(address spender, uint256 addedValue) external returns (bool) {
            _approve(msg.sender, spender, _allowances[msg.sender][spender] + 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) external returns (bool) {
            uint256 currentAllowance = _allowances[msg.sender][spender];
            require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
            unchecked {
                _approve(msg.sender, spender, currentAllowance - subtractedValue);
            }
            return true;
        }
        /**
         * @dev Moves `amount` of tokens from `sender` to `recipient`.
         *
         * This 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 {
            require(sender != address(0), "ERC20: transfer from the zero address");
            require(recipient != address(0), "ERC20: transfer to the zero address");
            uint256 senderBalance = _balances[sender];
            require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
            unchecked {
                _balances[sender] = senderBalance - amount;
            }
            _balances[recipient] += amount;
            emit Transfer(sender, recipient, amount);
        }
        /**
         * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
         *
         * This internal function is equivalent to `approve`, and can be used to
         * e.g. set automatic allowances for certain subsystems, etc.
         *
         * Emits an {Approval} event.
         *
         * Requirements:
         *
         * - `owner` cannot be the zero address.
         * - `spender` cannot be the zero address.
         */
        function _approve(
            address owner,
            address spender,
            uint256 amount
        ) internal {
            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);
        }
    }
    

    File 3 of 3: Presale
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
    import '@openzeppelin/contracts/access/Ownable.sol';
    contract Presale is Ownable {
        IERC20 kataToken;
        uint256 public fundingGoal = 25 ether;    //  ETH
        uint256 public soldAmount;
        uint256 public ethRaised;
        uint256 public startTime;
        uint256 public endTime;
        uint256 public whitelistTime;
        uint256 public minETHAmount = 0.025 ether;
        uint256 public maxETHAmount = 0.06 ether;
        uint256 public price = 5333333;       // 1 ETH = 5333333 $KATA
        mapping(address => bool) public whitelist;
        mapping(address => uint256) public buyETH;
        mapping(address => uint256) public buyTokens;
        mapping(address => uint256) public claimedTokens;
        uint256 public tgeAmount = 15;
        uint256 public tgeCliffTime = 1645617600;
        uint256 public tgeTime = 1640260800;
        uint256 public duration = 60 * 60 * 24 * 30 * 5;    // 5 months
        constructor(uint256 _startTime, uint256 _endTime, uint256 _whitelistTime, uint256 _tgeTime, uint256 _tgeCliffTime) {
            startTime = _startTime;
            endTime = _endTime;
            whitelistTime = _whitelistTime;
            tgeTime = _tgeTime;
            tgeCliffTime = _tgeCliffTime;
        }
        function buy() payable external {
            require(msg.value > 0, "Zero ETH sent");
            require(msg.value >= minETHAmount && msg.value <= maxETHAmount,
                "Invalid ETH amount");
            require(block.timestamp >= startTime && block.timestamp <= endTime,
                "Sales not live");
            require(ethRaised < fundingGoal, "sales completed");
            require(buyETH[msg.sender] + msg.value <= maxETHAmount,"max eth amount exceeds");
            if (block.timestamp < whitelistTime) {
                require(whitelist[msg.sender], "you are not whitelisted");
            }
            ethRaised = ethRaised + msg.value;
            uint256 amount = price * msg.value;
            soldAmount = soldAmount + amount;
            buyTokens[msg.sender] = buyTokens[msg.sender] + amount;
            buyETH[msg.sender] = buyETH[msg.sender] + msg.value;
        }
        function getClaimable() public view returns(uint256) {
            if (block.timestamp < tgeTime) return 0;
            if (block.timestamp < tgeCliffTime) {
              return (buyTokens[msg.sender] * tgeAmount) / 100;
            }
            if (buyTokens[msg.sender] <= 0) return 0;
            if (buyTokens[msg.sender] <= claimedTokens[msg.sender]) return 0;
            uint256 timeElapsed = block.timestamp - tgeCliffTime;
            if (timeElapsed > duration)
                timeElapsed = duration;
            uint256 _tge = 100 - tgeAmount;
            uint256 unlockedPercent = (10**6 * _tge * timeElapsed) / duration;
            unlockedPercent = unlockedPercent + tgeAmount * 10**6;
            uint256 unlockedAmount = (buyTokens[msg.sender] * unlockedPercent) / (100 * 10**6);
            if (unlockedAmount < claimedTokens[msg.sender]) {
              return 0;
            }
            uint256 claimable = unlockedAmount - claimedTokens[msg.sender];
            return claimable;
        }
        function claim() external {
            require(block.timestamp > endTime, "Sales not ended yet");
            require(buyTokens[msg.sender] > 0, "No token purcahsed");
            require(buyTokens[msg.sender] > claimedTokens[msg.sender], "You already claimed all");
            require(address(kataToken) != address(0), "Not initialised");
            uint256 claimable = getClaimable();
            require (claimable > 0, "No token to claim");
            kataToken.transfer(msg.sender, claimable);
            claimedTokens[msg.sender] = claimedTokens[msg.sender] + claimable;
        }
        function withdrawETH() external onlyOwner {
            uint256 ethAmount = address(this).balance;
            payable(msg.sender).transfer(ethAmount);
        }
        function setSalesTime(uint256 _startTime, uint256 _endTime, uint256 _whitelistTime) external onlyOwner {
            require(_whitelistTime < _endTime, "Invalid time");
            require(_startTime < _whitelistTime, "Invalid time");
            startTime = _startTime;
            endTime = _endTime;
            whitelistTime = _whitelistTime;
        }
        function setETHrange(uint256 _minETHAmount, uint256 _maxETHAmount) external onlyOwner {
            require(minETHAmount < maxETHAmount, "Invalid range");
            minETHAmount = _minETHAmount;
            maxETHAmount = _maxETHAmount;
        }
        function setPrice(uint256 _price) external onlyOwner {
            price = _price;
        }
        function setVesting(uint256 _tgeAmount, uint256 _tgeTime, uint256 _tgeCliffTime, uint256 _duration) external onlyOwner {
            tgeAmount = _tgeAmount;
            tgeTime = _tgeTime;
            tgeCliffTime = _tgeCliffTime;
            duration = _duration;
        }
        function setKataToken(address _kata) external onlyOwner {
            kataToken = IERC20(_kata);
        }
        function setFundingGoal(uint256 _fundingGoal) external onlyOwner {
            fundingGoal = _fundingGoal;
        }
        function registerWhitelist(address[] memory addrs) external onlyOwner {
            for(uint256 i = 0; i < addrs.length; i++)
                whitelist[addrs[i]] = true;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.0 (utils/Context.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP.
     */
    interface IERC20 {
        /**
         * @dev Returns the amount of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
        /**
         * @dev Returns the amount of tokens owned by `account`.
         */
        function balanceOf(address account) external view returns (uint256);
        /**
         * @dev Moves `amount` tokens from the caller's account to `recipient`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address recipient, uint256 amount) external returns (bool);
        /**
         * @dev Returns the remaining number of tokens that `spender` will be
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
         * zero by default.
         *
         * This value changes when {approve} or {transferFrom} are called.
         */
        function allowance(address owner, address spender) external view returns (uint256);
        /**
         * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
         * that someone may use both the old and the new allowance by unfortunate
         * transaction ordering. One possible solution to mitigate this race
         * condition is to first reduce the spender's allowance to 0 and set the
         * desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         *
         * Emits an {Approval} event.
         */
        function approve(address spender, uint256 amount) external returns (bool);
        /**
         * @dev Moves `amount` tokens from `sender` to `recipient` using the
         * allowance mechanism. `amount` is then deducted from the caller's
         * allowance.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(
            address sender,
            address recipient,
            uint256 amount
        ) external returns (bool);
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.0 (access/Ownable.sol)
    pragma solidity ^0.8.0;
    import "../utils/Context.sol";
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * By default, the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    abstract contract Ownable is Context {
        address private _owner;
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor() {
            _transferOwnership(_msgSender());
        }
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            return _owner;
        }
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(owner() == _msgSender(), "Ownable: caller is not the owner");
            _;
        }
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            _transferOwnership(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");
            _transferOwnership(newOwner);
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Internal function without access restriction.
         */
        function _transferOwnership(address newOwner) internal virtual {
            address oldOwner = _owner;
            _owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }