ETH Price: $2,069.44 (-2.45%)

Transaction Decoder

Block:
23838879 at Nov-20-2025 07:50:35 AM +UTC
Transaction Fee:
0.000918807814263615 ETH $1.90
Gas Used:
177,679 Gas / 5.171167185 Gwei

Emitted Events:

833 0xf6801d319497789f934ec7f83e142a9536312b08.0x7724394874fdd8ad13292ec739b441f85c6559f10dc4141b8d4c0fa4cbf55bdb( 0x7724394874fdd8ad13292ec739b441f85c6559f10dc4141b8d4c0fa4cbf55bdb, 0000000000000000000000000000000000000000000000000039f2f141ff3dc0 )
834 0xf6801d319497789f934ec7f83e142a9536312b08.0x6895551786bbb86042fcc29bf0c6657e90b7d1e78721946cb40dde1d35088545( 0x6895551786bbb86042fcc29bf0c6657e90b7d1e78721946cb40dde1d35088545, 00000000000000000000000000000000000000000000000000000000001312d0, 00000000000000000000000000000000000000000000000000000000000b71b0, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
835 TetherToken.Transfer( from=0xECd001449EF4Aa7e99C430677594a54352E6Cec5, to=[Receiver] 0xf6801d319497789f934ec7f83e142a9536312b08, value=3207710445 )
836 ENA.Transfer( from=[Sender] 0xac56b3b1c9ccbf3c2a15585387496b6ba187e41d, to=0xECd001449EF4Aa7e99C430677594a54352E6Cec5, value=11719166979840650724842 )
837 0xecd001449ef4aa7e99c430677594a54352e6cec5.0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67( 0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67, 0x000000000000000000000000f6801d319497789f934ec7f83e142a9536312b08, 0x000000000000000000000000f6801d319497789f934ec7f83e142a9536312b08, 00000000000000000000000000000000000000000000027b4c1cd55b795f45ea, ffffffffffffffffffffffffffffffffffffffffffffffffffffffff40ce3913, 0000000000000000000000000000000000000000000008c6fbbc996d122b0a5a, 0000000000000000000000000000000000000000000000009cc91c874d9cb6d4, fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb95fe )
838 TetherToken.Transfer( from=[Receiver] 0xf6801d319497789f934ec7f83e142a9536312b08, to=0x6eA08ca8F313d860808ef7431fc72c6FbcF4A72D, value=4009637 )
839 0xf6801d319497789f934ec7f83e142a9536312b08.0xf171268de859ec269c52bbfac94dcb7715e784de194342abb284bf34fd30b32d( 0xf171268de859ec269c52bbfac94dcb7715e784de194342abb284bf34fd30b32d, 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7, 00000000000000000000000000000000000000000000000000000000003d2ea5, 0000000000000000000000006ea08ca8f313d860808ef7431fc72c6fbcf4a72d )
840 TetherToken.Transfer( from=[Receiver] 0xf6801d319497789f934ec7f83e142a9536312b08, to=0x829020f83E055BeaEBeE8B22f5b816CB825d839c, value=2405783 )
841 0xf6801d319497789f934ec7f83e142a9536312b08.0xf171268de859ec269c52bbfac94dcb7715e784de194342abb284bf34fd30b32d( 0xf171268de859ec269c52bbfac94dcb7715e784de194342abb284bf34fd30b32d, 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7, 000000000000000000000000000000000000000000000000000000000024b597, 000000000000000000000000829020f83e055beaebee8b22f5b816cb825d839c )
842 TetherToken.Transfer( from=[Receiver] 0xf6801d319497789f934ec7f83e142a9536312b08, to=[Sender] 0xac56b3b1c9ccbf3c2a15585387496b6ba187e41d, value=3201295025 )
843 0xf6801d319497789f934ec7f83e142a9536312b08.0x1bb43f2da90e35f7b0cf38521ca95a49e68eb42fac49924930a5bd73cdf7576c( 0x1bb43f2da90e35f7b0cf38521ca95a49e68eb42fac49924930a5bd73cdf7576c, 00000000000000000000000057e114b691db790c35207b2e685d4a43181e6061, 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7, 000000000000000000000000ac56b3b1c9ccbf3c2a15585387496b6ba187e41d, 00000000000000000000000000000000000000000000027b4c1cd55b795f45ea, 00000000000000000000000000000000000000000000000000000000becfe2b1 )

Account State Difference:

  Address   Before After State Difference Code
(quasarbuilder)
18.843284139217145927 Eth18.843289469587145927 Eth0.00000533037
0x57e114B6...3181e6061
0xAC56b3B1...BA187E41D
0.010344865439112107 Eth
Nonce: 446
0.009426057624848492 Eth
Nonce: 447
0.000918807814263615
0xdAC17F95...13D831ec7
0xECd00144...352E6Cec5
(Uniswap V3: ENA-USDT 3)

Execution Trace

OKX: DEX Router 5.0d5f0e3b( )
  • Uniswap V3: ENA-USDT 3.STATICCALL( )
  • Uniswap V3: ENA-USDT 3.STATICCALL( )
  • TetherToken.balanceOf( who=0xAC56b3B1C9CCBF3c2A15585387496b6BA187E41D ) => ( 8981805 )
  • TetherToken.balanceOf( who=0xF6801D319497789f934ec7F83E142a9536312B08 ) => ( 0 )
  • Uniswap V3: ENA-USDT 3.128acb08( )
    • TetherToken.transfer( _to=0xF6801D319497789f934ec7F83E142a9536312B08, _value=3207710445 )
    • ENA.balanceOf( account=0xECd001449EF4Aa7e99C430677594a54352E6Cec5 ) => ( 116602844507409894559240 )
    • OKX: DEX Router 5.fa461e33( )
      • Uniswap V3: ENA-USDT 3.STATICCALL( )
      • Uniswap V3: ENA-USDT 3.STATICCALL( )
      • Uniswap V3: ENA-USDT 3.STATICCALL( )
      • OKX: Dex Aggregator.0a5ea466( )
        • OKX: DEX Token Approval 1.0a5ea466( )
          • ENA.transferFrom( from=0xAC56b3B1C9CCBF3c2A15585387496b6BA187E41D, to=0xECd001449EF4Aa7e99C430677594a54352E6Cec5, amount=11719166979840650724842 ) => ( True )
          • ENA.balanceOf( account=0xECd001449EF4Aa7e99C430677594a54352E6Cec5 ) => ( 128322011487250545284082 )
          • TetherToken.balanceOf( who=0xF6801D319497789f934ec7F83E142a9536312B08 ) => ( 3207710445 )
          • TetherToken.transfer( _to=0x6eA08ca8F313d860808ef7431fc72c6FbcF4A72D, _value=4009637 )
          • TetherToken.transfer( _to=0x829020f83E055BeaEBeE8B22f5b816CB825d839c, _value=2405783 )
          • TetherToken.transfer( _to=0xAC56b3B1C9CCBF3c2A15585387496b6BA187E41D, _value=3201295025 )
          • TetherToken.balanceOf( who=0xAC56b3B1C9CCBF3c2A15585387496b6BA187E41D ) => ( 3210276830 )
            File 1 of 2: TetherToken
            pragma solidity ^0.4.17;
            
            /**
             * @title SafeMath
             * @dev Math operations with safety checks that throw on error
             */
            library SafeMath {
                function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                    if (a == 0) {
                        return 0;
                    }
                    uint256 c = a * b;
                    assert(c / a == b);
                    return c;
                }
            
                function div(uint256 a, uint256 b) internal pure returns (uint256) {
                    // assert(b > 0); // Solidity automatically throws when dividing by 0
                    uint256 c = a / b;
                    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                    return c;
                }
            
                function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                    assert(b <= a);
                    return a - b;
                }
            
                function add(uint256 a, uint256 b) internal pure returns (uint256) {
                    uint256 c = a + b;
                    assert(c >= a);
                    return c;
                }
            }
            
            /**
             * @title Ownable
             * @dev The Ownable contract has an owner address, and provides basic authorization control
             * functions, this simplifies the implementation of "user permissions".
             */
            contract Ownable {
                address public owner;
            
                /**
                  * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                  * account.
                  */
                function Ownable() public {
                    owner = msg.sender;
                }
            
                /**
                  * @dev Throws if called by any account other than the owner.
                  */
                modifier onlyOwner() {
                    require(msg.sender == owner);
                    _;
                }
            
                /**
                * @dev Allows the current owner to transfer control of the contract to a newOwner.
                * @param newOwner The address to transfer ownership to.
                */
                function transferOwnership(address newOwner) public onlyOwner {
                    if (newOwner != address(0)) {
                        owner = newOwner;
                    }
                }
            
            }
            
            /**
             * @title ERC20Basic
             * @dev Simpler version of ERC20 interface
             * @dev see https://github.com/ethereum/EIPs/issues/20
             */
            contract ERC20Basic {
                uint public _totalSupply;
                function totalSupply() public constant returns (uint);
                function balanceOf(address who) public constant returns (uint);
                function transfer(address to, uint value) public;
                event Transfer(address indexed from, address indexed to, uint value);
            }
            
            /**
             * @title ERC20 interface
             * @dev see https://github.com/ethereum/EIPs/issues/20
             */
            contract ERC20 is ERC20Basic {
                function allowance(address owner, address spender) public constant returns (uint);
                function transferFrom(address from, address to, uint value) public;
                function approve(address spender, uint value) public;
                event Approval(address indexed owner, address indexed spender, uint value);
            }
            
            /**
             * @title Basic token
             * @dev Basic version of StandardToken, with no allowances.
             */
            contract BasicToken is Ownable, ERC20Basic {
                using SafeMath for uint;
            
                mapping(address => uint) public balances;
            
                // additional variables for use if transaction fees ever became necessary
                uint public basisPointsRate = 0;
                uint public maximumFee = 0;
            
                /**
                * @dev Fix for the ERC20 short address attack.
                */
                modifier onlyPayloadSize(uint size) {
                    require(!(msg.data.length < size + 4));
                    _;
                }
            
                /**
                * @dev transfer token for a specified address
                * @param _to The address to transfer to.
                * @param _value The amount to be transferred.
                */
                function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
                    uint fee = (_value.mul(basisPointsRate)).div(10000);
                    if (fee > maximumFee) {
                        fee = maximumFee;
                    }
                    uint sendAmount = _value.sub(fee);
                    balances[msg.sender] = balances[msg.sender].sub(_value);
                    balances[_to] = balances[_to].add(sendAmount);
                    if (fee > 0) {
                        balances[owner] = balances[owner].add(fee);
                        Transfer(msg.sender, owner, fee);
                    }
                    Transfer(msg.sender, _to, sendAmount);
                }
            
                /**
                * @dev Gets the balance of the specified address.
                * @param _owner The address to query the the balance of.
                * @return An uint representing the amount owned by the passed address.
                */
                function balanceOf(address _owner) public constant returns (uint balance) {
                    return balances[_owner];
                }
            
            }
            
            /**
             * @title Standard ERC20 token
             *
             * @dev Implementation of the basic standard token.
             * @dev https://github.com/ethereum/EIPs/issues/20
             * @dev Based oncode by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
             */
            contract StandardToken is BasicToken, ERC20 {
            
                mapping (address => mapping (address => uint)) public allowed;
            
                uint public constant MAX_UINT = 2**256 - 1;
            
                /**
                * @dev Transfer tokens from one address to another
                * @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 uint the amount of tokens to be transferred
                */
                function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) {
                    var _allowance = allowed[_from][msg.sender];
            
                    // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
                    // if (_value > _allowance) throw;
            
                    uint fee = (_value.mul(basisPointsRate)).div(10000);
                    if (fee > maximumFee) {
                        fee = maximumFee;
                    }
                    if (_allowance < MAX_UINT) {
                        allowed[_from][msg.sender] = _allowance.sub(_value);
                    }
                    uint sendAmount = _value.sub(fee);
                    balances[_from] = balances[_from].sub(_value);
                    balances[_to] = balances[_to].add(sendAmount);
                    if (fee > 0) {
                        balances[owner] = balances[owner].add(fee);
                        Transfer(_from, owner, fee);
                    }
                    Transfer(_from, _to, sendAmount);
                }
            
                /**
                * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
                * @param _spender The address which will spend the funds.
                * @param _value The amount of tokens to be spent.
                */
                function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
            
                    // To change the approve amount you first have to reduce the addresses`
                    //  allowance to zero by calling `approve(_spender, 0)` if it is not
                    //  already 0 to mitigate the race condition described here:
                    //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                    require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));
            
                    allowed[msg.sender][_spender] = _value;
                    Approval(msg.sender, _spender, _value);
                }
            
                /**
                * @dev Function to check the amount of tokens than an owner allowed to a spender.
                * @param _owner address The address which owns the funds.
                * @param _spender address The address which will spend the funds.
                * @return A uint specifying the amount of tokens still available for the spender.
                */
                function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                    return allowed[_owner][_spender];
                }
            
            }
            
            
            /**
             * @title Pausable
             * @dev Base contract which allows children to implement an emergency stop mechanism.
             */
            contract Pausable is Ownable {
              event Pause();
              event Unpause();
            
              bool public paused = false;
            
            
              /**
               * @dev Modifier to make a function callable only when the contract is not paused.
               */
              modifier whenNotPaused() {
                require(!paused);
                _;
              }
            
              /**
               * @dev Modifier to make a function callable only when the contract is paused.
               */
              modifier whenPaused() {
                require(paused);
                _;
              }
            
              /**
               * @dev called by the owner to pause, triggers stopped state
               */
              function pause() onlyOwner whenNotPaused public {
                paused = true;
                Pause();
              }
            
              /**
               * @dev called by the owner to unpause, returns to normal state
               */
              function unpause() onlyOwner whenPaused public {
                paused = false;
                Unpause();
              }
            }
            
            contract BlackList is Ownable, BasicToken {
            
                /////// Getters to allow the same blacklist to be used also by other contracts (including upgraded Tether) ///////
                function getBlackListStatus(address _maker) external constant returns (bool) {
                    return isBlackListed[_maker];
                }
            
                function getOwner() external constant returns (address) {
                    return owner;
                }
            
                mapping (address => bool) public isBlackListed;
                
                function addBlackList (address _evilUser) public onlyOwner {
                    isBlackListed[_evilUser] = true;
                    AddedBlackList(_evilUser);
                }
            
                function removeBlackList (address _clearedUser) public onlyOwner {
                    isBlackListed[_clearedUser] = false;
                    RemovedBlackList(_clearedUser);
                }
            
                function destroyBlackFunds (address _blackListedUser) public onlyOwner {
                    require(isBlackListed[_blackListedUser]);
                    uint dirtyFunds = balanceOf(_blackListedUser);
                    balances[_blackListedUser] = 0;
                    _totalSupply -= dirtyFunds;
                    DestroyedBlackFunds(_blackListedUser, dirtyFunds);
                }
            
                event DestroyedBlackFunds(address _blackListedUser, uint _balance);
            
                event AddedBlackList(address _user);
            
                event RemovedBlackList(address _user);
            
            }
            
            contract UpgradedStandardToken is StandardToken{
                // those methods are called by the legacy contract
                // and they must ensure msg.sender to be the contract address
                function transferByLegacy(address from, address to, uint value) public;
                function transferFromByLegacy(address sender, address from, address spender, uint value) public;
                function approveByLegacy(address from, address spender, uint value) public;
            }
            
            contract TetherToken is Pausable, StandardToken, BlackList {
            
                string public name;
                string public symbol;
                uint public decimals;
                address public upgradedAddress;
                bool public deprecated;
            
                //  The contract can be initialized with a number of tokens
                //  All the tokens are deposited to the owner address
                //
                // @param _balance Initial supply of the contract
                // @param _name Token Name
                // @param _symbol Token symbol
                // @param _decimals Token decimals
                function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public {
                    _totalSupply = _initialSupply;
                    name = _name;
                    symbol = _symbol;
                    decimals = _decimals;
                    balances[owner] = _initialSupply;
                    deprecated = false;
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function transfer(address _to, uint _value) public whenNotPaused {
                    require(!isBlackListed[msg.sender]);
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).transferByLegacy(msg.sender, _to, _value);
                    } else {
                        return super.transfer(_to, _value);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function transferFrom(address _from, address _to, uint _value) public whenNotPaused {
                    require(!isBlackListed[_from]);
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
                    } else {
                        return super.transferFrom(_from, _to, _value);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function balanceOf(address who) public constant returns (uint) {
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).balanceOf(who);
                    } else {
                        return super.balanceOf(who);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).approveByLegacy(msg.sender, _spender, _value);
                    } else {
                        return super.approve(_spender, _value);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                    if (deprecated) {
                        return StandardToken(upgradedAddress).allowance(_owner, _spender);
                    } else {
                        return super.allowance(_owner, _spender);
                    }
                }
            
                // deprecate current contract in favour of a new one
                function deprecate(address _upgradedAddress) public onlyOwner {
                    deprecated = true;
                    upgradedAddress = _upgradedAddress;
                    Deprecate(_upgradedAddress);
                }
            
                // deprecate current contract if favour of a new one
                function totalSupply() public constant returns (uint) {
                    if (deprecated) {
                        return StandardToken(upgradedAddress).totalSupply();
                    } else {
                        return _totalSupply;
                    }
                }
            
                // Issue a new amount of tokens
                // these tokens are deposited into the owner address
                //
                // @param _amount Number of tokens to be issued
                function issue(uint amount) public onlyOwner {
                    require(_totalSupply + amount > _totalSupply);
                    require(balances[owner] + amount > balances[owner]);
            
                    balances[owner] += amount;
                    _totalSupply += amount;
                    Issue(amount);
                }
            
                // Redeem tokens.
                // These tokens are withdrawn from the owner address
                // if the balance must be enough to cover the redeem
                // or the call will fail.
                // @param _amount Number of tokens to be issued
                function redeem(uint amount) public onlyOwner {
                    require(_totalSupply >= amount);
                    require(balances[owner] >= amount);
            
                    _totalSupply -= amount;
                    balances[owner] -= amount;
                    Redeem(amount);
                }
            
                function setParams(uint newBasisPoints, uint newMaxFee) public onlyOwner {
                    // Ensure transparency by hardcoding limit beyond which fees can never be added
                    require(newBasisPoints < 20);
                    require(newMaxFee < 50);
            
                    basisPointsRate = newBasisPoints;
                    maximumFee = newMaxFee.mul(10**decimals);
            
                    Params(basisPointsRate, maximumFee);
                }
            
                // Called when new token are issued
                event Issue(uint amount);
            
                // Called when tokens are redeemed
                event Redeem(uint amount);
            
                // Called when contract is deprecated
                event Deprecate(address newAddress);
            
                // Called if contract ever adds fees
                event Params(uint feeBasisPoints, uint maxFee);
            }

            File 2 of 2: ENA
            // SPDX-License-Identifier: GPL-3.0
            pragma solidity 0.8.20;
            import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
            import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
            import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
            import "@openzeppelin/contracts/access/Ownable2Step.sol";
            import "./interfaces/IENADefinitions.sol";
            /**
             * @title ENA
             * @notice Governance token for the Ethena protocol
             */
            contract ENA is Ownable2Step, ERC20Burnable, ERC20Permit, IENADefinitions {
              /// @notice Maximum inflation rate per year (percentage) expressed as an integer
              uint8 public constant MAX_INFLATION = 10;
              /// @notice The maximum frequency of inflationary mint invocations
              uint32 public constant MINT_WAIT_PERIOD = 365 days;
              /// @notice The last time the mint function was called
              uint40 public lastMintTimestamp;
              constructor(address _initialOwner, address _treasury, address _foundation) ERC20("ENA", "ENA") ERC20Permit("ENA") {
                // first mint not allowed until 1 year after deployment
                lastMintTimestamp = uint40(block.timestamp);
                if (_initialOwner == address(0) || _treasury == address(0) || _foundation == address(0)) revert ZeroAddressException();
                _transferOwnership(_initialOwner);
                // initial supply of 15 billion tokens
                _mint(_treasury, 3_750_000_000 * 10 ** 18);
                _mint(_foundation, 11_250_000_000 * 10 ** 18);
              }
              /**
               * @notice Mints new ENA tokens
               * @param to The address to mint tokens to
               * @param amount The amount of tokens to mint
               * @dev Only callable by the owner once per year and amount must be less than max inflation rate
               */
              function mint(address to, uint256 amount) external onlyOwner {
                if (block.timestamp - lastMintTimestamp < MINT_WAIT_PERIOD) revert MintWaitPeriodInProgress();
                uint256 _maxInflationAmount = totalSupply() * MAX_INFLATION / 100;
                if (amount > _maxInflationAmount) revert MaxInflationExceeded();
                lastMintTimestamp = uint40(block.timestamp);
                _mint(to, amount);
                emit Mint(to, amount);
              }
              /// @notice Prevents the owner from renouncing ownership
              function renounceOwnership() public view override onlyOwner {
                revert CantRenounceOwnership();
              }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
            pragma solidity ^0.8.0;
            import "./IERC20.sol";
            import "./extensions/IERC20Metadata.sol";
            import "../../utils/Context.sol";
            /**
             * @dev Implementation of the {IERC20} interface.
             *
             * This implementation is agnostic to the way tokens are created. This means
             * that a supply mechanism has to be added in a derived contract using {_mint}.
             * For a generic mechanism see {ERC20PresetMinterPauser}.
             *
             * TIP: For a detailed writeup see our guide
             * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
             * to implement supply mechanisms].
             *
             * The default value of {decimals} is 18. To change this, you should override
             * this function so it returns a different value.
             *
             * 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 ERC20 is Context, IERC20, IERC20Metadata {
                mapping(address => uint256) private _balances;
                mapping(address => mapping(address => uint256)) private _allowances;
                uint256 private _totalSupply;
                string private _name;
                string private _symbol;
                /**
                 * @dev Sets the values for {name} and {symbol}.
                 *
                 * All two of these values are immutable: they can only be set once during
                 * construction.
                 */
                constructor(string memory name_, string memory symbol_) {
                    _name = name_;
                    _symbol = symbol_;
                }
                /**
                 * @dev Returns the name of the token.
                 */
                function name() public view virtual override returns (string memory) {
                    return _name;
                }
                /**
                 * @dev Returns the symbol of the token, usually a shorter version of the
                 * name.
                 */
                function symbol() public view virtual override 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 default value returned by this function, unless
                 * it's 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 view virtual override returns (uint8) {
                    return 18;
                }
                /**
                 * @dev See {IERC20-totalSupply}.
                 */
                function totalSupply() public view virtual override returns (uint256) {
                    return _totalSupply;
                }
                /**
                 * @dev See {IERC20-balanceOf}.
                 */
                function balanceOf(address account) public view virtual override returns (uint256) {
                    return _balances[account];
                }
                /**
                 * @dev See {IERC20-transfer}.
                 *
                 * Requirements:
                 *
                 * - `to` cannot be the zero address.
                 * - the caller must have a balance of at least `amount`.
                 */
                function transfer(address to, uint256 amount) public virtual override returns (bool) {
                    address owner = _msgSender();
                    _transfer(owner, to, 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}.
                 *
                 * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
                 * `transferFrom`. This is semantically equivalent to an infinite approval.
                 *
                 * Requirements:
                 *
                 * - `spender` cannot be the zero address.
                 */
                function approve(address spender, uint256 amount) public virtual override returns (bool) {
                    address owner = _msgSender();
                    _approve(owner, 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}.
                 *
                 * NOTE: Does not update the allowance if the current allowance
                 * is the maximum `uint256`.
                 *
                 * Requirements:
                 *
                 * - `from` and `to` cannot be the zero address.
                 * - `from` must have a balance of at least `amount`.
                 * - the caller must have allowance for ``from``'s tokens of at least
                 * `amount`.
                 */
                function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
                    address spender = _msgSender();
                    _spendAllowance(from, spender, amount);
                    _transfer(from, to, amount);
                    return true;
                }
                /**
                 * @dev Atomically increases the allowance granted to `spender` by the caller.
                 *
                 * This is an alternative to {approve} that can be used as a mitigation for
                 * problems described in {IERC20-approve}.
                 *
                 * Emits an {Approval} event indicating the updated allowance.
                 *
                 * Requirements:
                 *
                 * - `spender` cannot be the zero address.
                 */
                function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                    address owner = _msgSender();
                    _approve(owner, spender, allowance(owner, 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) public virtual returns (bool) {
                    address owner = _msgSender();
                    uint256 currentAllowance = allowance(owner, spender);
                    require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
                    unchecked {
                        _approve(owner, spender, currentAllowance - subtractedValue);
                    }
                    return true;
                }
                /**
                 * @dev Moves `amount` of tokens from `from` to `to`.
                 *
                 * 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:
                 *
                 * - `from` cannot be the zero address.
                 * - `to` cannot be the zero address.
                 * - `from` must have a balance of at least `amount`.
                 */
                function _transfer(address from, address to, uint256 amount) internal virtual {
                    require(from != address(0), "ERC20: transfer from the zero address");
                    require(to != address(0), "ERC20: transfer to the zero address");
                    _beforeTokenTransfer(from, to, amount);
                    uint256 fromBalance = _balances[from];
                    require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
                    unchecked {
                        _balances[from] = fromBalance - amount;
                        // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
                        // decrementing then incrementing.
                        _balances[to] += amount;
                    }
                    emit Transfer(from, to, amount);
                    _afterTokenTransfer(from, to, 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:
                 *
                 * - `account` 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 += amount;
                    unchecked {
                        // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
                        _balances[account] += amount;
                    }
                    emit Transfer(address(0), account, amount);
                    _afterTokenTransfer(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);
                    uint256 accountBalance = _balances[account];
                    require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
                    unchecked {
                        _balances[account] = accountBalance - amount;
                        // Overflow not possible: amount <= accountBalance <= totalSupply.
                        _totalSupply -= amount;
                    }
                    emit Transfer(account, address(0), amount);
                    _afterTokenTransfer(account, address(0), amount);
                }
                /**
                 * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
                 *
                 * This internal function is equivalent to `approve`, and can be used to
                 * e.g. set automatic allowances for certain subsystems, etc.
                 *
                 * Emits an {Approval} event.
                 *
                 * Requirements:
                 *
                 * - `owner` cannot be the zero address.
                 * - `spender` cannot be the zero address.
                 */
                function _approve(address owner, address spender, uint256 amount) internal virtual {
                    require(owner != address(0), "ERC20: approve from the zero address");
                    require(spender != address(0), "ERC20: approve to the zero address");
                    _allowances[owner][spender] = amount;
                    emit Approval(owner, spender, amount);
                }
                /**
                 * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
                 *
                 * Does not update the allowance amount in case of infinite allowance.
                 * Revert if not enough allowance is available.
                 *
                 * Might emit an {Approval} event.
                 */
                function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
                    uint256 currentAllowance = allowance(owner, spender);
                    if (currentAllowance != type(uint256).max) {
                        require(currentAllowance >= amount, "ERC20: insufficient allowance");
                        unchecked {
                            _approve(owner, spender, currentAllowance - amount);
                        }
                    }
                }
                /**
                 * @dev Hook that is called before any transfer of tokens. This includes
                 * minting and burning.
                 *
                 * Calling conditions:
                 *
                 * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                 * will be 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 {}
                /**
                 * @dev Hook that is called after any transfer of tokens. This includes
                 * minting and burning.
                 *
                 * Calling conditions:
                 *
                 * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                 * has been transferred to `to`.
                 * - when `from` is zero, `amount` tokens have been minted for `to`.
                 * - when `to` is zero, `amount` of ``from``'s tokens have been 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 _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)
            pragma solidity ^0.8.0;
            import "../ERC20.sol";
            import "../../../utils/Context.sol";
            /**
             * @dev Extension of {ERC20} that allows token holders to destroy both their own
             * tokens and those that they have an allowance for, in a way that can be
             * recognized off-chain (via event analysis).
             */
            abstract contract ERC20Burnable is Context, ERC20 {
                /**
                 * @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 {
                    _spendAllowance(account, _msgSender(), amount);
                    _burn(account, amount);
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/ERC20Permit.sol)
            pragma solidity ^0.8.0;
            import "./IERC20Permit.sol";
            import "../ERC20.sol";
            import "../../../utils/cryptography/ECDSA.sol";
            import "../../../utils/cryptography/EIP712.sol";
            import "../../../utils/Counters.sol";
            /**
             * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
             * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
             *
             * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
             * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
             * need to send a transaction, and thus is not required to hold Ether at all.
             *
             * _Available since v3.4._
             */
            abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
                using Counters for Counters.Counter;
                mapping(address => Counters.Counter) private _nonces;
                // solhint-disable-next-line var-name-mixedcase
                bytes32 private constant _PERMIT_TYPEHASH =
                    keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
                /**
                 * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.
                 * However, to ensure consistency with the upgradeable transpiler, we will continue
                 * to reserve a slot.
                 * @custom:oz-renamed-from _PERMIT_TYPEHASH
                 */
                // solhint-disable-next-line var-name-mixedcase
                bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;
                /**
                 * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
                 *
                 * It's a good idea to use the same `name` that is defined as the ERC20 token name.
                 */
                constructor(string memory name) EIP712(name, "1") {}
                /**
                 * @inheritdoc IERC20Permit
                 */
                function permit(
                    address owner,
                    address spender,
                    uint256 value,
                    uint256 deadline,
                    uint8 v,
                    bytes32 r,
                    bytes32 s
                ) public virtual override {
                    require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
                    bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
                    bytes32 hash = _hashTypedDataV4(structHash);
                    address signer = ECDSA.recover(hash, v, r, s);
                    require(signer == owner, "ERC20Permit: invalid signature");
                    _approve(owner, spender, value);
                }
                /**
                 * @inheritdoc IERC20Permit
                 */
                function nonces(address owner) public view virtual override returns (uint256) {
                    return _nonces[owner].current();
                }
                /**
                 * @inheritdoc IERC20Permit
                 */
                // solhint-disable-next-line func-name-mixedcase
                function DOMAIN_SEPARATOR() external view override returns (bytes32) {
                    return _domainSeparatorV4();
                }
                /**
                 * @dev "Consume a nonce": return the current value and increment.
                 *
                 * _Available since v4.1._
                 */
                function _useNonce(address owner) internal virtual returns (uint256 current) {
                    Counters.Counter storage nonce = _nonces[owner];
                    current = nonce.current();
                    nonce.increment();
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
            pragma solidity ^0.8.0;
            import "./Ownable.sol";
            /**
             * @dev Contract module which provides 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} and {acceptOwnership}.
             *
             * This module is used through inheritance. It will make available all functions
             * from parent (Ownable).
             */
            abstract contract Ownable2Step is Ownable {
                address private _pendingOwner;
                event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
                /**
                 * @dev Returns the address of the pending owner.
                 */
                function pendingOwner() public view virtual returns (address) {
                    return _pendingOwner;
                }
                /**
                 * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual override onlyOwner {
                    _pendingOwner = newOwner;
                    emit OwnershipTransferStarted(owner(), newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual override {
                    delete _pendingOwner;
                    super._transferOwnership(newOwner);
                }
                /**
                 * @dev The new owner accepts the ownership transfer.
                 */
                function acceptOwnership() public virtual {
                    address sender = _msgSender();
                    require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
                    _transferOwnership(sender);
                }
            }
            // SPDX-License-Identifier: GPL-3.0
            pragma solidity 0.8.20;
            interface IENADefinitions {
              /// @notice Event emitted when a new ENA token is minted (inflation) by the owner
              event Mint(address indexed to, uint256 amount);
              /// @notice This error is returned if the zero address is used
              error ZeroAddressException();
              /// @notice This error is returned if mint is called within 1 year of last mint
              error MintWaitPeriodInProgress();
              /// @notice This error is returned if the owner tries to renounce ownership
              error CantRenounceOwnership();
              /// @notice This error is returned if the max inflation rate is exceeded on mint
              error MaxInflationExceeded();
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Interface of the ERC20 standard as defined in the EIP.
             */
            interface IERC20 {
                /**
                 * @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 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 `to`.
                 *
                 * Returns a boolean value indicating whether the operation succeeded.
                 *
                 * Emits a {Transfer} event.
                 */
                function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
            pragma solidity ^0.8.0;
            import "../IERC20.sol";
            /**
             * @dev Interface for the optional metadata functions from the ERC20 standard.
             *
             * _Available since v4.1._
             */
            interface IERC20Metadata is IERC20 {
                /**
                 * @dev Returns the name of the token.
                 */
                function name() external view returns (string memory);
                /**
                 * @dev Returns the symbol of the token.
                 */
                function symbol() external view returns (string memory);
                /**
                 * @dev Returns the decimals places of the token.
                 */
                function decimals() external view returns (uint8);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.4) (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;
                }
                function _contextSuffixLength() internal view virtual returns (uint256) {
                    return 0;
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
             * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
             *
             * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
             * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
             * need to send a transaction, and thus is not required to hold Ether at all.
             *
             * ==== Security Considerations
             *
             * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
             * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
             * considered as an intention to spend the allowance in any specific way. The second is that because permits have
             * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
             * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
             * generally recommended is:
             *
             * ```solidity
             * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
             *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
             *     doThing(..., value);
             * }
             *
             * function doThing(..., uint256 value) public {
             *     token.safeTransferFrom(msg.sender, address(this), value);
             *     ...
             * }
             * ```
             *
             * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
             * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
             * {SafeERC20-safeTransferFrom}).
             *
             * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
             * contracts should have entry points that don't rely on permit.
             */
            interface IERC20Permit {
                /**
                 * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
                 * given ``owner``'s signed approval.
                 *
                 * IMPORTANT: The same issues {IERC20-approve} has related to transaction
                 * ordering also apply here.
                 *
                 * Emits an {Approval} event.
                 *
                 * Requirements:
                 *
                 * - `spender` cannot be the zero address.
                 * - `deadline` must be a timestamp in the future.
                 * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
                 * over the EIP712-formatted function arguments.
                 * - the signature must use ``owner``'s current nonce (see {nonces}).
                 *
                 * For more information on the signature format, see the
                 * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
                 * section].
                 *
                 * CAUTION: See Security Considerations above.
                 */
                function permit(
                    address owner,
                    address spender,
                    uint256 value,
                    uint256 deadline,
                    uint8 v,
                    bytes32 r,
                    bytes32 s
                ) external;
                /**
                 * @dev Returns the current nonce for `owner`. This value must be
                 * included whenever a signature is generated for {permit}.
                 *
                 * Every successful call to {permit} increases ``owner``'s nonce by one. This
                 * prevents a signature from being used multiple times.
                 */
                function nonces(address owner) external view returns (uint256);
                /**
                 * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
                 */
                // solhint-disable-next-line func-name-mixedcase
                function DOMAIN_SEPARATOR() external view returns (bytes32);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
            pragma solidity ^0.8.0;
            import "../Strings.sol";
            /**
             * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
             *
             * These functions can be used to verify that a message was signed by the holder
             * of the private keys of a given address.
             */
            library ECDSA {
                enum RecoverError {
                    NoError,
                    InvalidSignature,
                    InvalidSignatureLength,
                    InvalidSignatureS,
                    InvalidSignatureV // Deprecated in v4.8
                }
                function _throwError(RecoverError error) private pure {
                    if (error == RecoverError.NoError) {
                        return; // no error: do nothing
                    } else if (error == RecoverError.InvalidSignature) {
                        revert("ECDSA: invalid signature");
                    } else if (error == RecoverError.InvalidSignatureLength) {
                        revert("ECDSA: invalid signature length");
                    } else if (error == RecoverError.InvalidSignatureS) {
                        revert("ECDSA: invalid signature 's' value");
                    }
                }
                /**
                 * @dev Returns the address that signed a hashed message (`hash`) with
                 * `signature` or error string. This address can then be used for verification purposes.
                 *
                 * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
                 * this function rejects them by requiring the `s` value to be in the lower
                 * half order, and the `v` value to be either 27 or 28.
                 *
                 * IMPORTANT: `hash` _must_ be the result of a hash operation for the
                 * verification to be secure: it is possible to craft signatures that
                 * recover to arbitrary addresses for non-hashed data. A safe way to ensure
                 * this is by receiving a hash of the original message (which may otherwise
                 * be too long), and then calling {toEthSignedMessageHash} on it.
                 *
                 * Documentation for signature generation:
                 * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
                 * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
                 *
                 * _Available since v4.3._
                 */
                function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
                    if (signature.length == 65) {
                        bytes32 r;
                        bytes32 s;
                        uint8 v;
                        // ecrecover takes the signature parameters, and the only way to get them
                        // currently is to use assembly.
                        /// @solidity memory-safe-assembly
                        assembly {
                            r := mload(add(signature, 0x20))
                            s := mload(add(signature, 0x40))
                            v := byte(0, mload(add(signature, 0x60)))
                        }
                        return tryRecover(hash, v, r, s);
                    } else {
                        return (address(0), RecoverError.InvalidSignatureLength);
                    }
                }
                /**
                 * @dev Returns the address that signed a hashed message (`hash`) with
                 * `signature`. This address can then be used for verification purposes.
                 *
                 * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
                 * this function rejects them by requiring the `s` value to be in the lower
                 * half order, and the `v` value to be either 27 or 28.
                 *
                 * IMPORTANT: `hash` _must_ be the result of a hash operation for the
                 * verification to be secure: it is possible to craft signatures that
                 * recover to arbitrary addresses for non-hashed data. A safe way to ensure
                 * this is by receiving a hash of the original message (which may otherwise
                 * be too long), and then calling {toEthSignedMessageHash} on it.
                 */
                function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
                    (address recovered, RecoverError error) = tryRecover(hash, signature);
                    _throwError(error);
                    return recovered;
                }
                /**
                 * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
                 *
                 * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
                 *
                 * _Available since v4.3._
                 */
                function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
                    bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
                    uint8 v = uint8((uint256(vs) >> 255) + 27);
                    return tryRecover(hash, v, r, s);
                }
                /**
                 * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
                 *
                 * _Available since v4.2._
                 */
                function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
                    (address recovered, RecoverError error) = tryRecover(hash, r, vs);
                    _throwError(error);
                    return recovered;
                }
                /**
                 * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
                 * `r` and `s` signature fields separately.
                 *
                 * _Available since v4.3._
                 */
                function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
                    // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
                    // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
                    // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
                    // signatures from current libraries generate a unique signature with an s-value in the lower half order.
                    //
                    // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
                    // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
                    // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
                    // these malleable signatures as well.
                    if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
                        return (address(0), RecoverError.InvalidSignatureS);
                    }
                    // If the signature is valid (and not malleable), return the signer address
                    address signer = ecrecover(hash, v, r, s);
                    if (signer == address(0)) {
                        return (address(0), RecoverError.InvalidSignature);
                    }
                    return (signer, RecoverError.NoError);
                }
                /**
                 * @dev Overload of {ECDSA-recover} that receives the `v`,
                 * `r` and `s` signature fields separately.
                 */
                function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
                    (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
                    _throwError(error);
                    return recovered;
                }
                /**
                 * @dev Returns an Ethereum Signed Message, created from a `hash`. This
                 * produces hash corresponding to the one signed with the
                 * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
                 * JSON-RPC method as part of EIP-191.
                 *
                 * See {recover}.
                 */
                function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
                    // 32 is the length in bytes of hash,
                    // enforced by the type signature above
                    /// @solidity memory-safe-assembly
                    assembly {
                        mstore(0x00, "\\x19Ethereum Signed Message:\
            32")
                        mstore(0x1c, hash)
                        message := keccak256(0x00, 0x3c)
                    }
                }
                /**
                 * @dev Returns an Ethereum Signed Message, created from `s`. This
                 * produces hash corresponding to the one signed with the
                 * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
                 * JSON-RPC method as part of EIP-191.
                 *
                 * See {recover}.
                 */
                function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
                    return keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
            ", Strings.toString(s.length), s));
                }
                /**
                 * @dev Returns an Ethereum Signed Typed Data, created from a
                 * `domainSeparator` and a `structHash`. This produces hash corresponding
                 * to the one signed with the
                 * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
                 * JSON-RPC method as part of EIP-712.
                 *
                 * See {recover}.
                 */
                function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        let ptr := mload(0x40)
                        mstore(ptr, "\\x19\\x01")
                        mstore(add(ptr, 0x02), domainSeparator)
                        mstore(add(ptr, 0x22), structHash)
                        data := keccak256(ptr, 0x42)
                    }
                }
                /**
                 * @dev Returns an Ethereum Signed Data with intended validator, created from a
                 * `validator` and `data` according to the version 0 of EIP-191.
                 *
                 * See {recover}.
                 */
                function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
                    return keccak256(abi.encodePacked("\\x19\\x00", validator, data));
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)
            pragma solidity ^0.8.8;
            import "./ECDSA.sol";
            import "../ShortStrings.sol";
            import "../../interfaces/IERC5267.sol";
            /**
             * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
             *
             * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
             * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
             * they need in their contracts using a combination of `abi.encode` and `keccak256`.
             *
             * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
             * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
             * ({_hashTypedDataV4}).
             *
             * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
             * the chain id to protect against replay attacks on an eventual fork of the chain.
             *
             * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
             * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
             *
             * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
             * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the
             * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
             *
             * _Available since v3.4._
             *
             * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
             */
            abstract contract EIP712 is IERC5267 {
                using ShortStrings for *;
                bytes32 private constant _TYPE_HASH =
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
                // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
                // invalidate the cached domain separator if the chain id changes.
                bytes32 private immutable _cachedDomainSeparator;
                uint256 private immutable _cachedChainId;
                address private immutable _cachedThis;
                bytes32 private immutable _hashedName;
                bytes32 private immutable _hashedVersion;
                ShortString private immutable _name;
                ShortString private immutable _version;
                string private _nameFallback;
                string private _versionFallback;
                /**
                 * @dev Initializes the domain separator and parameter caches.
                 *
                 * The meaning of `name` and `version` is specified in
                 * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
                 *
                 * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
                 * - `version`: the current major version of the signing domain.
                 *
                 * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
                 * contract upgrade].
                 */
                constructor(string memory name, string memory version) {
                    _name = name.toShortStringWithFallback(_nameFallback);
                    _version = version.toShortStringWithFallback(_versionFallback);
                    _hashedName = keccak256(bytes(name));
                    _hashedVersion = keccak256(bytes(version));
                    _cachedChainId = block.chainid;
                    _cachedDomainSeparator = _buildDomainSeparator();
                    _cachedThis = address(this);
                }
                /**
                 * @dev Returns the domain separator for the current chain.
                 */
                function _domainSeparatorV4() internal view returns (bytes32) {
                    if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
                        return _cachedDomainSeparator;
                    } else {
                        return _buildDomainSeparator();
                    }
                }
                function _buildDomainSeparator() private view returns (bytes32) {
                    return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
                }
                /**
                 * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
                 * function returns the hash of the fully encoded EIP712 message for this domain.
                 *
                 * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
                 *
                 * ```solidity
                 * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
                 *     keccak256("Mail(address to,string contents)"),
                 *     mailTo,
                 *     keccak256(bytes(mailContents))
                 * )));
                 * address signer = ECDSA.recover(digest, signature);
                 * ```
                 */
                function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
                    return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
                }
                /**
                 * @dev See {EIP-5267}.
                 *
                 * _Available since v4.9._
                 */
                function eip712Domain()
                    public
                    view
                    virtual
                    override
                    returns (
                        bytes1 fields,
                        string memory name,
                        string memory version,
                        uint256 chainId,
                        address verifyingContract,
                        bytes32 salt,
                        uint256[] memory extensions
                    )
                {
                    return (
                        hex"0f", // 01111
                        _name.toStringWithFallback(_nameFallback),
                        _version.toStringWithFallback(_versionFallback),
                        block.chainid,
                        address(this),
                        bytes32(0),
                        new uint256[](0)
                    );
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
            pragma solidity ^0.8.0;
            /**
             * @title Counters
             * @author Matt Condon (@shrugs)
             * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
             * of elements in a mapping, issuing ERC721 ids, or counting request ids.
             *
             * Include with `using Counters for Counters.Counter;`
             */
            library Counters {
                struct Counter {
                    // This variable should never be directly accessed by users of the library: interactions must be restricted to
                    // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
                    // this feature: see https://github.com/ethereum/solidity/issues/4637
                    uint256 _value; // default: 0
                }
                function current(Counter storage counter) internal view returns (uint256) {
                    return counter._value;
                }
                function increment(Counter storage counter) internal {
                    unchecked {
                        counter._value += 1;
                    }
                }
                function decrement(Counter storage counter) internal {
                    uint256 value = counter._value;
                    require(value > 0, "Counter: decrement overflow");
                    unchecked {
                        counter._value = value - 1;
                    }
                }
                function reset(Counter storage counter) internal {
                    counter._value = 0;
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.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 Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    _checkOwner();
                    _;
                }
                /**
                 * @dev Returns the address of the current owner.
                 */
                function owner() public view virtual returns (address) {
                    return _owner;
                }
                /**
                 * @dev Throws if the sender is not the owner.
                 */
                function _checkOwner() internal view virtual {
                    require(owner() == _msgSender(), "Ownable: caller is not the owner");
                }
                /**
                 * @dev Leaves the contract without owner. It will not be possible to call
                 * `onlyOwner` functions. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby disabling 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);
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
            pragma solidity ^0.8.0;
            import "./math/Math.sol";
            import "./math/SignedMath.sol";
            /**
             * @dev String operations.
             */
            library Strings {
                bytes16 private constant _SYMBOLS = "0123456789abcdef";
                uint8 private constant _ADDRESS_LENGTH = 20;
                /**
                 * @dev Converts a `uint256` to its ASCII `string` decimal representation.
                 */
                function toString(uint256 value) internal pure returns (string memory) {
                    unchecked {
                        uint256 length = Math.log10(value) + 1;
                        string memory buffer = new string(length);
                        uint256 ptr;
                        /// @solidity memory-safe-assembly
                        assembly {
                            ptr := add(buffer, add(32, length))
                        }
                        while (true) {
                            ptr--;
                            /// @solidity memory-safe-assembly
                            assembly {
                                mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                            }
                            value /= 10;
                            if (value == 0) break;
                        }
                        return buffer;
                    }
                }
                /**
                 * @dev Converts a `int256` to its ASCII `string` decimal representation.
                 */
                function toString(int256 value) internal pure returns (string memory) {
                    return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
                }
                /**
                 * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
                 */
                function toHexString(uint256 value) internal pure returns (string memory) {
                    unchecked {
                        return toHexString(value, Math.log256(value) + 1);
                    }
                }
                /**
                 * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
                 */
                function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                    bytes memory buffer = new bytes(2 * length + 2);
                    buffer[0] = "0";
                    buffer[1] = "x";
                    for (uint256 i = 2 * length + 1; i > 1; --i) {
                        buffer[i] = _SYMBOLS[value & 0xf];
                        value >>= 4;
                    }
                    require(value == 0, "Strings: hex length insufficient");
                    return string(buffer);
                }
                /**
                 * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
                 */
                function toHexString(address addr) internal pure returns (string memory) {
                    return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
                }
                /**
                 * @dev Returns true if the two strings are equal.
                 */
                function equal(string memory a, string memory b) internal pure returns (bool) {
                    return keccak256(bytes(a)) == keccak256(bytes(b));
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol)
            pragma solidity ^0.8.8;
            import "./StorageSlot.sol";
            // | string  | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   |
            // | length  | 0x                                                              BB |
            type ShortString is bytes32;
            /**
             * @dev This library provides functions to convert short memory strings
             * into a `ShortString` type that can be used as an immutable variable.
             *
             * Strings of arbitrary length can be optimized using this library if
             * they are short enough (up to 31 bytes) by packing them with their
             * length (1 byte) in a single EVM word (32 bytes). Additionally, a
             * fallback mechanism can be used for every other case.
             *
             * Usage example:
             *
             * ```solidity
             * contract Named {
             *     using ShortStrings for *;
             *
             *     ShortString private immutable _name;
             *     string private _nameFallback;
             *
             *     constructor(string memory contractName) {
             *         _name = contractName.toShortStringWithFallback(_nameFallback);
             *     }
             *
             *     function name() external view returns (string memory) {
             *         return _name.toStringWithFallback(_nameFallback);
             *     }
             * }
             * ```
             */
            library ShortStrings {
                // Used as an identifier for strings longer than 31 bytes.
                bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
                error StringTooLong(string str);
                error InvalidShortString();
                /**
                 * @dev Encode a string of at most 31 chars into a `ShortString`.
                 *
                 * This will trigger a `StringTooLong` error is the input string is too long.
                 */
                function toShortString(string memory str) internal pure returns (ShortString) {
                    bytes memory bstr = bytes(str);
                    if (bstr.length > 31) {
                        revert StringTooLong(str);
                    }
                    return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
                }
                /**
                 * @dev Decode a `ShortString` back to a "normal" string.
                 */
                function toString(ShortString sstr) internal pure returns (string memory) {
                    uint256 len = byteLength(sstr);
                    // using `new string(len)` would work locally but is not memory safe.
                    string memory str = new string(32);
                    /// @solidity memory-safe-assembly
                    assembly {
                        mstore(str, len)
                        mstore(add(str, 0x20), sstr)
                    }
                    return str;
                }
                /**
                 * @dev Return the length of a `ShortString`.
                 */
                function byteLength(ShortString sstr) internal pure returns (uint256) {
                    uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
                    if (result > 31) {
                        revert InvalidShortString();
                    }
                    return result;
                }
                /**
                 * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
                 */
                function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
                    if (bytes(value).length < 32) {
                        return toShortString(value);
                    } else {
                        StorageSlot.getStringSlot(store).value = value;
                        return ShortString.wrap(_FALLBACK_SENTINEL);
                    }
                }
                /**
                 * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
                 */
                function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
                    if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
                        return toString(value);
                    } else {
                        return store;
                    }
                }
                /**
                 * @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
                 *
                 * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
                 * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
                 */
                function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
                    if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
                        return byteLength(value);
                    } else {
                        return bytes(store).length;
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)
            pragma solidity ^0.8.0;
            interface IERC5267 {
                /**
                 * @dev MAY be emitted to signal that the domain could have changed.
                 */
                event EIP712DomainChanged();
                /**
                 * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
                 * signature.
                 */
                function eip712Domain()
                    external
                    view
                    returns (
                        bytes1 fields,
                        string memory name,
                        string memory version,
                        uint256 chainId,
                        address verifyingContract,
                        bytes32 salt,
                        uint256[] memory extensions
                    );
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Standard math utilities missing in the Solidity language.
             */
            library Math {
                enum Rounding {
                    Down, // Toward negative infinity
                    Up, // Toward infinity
                    Zero // Toward zero
                }
                /**
                 * @dev Returns the largest of two numbers.
                 */
                function max(uint256 a, uint256 b) internal pure returns (uint256) {
                    return a > b ? a : b;
                }
                /**
                 * @dev Returns the smallest of two numbers.
                 */
                function min(uint256 a, uint256 b) internal pure returns (uint256) {
                    return a < b ? a : b;
                }
                /**
                 * @dev Returns the average of two numbers. The result is rounded towards
                 * zero.
                 */
                function average(uint256 a, uint256 b) internal pure returns (uint256) {
                    // (a + b) / 2 can overflow.
                    return (a & b) + (a ^ b) / 2;
                }
                /**
                 * @dev Returns the ceiling of the division of two numbers.
                 *
                 * This differs from standard division with `/` in that it rounds up instead
                 * of rounding down.
                 */
                function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                    // (a + b - 1) / b can overflow on addition, so we distribute.
                    return a == 0 ? 0 : (a - 1) / b + 1;
                }
                /**
                 * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
                 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
                 * with further edits by Uniswap Labs also under MIT license.
                 */
                function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
                    unchecked {
                        // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                        // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                        // variables such that product = prod1 * 2^256 + prod0.
                        uint256 prod0; // Least significant 256 bits of the product
                        uint256 prod1; // Most significant 256 bits of the product
                        assembly {
                            let mm := mulmod(x, y, not(0))
                            prod0 := mul(x, y)
                            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                        }
                        // Handle non-overflow cases, 256 by 256 division.
                        if (prod1 == 0) {
                            // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                            // The surrounding unchecked block does not change this fact.
                            // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                            return prod0 / denominator;
                        }
                        // Make sure the result is less than 2^256. Also prevents denominator == 0.
                        require(denominator > prod1, "Math: mulDiv overflow");
                        ///////////////////////////////////////////////
                        // 512 by 256 division.
                        ///////////////////////////////////////////////
                        // Make division exact by subtracting the remainder from [prod1 prod0].
                        uint256 remainder;
                        assembly {
                            // Compute remainder using mulmod.
                            remainder := mulmod(x, y, denominator)
                            // Subtract 256 bit number from 512 bit number.
                            prod1 := sub(prod1, gt(remainder, prod0))
                            prod0 := sub(prod0, remainder)
                        }
                        // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
                        // See https://cs.stackexchange.com/q/138556/92363.
                        // Does not overflow because the denominator cannot be zero at this stage in the function.
                        uint256 twos = denominator & (~denominator + 1);
                        assembly {
                            // Divide denominator by twos.
                            denominator := div(denominator, twos)
                            // Divide [prod1 prod0] by twos.
                            prod0 := div(prod0, twos)
                            // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                            twos := add(div(sub(0, twos), twos), 1)
                        }
                        // Shift in bits from prod1 into prod0.
                        prod0 |= prod1 * twos;
                        // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                        // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                        // four bits. That is, denominator * inv = 1 mod 2^4.
                        uint256 inverse = (3 * denominator) ^ 2;
                        // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                        // in modular arithmetic, doubling the correct bits in each step.
                        inverse *= 2 - denominator * inverse; // inverse mod 2^8
                        inverse *= 2 - denominator * inverse; // inverse mod 2^16
                        inverse *= 2 - denominator * inverse; // inverse mod 2^32
                        inverse *= 2 - denominator * inverse; // inverse mod 2^64
                        inverse *= 2 - denominator * inverse; // inverse mod 2^128
                        inverse *= 2 - denominator * inverse; // inverse mod 2^256
                        // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                        // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                        // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                        // is no longer required.
                        result = prod0 * inverse;
                        return result;
                    }
                }
                /**
                 * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
                 */
                function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
                    uint256 result = mulDiv(x, y, denominator);
                    if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
                        result += 1;
                    }
                    return result;
                }
                /**
                 * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
                 *
                 * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
                 */
                function sqrt(uint256 a) internal pure returns (uint256) {
                    if (a == 0) {
                        return 0;
                    }
                    // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
                    //
                    // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
                    // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
                    //
                    // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
                    // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
                    // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
                    //
                    // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
                    uint256 result = 1 << (log2(a) >> 1);
                    // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
                    // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
                    // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
                    // into the expected uint128 result.
                    unchecked {
                        result = (result + a / result) >> 1;
                        result = (result + a / result) >> 1;
                        result = (result + a / result) >> 1;
                        result = (result + a / result) >> 1;
                        result = (result + a / result) >> 1;
                        result = (result + a / result) >> 1;
                        result = (result + a / result) >> 1;
                        return min(result, a / result);
                    }
                }
                /**
                 * @notice Calculates sqrt(a), following the selected rounding direction.
                 */
                function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
                    unchecked {
                        uint256 result = sqrt(a);
                        return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
                    }
                }
                /**
                 * @dev Return the log in base 2, rounded down, of a positive value.
                 * Returns 0 if given 0.
                 */
                function log2(uint256 value) internal pure returns (uint256) {
                    uint256 result = 0;
                    unchecked {
                        if (value >> 128 > 0) {
                            value >>= 128;
                            result += 128;
                        }
                        if (value >> 64 > 0) {
                            value >>= 64;
                            result += 64;
                        }
                        if (value >> 32 > 0) {
                            value >>= 32;
                            result += 32;
                        }
                        if (value >> 16 > 0) {
                            value >>= 16;
                            result += 16;
                        }
                        if (value >> 8 > 0) {
                            value >>= 8;
                            result += 8;
                        }
                        if (value >> 4 > 0) {
                            value >>= 4;
                            result += 4;
                        }
                        if (value >> 2 > 0) {
                            value >>= 2;
                            result += 2;
                        }
                        if (value >> 1 > 0) {
                            result += 1;
                        }
                    }
                    return result;
                }
                /**
                 * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
                 * Returns 0 if given 0.
                 */
                function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
                    unchecked {
                        uint256 result = log2(value);
                        return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
                    }
                }
                /**
                 * @dev Return the log in base 10, rounded down, of a positive value.
                 * Returns 0 if given 0.
                 */
                function log10(uint256 value) internal pure returns (uint256) {
                    uint256 result = 0;
                    unchecked {
                        if (value >= 10 ** 64) {
                            value /= 10 ** 64;
                            result += 64;
                        }
                        if (value >= 10 ** 32) {
                            value /= 10 ** 32;
                            result += 32;
                        }
                        if (value >= 10 ** 16) {
                            value /= 10 ** 16;
                            result += 16;
                        }
                        if (value >= 10 ** 8) {
                            value /= 10 ** 8;
                            result += 8;
                        }
                        if (value >= 10 ** 4) {
                            value /= 10 ** 4;
                            result += 4;
                        }
                        if (value >= 10 ** 2) {
                            value /= 10 ** 2;
                            result += 2;
                        }
                        if (value >= 10 ** 1) {
                            result += 1;
                        }
                    }
                    return result;
                }
                /**
                 * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
                 * Returns 0 if given 0.
                 */
                function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
                    unchecked {
                        uint256 result = log10(value);
                        return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
                    }
                }
                /**
                 * @dev Return the log in base 256, rounded down, of a positive value.
                 * Returns 0 if given 0.
                 *
                 * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
                 */
                function log256(uint256 value) internal pure returns (uint256) {
                    uint256 result = 0;
                    unchecked {
                        if (value >> 128 > 0) {
                            value >>= 128;
                            result += 16;
                        }
                        if (value >> 64 > 0) {
                            value >>= 64;
                            result += 8;
                        }
                        if (value >> 32 > 0) {
                            value >>= 32;
                            result += 4;
                        }
                        if (value >> 16 > 0) {
                            value >>= 16;
                            result += 2;
                        }
                        if (value >> 8 > 0) {
                            result += 1;
                        }
                    }
                    return result;
                }
                /**
                 * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
                 * Returns 0 if given 0.
                 */
                function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
                    unchecked {
                        uint256 result = log256(value);
                        return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Standard signed math utilities missing in the Solidity language.
             */
            library SignedMath {
                /**
                 * @dev Returns the largest of two signed numbers.
                 */
                function max(int256 a, int256 b) internal pure returns (int256) {
                    return a > b ? a : b;
                }
                /**
                 * @dev Returns the smallest of two signed numbers.
                 */
                function min(int256 a, int256 b) internal pure returns (int256) {
                    return a < b ? a : b;
                }
                /**
                 * @dev Returns the average of two signed numbers without overflow.
                 * The result is rounded towards zero.
                 */
                function average(int256 a, int256 b) internal pure returns (int256) {
                    // Formula from the book "Hacker's Delight"
                    int256 x = (a & b) + ((a ^ b) >> 1);
                    return x + (int256(uint256(x) >> 255) & (a ^ b));
                }
                /**
                 * @dev Returns the absolute unsigned value of a signed value.
                 */
                function abs(int256 n) internal pure returns (uint256) {
                    unchecked {
                        // must be unchecked in order to support `n = type(int256).min`
                        return uint256(n >= 0 ? n : -n);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            pragma solidity ^0.8.0;
            /**
             * @dev Library for reading and writing primitive types to specific storage slots.
             *
             * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
             * This library helps with reading and writing to such slots without the need for inline assembly.
             *
             * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
             *
             * Example usage to set ERC1967 implementation slot:
             * ```solidity
             * contract ERC1967 {
             *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
             *
             *     function _getImplementation() internal view returns (address) {
             *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
             *     }
             *
             *     function _setImplementation(address newImplementation) internal {
             *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
             *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
             *     }
             * }
             * ```
             *
             * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
             * _Available since v4.9 for `string`, `bytes`._
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
                struct BooleanSlot {
                    bool value;
                }
                struct Bytes32Slot {
                    bytes32 value;
                }
                struct Uint256Slot {
                    uint256 value;
                }
                struct StringSlot {
                    string value;
                }
                struct BytesSlot {
                    bytes value;
                }
                /**
                 * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                 */
                function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                 */
                function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                 */
                function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                 */
                function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }