ETH Price: $2,818.37 (+2.44%)

Contract

0x0000000000000D1Dd95e299c2aB8Df107Dc83aEd

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
17983572025-05-29 17:52:48177 days ago1748541168  Contract Creation0 ETH

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AgoraDollar

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 100000000 runs

Other Settings:
shanghai EvmVersion
File 1 of 19 : AgoraDollar.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.21;

// ====================================================================
//             _        ______     ___   _______          _
//            / \     .' ___  |  .'   `.|_   __ \        / \
//           / _ \   / .'   \_| /  .-.  \ | |__) |      / _ \
//          / ___ \  | |   ____ | |   | | |  __ /      / ___ \
//        _/ /   \ \_\ `.___]  |\  `-'  /_| |  \ \_  _/ /   \ \_
//       |____| |____|`._____.'  `.___.'|____| |___||____| |____|
// ====================================================================
// =========================== AgoraDollar ============================
// ====================================================================

import { AgoraDollarCore, ConstructorParams, ShortStrings } from "./AgoraDollarCore.sol";

import { StorageLib } from "./proxy/StorageLib.sol";

/// @title AgoraDollar
/// @notice AgoraDollar is a digital dollar implementation
/// @author Agora
contract AgoraDollar is AgoraDollarCore {
    using StorageLib for uint256;
    using ShortStrings for *;

    /// @notice The AgoraDollar Constructor, invoked upon deployment
    /// @param _params The constructor params for AgoraDollar
    constructor(ConstructorParams memory _params) AgoraDollarCore(_params) {}

    //==============================================================================
    // External View Functions: Erc3009
    //==============================================================================

    // solhint-disable func-name-mixedcase
    /// @notice The ```TRANSFER_WITH_AUTHORIZATION_TYPEHASH``` function returns the typehash for the transfer with authorization
    function TRANSFER_WITH_AUTHORIZATION_TYPEHASH() external pure returns (bytes32) {
        return TRANSFER_WITH_AUTHORIZATION_TYPEHASH_;
    }

    /// @notice The ```RECEIVE_WITH_AUTHORIZATION_TYPEHASH``` function returns the typehash for the receive with authorization
    function RECEIVE_WITH_AUTHORIZATION_TYPEHASH() external pure returns (bytes32) {
        return RECEIVE_WITH_AUTHORIZATION_TYPEHASH_;
    }

    /// @notice The ```CANCEL_AUTHORIZATION_TYPEHASH``` function returns the typehash for the cancel authorization
    function CANCEL_AUTHORIZATION_TYPEHASH() external pure returns (bytes32) {
        return CANCEL_AUTHORIZATION_TYPEHASH_;
    }

    /// @notice The ```authorizationState``` function returns the state of the authorization nonce for a given authorizer
    /// @param _authorizer The account which is providing the authorization
    /// @param _nonce The unique nonce for the authorization
    /// @return _isNonceUsed The state of the authorization
    function authorizationState(address _authorizer, bytes32 _nonce) external view returns (bool _isNonceUsed) {
        _isNonceUsed = StorageLib.getPointerToEip3009Storage().isAuthorizationUsed[_authorizer][_nonce];
    }

    //==============================================================================
    //  External View Functions: Eip712
    //==============================================================================

    /// @notice The ```hashTypedDataV4``` function hashes the typed data according to Eip712
    /// @param _structHash The hash of the struct
    function hashTypedDataV4(bytes32 _structHash) external view returns (bytes32) {
        return _hashTypedDataV4({ structHash: _structHash });
    }

    /// @notice The ```domainSeparatorV4``` function returns the domain separator for Eip712
    function domainSeparatorV4() external view returns (bytes32) {
        return _domainSeparatorV4();
    }

    //==============================================================================
    // External View Functions: Erc2612
    //==============================================================================

    /// @notice The ```ERC2612_STORAGE_SLOT``` function returns the storage slot for Erc2612 storage
    function ERC2612_STORAGE_SLOT() external pure returns (bytes32) {
        return StorageLib.ERC2612_STORAGE_SLOT_;
    }

    /// @notice The ```nonces``` function returns the nonce for a given account according to Erc2612
    function nonces(address _account) external view returns (uint256 _nonce) {
        _nonce = StorageLib.getPointerToErc2612Storage().nonces[_account];
    }

    //==============================================================================
    // External View Functions: Erc20
    //==============================================================================

    /// @notice The ```name``` function returns the name of the token
    function name() external view returns (string memory) {
        return _name.toString();
    }

    /// @notice The ```symbol``` function returns the symbol of the token
    function symbol() external view returns (string memory) {
        return _symbol.toString();
    }

    /// @notice The ```balanceOf``` function returns the token balance of a given account
    /// @param _account The account to check the balance of
    /// @return The balance of the account
    function balanceOf(address _account) external view returns (uint256) {
        return StorageLib.getPointerToErc20CoreStorage().accountData[_account].balance;
    }

    /// @notice The ```allowance``` function returns the allowance a given owner has given to the spender
    /// @param _owner The account which is giving the allowance
    /// @param _spender The account which is being given the allowance
    /// @return The allowance the owner has given to the spender
    function allowance(address _owner, address _spender) external view returns (uint256) {
        return StorageLib.getPointerToErc20CoreStorage().accountAllowances[_owner][_spender];
    }

    /// @notice The ```totalSupply``` function returns the total supply of the token
    /// @return The total supply of the token
    function totalSupply() external view returns (uint256) {
        return StorageLib.getPointerToErc20CoreStorage().totalSupply;
    }

    /// @notice The ```isAccountFrozen``` function returns a boolean indicating if an account is frozen
    /// @param _account The account whose frozen status to check
    function isAccountFrozen(address _account) external view returns (bool) {
        return StorageLib.getPointerToErc20CoreStorage().accountData[_account].isFrozen;
    }

    /// @notice The ```accountData``` function returns Erc20 information about a given account
    /// @param _account The account to get the Erc20 information for
    /// @return The Erc20 information for the account (balance, isFrozenStatus)
    function accountData(address _account) external view returns (StorageLib.Erc20AccountData memory) {
        return StorageLib.getPointerToErc20CoreStorage().accountData[_account];
    }

    /// @notice The ```ERC20_CORE_STORAGE_SLOT``` function returns the storage slot for Erc20 storage
    function ERC20_CORE_STORAGE_SLOT() external pure returns (bytes32) {
        return StorageLib.ERC20_CORE_STORAGE_SLOT_;
    }

    //==============================================================================
    // External View Functions: AgoraDollarAccessControl
    //==============================================================================

    /// @notice The ``` getRoleData``` function returns the role data for a given role
    /// @param _roleId The role to get the data for
    /// @return The role data for the given role
    function getRoleData(bytes32 _roleId) external view returns (StorageLib.AgoraDollarAccessControlRoleData memory) {
        return StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[_roleId];
    }

    /// @notice The ```adminAddress``` function returns the address of the admin role
    /// @return The address which holds the admin role
    function adminAddress() external view returns (address) {
        return StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[ADMIN_ROLE].currentRoleAddress;
    }

    /// @notice The ```pendingAdminAddress``` function returns the pending address of the admin role
    /// @return The pending address of the admin role
    function pendingAdminAddress() external view returns (address) {
        return StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[ADMIN_ROLE].pendingRoleAddress;
    }

    /// @notice The ```minterAddress``` function returns the address of the minter role
    /// @return The address which holds the minter role
    function minterAddress() external view returns (address) {
        return StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[MINTER_ROLE].currentRoleAddress;
    }

    /// @notice The ```pendingMinterAddress``` function returns the pending address of the minter role
    /// @return The pending address of the minter role
    function pendingMinterAddress() external view returns (address) {
        return StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[MINTER_ROLE].pendingRoleAddress;
    }

    /// @notice The ```burnerAddress``` function returns the address of the burner role
    /// @return The address which holds the burner role
    function burnerAddress() external view returns (address) {
        return StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[BURNER_ROLE].currentRoleAddress;
    }

    /// @notice The ```pendingBurnerAddress``` function returns the pending address of the burner role
    /// @return The pending address of the burner role
    function pendingBurnerAddress() external view returns (address) {
        return StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[BURNER_ROLE].pendingRoleAddress;
    }

    /// @notice The ```pauserAddress``` function returns the address of the pauser role
    /// @return The address which holds the pauser role
    function pauserAddress() external view returns (address) {
        return StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[PAUSER_ROLE].currentRoleAddress;
    }

    /// @notice The ```pendingPauserAddress``` function returns the pending address of the pauser role
    /// @return The pending address of the pauser role
    function pendingPauserAddress() external view returns (address) {
        return StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[PAUSER_ROLE].pendingRoleAddress;
    }

    /// @notice The ```freezerAddress``` function returns the address of the freezer role
    /// @return The address which holds the freezer role
    function freezerAddress() external view returns (address) {
        return StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[FREEZER_ROLE].currentRoleAddress;
    }

    /// @notice The ```pendingFreezerAddress``` function returns the pending address of the freezer role
    /// @return The pending address of the freezer role
    function pendingFreezerAddress() external view returns (address) {
        return StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[FREEZER_ROLE].pendingRoleAddress;
    }

    //==============================================================================
    // External View Functions: Eip712
    //==============================================================================

    /// @notice The ```eip712Domain``` function returns the Eip712 domain data
    function eip712Domain()
        external
        view
        returns (
            bytes1 _fields,
            string memory _name,
            string memory _version,
            uint256 _chainId,
            address _verifyingContract,
            bytes32 _salt,
            uint256[] memory _extensions
        )
    {
        return (
            hex"0f", // 01111
            _Eip712Name(),
            _Eip712Version(),
            block.chainid,
            address(this),
            bytes32(0),
            new uint256[](0)
        );
    }

    //==============================================================================
    // External View Functions: AgoraDollarErc1967Proxy
    //==============================================================================

    /// @notice The ```proxyAdminAddress``` function returns the address of the proxy admin
    /// @return The address of the proxy admin
    function proxyAdminAddress() external view returns (address) {
        return StorageLib.getPointerToAgoraDollarErc1967ProxyAdminStorage().proxyAdminAddress;
    }

    /// @notice The ```isMsgSenderFrozenCheckEnabled``` function returns a boolean indicating if the msg.sender frozen check is turned on
    /// @return A boolean indicating if the msg sender frozen check is true
    function isMsgSenderFrozenCheckEnabled() external view returns (bool) {
        return StorageLib.sloadImplementationSlotDataAsUint256().isMsgSenderFrozenCheckEnabled();
    }

    /// @notice The ```isTransferPaused``` function returns a boolean indicating if transfers are paused
    /// @return A boolean indicating if transfers are paused
    function isTransferPaused() external view returns (bool) {
        return StorageLib.sloadImplementationSlotDataAsUint256().isTransferPaused();
    }

    /// @notice The ```isSignatureVerificationPaused``` function returns a boolean indicating if signature verification is paused
    /// @return A boolean indicating if signature verification is paused
    function isSignatureVerificationPaused() external view returns (bool) {
        return StorageLib.sloadImplementationSlotDataAsUint256().isSignatureVerificationPaused();
    }

    /// @notice The ```isMintPaused``` function returns a boolean indicating if minting is paused
    /// @return A boolean indicating if minting is paused
    function isMintPaused() external view returns (bool) {
        return StorageLib.sloadImplementationSlotDataAsUint256().isMintPaused();
    }

    /// @notice The ```isBurnFromPaused``` function returns a boolean indicating if burnFrom is paused
    /// @return A boolean indicating if burnFrom is paused
    function isBurnFromPaused() external view returns (bool) {
        return StorageLib.sloadImplementationSlotDataAsUint256().isBurnFromPaused();
    }

    /// @notice The ```isFreezingPaused``` function returns a boolean indicating if freezing is paused
    /// @return A boolean indicating if freezing is paused
    function isFreezingPaused() external view returns (bool) {
        return StorageLib.sloadImplementationSlotDataAsUint256().isFreezingPaused();
    }

    /// @notice The ```isTransferUpgraded``` function returns a boolean indicating if the transfer function is upgraded
    /// @return A boolean indicating if the transfer function is upgraded
    function isTransferUpgraded() external view returns (bool) {
        return StorageLib.sloadImplementationSlotDataAsUint256().isTransferUpgraded();
    }

    /// @notice The ```isTransferFromUpgraded``` function returns a boolean indicating if the transferFrom function is upgraded
    /// @return A boolean indicating if the transferFrom function is upgraded
    function isTransferFromUpgraded() external view returns (bool) {
        return StorageLib.sloadImplementationSlotDataAsUint256().isTransferFromUpgraded();
    }

    /// @notice The ```isTransferWithAuthorizationUpgraded``` function returns a boolean indicating if the transferWithAuthorization function is upgraded
    /// @return A boolean indicating if the transferWithAuthorization function is upgraded
    function isTransferWithAuthorizationUpgraded() external view returns (bool) {
        return StorageLib.sloadImplementationSlotDataAsUint256().isTransferWithAuthorizationUpgraded();
    }

    /// @notice The ```isReceiveWithAuthorizationUpgraded``` function returns a boolean indicating if the receiveWithAuthorization function is upgraded
    /// @return A boolean indicating if the receiveWithAuthorization function is upgraded
    function isReceiveWithAuthorizationUpgraded() external view returns (bool) {
        return StorageLib.sloadImplementationSlotDataAsUint256().isReceiveWithAuthorizationUpgraded();
    }

    /// @notice The ```implementation``` function returns the address of the implementation contract
    /// @return The address of the implementation contract
    function implementation() external view returns (address) {
        return StorageLib.sloadImplementationSlotDataAsUint256().implementation();
    }

    //==============================================================================
    // External View Functions: StorageLib Proxy Storage Bitmasks
    //==============================================================================

    /// @notice The ```IS_MSG_SENDER_FROZEN_CHECK_ENABLED_BIT_POSITION``` function returns a uint256 with a single bit flipped which indicates the bit position
    /// @return A uint256 with a single bit flipped to 1
    function IS_MSG_SENDER_FROZEN_CHECK_ENABLED_BIT_POSITION() external pure returns (uint256) {
        return StorageLib.IS_MSG_SENDER_FROZEN_CHECK_ENABLED_BIT_POSITION_;
    }

    /// @notice The ```IS_TRANSFER_PAUSED_BIT_POSITION``` function returns a uint256 with a single bit flipped which indicates the bit position
    /// @return A uint256 with a single bit flipped to 1
    function IS_MINT_PAUSED_BIT_POSITION() external pure returns (uint256) {
        return StorageLib.IS_MINT_PAUSED_BIT_POSITION_;
    }

    /// @notice The ```IS_BURN_FROM_PAUSED_BIT_POSITION``` function returns a uint256 with a single bit flipped which indicates the bit position
    /// @return A uint256 with a single bit flipped to 1
    function IS_BURN_FROM_PAUSED_BIT_POSITION() external pure returns (uint256) {
        return StorageLib.IS_BURN_FROM_PAUSED_BIT_POSITION_;
    }

    /// @notice The ```IS_FREEZING_PAUSED_BIT_POSITION``` function returns a uint256 with a single bit flipped which indicates the bit position
    /// @return A uint256 with a single bit flipped to 1
    function IS_FREEZING_PAUSED_BIT_POSITION() external pure returns (uint256) {
        return StorageLib.IS_FREEZING_PAUSED_BIT_POSITION_;
    }

    /// @notice The ```IS_TRANSFER_PAUSED_BIT_POSITION``` function returns a uint256 with a single bit flipped which indicates the bit position
    /// @return A uint256 with a single bit flipped to 1
    function IS_TRANSFER_PAUSED_BIT_POSITION() external pure returns (uint256) {
        return StorageLib.IS_TRANSFER_PAUSED_BIT_POSITION_;
    }

    /// @notice The ```IS_SIGNATURE_VERIFICATION_PAUSED_BIT_POSITION``` function returns a uint256 with a single bit flipped which indicates the bit position
    /// @return A uint256 with a single bit flipped to 1
    function IS_SIGNATURE_VERIFICATION_PAUSED_BIT_POSITION() external pure returns (uint256) {
        return StorageLib.IS_SIGNATURE_VERIFICATION_PAUSED_BIT_POSITION_;
    }

    /// @notice The ```IS_MINT_UPGRADED_BIT_POSITION``` function returns a uint256 with a single bit flipped which indicates the bit position
    /// @return A uint256 with a single bit flipped to 1
    function IS_TRANSFER_UPGRADED_BIT_POSITION() external pure returns (uint256) {
        return StorageLib.IS_TRANSFER_UPGRADED_BIT_POSITION_;
    }

    /// @notice The ```IS_TRANSFER_FROM_UPGRADED_BIT_POSITION``` function returns a uint256 with a single bit flipped which indicates the bit position
    /// @return A uint256 with a single bit flipped to 1
    function IS_TRANSFER_FROM_UPGRADED_BIT_POSITION() external pure returns (uint256) {
        return StorageLib.IS_TRANSFER_FROM_UPGRADED_BIT_POSITION_;
    }

    /// @notice The ```IS_TRANSFER_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION``` function returns a uint256 with a single bit flipped which indicates the bit position
    /// @return A uint256 with a single bit flipped to 1
    function IS_TRANSFER_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION() external pure returns (uint256) {
        return StorageLib.IS_TRANSFER_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION_;
    }

    /// @notice The ```IS_RECEIVE_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION``` function returns a uint256 with a single bit flipped which indicates the bit position
    /// @return A uint256 with a single bit flipped to 1
    function IS_RECEIVE_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION() external pure returns (uint256) {
        return StorageLib.IS_RECEIVE_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION_;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)

pragma solidity ^0.8.20;

import {StorageSlot} from "./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 v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @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(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 */
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
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @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), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(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) {
        uint256 localValue = value;
        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] = HEX_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        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 bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)

pragma solidity ^0.8.20;

import {Strings} from "../Strings.sol";

/**
 * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
 *
 * The library provides methods for generating a hash of a message that conforms to the
 * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
 * specifications.
 */
library MessageHashUtils {
    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing a bytes32 `messageHash` with
     * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
     * keccak256, although any bytes32 value can be safely used because the final digest will
     * be re-hashed.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
        }
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing an arbitrary `message` with
     * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
        return
            keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x00` (data with intended validator).
     *
     * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
     * `validator` address. Then hashing the result.
     *
     * See {ECDSA-recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(hex"19_00", validator, data));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
     *
     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
     * `\x19\x01` and hashing the result. It corresponds to the hash signed by the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
     *
     * See {ECDSA-recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, hex"19_01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            digest := keccak256(ptr, 0x42)
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @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 towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (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 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                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.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 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.

            uint256 twos = denominator & (0 - denominator);
            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 (unsignedRoundsUp(rounding) && 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
     * towards zero.
     *
     * 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 + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * 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 + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * 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 + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * 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 + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

/**
 * @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);
        }
    }
}

File 10 of 19 : SafeCastLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe integer casting library that reverts on overflow.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeCastLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol)
library SafeCastLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    error Overflow();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*          UNSIGNED INTEGER SAFE CASTING OPERATIONS          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function toUint8(uint256 x) internal pure returns (uint8) {
        if (x >= 1 << 8) _revertOverflow();
        return uint8(x);
    }

    function toUint16(uint256 x) internal pure returns (uint16) {
        if (x >= 1 << 16) _revertOverflow();
        return uint16(x);
    }

    function toUint24(uint256 x) internal pure returns (uint24) {
        if (x >= 1 << 24) _revertOverflow();
        return uint24(x);
    }

    function toUint32(uint256 x) internal pure returns (uint32) {
        if (x >= 1 << 32) _revertOverflow();
        return uint32(x);
    }

    function toUint40(uint256 x) internal pure returns (uint40) {
        if (x >= 1 << 40) _revertOverflow();
        return uint40(x);
    }

    function toUint48(uint256 x) internal pure returns (uint48) {
        if (x >= 1 << 48) _revertOverflow();
        return uint48(x);
    }

    function toUint56(uint256 x) internal pure returns (uint56) {
        if (x >= 1 << 56) _revertOverflow();
        return uint56(x);
    }

    function toUint64(uint256 x) internal pure returns (uint64) {
        if (x >= 1 << 64) _revertOverflow();
        return uint64(x);
    }

    function toUint72(uint256 x) internal pure returns (uint72) {
        if (x >= 1 << 72) _revertOverflow();
        return uint72(x);
    }

    function toUint80(uint256 x) internal pure returns (uint80) {
        if (x >= 1 << 80) _revertOverflow();
        return uint80(x);
    }

    function toUint88(uint256 x) internal pure returns (uint88) {
        if (x >= 1 << 88) _revertOverflow();
        return uint88(x);
    }

    function toUint96(uint256 x) internal pure returns (uint96) {
        if (x >= 1 << 96) _revertOverflow();
        return uint96(x);
    }

    function toUint104(uint256 x) internal pure returns (uint104) {
        if (x >= 1 << 104) _revertOverflow();
        return uint104(x);
    }

    function toUint112(uint256 x) internal pure returns (uint112) {
        if (x >= 1 << 112) _revertOverflow();
        return uint112(x);
    }

    function toUint120(uint256 x) internal pure returns (uint120) {
        if (x >= 1 << 120) _revertOverflow();
        return uint120(x);
    }

    function toUint128(uint256 x) internal pure returns (uint128) {
        if (x >= 1 << 128) _revertOverflow();
        return uint128(x);
    }

    function toUint136(uint256 x) internal pure returns (uint136) {
        if (x >= 1 << 136) _revertOverflow();
        return uint136(x);
    }

    function toUint144(uint256 x) internal pure returns (uint144) {
        if (x >= 1 << 144) _revertOverflow();
        return uint144(x);
    }

    function toUint152(uint256 x) internal pure returns (uint152) {
        if (x >= 1 << 152) _revertOverflow();
        return uint152(x);
    }

    function toUint160(uint256 x) internal pure returns (uint160) {
        if (x >= 1 << 160) _revertOverflow();
        return uint160(x);
    }

    function toUint168(uint256 x) internal pure returns (uint168) {
        if (x >= 1 << 168) _revertOverflow();
        return uint168(x);
    }

    function toUint176(uint256 x) internal pure returns (uint176) {
        if (x >= 1 << 176) _revertOverflow();
        return uint176(x);
    }

    function toUint184(uint256 x) internal pure returns (uint184) {
        if (x >= 1 << 184) _revertOverflow();
        return uint184(x);
    }

    function toUint192(uint256 x) internal pure returns (uint192) {
        if (x >= 1 << 192) _revertOverflow();
        return uint192(x);
    }

    function toUint200(uint256 x) internal pure returns (uint200) {
        if (x >= 1 << 200) _revertOverflow();
        return uint200(x);
    }

    function toUint208(uint256 x) internal pure returns (uint208) {
        if (x >= 1 << 208) _revertOverflow();
        return uint208(x);
    }

    function toUint216(uint256 x) internal pure returns (uint216) {
        if (x >= 1 << 216) _revertOverflow();
        return uint216(x);
    }

    function toUint224(uint256 x) internal pure returns (uint224) {
        if (x >= 1 << 224) _revertOverflow();
        return uint224(x);
    }

    function toUint232(uint256 x) internal pure returns (uint232) {
        if (x >= 1 << 232) _revertOverflow();
        return uint232(x);
    }

    function toUint240(uint256 x) internal pure returns (uint240) {
        if (x >= 1 << 240) _revertOverflow();
        return uint240(x);
    }

    function toUint248(uint256 x) internal pure returns (uint248) {
        if (x >= 1 << 248) _revertOverflow();
        return uint248(x);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*           SIGNED INTEGER SAFE CASTING OPERATIONS           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function toInt8(int256 x) internal pure returns (int8) {
        int8 y = int8(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt16(int256 x) internal pure returns (int16) {
        int16 y = int16(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt24(int256 x) internal pure returns (int24) {
        int24 y = int24(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt32(int256 x) internal pure returns (int32) {
        int32 y = int32(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt40(int256 x) internal pure returns (int40) {
        int40 y = int40(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt48(int256 x) internal pure returns (int48) {
        int48 y = int48(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt56(int256 x) internal pure returns (int56) {
        int56 y = int56(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt64(int256 x) internal pure returns (int64) {
        int64 y = int64(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt72(int256 x) internal pure returns (int72) {
        int72 y = int72(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt80(int256 x) internal pure returns (int80) {
        int80 y = int80(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt88(int256 x) internal pure returns (int88) {
        int88 y = int88(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt96(int256 x) internal pure returns (int96) {
        int96 y = int96(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt104(int256 x) internal pure returns (int104) {
        int104 y = int104(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt112(int256 x) internal pure returns (int112) {
        int112 y = int112(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt120(int256 x) internal pure returns (int120) {
        int120 y = int120(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt128(int256 x) internal pure returns (int128) {
        int128 y = int128(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt136(int256 x) internal pure returns (int136) {
        int136 y = int136(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt144(int256 x) internal pure returns (int144) {
        int144 y = int144(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt152(int256 x) internal pure returns (int152) {
        int152 y = int152(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt160(int256 x) internal pure returns (int160) {
        int160 y = int160(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt168(int256 x) internal pure returns (int168) {
        int168 y = int168(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt176(int256 x) internal pure returns (int176) {
        int176 y = int176(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt184(int256 x) internal pure returns (int184) {
        int184 y = int184(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt192(int256 x) internal pure returns (int192) {
        int192 y = int192(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt200(int256 x) internal pure returns (int200) {
        int200 y = int200(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt208(int256 x) internal pure returns (int208) {
        int208 y = int208(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt216(int256 x) internal pure returns (int216) {
        int216 y = int216(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt224(int256 x) internal pure returns (int224) {
        int224 y = int224(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt232(int256 x) internal pure returns (int232) {
        int232 y = int232(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt240(int256 x) internal pure returns (int240) {
        int240 y = int240(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt248(int256 x) internal pure returns (int248) {
        int248 y = int248(x);
        if (x != y) _revertOverflow();
        return y;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               OTHER SAFE CASTING OPERATIONS                */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function toInt256(uint256 x) internal pure returns (int256) {
        if (x >= 1 << 255) _revertOverflow();
        return int256(x);
    }

    function toUint256(int256 x) internal pure returns (uint256) {
        if (x < 0) _revertOverflow();
        return uint256(x);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function _revertOverflow() private pure {
        /// @solidity memory-safe-assembly
        assembly {
            // Store the function selector of `Overflow()`.
            mstore(0x00, 0x35278d12)
            // Revert with (offset, size).
            revert(0x1c, 0x04)
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Signature verification helper that supports both ECDSA signatures from EOAs
/// and ERC1271 signatures from smart contract wallets like Argent and Gnosis safe.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SignatureCheckerLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol)
///
/// @dev Note:
/// - The signature checking functions use the ecrecover precompile (0x1).
/// - The `bytes memory signature` variants use the identity precompile (0x4)
///   to copy memory internally.
/// - Unlike ECDSA signatures, contract signatures are revocable.
/// - As of Solady version 0.0.134, all `bytes signature` variants accept both
///   regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures.
///   See: https://eips.ethereum.org/EIPS/eip-2098
///   This is for calldata efficiency on smart accounts prevalent on L2s.
///
/// WARNING! Do NOT use signatures as unique identifiers:
/// - Use a nonce in the digest to prevent replay attacks on the same contract.
/// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts.
///   EIP-712 also enables readable signing of typed data for better user safety.
/// This implementation does NOT check if a signature is non-malleable.
library SignatureCheckerLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               SIGNATURE CHECKING OPERATIONS                */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns whether `signature` is valid for `signer` and `hash`.
    /// If `signer` is a smart contract, the signature is validated with ERC1271.
    /// Otherwise, the signature is validated with `ECDSA.recover`.
    function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits of `signer` in case they are dirty.
            for { signer := shr(96, shl(96, signer)) } signer {} {
                let m := mload(0x40)
                mstore(0x00, hash)
                mstore(0x40, mload(add(signature, 0x20))) // `r`.
                if eq(mload(signature), 64) {
                    let vs := mload(add(signature, 0x40))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                    let t :=
                        staticcall(
                            gas(), // Amount of gas left for the transaction.
                            1, // Address of `ecrecover`.
                            0x00, // Start of input.
                            0x80, // Size of input.
                            0x01, // Start of output.
                            0x20 // Size of output.
                        )
                    // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                    if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {
                        isValid := 1
                        mstore(0x60, 0) // Restore the zero slot.
                        mstore(0x40, m) // Restore the free memory pointer.
                        break
                    }
                }
                if eq(mload(signature), 65) {
                    mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                    mstore(0x60, mload(add(signature, 0x40))) // `s`.
                    let t :=
                        staticcall(
                            gas(), // Amount of gas left for the transaction.
                            1, // Address of `ecrecover`.
                            0x00, // Start of input.
                            0x80, // Size of input.
                            0x01, // Start of output.
                            0x20 // Size of output.
                        )
                    // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                    if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {
                        isValid := 1
                        mstore(0x60, 0) // Restore the zero slot.
                        mstore(0x40, m) // Restore the free memory pointer.
                        break
                    }
                }
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.

                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                // Copy the `signature` over.
                let n := add(0x20, mload(signature))
                pop(staticcall(gas(), 4, signature, n, add(m, 0x44), n))
                // forgefmt: disable-next-item
                isValid := and(
                    // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                    eq(mload(d), f),
                    // Whether the staticcall does not revert.
                    // This must be placed at the end of the `and` clause,
                    // as the arguments are evaluated from right to left.
                    staticcall(
                        gas(), // Remaining gas.
                        signer, // The `signer` address.
                        m, // Offset of calldata in memory.
                        add(returndatasize(), 0x44), // Length of calldata in memory.
                        d, // Offset of returndata.
                        0x20 // Length of returndata to write.
                    )
                )
                break
            }
        }
    }

    /// @dev Returns whether `signature` is valid for `signer` and `hash`.
    /// If `signer` is a smart contract, the signature is validated with ERC1271.
    /// Otherwise, the signature is validated with `ECDSA.recover`.
    function isValidSignatureNowCalldata(address signer, bytes32 hash, bytes calldata signature)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits of `signer` in case they are dirty.
            for { signer := shr(96, shl(96, signer)) } signer {} {
                let m := mload(0x40)
                mstore(0x00, hash)
                if eq(signature.length, 64) {
                    let vs := calldataload(add(signature.offset, 0x20))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x40, calldataload(signature.offset)) // `r`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                    let t :=
                        staticcall(
                            gas(), // Amount of gas left for the transaction.
                            1, // Address of `ecrecover`.
                            0x00, // Start of input.
                            0x80, // Size of input.
                            0x01, // Start of output.
                            0x20 // Size of output.
                        )
                    // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                    if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {
                        isValid := 1
                        mstore(0x60, 0) // Restore the zero slot.
                        mstore(0x40, m) // Restore the free memory pointer.
                        break
                    }
                }
                if eq(signature.length, 65) {
                    mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
                    calldatacopy(0x40, signature.offset, 0x40) // `r`, `s`.
                    let t :=
                        staticcall(
                            gas(), // Amount of gas left for the transaction.
                            1, // Address of `ecrecover`.
                            0x00, // Start of input.
                            0x80, // Size of input.
                            0x01, // Start of output.
                            0x20 // Size of output.
                        )
                    // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                    if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {
                        isValid := 1
                        mstore(0x60, 0) // Restore the zero slot.
                        mstore(0x40, m) // Restore the free memory pointer.
                        break
                    }
                }
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.

                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                mstore(add(m, 0x44), signature.length)
                // Copy the `signature` over.
                calldatacopy(add(m, 0x64), signature.offset, signature.length)
                // forgefmt: disable-next-item
                isValid := and(
                    // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                    eq(mload(d), f),
                    // Whether the staticcall does not revert.
                    // This must be placed at the end of the `and` clause,
                    // as the arguments are evaluated from right to left.
                    staticcall(
                        gas(), // Remaining gas.
                        signer, // The `signer` address.
                        m, // Offset of calldata in memory.
                        add(signature.length, 0x64), // Length of calldata in memory.
                        d, // Offset of returndata.
                        0x20 // Length of returndata to write.
                    )
                )
                break
            }
        }
    }

    /// @dev Returns whether the signature (`r`, `vs`) is valid for `signer` and `hash`.
    /// If `signer` is a smart contract, the signature is validated with ERC1271.
    /// Otherwise, the signature is validated with `ECDSA.recover`.
    function isValidSignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits of `signer` in case they are dirty.
            for { signer := shr(96, shl(96, signer)) } signer {} {
                let m := mload(0x40)
                mstore(0x00, hash)
                mstore(0x20, add(shr(255, vs), 27)) // `v`.
                mstore(0x40, r) // `r`.
                mstore(0x60, shr(1, shl(1, vs))) // `s`.
                let t :=
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        1, // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x01, // Start of output.
                        0x20 // Size of output.
                    )
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {
                    isValid := 1
                    mstore(0x60, 0) // Restore the zero slot.
                    mstore(0x40, m) // Restore the free memory pointer.
                    break
                }

                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                mstore(add(m, 0x44), 65) // Length of the signature.
                mstore(add(m, 0x64), r) // `r`.
                mstore(add(m, 0x84), mload(0x60)) // `s`.
                mstore8(add(m, 0xa4), mload(0x20)) // `v`.
                // forgefmt: disable-next-item
                isValid := and(
                    // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                    eq(mload(d), f),
                    // Whether the staticcall does not revert.
                    // This must be placed at the end of the `and` clause,
                    // as the arguments are evaluated from right to left.
                    staticcall(
                        gas(), // Remaining gas.
                        signer, // The `signer` address.
                        m, // Offset of calldata in memory.
                        0xa5, // Length of calldata in memory.
                        d, // Offset of returndata.
                        0x20 // Length of returndata to write.
                    )
                )
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.
                break
            }
        }
    }

    /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `signer` and `hash`.
    /// If `signer` is a smart contract, the signature is validated with ERC1271.
    /// Otherwise, the signature is validated with `ECDSA.recover`.
    function isValidSignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits of `signer` in case they are dirty.
            for { signer := shr(96, shl(96, signer)) } signer {} {
                let m := mload(0x40)
                mstore(0x00, hash)
                mstore(0x20, and(v, 0xff)) // `v`.
                mstore(0x40, r) // `r`.
                mstore(0x60, s) // `s`.
                let t :=
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        1, // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x01, // Start of output.
                        0x20 // Size of output.
                    )
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {
                    isValid := 1
                    mstore(0x60, 0) // Restore the zero slot.
                    mstore(0x40, m) // Restore the free memory pointer.
                    break
                }

                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                mstore(add(m, 0x44), 65) // Length of the signature.
                mstore(add(m, 0x64), r) // `r`.
                mstore(add(m, 0x84), s) // `s`.
                mstore8(add(m, 0xa4), v) // `v`.
                // forgefmt: disable-next-item
                isValid := and(
                    // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                    eq(mload(d), f),
                    // Whether the staticcall does not revert.
                    // This must be placed at the end of the `and` clause,
                    // as the arguments are evaluated from right to left.
                    staticcall(
                        gas(), // Remaining gas.
                        signer, // The `signer` address.
                        m, // Offset of calldata in memory.
                        0xa5, // Length of calldata in memory.
                        d, // Offset of returndata.
                        0x20 // Length of returndata to write.
                    )
                )
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.
                break
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     ERC1271 OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes memory signature)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            // Copy the `signature` over.
            let n := add(0x20, mload(signature))
            pop(staticcall(gas(), 4, signature, n, add(m, 0x44), n))
            // forgefmt: disable-next-item
            isValid := and(
                // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                eq(mload(d), f),
                // Whether the staticcall does not revert.
                // This must be placed at the end of the `and` clause,
                // as the arguments are evaluated from right to left.
                staticcall(
                    gas(), // Remaining gas.
                    signer, // The `signer` address.
                    m, // Offset of calldata in memory.
                    add(returndatasize(), 0x44), // Length of calldata in memory.
                    d, // Offset of returndata.
                    0x20 // Length of returndata to write.
                )
            )
        }
    }

    /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNowCalldata(
        address signer,
        bytes32 hash,
        bytes calldata signature
    ) internal view returns (bool isValid) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            mstore(add(m, 0x44), signature.length)
            // Copy the `signature` over.
            calldatacopy(add(m, 0x64), signature.offset, signature.length)
            // forgefmt: disable-next-item
            isValid := and(
                // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                eq(mload(d), f),
                // Whether the staticcall does not revert.
                // This must be placed at the end of the `and` clause,
                // as the arguments are evaluated from right to left.
                staticcall(
                    gas(), // Remaining gas.
                    signer, // The `signer` address.
                    m, // Offset of calldata in memory.
                    add(signature.length, 0x64), // Length of calldata in memory.
                    d, // Offset of returndata.
                    0x20 // Length of returndata to write.
                )
            )
        }
    }

    /// @dev Returns whether the signature (`r`, `vs`) is valid for `hash`
    /// for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            mstore(add(m, 0x44), 65) // Length of the signature.
            mstore(add(m, 0x64), r) // `r`.
            mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`.
            mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`.
            // forgefmt: disable-next-item
            isValid := and(
                // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                eq(mload(d), f),
                // Whether the staticcall does not revert.
                // This must be placed at the end of the `and` clause,
                // as the arguments are evaluated from right to left.
                staticcall(
                    gas(), // Remaining gas.
                    signer, // The `signer` address.
                    m, // Offset of calldata in memory.
                    0xa5, // Length of calldata in memory.
                    d, // Offset of returndata.
                    0x20 // Length of returndata to write.
                )
            )
        }
    }

    /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `hash`
    /// for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            mstore(add(m, 0x44), 65) // Length of the signature.
            mstore(add(m, 0x64), r) // `r`.
            mstore(add(m, 0x84), s) // `s`.
            mstore8(add(m, 0xa4), v) // `v`.
            // forgefmt: disable-next-item
            isValid := and(
                // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).
                eq(mload(d), f),
                // Whether the staticcall does not revert.
                // This must be placed at the end of the `and` clause,
                // as the arguments are evaluated from right to left.
                staticcall(
                    gas(), // Remaining gas.
                    signer, // The `signer` address.
                    m, // Offset of calldata in memory.
                    0xa5, // Length of calldata in memory.
                    d, // Offset of returndata.
                    0x20 // Length of returndata to write.
                )
            )
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     HASHING OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an Ethereum Signed Message, created from a `hash`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x20, hash) // Store into scratch space for keccak256.
            mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes.
            result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
        }
    }

    /// @dev Returns an Ethereum Signed Message, created from `s`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    /// Note: Supports lengths of `s` up to 999999 bytes.
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let sLength := mload(s)
            let o := 0x20
            mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded.
            mstore(0x00, 0x00)
            // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
            for { let temp := sLength } 1 {} {
                o := sub(o, 1)
                mstore8(o, add(48, mod(temp, 10)))
                temp := div(temp, 10)
                if iszero(temp) { break }
            }
            let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
            // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
            mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
            result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
            mstore(s, sLength) // Restore the length.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   EMPTY CALLDATA HELPERS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an empty calldata bytes.
    function emptySignature() internal pure returns (bytes calldata signature) {
        /// @solidity memory-safe-assembly
        assembly {
            signature.length := 0
        }
    }
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.21;

// ====================================================================
//             _        ______     ___   _______          _
//            / \     .' ___  |  .'   `.|_   __ \        / \
//           / _ \   / .'   \_| /  .-.  \ | |__) |      / _ \
//          / ___ \  | |   ____ | |   | | |  __ /      / ___ \
//        _/ /   \ \_\ `.___]  |\  `-'  /_| |  \ \_  _/ /   \ \_
//       |____| |____|`._____.'  `.___.'|____| |___||____| |____|
// ====================================================================
// ===================== AgoraDollarAccessControl =====================
// ====================================================================

import { StorageLib } from "./proxy/StorageLib.sol";

/// @title AgoraDollarAccessControl
/// @dev Inspired by Frax Finance's Timelock2Step contract which was inspired by OpenZeppelin's Ownable2Step contract
/// @notice An abstract contract which contains 2-step transfer and renounce logic for a privileged roles
abstract contract AgoraDollarAccessControl {
    /// @notice The ADMIN_ROLE identifier
    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");

    /// @notice The MINTER_ROLE identifier
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    /// @notice The BURNER_ROLE identifier
    bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");

    /// @notice The PAUSER_ROLE identifier
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

    /// @notice The FREEZER_ROLE identifier
    bytes32 public constant FREEZER_ROLE = keccak256("FREEZER_ROLE");

    /// @notice The RoleData struct
    /// @param pendingRoleAddress The address of the nominated (pending) role
    /// @param currentRoleAddress The address of the current role
    struct RoleData {
        address pendingRoleAddress;
        address currentRoleAddress;
    }

    function _initializeAgoraDollarAccessControl(address _initialAdminAddress) internal {
        StorageLib
            .getPointerToAgoraDollarAccessControlStorage()
            .roleData[ADMIN_ROLE]
            .currentRoleAddress = _initialAdminAddress;
    }

    // ============================================================================================
    // External Procedural Functions
    // ============================================================================================

    /// @notice The ```transferRole``` function initiates the role transfer
    /// @dev Must be called by the current role or the Admin
    /// @param _newAddress The address of the nominated (pending) role
    function transferRole(bytes32 _role, address _newAddress) external virtual {
        // Checks: Only current role or Admin can transfer role
        if (!(_isRole({ _role: _role, _address: msg.sender }) || _isRole({ _role: ADMIN_ROLE, _address: msg.sender })))
            revert AddressIsNotRole({ role: _role });

        // Effects: update pendingRole
        _setPendingRoleAddress({ _role: _role, _newAddress: _newAddress });
    }

    /// @notice The ```acceptTransferRole``` function completes the role transfer
    /// @dev Must be called by the pending role
    function acceptTransferRole(bytes32 _role) external virtual {
        // Checks
        _requireSenderIsPendingRole({ _role: _role });

        // Effects update role address
        _acceptTransferRole({ _role: _role });
    }

    // ============================================================================================
    // Internal Effects Functions
    // ============================================================================================

    /// @notice The ```_transferRole``` function initiates the role transfer
    /// @dev This function is to be implemented by a public function
    /// @param _role The role to transfer
    /// @param _newAddress The address of the nominated (pending) role
    function _setPendingRoleAddress(bytes32 _role, address _newAddress) internal {
        StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[_role].pendingRoleAddress = _newAddress;
        emit RoleTransferStarted({
            role: _role,
            previousAddress: StorageLib
                .getPointerToAgoraDollarAccessControlStorage()
                .roleData[_role]
                .currentRoleAddress,
            newAddress: _newAddress
        });
    }

    /// @notice The ```_acceptTransferRole``` function completes the role transfer
    /// @dev This function is to be implemented by a public function
    /// @param _role The role identifier to transfer
    function _acceptTransferRole(bytes32 _role) internal {
        StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[_role].pendingRoleAddress = address(0);
        _setCurrentRoleAddress({ _role: _role, _newAddress: msg.sender });
    }

    /// @notice The ```_setRole``` function sets the role address
    /// @dev This function is to be implemented by a public function
    /// @param _role The role identifier to transfer
    /// @param _newAddress The address of the new role
    function _setCurrentRoleAddress(bytes32 _role, address _newAddress) internal {
        emit RoleTransferred({
            role: _role,
            previousAddress: StorageLib
                .getPointerToAgoraDollarAccessControlStorage()
                .roleData[_role]
                .currentRoleAddress,
            newAddress: _newAddress
        });
        StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[_role].currentRoleAddress = _newAddress;
    }

    // ============================================================================================
    // Internal Checks Functions
    // ============================================================================================

    /// @notice The ```_isRole``` function checks if _address is current role address
    /// @param _role The role identifier to check
    /// @param _address The address to check against the role
    /// @return Whether or not msg.sender is current role address
    function _isRole(bytes32 _role, address _address) internal view returns (bool) {
        return _address == StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[_role].currentRoleAddress;
    }

    /// @notice The ```_requireIsRole``` function reverts if _address is not current role address
    /// @param _role The role identifier to check
    /// @param _address The address to check against the role
    function _requireIsRole(bytes32 _role, address _address) internal view {
        if (!_isRole({ _role: _role, _address: _address })) revert AddressIsNotRole({ role: _role });
    }

    /// @notice The ```_requireSenderIsRole``` function reverts if msg.sender is not current role address
    /// @dev This function is to be implemented by a public function
    /// @param _role The role identifier to check
    function _requireSenderIsRole(bytes32 _role) internal view {
        _requireIsRole({ _role: _role, _address: msg.sender });
    }

    /// @notice The ```_isPendingRole``` function checks if the _address is pending role address
    /// @dev This function is to be implemented by a public function
    /// @param _role The role identifier to check
    /// @param _address The address to check against the pending role
    /// @return Whether or not _address is pending role address
    function _isPendingRole(bytes32 _role, address _address) internal view returns (bool) {
        return _address == StorageLib.getPointerToAgoraDollarAccessControlStorage().roleData[_role].pendingRoleAddress;
    }

    /// @notice The ```_requireIsPendingRole``` function reverts if the _address is not pending role address
    /// @dev This function is to be implemented by a public function
    /// @param _role The role identifier to check
    /// @param _address The address to check against the pending role
    function _requireIsPendingRole(bytes32 _role, address _address) internal view {
        if (!_isPendingRole({ _role: _role, _address: _address })) revert AddressIsNotPendingRole({ role: _role });
    }

    /// @notice The ```_requirePendingRole``` function reverts if msg.sender is not pending role address
    /// @dev This function is to be implemented by a public function
    /// @param _role The role identifier to check
    function _requireSenderIsPendingRole(bytes32 _role) internal view {
        _requireIsPendingRole({ _role: _role, _address: msg.sender });
    }

    // ============================================================================================
    // Events
    // ============================================================================================

    /// @notice The ```RoleTransferStarted``` event is emitted when the role transfer is initiated
    /// @param role The bytes32 identifier of the role that is being transferred
    /// @param previousAddress The address of the previous role
    /// @param newAddress The address of the new role
    event RoleTransferStarted(bytes32 role, address indexed previousAddress, address indexed newAddress);

    /// @notice The ```RoleTransferred``` event is emitted when the role transfer is completed
    /// @param role The bytes32 identifier of the role that was transferred
    /// @param previousAddress The address of the previous role
    /// @param newAddress The address of the new role
    event RoleTransferred(bytes32 role, address indexed previousAddress, address indexed newAddress);

    // ============================================================================================
    // Errors
    // ============================================================================================

    /// @notice Emitted when role is transferred
    /// @param role The role identifier
    error AddressIsNotRole(bytes32 role);

    /// @notice Emitted when pending role is transferred
    /// @param role The role identifier
    error AddressIsNotPendingRole(bytes32 role);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.21;

// solhint-disable func-name-mixedcase
// ====================================================================
//             _        ______     ___   _______          _
//            / \     .' ___  |  .'   `.|_   __ \        / \
//           / _ \   / .'   \_| /  .-.  \ | |__) |      / _ \
//          / ___ \  | |   ____ | |   | | |  __ /      / ___ \
//        _/ /   \ \_\ `.___]  |\  `-'  /_| |  \ \_  _/ /   \ \_
//       |____| |____|`._____.'  `.___.'|____| |___||____| |____|
// ====================================================================
// ========================= AgoraDollarCore ==========================
// ====================================================================

import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { ShortString, ShortStrings } from "@openzeppelin/contracts/utils/ShortStrings.sol";

import { Eip3009 } from "./Eip3009.sol";
import { Eip712 } from "./Eip712.sol";
import { Erc20Privileged } from "./Erc20Privileged.sol";
import { Erc2612 } from "./Erc2612.sol";

import { StorageLib } from "./proxy/StorageLib.sol";

/// @notice The Constructor Params for AgoraDollarCore
/// @param name The name of the token
/// @param symbol The symbol of the token
/// @param eip712Name The name of the Eip712 domain
/// @param eip712Version The version of the Eip712 domain
/// @param proxyAddress The address of the proxy contract
struct ConstructorParams {
    string name;
    string symbol;
    string eip712Name;
    string eip712Version;
    address proxyAddress;
}

/// @title AgoraDollarCore
/// @notice The AgoraDollarCore contract is the core implementation of the Agora Dollar token
/// @author Agora
contract AgoraDollarCore is Initializable, Eip3009, Erc2612, Erc20Privileged {
    using StorageLib for uint256;
    using ShortStrings for *;

    ShortString internal immutable _name;

    ShortString internal immutable _symbol;

    uint8 public immutable decimals = 6;

    constructor(
        ConstructorParams memory _params
    ) Eip712(_params.eip712Name, _params.eip712Version, _params.proxyAddress) {
        _name = _params.name.toShortString();
        _symbol = _params.symbol.toShortString();

        // Prevent implementation from being initialized
        _disableInitializers();
    }

    /// @notice The ```_initialAdminAddress``` initializes the AgoraDollarCore and inherited contracts
    /// @dev Has a modifier to prevent reinitialization
    /// @param _initialAdminAddress The initial admin address for role-based access control
    function initialize(address _initialAdminAddress) external reinitializer(2) {
        _initializeAgoraDollarAccessControl({ _initialAdminAddress: _initialAdminAddress });
    }

    //==============================================================================
    // External stateful Functions: Erc20
    //==============================================================================

    /// The ```approve``` function is used to approve a spender to spend a certain amount of tokens on behalf of the caller
    /// @dev This function reverts on failure
    /// @param _spender The address of the spender
    /// @param _value The amount of tokens to approve for spending
    /// @return success A boolean indicating if the approval was successful
    function approve(address _spender, uint256 _value) external returns (bool) {
        _approve({ _owner: msg.sender, _spender: _spender, _value: _value });
        return true;
    }

    function transfer(address _to, uint256 _value) external returns (bool) {
        // NOTE: implemented in proxy, here to check for signature collisions
    }

    function transferFrom(address _from, address _to, uint256 _value) external returns (bool) {
        // NOTE: implemented in proxy, here to check for signature collisions
    }

    //==============================================================================
    // External Stateful Functions: Erc3009
    //==============================================================================

    function transferWithAuthorization(
        address _from,
        address _to,
        uint256 _value,
        uint256 _validAfter,
        uint256 _validBefore,
        bytes32 _nonce,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) external {
        // NOTE: implemented in proxy, here to check for signature collisions
    }

    function transferWithAuthorization(
        address _from,
        address _to,
        uint256 _value,
        uint256 _validAfter,
        uint256 _validBefore,
        bytes32 _nonce,
        bytes memory _signature
    ) public {
        // NOTE: implemented in proxy, here to check for signature collisions
    }

    function receiveWithAuthorization(
        address _from,
        address _to,
        uint256 _value,
        uint256 _validAfter,
        uint256 _validBefore,
        bytes32 _nonce,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) external {
        // NOTE: implemented in proxy, here to check for signature collisions
    }

    function receiveWithAuthorization(
        address _from,
        address _to,
        uint256 _value,
        uint256 _validAfter,
        uint256 _validBefore,
        bytes32 _nonce,
        bytes memory _signature
    ) public {
        // NOTE: implemented in proxy, here to check for signature collisions
    }

    /// @notice The ```cancelAuthorization``` function cancels an authorization nonce
    /// @dev EOA wallet signatures should be packed in the order of r, s, v
    /// @param _authorizer    Authorizer's address
    /// @param _nonce         Nonce of the authorization
    /// @param _v           ECDSA signature v value
    /// @param _r           ECDSA signature r value
    /// @param _s           ECDSA signature s value
    function cancelAuthorization(address _authorizer, bytes32 _nonce, uint8 _v, bytes32 _r, bytes32 _s) external {
        cancelAuthorization({ _authorizer: _authorizer, _nonce: _nonce, _signature: abi.encodePacked(_r, _s, _v) });
    }

    /// @notice The ```cancelAuthorization``` function cancels an authorization nonce
    /// @dev EOA wallet signatures should be packed in the order of r, s, v
    /// @param _authorizer    Authorizer's address
    /// @param _nonce         Nonce of the authorization
    /// @param _signature     Signature byte array produced by an EOA wallet or a contract wallet
    function cancelAuthorization(address _authorizer, bytes32 _nonce, bytes memory _signature) public {
        // Effects: mark the signature as used
        _cancelAuthorization({ _authorizer: _authorizer, _nonce: _nonce, _signature: _signature });
    }

    //==============================================================================
    // Contract Data Setters Functions
    //==============================================================================

    /// @notice The ```setIsMsgSenderCheckEnabled``` function sets the isMsgSenderCheckEnabled state variable
    /// @param _isEnabled The new value of the isMsgSenderCheckEnabled state variable
    function setIsMsgSenderCheckEnabled(bool _isEnabled) external {
        _requireSenderIsRole({ _role: ADMIN_ROLE });
        uint256 _contractData = StorageLib.sloadImplementationSlotDataAsUint256();
        uint256 _newContractData = _contractData.setBitWithMask({
            _bitToSet: StorageLib.IS_MSG_SENDER_FROZEN_CHECK_ENABLED_BIT_POSITION_,
            _setBitToOne: _isEnabled
        });
        _newContractData.sstoreImplementationSlotDataAsUint256();
        emit SetIsMsgSenderCheckEnabled({ isEnabled: _isEnabled });
    }

    /// @notice The ```setIsMintPaused``` function sets the isMintPaused state variable
    /// @param _isPaused The new value of the isMintPaused state variable
    function setIsMintPaused(bool _isPaused) external {
        _requireSenderIsRole({ _role: PAUSER_ROLE });
        uint256 _contractData = StorageLib.sloadImplementationSlotDataAsUint256();
        uint256 _newContractData = _contractData.setBitWithMask({
            _bitToSet: StorageLib.IS_MINT_PAUSED_BIT_POSITION_,
            _setBitToOne: _isPaused
        });
        _newContractData.sstoreImplementationSlotDataAsUint256();
        emit SetIsMintPaused({ isPaused: _isPaused });
    }

    /// @notice The ```setIsBurnFromPaused``` function sets the isBurnFromPaused state variable
    /// @param _isPaused The new value of the isBurnFromPaused state variable
    function setIsBurnFromPaused(bool _isPaused) external {
        _requireSenderIsRole({ _role: PAUSER_ROLE });
        uint256 _contractData = StorageLib.sloadImplementationSlotDataAsUint256();
        uint256 _newContractData = _contractData.setBitWithMask({
            _bitToSet: StorageLib.IS_BURN_FROM_PAUSED_BIT_POSITION_,
            _setBitToOne: _isPaused
        });
        _newContractData.sstoreImplementationSlotDataAsUint256();
        emit SetIsBurnFromPaused({ isPaused: _isPaused });
    }

    /// @notice The ```setIsFreezingPaused``` function sets the isFreezingPaused state variable
    /// @param _isPaused The new value of the isFreezingPaused state variable
    function setIsFreezingPaused(bool _isPaused) external {
        _requireSenderIsRole({ _role: PAUSER_ROLE });
        uint256 _contractData = StorageLib.sloadImplementationSlotDataAsUint256();
        uint256 _newContractData = _contractData.setBitWithMask({
            _bitToSet: StorageLib.IS_FREEZING_PAUSED_BIT_POSITION_,
            _setBitToOne: _isPaused
        });
        _newContractData.sstoreImplementationSlotDataAsUint256();
        emit SetIsFreezingPaused({ isPaused: _isPaused });
    }

    /// @notice The ```setIsTransferPaused``` function sets the isTransferPaused state variable
    /// @param _isPaused The new value of the isTransferPaused state variable
    function setIsTransferPaused(bool _isPaused) external {
        _requireSenderIsRole({ _role: PAUSER_ROLE });
        uint256 _contractData = StorageLib.sloadImplementationSlotDataAsUint256();
        uint256 _newContractData = _contractData.setBitWithMask({
            _bitToSet: StorageLib.IS_TRANSFER_PAUSED_BIT_POSITION_,
            _setBitToOne: _isPaused
        });
        _newContractData.sstoreImplementationSlotDataAsUint256();
        emit SetIsTransferPaused({ isPaused: _isPaused });
    }

    /// @notice The ```setIsSignatureVerificationPaused``` function sets the isSignatureVerificationPaused state variable
    /// @param _isPaused The new value of the isSignatureVerificationPaused state variable
    function setIsSignatureVerificationPaused(bool _isPaused) external {
        _requireSenderIsRole({ _role: PAUSER_ROLE });
        uint256 _contractData = StorageLib.sloadImplementationSlotDataAsUint256();
        uint256 _newContractData = _contractData.setBitWithMask({
            _bitToSet: StorageLib.IS_SIGNATURE_VERIFICATION_PAUSED_BIT_POSITION_,
            _setBitToOne: _isPaused
        });
        _newContractData.sstoreImplementationSlotDataAsUint256();
        emit SetIsSignatureVerificationPaused({ isPaused: _isPaused });
    }

    /// @notice The ```setIsTransferUpgraded``` function sets the isTransferUpgraded state variable
    /// @param _isUpgraded The new value of the isTransferUpgraded state variable
    function setIsTransferUpgraded(bool _isUpgraded) external {
        _requireSenderIsRole({ _role: ADMIN_ROLE });
        uint256 _contractData = StorageLib.sloadImplementationSlotDataAsUint256();
        uint256 _newContractData = _contractData.setBitWithMask({
            _bitToSet: StorageLib.IS_TRANSFER_UPGRADED_BIT_POSITION_,
            _setBitToOne: _isUpgraded
        });
        _newContractData.sstoreImplementationSlotDataAsUint256();
        emit SetIsTransferUpgraded({ isUpgraded: _isUpgraded });
    }

    /// @notice The ```setIsTransferFromUpgraded``` function sets the isTransferFromUpgraded state variable
    /// @param _isUpgraded The new value of the isTransferFromUpgraded state variable
    function setIsTransferFromUpgraded(bool _isUpgraded) external {
        _requireSenderIsRole({ _role: ADMIN_ROLE });
        uint256 _contractData = StorageLib.sloadImplementationSlotDataAsUint256();
        uint256 _newContractData = _contractData.setBitWithMask({
            _bitToSet: StorageLib.IS_TRANSFER_FROM_UPGRADED_BIT_POSITION_,
            _setBitToOne: _isUpgraded
        });
        _newContractData.sstoreImplementationSlotDataAsUint256();
        emit SetIsTransferFromUpgraded({ isUpgraded: _isUpgraded });
    }

    /// @notice The ```setIsTransferWithAuthorizationUpgraded``` function sets the isTransferWithAuthorizationUpgraded state variable
    /// @param _isUpgraded The new value of the isTransferWithAuthorizationUpgraded state variable
    function setIsTransferWithAuthorizationUpgraded(bool _isUpgraded) external {
        _requireSenderIsRole({ _role: ADMIN_ROLE });
        uint256 _contractData = StorageLib.sloadImplementationSlotDataAsUint256();
        uint256 _newContractData = _contractData.setBitWithMask({
            _bitToSet: StorageLib.IS_TRANSFER_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION_,
            _setBitToOne: _isUpgraded
        });
        _newContractData.sstoreImplementationSlotDataAsUint256();
        emit SetIsTransferWithAuthorizationUpgraded({ isUpgraded: _isUpgraded });
    }

    /// @notice The ```setIsReceiveWithAuthorizationUpgraded``` function sets the isReceiveWithAuthorizationUpgraded state variable
    /// @param _isUpgraded The new value of the isReceiveWithAuthorizationUpgraded state variable
    function setIsReceiveWithAuthorizationUpgraded(bool _isUpgraded) external {
        _requireSenderIsRole({ _role: ADMIN_ROLE });
        uint256 _contractData = StorageLib.sloadImplementationSlotDataAsUint256();
        uint256 _newContractData = _contractData.setBitWithMask({
            _bitToSet: StorageLib.IS_RECEIVE_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION_,
            _setBitToOne: _isUpgraded
        });
        _newContractData.sstoreImplementationSlotDataAsUint256();
        emit SetIsReceiveWithAuthorizationUpgraded({ isUpgraded: _isUpgraded });
    }

    //==============================================================================
    // Events
    //==============================================================================

    /// @notice The ```SetIsMsgSenderCheckEnabled``` event is emitted when the isMsgSenderCheckEnabled state variable is updated
    /// @param isEnabled The new value of the isMsgSenderCheckEnabled state variable
    event SetIsMsgSenderCheckEnabled(bool isEnabled);

    /// @notice The ```SetIsMintPaused``` event is emitted when the isMintPaused state variable is updated
    /// @param isPaused The new value of the isMintPaused state variable
    event SetIsMintPaused(bool isPaused);

    /// @notice The ```SetIsBurnFromPaused``` event is emitted when the isBurnFromPaused state variable is updated
    /// @param isPaused The new value of the isBurnFromPaused state variable
    event SetIsBurnFromPaused(bool isPaused);

    /// @notice The ```SetIsFreezingPaused``` event is emitted when the isFreezingPaused state variable is updated
    /// @param isPaused The new value of the isFreezingPaused state variable
    event SetIsFreezingPaused(bool isPaused);

    /// @notice The ```SetIsTransferPaused``` event is emitted when the isTransferPaused state variable is updated
    /// @param isPaused The new value of the isTransferPaused state variable
    event SetIsTransferPaused(bool isPaused);

    /// @notice The ```SetIsSignatureVerificationPaused``` event is emitted when the isSignatureVerificationPaused state variable is updated
    /// @param isPaused The new value of the isSignatureVerificationPaused state variable
    event SetIsSignatureVerificationPaused(bool isPaused);

    /// @notice The ```SetIsTransferUpgraded``` event is emitted when the isTransferUpgraded state variable is updated
    /// @param isUpgraded The new value of the isTransferUpgraded state variable
    event SetIsTransferUpgraded(bool isUpgraded);

    /// @notice The ```SetIsTransferFromUpgraded``` event is emitted when the isTransferFromUpgraded state variable is updated
    /// @param isUpgraded The new value of the isTransferFromUpgraded state variable
    event SetIsTransferFromUpgraded(bool isUpgraded);

    /// @notice The ```SetIsTransferWithAuthorizationUpgraded``` event is emitted when the isTransferWithAuthorizationUpgraded state variable is updated
    /// @param isUpgraded The new value of the isTransferWithAuthorizationUpgraded state variable
    event SetIsTransferWithAuthorizationUpgraded(bool isUpgraded);

    /// @notice The ```SetIsReceiveWithAuthorizationUpgraded``` event is emitted when the isReceiveWithAuthorizationUpgraded state variable is updated
    /// @param isUpgraded The new value of the isReceiveWithAuthorizationUpgraded state variable
    event SetIsReceiveWithAuthorizationUpgraded(bool isUpgraded);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.21;

// ====================================================================
//             _        ______     ___   _______          _
//            / \     .' ___  |  .'   `.|_   __ \        / \
//           / _ \   / .'   \_| /  .-.  \ | |__) |      / _ \
//          / ___ \  | |   ____ | |   | | |  __ /      / ___ \
//        _/ /   \ \_\ `.___]  |\  `-'  /_| |  \ \_  _/ /   \ \_
//       |____| |____|`._____.'  `.___.'|____| |___||____| |____|
// ====================================================================
// ============================= Eip3009 ==============================
// ====================================================================

import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import { SafeCastLib } from "solady/src/utils/SafeCastLib.sol";
import { SignatureCheckerLib } from "solady/src/utils/SignatureCheckerLib.sol";

import { Eip712 } from "./Eip712.sol";
import { Erc20Core } from "./Erc20Core.sol";

import { StorageLib } from "./proxy/StorageLib.sol";

/// @title Eip3009
/// @notice Eip3009 provides internal implementations for gas-abstracted transfers under Eip3009 guidelines
/// @author Agora, inspired by Circle's Eip3009 implementation
abstract contract Eip3009 is Eip712, Erc20Core {
    using SafeCastLib for uint256;
    using StorageLib for uint256;

    /// @notice keccak256("TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)")
    bytes32 internal constant TRANSFER_WITH_AUTHORIZATION_TYPEHASH_ =
        0x7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a2267;

    /// @notice keccak256("ReceiveWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)")
    bytes32 internal constant RECEIVE_WITH_AUTHORIZATION_TYPEHASH_ =
        0xd099cc98ef71107a616c4f0f941f04c322d8e254fe26b3c6668db87aae413de8;

    /// @notice keccak256("CancelAuthorization(address authorizer,bytes32 nonce)")
    bytes32 internal constant CANCEL_AUTHORIZATION_TYPEHASH_ =
        0x158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a1597429;

    //==============================================================================
    // Internal Procedural Functions
    //==============================================================================

    /// @notice The ```_transferWithAuthorization``` function executes a transfer with a signed authorization
    /// @dev EOA wallet signatures should be packed in the order of r, s, v
    /// @param _from Payer's address (Authorizer)
    /// @param _to Payee's address
    /// @param _value Amount to be transferred
    /// @param _validAfter The time after which this is valid (unix time)
    /// @param _validBefore The time before which this is valid (unix time)
    /// @param _nonce Unique nonce
    /// @param _signature Signature byte array produced by an EOA wallet or a contract wallet
    function _transferWithAuthorization(
        address _from,
        address _to,
        uint256 _value,
        uint256 _validAfter,
        uint256 _validBefore,
        bytes32 _nonce,
        bytes memory _signature
    ) internal {
        // Checks: authorization validity
        if (block.timestamp <= _validAfter) revert InvalidAuthorization();
        if (block.timestamp >= _validBefore) revert ExpiredAuthorization();
        _requireUnusedAuthorization({ _authorizer: _from, _nonce: _nonce });

        // Checks: valid signature
        _requireIsValidSignatureNow({
            _signer: _from,
            _dataHash: keccak256(
                abi.encode(TRANSFER_WITH_AUTHORIZATION_TYPEHASH_, _from, _to, _value, _validAfter, _validBefore, _nonce)
            ),
            _signature: _signature
        });

        // Effects: mark authorization as used and transfer
        _markAuthorizationAsUsed({ _authorizer: _from, _nonce: _nonce });
        _transfer({ _from: _from, _to: _to, _transferValue: _value.toUint248() });
    }

    /// @notice The ```_receiveWithAuthorization``` function receives a transfer with a signed authorization from the payer
    /// @dev This has an additional check to ensure that the payee's address matches the caller of this function to prevent front-running attacks
    /// @dev EOA wallet signatures should be packed in the order of r, s, v
    /// @param _from Payer's address (Authorizer)
    /// @param _to Payee's address
    /// @param _value Amount to be transferred
    /// @param _validAfter The block.timestamp after which the authorization is valid
    /// @param _validBefore The block.timestamp before which the authorization is valid
    /// @param _nonce Unique nonce
    /// @param _signature Signature byte array produced by an EOA wallet or a contract wallet
    function _receiveWithAuthorization(
        address _from,
        address _to,
        uint256 _value,
        uint256 _validAfter,
        uint256 _validBefore,
        bytes32 _nonce,
        bytes memory _signature
    ) internal {
        // Checks: authorization validity
        if (_to != msg.sender) revert InvalidPayee({ caller: msg.sender, payee: _to });
        if (block.timestamp <= _validAfter) revert InvalidAuthorization();
        if (block.timestamp >= _validBefore) revert ExpiredAuthorization();
        _requireUnusedAuthorization({ _authorizer: _from, _nonce: _nonce });

        // Checks: valid signature
        _requireIsValidSignatureNow({
            _signer: _from,
            _dataHash: keccak256(
                abi.encode(RECEIVE_WITH_AUTHORIZATION_TYPEHASH_, _from, _to, _value, _validAfter, _validBefore, _nonce)
            ),
            _signature: _signature
        });

        // Effects: mark authorization as used and transfer
        _markAuthorizationAsUsed({ _authorizer: _from, _nonce: _nonce });
        _transfer({ _from: _from, _to: _to, _transferValue: _value.toUint248() });
    }

    /// @notice The ```_cancelAuthorization``` function cancels an authorization
    /// @dev EOA wallet signatures should be packed in the order of r, s, v
    /// @param _authorizer Authorizer's address
    /// @param _nonce Nonce of the authorization
    /// @param _signature Signature byte array produced by an EOA wallet or a contract wallet
    function _cancelAuthorization(address _authorizer, bytes32 _nonce, bytes memory _signature) internal {
        _requireUnusedAuthorization({ _authorizer: _authorizer, _nonce: _nonce });
        _requireIsValidSignatureNow({
            _signer: _authorizer,
            _dataHash: keccak256(abi.encode(CANCEL_AUTHORIZATION_TYPEHASH_, _authorizer, _nonce)),
            _signature: _signature
        });

        StorageLib.getPointerToEip3009Storage().isAuthorizationUsed[_authorizer][_nonce] = true;
        emit AuthorizationCanceled({ authorizer: _authorizer, nonce: _nonce });
    }

    //==============================================================================
    // Internal Checks Functions
    //==============================================================================

    /// @notice The ```_requireIsValidSignatureNow``` function validates that signature against input data struct
    /// @param _signer Signer's address
    /// @param _dataHash Hash of encoded data struct
    /// @param _signature Signature byte array produced by an EOA wallet or a contract wallet
    function _requireIsValidSignatureNow(address _signer, bytes32 _dataHash, bytes memory _signature) private view {
        if (
            !SignatureCheckerLib.isValidSignatureNow({
                signer: _signer,
                hash: MessageHashUtils.toTypedDataHash({
                    domainSeparator: _domainSeparatorV4(),
                    structHash: _dataHash
                }),
                signature: _signature
            })
        ) revert InvalidSignature();
    }

    /// @notice The ```_requireUnusedAuthorization``` checks that an authorization nonce is unused
    /// @param _authorizer    Authorizer's address
    /// @param _nonce         Nonce of the authorization
    function _requireUnusedAuthorization(address _authorizer, bytes32 _nonce) private view {
        if (StorageLib.getPointerToEip3009Storage().isAuthorizationUsed[_authorizer][_nonce])
            revert UsedOrCanceledAuthorization();
    }

    //==============================================================================
    // Internal Effects Functions
    //==============================================================================

    /// @notice The ```_markAuthorizationAsUsed``` function marks an authorization nonce as used
    /// @param _authorizer    Authorizer's address
    /// @param _nonce         Nonce of the authorization
    function _markAuthorizationAsUsed(address _authorizer, bytes32 _nonce) private {
        StorageLib.getPointerToEip3009Storage().isAuthorizationUsed[_authorizer][_nonce] = true;
        emit AuthorizationUsed({ authorizer: _authorizer, nonce: _nonce });
    }

    //==============================================================================
    // Events
    //==============================================================================

    /// @notice ```AuthorizationUsed``` event is emitted when an authorization is used
    /// @param authorizer Authorizer's address
    /// @param nonce Nonce of the authorization
    event AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce);

    /// @notice ```AuthorizationCanceled``` event is emitted when an authorization is canceled
    /// @param authorizer Authorizer's address
    /// @param nonce Nonce of the authorization
    event AuthorizationCanceled(address indexed authorizer, bytes32 indexed nonce);

    //==============================================================================
    // Errors
    //==============================================================================

    /// @notice The ```InvalidPayee``` error is emitted when the payee does not match sender in receiveWithAuthorization
    /// @param caller The caller of the function
    /// @param payee The expected payee in the function
    error InvalidPayee(address caller, address payee);

    /// @notice The ```InvalidAuthorization``` error is emitted when the authorization is invalid because its too early
    error InvalidAuthorization();

    /// @notice The ```ExpiredAuthorization``` error is emitted when the authorization is expired
    error ExpiredAuthorization();

    /// @notice The ```InvalidSignature``` error is emitted when the signature is invalid
    error InvalidSignature();

    /// @notice The ```UsedOrCanceledAuthorization``` error is emitted when the authorization nonce is already used or canceled
    error UsedOrCanceledAuthorization();
}

// SPDX-License-Identifier: Apache-2.0

// ***NOTE***: This file has been modified to remove external functions and storage for use in a transparent-ish proxy
// ***NOTE***: Modified from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/dbb6104ce834628e473d2173bbc9d47f81a9eec3/contracts/utils/cryptography/EIP712.sol

pragma solidity 0.8.21;

// ====================================================================
//             _        ______     ___   _______          _
//            / \     .' ___  |  .'   `.|_   __ \        / \
//           / _ \   / .'   \_| /  .-.  \ | |__) |      / _ \
//          / ___ \  | |   ____ | |   | | |  __ /      / ___ \
//        _/ /   \ \_\ `.___]  |\  `-'  /_| |  \ \_  _/ /   \ \_
//       |____| |____|`._____.'  `.___.'|____| |___||____| |____|
// ====================================================================
// ============================= Eip712 ===============================
// ====================================================================

import { ShortString, ShortStrings } from "@openzeppelin/contracts/utils/ShortStrings.sol";
import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
 * encoding is very generic and therefore its 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 order to
 * produce the hash of their typed data 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].
 *
 */

/// @title Eip712
/// @author Agora, modified from OpenZeppelin implementation
abstract contract Eip712 {
    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;

    /**
     * @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.
     */
    constructor(string memory name, string memory version, address expectedProxyAddress) {
        _name = name.toShortString();
        _version = version.toShortString();
        _hashedName = keccak256(bytes(name));
        _hashedVersion = keccak256(bytes(version));

        _cachedChainId = block.chainid;
        _cachedDomainSeparator = keccak256(
            abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, expectedProxyAddress)
        );
        _cachedThis = expectedProxyAddress;
    }

    /// @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 returns (bytes32) {
        return MessageHashUtils.toTypedDataHash({ domainSeparator: _domainSeparatorV4(), structHash: structHash });
    }

    /**
     * @dev The name parameter for the Eip712 domain.
     *
     * NOTE: By default this function reads _name which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _Eip712Name() internal view returns (string memory) {
        return _name.toString();
    }

    /**
     * @dev The version parameter for the Eip712 domain.
     *
     * NOTE: By default this function reads _version which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _Eip712Version() internal view returns (string memory) {
        return _version.toString();
    }
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.21;

// ====================================================================
//             _        ______     ___   _______          _
//            / \     .' ___  |  .'   `.|_   __ \        / \
//           / _ \   / .'   \_| /  .-.  \ | |__) |      / _ \
//          / ___ \  | |   ____ | |   | | |  __ /      / ___ \
//        _/ /   \ \_\ `.___]  |\  `-'  /_| |  \ \_  _/ /   \ \_
//       |____| |____|`._____.'  `.___.'|____| |___||____| |____|
// ====================================================================
// ============================ Erc20Core =============================
// ====================================================================

import { IERC20Errors as IErc20Errors } from "@openzeppelin/contracts/interfaces/draft-IErc6093.sol";
import { SafeCastLib } from "solady/src/utils/SafeCastLib.sol";

import { StorageLib } from "./proxy/StorageLib.sol";

/// @notice The ```Erc20Core``` contract is a base contract for the Erc20 standard
/// @title Erc20Core
/// @author Agora
abstract contract Erc20Core is IErc20Errors {
    using StorageLib for uint256;
    using SafeCastLib for uint256;

    //==============================================================================
    // Internal Procedural Functions
    //==============================================================================

    /// The ```_approve``` function is used to approve a spender to spend a certain amount of tokens on behalf of the caller
    /// @dev This function reverts on failure
    /// @param _spender The address of the spender
    /// @param _value The amount of tokens to approve for spending
    function _approve(address _owner, address _spender, uint256 _value) internal {
        StorageLib.getPointerToErc20CoreStorage().accountAllowances[_owner][_spender] = _value;
        emit Approval({ owner: _owner, spender: _spender, value: _value });
    }

    /// @notice The ```_transfer``` function transfers tokens which belong to the caller
    /// @dev This function reverts on failure
    /// @param _to The address of the recipient
    /// @param _transferValue The amount of tokens to transfer
    function _transfer(address _from, address _to, uint248 _transferValue) internal {
        // Checks: Ensure _from address is not frozen
        StorageLib.Erc20AccountData memory _accountDataFrom = StorageLib.getPointerToErc20CoreStorage().accountData[
            _from
        ];
        if (_accountDataFrom.isFrozen) revert AccountIsFrozen({ frozenAccount: _from });

        // Checks: Ensure _from has enough balance
        if (_accountDataFrom.balance < _transferValue)
            revert ERC20InsufficientBalance({
                sender: _from,
                balance: _accountDataFrom.balance,
                needed: _transferValue
            });

        // Effects: update balances on the _from account
        unchecked {
            // Underflow not possible: _transferValue <= fromBalance asserted above
            StorageLib.getPointerToErc20CoreStorage().accountData[_from].balance =
                _accountDataFrom.balance -
                _transferValue;
        }

        // NOTE: typically checks are done before effects, but in this case we need to handle the case where _to == _from and so we want to read the latest values
        // Checks: Ensure _to address is not frozen
        StorageLib.Erc20AccountData memory _accountDataTo = StorageLib.getPointerToErc20CoreStorage().accountData[_to];
        if (_accountDataTo.isFrozen) revert AccountIsFrozen({ frozenAccount: _to });

        // Effects: update balances on the _to account
        unchecked {
            // Overflow not possible: _transferValue + toBalance <= (2^248 -1) x 10^-6 [more money than atoms in the galaxy]
            StorageLib.getPointerToErc20CoreStorage().accountData[_to].balance =
                _accountDataTo.balance +
                _transferValue;
        }

        emit Transfer({ from: _from, to: _to, value: _transferValue });
    }

    /// @notice The ```_spendAllowance``` function decrements a spenders allowance
    /// @dev Treats type(uint256).max as infinite allowance and does not update balance
    /// @param _owner The address of the owner
    /// @param _spender The address of the spender
    /// @param _value The amount of allowance to decrement
    function _spendAllowance(address _owner, address _spender, uint256 _value) internal {
        uint256 _currentAllowance = StorageLib.getPointerToErc20CoreStorage().accountAllowances[_owner][_spender];

        // We treat uint256.max as infinite allowance, so we don't need to read/write storage in that case
        if (_currentAllowance != type(uint256).max) {
            if (_currentAllowance < _value)
                revert ERC20InsufficientAllowance({ spender: _spender, allowance: _currentAllowance, needed: _value });
            unchecked {
                StorageLib.getPointerToErc20CoreStorage().accountAllowances[_owner][_spender] =
                    _currentAllowance -
                    _value;
            }
        }
    }

    //==============================================================================
    // Events
    //==============================================================================

    /// @notice The ```Transfer``` event is emitted when tokens are transferred from one account to another
    /// @param from The account that is transferring tokens
    /// @param to The account that is receiving tokens
    /// @param value The amount of tokens being transferred
    event Transfer(address indexed from, address indexed to, uint256 value);

    /// @notice ```Approval``` emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}
    /// @param owner The account that is allowing the spender to spend
    /// @param spender The account that is allowed to spend
    /// @param value The amount of funds that the spender is allowed to spend
    event Approval(address indexed owner, address indexed spender, uint256 value);

    //==============================================================================
    // Errors
    //==============================================================================

    /// @notice ```AccountIsFrozen``` error is emitted when an account is frozen and a transfer is attempted
    /// @param frozenAccount The account that is frozen
    error AccountIsFrozen(address frozenAccount);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.21;

// ====================================================================
//             _        ______     ___   _______          _
//            / \     .' ___  |  .'   `.|_   __ \        / \
//           / _ \   / .'   \_| /  .-.  \ | |__) |      / _ \
//          / ___ \  | |   ____ | |   | | |  __ /      / ___ \
//        _/ /   \ \_\ `.___]  |\  `-'  /_| |  \ \_  _/ /   \ \_
//       |____| |____|`._____.'  `.___.'|____| |___||____| |____|
// ====================================================================
// ========================= Erc20Privileged ==========================
// ====================================================================

import { SafeCastLib } from "solady/src/utils/SafeCastLib.sol";

import { AgoraDollarAccessControl } from "./AgoraDollarAccessControl.sol";
import { Erc20Core } from "./Erc20Core.sol";

import { StorageLib } from "./proxy/StorageLib.sol";

/// @notice The ```Erc20Privileged``` contract extends the ```Erc20Core``` contract with privileged actions (mint, burn, freeze)
abstract contract Erc20Privileged is Erc20Core, AgoraDollarAccessControl {
    using SafeCastLib for uint256;
    using StorageLib for uint256;

    //==============================================================================
    // Mint Functions
    //==============================================================================

    /// @notice Parameters for a single mint operation
    /// @param receiverAddress The address to mint tokens to
    /// @param value The amount of tokens to mint
    struct BatchMintParam {
        address receiverAddress;
        uint256 value;
    }

    /// @notice The ```batchMint``` function mints tokens to multiple accounts in a single transaction
    /// @dev This function must be called by an address to which the MINTER_ROLE is granted
    /// @dev Reverts on failure
    /// @param _mints An array of ```BatchMintParam``` structs
    function batchMint(BatchMintParam[] memory _mints) external {
        // Checks: sender must be minter
        _requireSenderIsRole({ _role: MINTER_ROLE });

        // Checks: minting must not be paused
        if (StorageLib.sloadImplementationSlotDataAsUint256().isMintPaused()) revert StorageLib.MintPaused();

        // Effects: add to totalSupply and account balances
        for (uint256 i = 0; i < _mints.length; i++) {
            // Checks: account cannot be 0 address
            if (_mints[i].receiverAddress == address(0)) revert ERC20InvalidReceiver({ receiver: address(0) });

            // Effects: add to totalSupply and account balance
            uint248 _value248 = _mints[i].value.toUint248();
            StorageLib.getPointerToErc20CoreStorage().totalSupply += _value248;
            StorageLib.getPointerToErc20CoreStorage().accountData[_mints[i].receiverAddress].balance += _value248;

            // Emit event
            emit Transfer({ from: address(0), to: _mints[i].receiverAddress, value: _mints[i].value });
            emit Minted({ receiver: _mints[i].receiverAddress, value: _mints[i].value });
        }
    }

    //==============================================================================
    // Burn Functions
    //==============================================================================

    /// @notice Parameters for a single burn operation
    /// @param burnFromAddress The address to burn tokens from
    /// @param value The amount of tokens to burn
    struct BatchBurnFromParam {
        address burnFromAddress;
        uint256 value;
    }

    /// @notice The ```batchBurnFrom``` function burns tokens from multiple accounts in a single transaction
    /// @dev This function must be called by an address to which the BURNER_ROLE is granted
    /// @dev Reverts on failure
    /// @param _burns An array of ```BatchBurnFromParam``` structs
    function batchBurnFrom(BatchBurnFromParam[] memory _burns) external {
        // Checks: sender must be burner
        _requireSenderIsRole({ _role: BURNER_ROLE });

        // Checks: burnFrom must not be paused
        if (StorageLib.sloadImplementationSlotDataAsUint256().isBurnFromPaused()) revert StorageLib.BurnFromPaused();

        for (uint256 i = 0; i < _burns.length; i++) {
            // Effects: subtract from totalSupply and account balance
            uint248 _value248 = _burns[i].value.toUint248();
            StorageLib.getPointerToErc20CoreStorage().totalSupply -= _value248;
            StorageLib.getPointerToErc20CoreStorage().accountData[_burns[i].burnFromAddress].balance -= _value248;

            // emit event (include Burned event to prevent spoofing of Transfer event as we don't check for 0 address in transfer)
            emit Transfer({ from: _burns[i].burnFromAddress, to: address(0), value: _burns[i].value });
            emit Burned({ burnFrom: _burns[i].burnFromAddress, value: _burns[i].value });
        }
    }

    //==============================================================================
    // Freeze Functions
    //==============================================================================

    /// @notice The ```freeze``` function freezes an account so that it cannot transfer tokens
    /// @param _account The account to freeze
    function freeze(address _account) external {
        _requireSenderIsRole({ _role: FREEZER_ROLE });
        if (StorageLib.sloadImplementationSlotDataAsUint256().isFreezingPaused()) revert StorageLib.FreezingPaused();

        StorageLib.getPointerToErc20CoreStorage().accountData[_account].isFrozen = true;
        emit AccountFrozen({ account: _account });
    }

    /// @notice The ```unfreeze``` function unfreezes an account so that it can transfer tokens again
    /// @param _account The account to unfreeze
    function unfreeze(address _account) external {
        _requireSenderIsRole({ _role: FREEZER_ROLE });
        if (StorageLib.sloadImplementationSlotDataAsUint256().isFreezingPaused()) revert StorageLib.FreezingPaused();

        StorageLib.getPointerToErc20CoreStorage().accountData[_account].isFrozen = false;
        emit AccountUnfrozen({ account: _account });
    }

    //==============================================================================
    // Events
    //==============================================================================

    /// @notice The ```AccountUnfrozen``` event is emitted when an account is unfrozen
    /// @param account The account that was unfrozen
    event AccountUnfrozen(address indexed account);

    /// @notice The ```AccountFrozen``` event is emitted when an account is frozen
    /// @param account The account that was frozen
    event AccountFrozen(address indexed account);

    /// @notice The ```Minted``` event is emitted when tokens are minted
    /// @param receiver The account that received the minted tokens
    /// @param value The amount of tokens minted
    event Minted(address indexed receiver, uint256 value);

    /// @notice The ```Burned``` event is emitted when tokens are burned
    /// @param burnFrom The account that burned the tokens
    /// @param value The amount of tokens burned
    event Burned(address indexed burnFrom, uint256 value);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.21;

// ====================================================================
//             _        ______     ___   _______          _
//            / \     .' ___  |  .'   `.|_   __ \        / \
//           / _ \   / .'   \_| /  .-.  \ | |__) |      / _ \
//          / ___ \  | |   ____ | |   | | |  __ /      / ___ \
//        _/ /   \ \_\ `.___]  |\  `-'  /_| |  \ \_  _/ /   \ \_
//       |____| |____|`._____.'  `.___.'|____| |___||____| |____|
// ====================================================================
// ============================= Erc2612 ==============================
// ====================================================================

import { SignatureCheckerLib } from "solady/src/utils/SignatureCheckerLib.sol";

import { Eip712 } from "./Eip712.sol";
import { Erc20Core } from "./Erc20Core.sol";

import { StorageLib } from "./proxy/StorageLib.sol";

abstract contract Erc2612 is Eip712, Erc20Core {
    using StorageLib for uint256;

    /// @notice The ```PERMIT_TYPEHASH``` stores keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")
    bytes32 public constant PERMIT_TYPEHASH =
        keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

    //==============================================================================
    // External Procedural Functions
    //==============================================================================

    /// @notice The ```permit``` function sets an allowance with a signature
    /// @param _owner The account that signed the message
    /// @param _spender The account that is allowed to spend the funds
    /// @param _value The amount of funds that can be spent
    /// @param _deadline The time by which the transaction must be completed
    /// @param _v The v of the ECDSA signature
    /// @param _r The r of the ECDSA signature
    /// @param _s The s of the ECDSA signature
    function permit(
        address _owner,
        address _spender,
        uint256 _value,
        uint256 _deadline,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) external {
        permit({
            _owner: _owner,
            _spender: _spender,
            _value: _value,
            _deadline: _deadline,
            _signature: abi.encodePacked(_r, _s, _v)
        });
    }
    /// @notice The ```permit``` function sets an allowance with a signature
    /// @param _owner The account that signed the message
    /// @param _spender The account that is allowed to spend the funds
    /// @param _value The amount of funds that can be spent
    /// @param _deadline The time by which the transaction must be completed
    /// @param _signature The signature of the message

    function permit(
        address _owner,
        address _spender,
        uint256 _value,
        uint256 _deadline,
        bytes memory _signature
    ) public {
        // Checks: contract-wide access control
        bool _isSignatureVerificationPaused = StorageLib
            .sloadImplementationSlotDataAsUint256()
            .isSignatureVerificationPaused();
        if (_isSignatureVerificationPaused) revert StorageLib.SignatureVerificationPaused();

        // Checks: deadline
        if (block.timestamp > _deadline) revert Erc2612ExpiredSignature({ deadline: _deadline });

        // Effects: increment nonce
        uint256 _nextNonce;
        unchecked {
            _nextNonce = StorageLib.getPointerToErc2612Storage().nonces[_owner]++;
        }
        bytes32 _structHash = keccak256(abi.encode(PERMIT_TYPEHASH, _owner, _spender, _value, _nextNonce, _deadline));

        bytes32 _hash = _hashTypedDataV4({ structHash: _structHash });

        // Checks: is valid eoa or eip1271 signature
        bool _isValidSignature = SignatureCheckerLib.isValidSignatureNow({
            signer: _owner,
            hash: _hash,
            signature: _signature
        });
        if (!_isValidSignature) revert Erc2612InvalidSignature();

        // Effects: update bookkeeping
        _approve({ _owner: _owner, _spender: _spender, _value: _value });
    }

    /// @notice The ```DOMAIN_SEPARATOR``` function returns the configured domain separator
    /// @return _domainSeparator The domain separator
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32 _domainSeparator) {
        _domainSeparator = _domainSeparatorV4();
    }

    //==============================================================================
    // Errors
    //==============================================================================

    /// @notice The ```Erc2612ExpiredSignature``` error is emitted when the signature is expired
    /// @param deadline the time by which the transaction must be completed
    error Erc2612ExpiredSignature(uint256 deadline);

    /// @notice The ```Erc2612InvalidSignature``` error is emitted when the signature is invalid
    error Erc2612InvalidSignature();
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.21;

// ====================================================================
//             _        ______     ___   _______          _
//            / \     .' ___  |  .'   `.|_   __ \        / \
//           / _ \   / .'   \_| /  .-.  \ | |__) |      / _ \
//          / ___ \  | |   ____ | |   | | |  __ /      / ___ \
//        _/ /   \ \_\ `.___]  |\  `-'  /_| |  \ \_  _/ /   \ \_
//       |____| |____|`._____.'  `.___.'|____| |___||____| |____|
// ====================================================================
// ============================ StorageLib ============================
// ====================================================================

/**
 * This library contains information for accessing unstructured storage following erc1967
 * and erc7201 standards.
 *
 * The erc1967 storage slots are defined using their own formula/namespace.
 * These are listed last in the contract.
 *
 * The erc7201 namespace is defined as <ContractName>.<Namespace>
 * The deriveErc7201StorageSlot() function is used to derive the storage slot for a given namespace
 * and to check that value against the hard-coded bytes32 value for the slot location in testing frameworks
 * Each inherited contract has its own struct of the form <ContractName>Storage which matches <Namespace>
 * from above. Each struct is held in a unique namespace and has a unique storage slot.
 * See: https://eips.ethereum.org/EIPS/eip-7201 for additional information regarding this standard
 */
/// @title StorageLib
/// @dev Implements pure functions for calculating and accessing storage slots according to eip1967 and eip7201
/// @author Agora
library StorageLib {
    /// @notice Global namespace for use in deriving storage slot locations
    string internal constant GLOBAL_ERC7201_NAMESPACE = "AgoraDollarErc1967Proxy";

    // Use this function to check hardcoded bytes32 values against the expected formula
    function deriveErc7201StorageSlot(string memory _localNamespace) internal pure returns (bytes32) {
        bytes memory _namespace = abi.encodePacked(GLOBAL_ERC7201_NAMESPACE, ".", _localNamespace);
        return keccak256(abi.encode(uint256(keccak256(_namespace)) - 1)) & ~bytes32(uint256(0xff));
    }

    //==============================================================================
    // Eip3009 Storage Items
    //==============================================================================

    /// @notice The EIP3009 namespace
    string internal constant EIP3009_NAMESPACE = "Eip3009Storage";

    /// @notice The Eip3009Storage struct
    /// @param isAuthorizationUsed A mapping of authorizer to nonce to boolean to indicate if the nonce has been used
    /// @custom:storage-location erc7201:AgoraDollarErc1967Proxy.Eip3009Storage
    struct Eip3009Storage {
        mapping(address _authorizer => mapping(bytes32 _nonce => bool _isNonceUsed)) isAuthorizationUsed;
    }

    /// @notice The ```EIP3009_STORAGE_SLOT_``` is the storage slot for the Eip3009Storage struct
    /// @dev keccak256(abi.encode(uint256(keccak256("AgoraDollarErc1967Proxy.Eip3009Storage")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 internal constant EIP3009_STORAGE_SLOT_ =
        0xbb0a37da742be2e3b68bdb11d195150f4243c03fb37d3cdfa756046082a38600;

    /// @notice The ```getPointerToEip3009Storage``` function returns a pointer to the Eip3009Storage struct
    /// @return $ A pointer to the Eip3009Storage struct
    function getPointerToEip3009Storage() internal pure returns (Eip3009Storage storage $) {
        /// @solidity memory-safe-assembly
        assembly {
            $.slot := EIP3009_STORAGE_SLOT_
        }
    }

    //==============================================================================
    // Erc2612 Storage Items
    //==============================================================================

    /// @notice The Erc2612 namespace
    string internal constant ERC2612_NAMESPACE = "Erc2612Storage";

    /// @notice The Erc2612Storage struct
    /// @param nonces A mapping of signer address to uint256 to store the nonce
    /// @custom:storage-location erc7201:AgoraDollarErc1967Proxy.Erc2612Storage
    struct Erc2612Storage {
        mapping(address _signer => uint256 _nonce) nonces;
    }

    /// @notice The ```ERC2612_STORAGE_SLOT_``` is the storage slot for the Erc2612Storage struct
    /// @dev keccak256(abi.encode(uint256(keccak256("AgoraDollarErc1967Proxy.Erc2612Storage")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 internal constant ERC2612_STORAGE_SLOT_ =
        0x69e87f5b9323740fce20cdf574dacd1d10e756da64a1f2df70fd1ace4c7cc300;

    /// @notice The ```getPointerToErc2612Storage``` function returns a pointer to the Erc2612Storage struct
    /// @return $ A pointer to the Erc2612Storage struct
    function getPointerToErc2612Storage() internal pure returns (Erc2612Storage storage $) {
        /// @solidity memory-safe-assembly
        assembly {
            $.slot := ERC2612_STORAGE_SLOT_
        }
    }

    //==============================================================================
    // Erc20Core Storage Items
    //==============================================================================

    /// @notice The Erc20Core namespace
    string internal constant ERC20_CORE_NAMESPACE = "Erc20CoreStorage";

    /// @notice The Erc20AccountData struct
    /// @param isFrozen A boolean to indicate if the account is frozen
    /// @param balance A uint248 to store the balance of the account
    struct Erc20AccountData {
        bool isFrozen;
        uint248 balance;
    }

    /// @notice The Erc20CoreStorage struct
    /// @param accountData A mapping of address to Erc20AccountData to store account data
    /// @param accountAllowances A mapping of owner to spender to uint256 to store the allowance
    /// @param totalSupply A uint256 to store the total supply of tokens
    /// @custom:storage-location erc7201:AgoraDollarErc1967Proxy.Erc20CoreStorage
    struct Erc20CoreStorage {
        /// @dev _account The account whose data we are accessing
        /// @dev _accountData The account data for the account
        mapping(address _account => Erc20AccountData _accountData) accountData;
        /// @dev _owner The owner of the tokens
        /// @dev _spender The spender of the tokens
        /// @dev _accountAllowance The allowance of the spender
        mapping(address _owner => mapping(address _spender => uint256 _accountAllowance)) accountAllowances;
        /// @dev The total supply of tokens
        uint256 totalSupply;
    }

    /// @notice The ```ERC20_CORE_STORAGE_SLOT_``` is the storage slot for the Erc20CoreStorage struct
    /// @dev keccak256(abi.encode(uint256(keccak256("AgoraDollarErc1967Proxy.Erc20CoreStorage")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 internal constant ERC20_CORE_STORAGE_SLOT_ =
        0x455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b700;

    /// @notice The ```getPointerToErc20CoreStorage``` function returns a pointer to the Erc20CoreStorage struct
    /// @return $ A pointer to the Erc20CoreStorage struct
    function getPointerToErc20CoreStorage() internal pure returns (Erc20CoreStorage storage $) {
        /// @solidity memory-safe-assembly
        assembly {
            $.slot := ERC20_CORE_STORAGE_SLOT_
        }
    }

    //==============================================================================
    // AgoraDollarAccessControl Storage Items
    //==============================================================================

    /// @notice The AgoraDollarAccessControl namespace
    string internal constant AGORA_DOLLAR_ACCESS_CONTROL_NAMESPACE = "AgoraDollarAccessControlStorage";

    /// @notice The RoleData struct
    /// @param pendingRoleAddress The address of the nominated (pending) role
    /// @param currentRoleAddress The address of the current role
    struct AgoraDollarAccessControlRoleData {
        address pendingRoleAddress;
        address currentRoleAddress;
    }

    /// @notice The AgoraDollarAccessControlStorage struct
    /// @param roleData A mapping of role identifier to AgoraDollarAccessControlRoleData to store role data
    /// @custom:storage-location erc7201:AgoraDollarErc1967Proxy.AgoraDollarAccessControlStorage
    struct AgoraDollarAccessControlStorage {
        mapping(bytes32 _role => AgoraDollarAccessControlRoleData _roleData) roleData;
    }

    /// @notice The ```AGORA_DOLLAR_ACCESS_CONTROL_STORAGE_SLOT_``` is the storage slot for the AgoraDollarAccessControlStorage struct
    /// @dev keccak256(abi.encode(uint256(keccak256("AgoraDollarErc1967Proxy.AgoraDollarAccessControlStorage")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 internal constant AGORA_DOLLAR_ACCESS_CONTROL_STORAGE_SLOT_ =
        0x9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe700;

    /// @notice The ```getPointerToAgoraDollarAccessControlStorage``` function returns a pointer to the AgoraDollarAccessControlStorage struct
    /// @return $ A pointer to the AgoraDollarAccessControlStorage struct
    function getPointerToAgoraDollarAccessControlStorage()
        internal
        pure
        returns (AgoraDollarAccessControlStorage storage $)
    {
        /// @solidity memory-safe-assembly
        assembly {
            $.slot := AGORA_DOLLAR_ACCESS_CONTROL_STORAGE_SLOT_
        }
    }

    //==============================================================================
    // AgoraDollarErc1967 Admin Slot Items
    //==============================================================================

    /// @notice The AgoraDollarErc1967ProxyAdminStorage struct
    /// @param proxyAdminAddress The address of the proxy admin contract
    /// @custom:storage-location erc1967:eip1967.proxy.admin
    struct AgoraDollarErc1967ProxyAdminStorage {
        address proxyAdminAddress;
    }

    /// @notice The ```AGORA_DOLLAR_ERC1967_PROXY_ADMIN_STORAGE_SLOT_``` is the storage slot for the AgoraDollarErc1967ProxyAdminStorage struct
    /// @dev NOTE: deviates from erc7201 standard because erc1967 defines its own storage slot algorithm
    /// @dev bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1)
    bytes32 internal constant AGORA_DOLLAR_ERC1967_PROXY_ADMIN_STORAGE_SLOT_ =
        0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /// @notice The ```getPointerToAgoraDollarErc1967ProxyAdminStorage``` function returns a pointer to the AgoraDollarErc1967ProxyAdminStorage struct
    /// @return adminSlot A pointer to the AgoraDollarErc1967ProxyAdminStorage struct
    function getPointerToAgoraDollarErc1967ProxyAdminStorage()
        internal
        pure
        returns (AgoraDollarErc1967ProxyAdminStorage storage adminSlot)
    {
        /// @solidity memory-safe-assembly
        assembly {
            adminSlot.slot := AGORA_DOLLAR_ERC1967_PROXY_ADMIN_STORAGE_SLOT_
        }
    }

    //==============================================================================
    // AgoraDollarErc1967Proxy Implementation Slot Items
    //==============================================================================

    /// @notice The AgoraDollarErc1967ProxyContractStorage struct
    /// @param implementationAddress The address of the implementation contract
    /// @param placeholder A placeholder for bits to be used as bitmask items
    /// @custom:storage-location erc1967:eip1967.proxy.implementation
    struct AgoraDollarErc1967ProxyContractStorage {
        address implementationAddress; // least significant bits first
        uint96 placeholder; // Placeholder for bitmask items defined below
    }

    /// @notice The ```AGORA_DOLLAR_ERC1967_PROXY_CONTRACT_STORAGE_SLOT_``` is the storage slot for the AgoraDollarErc1967ProxyContractStorage struct
    /// @dev bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)
    bytes32 internal constant AGORA_DOLLAR_ERC1967_PROXY_CONTRACT_STORAGE_SLOT_ =
        0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /// @notice The ```getPointerToAgoraDollarErc1967ProxyContractStorage``` function returns a pointer to the storage slot for the implementation address
    /// @return contractData A pointer to the data in the storage slot for the implementation address and other contract data
    function getPointerToAgoraDollarErc1967ProxyContractStorage()
        internal
        pure
        returns (AgoraDollarErc1967ProxyContractStorage storage contractData)
    {
        /// @solidity memory-safe-assembly
        assembly {
            contractData.slot := AGORA_DOLLAR_ERC1967_PROXY_CONTRACT_STORAGE_SLOT_
        }
    }

    /// @notice The ```sloadImplementationSlotDataAsUint256``` function returns the data at the implementation slot as a uint256
    /// @dev Named this way to draw attention to the sload call
    /// @return _contractData The data at the implementation slot as a uint256
    function sloadImplementationSlotDataAsUint256() internal view returns (uint256 _contractData) {
        /// @solidity memory-safe-assembly
        assembly {
            _contractData := sload(AGORA_DOLLAR_ERC1967_PROXY_CONTRACT_STORAGE_SLOT_)
        }
    }

    /// @notice The ```sstoreImplementationSlotDataAsUint256``` function stores the data at the implementation slot
    /// @dev Named this way to draw attention to the sstore call
    /// @param _contractData The data to store at the implementation slot, given as a uint256
    function sstoreImplementationSlotDataAsUint256(uint256 _contractData) internal {
        /// @solidity memory-safe-assembly
        assembly {
            sstore(AGORA_DOLLAR_ERC1967_PROXY_CONTRACT_STORAGE_SLOT_, _contractData)
        }
    }

    // Contract Access Control masks
    uint256 internal constant IS_MSG_SENDER_FROZEN_CHECK_ENABLED_BIT_POSITION_ = 1 << (255 - 95);
    uint256 internal constant IS_MINT_PAUSED_BIT_POSITION_ = 1 << (255 - 94);
    uint256 internal constant IS_BURN_FROM_PAUSED_BIT_POSITION_ = 1 << (255 - 93);
    uint256 internal constant IS_FREEZING_PAUSED_BIT_POSITION_ = 1 << (255 - 92);
    uint256 internal constant IS_TRANSFER_PAUSED_BIT_POSITION_ = 1 << (255 - 91);
    uint256 internal constant IS_SIGNATURE_VERIFICATION_PAUSED_BIT_POSITION_ = 1 << (255 - 90);

    // internal function upgrade masks
    // Erc20
    uint256 internal constant IS_TRANSFER_UPGRADED_BIT_POSITION_ = 1 << (255 - 89);
    uint256 internal constant IS_TRANSFER_FROM_UPGRADED_BIT_POSITION_ = 1 << (255 - 88);

    // Eip 3009
    uint256 internal constant IS_TRANSFER_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION_ = 1 << (255 - 87);
    uint256 internal constant IS_RECEIVE_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION_ = 1 << (255 - 86);

    //==============================================================================
    // Bitmask Functions
    //==============================================================================

    // These function use a bitmask to check if a specific bit is set in the contract data
    function isMsgSenderFrozenCheckEnabled(uint256 _contractData) internal pure returns (bool) {
        return _contractData & IS_MSG_SENDER_FROZEN_CHECK_ENABLED_BIT_POSITION_ != 0;
    }

    function isMintPaused(uint256 _contractData) internal pure returns (bool) {
        return _contractData & IS_MINT_PAUSED_BIT_POSITION_ != 0;
    }

    function isBurnFromPaused(uint256 _contractData) internal pure returns (bool) {
        return _contractData & IS_BURN_FROM_PAUSED_BIT_POSITION_ != 0;
    }

    function isFreezingPaused(uint256 _contractData) internal pure returns (bool) {
        return _contractData & IS_FREEZING_PAUSED_BIT_POSITION_ != 0;
    }

    function isTransferPaused(uint256 _contractData) internal pure returns (bool) {
        return _contractData & IS_TRANSFER_PAUSED_BIT_POSITION_ != 0;
    }

    function isSignatureVerificationPaused(uint256 _contractData) internal pure returns (bool) {
        return _contractData & IS_SIGNATURE_VERIFICATION_PAUSED_BIT_POSITION_ != 0;
    }

    function isTransferUpgraded(uint256 _contractData) internal pure returns (bool) {
        return _contractData & IS_TRANSFER_UPGRADED_BIT_POSITION_ != 0;
    }

    function isTransferFromUpgraded(uint256 _contractData) internal pure returns (bool) {
        return _contractData & IS_TRANSFER_FROM_UPGRADED_BIT_POSITION_ != 0;
    }

    function isTransferWithAuthorizationUpgraded(uint256 _contractData) internal pure returns (bool) {
        return _contractData & IS_TRANSFER_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION_ != 0;
    }

    function isReceiveWithAuthorizationUpgraded(uint256 _contractData) internal pure returns (bool) {
        return _contractData & IS_RECEIVE_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION_ != 0;
    }

    function implementation(uint256 _contractData) internal pure returns (address) {
        // return least significant 160 bits and cast to an address
        return address(uint160(_contractData));
    }

    function setBitWithMask(
        uint256 _original,
        uint256 _bitToSet,
        bool _setBitToOne
    ) internal pure returns (uint256 _new) {
        // Sets the specified bit to 1 or 0
        _new = _setBitToOne ? _original | _bitToSet : _original & ~_bitToSet;
    }

    //==============================================================================
    // Errors
    //==============================================================================

    /// @notice The ```TransferPaused``` error is emitted when transfers are paused during an attempted transfer
    error TransferPaused();

    /// @notice The ```SignatureVerificationPaused``` error is emitted when signature verification is paused during an attempted transfer
    error SignatureVerificationPaused();

    /// @notice The ```MintPaused``` error is emitted when minting is paused during an attempted mint
    error MintPaused();

    /// @notice The ```BurnFromPaused``` error is emitted when burning is paused during an attempted burn
    error BurnFromPaused();

    /// @notice The ```FreezingPaused``` error is emitted when freezing is paused during an attempted call to freeze() or unfreeze()
    error FreezingPaused();
}

Settings
{
  "evmVersion": "shanghai",
  "libraries": {},
  "metadata": {
    "appendCBOR": false,
    "bytecodeHash": "none",
    "useLiteralContent": false
  },
  "optimizer": {
    "enabled": true,
    "runs": 100000000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "remappings": [
    "contracts/=src/contracts/",
    "interfaces/=src/contracts/interfaces/",
    "forge-std/=node_modules/forge-std/src/",
    "ds-test/=node_modules/ds-test/src/",
    "agora-std/=lib/agora-standard-solidity/src/",
    "@chainlink/=lib/agora-standard-solidity/node_modules/@chainlink/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "agora-standard-solidity/=lib/agora-standard-solidity/src/",
    "createx/=node_modules/createx/",
    "openzeppelin/=node_modules/createx/lib/openzeppelin-contracts/contracts/",
    "solady/=node_modules/solady/",
    "solidity-bytes-utils/=lib/agora-standard-solidity/node_modules/solidity-bytes-utils/"
  ],
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"eip712Name","type":"string"},{"internalType":"string","name":"eip712Version","type":"string"},{"internalType":"address","name":"proxyAddress","type":"address"}],"internalType":"struct ConstructorParams","name":"_params","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"frozenAccount","type":"address"}],"name":"AccountIsFrozen","type":"error"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"AddressIsNotPendingRole","type":"error"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"AddressIsNotRole","type":"error"},{"inputs":[],"name":"BurnFromPaused","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"Erc2612ExpiredSignature","type":"error"},{"inputs":[],"name":"Erc2612InvalidSignature","type":"error"},{"inputs":[],"name":"ExpiredAuthorization","type":"error"},{"inputs":[],"name":"FreezingPaused","type":"error"},{"inputs":[],"name":"InvalidAuthorization","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"payee","type":"address"}],"name":"InvalidPayee","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"MintPaused","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"SignatureVerificationPaused","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"UsedOrCanceledAuthorization","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AccountFrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AccountUnfrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationUsed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"burnFrom","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Burned","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"previousAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"RoleTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"previousAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"RoleTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"SetIsBurnFromPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"SetIsFreezingPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"SetIsMintPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isEnabled","type":"bool"}],"name":"SetIsMsgSenderCheckEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isUpgraded","type":"bool"}],"name":"SetIsReceiveWithAuthorizationUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"SetIsSignatureVerificationPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isUpgraded","type":"bool"}],"name":"SetIsTransferFromUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"SetIsTransferPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isUpgraded","type":"bool"}],"name":"SetIsTransferUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isUpgraded","type":"bool"}],"name":"SetIsTransferWithAuthorizationUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BURNER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CANCEL_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"_domainSeparator","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ERC20_CORE_STORAGE_SLOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"ERC2612_STORAGE_SLOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"FREEZER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IS_BURN_FROM_PAUSED_BIT_POSITION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"IS_FREEZING_PAUSED_BIT_POSITION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"IS_MINT_PAUSED_BIT_POSITION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"IS_MSG_SENDER_FROZEN_CHECK_ENABLED_BIT_POSITION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"IS_RECEIVE_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"IS_SIGNATURE_VERIFICATION_PAUSED_BIT_POSITION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"IS_TRANSFER_FROM_UPGRADED_BIT_POSITION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"IS_TRANSFER_PAUSED_BIT_POSITION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"IS_TRANSFER_UPGRADED_BIT_POSITION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"IS_TRANSFER_WITH_AUTHORIZATION_UPGRADED_BIT_POSITION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RECEIVE_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"TRANSFER_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_role","type":"bytes32"}],"name":"acceptTransferRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"accountData","outputs":[{"components":[{"internalType":"bool","name":"isFrozen","type":"bool"},{"internalType":"uint248","name":"balance","type":"uint248"}],"internalType":"struct StorageLib.Erc20AccountData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"adminAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_authorizer","type":"address"},{"internalType":"bytes32","name":"_nonce","type":"bytes32"}],"name":"authorizationState","outputs":[{"internalType":"bool","name":"_isNonceUsed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"burnFromAddress","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct Erc20Privileged.BatchBurnFromParam[]","name":"_burns","type":"tuple[]"}],"name":"batchBurnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"receiverAddress","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct Erc20Privileged.BatchMintParam[]","name":"_mints","type":"tuple[]"}],"name":"batchMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"burnerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_authorizer","type":"address"},{"internalType":"bytes32","name":"_nonce","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"cancelAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_authorizer","type":"address"},{"internalType":"bytes32","name":"_nonce","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"cancelAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainSeparatorV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"_fields","type":"bytes1"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_version","type":"string"},{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"address","name":"_verifyingContract","type":"address"},{"internalType":"bytes32","name":"_salt","type":"bytes32"},{"internalType":"uint256[]","name":"_extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"freeze","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"freezerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_roleId","type":"bytes32"}],"name":"getRoleData","outputs":[{"components":[{"internalType":"address","name":"pendingRoleAddress","type":"address"},{"internalType":"address","name":"currentRoleAddress","type":"address"}],"internalType":"struct StorageLib.AgoraDollarAccessControlRoleData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_structHash","type":"bytes32"}],"name":"hashTypedDataV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_initialAdminAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isAccountFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBurnFromPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isFreezingPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isMintPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isMsgSenderFrozenCheckEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isReceiveWithAuthorizationUpgraded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isSignatureVerificationPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTransferFromUpgraded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTransferPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTransferUpgraded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTransferWithAuthorizationUpgraded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minterAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"_nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauserAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdminAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingBurnerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingFreezerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingMinterAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingPauserAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proxyAdminAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_validAfter","type":"uint256"},{"internalType":"uint256","name":"_validBefore","type":"uint256"},{"internalType":"bytes32","name":"_nonce","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"receiveWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_validAfter","type":"uint256"},{"internalType":"uint256","name":"_validBefore","type":"uint256"},{"internalType":"bytes32","name":"_nonce","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"receiveWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isPaused","type":"bool"}],"name":"setIsBurnFromPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isPaused","type":"bool"}],"name":"setIsFreezingPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isPaused","type":"bool"}],"name":"setIsMintPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isEnabled","type":"bool"}],"name":"setIsMsgSenderCheckEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isUpgraded","type":"bool"}],"name":"setIsReceiveWithAuthorizationUpgraded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isPaused","type":"bool"}],"name":"setIsSignatureVerificationPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isUpgraded","type":"bool"}],"name":"setIsTransferFromUpgraded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isPaused","type":"bool"}],"name":"setIsTransferPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isUpgraded","type":"bool"}],"name":"setIsTransferUpgraded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isUpgraded","type":"bool"}],"name":"setIsTransferWithAuthorizationUpgraded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_role","type":"bytes32"},{"internalType":"address","name":"_newAddress","type":"address"}],"name":"transferRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_validAfter","type":"uint256"},{"internalType":"uint256","name":"_validBefore","type":"uint256"},{"internalType":"bytes32","name":"_nonce","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"transferWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_validAfter","type":"uint256"},{"internalType":"uint256","name":"_validBefore","type":"uint256"},{"internalType":"bytes32","name":"_nonce","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"transferWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"unfreeze","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6101c0604081815234620002d057620048968038038091620000228286620002d4565b8439820160208084830312620002d05783516001600160401b0394858211620002d057019260a0948585850312620002d05781519386850185811083821117620002bc5783528551828111620002d05781620000809188016200031b565b855283860151828111620002d057816200009c9188016200031b565b9284860193845280870151838111620002d05782620000bd9189016200031b565b918187019283526060880151848111620002d057608091620000e1918a016200031b565b606088018190529701516001600160a01b0381169290838103620002d05760808801525192620001118462000376565b92610120938452620001238962000376565b94610140958652878151910120988960e0528781519101209861010099808b52468c52845190898201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452868301526060820152466080820152828c8201528b815260c0810181811085821117620002bc57855251902060805260c052620001c7620001b96101a09860068a525162000376565b956101609687525162000376565b956101809687527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549260ff84861c16620002ab57818085160362000268575b5050505051956144b19788620003e58939608051886140820152518761414e015260c05187614053015260e051876140d1015251866140f7015251856123f701525184612421015251836138e001525182611d4c015251816132e10152f35b6001600160401b0319909316811790925582519182527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d291a15f80808062000209565b845163f92ee8a960e01b8152600490fd5b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b601f909101601f19168101906001600160401b03821190821017620002bc57604052565b5f5b8381106200030a5750505f910152565b8181015183820152602001620002fa565b81601f82011215620002d05780516001600160401b038111620002bc576040519262000352601f8301601f191660200185620002d4565b81845260208284010111620002d057620003739160208085019101620002f8565b90565b601f815111620003a357602081519101516020821062000394571790565b5f198260200360031b1b161790565b6044604051809263305a27a960e01b825260206004830152620003d68151809281602486015260208686019101620002f8565b601f01601f19168101030190fdfe6080604081815260049182361015610015575f80fd5b5f92833560e01c91826306a85f0f146139045750816306fdde03146138a7578163095ea7b3146138585781630d4a3f9c146137e357816315839b301461376e57816315e4dadd1461369257816318160ddd14613636578163192e117c1461355a5781631d1b2a47146134c157816322a5e9501461344b57816323b872dd14613405578163282c51f3146133ac57816330adf81f1461335357816331253bf514613305578163313ce567146132a957816334d722c91461320d5781633644e515146126e85781633e1481be1461313057816345c8b1a6146130235781634980f28814612fd857816350ba1fb214612f8a5781635544f37414612ef15781635979e75514612e7f5781635a049a7014612c665781635bfe8ad814612bca5781635c60da1b14612b585781635fa0bf3714612ae35781636028aab814612a945781636b91bf5014612a1f57816370a082311461299b57816372ac04bb1461287057816375b238fc14612817578163764ce8f7146127c957816376e53761146126ed57816378e890ba146126e85781637ecebe00146126675781637f2eecc31461260e578163804effb91461253257816384b0196e146123c157816388b7ab6314610e385781638a00a0ed146123685781638d1fdf2f1461223157816390e41f1614612155578163930b6cd7146120795781639386e19714611d8757816395d89b4114611d1357816398b1b60214611c7a5781639ee12c8914611b1d5781639fd5a6cf14611aac578163a0cc6a6814611a53578163a1a1ef43146119de578163a4753af014611945578163a9059cbb14611902578163aa46b7bf1461188d578163af5045a61461183f578163b031623e14611763578163b260d8b314611416578163b4880c2f14611363578163b7b7289914611163578163bd7c04bf14611115578163bfcc8ac0146110bc578163c3cd74701461106d578163c4d66de814610eb2578163c8d7e6ae14610e3d578163cf09299514610e38578163d46af79714610d5c578163d505accf14610ca7578163d539139314610c4e578163d916948714610bf5578163dd62ed3e14610b46578163deb906e714610a6d578163e0e6626f14610a1f578163e38d890e146109a9578163e3ee160e1461061b578163e6293e231461090d578163e63ab1e9146108b4578163e816d97f1461082e578163e81b39b814610795578163e94a010214610706578163e9ec7ba51461062057508063ef55bec61461061b578063ef654072146105ce578063f08cdab214610581578063f2e547461461050d578063f7fb869b146104725763fc6f9468146103d4575f80fd5b3461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff600182847fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775602096527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008652200154169051908152f35b5080fd5b503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff600182847f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a602096527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008652200154169051908152f35b503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090740400000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051740200000000000000000000000000000000000000008152f35b503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051742000000000000000000000000000000000000000008152f35b613c74565b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f7e22bd1ded40af89556ea2a186756d2d071fdab25d3a91442c2450abc4035f9892602092610689613de6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80549091156106d657750100000000000000000000000000000000000000000017905b5551908152a180f35b7ffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffff16906106cd565b8380fd5b8280fd5b50503461046e57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760ff8160209373ffffffffffffffffffffffffffffffffffffffff6107596139b8565b1681527fbb0a37da742be2e3b68bdb11d195150f4243c03fb37d3cdfa756046082a3860085528181206024358252855220541690519015158152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff81837f92de27771f92d6942691d73358b3a4673e4880de8356f8f2cf452be87e02d363602095527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe70085522054169051908152f35b50503461046e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760ff8160209373ffffffffffffffffffffffffffffffffffffffff6108826139b8565b1681527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b700855220541690519015158152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a8152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff600182847f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848602096527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008652200154169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209075010000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051744000000000000000000000000000000000000000008152f35b50503461046e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57809173ffffffffffffffffffffffffffffffffffffffff610abd6139b8565b8260208551610acb81613a42565b82815201521681527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b700602052207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff825191610b2483613a42565b54602060ff8216151593848152019060081c8152835192835251166020820152f35b50503461046e57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5780602092610b826139b8565b73ffffffffffffffffffffffffffffffffffffffff610be6610ba26139df565b9273ffffffffffffffffffffffffffffffffffffffff165f527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b70160205260405f2090565b91168252845220549051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a15974298152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a68152f35b50503461046e5760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57610ce06139b8565b610ce86139df565b6084359160ff83168303610d5857925160a435602082015260c435604082015260f89290921b7fff0000000000000000000000000000000000000000000000000000000000000016606083015260418252610d5592610d48606184613aa7565b6064359160443591614305565b80f35b8480fd5b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f6c0ffede7c170452907272cb5f247b8e3a2f5ccbd1dd1b6158589316c105063492602092610dc5613de6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8054909115610e10577440000000000000000000000000000000000000000017905551908152a180f35b7fffffffffffffffffffffffbfffffffffffffffffffffffffffffffffffffffff16906106cd565b613b5c565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090742000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257610eeb6139b8565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549060ff82861c168015611058575b6110315750917fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29391680100000000000000027fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000602095161782557fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177586527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe700845273ffffffffffffffffffffffffffffffffffffffff60018488200191167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790557fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff81541690555160028152a180f35b84517ff92ee8a9000000000000000000000000000000000000000000000000000000008152fd5b50600267ffffffffffffffff83161015610f1d565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e576020905175020000000000000000000000000000000000000000008152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f69e87f5b9323740fce20cdf574dacd1d10e756da64a1f2df70fd1ace4c7cc3008152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051748000000000000000000000000000000000000000008152f35b9050346107025760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107025761119c6139b8565b916024359260443567ffffffffffffffff811161135f576111c09036908501613ae8565b9273ffffffffffffffffffffffffffffffffffffffff8216938487527fbb0a37da742be2e3b68bdb11d195150f4243c03fb37d3cdfa756046082a38600928360205284882087895260205260ff858920541661133757906112a9916112a3865160208101907f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a1597429825289898201528a60608201526060815261126081613a8b565b51902061126b61403c565b604291604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b90613efa565b156113105750828552602052808420838552602052832060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f1cdd46ff242716cdaa72d159d339a485b3438398348d68f09d7c8c0a59353d818380a380f35b82517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b8285517f1dbc01d4000000000000000000000000000000000000000000000000000000008152fd5b8580fd5b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107025791819281602084516113a581613a42565b82815201523581527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7006020522081516113dd81613a42565b73ffffffffffffffffffffffffffffffffffffffff90602082600181865416958685520154169101908152835192835251166020820152f35b9190503461070257602091827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106fe5780359167ffffffffffffffff8311610d585736602384011215610d585761147b602493369085818601359101613bd8565b917f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848938487527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe700865273ffffffffffffffffffffffffffffffffffffffff916001958387868b2001541633036117385750740400000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54166117115787865b611534578880f35b855181101561170d577effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff806115748a61156c858b61426b565b5101516142ac565b167f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b7028054908282039182116116e25755856115af848a61426b565b5151168b527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b7008a52868b2090815460081c039182116116b7576116b19291611623919060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083549260081b169116179055565b898561162f838a61426b565b5151167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8b8061165f868d61426b565b5101518a51908152a384611673828961426b565b5151167f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df78a806116a3858c61426b565b5101518951908152a2614211565b8661152c565b848b6011867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b868d6011887f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b8880f35b83517f1f892176000000000000000000000000000000000000000000000000000000008152fd5b8451917f079505ac000000000000000000000000000000000000000000000000000000008352820152fd5b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f1d8f9f59c229095c03ad21f2cb3d42f0992c697cd9186f8743672e7f7a6cfae6926020926117cc613d2b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8054909115611817577402000000000000000000000000000000000000000017905551908152a180f35b7ffffffffffffffffffffffffdffffffffffffffffffffffffffffffffffffffff16906106cd565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051740800000000000000000000000000000000000000008152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090740100000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e579060209161193e6139b8565b5051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff81837f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a602095527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe70085522054169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090741000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a22678152f35b83903461046e5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57611ae56139b8565b611aed6139df565b60843567ffffffffffffffff8111610d5857610d5593611b0f91369101613ae8565b916064359160443591614305565b9190503461070257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610702578135611b586139df565b928185527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008060205273ffffffffffffffffffffffffffffffffffffffff9182600186892001541633148015611c46575b15611c175750916020917fc9ba1b1f5a418274427c969ace813494ac92d03206cbee8cffb4ba8696f50736938288528352600181868920971696877fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781550154169351908152a380f35b602490848651917f079505ac000000000000000000000000000000000000000000000000000000008352820152fd5b507fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177587528260018689200154163314611ba9565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff81837f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848602095527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe70085522054169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57611d8390611d707f0000000000000000000000000000000000000000000000000000000000000000613cdd565b905191829160208352602083019061395c565b0390f35b9190503461070257602091827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106fe5780359167ffffffffffffffff8311610d585736602384011215610d5857611dec602493369085818601359101613bd8565b917f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6938487527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe700865273ffffffffffffffffffffffffffffffffffffffff916001958387868b2001541633036117385750740200000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54166120525787865b611ea5578880f35b855181101561170d5783611eb9828861426b565b51511615612025577effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80611ef08a61156c858b61426b565b167f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b7028054908282018092116116e2575585611f2b848a61426b565b5151168b527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b7008a52868b2090815460081c019182116116b75761201f9291611f9f919060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083549260081b169116179055565b84611faa828961426b565b5151168a7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8b80611fdb868d61426b565b5101518a51908152a384611fef828961426b565b5151167f30385c845b448a36257a6a1716e6ad2e1bc2cbe333cde1e69fe849ad6511adfe8a806116a3858c61426b565b86611e9d565b50878451917fec442f05000000000000000000000000000000000000000000000000000000008352820152fd5b83517fd7d248ba000000000000000000000000000000000000000000000000000000008152fd5b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f3dc87209d08fd89c2d0388c38457d4596c54dc30cf3f233388204c98c0f4fe4c926020926120e2613de6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc805490911561212d577401000000000000000000000000000000000000000017905551908152a180f35b7ffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffff16906106cd565b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577fe0d2b2dd09773cdb297acee4b00cd79ae1f5634e497574a791a9010abb9badc7926020926121be613d2b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8054909115612209577420000000000000000000000000000000000000000017905551908152a180f35b7fffffffffffffffffffffffdfffffffffffffffffffffffffffffffffffffffff16906106cd565b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107025761226a6139b8565b90612273613e70565b740800000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416612341575073ffffffffffffffffffffffffffffffffffffffff16908183527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b700602052822060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f4f2a367e694e71282f29ab5eaa04c4c0be45ac5bf2ca74fb67068b98bdc2887d8280a280f35b82517f6906df70000000000000000000000000000000000000000000000000000000008152fd5b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b7008152f35b9190503461070257827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107025761241b7f0000000000000000000000000000000000000000000000000000000000000000613cdd565b926124457f0000000000000000000000000000000000000000000000000000000000000000613cdd565b908251926020928385019585871067ffffffffffffffff881117612506575092806124bc8388966124af998b9996528686528151998a997f0f000000000000000000000000000000000000000000000000000000000000008b5260e0868c015260e08b019061395c565b91898303908a015261395c565b924660608801523060808801528460a088015286840360c088015251928381520193925b8281106124ef57505050500390f35b8351855286955093810193928101926001016124e0565b8360416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577fc779944e65337e9ddd9d470f0c405c42113eff4f1ecbfb642fa7ec30d2f5cd009260209261259b613d2b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80549091156125e6577410000000000000000000000000000000000000000017905551908152a180f35b7fffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffff16906106cd565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517fd099cc98ef71107a616c4f0f941f04c322d8e254fe26b3c6668db87aae413de88152f35b50503461046e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e578060209273ffffffffffffffffffffffffffffffffffffffff6126b96139b8565b1681527f69e87f5b9323740fce20cdf574dacd1d10e756da64a1f2df70fd1ace4c7cc300845220549051908152f35b613a02565b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f75a44401a06f3f016e2c430f84db52a403f7ef06531c601be59c510f90cae36492602092612756613d2b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80549091156127a1577408000000000000000000000000000000000000000017905551908152a180f35b7ffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffff16906106cd565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051740100000000000000000000000000000000000000008152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217758152f35b8391503461046e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e578035928383527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008060205273ffffffffffffffffffffffffffffffffffffffff92838386205416330361296c575084849560019495528160205282862094847fffffffffffffffffffffffff0000000000000000000000000000000000000000968781541681550154168351908282527f274dd4127a55dcb6f6c12ed38fec5007d965d2afffa8b0bc75c3dc8f3f6b222460203393a3855260205283200190339082541617905580f35b602490868451917f2b184716000000000000000000000000000000000000000000000000000000008352820152fd5b50503461046e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e578060209273ffffffffffffffffffffffffffffffffffffffff6129ed6139b8565b1681527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b7008452205460081c9051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090740800000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e576020905175010000000000000000000000000000000000000000008152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090744000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209073ffffffffffffffffffffffffffffffffffffffff7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff600182847f92de27771f92d6942691d73358b3a4673e4880de8356f8f2cf452be87e02d363602096527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008652200154169051908152f35b9050346107025760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257612c9f6139b8565b91602435926044359060ff8216820361135f57825193612d2f85612d0360209560843560643588850191926041937fff00000000000000000000000000000000000000000000000000000000000000928452602084015260f81b1660408201520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101875286613aa7565b73ffffffffffffffffffffffffffffffffffffffff8216948588527fbb0a37da742be2e3b68bdb11d195150f4243c03fb37d3cdfa756046082a3860092838552858920888a52855260ff868a205416612e575790612dcb916112a38751878101907f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a159742982528a8a8201528b60608201526060815261126081613a8b565b15612e30575083865281528185209084865252832060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f1cdd46ff242716cdaa72d159d339a485b3438398348d68f09d7c8c0a59353d818380a380f35b83517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b8286517f1dbc01d4000000000000000000000000000000000000000000000000000000008152fd5b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209073ffffffffffffffffffffffffffffffffffffffff7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610354169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff81837fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775602095527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe70085522054169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051740400000000000000000000000000000000000000008152f35b8284346130205760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261302057506130196020923561126b61403c565b9051908152f35b80fd5b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107025761305c6139b8565b90613065613e70565b740800000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416612341575073ffffffffffffffffffffffffffffffffffffffff16908183527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b70060205282207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff915cd9fe234de6e8d3afe7bf2388d35b2b6d48e8c629a24602019bde79c213a8280a280f35b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f1a0d99f7303b92ed36c0994e28a012442012c3c131cd7fadf9bb3fd6e2e4267492602092613199613de6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80549091156131e557750200000000000000000000000000000000000000000017905551908152a180f35b7ffffffffffffffffffffffdffffffffffffffffffffffffffffffffffffffffff16906106cd565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff600182847f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6602096527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008652200154169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e576020905160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051741000000000000000000000000000000000000000008152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a8488152f35b50503461046e5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57906020916134426139b8565b5061193e6139df565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209075020000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff81837f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6602095527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe70085522054169051908152f35b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f54385a146bb476b7174837575178b2fe5f41d25fa9ef302efe8d11a71548d279926020926135c3613de6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc805490911561360e577480000000000000000000000000000000000000000017905551908152a180f35b7fffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffff16906106cd565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e576020907f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b702549051908152f35b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f54c00807d114bba237f2a5490bcd33953803557fb963b91913d12b3c050e7e01926020926136fb613d2b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8054909115613746577404000000000000000000000000000000000000000017905551908152a180f35b7ffffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffffff16906106cd565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090740200000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090748000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e576020906138a06138966139b8565b6024359033614174565b5160018152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57611d8390611d707f0000000000000000000000000000000000000000000000000000000000000000613cdd565b84903461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57807f92de27771f92d6942691d73358b3a4673e4880de8356f8f2cf452be87e02d36360209252f35b91908251928382525f5b8481106139a45750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6020809697860101520116010190565b602081830181015184830182015201613966565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036139db57565b5f80fd5b6024359073ffffffffffffffffffffffffffffffffffffffff821682036139db57565b346139db575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126139db576020613a3a61403c565b604051908152f35b6040810190811067ffffffffffffffff821117613a5e57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6080810190811067ffffffffffffffff821117613a5e57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117613a5e57604052565b81601f820112156139db5780359067ffffffffffffffff8211613a5e5760405192613b3b60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8601160185613aa7565b828452602083830101116139db57815f926020809301838601378301015290565b346139db5760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126139db5773ffffffffffffffffffffffffffffffffffffffff600435818116036139db57602435908116036139db5760c43567ffffffffffffffff81116139db57613bd6903690600401613ae8565b005b92919267ffffffffffffffff8211613a5e576020604092835195613c01838360051b0188613aa7565b8287838152019160061b8401938185116139db57915b848310613c2657505050505050565b85838303126139db57855190613c3b82613a42565b83359073ffffffffffffffffffffffffffffffffffffffff821682036139db578286928994528286013583820152815201920191613c17565b346139db576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126139db5773ffffffffffffffffffffffffffffffffffffffff600435818116036139db57602435908116036139db5760c43560ff8116036139db57005b60ff811690601f8211613d015760405191613cf783613a42565b8252602082015290565b60046040517fb3512b0c000000000000000000000000000000000000000000000000000000008152fd5b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a5f8190527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7006020527fabd82dbd05b39244206723f51e84a7c6598e8be9964fb10cb3a52e369c813b715473ffffffffffffffffffffffffffffffffffffffff163303613db55750565b602490604051907f079505ac0000000000000000000000000000000000000000000000000000000082526004820152fd5b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217755f8190527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7006020527fd1f8c51c6981d62cef9341fbb8b1bc980e6fec9aad2faecb149696b3c033c7765473ffffffffffffffffffffffffffffffffffffffff163303613db55750565b7f92de27771f92d6942691d73358b3a4673e4880de8356f8f2cf452be87e02d3635f8190527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7006020527f8ee12e1d3431af53f63fc671affd6463dcd6fd677075c7c287208221042747435473ffffffffffffffffffffffffffffffffffffffff163303613db55750565b92915f9373ffffffffffffffffffffffffffffffffffffffff5f911680613f22575b50505050565b909192939450604090815185845260209384860151845283865114613fec575b6041865114613faa575b6060528083527f1626ba7e000000000000000000000000000000000000000000000000000000009485825260049687830152602482019687948552815186019081604493848601925afa503d01915afa91511416905f808080613f1c565b606080870151821a865284870151815260018681608085825afa5185183d151715613fd6575050613f4c565b935097965092935093509452525f808080613f1c565b83860151601b8160ff1c0186527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60609116815260018681608085825afa5185183d151715613fd6575050613f42565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630148061414b575b156140a4577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a0815260c0810181811067ffffffffffffffff821117613a5e5760405251902090565b507f0000000000000000000000000000000000000000000000000000000000000000461461407b565b919060207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925916141e18573ffffffffffffffffffffffffffffffffffffffff165f527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b70160205260405f2090565b9473ffffffffffffffffffffffffffffffffffffffff80921695865f5283528460405f20556040519485521692a3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811461423e5760010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b805182101561427f5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f01000000000000000000000000000000000000000000000000000000000000008110156142f8577effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b6335278d125f526004601cfd5b9392909192742000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416614487578142116144565773ffffffffffffffffffffffffffffffffffffffff9182861690815f527f69e87f5b9323740fce20cdf574dacd1d10e756da64a1f2df70fd1ace4c7cc30060205260405f208054906001820190556040519460208601937f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9855260408701528616606086015286608086015260a085015260c084015260c0835260e083019083821067ffffffffffffffff831117613a5e5761441c936144169260405251902061126b61403c565b85613efa565b1561442c5761442a92614174565b565b60046040517f4f8bbd8d000000000000000000000000000000000000000000000000000000008152fd5b602482604051907fa546f0e30000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517fe283c875000000000000000000000000000000000000000000000000000000008152fd000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000efe302beaa2b3e6e1b18d08d69a9012a0000000000000000000000000000000000000000000000000000000000000004415553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044155534400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c41676f726120446f6c6c6172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013100000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604081815260049182361015610015575f80fd5b5f92833560e01c91826306a85f0f146139045750816306fdde03146138a7578163095ea7b3146138585781630d4a3f9c146137e357816315839b301461376e57816315e4dadd1461369257816318160ddd14613636578163192e117c1461355a5781631d1b2a47146134c157816322a5e9501461344b57816323b872dd14613405578163282c51f3146133ac57816330adf81f1461335357816331253bf514613305578163313ce567146132a957816334d722c91461320d5781633644e515146126e85781633e1481be1461313057816345c8b1a6146130235781634980f28814612fd857816350ba1fb214612f8a5781635544f37414612ef15781635979e75514612e7f5781635a049a7014612c665781635bfe8ad814612bca5781635c60da1b14612b585781635fa0bf3714612ae35781636028aab814612a945781636b91bf5014612a1f57816370a082311461299b57816372ac04bb1461287057816375b238fc14612817578163764ce8f7146127c957816376e53761146126ed57816378e890ba146126e85781637ecebe00146126675781637f2eecc31461260e578163804effb91461253257816384b0196e146123c157816388b7ab6314610e385781638a00a0ed146123685781638d1fdf2f1461223157816390e41f1614612155578163930b6cd7146120795781639386e19714611d8757816395d89b4114611d1357816398b1b60214611c7a5781639ee12c8914611b1d5781639fd5a6cf14611aac578163a0cc6a6814611a53578163a1a1ef43146119de578163a4753af014611945578163a9059cbb14611902578163aa46b7bf1461188d578163af5045a61461183f578163b031623e14611763578163b260d8b314611416578163b4880c2f14611363578163b7b7289914611163578163bd7c04bf14611115578163bfcc8ac0146110bc578163c3cd74701461106d578163c4d66de814610eb2578163c8d7e6ae14610e3d578163cf09299514610e38578163d46af79714610d5c578163d505accf14610ca7578163d539139314610c4e578163d916948714610bf5578163dd62ed3e14610b46578163deb906e714610a6d578163e0e6626f14610a1f578163e38d890e146109a9578163e3ee160e1461061b578163e6293e231461090d578163e63ab1e9146108b4578163e816d97f1461082e578163e81b39b814610795578163e94a010214610706578163e9ec7ba51461062057508063ef55bec61461061b578063ef654072146105ce578063f08cdab214610581578063f2e547461461050d578063f7fb869b146104725763fc6f9468146103d4575f80fd5b3461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff600182847fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775602096527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008652200154169051908152f35b5080fd5b503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff600182847f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a602096527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008652200154169051908152f35b503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090740400000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051740200000000000000000000000000000000000000008152f35b503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051742000000000000000000000000000000000000000008152f35b613c74565b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f7e22bd1ded40af89556ea2a186756d2d071fdab25d3a91442c2450abc4035f9892602092610689613de6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80549091156106d657750100000000000000000000000000000000000000000017905b5551908152a180f35b7ffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffff16906106cd565b8380fd5b8280fd5b50503461046e57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760ff8160209373ffffffffffffffffffffffffffffffffffffffff6107596139b8565b1681527fbb0a37da742be2e3b68bdb11d195150f4243c03fb37d3cdfa756046082a3860085528181206024358252855220541690519015158152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff81837f92de27771f92d6942691d73358b3a4673e4880de8356f8f2cf452be87e02d363602095527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe70085522054169051908152f35b50503461046e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760ff8160209373ffffffffffffffffffffffffffffffffffffffff6108826139b8565b1681527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b700855220541690519015158152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a8152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff600182847f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848602096527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008652200154169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209075010000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051744000000000000000000000000000000000000000008152f35b50503461046e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57809173ffffffffffffffffffffffffffffffffffffffff610abd6139b8565b8260208551610acb81613a42565b82815201521681527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b700602052207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff825191610b2483613a42565b54602060ff8216151593848152019060081c8152835192835251166020820152f35b50503461046e57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5780602092610b826139b8565b73ffffffffffffffffffffffffffffffffffffffff610be6610ba26139df565b9273ffffffffffffffffffffffffffffffffffffffff165f527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b70160205260405f2090565b91168252845220549051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a15974298152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a68152f35b50503461046e5760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57610ce06139b8565b610ce86139df565b6084359160ff83168303610d5857925160a435602082015260c435604082015260f89290921b7fff0000000000000000000000000000000000000000000000000000000000000016606083015260418252610d5592610d48606184613aa7565b6064359160443591614305565b80f35b8480fd5b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f6c0ffede7c170452907272cb5f247b8e3a2f5ccbd1dd1b6158589316c105063492602092610dc5613de6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8054909115610e10577440000000000000000000000000000000000000000017905551908152a180f35b7fffffffffffffffffffffffbfffffffffffffffffffffffffffffffffffffffff16906106cd565b613b5c565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090742000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257610eeb6139b8565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009182549060ff82861c168015611058575b6110315750917fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29391680100000000000000027fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000602095161782557fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177586527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe700845273ffffffffffffffffffffffffffffffffffffffff60018488200191167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790557fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff81541690555160028152a180f35b84517ff92ee8a9000000000000000000000000000000000000000000000000000000008152fd5b50600267ffffffffffffffff83161015610f1d565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e576020905175020000000000000000000000000000000000000000008152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f69e87f5b9323740fce20cdf574dacd1d10e756da64a1f2df70fd1ace4c7cc3008152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051748000000000000000000000000000000000000000008152f35b9050346107025760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107025761119c6139b8565b916024359260443567ffffffffffffffff811161135f576111c09036908501613ae8565b9273ffffffffffffffffffffffffffffffffffffffff8216938487527fbb0a37da742be2e3b68bdb11d195150f4243c03fb37d3cdfa756046082a38600928360205284882087895260205260ff858920541661133757906112a9916112a3865160208101907f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a1597429825289898201528a60608201526060815261126081613a8b565b51902061126b61403c565b604291604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b90613efa565b156113105750828552602052808420838552602052832060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f1cdd46ff242716cdaa72d159d339a485b3438398348d68f09d7c8c0a59353d818380a380f35b82517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b8285517f1dbc01d4000000000000000000000000000000000000000000000000000000008152fd5b8580fd5b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107025791819281602084516113a581613a42565b82815201523581527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7006020522081516113dd81613a42565b73ffffffffffffffffffffffffffffffffffffffff90602082600181865416958685520154169101908152835192835251166020820152f35b9190503461070257602091827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106fe5780359167ffffffffffffffff8311610d585736602384011215610d585761147b602493369085818601359101613bd8565b917f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848938487527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe700865273ffffffffffffffffffffffffffffffffffffffff916001958387868b2001541633036117385750740400000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54166117115787865b611534578880f35b855181101561170d577effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff806115748a61156c858b61426b565b5101516142ac565b167f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b7028054908282039182116116e25755856115af848a61426b565b5151168b527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b7008a52868b2090815460081c039182116116b7576116b19291611623919060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083549260081b169116179055565b898561162f838a61426b565b5151167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8b8061165f868d61426b565b5101518a51908152a384611673828961426b565b5151167f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df78a806116a3858c61426b565b5101518951908152a2614211565b8661152c565b848b6011867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b868d6011887f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b8880f35b83517f1f892176000000000000000000000000000000000000000000000000000000008152fd5b8451917f079505ac000000000000000000000000000000000000000000000000000000008352820152fd5b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f1d8f9f59c229095c03ad21f2cb3d42f0992c697cd9186f8743672e7f7a6cfae6926020926117cc613d2b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8054909115611817577402000000000000000000000000000000000000000017905551908152a180f35b7ffffffffffffffffffffffffdffffffffffffffffffffffffffffffffffffffff16906106cd565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051740800000000000000000000000000000000000000008152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090740100000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e579060209161193e6139b8565b5051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff81837f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a602095527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe70085522054169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090741000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a22678152f35b83903461046e5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57611ae56139b8565b611aed6139df565b60843567ffffffffffffffff8111610d5857610d5593611b0f91369101613ae8565b916064359160443591614305565b9190503461070257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610702578135611b586139df565b928185527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008060205273ffffffffffffffffffffffffffffffffffffffff9182600186892001541633148015611c46575b15611c175750916020917fc9ba1b1f5a418274427c969ace813494ac92d03206cbee8cffb4ba8696f50736938288528352600181868920971696877fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781550154169351908152a380f35b602490848651917f079505ac000000000000000000000000000000000000000000000000000000008352820152fd5b507fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177587528260018689200154163314611ba9565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff81837f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848602095527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe70085522054169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57611d8390611d707f4155534400000000000000000000000000000000000000000000000000000004613cdd565b905191829160208352602083019061395c565b0390f35b9190503461070257602091827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106fe5780359167ffffffffffffffff8311610d585736602384011215610d5857611dec602493369085818601359101613bd8565b917f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6938487527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe700865273ffffffffffffffffffffffffffffffffffffffff916001958387868b2001541633036117385750740200000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54166120525787865b611ea5578880f35b855181101561170d5783611eb9828861426b565b51511615612025577effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80611ef08a61156c858b61426b565b167f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b7028054908282018092116116e2575585611f2b848a61426b565b5151168b527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b7008a52868b2090815460081c019182116116b75761201f9291611f9f919060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083549260081b169116179055565b84611faa828961426b565b5151168a7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8b80611fdb868d61426b565b5101518a51908152a384611fef828961426b565b5151167f30385c845b448a36257a6a1716e6ad2e1bc2cbe333cde1e69fe849ad6511adfe8a806116a3858c61426b565b86611e9d565b50878451917fec442f05000000000000000000000000000000000000000000000000000000008352820152fd5b83517fd7d248ba000000000000000000000000000000000000000000000000000000008152fd5b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f3dc87209d08fd89c2d0388c38457d4596c54dc30cf3f233388204c98c0f4fe4c926020926120e2613de6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc805490911561212d577401000000000000000000000000000000000000000017905551908152a180f35b7ffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffff16906106cd565b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577fe0d2b2dd09773cdb297acee4b00cd79ae1f5634e497574a791a9010abb9badc7926020926121be613d2b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8054909115612209577420000000000000000000000000000000000000000017905551908152a180f35b7fffffffffffffffffffffffdfffffffffffffffffffffffffffffffffffffffff16906106cd565b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107025761226a6139b8565b90612273613e70565b740800000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416612341575073ffffffffffffffffffffffffffffffffffffffff16908183527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b700602052822060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f4f2a367e694e71282f29ab5eaa04c4c0be45ac5bf2ca74fb67068b98bdc2887d8280a280f35b82517f6906df70000000000000000000000000000000000000000000000000000000008152fd5b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b7008152f35b9190503461070257827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107025761241b7f41676f726120446f6c6c6172000000000000000000000000000000000000000c613cdd565b926124457f3100000000000000000000000000000000000000000000000000000000000001613cdd565b908251926020928385019585871067ffffffffffffffff881117612506575092806124bc8388966124af998b9996528686528151998a997f0f000000000000000000000000000000000000000000000000000000000000008b5260e0868c015260e08b019061395c565b91898303908a015261395c565b924660608801523060808801528460a088015286840360c088015251928381520193925b8281106124ef57505050500390f35b8351855286955093810193928101926001016124e0565b8360416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577fc779944e65337e9ddd9d470f0c405c42113eff4f1ecbfb642fa7ec30d2f5cd009260209261259b613d2b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80549091156125e6577410000000000000000000000000000000000000000017905551908152a180f35b7fffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffff16906106cd565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517fd099cc98ef71107a616c4f0f941f04c322d8e254fe26b3c6668db87aae413de88152f35b50503461046e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e578060209273ffffffffffffffffffffffffffffffffffffffff6126b96139b8565b1681527f69e87f5b9323740fce20cdf574dacd1d10e756da64a1f2df70fd1ace4c7cc300845220549051908152f35b613a02565b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f75a44401a06f3f016e2c430f84db52a403f7ef06531c601be59c510f90cae36492602092612756613d2b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80549091156127a1577408000000000000000000000000000000000000000017905551908152a180f35b7ffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffff16906106cd565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051740100000000000000000000000000000000000000008152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217758152f35b8391503461046e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e578035928383527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008060205273ffffffffffffffffffffffffffffffffffffffff92838386205416330361296c575084849560019495528160205282862094847fffffffffffffffffffffffff0000000000000000000000000000000000000000968781541681550154168351908282527f274dd4127a55dcb6f6c12ed38fec5007d965d2afffa8b0bc75c3dc8f3f6b222460203393a3855260205283200190339082541617905580f35b602490868451917f2b184716000000000000000000000000000000000000000000000000000000008352820152fd5b50503461046e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e578060209273ffffffffffffffffffffffffffffffffffffffff6129ed6139b8565b1681527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b7008452205460081c9051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090740800000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e576020905175010000000000000000000000000000000000000000008152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090744000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209073ffffffffffffffffffffffffffffffffffffffff7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff600182847f92de27771f92d6942691d73358b3a4673e4880de8356f8f2cf452be87e02d363602096527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008652200154169051908152f35b9050346107025760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257612c9f6139b8565b91602435926044359060ff8216820361135f57825193612d2f85612d0360209560843560643588850191926041937fff00000000000000000000000000000000000000000000000000000000000000928452602084015260f81b1660408201520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101875286613aa7565b73ffffffffffffffffffffffffffffffffffffffff8216948588527fbb0a37da742be2e3b68bdb11d195150f4243c03fb37d3cdfa756046082a3860092838552858920888a52855260ff868a205416612e575790612dcb916112a38751878101907f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a159742982528a8a8201528b60608201526060815261126081613a8b565b15612e30575083865281528185209084865252832060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557f1cdd46ff242716cdaa72d159d339a485b3438398348d68f09d7c8c0a59353d818380a380f35b83517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b8286517f1dbc01d4000000000000000000000000000000000000000000000000000000008152fd5b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209073ffffffffffffffffffffffffffffffffffffffff7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610354169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff81837fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775602095527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe70085522054169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051740400000000000000000000000000000000000000008152f35b8284346130205760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261302057506130196020923561126b61403c565b9051908152f35b80fd5b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107025761305c6139b8565b90613065613e70565b740800000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416612341575073ffffffffffffffffffffffffffffffffffffffff16908183527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b70060205282207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557ff915cd9fe234de6e8d3afe7bf2388d35b2b6d48e8c629a24602019bde79c213a8280a280f35b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f1a0d99f7303b92ed36c0994e28a012442012c3c131cd7fadf9bb3fd6e2e4267492602092613199613de6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80549091156131e557750200000000000000000000000000000000000000000017905551908152a180f35b7ffffffffffffffffffffffdffffffffffffffffffffffffffffffffffffffffff16906106cd565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff600182847f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6602096527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7008652200154169051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e576020905160ff7f0000000000000000000000000000000000000000000000000000000000000006168152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209051741000000000000000000000000000000000000000008152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090517f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a8488152f35b50503461046e5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57906020916134426139b8565b5061193e6139df565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5760209075020000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e5773ffffffffffffffffffffffffffffffffffffffff81837f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6602095527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe70085522054169051908152f35b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f54385a146bb476b7174837575178b2fe5f41d25fa9ef302efe8d11a71548d279926020926135c3613de6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc805490911561360e577480000000000000000000000000000000000000000017905551908152a180f35b7fffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffff16906106cd565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e576020907f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b702549051908152f35b9050346107025760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070257358015158082036106fe577f54c00807d114bba237f2a5490bcd33953803557fb963b91913d12b3c050e7e01926020926136fb613d2b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8054909115613746577404000000000000000000000000000000000000000017905551908152a180f35b7ffffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffffff16906106cd565b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090740200000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57602090748000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541615159051908152f35b50503461046e57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e576020906138a06138966139b8565b6024359033614174565b5160018152f35b50503461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57611d8390611d707f4155534400000000000000000000000000000000000000000000000000000004613cdd565b84903461046e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261046e57807f92de27771f92d6942691d73358b3a4673e4880de8356f8f2cf452be87e02d36360209252f35b91908251928382525f5b8481106139a45750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6020809697860101520116010190565b602081830181015184830182015201613966565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036139db57565b5f80fd5b6024359073ffffffffffffffffffffffffffffffffffffffff821682036139db57565b346139db575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126139db576020613a3a61403c565b604051908152f35b6040810190811067ffffffffffffffff821117613a5e57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6080810190811067ffffffffffffffff821117613a5e57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117613a5e57604052565b81601f820112156139db5780359067ffffffffffffffff8211613a5e5760405192613b3b60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8601160185613aa7565b828452602083830101116139db57815f926020809301838601378301015290565b346139db5760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126139db5773ffffffffffffffffffffffffffffffffffffffff600435818116036139db57602435908116036139db5760c43567ffffffffffffffff81116139db57613bd6903690600401613ae8565b005b92919267ffffffffffffffff8211613a5e576020604092835195613c01838360051b0188613aa7565b8287838152019160061b8401938185116139db57915b848310613c2657505050505050565b85838303126139db57855190613c3b82613a42565b83359073ffffffffffffffffffffffffffffffffffffffff821682036139db578286928994528286013583820152815201920191613c17565b346139db576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126139db5773ffffffffffffffffffffffffffffffffffffffff600435818116036139db57602435908116036139db5760c43560ff8116036139db57005b60ff811690601f8211613d015760405191613cf783613a42565b8252602082015290565b60046040517fb3512b0c000000000000000000000000000000000000000000000000000000008152fd5b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a5f8190527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7006020527fabd82dbd05b39244206723f51e84a7c6598e8be9964fb10cb3a52e369c813b715473ffffffffffffffffffffffffffffffffffffffff163303613db55750565b602490604051907f079505ac0000000000000000000000000000000000000000000000000000000082526004820152fd5b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217755f8190527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7006020527fd1f8c51c6981d62cef9341fbb8b1bc980e6fec9aad2faecb149696b3c033c7765473ffffffffffffffffffffffffffffffffffffffff163303613db55750565b7f92de27771f92d6942691d73358b3a4673e4880de8356f8f2cf452be87e02d3635f8190527f9d28e63f6379c0b2127b14120db65179caba9597ddafa73863de41a4ba1fe7006020527f8ee12e1d3431af53f63fc671affd6463dcd6fd677075c7c287208221042747435473ffffffffffffffffffffffffffffffffffffffff163303613db55750565b92915f9373ffffffffffffffffffffffffffffffffffffffff5f911680613f22575b50505050565b909192939450604090815185845260209384860151845283865114613fec575b6041865114613faa575b6060528083527f1626ba7e000000000000000000000000000000000000000000000000000000009485825260049687830152602482019687948552815186019081604493848601925afa503d01915afa91511416905f808080613f1c565b606080870151821a865284870151815260018681608085825afa5185183d151715613fd6575050613f4c565b935097965092935093509452525f808080613f1c565b83860151601b8160ff1c0186527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60609116815260018681608085825afa5185183d151715613fd6575050613f42565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000efe302beaa2b3e6e1b18d08d69a9012a1630148061414b575b156140a4577f2df49faf2f247a107fa56867bf43cc14fdf9d3f10e6f496d056b2691ec8f85df90565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f1fff4a77785eee286dafb0db6b1c7e21126d99ba99f92d2242416147d8f70a0160408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815260c0810181811067ffffffffffffffff821117613a5e5760405251902090565b507f00000000000000000000000000000000000000000000000000000000000b67d2461461407b565b919060207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925916141e18573ffffffffffffffffffffffffffffffffffffffff165f527f455730fed596673e69db1907be2e521374ba893f1a04cc5f5dd931616cd6b70160205260405f2090565b9473ffffffffffffffffffffffffffffffffffffffff80921695865f5283528460405f20556040519485521692a3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811461423e5760010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b805182101561427f5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f01000000000000000000000000000000000000000000000000000000000000008110156142f8577effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b6335278d125f526004601cfd5b9392909192742000000000000000000000000000000000000000007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416614487578142116144565773ffffffffffffffffffffffffffffffffffffffff9182861690815f527f69e87f5b9323740fce20cdf574dacd1d10e756da64a1f2df70fd1ace4c7cc30060205260405f208054906001820190556040519460208601937f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9855260408701528616606086015286608086015260a085015260c084015260c0835260e083019083821067ffffffffffffffff831117613a5e5761441c936144169260405251902061126b61403c565b85613efa565b1561442c5761442a92614174565b565b60046040517f4f8bbd8d000000000000000000000000000000000000000000000000000000008152fd5b602482604051907fa546f0e30000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517fe283c875000000000000000000000000000000000000000000000000000000008152fd

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000efe302beaa2b3e6e1b18d08d69a9012a0000000000000000000000000000000000000000000000000000000000000004415553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044155534400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c41676f726120446f6c6c6172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013100000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _params (tuple):
Arg [1] : name (string): AUSD
Arg [2] : symbol (string): AUSD
Arg [3] : eip712Name (string): Agora Dollar
Arg [4] : eip712Version (string): 1
Arg [5] : proxyAddress (address): 0x00000000eFE302BEAA2b3e6e1b18d08D69a9012a


-----Encoded View---------------
14 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [2] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [5] : 00000000000000000000000000000000efe302beaa2b3e6e1b18d08d69a9012a
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [7] : 4155534400000000000000000000000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [9] : 4155534400000000000000000000000000000000000000000000000000000000
Arg [10] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [11] : 41676f726120446f6c6c61720000000000000000000000000000000000000000
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [13] : 3100000000000000000000000000000000000000000000000000000000000000


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.