Sepolia Testnet

Contract

0xC0A9A6cf5d6873523da5B372e326e0668871d377
Source Code Source Code

Overview

ETH Balance

0 ETH

More Info

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Amount
Deploy103286772026-02-24 17:58:4813 days ago1771955928IN
0xC0A9A6cf...68871d377
0 ETH0.000011960.00100001
Deploy103208212026-02-23 14:09:3614 days ago1771855776IN
0xC0A9A6cf...68871d377
0 ETH0.000011960.00100001
Deploy101550492026-01-30 11:25:3638 days ago1769772336IN
0xC0A9A6cf...68871d377
0 ETH0.012401231.03938912
Deploy101548142026-01-30 10:36:2438 days ago1769769384IN
0xC0A9A6cf...68871d377
0 ETH0.01246711.04308959
Deploy101543402026-01-30 8:59:1238 days ago1769763552IN
0xC0A9A6cf...68871d377
0 ETH0.011718890.97974206
Deploy100058722026-01-09 0:18:4859 days ago1767917928IN
0xC0A9A6cf...68871d377
0 ETH0.000011960.001
Deploy100039932026-01-08 17:08:4860 days ago1767892128IN
0xC0A9A6cf...68871d377
0 ETH0.000250050.02090566
Deploy99894972026-01-06 9:57:4862 days ago1767693468IN
0xC0A9A6cf...68871d377
0 ETH0.000011960.001
Deploy96915552025-11-23 18:37:12106 days ago1763923032IN
0xC0A9A6cf...68871d377
0 ETH0.000011960.001
Deploy96295632025-11-14 16:51:12115 days ago1763139072IN
0xC0A9A6cf...68871d377
0 ETH0.000011960.001
Deploy94544562025-10-20 20:17:24140 days ago1760991444IN
0xC0A9A6cf...68871d377
0 ETH0.000011960.001
Deploy93694252025-10-08 15:21:36152 days ago1759936896IN
0xC0A9A6cf...68871d377
0 ETH0.000012070.00100958
Deploy93694172025-10-08 15:20:00152 days ago1759936800IN
0xC0A9A6cf...68871d377
0 ETH0.000012070.0010097
Deploy93482082025-10-05 12:09:36155 days ago1759666176IN
0xC0A9A6cf...68871d377
0 ETH0.000011960.00100001
Deploy90705302025-08-26 21:35:36194 days ago1756244136IN
0xC0A9A6cf...68871d377
0 ETH0.000445050.03720891
Deploy83976512025-05-24 16:53:48289 days ago1748105628IN
0xC0A9A6cf...68871d377
0 ETH0.004889350.40877037
Deploy82817082025-05-08 10:29:00305 days ago1746700140IN
0xC0A9A6cf...68871d377
0 ETH0.043518711.57892973
Deploy82423832025-05-02 20:00:00311 days ago1746216000IN
0xC0A9A6cf...68871d377
0 ETH0.027672696.01643024
Deploy82101402025-04-28 2:50:12315 days ago1745808612IN
0xC0A9A6cf...68871d377
0 ETH0.036135299.1464734
Deploy81865292025-04-24 14:43:36319 days ago1745505816IN
0xC0A9A6cf...68871d377
0 ETH0.128159439.09872545
Deploy80930282025-04-10 21:04:12332 days ago1744319052IN
0xC0A9A6cf...68871d377
0 ETH0.000011960.00100001
Deploy79936192025-03-27 16:14:12347 days ago1743092052IN
0xC0A9A6cf...68871d377
0 ETH0.009380640.78426091
Deploy79228802025-03-17 19:02:24357 days ago1742238144IN
0xC0A9A6cf...68871d377
0 ETH0.000048730.00407404
Deploy79210102025-03-17 12:47:36357 days ago1742215656IN
0xC0A9A6cf...68871d377
0 ETH0.023106224.74855763
Deploy78211882025-03-03 2:46:12371 days ago1740969972IN
0xC0A9A6cf...68871d377
0 ETH0.024201875.04017684
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Amount
0x60806040103286772026-02-24 17:58:4813 days ago1771955928
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x61010060103286772026-02-24 17:58:4813 days ago1771955928
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x60806040103208212026-02-23 14:09:3614 days ago1771855776
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x61010060103208212026-02-23 14:09:3614 days ago1771855776
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x60806040101550492026-01-30 11:25:3638 days ago1769772336
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x61010060101550492026-01-30 11:25:3638 days ago1769772336
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x60806040101548142026-01-30 10:36:2438 days ago1769769384
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x61010060101548142026-01-30 10:36:2438 days ago1769769384
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x60806040101543402026-01-30 8:59:1238 days ago1769763552
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x61010060101543402026-01-30 8:59:1238 days ago1769763552
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x60806040100058722026-01-09 0:18:4859 days ago1767917928
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x61010060100058722026-01-09 0:18:4859 days ago1767917928
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x60806040100039932026-01-08 17:08:4860 days ago1767892128
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x61010060100039932026-01-08 17:08:4860 days ago1767892128
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x6080604099894972026-01-06 9:57:4862 days ago1767693468
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x6101006099894972026-01-06 9:57:4862 days ago1767693468
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x6080604096915552025-11-23 18:37:12106 days ago1763923032
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x6101006096915552025-11-23 18:37:12106 days ago1763923032
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x6080604096295632025-11-14 16:51:12115 days ago1763139072
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x6101006096295632025-11-14 16:51:12115 days ago1763139072
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x6080604094544562025-10-20 20:17:24140 days ago1760991444
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x6101006094544562025-10-20 20:17:24140 days ago1760991444
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x6080604093694252025-10-08 15:21:36152 days ago1759936896
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x6101006093694252025-10-08 15:21:36152 days ago1759936896
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
0x6080604093694172025-10-08 15:20:00152 days ago1759936800
0xC0A9A6cf...68871d377
 Contract Creation0 ETH
View All Internal Transactions
Loading...
Loading
Loading...
Loading

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
L1OpUSDCFactory

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2024-08-21
*/

// SPDX-License-Identifier: MIT
pragma solidity =0.8.25 ^0.8.20;

// node_modules/@openzeppelin/contracts/interfaces/IERC1271.sol

// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol)

/**
 * @dev Interface of the ERC1271 standard signature validation method for
 * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
 */
interface IERC1271 {
    /**
     * @dev Should return whether the signature provided is valid for the provided data
     * @param hash      Hash of the data to be signed
     * @param signature Signature byte array associated with _data
     */
    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}

// node_modules/@openzeppelin/contracts/interfaces/IERC5267.sol

// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)

interface IERC5267 {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}

// node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol

// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822Proxiable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

// node_modules/@openzeppelin/contracts/proxy/Proxy.sol

// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)

/**
 * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
 * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
 * be specified by overriding the virtual {_implementation} function.
 *
 * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
 * different contract through the {_delegate} function.
 *
 * The success and return data of the delegated call will be returned back to the caller of the proxy.
 */
abstract contract Proxy {
    /**
     * @dev Delegates the current call to `implementation`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _delegate(address implementation) internal virtual {
        assembly {
            // Copy msg.data. We take full control of memory in this inline assembly
            // block because it will not return to Solidity code. We overwrite the
            // Solidity scratch pad at memory position 0.
            calldatacopy(0, 0, calldatasize())

            // Call the implementation.
            // out and outsize are 0 because we don't know the size yet.
            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

            // Copy the returned data.
            returndatacopy(0, 0, returndatasize())

            switch result
            // delegatecall returns 0 on error.
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }

    /**
     * @dev This is a virtual function that should be overridden so it returns the address to which the fallback
     * function and {_fallback} should delegate.
     */
    function _implementation() internal view virtual returns (address);

    /**
     * @dev Delegates the current call to the address returned by `_implementation()`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _fallback() internal virtual {
        _delegate(_implementation());
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
     * function in the contract matches the call data.
     */
    fallback() external payable virtual {
        _fallback();
    }
}

// node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol

// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeacon {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {UpgradeableBeacon} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol

// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol

// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// node_modules/@openzeppelin/contracts/utils/Address.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}

// node_modules/@openzeppelin/contracts/utils/Context.sol

// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// node_modules/@openzeppelin/contracts/utils/StorageSlot.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

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

// node_modules/@openzeppelin/contracts/utils/cryptography/ECDSA.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError, bytes32) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}

// node_modules/@openzeppelin/contracts/utils/math/Math.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

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

// node_modules/@openzeppelin/contracts/utils/math/SignedMath.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

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

// node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol

// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

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

// src/contracts/utils/USDCProxyCreationCode.sol

// Native USDC proxy contract bytecode on mainnet:
// https://optimistic.etherscan.io/token/0x0b2c639c533813f4aa9d7837caf62653d097ff85#code
bytes constant USDC_PROXY_CREATION_CODE =
// solhint-disable-next-line max-line-length
  hex'608060405234801561001057600080fd5b506040516108a93803806108a98339818101604052602081101561003357600080fd5b5051808061004081610051565b5061004a336100c3565b5050610123565b610064816100e760201b61042a1760201c565b61009f5760405162461bcd60e51b815260040180806020018281038252603b81526020018061086e603b913960400191505060405180910390fd5b7f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c355565b7f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b55565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061011b57508115155b949350505050565b61073c806101326000396000f3fe60806040526004361061005a5760003560e01c80635c60da1b116100435780635c60da1b146101315780638f2839701461016f578063f851a440146101af5761005a565b80633659cfe6146100645780634f1ef286146100a4575b6100626101c4565b005b34801561007057600080fd5b506100626004803603602081101561008757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166101de565b610062600480360360408110156100ba57600080fd5b73ffffffffffffffffffffffffffffffffffffffff82351691908101906040810160208201356401000000008111156100f257600080fd5b82018360208201111561010457600080fd5b8035906020019184600183028401116401000000008311171561012657600080fd5b509092509050610232565b34801561013d57600080fd5b50610146610309565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561017b57600080fd5b506100626004803603602081101561019257600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610318565b3480156101bb57600080fd5b50610146610420565b6101cc610466565b6101dc6101d76104fa565b61051f565b565b6101e6610543565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102275761022281610568565b61022f565b61022f6101c4565b50565b61023a610543565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102fc5761027683610568565b60003073ffffffffffffffffffffffffffffffffffffffff16348484604051808383808284376040519201945060009350909150508083038185875af1925050503d80600081146102e3576040519150601f19603f3d011682016040523d82523d6000602084013e6102e8565b606091505b50509050806102f657600080fd5b50610304565b6103046101c4565b505050565b60006103136104fa565b905090565b610320610543565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102275773ffffffffffffffffffffffffffffffffffffffff81166103bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260368152602001806106966036913960400191505060405180910390fd5b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103e8610543565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301528051918290030190a1610222816105bd565b6000610313610543565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061045e57508115155b949350505050565b61046e610543565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156104f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001806106646032913960400191505060405180910390fd5b6101dc6101dc565b7f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c35490565b3660008037600080366000845af43d6000803e80801561053e573d6000f35b3d6000fd5b7f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b5490565b610571816105e1565b6040805173ffffffffffffffffffffffffffffffffffffffff8316815290517fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b9181900360200190a150565b7f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b55565b6105ea8161042a565b61063f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603b8152602001806106cc603b913960400191505060405180910390fd5b7f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c35556fe43616e6e6f742063616c6c2066616c6c6261636b2066756e6374696f6e2066726f6d207468652070726f78792061646d696e43616e6e6f74206368616e6765207468652061646d696e206f6620612070726f787920746f20746865207a65726f206164647265737343616e6e6f742073657420612070726f787920696d706c656d656e746174696f6e20746f2061206e6f6e2d636f6e74726163742061646472657373a2646970667358221220046bec85a39556fa01d3014f9bbd881bf3dfd8a920836836698508b80c55e88964736f6c634300060c003343616e6e6f742073657420612070726f787920696d706c656d656e746174696f6e20746f2061206e6f6e2d636f6e74726163742061646472657373';

// src/interfaces/IL1OpUSDCBridgeAdapter.sol

interface IL1OpUSDCBridgeAdapter {
  /*///////////////////////////////////////////////////////////////
                            EVENTS
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Emitted when the burn amount is set
   * @param _burnAmount The amount to be burned
   */
  event BurnAmountSet(uint256 _burnAmount);

  /**
   * @notice Emitted when the migration process is complete
   * @param _burnedAmount The amount of USDC tokens that were burned
   */
  event MigrationComplete(uint256 _burnedAmount);

  /*///////////////////////////////////////////////////////////////
                            LOGIC
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Initiates the process to migrate the bridged USDC to native USDC
   * @param _roleCaller The address that will be allowed to transfer the usdc roles
   * @param _burnCaller The address that will be allowed to call this contract to burn the USDC tokens
   * @param _minGasLimitReceiveOnL2 Minimum gas limit that the message can be executed with on L2
   * @param _minGasLimitSetBurnAmount Minimum gas limit that the message can be executed with to set the burn amount
   */
  function migrateToNative(
    address _roleCaller,
    address _burnCaller,
    uint32 _minGasLimitReceiveOnL2,
    uint32 _minGasLimitSetBurnAmount
  ) external;

  /**
   * @notice Sets the amount of USDC tokens that will be burned when the burnLockedUSDC function is called
   * @param _amount The amount of USDC tokens that will be burned
   * @dev Only callable by a whitelisted messenger during its migration process
   */
  function setBurnAmount(uint256 _amount) external;

  /**
   * @notice Burns the USDC tokens locked in the contract
   * @dev The amount is determined by the burnAmount variable, which is set in the setBurnAmount function
   */
  function burnLockedUSDC() external;

  /**
   * @notice Send a message to the linked adapter to call receiveStopMessaging() and stop outgoing messages.
   * @dev Only callable by the owner of the adapter
   * @dev Setting isMessagingDisabled to true is an irreversible operation
   * @param _minGasLimit Minimum gas limit that the message can be executed with
   */
  function stopMessaging(uint32 _minGasLimit) external;

  /**
   * @notice Resume messaging on the messenger
   * @dev Only callable by the owner
   * @dev Can't resume deprecated messengers
   * @param _minGasLimit Minimum gas limit that the message can be executed with
   */
  function resumeMessaging(uint32 _minGasLimit) external;

  /**
   * @notice Receives a message from L2 if the adapter is deprecated and a user is withdrawing locked funds
   * @dev If the _spender is still locked, the user will be forced to replay this message
   * @param _spender The user that initially provided the tokens
   * @param _amount The amount of tokens to withdraw
   */
  function receiveWithdrawLockedFundsPostMigration(address _spender, uint256 _amount) external;

  /*///////////////////////////////////////////////////////////////
                            VARIABLES
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Fetches the amount of USDC tokens that will be burned when the burnLockedUSDC function is called
   * @return _burnAmount The amount of USDC tokens that will be burned
   */
  function burnAmount() external view returns (uint256 _burnAmount);

  /**
   * @notice Fetches the address of the burn caller
   * @return _burnCaller The address of the burn caller
   */
  function burnCaller() external view returns (address _burnCaller);
}

// src/interfaces/IL2OpUSDCDeploy.sol

interface IL2OpUSDCDeploy {
  /*///////////////////////////////////////////////////////////////
                            STRUCTS
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice The struct to hold the USDC data for the name, symbol, currency, and decimals when initializing
   * @param tokenName The name of the USDC token
   * @param tokenSymbol The symbol of the USDC token
   * @param tokenCurrency The currency that the USDC token represents
   * @param tokenDecimals The number of decimals that the USDC token uses
   */
  struct USDCInitializeData {
    string tokenName;
    string tokenSymbol;
    string tokenCurrency;
    uint8 tokenDecimals;
  }

  /*///////////////////////////////////////////////////////////////
                            EVENTS
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Emitted when the USDC implementation is deployed
   * @param _l2UsdcImplementation The address of the L2 USDC implementation
   */
  event USDCImplementationDeployed(address _l2UsdcImplementation);

  /**
   * @notice Emitted when the USDC proxy is deployed
   * @param _l2UsdcProxy The address of the L2 USDC proxy
   */
  event USDCProxyDeployed(address _l2UsdcProxy);

  /**
   * @notice Emitted when the L2 adapter is deployed
   * @param _l2Adapter The address of the L2 adapter
   */
  event L2AdapterDeployed(address _l2Adapter);

  /*///////////////////////////////////////////////////////////////
                            ERRORS
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Thrown when a contract deployment fails
   */
  error IL2OpUSDCDeploy_DeploymentFailed();

  /**
   * @notice Thrown when an USDC initialization tx failed
   * @param _txIndex The index of the failed initialization tx
   */
  error IL2OpUSDCDeploy_InitializationFailed(uint256 _txIndex);
}

// src/interfaces/IOpUSDCBridgeAdapter.sol

interface IOpUSDCBridgeAdapter {
  /*///////////////////////////////////////////////////////////////
                            ENUMS
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice The status of an L1 Messenger
   * @param Active The messenger is active
   * @param Paused The messenger is paused
   * @param Upgrading The messenger is upgrading
   * @param Deprecated The messenger is deprecated
   */
  enum Status {
    Active,
    Paused,
    Upgrading,
    Deprecated
  }

  /*///////////////////////////////////////////////////////////////
                          STRUCTS
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice The struct to hold the data for a bridge message with signature
   * @param to The target address on the destination chain
   * @param amount The amount of tokens to send
   * @param deadline The deadline for the message to be executed
   * @param nonce The nonce of the user
   * @param minGasLimit The minimum gas limit for the message to be executed
   */
  struct BridgeMessage {
    address to;
    uint256 amount;
    uint256 deadline;
    uint256 nonce;
    uint32 minGasLimit;
  }

  /*///////////////////////////////////////////////////////////////
                            EVENTS
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Emitted when messaging is stopped
   * @param _messenger The address of the messenger contract that was stopped
   */
  event MessagingStopped(address _messenger);

  /**
   * @notice Emitted when a message is sent to the linked adapter
   * @param _user The user that sent the message
   * @param _to The target address on the destination chain
   * @param _amount The amount of tokens to send
   * @param _messenger The address of the messenger contract that was sent through
   * @param _minGasLimit Minimum gas limit that the message can be executed with
   */
  event MessageSent(
    address indexed _user, address indexed _to, uint256 _amount, address indexed _messenger, uint32 _minGasLimit
  );

  /**
   * @notice Emitted when a message as received
   * @param _spender The address that provided the tokens
   * @param _user The user that received the message
   * @param _amount The amount of tokens received
   * @param _messenger The address of the messenger contract that was received through
   */
  event MessageReceived(address indexed _spender, address indexed _user, uint256 _amount, address indexed _messenger);

  /**
   * @notice Emitted when messaging is resumed
   * @param _messenger The address of the messenger that was resumed
   */
  event MessagingResumed(address _messenger);

  /**
   * @notice Emitted when the adapter is migrating usdc to native
   * @param _messenger The address of the messenger contract that is doing the migration
   * @param _caller The address that will be allowed to call the permissioned function on the given chain
   * @dev On L1 _caller can call burnLockedUSDC
   * @dev On L2 _caller can call transferUSDCRoles
   */
  event MigratingToNative(address _messenger, address _caller);

  /**
   * @notice Emitted when a message fails
   * @param _spender The address that provided the tokens
   * @param _user The user that the message failed for
   * @param _amount The amount of tokens that were added to the blacklisted funds
   * @param _messenger The address of the messenger that the message failed for
   */
  event MessageFailed(address indexed _spender, address indexed _user, uint256 _amount, address indexed _messenger);

  /**
   * @notice Emitted when the any previously locked funds are withdrawn outside of the traditional bridging flows
   * @param _user The user that the funds were withdrawn for
   * @param _amountWithdrawn The amount of tokens that were withdrawn
   */
  event LockedFundsWithdrawn(address indexed _user, uint256 _amountWithdrawn);

  /**
   * @notice Emitted when a nonce is canceled
   * @param _caller The caller
   * @param _nonce The nonce that was canceled
   */
  event NonceCanceled(address _caller, uint256 _nonce);

  /*///////////////////////////////////////////////////////////////
                            ERRORS
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Error when burnLockedUSDC is called before a burn amount is set
   */
  error IOpUSDCBridgeAdapter_BurnAmountNotSet();

  /**
   * @notice Error when the caller is not the roleCaller
   */
  error IOpUSDCBridgeAdapter_InvalidCaller();

  /**
   * @notice Error when address is not valid
   */
  error IOpUSDCBridgeAdapter_InvalidAddress();

  /**
   * @notice Error when the owner transaction is invalid
   */
  error IOpUSDCBridgeAdapter_InvalidTransaction();

  /**
   * @notice Error when signature is not valid
   */
  error IOpUSDCBridgeAdapter_ForbiddenTransaction();

  /**
   * @notice Error when messaging is disabled
   */
  error IOpUSDCBridgeAdapter_MessagingDisabled();

  /**
   * @notice Error when messaging is enabled
   */
  error IOpUSDCBridgeAdapter_MessagingEnabled();

  /**
   * @notice Error when the caller is not the linked adapter
   */
  error IOpUSDCBridgeAdapter_InvalidSender();

  /**
   * @notice Error when the nonce is already used for the given signature
   */
  error IOpUSDCBridgeAdapter_InvalidNonce();

  /**
   * @notice Error when the signature is invalid
   */
  error IOpUSDCBridgeAdapter_InvalidSignature();

  /**
   * @notice Error when the deadline has passed
   */
  error IOpUSDCBridgeAdapter_MessageExpired();

  /**
   * @notice Error when the contract is not in the upgrading state
   */
  error IOpUSDCBridgeAdapter_NotUpgrading();

  /**
   * @notice Error when the address is blacklisted
   */
  error IOpUSDCBridgeAdapter_BlacklistedAddress();

  /**
   *  @notice Error when bridgedUSDC has not been migrated yet to native USDC
   */
  error IOpUSDCBridgeAdapter_NotMigrated();

  /*///////////////////////////////////////////////////////////////
                            LOGIC
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Initialize the contract
   * @param _owner The owner of the contract
   * @dev This function needs only used during the deployment of the proxy contract, and it is disabled for the
   * implementation contract
   */
  function initialize(address _owner) external;

  /**
   * @notice Send tokens to another chain through the linked adapter
   * @param _to The target address on the destination chain
   * @param _amount The amount of tokens to send
   * @param _minGasLimit Minimum gas limit that the message can be executed with
   */
  function sendMessage(address _to, uint256 _amount, uint32 _minGasLimit) external;

  /**
   * @notice Send signer tokens to another chain through the linked adapter
   * @param _signer The address of the user sending the message
   * @param _to The target address on the destination chain
   * @param _amount The amount of tokens to send
   * @param _signature The signature of the user
   * @param _nonce The nonce of the user
   * @param _deadline The deadline for the message to be executed
   * @param _minGasLimit Minimum gas limit that the message can be executed with
   */
  function sendMessage(
    address _signer,
    address _to,
    uint256 _amount,
    bytes calldata _signature,
    uint256 _nonce,
    uint256 _deadline,
    uint32 _minGasLimit
  ) external;

  /**
   * @notice Receive the message from the other chain and mint or transfer tokens to the user
   * @dev This function should only be called when receiving a message to mint or transfer tokens
   * @param _user The user to mint or transfer the tokens for
   * @param _spender The address that provided the tokens
   * @param _amount The amount of tokens to transfer or mint
   */
  function receiveMessage(address _user, address _spender, uint256 _amount) external;

  /**
   * @notice Withdraws the locked funds from the contract if they get unlocked
   * @param _spender The address that provided the tokens
   * @param _user The user to withdraw the funds for
   */
  function withdrawLockedFunds(address _spender, address _user) external;

  /**
   * @notice Cancels a signature by setting the nonce as used
   * @param _nonce The nonce of the signature to cancel
   */
  function cancelSignature(uint256 _nonce) external;

  /*///////////////////////////////////////////////////////////////
                            VARIABLES
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Fetches address of the USDC token
   * @return _usdc Address of the USDC token
   */
  // solhint-disable-next-line func-name-mixedcase
  function USDC() external view returns (address _usdc);

  /**
   * @notice Fetches address of the linked adapter on L2 to send messages to and receive from
   * @return _linkedAdapter Address of the linked adapter
   */
  // solhint-disable-next-line func-name-mixedcase
  function LINKED_ADAPTER() external view returns (address _linkedAdapter);

  /**
   * @notice Fetches address of the CrossDomainMessenger to send messages to L1 <-> L2
   * @return _messenger Address of the messenger
   */
  // solhint-disable-next-line func-name-mixedcase
  function MESSENGER() external view returns (address _messenger);

  /**
   * @notice Fetches the status of the messenger
   * @return _status The status of the messenger
   */
  function messengerStatus() external view returns (Status _status);

  /**
   * @notice Returns the nonce of a given user to avoid replay attacks
   * @param _user The user to check for
   * @param _nonce The nonce to check for
   * @return _used If the nonce has been used
   */
  function userNonces(address _user, uint256 _nonce) external view returns (bool _used);

  /**
   * @notice Returns the amount of funds locked that got locked for a specific user
   * @param _spender The address that provided the tokens
   * @param _user The user to check for
   * @return _lockedAmount The amount of funds locked from locked messages
   */
  function lockedFundsDetails(address _spender, address _user) external view returns (uint256 _lockedAmount);
}

// src/interfaces/external/ICreate2Deployer.sol

interface ICreate2Deployer {
  /**
   * @notice Deploys a contract using the CREATE2 opcode
   * @param _value The value to send with the deployment
   * @param _salt The salt value to use for the deployment
   * @param _code The init code to deploy
   */
  function deploy(uint256 _value, bytes32 _salt, bytes memory _code) external;
}

// src/interfaces/external/ICrossDomainMessenger.sol

interface ICrossDomainMessenger {
  /**
   * @notice Sends a message to some target address on the other chain. Note that if the call
   *         always reverts, then the message will be unrelayable, and any ETH sent will be
   *         permanently locked. The same will occur if the target on the other chain is
   *         considered unsafe (see the _isUnsafeTarget() function).
   * @param _target      Target contract or wallet address.
   * @param _message     Message to trigger the target address with.
   * @param _minGasLimit Minimum gas limit that the message can be executed with.
   */
  function sendMessage(address _target, bytes calldata _message, uint32 _minGasLimit) external;

  /**
   * @notice Retrieves the address of the contract or wallet that initiated the currently
   *         executing message on the other chain. Will throw an error if there is no message
   *         currently being executed. Allows the recipient of a call to see who triggered it.
   * @return _sender Address of the sender of the currently executing message on the other chain.
   */
  function xDomainMessageSender() external view returns (address _sender);

  /**
   * @notice Returns the address of the portal.
   * @return _portal Address of the portal.
   */
  function portal() external view returns (address _portal);

  /**
   * @notice Returns the address of the portal.
   * @dev This is a legacy function that is used for any legacy messengers.
   * @return _portal Address of the portal.
   */
  // solhint-disable-next-line func-name-mixedcase
  function PORTAL() external view returns (address _portal);
}

// src/interfaces/external/IOptimismPortal.sol

interface IOptimismPortal {
  /**
   * @notice Accepts deposits of ETH and data, and emits a TransactionDeposited event for use in
   *         deriving deposit transactions. Note that if a deposit is made by a contract, its
   *         address will be aliased when retrieved using `tx.origin` or `msg.sender`. Consider
   *         using the CrossDomainMessenger contracts for a simpler developer experience.
   * @param _to         Target address on L2.
   * @param _value      ETH value to send to the recipient.
   * @param _gasLimit   Amount of L2 gas to purchase by burning gas on L1.
   * @param _isCreation Whether or not the transaction is a contract creation.
   * @param _data       Data to trigger the recipient with.
   */
  function depositTransaction(
    address _to,
    uint256 _value,
    uint64 _gasLimit,
    bool _isCreation,
    bytes memory _data
  ) external payable;
}

// node_modules/@openzeppelin/contracts/access/Ownable.sol

// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// node_modules/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol

// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// src/interfaces/external/IUSDC.sol

interface IUSDC is IERC20 {
  /**
   * @notice Mints USDC tokens
   * @param _to Address to mint tokens to
   * @param _amount Amount of tokens to mint
   */
  function mint(address _to, uint256 _amount) external;

  /**
   * @notice allows a minter to burn some of its own tokens
   * Validates that caller is a minter and that sender is not blacklisted
   * amount is less than or equal to the minter's account balance
   * @param _amount uint256 the amount of tokens to be burned
   */
  function burn(uint256 _amount) external;

  /**
   * @notice Transfers USDC ownership  to another address
   * @param _newOwner Address to transfer ownership to
   */
  function transferOwnership(address _newOwner) external;

  /**
   * @dev Changes the admin of the proxy.
   * Only the current admin can call this function.
   * @param newAdmin Address to transfer proxy administration to.
   */
  function changeAdmin(address newAdmin) external;

  /**
   * @notice Initializes the fiat token contract.
   * @param _tokenName       The name of the fiat token.
   * @param _tokenSymbol     The symbol of the fiat token.
   * @param _tokenCurrency   The fiat currency that the token represents.
   * @param _tokenDecimals   The number of decimals that the token uses.
   * @param _newMasterMinter The masterMinter address for the fiat token.
   * @param _newPauser       The pauser address for the fiat token.
   * @param _newBlacklister  The blacklister address for the fiat token.
   * @param _newOwner        The owner of the fiat token.
   */
  function initialize(
    string memory _tokenName,
    string memory _tokenSymbol,
    string memory _tokenCurrency,
    uint8 _tokenDecimals,
    address _newMasterMinter,
    address _newPauser,
    address _newBlacklister,
    address _newOwner
  ) external;

  /**
   * @notice Initialize v2
   * @param _newName   New token name
   */
  // solhint-disable-next-line func-name-mixedcase
  function initializeV2(string calldata _newName) external;

  /**
   * @notice Initialize v2.1
   * @param _lostAndFound  The address to which the locked funds are sent
   */
  // solhint-disable-next-line func-name-mixedcase
  function initializeV2_1(address _lostAndFound) external;

  /**
   * @notice Initialize v2.2
   * @param _accountsToBlacklist   A list of accounts to migrate from the old blacklist
   * @param _newSymbol             New token symbol
   * data structure to the new blacklist data structure.
   */
  // solhint-disable-next-line func-name-mixedcase
  function initializeV2_2(address[] calldata _accountsToBlacklist, string calldata _newSymbol) external;

  /**
   * @dev Function to add/update a new minter
   * @param _minter The address of the minter
   * @param _minterAllowedAmount The minting amount allowed for the minter
   * @return _result True if the operation was successful.
   */
  function configureMinter(address _minter, uint256 _minterAllowedAmount) external returns (bool _result);

  /**
   * @notice Removes a minter.
   * @param _minter The address of the minter to remove.
   * @return _result True if the operation was successful.
   */
  function removeMinter(address _minter) external returns (bool _result);

  /**
   * @notice Updates the master minter address.
   * @param _newMasterMinter The address of the new master minter.
   */
  function updateMasterMinter(address _newMasterMinter) external;

  /**
   * @notice Adds account to blacklist
   * @param _account The address to blacklist
   */
  function blacklist(address _account) external;

  /**
   * @notice Removes account from blacklist.
   * @param _account The address to remove from the blacklist.
   */
  function unBlacklist(address _account) external;

  /**
   * @notice Function to upgrade the usdc proxy to a new implementation
   * @param _newImplementation Address of the new implementation
   */
  function upgradeTo(address _newImplementation) external;

  /**
   * @notice Upgrades the USDC proxy to a new implementation and calls a function on the new implementation
   * @param _newImplementation Address of the new implementation
   * @param _data Data to call on the new implementation
   */
  function upgradeToAndCall(address _newImplementation, bytes calldata _data) external;

  /**
   * @notice Returns the current implementation address
   * @return _implementation Address of the current implementation
   */
  function implementation() external view returns (address _implementation);

  /**
   * @notice Returns the current master minter address
   * @return _masterMinter Address of the current master minter
   */
  function masterMinter() external view returns (address _masterMinter);

  /**
   * @notice Returns the current owner address
   * @return _owner Address of the current owner
   */
  function owner() external view returns (address _owner);

  /**
   * @return _currency The currency of the token
   */
  function currency() external view returns (string memory _currency);

  /**
   * @return _decimals The decimals of the token
   */
  function decimals() external view returns (uint8 _decimals);

  /**
   * @return _name The name of the token
   */
  function name() external view returns (string memory _name);

  /**
   * @return _symbol The symbol of the token
   */
  function symbol() external view returns (string memory _symbol);

  /**
   * @notice Checks if an account is a minter.
   * @param _account The address to check.
   * @return _isMinter True if the account is a minter, false if the account is not a minter.
   */
  function isMinter(address _account) external view returns (bool _isMinter);

  /**
   * @notice Returns the allowance of a minter
   * @param _minter The address of the minter
   * @return _allowance The minting amount allowed for the minter
   */
  function minterAllowance(address _minter) external view returns (uint256 _allowance);

  /**
   * @notice Returns the address of the current pauser
   * @return _pauser Address of the current pauser
   */
  function pauser() external view returns (address _pauser);

  /**
   * @notice Returns the address of the current blacklister
   * @return _blacklister Address of the current blacklister
   */
  function blacklister() external view returns (address _blacklister);

  /**
   * @notice Checks if account is blacklisted
   * @param _account The address to check
   * @return _result True if the account is blacklisted, false if not
   */
  function isBlacklisted(address _account) external view returns (bool _result);

  /**
   * @notice Returns the address of the current admin
   * @return _admin Address of the current admin
   */
  function admin() external view returns (address _admin);
}

// node_modules/@openzeppelin/contracts/utils/Strings.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.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));
    }
}

// node_modules/@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/SignatureChecker.sol)

/**
 * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
 * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
 * Argent and Safe Wallet (previously Gnosis Safe).
 */
library SignatureChecker {
    /**
     * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
     * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
        (address recovered, ECDSA.RecoverError error, ) = ECDSA.tryRecover(hash, signature);
        return
            (error == ECDSA.RecoverError.NoError && recovered == signer) ||
            isValidERC1271SignatureNow(signer, hash, signature);
    }

    /**
     * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
     * against the signer smart contract using ERC1271.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidERC1271SignatureNow(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) internal view returns (bool) {
        (bool success, bytes memory result) = signer.staticcall(
            abi.encodeCall(IERC1271.isValidSignature, (hash, signature))
        );
        return (success &&
            result.length >= 32 &&
            abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
    }
}

// node_modules/@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol

// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Ownable
    struct OwnableStorage {
        address _owner;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;

    function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
        assembly {
            $.slot := OwnableStorageLocation
        }
    }

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    function __Ownable_init(address initialOwner) internal onlyInitializing {
        __Ownable_init_unchained(initialOwner);
    }

    function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        OwnableStorage storage $ = _getOwnableStorage();
        return $._owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        OwnableStorage storage $ = _getOwnableStorage();
        address oldOwner = $._owner;
        $._owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// src/interfaces/IL1OpUSDCFactory.sol

// solhint-disable func-name-mixedcase
interface IL1OpUSDCFactory {
  /**
   * @notice The struct to hold the deployments data to deploy the L2 Factory, L2 adapter, and the L2 USDC contracts
   * @param l2AdapterOwner The address of the owner of the L2 adapter
   * @param usdcImplAddr The address of the USDC implementation on L2 to connect the proxy to
   * @param minGasLimitDeploy The minimum gas limit for deploying the L2 Deploy, L2 adapter, and L2 USDC proxy
   * @param usdcInitTxs The initialization transactions to be executed on the USDC contract. The `initialize()` first
   * init tx must not be included since it is defined in the L2 factory contract
   */
  struct L2Deployments {
    address l2AdapterOwner;
    address usdcImplAddr;
    uint32 minGasLimitDeploy;
    bytes[] usdcInitTxs;
  }

  /*///////////////////////////////////////////////////////////////
                            EVENTS
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Emitted when the `L1OpUSDCBridgeAdapter` is deployed
   * @param _l1Adapter The address of the L1 adapter
   * @param _l2Deploy The address of the L2 deployer contract
   * @param _l2Adapter The address of the L2 adapter
   */
  event ProtocolDeployed(address _l1Adapter, address _l2Deploy, address _l2Adapter);

  /*///////////////////////////////////////////////////////////////
                            ERRORS
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Thrown when the `initialize()` tx is provided as the first init tx for the USDC contract
   */
  error IL1OpUSDCFactory_NoInitializeTx();

  /*///////////////////////////////////////////////////////////////
                            LOGIC
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Deploys the L1 Adapter, and sends the deployment txs for the L2 factory, L2 adapter and the L2 USDC through
   * the L1 messenger
   * @param _l1Messenger The address of the L1 messenger for the L2 Op chain
   * @param _l1AdapterOwner The address of the owner of the L1 adapter
   * @param _chainName The name of the L2 Op chain
   * @param _l2Deployments The deployments data for the L2 adapter, and the L2 USDC contracts
   * @return _l1Adapter The address of the L1 adapter
   * @return _l2Deploy The address of the L2 deployer contract
   * @return _l2Adapter The address of the L2 adapter
   * @dev It can fail on L2 due to a gas miscalculation, but in that case the tx can be replayed. It only deploys 1 L2
   * factory per L2 deployments, to make sure the nonce is being tracked correctly while precalculating addresses
   * @dev The implementation of the USDC contract needs to be deployed on L2 before this is called
   * Then set the `usdcImplAddr` in the L2Deployments struct to the address of the deployed USDC implementation contract
   *
   * @dev IMPORTANT!!!!
   * The _l2Deployments.usdcInitTxs must be manually entered to correctly initialize the USDC contract on L2.
   * If a function is not included in the init txs, it could lead to potential attack vectors.
   * We currently hardcode the `initialize()` function in the L2 factory contract, to correctly configure the setup
   * You must provide the following init txs:
   * - initalizeV2
   * - initilizeV2_1
   * - initializeV2_2
   *
   * It is also important to note that circle may add more init functions in future implementations
   * This is up to the deployer to check and be sure all init transactions are included
   */
  function deploy(
    address _l1Messenger,
    address _l1AdapterOwner,
    string calldata _chainName,
    L2Deployments calldata _l2Deployments
  ) external returns (address _l1Adapter, address _l2Deploy, address _l2Adapter);

  /*///////////////////////////////////////////////////////////////
                            VARIABLES
  ///////////////////////////////////////////////////////////////*/

  /**
   * @return _l2Create2Deployer The address of the `create2Deployer` contract on L2
   */
  function L2_CREATE2_DEPLOYER() external view returns (address _l2Create2Deployer);

  /**
   * @return _usdc The address of USDC on L1
   */
  function USDC() external view returns (IUSDC _usdc);

  /**
   * @return _name The name of the USDC token
   * @dev If the 3rd party team wants to update the name, it can be done on the `initialize2()` 2nd init tx
   */
  function USDC_NAME() external view returns (string memory _name);

  /**
   * @return _symbol The symbol of the USDC token
   */
  function USDC_SYMBOL() external view returns (string memory _symbol);

  /**
   * @return _deploymentsSaltCounter The counter for the deployments salt to be used on the L2 factory deployment
   */
  function deploymentsSaltCounter() external view returns (uint256 _deploymentsSaltCounter);
}

// node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol

// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 */
library ERC1967Utils {
    // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
    // This will be fixed in Solidity 0.8.21. At that point we should remove these events.
    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Emitted when the beacon is changed.
     */
    event BeaconUpgraded(address indexed beacon);

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev The `implementation` of the proxy is invalid.
     */
    error ERC1967InvalidImplementation(address implementation);

    /**
     * @dev The `admin` of the proxy is invalid.
     */
    error ERC1967InvalidAdmin(address admin);

    /**
     * @dev The `beacon` of the proxy is invalid.
     */
    error ERC1967InvalidBeacon(address beacon);

    /**
     * @dev An upgrade function sees `msg.value > 0` that may be lost.
     */
    error ERC1967NonPayable();

    /**
     * @dev Returns the current implementation address.
     */
    function getImplementation() internal view returns (address) {
        return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        if (newImplementation.code.length == 0) {
            revert ERC1967InvalidImplementation(newImplementation);
        }
        StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Performs implementation upgrade with additional setup call if data is nonempty.
     * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
     * to avoid stuck value in the contract.
     *
     * Emits an {IERC1967-Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);

        if (data.length > 0) {
            Address.functionDelegateCall(newImplementation, data);
        } else {
            _checkNonPayable();
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Returns the current admin.
     *
     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
     * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
     * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
     */
    function getAdmin() internal view returns (address) {
        return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        if (newAdmin == address(0)) {
            revert ERC1967InvalidAdmin(address(0));
        }
        StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {IERC1967-AdminChanged} event.
     */
    function changeAdmin(address newAdmin) internal {
        emit AdminChanged(getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Returns the current beacon.
     */
    function getBeacon() internal view returns (address) {
        return StorageSlot.getAddressSlot(BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        if (newBeacon.code.length == 0) {
            revert ERC1967InvalidBeacon(newBeacon);
        }

        StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;

        address beaconImplementation = IBeacon(newBeacon).implementation();
        if (beaconImplementation.code.length == 0) {
            revert ERC1967InvalidImplementation(beaconImplementation);
        }
    }

    /**
     * @dev Change the beacon and trigger a setup call if data is nonempty.
     * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
     * to avoid stuck value in the contract.
     *
     * Emits an {IERC1967-BeaconUpgraded} event.
     *
     * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
     * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
     * efficiency.
     */
    function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);

        if (data.length > 0) {
            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
        } else {
            _checkNonPayable();
        }
    }

    /**
     * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
     * if an upgrade doesn't perform an initialization call.
     */
    function _checkNonPayable() private {
        if (msg.value > 0) {
            revert ERC1967NonPayable();
        }
    }
}

// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol

// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

// node_modules/@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.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)
        }
    }
}

// src/contracts/utils/FallbackProxyAdmin.sol

/**
 * @title FallbackProxyAdmin
 * @notice Middleware contract for the L2 Adapter to interact with the USDC proxy.
 * @dev The admin can't call the fallback function of the USDC proxy, meaning it can't interact with the functions
 * such as mint and burn between others. Because of this, the FallbackProxyAdmin contract is used as a middleware,
 * being controlled by the L2OpUSDCBridgeAdapter contract and allowing to call the admin functions through it while
 * also being able to call the fallback function of the USDC proxy.
 */
contract FallbackProxyAdmin is Ownable {
  /// @notice USDC address
  address public immutable USDC;

  /**
   * @notice Construct the FallbackProxyAdmin contract
   * @param _usdc USDC address
   */
  constructor(address _usdc) Ownable(msg.sender) {
    USDC = _usdc;
  }

  /**
   * @notice Changes the admin of the USDC proxy
   * @param _newAdmin Address to transfer proxy administration to
   * @dev Owner should always be the L2 Adapter
   * @dev USDC admin cant interact proxy with implementation so we use this contract as the middleman
   */
  function changeAdmin(address _newAdmin) external onlyOwner {
    IUSDC(USDC).changeAdmin(_newAdmin);
  }

  /**
   * @notice Function to upgrade the usdc proxy to a new implementation
   * @param _newImplementation Address of the new implementation
   */
  function upgradeTo(address _newImplementation) external onlyOwner {
    IUSDC(USDC).upgradeTo(_newImplementation);
  }

  /**
   * @notice Upgrades the USDC proxy to a new implementation and calls a function on the new implementation
   * @param _newImplementation Address of the new implementation
   * @param _data Data to call on the new implementation
   */
  function upgradeToAndCall(address _newImplementation, bytes calldata _data) external onlyOwner {
    IUSDC(USDC).upgradeToAndCall(_newImplementation, _data);
  }
}

// node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol

// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol)

/**
 * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
 * implementation address that can be changed. This address is stored in storage in the location specified by
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
 * implementation behind the proxy.
 */
contract ERC1967Proxy is Proxy {
    /**
     * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
     *
     * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
     * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
     *
     * Requirements:
     *
     * - If `data` is empty, `msg.value` must be zero.
     */
    constructor(address implementation, bytes memory _data) payable {
        ERC1967Utils.upgradeToAndCall(implementation, _data);
    }

    /**
     * @dev Returns the current implementation address.
     *
     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
     * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
     * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
     */
    function _implementation() internal view virtual override returns (address) {
        return ERC1967Utils.getImplementation();
    }
}

// src/interfaces/IL2OpUSDCBridgeAdapter.sol

interface IL2OpUSDCBridgeAdapter {
  /*///////////////////////////////////////////////////////////////
                            EVENTS
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Emitted when the owner message is sent
   * @param _functionSignature The signature of the function sent
   */
  event USDCFunctionSent(bytes4 _functionSignature);

  /**
   * @notice Emitted when a `receiveMessage` call message is replayed after the adapter was deprecated
   * @param _spender The address that provided the tokens
   * @param _amount The amount of USDC sent back to L1
   */
  event ReplayedFundsSentBackToL1(address _spender, uint256 _amount);

  /**
   * @notice Emitted when the locked funds are sent back to L1
   * @param _spender The address that provided the tokens
   * @param _amountSent The amount of tokens that were withdrawn
   */
  event LockedFundsSentBackToL1(address indexed _spender, uint256 _amountSent);

  /*///////////////////////////////////////////////////////////////
                            LOGIC
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Initiates the process to migrate the bridged USDC to native USDC
   * @dev Full migration can't finish until L1 receives the message for setting the burn amount
   * @param _roleCaller The address that will be allowed to transfer the USDC roles
   * @param _setBurnAmountMinGasLimit Minimum gas limit that the setBurnAmount message can be executed on L1
   */
  function receiveMigrateToNative(address _roleCaller, uint32 _setBurnAmountMinGasLimit) external;

  /**
   * @notice Transfer the USDC roles to the new owner
   * @param _owner The address to transfer ownership to
   * @dev Can only be called by the role caller set in the migration process
   */
  function transferUSDCRoles(address _owner) external;

  /**
   * @notice Receive the stop messaging message from the linked adapter and stop outgoing messages
   */
  function receiveStopMessaging() external;

  /**
   * @notice Resume messaging after it was stopped
   */
  function receiveResumeMessaging() external;

  /**
   * @notice Call with arbitrary calldata on USDC contract.
   * @dev can't execute the following list of transactions:
   *  • transferOwnership (0xf2fde38b)
   *  • changeAdmin (0x8f283970)
   * @dev UpgradeTo and UpgradeToAndCall go through the fallback admin
   * @param _data The calldata to execute on the USDC contract
   */
  function callUsdcTransaction(bytes calldata _data) external;

  /*///////////////////////////////////////////////////////////////
                            VARIABLES
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Fetches the address of the role caller
   * @return _roleCaller The address of the role caller
   */
  function roleCaller() external view returns (address _roleCaller);

  /**
   * @return _fallbackProxyAdmin The address of the fallback proxy admin
   * @dev The admin can't call the fallback function of the USDC proxy, meaning it can't interact with the functions
   * such as mint and burn between others. Because of this, the FallbackProxyAdmin contract is used as a middleware,
   * being controlled by the L2OpUSDCBridgeAdapter contract and allowing to call the admin functions through it while
   * also being able to call the fallback function of the USDC proxy.
   * @dev Declared with immutable notation even though it is not defined on the constructor because it is set on the
   * `initialize` function which replicates the behavior of the constructor.
   */
  // solhint-disable-next-line func-name-mixedcase
  function FALLBACK_PROXY_ADMIN() external view returns (FallbackProxyAdmin _fallbackProxyAdmin);
}

// node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol

// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 */
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    address private immutable __self = address(this);

    /**
     * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
     * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
     * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
     * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
     * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
     * during an upgrade.
     */
    string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";

    /**
     * @dev The call is from an unauthorized context.
     */
    error UUPSUnauthorizedCallContext();

    /**
     * @dev The storage `slot` is unsupported as a UUID.
     */
    error UUPSUnsupportedProxiableUUID(bytes32 slot);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        _checkProxy();
        _;
    }

    /**
     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
     * callable on the implementing contract but not through proxies.
     */
    modifier notDelegated() {
        _checkNotDelegated();
        _;
    }

    function __UUPSUpgradeable_init() internal onlyInitializing {
    }

    function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
     * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
     */
    function proxiableUUID() external view virtual notDelegated returns (bytes32) {
        return ERC1967Utils.IMPLEMENTATION_SLOT;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     *
     * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, data);
    }

    /**
     * @dev Reverts if the execution is not performed via delegatecall or the execution
     * context is not of a proxy with an ERC1967-compliant implementation pointing to self.
     * See {_onlyProxy}.
     */
    function _checkProxy() internal view virtual {
        if (
            address(this) == __self || // Must be called through delegatecall
            ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
        ) {
            revert UUPSUnauthorizedCallContext();
        }
    }

    /**
     * @dev Reverts if the execution is performed via delegatecall.
     * See {notDelegated}.
     */
    function _checkNotDelegated() internal view virtual {
        if (address(this) != __self) {
            // Must not be called through delegatecall
            revert UUPSUnauthorizedCallContext();
        }
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;

    /**
     * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
     *
     * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
     * is expected to be the implementation slot in ERC1967.
     *
     * Emits an {IERC1967-Upgraded} event.
     */
    function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
        try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
            if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
                revert UUPSUnsupportedProxiableUUID(slot);
            }
            ERC1967Utils.upgradeToAndCall(newImplementation, data);
        } catch {
            // The implementation is not UUPS
            revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
        }
    }
}

// node_modules/@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.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].
 *
 * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
 * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
 * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
 */
abstract contract EIP712Upgradeable is Initializable, IERC5267 {
    bytes32 private constant TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    /// @custom:storage-location erc7201:openzeppelin.storage.EIP712
    struct EIP712Storage {
        /// @custom:oz-renamed-from _HASHED_NAME
        bytes32 _hashedName;
        /// @custom:oz-renamed-from _HASHED_VERSION
        bytes32 _hashedVersion;

        string _name;
        string _version;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.EIP712")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant EIP712StorageLocation = 0xa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100;

    function _getEIP712Storage() private pure returns (EIP712Storage storage $) {
        assembly {
            $.slot := EIP712StorageLocation
        }
    }

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    function __EIP712_init(string memory name, string memory version) internal onlyInitializing {
        __EIP712_init_unchained(name, version);
    }

    function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {
        EIP712Storage storage $ = _getEIP712Storage();
        $._name = name;
        $._version = version;

        // Reset prior values in storage if upgrading
        $._hashedName = 0;
        $._hashedVersion = 0;
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        return _buildDomainSeparator();
    }

    function _buildDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
    }

    /**
     * @dev See {IERC-5267}.
     */
    function eip712Domain()
        public
        view
        virtual
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        EIP712Storage storage $ = _getEIP712Storage();
        // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized
        // and the EIP712 domain is not reliable, as it will be missing name and version.
        require($._hashedName == 0 && $._hashedVersion == 0, "EIP712: Uninitialized");

        return (
            hex"0f", // 01111
            _EIP712Name(),
            _EIP712Version(),
            block.chainid,
            address(this),
            bytes32(0),
            new uint256[](0)
        );
    }

    /**
     * @dev The name parameter for the EIP712 domain.
     *
     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
     * are a concern.
     */
    function _EIP712Name() internal view virtual returns (string memory) {
        EIP712Storage storage $ = _getEIP712Storage();
        return $._name;
    }

    /**
     * @dev The version parameter for the EIP712 domain.
     *
     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
     * are a concern.
     */
    function _EIP712Version() internal view virtual returns (string memory) {
        EIP712Storage storage $ = _getEIP712Storage();
        return $._version;
    }

    /**
     * @dev The hash of the name parameter for the EIP712 domain.
     *
     * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead.
     */
    function _EIP712NameHash() internal view returns (bytes32) {
        EIP712Storage storage $ = _getEIP712Storage();
        string memory name = _EIP712Name();
        if (bytes(name).length > 0) {
            return keccak256(bytes(name));
        } else {
            // If the name is empty, the contract may have been upgraded without initializing the new storage.
            // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design.
            bytes32 hashedName = $._hashedName;
            if (hashedName != 0) {
                return hashedName;
            } else {
                return keccak256("");
            }
        }
    }

    /**
     * @dev The hash of the version parameter for the EIP712 domain.
     *
     * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead.
     */
    function _EIP712VersionHash() internal view returns (bytes32) {
        EIP712Storage storage $ = _getEIP712Storage();
        string memory version = _EIP712Version();
        if (bytes(version).length > 0) {
            return keccak256(bytes(version));
        } else {
            // If the version is empty, the contract may have been upgraded without initializing the new storage.
            // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design.
            bytes32 hashedVersion = $._hashedVersion;
            if (hashedVersion != 0) {
                return hashedVersion;
            } else {
                return keccak256("");
            }
        }
    }
}

// src/contracts/universal/OpUSDCBridgeAdapter.sol

abstract contract OpUSDCBridgeAdapter is UUPSUpgradeable, OwnableUpgradeable, EIP712Upgradeable, IOpUSDCBridgeAdapter {
  using MessageHashUtils for bytes32;
  using SignatureChecker for address;

  /// @notice The typehash for the bridge message
  bytes32 public constant BRIDGE_MESSAGE_TYPEHASH =
    keccak256('BridgeMessage(address to,uint256 amount,uint256 deadline,uint256 nonce,uint32 minGasLimit)');

  /// @inheritdoc IOpUSDCBridgeAdapter
  address public immutable USDC;

  /// @inheritdoc IOpUSDCBridgeAdapter
  address public immutable LINKED_ADAPTER;

  /// @inheritdoc IOpUSDCBridgeAdapter
  address public immutable MESSENGER;

  /// @inheritdoc IOpUSDCBridgeAdapter
  Status public messengerStatus;

  /// @inheritdoc IOpUSDCBridgeAdapter
  mapping(address _user => mapping(uint256 _nonce => bool _used)) public userNonces;

  /// @inheritdoc IOpUSDCBridgeAdapter
  mapping(address _spender => mapping(address _user => uint256 _lockedAmount)) public lockedFundsDetails;

  /// @notice Reserve 50 storage slots to be safe on future upgrades
  uint256[50] private __gap;

  /**
   * @notice Modifier to check if the sender is the linked adapter through the messenger
   */
  modifier onlyLinkedAdapter() {
    if (msg.sender != MESSENGER || ICrossDomainMessenger(MESSENGER).xDomainMessageSender() != LINKED_ADAPTER) {
      revert IOpUSDCBridgeAdapter_InvalidSender();
    }
    _;
  }

  /**
   * @notice Construct the OpUSDCBridgeAdapter contract
   * @param _usdc The address of the USDC Contract to be used by the adapter
   * @param _messenger The address of the messenger contract
   * @param _linkedAdapter The address of the linked adapter
   */
  // solhint-disable-next-line no-unused-vars
  constructor(address _usdc, address _messenger, address _linkedAdapter) {
    USDC = _usdc;
    MESSENGER = _messenger;
    LINKED_ADAPTER = _linkedAdapter;
    _disableInitializers();
  }

  /**
   * @notice Initialize the contract
   * @param _owner The owner of the contract
   */
  function initialize(address _owner) external virtual initializer {}

  /*///////////////////////////////////////////////////////////////
                             MESSAGING
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Send tokens to another chain through the linked adapter
   * @param _to The target address on the destination chain
   * @param _amount The amount of tokens to send
   * @param _minGasLimit Minimum gas limit that the message can be executed with
   */
  function sendMessage(address _to, uint256 _amount, uint32 _minGasLimit) external virtual;

  /**
   * @notice Send signer tokens to another chain through the linked adapter
   * @param _signer The address of the user sending the message
   * @param _to The target address on the destination chain
   * @param _amount The amount of tokens to send
   * @param _signature The signature of the user
   * @param _nonce The nonce of the user
   * @param _deadline The deadline for the message to be executed
   * @param _minGasLimit Minimum gas limit that the message can be executed with
   */
  function sendMessage(
    address _signer,
    address _to,
    uint256 _amount,
    bytes calldata _signature,
    uint256 _nonce,
    uint256 _deadline,
    uint32 _minGasLimit
  ) external virtual;

  /**
   * @notice Receive the message from the other chain and mint or transfer tokens to the user
   * @dev This function should only be called when receiving a message to mint or transfer tokens
   * @param _user The user to mint or transfer the tokens for
   * @param _spender The address that provided the tokens
   * @param _amount The amount of tokens to transfer or mint
   */
  function receiveMessage(address _user, address _spender, uint256 _amount) external virtual;

  /**
   * @notice Withdraws the locked funds from the contract if they get unlocked
   * @param _spender The address that provided the tokens
   * @param _user The user to withdraw the funds for
   */
  function withdrawLockedFunds(address _spender, address _user) external virtual;

  /**
   * @notice Cancels a signature by setting the nonce as used
   * @param _nonce The nonce of the signature to cancel
   */
  function cancelSignature(uint256 _nonce) external {
    userNonces[msg.sender][_nonce] = true;

    emit NonceCanceled(msg.sender, _nonce);
  }

  /**
   * @notice Checks the caller is the owner to authorize the upgrade
   */
  function _authorizeUpgrade(address) internal virtual override onlyOwner {}

  /**
   * @notice Check the signature of a message
   * @param _signer the address that signed the message
   * @param _messageHash the hash of the message that was signed
   * @param _signature the signature of the message
   */
  function _checkSignature(address _signer, bytes32 _messageHash, bytes memory _signature) internal view {
    // Uses the EIP712Upgradeable typed data hash
    _messageHash = _hashTypedDataV4(_messageHash);

    if (!_signer.isValidSignatureNow(_messageHash, _signature)) revert IOpUSDCBridgeAdapter_InvalidSignature();
  }

  /**
   * @notice Hashes the bridge message struct
   * @param _message The bridge message struct to hash
   * @return _hash The hash of the bridge message struct
   */
  function _hashMessageStruct(BridgeMessage memory _message) internal pure returns (bytes32 _hash) {
    _hash = keccak256(
      abi.encode(
        BRIDGE_MESSAGE_TYPEHASH, _message.to, _message.amount, _message.deadline, _message.nonce, _message.minGasLimit
      )
    );
  }
}

// src/contracts/L1OpUSDCBridgeAdapter.sol

/**
 * @title L1OpUSDCBridgeAdapter
 * @notice L1OpUSDCBridgeAdapter is a contract that bridges Bridged USDC from L1 to L2 and and receives it from L2.
 * It is also in charge of pausing and resuming messaging between the L1 and L2 adapters, and properly initiating the
 * migration process to the for bridged USDC to native.
 */
contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter {
  using SafeERC20 for IUSDC;

  /// @inheritdoc IL1OpUSDCBridgeAdapter
  uint256 public burnAmount;

  /// @inheritdoc IL1OpUSDCBridgeAdapter
  address public burnCaller;

  /// @notice Reserve 50 more storage slots to be safe on future upgrades
  uint256[50] private __gap;

  /**
   * @notice Construct the OpUSDCBridgeAdapter contract
   * @param _usdc The address of the USDC Contract to be used by the adapter
   * @param _messenger The address of the L1 messenger
   * @param _linkedAdapter The address of the linked adapter
   * @dev The constructor is only used to initialize the OpUSDCBridgeAdapter immutable variables
   */
  constructor(
    address _usdc,
    address _messenger,
    address _linkedAdapter
  ) OpUSDCBridgeAdapter(_usdc, _messenger, _linkedAdapter) {}

  /**
   * @notice Sets the owner of the contract
   * @param _owner The address of the owner
   * @dev This function needs only used during the deployment of the proxy contract, and it is disabled for the
   * implementation contract
   */
  function initialize(address _owner) external virtual override initializer {
    __Ownable_init(_owner);
    string memory _name = 'OpUSDCBridgeAdapter';
    string memory _version = '1.0.0';
    __EIP712_init(_name, _version);
  }

  /*///////////////////////////////////////////////////////////////
                              MIGRATION
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Initiates the process to migrate the bridged USDC to native USDC
   * @param _roleCaller The address that will be allowed to transfer the usdc roles
   * @param _burnCaller The address that will be allowed to call this contract to burn the USDC tokens
   * @param _minGasLimitReceiveOnL2 Minimum gas limit that the message can be executed with on L2
   * @param _minGasLimitSetBurnAmount Minimum gas limit that the message can be executed with to set the burn amount
   * @dev Migrating to native is irreversible and will deprecate these adapters
   */
  function migrateToNative(
    address _roleCaller,
    address _burnCaller,
    uint32 _minGasLimitReceiveOnL2,
    uint32 _minGasLimitSetBurnAmount
  ) external onlyOwner {
    // Leave this flow open to resend upgrading flow in case message fails on L2
    // Circle's USDC implementation of `transferOwnership` reverts on address(0)
    if (_roleCaller == address(0) || _burnCaller == address(0)) revert IOpUSDCBridgeAdapter_InvalidAddress();

    // Ensure messaging is enabled
    if (messengerStatus != Status.Active && messengerStatus != Status.Upgrading) {
      revert IOpUSDCBridgeAdapter_MessagingDisabled();
    }

    burnCaller = _burnCaller;
    messengerStatus = Status.Upgrading;

    ICrossDomainMessenger(MESSENGER).sendMessage(
      LINKED_ADAPTER,
      abi.encodeCall(IL2OpUSDCBridgeAdapter.receiveMigrateToNative, (_roleCaller, _minGasLimitSetBurnAmount)),
      _minGasLimitReceiveOnL2
    );

    emit MigratingToNative(MESSENGER, _burnCaller);
  }

  /**
   * @notice Sets the amount of USDC tokens that will be burned when the burnLockedUSDC function is called
   * @param _amount The amount of USDC tokens that will be burned
   * @dev Only callable by a whitelisted messenger during its migration process
   */
  function setBurnAmount(uint256 _amount) external onlyLinkedAdapter {
    if (messengerStatus != Status.Upgrading) revert IOpUSDCBridgeAdapter_NotUpgrading();

    burnAmount = _amount;
    messengerStatus = Status.Deprecated;

    emit BurnAmountSet(_amount);
  }

  /**
   * @notice Burns the USDC tokens locked in the contract
   * @dev The amount is determined by the burnAmount variable, which is set in the setBurnAmount function
   */
  function burnLockedUSDC() external {
    if (msg.sender != burnCaller) revert IOpUSDCBridgeAdapter_InvalidSender();

    // If the adapter is not deprecated the burn amount has not been set
    if (messengerStatus != Status.Deprecated) revert IOpUSDCBridgeAdapter_BurnAmountNotSet();

    // NOTE: This is a very edge case and will only happen if the chain operator adds a second minter on L2
    // So now this adapter doesnt have the full backing supply locked in this contract
    // in case the bridged usdc token has other minters and the supply sent is greater then what we have
    // We need to burn the full amount stored in this contract
    // This could also cause in-flight messages to fail because of the multiple supply sources
    uint256 _burnAmount = burnAmount;
    uint256 _balanceOf = IUSDC(USDC).balanceOf(address(this));
    _burnAmount = _burnAmount > _balanceOf ? _balanceOf : _burnAmount;

    // Burn the USDC tokens
    if (_burnAmount != 0) {
      IUSDC(USDC).burn(_burnAmount);
    }

    // Set the burn amount to 0
    burnAmount = 0;
    burnCaller = address(0);
    emit MigrationComplete(_burnAmount);
  }

  /*///////////////////////////////////////////////////////////////
                          ADMIN CONTROL
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Send a message to the linked adapter to call receiveStopMessaging() and stop outgoing messages.
   * @dev Only callable by the owner of the adapter
   * @param _minGasLimit Minimum gas limit that the message can be executed with
   */
  function stopMessaging(uint32 _minGasLimit) external onlyOwner {
    // Ensure messaging is enabled
    // If its paused we still leave this function open to be called in case the message fails on L2
    if (messengerStatus != Status.Active && messengerStatus != Status.Paused) {
      revert IOpUSDCBridgeAdapter_MessagingDisabled();
    }

    messengerStatus = Status.Paused;

    ICrossDomainMessenger(MESSENGER).sendMessage(
      LINKED_ADAPTER, abi.encodeCall(IL2OpUSDCBridgeAdapter.receiveStopMessaging, ()), _minGasLimit
    );

    emit MessagingStopped(MESSENGER);
  }

  /**
   * @notice Resume messaging on the messenger
   * @dev Only callable by the owner
   * @dev Can't resume deprecated or upgrading messengers
   * @param _minGasLimit Minimum gas limit that the message can be executed with
   */
  function resumeMessaging(uint32 _minGasLimit) external onlyOwner {
    // Ensure messaging is disabled
    // If its active we still leave this function open to be called in case the message fails on L2
    if (messengerStatus != Status.Paused && messengerStatus != Status.Active) {
      revert IOpUSDCBridgeAdapter_MessagingEnabled();
    }

    messengerStatus = Status.Active;

    ICrossDomainMessenger(MESSENGER).sendMessage(
      LINKED_ADAPTER, abi.encodeCall(IL2OpUSDCBridgeAdapter.receiveResumeMessaging, ()), _minGasLimit
    );

    emit MessagingResumed(MESSENGER);
  }

  /*///////////////////////////////////////////////////////////////
                             MESSAGING
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Send tokens to another chain through the linked adapter
   * @param _to The target address on the destination chain
   * @param _amount The amount of tokens to send
   * @param _minGasLimit Minimum gas limit that the message can be executed with
   */
  function sendMessage(address _to, uint256 _amount, uint32 _minGasLimit) external override {
    if (_to == address(0)) revert IOpUSDCBridgeAdapter_InvalidAddress();

    // Ensure the address is not blacklisted
    if (IUSDC(USDC).isBlacklisted(_to)) revert IOpUSDCBridgeAdapter_BlacklistedAddress();

    // Ensure messaging is enabled
    if (messengerStatus != Status.Active) revert IOpUSDCBridgeAdapter_MessagingDisabled();

    _sendMessage(msg.sender, _to, _amount, _minGasLimit);
  }

  /**
   * @notice Send signer tokens to another chain through the linked adapter
   * @param _signer The address of the user sending the message
   * @param _to The target address on the destination chain
   * @param _amount The amount of tokens to send
   * @param _signature The signature of the user
   * @param _nonce The nonce of the user
   * @param _deadline The deadline for the message to be executed
   * @param _minGasLimit Minimum gas limit that the message can be executed with
   */
  function sendMessage(
    address _signer,
    address _to,
    uint256 _amount,
    bytes calldata _signature,
    uint256 _nonce,
    uint256 _deadline,
    uint32 _minGasLimit
  ) external override {
    if (_to == address(0)) revert IOpUSDCBridgeAdapter_InvalidAddress();

    // Ensure the address is not blacklisted
    if (IUSDC(USDC).isBlacklisted(_to)) revert IOpUSDCBridgeAdapter_BlacklistedAddress();

    // Ensure messaging is enabled
    if (messengerStatus != Status.Active) revert IOpUSDCBridgeAdapter_MessagingDisabled();

    // Ensure the nonce has not already been used
    if (userNonces[_signer][_nonce]) revert IOpUSDCBridgeAdapter_InvalidNonce();

    // Ensure the deadline has not passed
    if (block.timestamp > _deadline) revert IOpUSDCBridgeAdapter_MessageExpired();

    BridgeMessage memory _message =
      BridgeMessage({to: _to, amount: _amount, deadline: _deadline, nonce: _nonce, minGasLimit: _minGasLimit});

    _checkSignature(_signer, _hashMessageStruct(_message), _signature);

    // Mark the nonce as used
    userNonces[_signer][_nonce] = true;

    _sendMessage(_signer, _to, _amount, _minGasLimit);
  }

  /**
   * @notice Receive the message from the other chain and transfer tokens to the user
   * @dev This function should only be called when receiving a message to transfer tokens
   * @dev If the transfer fails the funds might be recovered by calling withdrawLockedFunds
   * @param _user The user to transfer the tokens to
   * @param _spender The address that provided the tokens
   * @param _amount The amount of tokens to transfer
   */
  function receiveMessage(address _user, address _spender, uint256 _amount) external override onlyLinkedAdapter {
    // Transfer the tokens to the user
    try this.attemptTransfer(_user, _amount) {
      emit MessageReceived(_spender, _user, _amount, MESSENGER);
    } catch {
      // If the transfer fails, the user could be locked for multiple reasons such as blacklist or usdc being paused
      lockedFundsDetails[_spender][_user] += _amount;
      emit MessageFailed(_spender, _user, _amount, MESSENGER);
    }
  }

  /**
   * @notice Receives a message from L2 if the adapter is deprecated and a user is withdrawing locked funds
   * @dev If the _spender is still locked, the user will be forced to replay this message
   * @param _spender The user that initially provided the tokens
   * @param _amount The amount of tokens to withdraw
   */
  function receiveWithdrawLockedFundsPostMigration(address _spender, uint256 _amount) external onlyLinkedAdapter {
    if (messengerStatus != Status.Deprecated) revert IOpUSDCBridgeAdapter_NotMigrated();

    // If the spender is still locked, the user will be forced to replay this message
    IUSDC(USDC).safeTransfer(_spender, _amount);

    emit LockedFundsWithdrawn(_spender, _amount);
  }

  /**
   * @notice Withdraws the locked funds from the contract in case they get unlocked
   * @param _spender The address that provided the tokens
   * @param _user The user to withdraw the funds for
   */
  function withdrawLockedFunds(address _spender, address _user) external override {
    uint256 _amount = lockedFundsDetails[_spender][_user];
    lockedFundsDetails[_spender][_user] = 0;

    // The check for if the user is locked happens in USDC's contract
    IUSDC(USDC).safeTransfer(_user, _amount);

    emit LockedFundsWithdrawn(_user, _amount);
  }

  /**
   * @notice Attempts to transfer the tokens to the user
   * @param _to The target address on the destination chain
   * @param _amount The amount of tokens to send
   * @dev This function should only be called when receiving a message
   * And is a workaround for the fact that try/catch
   * Only works on external calls and SafeERC20 is an internal library
   */
  function attemptTransfer(address _to, uint256 _amount) external {
    if (msg.sender != address(this)) revert IOpUSDCBridgeAdapter_InvalidSender();
    IUSDC(USDC).safeTransfer(_to, _amount);
  }

  /*///////////////////////////////////////////////////////////////
                        INTERNAL FUNCTIONS
  ///////////////////////////////////////////////////////////////*/
  /**
   * @notice Send the message to the linked adapter
   * @param _from address that originated the message
   * @param _to target address on the destination chain
   * @param _amount amount of tokens to be bridged
   * @param _minGasLimit minimum gas limit for the other chain to execute the message
   */
  function _sendMessage(address _from, address _to, uint256 _amount, uint32 _minGasLimit) internal {
    // Transfer the tokens to the contract
    IUSDC(USDC).safeTransferFrom(_from, address(this), _amount);

    // Send the message to the linked adapter
    ICrossDomainMessenger(MESSENGER).sendMessage(
      LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_to, _from, _amount)), _minGasLimit
    );

    emit MessageSent(_from, _to, _amount, MESSENGER, _minGasLimit);
  }
}

// src/contracts/L2OpUSDCBridgeAdapter.sol

/**
 * @title L2OpUSDCBridgeAdapter
 * @notice L2OpUSDCBridgeAdapter is a contract that bridges Bridged USDC from L2 to L1 and and receives the it from L1.
 * It finalizes the migration process of bridged USDC to native USDC on L2 after being triggered by the L1 adapter, and
 * sends the amount to be burned back to the L1 adapter to finish the migration process.
 * @dev The owner of this contract is capable of calling any USDC function, except the ownership or admin ones.
 */
contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter {
  using SafeERC20 for IUSDC;

  ///@notice `transferOwnership(address)` USDC function selector
  bytes4 internal constant _TRANSFER_OWNERSHIP_SELECTOR = 0xf2fde38b;
  ///@notice `changeAdmin(address)` USDC function selector
  bytes4 internal constant _CHANGE_ADMIN_SELECTOR = 0x8f283970;
  ///@notice `upgradeTo(address)` USDC function selector
  bytes4 internal constant _UPGRADE_TO_SELECTOR = 0x3659cfe6;
  ///@notice `upgradeToAndCall(address,bytes)` USDC function selector
  bytes4 internal constant _UPGRADE_TO_AND_CALL_SELECTOR = 0x4f1ef286;
  ///@notice `updateMasterMinter(address)` USDC function selector
  bytes4 internal constant _UPDATE_MASTER_MINTER_SELECTOR = 0xaa20e1e4;

  /// @inheritdoc IL2OpUSDCBridgeAdapter
  // solhint-disable-next-line var-name-mixedcase
  FallbackProxyAdmin public FALLBACK_PROXY_ADMIN;

  /// @inheritdoc IL2OpUSDCBridgeAdapter
  address public roleCaller;

  /// @notice Reserve 50 more storage slots to be safe on future upgrades
  uint256[50] private __gap;

  /**
   * @notice Construct the OpUSDCBridgeAdapter contract
   * @param _usdc The address of the USDC Contract to be used by the adapter
   * @param _messenger The address of the messenger contract
   * @param _linkedAdapter The address of the linked adapter
   * @dev The constructor is only used to initialize the OpUSDCBridgeAdapter immutable variables
   */
  /* solhint-disable no-unused-vars */
  constructor(
    address _usdc,
    address _messenger,
    address _linkedAdapter
  ) OpUSDCBridgeAdapter(_usdc, _messenger, _linkedAdapter) {}
  /* solhint-enable no-unused-vars */

  /**
   * @notice Sets the owner of the contract
   * @param _owner The address of the owner
   * @dev This function needs only used during the deployment of the proxy contract, and it is disabled for the
   * implementation contract
   */
  function initialize(address _owner) external virtual override initializer {
    __Ownable_init(_owner);
    string memory _name = 'OpUSDCBridgeAdapter';
    string memory _version = '1.0.0';
    __EIP712_init(_name, _version);
    FALLBACK_PROXY_ADMIN = new FallbackProxyAdmin(USDC);
  }

  /*///////////////////////////////////////////////////////////////
                              MIGRATION
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Initiates the process to migrate the bridged USDC to native USDC
   * @dev Full migration can't finish until L1 receives the message for setting the burn amount
   * @param _roleCaller The address that will be allowed to transfer the USDC roles
   * @param _setBurnAmountMinGasLimit Minimum gas limit that the setBurnAmount message can be executed on L1
   */
  function receiveMigrateToNative(address _roleCaller, uint32 _setBurnAmountMinGasLimit) external onlyLinkedAdapter {
    messengerStatus = Status.Deprecated;
    roleCaller = _roleCaller;

    uint256 _burnAmount = IUSDC(USDC).totalSupply();

    // Remove the L2 Adapter as a minter
    IUSDC(USDC).removeMinter(address(this));

    ICrossDomainMessenger(MESSENGER).sendMessage(
      LINKED_ADAPTER, abi.encodeCall(IL1OpUSDCBridgeAdapter.setBurnAmount, (_burnAmount)), _setBurnAmountMinGasLimit
    );

    emit MigratingToNative(MESSENGER, _roleCaller);
  }

  /**
   * @notice Transfers the USDC roles to the new owner
   * @param _owner The address to transfer ownership to
   * @dev Can only be called by the role caller set in the migration process
   */
  function transferUSDCRoles(address _owner) external {
    if (msg.sender != roleCaller) revert IOpUSDCBridgeAdapter_InvalidCaller();

    // Transfer ownership of the USDC contract to circle
    IUSDC(USDC).transferOwnership(_owner);

    // Transfer proxy admin ownership to the caller
    FALLBACK_PROXY_ADMIN.changeAdmin(msg.sender);
  }

  /*///////////////////////////////////////////////////////////////
                          MESSAGING CONTROL
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Receive the stop messaging message from the linked adapter and stop outgoing messages
   */
  function receiveStopMessaging() external onlyLinkedAdapter {
    if (messengerStatus == Status.Deprecated) revert IOpUSDCBridgeAdapter_MessagingDisabled();

    messengerStatus = Status.Paused;

    emit MessagingStopped(MESSENGER);
  }

  /**
   * @notice Resume messaging after it was stopped
   */
  function receiveResumeMessaging() external onlyLinkedAdapter {
    if (messengerStatus == Status.Deprecated) revert IOpUSDCBridgeAdapter_MessagingDisabled();

    messengerStatus = Status.Active;

    emit MessagingResumed(MESSENGER);
  }

  /*///////////////////////////////////////////////////////////////
                             MESSAGING
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Send tokens to another chain through the linked adapter
   * @param _to The target address on the destination chain
   * @param _amount The amount of tokens to send
   * @param _minGasLimit Minimum gas limit that the message can be executed with
   */
  function sendMessage(address _to, uint256 _amount, uint32 _minGasLimit) external override {
    if (_to == address(0)) revert IOpUSDCBridgeAdapter_InvalidAddress();
    // Ensure the address is not blacklisted
    if (IUSDC(USDC).isBlacklisted(_to)) revert IOpUSDCBridgeAdapter_BlacklistedAddress();

    // Ensure messaging is enabled
    if (messengerStatus != Status.Active) revert IOpUSDCBridgeAdapter_MessagingDisabled();

    _sendMessage(msg.sender, _to, _amount, _minGasLimit);
  }

  /**
   * @notice Send signer tokens to another chain through the linked adapter
   * @param _signer The address of the user sending the message
   * @param _to The target address on the destination chain
   * @param _amount The amount of tokens to send
   * @param _signature The signature of the user
   * @param _nonce The nonce of the user
   * @param _deadline The deadline for the message to be executed
   * @param _minGasLimit Minimum gas limit that the message can be executed with
   */
  function sendMessage(
    address _signer,
    address _to,
    uint256 _amount,
    bytes calldata _signature,
    uint256 _nonce,
    uint256 _deadline,
    uint32 _minGasLimit
  ) external override {
    if (_to == address(0)) revert IOpUSDCBridgeAdapter_InvalidAddress();
    // Ensure the address is not blacklisted
    if (IUSDC(USDC).isBlacklisted(_to)) revert IOpUSDCBridgeAdapter_BlacklistedAddress();

    // Ensure messaging is enabled
    if (messengerStatus != Status.Active) revert IOpUSDCBridgeAdapter_MessagingDisabled();

    // Ensure the nonce has not already been used
    if (userNonces[_signer][_nonce]) revert IOpUSDCBridgeAdapter_InvalidNonce();

    // Ensure the deadline has not passed
    if (block.timestamp > _deadline) revert IOpUSDCBridgeAdapter_MessageExpired();

    BridgeMessage memory _message =
      BridgeMessage({to: _to, amount: _amount, deadline: _deadline, nonce: _nonce, minGasLimit: _minGasLimit});

    _checkSignature(_signer, _hashMessageStruct(_message), _signature);

    // Mark the nonce as used
    userNonces[_signer][_nonce] = true;

    _sendMessage(_signer, _to, _amount, _minGasLimit);
  }

  /**
   * @notice Receive the message from the other chain and mint the bridged representation for the user
   * @dev This function should only be called when receiving a message to mint the bridged representation
   * @dev If the mint fails the funds might be recovered by calling withdrawLockedFunds
   * @param _user The user to mint the bridged representation for
   * @param _spender The address that provided the tokens
   * @param _amount The amount of tokens to mint
   */
  function receiveMessage(address _user, address _spender, uint256 _amount) external override onlyLinkedAdapter {
    if (messengerStatus == Status.Deprecated) {
      uint32 _minGasLimit = 150_000;
      // Return the funds to the spender in case the target on L2 is a contract that can´t handle the funds on L1
      ICrossDomainMessenger(MESSENGER).sendMessage(
        LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_spender, _spender, _amount)), _minGasLimit
      );

      emit ReplayedFundsSentBackToL1(_spender, _amount);
    } else {
      // Mint the tokens to the user
      try IUSDC(USDC).mint(_user, _amount) {
        emit MessageReceived(_spender, _user, _amount, MESSENGER);
      } catch {
        // If the mint fails, the user could be locked for multiple reasons such as blacklist or usdc being paused
        lockedFundsDetails[_spender][_user] += _amount;
        emit MessageFailed(_spender, _user, _amount, MESSENGER);
      }
    }
  }

  /**
   * @notice Mints the locked funds from the contract in case they get unlocked
   * @dev Returns the funds to the spender through a message to L1 if the contract is deprecated
   * @param _spender The address that provided the tokens
   * @param _user The user to withdraw the funds for
   */
  function withdrawLockedFunds(address _spender, address _user) external override {
    uint256 _amount = lockedFundsDetails[_spender][_user];
    lockedFundsDetails[_spender][_user] = 0;

    if (messengerStatus != Status.Deprecated) {
      // The check for if the user is blacklisted happens in USDC's contract
      IUSDC(USDC).mint(_user, _amount);
      emit LockedFundsWithdrawn(_user, _amount);
    } else {
      uint32 _minGasLimit = 150_000;
      // Send the message to the linked adapter
      ICrossDomainMessenger(MESSENGER).sendMessage(
        LINKED_ADAPTER,
        abi.encodeCall(IL1OpUSDCBridgeAdapter.receiveWithdrawLockedFundsPostMigration, (_spender, _amount)),
        _minGasLimit
      );
      emit LockedFundsSentBackToL1(_spender, _amount);
    }
  }

  /*///////////////////////////////////////////////////////////////
                        BRIDGED USDC FUNCTIONS
  ///////////////////////////////////////////////////////////////*/

  /**
   * @notice Call with abitrary calldata on USDC contract.
   * @dev can't execute the following list of transactions:
   *  • transferOwnership (0xf2fde38b)
   *  • changeAdmin (0x8f283970)
   * @dev UpgradeTo and UpgradeToAndCall go through the fallback admin
   * @param _data The calldata to execute on the USDC contract
   */
  function callUsdcTransaction(bytes calldata _data) external onlyOwner {
    bytes4 _selector = bytes4(_data);
    bool _success;

    if (
      _selector == _TRANSFER_OWNERSHIP_SELECTOR || _selector == _CHANGE_ADMIN_SELECTOR
        || _selector == _UPDATE_MASTER_MINTER_SELECTOR
    ) {
      revert IOpUSDCBridgeAdapter_ForbiddenTransaction();
    } else if (_selector == _UPGRADE_TO_SELECTOR || _selector == _UPGRADE_TO_AND_CALL_SELECTOR) {
      (_success,) = address(FALLBACK_PROXY_ADMIN).call(_data);
    } else {
      (_success,) = USDC.call(_data);
    }

    if (!_success) {
      revert IOpUSDCBridgeAdapter_InvalidTransaction();
    }

    emit USDCFunctionSent(_selector);
  }

  /*///////////////////////////////////////////////////////////////
                        INTERNAL FUNCTIONS
  ///////////////////////////////////////////////////////////////*/
  /**
   * @notice Send the message to the linked adapter
   * @param _from address that originated the message
   * @param _to target address on the destination chain
   * @param _amount amount of tokens to be bridged
   * @param _minGasLimit minimum gas limit for the other chain to execute the message
   */
  function _sendMessage(address _from, address _to, uint256 _amount, uint32 _minGasLimit) internal {
    IUSDC(USDC).safeTransferFrom(_from, address(this), _amount);

    // Burn the tokens
    IUSDC(USDC).burn(_amount);

    // Send the message to the linked adapter
    ICrossDomainMessenger(MESSENGER).sendMessage(
      LINKED_ADAPTER, abi.encodeCall(IOpUSDCBridgeAdapter.receiveMessage, (_to, _from, _amount)), _minGasLimit
    );

    emit MessageSent(_from, _to, _amount, MESSENGER, _minGasLimit);
  }
}

// src/contracts/L2OpUSDCDeploy.sol

/**
 * @title L2OpUSDCDeploy
 * @notice Deployer contract for deploying the L2 USDC implementation, proxy, and `L2OpUSDCBridgeAdapter` contract,
 * all at once on the `deploy` function.
 * @dev The salt is always different for each deployed instance of this contract on the L1 Factory, and the L2 contracts
 * are deployed with `CREATE` to guarantee that the addresses are unique among all the L2s, so we avoid a scenario where
 * L2 contracts have the same address on different L2s when triggered by different owners.
 */
contract L2OpUSDCDeploy is IL2OpUSDCDeploy {
  address internal constant _L2_MESSENGER = 0x4200000000000000000000000000000000000007;

  /**
   * @notice Deploys the USDC implementation, proxy, and L2 adapter contracts all at once, and then initializes the USDC
   * @param _l1Adapter The address of the L1 adapter contract
   * @param _l2AdapterOwner The address of the L2 adapter owner
   * @param _usdcImplAddr The address of the USDC implementation on L2 to connect the proxy to
   * @param _usdcInitializeData The USDC name, symbol, currency, and decimals used on the first `initialize()` call
   * @param _usdcInitTxs The initialization transactions for the USDC proxy and implementation contracts
   * @dev The USDC proxy owner needs to be set on the first init tx, and will be set to the L2 adapter address
   * @dev Using `CREATE` to guarantee that the addresses are unique among all the L2s
   */
  constructor(
    address _l1Adapter,
    address _l2AdapterOwner,
    address _usdcImplAddr,
    USDCInitializeData memory _usdcInitializeData,
    bytes[] memory _usdcInitTxs
  ) {
    // Deploy USDC proxy
    bytes memory _usdcProxyCArgs = abi.encode(_usdcImplAddr);
    bytes memory _usdcProxyInitCode = bytes.concat(USDC_PROXY_CREATION_CODE, _usdcProxyCArgs);

    // 1st nonce
    address _usdcProxy = _deployCreate(_usdcProxyInitCode);
    emit USDCProxyDeployed(_usdcProxy);

    // Deploy L2 Adapter implementation and proxy, initializing it with the owner
    // 2nd nonce
    address _l2AdapterImpl = address(new L2OpUSDCBridgeAdapter(_usdcProxy, _L2_MESSENGER, _l1Adapter));

    // 3rd nonce
    address _l2Adapter =
      address(new ERC1967Proxy(_l2AdapterImpl, abi.encodeCall(OpUSDCBridgeAdapter.initialize, _l2AdapterOwner)));
    emit L2AdapterDeployed(_l2Adapter);

    // Deploy the FallbackProxyAdmin internally in the L2 Adapter to keep it unique
    address _fallbackProxyAdmin = address(L2OpUSDCBridgeAdapter(_l2Adapter).FALLBACK_PROXY_ADMIN());
    // Change the USDC admin so the init txs can be executed over the proxy from this contract
    IUSDC(_usdcProxy).changeAdmin(_fallbackProxyAdmin);

    // Execute the USDC initialization transactions over the USDC proxy
    _executeInitTxs(_usdcProxy, _usdcInitializeData, _l2Adapter, _usdcInitTxs);
  }

  /**
   * @notice Executes the initialization transactions for a target contract
   * @param _usdc The address of the contract to execute the transactions on
   * @param _usdcInitializeData The USDC name, symbol, currency, and decimals used on the first `initialize()` call
   * @param _l2Adapter The address of the L2 adapter
   * @param _initTxs The initialization transactions to execute
   * @dev The first `initialize()` call is defined here to ensure it is properly done, granting the right permissions
   * to the L2 adapter contract. The L2 factory is set as master minter first so it can configure the l2 adapter as
   * unlimited minter and then the master minter is updated again to the l2 adapter
   */
  function _executeInitTxs(
    address _usdc,
    USDCInitializeData memory _usdcInitializeData,
    address _l2Adapter,
    bytes[] memory _initTxs
  ) internal {
    // Initialize the USDC contract
    IUSDC(_usdc).initialize(
      _usdcInitializeData.tokenName,
      _usdcInitializeData.tokenSymbol,
      _usdcInitializeData.tokenCurrency,
      _usdcInitializeData.tokenDecimals,
      address(this),
      _l2Adapter,
      _l2Adapter,
      address(this)
    );

    // Add l2 adapter as unlimited minter
    IUSDC(_usdc).configureMinter(_l2Adapter, type(uint256).max);
    // Set l2 adapter as new master minter
    IUSDC(_usdc).updateMasterMinter(_l2Adapter);
    // Transfer USDC ownership to the L2 adapter
    IUSDC(_usdc).transferOwnership(_l2Adapter);

    // Execute the input init txs, use `_i+1` as revert argument since the first tx is already executed on the contract
    for (uint256 _i; _i < _initTxs.length; _i++) {
      (bool _success,) = _usdc.call(_initTxs[_i]);
      if (!_success) {
        revert IL2OpUSDCDeploy_InitializationFailed(_i + 1);
      }
    }
  }

  /**
   * @notice Deploys a new contract via calling the `CREATE` opcode
   * @param _initCode The creation bytecode.
   * @return _newContract The 20-byte address where the contract was deployed.
   */
  function _deployCreate(bytes memory _initCode) internal returns (address _newContract) {
    assembly ("memory-safe") {
      _newContract := create(0x0, add(_initCode, 0x20), mload(_initCode))
    }
    if (_newContract == address(0) || _newContract.code.length == 0) {
      revert IL2OpUSDCDeploy_DeploymentFailed();
    }
  }
}

// src/libraries/CrossChainDeployments.sol

/**
 * @title CrossChainDeployments
 * @notice Library containing logic needed on the L1 Factory to properly deploy contracts on the L2.
 * @dev Logic splitted here to reduce code size on the L1 Factory contract.
 */
library CrossChainDeployments {
  /// @notice RLP encoding deployer length prefix for calculating the address of a contract deployed through `CREATE`
  bytes1 internal constant _LEN = bytes1(0x94);

  /// @notice The status of if the transaction is a contract creation
  bool internal constant _IS_CONTRACT_CREATION = false;

  /// @notice The msg.value sent with the transaction
  uint256 internal constant _VALUE = 0;

  /**
   * @notice Deploys the L2 factory contract through the L1 messenger
   * @param _args The initialization arguments for the L2 factory
   * @param _salt The salt to be used to deploy the L2 factory
   * @param _messenger The address of the L1 messenger
   * @param _create2Deployer The address of the L2 create2 deployer
   * @param _minGasLimit The minimum gas limit that the message can be executed with
   * @return _l2Deploy The address of the L2 factory
   */
  function deployL2Factory(
    bytes memory _args,
    bytes32 _salt,
    address _messenger,
    address _create2Deployer,
    uint32 _minGasLimit
  ) external returns (address _l2Deploy) {
    bytes memory _l2DeployInitCode = bytes.concat(type(L2OpUSDCDeploy).creationCode, _args);
    _l2Deploy = precalculateCreate2Address(_salt, keccak256(_l2DeployInitCode), _create2Deployer);

    bytes memory _l2DeploymentsTx = abi.encodeCall(ICreate2Deployer.deploy, (_VALUE, _salt, _l2DeployInitCode));

    address _portal;

    // Some messengers are still using the legacy `portal` function so we need to handle this case
    try ICrossDomainMessenger(_messenger).portal() returns (address _p) {
      _portal = _p;
    } catch {
      _portal = ICrossDomainMessenger(_messenger).PORTAL();
    }

    IOptimismPortal(_portal).depositTransaction(
      _create2Deployer, _VALUE, _minGasLimit, _IS_CONTRACT_CREATION, _l2DeploymentsTx
    );
  }

  /**
   * @notice Precalculate and address to be deployed using the `CREATE2` opcode
   * @param _salt The 32-byte random value used to create the contract address.
   * @param _initCodeHash The 32-byte bytecode digest of the contract creation bytecode.
   * @param _deployer The 20-byte _deployer address.
   * @return _precalculatedAddress The 20-byte address where a contract will be stored.
   */
  function precalculateCreate2Address(
    bytes32 _salt,
    bytes32 _initCodeHash,
    address _deployer
  ) internal pure returns (address _precalculatedAddress) {
    assembly ("memory-safe") {
      let _ptr := mload(0x40)
      mstore(add(_ptr, 0x40), _initCodeHash)
      mstore(add(_ptr, 0x20), _salt)
      mstore(_ptr, _deployer)
      let _start := add(_ptr, 0x0b)
      mstore8(_start, 0xff)
      _precalculatedAddress := and(keccak256(_start, 85), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
    }
  }

  /**
   * @notice Precalculates the address of a contract that will be deployed thorugh `CREATE` opcode
   * @param _deployer The deployer address
   * @param _nonce The next nonce of the deployer address
   * @return _precalculatedAddress The address where the contract will be stored
   * @dev Only works for nonces between 1 and (2 ** 64 - 2), which is enough for this use case
   */
  function precalculateCreateAddress(
    address _deployer,
    uint256 _nonce
  ) internal pure returns (address _precalculatedAddress) {
    bytes memory _data;

    // A one-byte integer in the [0x00, 0x7f] range uses its own value as a length prefix, there is no
    // additional "0x80 + length" prefix that precedes it.

    if (_nonce <= 0x7f) {
      _data = abi.encodePacked(bytes1(0xd6), _LEN, _deployer, uint8(_nonce));
    }
    // In the case of `_nonce > 0x7f` and `_nonce <= type(uint8).max`, we have the following encoding scheme
    // (the same calculation can be carried over for higher _nonce bytes):
    // 0xda = 0xc0 (short RLP prefix) + 0x1a (= the bytes length of: 0x94 + address + 0x84 + _nonce, in hex),
    // 0x94 = 0x80 + 0x14 (= the bytes length of an address, 20 bytes, in hex),
    // 0x84 = 0x80 + 0x04 (= the bytes length of the _nonce, 4 bytes, in hex).
    else if (_nonce <= type(uint8).max) {
      _data = abi.encodePacked(bytes1(0xd7), _LEN, _deployer, bytes1(0x81), uint8(_nonce));
    } else if (_nonce <= type(uint16).max) {
      _data = abi.encodePacked(bytes1(0xd8), _LEN, _deployer, bytes1(0x82), uint16(_nonce));
    } else if (_nonce <= type(uint24).max) {
      _data = abi.encodePacked(bytes1(0xd9), _LEN, _deployer, bytes1(0x83), uint24(_nonce));
    } else if (_nonce <= type(uint32).max) {
      _data = abi.encodePacked(bytes1(0xda), _LEN, _deployer, bytes1(0x84), uint32(_nonce));
    } else if (_nonce <= type(uint40).max) {
      _data = abi.encodePacked(bytes1(0xdb), _LEN, _deployer, bytes1(0x85), uint40(_nonce));
    } else if (_nonce <= type(uint48).max) {
      _data = abi.encodePacked(bytes1(0xdc), _LEN, _deployer, bytes1(0x86), uint48(_nonce));
    } else if (_nonce <= type(uint56).max) {
      _data = abi.encodePacked(bytes1(0xdd), _LEN, _deployer, bytes1(0x87), uint56(_nonce));
    } else {
      _data = abi.encodePacked(bytes1(0xde), _LEN, _deployer, bytes1(0x88), uint64(_nonce));
    }

    _precalculatedAddress = address(uint160(uint256(keccak256(_data))));
  }
}

// src/contracts/L1OpUSDCFactory.sol

/**
 * @title L1OpUSDCFactory
 * @notice Factory contract to deploy and setup the `L1OpUSDCBridgeAdapter` contract on L1, and
 * triggers the deployment of the L2 factory, L2 adapter, and L2 USDC contracts.
 * @dev The salt is always different for each deployed instance of this contract on the L1 Factory, and the L2 contracts
 * are deployed with `CREATE` to guarantee that the addresses are unique among all the L2s, so we avoid a scenario where
 * L2 contracts have the same address on different L2s when triggered by different owners.
 */
contract L1OpUSDCFactory is IL1OpUSDCFactory {
  /// @inheritdoc IL1OpUSDCFactory
  address public constant L2_CREATE2_DEPLOYER = 0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2;

  /// @inheritdoc IL1OpUSDCFactory
  string public constant USDC_NAME = 'Bridged USDC';

  /// @inheritdoc IL1OpUSDCFactory
  string public constant USDC_SYMBOL = 'USDC.e';

  /// @notice The selector of the `initialize(string,string,string,uint8,address,address,address,address)` function.
  /// @dev Used to check the first init tx doesn't match it since it is already defined in the L2 factory contract
  bytes4 internal constant _INITIALIZE_SELECTOR = 0x3357162b;

  /// @notice The L2 Adapter proxy is the third of the L2 deployments so at that moment the nonce is 3
  uint256 internal constant _L2_ADAPTER_DEPLOYMENT_NONCE = 3;

  /// @inheritdoc IL1OpUSDCFactory
  IUSDC public immutable USDC;

  /// @inheritdoc IL1OpUSDCFactory
  uint256 public deploymentsSaltCounter;

  /**
   * @notice Constructs the L1 factory contract
   * @param _usdc The address of the USDC contract
   */
  constructor(address _usdc) {
    USDC = IUSDC(_usdc);
  }

  /**
   * @notice Deploys the L1 Adapter, and sends the deployment txs for the L2 factory, L2 adapter and the L2 USDC through
   * the L1 messenger
   * @param _l1Messenger The address of the L1 messenger for the L2 Op chain
   * @param _l1AdapterOwner The address of the owner of the L1 adapter
   * @param _chainName The name of the L2 Op chain
   * @param _l2Deployments The deployments data for the L2 adapter, and the L2 USDC contracts
   * @return _l1Adapter The address of the L1 adapter
   * @return _l2Deploy The address of the L2 deployer contract
   * @return _l2Adapter The address of the L2 adapter
   * @dev It can fail on L2 due to a gas miscalculation, but in that case the tx can be replayed. It only deploys 1 L2
   * factory per L2 deployments, to make sure the nonce is being tracked correctly while precalculating addresses
   * @dev The implementation of the USDC contract needs to be deployed on L2 before this is called
   * Then set the `usdcImplAddr` in the L2Deployments struct to the address of the deployed USDC implementation contract
   *
   * @dev IMPORTANT!!!!
   * The _l2Deployments.usdcInitTxs must be manually entered to correctly initialize the USDC contract on L2.
   * If a function is not included in the init txs, it could lead to potential attack vectors.
   * We currently hardcode the `initialize()` function in the L2 factory contract, to correctly configure the setup
   * You must provide the following init txs:
   * - initalizeV2
   * - initilizeV2_1
   * - initializeV2_2
   *
   * It is also important to note that circle may add more init functions in future implementations
   * This is up to the deployer to check and be sure all init transactions are included
   */
  function deploy(
    address _l1Messenger,
    address _l1AdapterOwner,
    string calldata _chainName,
    L2Deployments calldata _l2Deployments
  ) external returns (address _l1Adapter, address _l2Deploy, address _l2Adapter) {
    // Checks that the first init tx selector is not equal to the `initialize()` function since  we manually
    // Construct this function on the L2 factory contract
    if (bytes4(_l2Deployments.usdcInitTxs[0]) == _INITIALIZE_SELECTOR) revert IL1OpUSDCFactory_NoInitializeTx();

    // Update the salt counter so the L2 factory is deployed with a different salt to a different address and get it
    uint256 _currentNonce = deploymentsSaltCounter += 2;

    // Precalculate the l1 adapter proxy address
    _l1Adapter = CrossChainDeployments.precalculateCreateAddress(address(this), _currentNonce);

    // Get the L1 USDC naming and decimals to ensure they are the same on the L2, guaranteeing the same standard
    IL2OpUSDCDeploy.USDCInitializeData memory _usdcInitializeData = IL2OpUSDCDeploy.USDCInitializeData(
      string.concat(USDC_NAME, ' ', '(', _chainName, ')'), USDC_SYMBOL, USDC.currency(), USDC.decimals()
    );
    // Use the nonce as salt to ensure always a different salt since the nonce is always increasing
    bytes32 _salt = bytes32(_currentNonce);
    // Get the L2 factory init code and precalculate its address
    bytes memory _l2DeployCArgs = abi.encode(
      _l1Adapter,
      _l2Deployments.l2AdapterOwner,
      _l2Deployments.usdcImplAddr,
      _usdcInitializeData,
      _l2Deployments.usdcInitTxs
    );

    // Send the L2 factory deployment tx
    _l2Deploy = CrossChainDeployments.deployL2Factory(
      _l2DeployCArgs, _salt, _l1Messenger, L2_CREATE2_DEPLOYER, _l2Deployments.minGasLimitDeploy
    );

    // Precalculate the L2 adapter address
    _l2Adapter = CrossChainDeployments.precalculateCreateAddress(_l2Deploy, _L2_ADAPTER_DEPLOYMENT_NONCE);

    // Deploy L1 Adapter implementation and proxy, initializing it with the owner
    address _l1AdapterImpl = address(new L1OpUSDCBridgeAdapter(address(USDC), _l1Messenger, _l2Adapter));
    new ERC1967Proxy(_l1AdapterImpl, abi.encodeCall(OpUSDCBridgeAdapter.initialize, _l1AdapterOwner));

    emit ProtocolDeployed(_l1Adapter, _l2Deploy, _l2Adapter);
  }
}

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_usdc","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"IL1OpUSDCFactory_NoInitializeTx","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_l1Adapter","type":"address"},{"indexed":false,"internalType":"address","name":"_l2Deploy","type":"address"},{"indexed":false,"internalType":"address","name":"_l2Adapter","type":"address"}],"name":"ProtocolDeployed","type":"event"},{"inputs":[],"name":"L2_CREATE2_DEPLOYER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDC","outputs":[{"internalType":"contract IUSDC","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDC_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDC_SYMBOL","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Messenger","type":"address"},{"internalType":"address","name":"_l1AdapterOwner","type":"address"},{"internalType":"string","name":"_chainName","type":"string"},{"components":[{"internalType":"address","name":"l2AdapterOwner","type":"address"},{"internalType":"address","name":"usdcImplAddr","type":"address"},{"internalType":"uint32","name":"minGasLimitDeploy","type":"uint32"},{"internalType":"bytes[]","name":"usdcInitTxs","type":"bytes[]"}],"internalType":"struct IL1OpUSDCFactory.L2Deployments","name":"_l2Deployments","type":"tuple"}],"name":"deploy","outputs":[{"internalType":"address","name":"_l1Adapter","type":"address"},{"internalType":"address","name":"_l2Deploy","type":"address"},{"internalType":"address","name":"_l2Adapter","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deploymentsSaltCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60a0604052348015600f57600080fd5b5060405161461d38038061461d833981016040819052602c91603c565b6001600160a01b0316608052606a565b600060208284031215604d57600080fd5b81516001600160a01b0381168114606357600080fd5b9392505050565b60805161458461009960003960008181606c0152818161028c0152818161031701526104ab01526145846000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c806389a30271146100675780638b0f9bf8146100ab578063c25c3e18146100c6578063d6d9b34c146100f8578063eae1a64e14610135578063ec30286b1461014c575b600080fd5b61008e7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b61008e7313b0d85ccb8bf860b6b79af3029fca081ae9bef281565b6100eb60405180604001604052806006815260200165555344432e6560d01b81525081565b6040516100a291906109a7565b61010b6101063660046109f1565b610177565b604080516001600160a01b03948516815292841660208401529216918101919091526060016100a2565b61013e60005481565b6040519081526020016100a2565b6100eb6040518060400160405280600c81526020016b42726964676564205553444360a01b81525081565b60008080633357162b60e01b6101906060860186610aae565b60008181106101a1576101a1610aff565b90506020028101906101b39190610b15565b6101bc91610b5c565b6001600160e01b031916036101e4576040516340852a3f60e11b815260040160405180910390fd5b600060026000808282546101f89190610b8c565b925050819055905061020a30826105e7565b9350600060405180608001604052806040518060400160405280600c81526020016b42726964676564205553444360a01b8152508a8a60405160200161025293929190610bb3565b604051602081830303815290604052815260200160405180604001604052806006815260200165555344432e6560d01b81525081526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156102e8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526103109190810190610c11565b81526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610373573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103979190610cbe565b60ff1690529050816000866103af60208a018a610ce1565b6103bf60408b0160208c01610ce1565b856103cd60608d018d610aae565b6040516020016103e296959493929190610dbe565b6040516020818303038152906040529050731836b34184f2366917ca6135a6c9ac899421f7c66251ef5582848f7313b0d85ccb8bf860b6b79af3029fca081ae9bef28d60400160208101906104379190610e68565b6040518663ffffffff1660e01b8152600401610457959493929190610e8e565b602060405180830381865af4158015610474573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104989190610ed6565b95506104a58660036105e7565b945060007f00000000000000000000000000000000000000000000000000000000000000008d876040516104d89061093d565b6001600160a01b03938416815291831660208301529091166040820152606001604051809103906000f080158015610514573d6000803e3d6000fd5b506040516001600160a01b038e166024820152909150819060440160408051601f198184030181529181526020820180516001600160e01b031663189acdbd60e31b179052516105639061094a565b61056e929190610ef3565b604051809103906000f08015801561058a573d6000803e3d6000fd5b5050604080516001600160a01b038a81168252898116602083015288168183015290517fcccc4f8a3a087b06fc390663263fe07ebd765688740bdc56b78bdfe38e38f8dd9181900360600190a15050505050955095509592505050565b60006060607f831161064c57604051606b60f91b6020820152602560fa1b60218201526001600160601b0319606086901b16602282015260f884901b6001600160f81b03191660368201526037015b604051602081830303815290604052905061092e565b60ff83116106a55760405160d760f81b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152608160f81b603682015260f884901b6001600160f81b0319166037820152603801610636565b61ffff83116106ff57604051601b60fb1b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152604160f91b60368201526001600160f01b031960f085901b166037820152603901610636565b62ffffff831161075a5760405160d960f81b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152608360f81b60368201526001600160e81b031960e885901b166037820152603a01610636565b63ffffffff83116107b657604051606d60f91b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152602160fa1b60368201526001600160e01b031960e085901b166037820152603b01610636565b64ffffffffff83116108135760405160db60f81b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152608560f81b60368201526001600160d81b031960d885901b166037820152603c01610636565b65ffffffffffff831161087157604051603760fa1b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152604360f91b60368201526001600160d01b031960d085901b166037820152603d01610636565b66ffffffffffffff83116108d05760405160dd60f81b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152608760f81b60368201526001600160c81b031960c885901b166037820152603e01610636565b604051606f60f91b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152601160fb1b60368201526001600160c01b031960c085901b166037820152603f0160405160208183030381529060405290505b80516020909101209392505050565b61322580610f2083390190565b61040a8061414583390190565b60005b8381101561097257818101518382015260200161095a565b50506000910152565b60008151808452610993816020860160208601610957565b601f01601f19169290920160200192915050565b6020815260006109ba602083018461097b565b9392505050565b6001600160a01b03811681146109d657600080fd5b50565b6000608082840312156109eb57600080fd5b50919050565b600080600080600060808688031215610a0957600080fd5b8535610a14816109c1565b94506020860135610a24816109c1565b9350604086013567ffffffffffffffff80821115610a4157600080fd5b818801915088601f830112610a5557600080fd5b813581811115610a6457600080fd5b896020828501011115610a7657600080fd5b602083019550809450506060880135915080821115610a9457600080fd5b50610aa1888289016109d9565b9150509295509295909350565b6000808335601e19843603018112610ac557600080fd5b83018035915067ffffffffffffffff821115610ae057600080fd5b6020019150600581901b3603821315610af857600080fd5b9250929050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112610b2c57600080fd5b83018035915067ffffffffffffffff821115610b4757600080fd5b602001915036819003821315610af857600080fd5b6001600160e01b03198135818116916004851015610b845780818660040360031b1b83161692505b505092915050565b80820180821115610bad57634e487b7160e01b600052601160045260246000fd5b92915050565b60008451610bc5818460208901610957565b600160fd1b908301908152600560fb1b600182015283856002830137602960f81b93016002810193909352505060030192915050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215610c2357600080fd5b815167ffffffffffffffff80821115610c3b57600080fd5b818401915084601f830112610c4f57600080fd5b815181811115610c6157610c61610bfb565b604051601f8201601f19908116603f01168101908382118183101715610c8957610c89610bfb565b81604052828152876020848701011115610ca257600080fd5b610cb3836020830160208801610957565b979650505050505050565b600060208284031215610cd057600080fd5b815160ff811681146109ba57600080fd5b600060208284031215610cf357600080fd5b81356109ba816109c1565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000838385526020808601955060208560051b8301018460005b87811015610db157848303601f19018952813536889003601e19018112610d6757600080fd5b8701848101903567ffffffffffffffff811115610d8357600080fd5b803603821315610d9257600080fd5b610d9d858284610cfe565b9a86019a9450505090830190600101610d41565b5090979650505050505050565b600060018060a01b038089168352808816602084015280871660408401525060a060608301528451608060a0840152610dfb61012084018261097b565b90506020860151609f19808584030160c0860152610e19838361097b565b925060408801519150808584030160e086015250610e37828261097b565b91505060ff6060870151166101008401528281036080840152610e5b818587610d27565b9998505050505050505050565b600060208284031215610e7a57600080fd5b813563ffffffff811681146109ba57600080fd5b60a081526000610ea160a083018861097b565b6020830196909652506001600160a01b03938416604082015291909216606082015263ffffffff909116608090910152919050565b600060208284031215610ee857600080fd5b81516109ba816109c1565b6001600160a01b0383168152604060208201819052600090610f179083018461097b565b94935050505056fe6101006040523060805234801561001557600080fd5b5060405161322538038061322583398101604081905261003491610131565b6001600160a01b0380841660a05280831660e052811660c052828282610058610063565b505050505050610174565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156100b35760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146101125780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b80516001600160a01b038116811461012c57600080fd5b919050565b60008060006060848603121561014657600080fd5b61014f84610115565b925061015d60208501610115565b915061016b60408501610115565b90509250925092565b60805160a05160c05160e051612f916102946000396000818161046601528181610874015281816108c801528181610a0f01528181610a8b01528181610c3801528181610c8c01528181610eb101528181610f43015281816114490152818161149d015281816116ae01528181611784015281816118c90152818161196301528181611b880152611c6d0152600081816101fb0152818161089e01528181610c6201528181610ede01528181611473015281816116d7015281816118fe0152611bb10152600081816103e00152818161067f01528181610b4301528181610d7a01528181610fc60152818161112f015281816111d1015281816119e40152611b3c015260008181611cd401528181611cfd0152611e9d0152612f916000f3fe6080604052600436106101c25760003560e01c806389a30271116100f7578063bb416b3511610095578063e1ceec3411610064578063e1ceec34146105a5578063f2fde38b146105d9578063f68d1b9f146105f9578063fbea60221461061957600080fd5b8063bb416b351461051e578063c4d66de814610545578063cc43f3d314610565578063cdb9d2ea1461058557600080fd5b8063927ede2d116100d1578063927ede2d14610454578063ad3cb1cc14610488578063adbcea75146104c6578063aef26549146104e657600080fd5b806389a30271146103ce5780638a5e52bb146104025780638da5cb5b1461041757600080fd5b80634f872ec3116101645780635fae60251161013e5780635fae60251461035157806367bd044d14610371578063715018a61461039157806384b0196e146103a657600080fd5b80634f872ec3146102d157806352d1902d146102f15780635f8f4e9d1461030657600080fd5b80633bbcb44b116101a05780633bbcb44b1461025a578063486a7e6b1461027a5780634c598b561461029e5780634f1ef286146102be57600080fd5b80631902f068146101c75780632c8a6ae1146101e957806332b3a9871461023a575b600080fd5b3480156101d357600080fd5b506101e76101e2366004612883565b610639565b005b3480156101f557600080fd5b5061021d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561024657600080fd5b506101e7610255366004612948565b610869565b34801561026657600080fd5b5060365461021d906001600160a01b031681565b34801561028657600080fd5b5061029060355481565b604051908152602001610231565b3480156102aa57600080fd5b506101e76102b9366004612989565b610afd565b6101e76102cc3660046129dd565b610c0e565b3480156102dd57600080fd5b506101e76102ec366004612aa1565b610c2d565b3480156102fd57600080fd5b50610290610de8565b34801561031257600080fd5b50610341610321366004612aa1565b600160209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610231565b34801561035d57600080fd5b506101e761036c366004612acd565b610e05565b34801561037d57600080fd5b506101e761038c366004612aa1565b610f99565b34801561039d57600080fd5b506101e7610fed565b3480156103b257600080fd5b506103bb611001565b6040516102319796959493929190612b38565b3480156103da57600080fd5b5061021d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561040e57600080fd5b506101e76110b2565b34801561042357600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031661021d565b34801561046057600080fd5b5061021d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561049457600080fd5b506104b9604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516102319190612bd1565b3480156104d257600080fd5b506101e76104e1366004612be4565b611282565b3480156104f257600080fd5b50610290610501366004612bfd565b600260209081526000928352604080842090915290825290205481565b34801561052a57600080fd5b506000546105389060ff1681565b6040516102319190612c4c565b34801561055157600080fd5b506101e7610560366004612c74565b6112db565b34801561057157600080fd5b506101e7610580366004612be4565b61143e565b34801561059157600080fd5b506101e76105a0366004612c91565b6115c0565b3480156105b157600080fd5b506102907f87e4683aad14f1869b43140e06b846bd1b00c2e08e9825f6719d163b4cfef2a681565b3480156105e557600080fd5b506101e76105f4366004612c74565b6117e2565b34801561060557600080fd5b506101e7610614366004612acd565b611820565b34801561062557600080fd5b506101e7610634366004612bfd565b6119b2565b6001600160a01b03871661066057604051635432922d60e01b815260040160405180910390fd5b60405163fe575a8760e01b81526001600160a01b0388811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063fe575a8790602401602060405180830381865afa1580156106c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ea9190612ce9565b1561070857604051636e7fdaf760e11b815260040160405180910390fd5b6000805460ff16600381111561072057610720612c36565b1461073e57604051636a14cf2360e01b815260040160405180910390fd5b6001600160a01b038816600090815260016020908152604080832086845290915290205460ff1615610783576040516308be5f9d60e31b815260040160405180910390fd5b814211156107a457604051633c3c667760e01b815260040160405180910390fd5b6040805160a0810182526001600160a01b0389168152602081018890529081018390526060810184905263ffffffff82166080820152610823896107e783611a53565b88888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611af392505050565b6001600160a01b0389166000908152600160208181526040808420888552909152909120805460ff1916909117905561085e89898985611b2f565b505050505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614158061095457507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610924573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109489190612d0b565b6001600160a01b031614155b156109725760405163040e613d60e21b815260040160405180910390fd5b6040516367bd044d60e01b81526001600160a01b03841660048201526024810182905230906367bd044d90604401600060405180830381600087803b1580156109ba57600080fd5b505af19250505080156109cb575060015b610a89576001600160a01b03808316600090815260026020908152604080832093871683529290529081208054839290610a06908490612d28565b925050819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316836001600160a01b03167f57b0fa6deabbc9b92da071a794e0ee49fda25fca31a9e5a0336632a6731bda8484604051610a7c91815260200190565b60405180910390a4505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316836001600160a01b03167f6bf7034bf4a66e25fc097062a5aad392485138a48987ad77209e332e2535915684604051610a7c91815260200190565b505050565b6001600160a01b038316610b2457604051635432922d60e01b815260040160405180910390fd5b60405163fe575a8760e01b81526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063fe575a8790602401602060405180830381865afa158015610b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bae9190612ce9565b15610bcc57604051636e7fdaf760e11b815260040160405180910390fd5b6000805460ff166003811115610be457610be4612c36565b14610c0257604051636a14cf2360e01b815260040160405180910390fd5b610af833848484611b2f565b610c16611cc9565b610c1f82611d6e565b610c298282611d76565b5050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016141580610d1857507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ce8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d0c9190612d0b565b6001600160a01b031614155b15610d365760405163040e613d60e21b815260040160405180910390fd5b600360005460ff166003811115610d4f57610d4f612c36565b14610d6d57604051639e76a5b960e01b815260040160405180910390fd5b610da16001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168383611e33565b816001600160a01b03167fc47b52177930ba2672bfc1f75da55cf82adb3c61c2df74e28bdfefbf52ae9e0582604051610ddc91815260200190565b60405180910390a25050565b6000610df2611e92565b50600080516020612f3c83398151915290565b610e0d611edb565b600160005460ff166003811115610e2657610e26612c36565b14158015610e4a57506000805460ff166003811115610e4757610e47612c36565b14155b15610e6857604051637812aefb60e11b815260040160405180910390fd5b6000805460ff191690556040805160048082526024820183526020820180516001600160e01b031663fc8b55c760e01b1790529151633dbb202b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692633dbb202b92610f06927f000000000000000000000000000000000000000000000000000000000000000092879101612d49565b600060405180830381600087803b158015610f2057600080fd5b505af1158015610f34573d6000803e3d6000fd5b50506040516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681527ff1e9473f25478fe3af97fb26517a1882c3addc66e942ce3c98a2aeffaec54a58925060200190505b60405180910390a150565b333014610fb95760405163040e613d60e21b815260040160405180910390fd5b610c296001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168383611e33565b610ff5611edb565b610fff6000611f36565b565b60006060808280808381600080516020612f1c833981519152805490915015801561102e57506001810154155b6110775760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064015b60405180910390fd5b61107f611fa7565b61108761206a565b60408051600080825260208201909252600f60f81b9c939b5091995046985030975095509350915050565b6036546001600160a01b031633146110dd5760405163040e613d60e21b815260040160405180910390fd5b600360005460ff1660038111156110f6576110f6612c36565b146111145760405163622facd560e11b815260040160405180910390fd5b6035546040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561117e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a29190612d83565b90508082116111b157816111b3565b805b9150811561123657604051630852cd8d60e31b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b15801561121d57600080fd5b505af1158015611231573d6000803e3d6000fd5b505050505b6000603555603680546001600160a01b03191690556040518281527f82691da855159f603f5aecf930c44c33ed2b5838cbb20d7009074b3853c6a31d9060200160405180910390a15050565b336000818152600160208181526040808420868552825292839020805460ff1916909217909155815192835282018390527f0e6a4f4985873f666a9aa21268ce8c462bedf4231c9ed2811360ce956701cb289101610f8e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156113215750825b905060008267ffffffffffffffff16600114801561133e5750303b155b90508115801561134c575080155b1561136a5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561139457845460ff60401b1916600160401b1785555b61139d866120a9565b604080518082018252601381527227b82aa9a221a13934b233b2a0b230b83a32b960691b602080830191909152825180840190935260058352640312e302e360dc1b90830152906113ee82826120ba565b5050831561143657845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614158061152957507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151d9190612d0b565b6001600160a01b031614155b156115475760405163040e613d60e21b815260040160405180910390fd5b600260005460ff16600381111561156057611560612c36565b1461157e576040516314ca5c1760e21b815260040160405180910390fd5b60358190556000805460ff191660031790556040518181527f38acaebd0e3affc51737125878fe1e25cb5fdb627b3778416219d82f81ef42f890602001610f8e565b6115c8611edb565b6001600160a01b03841615806115e557506001600160a01b038316155b1561160357604051635432922d60e01b815260040160405180910390fd5b6000805460ff16600381111561161b5761161b612c36565b141580156116405750600260005460ff16600381111561163d5761163d612c36565b14155b1561165e57604051636a14cf2360e01b815260040160405180910390fd5b603680546001600160a01b0319166001600160a01b038516179055600080546002919060ff191660018302179055506040516001600160a01b03858116602483015263ffffffff831660448301527f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b907f00000000000000000000000000000000000000000000000000000000000000009060640160408051601f198184030181529181526020820180516001600160e01b03166369c5f5f360e01b179052516001600160e01b031960e085901b1681526117469291908790600401612d49565b600060405180830381600087803b15801561176057600080fd5b505af1158015611774573d6000803e3d6000fd5b5050604080516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081168252871660208201527f06aeee5a19965b1536947b7571a17a681add9aad3efd41c1bec130257eaab6c9935001905060405180910390a150505050565b6117ea611edb565b6001600160a01b03811661181457604051631e4fbdf760e01b81526000600482015260240161106e565b61181d81611f36565b50565b611828611edb565b6000805460ff16600381111561184057611840612c36565b141580156118655750600160005460ff16600381111561186257611862612c36565b14155b1561188357604051636a14cf2360e01b815260040160405180910390fd5b6000805460ff19166001179055604080516004808252602482018352602082018051634384a98f60e01b6001600160e01b039091161790529151633dbb202b60e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692633dbb202b92611926927f000000000000000000000000000000000000000000000000000000000000000092879101612d49565b600060405180830381600087803b15801561194057600080fd5b505af1158015611954573d6000803e3d6000fd5b50506040516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681527fc19ffaed16cc79d2c0c853889a5b1fd248a9208d0478bc07dd2da1cda4e8999292506020019050610f8e565b6001600160a01b03828116600090815260026020908152604080832085851684529091528120805491905590611a0b907f0000000000000000000000000000000000000000000000000000000000000000168383611e33565b816001600160a01b03167fc47b52177930ba2672bfc1f75da55cf82adb3c61c2df74e28bdfefbf52ae9e0582604051611a4691815260200190565b60405180910390a2505050565b60007f87e4683aad14f1869b43140e06b846bd1b00c2e08e9825f6719d163b4cfef2a682600001518360200151846040015185606001518660800151604051602001611ad6969594939291909586526001600160a01b0394909416602086015260408501929092526060840152608083015263ffffffff1660a082015260c00190565b604051602081830303815290604052805190602001209050919050565b611afc826120cc565b9150611b126001600160a01b03841683836120ff565b610af8576040516398ceb44f60e01b815260040160405180910390fd5b611b646001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016853085612163565b6040516001600160a01b0384811660248301528581166044830152606482018490527f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b907f00000000000000000000000000000000000000000000000000000000000000009060840160408051601f198184030181529181526020820180516001600160e01b03166332b3a98760e01b179052516001600160e01b031960e085901b168152611c209291908690600401612d49565b600060405180830381600087803b158015611c3a57600080fd5b505af1158015611c4e573d6000803e3d6000fd5b50506040805185815263ffffffff851660208201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116945087811693508816917fb8fa5fd165287d2cb897cb3ee53488b768ead242c87070b349394d2639824d4c910160405180910390a450505050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611d5057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611d44600080516020612f3c833981519152546001600160a01b031690565b6001600160a01b031614155b15610fff5760405163703e46dd60e11b815260040160405180910390fd5b61181d611edb565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611dd0575060408051601f3d908101601f19168201909252611dcd91810190612d83565b60015b611df857604051634c9c8ce360e01b81526001600160a01b038316600482015260240161106e565b600080516020612f3c8339815191528114611e2957604051632a87526960e21b81526004810182905260240161106e565b610af883836121a2565b6040516001600160a01b03838116602483015260448201839052610af891859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506121f8565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610fff5760405163703e46dd60e11b815260040160405180910390fd5b33611f0d7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614610fff5760405163118cdaa760e01b815233600482015260240161106e565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1028054606091600080516020612f1c83398151915291611fe690612d9c565b80601f016020809104026020016040519081016040528092919081815260200182805461201290612d9c565b801561205f5780601f106120345761010080835404028352916020019161205f565b820191906000526020600020905b81548152906001019060200180831161204257829003601f168201915b505050505091505090565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1038054606091600080516020612f1c83398151915291611fe690612d9c565b6120b161225b565b61181d816122a4565b6120c261225b565b610c2982826122ac565b60006120f96120d961230d565b8360405161190160f01b8152600281019290925260228201526042902090565b92915050565b600080600061210e858561231c565b509092509050600081600381111561212857612128612c36565b1480156121465750856001600160a01b0316826001600160a01b0316145b806121575750612157868686612369565b925050505b9392505050565b6040516001600160a01b03848116602483015283811660448301526064820183905261219c9186918216906323b872dd90608401611e60565b50505050565b6121ab82612444565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a28051156121f057610af882826124a9565b610c2961251f565b600061220d6001600160a01b0384168361253e565b905080516000141580156122325750808060200190518101906122309190612ce9565b155b15610af857604051635274afe760e01b81526001600160a01b038416600482015260240161106e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610fff57604051631afcd79f60e31b815260040160405180910390fd5b6117ea61225b565b6122b461225b565b600080516020612f1c8339815191527fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1026122ee8482612e1e565b50600381016122fd8382612e1e565b5060008082556001909101555050565b600061231761254c565b905090565b600080600083516041036123565760208401516040850151606086015160001a612348888285856125c0565b955095509550505050612362565b50508151600091506002905b9250925092565b6000806000856001600160a01b0316858560405160240161238b929190612ede565b60408051601f198184030181529181526020820180516001600160e01b0316630b135d3f60e11b179052516123c09190612eff565b600060405180830381855afa9150503d80600081146123fb576040519150601f19603f3d011682016040523d82523d6000602084013e612400565b606091505b509150915081801561241457506020815110155b801561215757508051630b135d3f60e11b906124399083016020908101908401612d83565b149695505050505050565b806001600160a01b03163b60000361247a57604051634c9c8ce360e01b81526001600160a01b038216600482015260240161106e565b600080516020612f3c83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516124c69190612eff565b600060405180830381855af49150503d8060008114612501576040519150601f19603f3d011682016040523d82523d6000602084013e612506565b606091505b509150915061251685838361268f565b95945050505050565b3415610fff5760405163b398979f60e01b815260040160405180910390fd5b606061215c838360006126eb565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61257761277e565b61257f6127e8565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156125fb5750600091506003905082612685565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa15801561264f573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661267b57506000925060019150829050612685565b9250600091508190505b9450945094915050565b6060826126a45761269f8261282c565b61215c565b81511580156126bb57506001600160a01b0384163b155b156126e457604051639996b31560e01b81526001600160a01b038516600482015260240161106e565b508061215c565b6060814710156127105760405163cd78605960e01b815230600482015260240161106e565b600080856001600160a01b0316848660405161272c9190612eff565b60006040518083038185875af1925050503d8060008114612769576040519150601f19603f3d011682016040523d82523d6000602084013e61276e565b606091505b509150915061215786838361268f565b6000600080516020612f1c83398151915281612798611fa7565b8051909150156127b057805160209091012092915050565b815480156127bf579392505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470935050505090565b6000600080516020612f1c8339815191528161280261206a565b80519091501561281a57805160209091012092915050565b600182015480156127bf579392505050565b80511561283c5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b038116811461181d57600080fd5b803563ffffffff8116811461287e57600080fd5b919050565b60008060008060008060008060e0898b03121561289f57600080fd5b88356128aa81612855565b975060208901356128ba81612855565b965060408901359550606089013567ffffffffffffffff808211156128de57600080fd5b818b0191508b601f8301126128f257600080fd5b81358181111561290157600080fd5b8c602082850101111561291357600080fd5b6020830197508096505050506080890135925060a0890135915061293960c08a0161286a565b90509295985092959890939650565b60008060006060848603121561295d57600080fd5b833561296881612855565b9250602084013561297881612855565b929592945050506040919091013590565b60008060006060848603121561299e57600080fd5b83356129a981612855565b9250602084013591506129be6040850161286a565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156129f057600080fd5b82356129fb81612855565b9150602083013567ffffffffffffffff80821115612a1857600080fd5b818501915085601f830112612a2c57600080fd5b813581811115612a3e57612a3e6129c7565b604051601f8201601f19908116603f01168101908382118183101715612a6657612a666129c7565b81604052828152886020848701011115612a7f57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60008060408385031215612ab457600080fd5b8235612abf81612855565b946020939093013593505050565b600060208284031215612adf57600080fd5b61215c8261286a565b60005b83811015612b03578181015183820152602001612aeb565b50506000910152565b60008151808452612b24816020860160208601612ae8565b601f01601f19169290920160200192915050565b60ff60f81b881681526000602060e06020840152612b5960e084018a612b0c565b8381036040850152612b6b818a612b0c565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b81811015612bbf57835183529284019291840191600101612ba3565b50909c9b505050505050505050505050565b60208152600061215c6020830184612b0c565b600060208284031215612bf657600080fd5b5035919050565b60008060408385031215612c1057600080fd5b8235612c1b81612855565b91506020830135612c2b81612855565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b6020810160048310612c6e57634e487b7160e01b600052602160045260246000fd5b91905290565b600060208284031215612c8657600080fd5b813561215c81612855565b60008060008060808587031215612ca757600080fd5b8435612cb281612855565b93506020850135612cc281612855565b9250612cd06040860161286a565b9150612cde6060860161286a565b905092959194509250565b600060208284031215612cfb57600080fd5b8151801515811461215c57600080fd5b600060208284031215612d1d57600080fd5b815161215c81612855565b808201808211156120f957634e487b7160e01b600052601160045260246000fd5b6001600160a01b0384168152606060208201819052600090612d6d90830185612b0c565b905063ffffffff83166040830152949350505050565b600060208284031215612d9557600080fd5b5051919050565b600181811c90821680612db057607f821691505b602082108103612dd057634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610af8576000816000526020600020601f850160051c81016020861015612dff5750805b601f850160051c820191505b8181101561143657828155600101612e0b565b815167ffffffffffffffff811115612e3857612e386129c7565b612e4c81612e468454612d9c565b84612dd6565b602080601f831160018114612e815760008415612e695750858301515b600019600386901b1c1916600185901b178555611436565b600085815260208120601f198616915b82811015612eb057888601518255948401946001909101908401612e91565b5085821015612ece5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b828152604060208201526000612ef76040830184612b0c565b949350505050565b60008251612f11818460208701612ae8565b919091019291505056fea16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212200ddb033b58a89d5a64fdf537a01b9b42b244de4dc988b6956399f187bffe09bf64736f6c63430008190033608060405260405161040a38038061040a83398101604081905261002291610268565b61002c8282610033565b5050610352565b61003c82610092565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a280511561008657610081828261010e565b505050565b61008e610185565b5050565b806001600160a01b03163b6000036100cd57604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b03168460405161012b9190610336565b600060405180830381855af49150503d8060008114610166576040519150601f19603f3d011682016040523d82523d6000602084013e61016b565b606091505b50909250905061017c8583836101a6565b95945050505050565b34156101a45760405163b398979f60e01b815260040160405180910390fd5b565b6060826101bb576101b682610205565b6101fe565b81511580156101d257506001600160a01b0384163b155b156101fb57604051639996b31560e01b81526001600160a01b03851660048201526024016100c4565b50805b9392505050565b8051156102155780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b600052604160045260246000fd5b60005b8381101561025f578181015183820152602001610247565b50506000910152565b6000806040838503121561027b57600080fd5b82516001600160a01b038116811461029257600080fd5b60208401519092506001600160401b03808211156102af57600080fd5b818501915085601f8301126102c357600080fd5b8151818111156102d5576102d561022e565b604051601f8201601f19908116603f011681019083821181831017156102fd576102fd61022e565b8160405282815288602084870101111561031657600080fd5b610327836020830160208801610244565b80955050505050509250929050565b60008251610348818460208701610244565b9190910192915050565b60aa806103606000396000f3fe6080604052600a600c565b005b60186014601a565b6051565b565b6000604c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e808015606f573d6000f35b3d6000fdfea264697066735822122033b4da528499851fa7a71d76c9379fa5c3858f229a179c9593045387f3d7985b64736f6c63430008190033a2646970667358221220e15270d5393a96ba7fba6637667ee8daa124a62133229b037fde0281b63fac1864736f6c634300081900330000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100625760003560e01c806389a30271146100675780638b0f9bf8146100ab578063c25c3e18146100c6578063d6d9b34c146100f8578063eae1a64e14610135578063ec30286b1461014c575b600080fd5b61008e7f0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c723881565b6040516001600160a01b0390911681526020015b60405180910390f35b61008e7313b0d85ccb8bf860b6b79af3029fca081ae9bef281565b6100eb60405180604001604052806006815260200165555344432e6560d01b81525081565b6040516100a291906109a7565b61010b6101063660046109f1565b610177565b604080516001600160a01b03948516815292841660208401529216918101919091526060016100a2565b61013e60005481565b6040519081526020016100a2565b6100eb6040518060400160405280600c81526020016b42726964676564205553444360a01b81525081565b60008080633357162b60e01b6101906060860186610aae565b60008181106101a1576101a1610aff565b90506020028101906101b39190610b15565b6101bc91610b5c565b6001600160e01b031916036101e4576040516340852a3f60e11b815260040160405180910390fd5b600060026000808282546101f89190610b8c565b925050819055905061020a30826105e7565b9350600060405180608001604052806040518060400160405280600c81526020016b42726964676564205553444360a01b8152508a8a60405160200161025293929190610bb3565b604051602081830303815290604052815260200160405180604001604052806006815260200165555344432e6560d01b81525081526020017f0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c72386001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156102e8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526103109190810190610c11565b81526020017f0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c72386001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610373573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103979190610cbe565b60ff1690529050816000866103af60208a018a610ce1565b6103bf60408b0160208c01610ce1565b856103cd60608d018d610aae565b6040516020016103e296959493929190610dbe565b6040516020818303038152906040529050731836b34184f2366917ca6135a6c9ac899421f7c66251ef5582848f7313b0d85ccb8bf860b6b79af3029fca081ae9bef28d60400160208101906104379190610e68565b6040518663ffffffff1660e01b8152600401610457959493929190610e8e565b602060405180830381865af4158015610474573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104989190610ed6565b95506104a58660036105e7565b945060007f0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c72388d876040516104d89061093d565b6001600160a01b03938416815291831660208301529091166040820152606001604051809103906000f080158015610514573d6000803e3d6000fd5b506040516001600160a01b038e166024820152909150819060440160408051601f198184030181529181526020820180516001600160e01b031663189acdbd60e31b179052516105639061094a565b61056e929190610ef3565b604051809103906000f08015801561058a573d6000803e3d6000fd5b5050604080516001600160a01b038a81168252898116602083015288168183015290517fcccc4f8a3a087b06fc390663263fe07ebd765688740bdc56b78bdfe38e38f8dd9181900360600190a15050505050955095509592505050565b60006060607f831161064c57604051606b60f91b6020820152602560fa1b60218201526001600160601b0319606086901b16602282015260f884901b6001600160f81b03191660368201526037015b604051602081830303815290604052905061092e565b60ff83116106a55760405160d760f81b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152608160f81b603682015260f884901b6001600160f81b0319166037820152603801610636565b61ffff83116106ff57604051601b60fb1b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152604160f91b60368201526001600160f01b031960f085901b166037820152603901610636565b62ffffff831161075a5760405160d960f81b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152608360f81b60368201526001600160e81b031960e885901b166037820152603a01610636565b63ffffffff83116107b657604051606d60f91b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152602160fa1b60368201526001600160e01b031960e085901b166037820152603b01610636565b64ffffffffff83116108135760405160db60f81b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152608560f81b60368201526001600160d81b031960d885901b166037820152603c01610636565b65ffffffffffff831161087157604051603760fa1b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152604360f91b60368201526001600160d01b031960d085901b166037820152603d01610636565b66ffffffffffffff83116108d05760405160dd60f81b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152608760f81b60368201526001600160c81b031960c885901b166037820152603e01610636565b604051606f60f91b6020820152602560fa1b60218201526001600160601b0319606086901b166022820152601160fb1b60368201526001600160c01b031960c085901b166037820152603f0160405160208183030381529060405290505b80516020909101209392505050565b61322580610f2083390190565b61040a8061414583390190565b60005b8381101561097257818101518382015260200161095a565b50506000910152565b60008151808452610993816020860160208601610957565b601f01601f19169290920160200192915050565b6020815260006109ba602083018461097b565b9392505050565b6001600160a01b03811681146109d657600080fd5b50565b6000608082840312156109eb57600080fd5b50919050565b600080600080600060808688031215610a0957600080fd5b8535610a14816109c1565b94506020860135610a24816109c1565b9350604086013567ffffffffffffffff80821115610a4157600080fd5b818801915088601f830112610a5557600080fd5b813581811115610a6457600080fd5b896020828501011115610a7657600080fd5b602083019550809450506060880135915080821115610a9457600080fd5b50610aa1888289016109d9565b9150509295509295909350565b6000808335601e19843603018112610ac557600080fd5b83018035915067ffffffffffffffff821115610ae057600080fd5b6020019150600581901b3603821315610af857600080fd5b9250929050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112610b2c57600080fd5b83018035915067ffffffffffffffff821115610b4757600080fd5b602001915036819003821315610af857600080fd5b6001600160e01b03198135818116916004851015610b845780818660040360031b1b83161692505b505092915050565b80820180821115610bad57634e487b7160e01b600052601160045260246000fd5b92915050565b60008451610bc5818460208901610957565b600160fd1b908301908152600560fb1b600182015283856002830137602960f81b93016002810193909352505060030192915050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215610c2357600080fd5b815167ffffffffffffffff80821115610c3b57600080fd5b818401915084601f830112610c4f57600080fd5b815181811115610c6157610c61610bfb565b604051601f8201601f19908116603f01168101908382118183101715610c8957610c89610bfb565b81604052828152876020848701011115610ca257600080fd5b610cb3836020830160208801610957565b979650505050505050565b600060208284031215610cd057600080fd5b815160ff811681146109ba57600080fd5b600060208284031215610cf357600080fd5b81356109ba816109c1565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000838385526020808601955060208560051b8301018460005b87811015610db157848303601f19018952813536889003601e19018112610d6757600080fd5b8701848101903567ffffffffffffffff811115610d8357600080fd5b803603821315610d9257600080fd5b610d9d858284610cfe565b9a86019a9450505090830190600101610d41565b5090979650505050505050565b600060018060a01b038089168352808816602084015280871660408401525060a060608301528451608060a0840152610dfb61012084018261097b565b90506020860151609f19808584030160c0860152610e19838361097b565b925060408801519150808584030160e086015250610e37828261097b565b91505060ff6060870151166101008401528281036080840152610e5b818587610d27565b9998505050505050505050565b600060208284031215610e7a57600080fd5b813563ffffffff811681146109ba57600080fd5b60a081526000610ea160a083018861097b565b6020830196909652506001600160a01b03938416604082015291909216606082015263ffffffff909116608090910152919050565b600060208284031215610ee857600080fd5b81516109ba816109c1565b6001600160a01b0383168152604060208201819052600090610f179083018461097b565b94935050505056fe6101006040523060805234801561001557600080fd5b5060405161322538038061322583398101604081905261003491610131565b6001600160a01b0380841660a05280831660e052811660c052828282610058610063565b505050505050610174565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156100b35760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146101125780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b80516001600160a01b038116811461012c57600080fd5b919050565b60008060006060848603121561014657600080fd5b61014f84610115565b925061015d60208501610115565b915061016b60408501610115565b90509250925092565b60805160a05160c05160e051612f916102946000396000818161046601528181610874015281816108c801528181610a0f01528181610a8b01528181610c3801528181610c8c01528181610eb101528181610f43015281816114490152818161149d015281816116ae01528181611784015281816118c90152818161196301528181611b880152611c6d0152600081816101fb0152818161089e01528181610c6201528181610ede01528181611473015281816116d7015281816118fe0152611bb10152600081816103e00152818161067f01528181610b4301528181610d7a01528181610fc60152818161112f015281816111d1015281816119e40152611b3c015260008181611cd401528181611cfd0152611e9d0152612f916000f3fe6080604052600436106101c25760003560e01c806389a30271116100f7578063bb416b3511610095578063e1ceec3411610064578063e1ceec34146105a5578063f2fde38b146105d9578063f68d1b9f146105f9578063fbea60221461061957600080fd5b8063bb416b351461051e578063c4d66de814610545578063cc43f3d314610565578063cdb9d2ea1461058557600080fd5b8063927ede2d116100d1578063927ede2d14610454578063ad3cb1cc14610488578063adbcea75146104c6578063aef26549146104e657600080fd5b806389a30271146103ce5780638a5e52bb146104025780638da5cb5b1461041757600080fd5b80634f872ec3116101645780635fae60251161013e5780635fae60251461035157806367bd044d14610371578063715018a61461039157806384b0196e146103a657600080fd5b80634f872ec3146102d157806352d1902d146102f15780635f8f4e9d1461030657600080fd5b80633bbcb44b116101a05780633bbcb44b1461025a578063486a7e6b1461027a5780634c598b561461029e5780634f1ef286146102be57600080fd5b80631902f068146101c75780632c8a6ae1146101e957806332b3a9871461023a575b600080fd5b3480156101d357600080fd5b506101e76101e2366004612883565b610639565b005b3480156101f557600080fd5b5061021d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561024657600080fd5b506101e7610255366004612948565b610869565b34801561026657600080fd5b5060365461021d906001600160a01b031681565b34801561028657600080fd5b5061029060355481565b604051908152602001610231565b3480156102aa57600080fd5b506101e76102b9366004612989565b610afd565b6101e76102cc3660046129dd565b610c0e565b3480156102dd57600080fd5b506101e76102ec366004612aa1565b610c2d565b3480156102fd57600080fd5b50610290610de8565b34801561031257600080fd5b50610341610321366004612aa1565b600160209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610231565b34801561035d57600080fd5b506101e761036c366004612acd565b610e05565b34801561037d57600080fd5b506101e761038c366004612aa1565b610f99565b34801561039d57600080fd5b506101e7610fed565b3480156103b257600080fd5b506103bb611001565b6040516102319796959493929190612b38565b3480156103da57600080fd5b5061021d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561040e57600080fd5b506101e76110b2565b34801561042357600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031661021d565b34801561046057600080fd5b5061021d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561049457600080fd5b506104b9604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516102319190612bd1565b3480156104d257600080fd5b506101e76104e1366004612be4565b611282565b3480156104f257600080fd5b50610290610501366004612bfd565b600260209081526000928352604080842090915290825290205481565b34801561052a57600080fd5b506000546105389060ff1681565b6040516102319190612c4c565b34801561055157600080fd5b506101e7610560366004612c74565b6112db565b34801561057157600080fd5b506101e7610580366004612be4565b61143e565b34801561059157600080fd5b506101e76105a0366004612c91565b6115c0565b3480156105b157600080fd5b506102907f87e4683aad14f1869b43140e06b846bd1b00c2e08e9825f6719d163b4cfef2a681565b3480156105e557600080fd5b506101e76105f4366004612c74565b6117e2565b34801561060557600080fd5b506101e7610614366004612acd565b611820565b34801561062557600080fd5b506101e7610634366004612bfd565b6119b2565b6001600160a01b03871661066057604051635432922d60e01b815260040160405180910390fd5b60405163fe575a8760e01b81526001600160a01b0388811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063fe575a8790602401602060405180830381865afa1580156106c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ea9190612ce9565b1561070857604051636e7fdaf760e11b815260040160405180910390fd5b6000805460ff16600381111561072057610720612c36565b1461073e57604051636a14cf2360e01b815260040160405180910390fd5b6001600160a01b038816600090815260016020908152604080832086845290915290205460ff1615610783576040516308be5f9d60e31b815260040160405180910390fd5b814211156107a457604051633c3c667760e01b815260040160405180910390fd5b6040805160a0810182526001600160a01b0389168152602081018890529081018390526060810184905263ffffffff82166080820152610823896107e783611a53565b88888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611af392505050565b6001600160a01b0389166000908152600160208181526040808420888552909152909120805460ff1916909117905561085e89898985611b2f565b505050505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614158061095457507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610924573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109489190612d0b565b6001600160a01b031614155b156109725760405163040e613d60e21b815260040160405180910390fd5b6040516367bd044d60e01b81526001600160a01b03841660048201526024810182905230906367bd044d90604401600060405180830381600087803b1580156109ba57600080fd5b505af19250505080156109cb575060015b610a89576001600160a01b03808316600090815260026020908152604080832093871683529290529081208054839290610a06908490612d28565b925050819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316836001600160a01b03167f57b0fa6deabbc9b92da071a794e0ee49fda25fca31a9e5a0336632a6731bda8484604051610a7c91815260200190565b60405180910390a4505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316836001600160a01b03167f6bf7034bf4a66e25fc097062a5aad392485138a48987ad77209e332e2535915684604051610a7c91815260200190565b505050565b6001600160a01b038316610b2457604051635432922d60e01b815260040160405180910390fd5b60405163fe575a8760e01b81526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063fe575a8790602401602060405180830381865afa158015610b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bae9190612ce9565b15610bcc57604051636e7fdaf760e11b815260040160405180910390fd5b6000805460ff166003811115610be457610be4612c36565b14610c0257604051636a14cf2360e01b815260040160405180910390fd5b610af833848484611b2f565b610c16611cc9565b610c1f82611d6e565b610c298282611d76565b5050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016141580610d1857507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ce8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d0c9190612d0b565b6001600160a01b031614155b15610d365760405163040e613d60e21b815260040160405180910390fd5b600360005460ff166003811115610d4f57610d4f612c36565b14610d6d57604051639e76a5b960e01b815260040160405180910390fd5b610da16001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168383611e33565b816001600160a01b03167fc47b52177930ba2672bfc1f75da55cf82adb3c61c2df74e28bdfefbf52ae9e0582604051610ddc91815260200190565b60405180910390a25050565b6000610df2611e92565b50600080516020612f3c83398151915290565b610e0d611edb565b600160005460ff166003811115610e2657610e26612c36565b14158015610e4a57506000805460ff166003811115610e4757610e47612c36565b14155b15610e6857604051637812aefb60e11b815260040160405180910390fd5b6000805460ff191690556040805160048082526024820183526020820180516001600160e01b031663fc8b55c760e01b1790529151633dbb202b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692633dbb202b92610f06927f000000000000000000000000000000000000000000000000000000000000000092879101612d49565b600060405180830381600087803b158015610f2057600080fd5b505af1158015610f34573d6000803e3d6000fd5b50506040516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681527ff1e9473f25478fe3af97fb26517a1882c3addc66e942ce3c98a2aeffaec54a58925060200190505b60405180910390a150565b333014610fb95760405163040e613d60e21b815260040160405180910390fd5b610c296001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168383611e33565b610ff5611edb565b610fff6000611f36565b565b60006060808280808381600080516020612f1c833981519152805490915015801561102e57506001810154155b6110775760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064015b60405180910390fd5b61107f611fa7565b61108761206a565b60408051600080825260208201909252600f60f81b9c939b5091995046985030975095509350915050565b6036546001600160a01b031633146110dd5760405163040e613d60e21b815260040160405180910390fd5b600360005460ff1660038111156110f6576110f6612c36565b146111145760405163622facd560e11b815260040160405180910390fd5b6035546040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561117e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a29190612d83565b90508082116111b157816111b3565b805b9150811561123657604051630852cd8d60e31b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b15801561121d57600080fd5b505af1158015611231573d6000803e3d6000fd5b505050505b6000603555603680546001600160a01b03191690556040518281527f82691da855159f603f5aecf930c44c33ed2b5838cbb20d7009074b3853c6a31d9060200160405180910390a15050565b336000818152600160208181526040808420868552825292839020805460ff1916909217909155815192835282018390527f0e6a4f4985873f666a9aa21268ce8c462bedf4231c9ed2811360ce956701cb289101610f8e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156113215750825b905060008267ffffffffffffffff16600114801561133e5750303b155b90508115801561134c575080155b1561136a5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561139457845460ff60401b1916600160401b1785555b61139d866120a9565b604080518082018252601381527227b82aa9a221a13934b233b2a0b230b83a32b960691b602080830191909152825180840190935260058352640312e302e360dc1b90830152906113ee82826120ba565b5050831561143657845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614158061152957507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151d9190612d0b565b6001600160a01b031614155b156115475760405163040e613d60e21b815260040160405180910390fd5b600260005460ff16600381111561156057611560612c36565b1461157e576040516314ca5c1760e21b815260040160405180910390fd5b60358190556000805460ff191660031790556040518181527f38acaebd0e3affc51737125878fe1e25cb5fdb627b3778416219d82f81ef42f890602001610f8e565b6115c8611edb565b6001600160a01b03841615806115e557506001600160a01b038316155b1561160357604051635432922d60e01b815260040160405180910390fd5b6000805460ff16600381111561161b5761161b612c36565b141580156116405750600260005460ff16600381111561163d5761163d612c36565b14155b1561165e57604051636a14cf2360e01b815260040160405180910390fd5b603680546001600160a01b0319166001600160a01b038516179055600080546002919060ff191660018302179055506040516001600160a01b03858116602483015263ffffffff831660448301527f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b907f00000000000000000000000000000000000000000000000000000000000000009060640160408051601f198184030181529181526020820180516001600160e01b03166369c5f5f360e01b179052516001600160e01b031960e085901b1681526117469291908790600401612d49565b600060405180830381600087803b15801561176057600080fd5b505af1158015611774573d6000803e3d6000fd5b5050604080516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081168252871660208201527f06aeee5a19965b1536947b7571a17a681add9aad3efd41c1bec130257eaab6c9935001905060405180910390a150505050565b6117ea611edb565b6001600160a01b03811661181457604051631e4fbdf760e01b81526000600482015260240161106e565b61181d81611f36565b50565b611828611edb565b6000805460ff16600381111561184057611840612c36565b141580156118655750600160005460ff16600381111561186257611862612c36565b14155b1561188357604051636a14cf2360e01b815260040160405180910390fd5b6000805460ff19166001179055604080516004808252602482018352602082018051634384a98f60e01b6001600160e01b039091161790529151633dbb202b60e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692633dbb202b92611926927f000000000000000000000000000000000000000000000000000000000000000092879101612d49565b600060405180830381600087803b15801561194057600080fd5b505af1158015611954573d6000803e3d6000fd5b50506040516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681527fc19ffaed16cc79d2c0c853889a5b1fd248a9208d0478bc07dd2da1cda4e8999292506020019050610f8e565b6001600160a01b03828116600090815260026020908152604080832085851684529091528120805491905590611a0b907f0000000000000000000000000000000000000000000000000000000000000000168383611e33565b816001600160a01b03167fc47b52177930ba2672bfc1f75da55cf82adb3c61c2df74e28bdfefbf52ae9e0582604051611a4691815260200190565b60405180910390a2505050565b60007f87e4683aad14f1869b43140e06b846bd1b00c2e08e9825f6719d163b4cfef2a682600001518360200151846040015185606001518660800151604051602001611ad6969594939291909586526001600160a01b0394909416602086015260408501929092526060840152608083015263ffffffff1660a082015260c00190565b604051602081830303815290604052805190602001209050919050565b611afc826120cc565b9150611b126001600160a01b03841683836120ff565b610af8576040516398ceb44f60e01b815260040160405180910390fd5b611b646001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016853085612163565b6040516001600160a01b0384811660248301528581166044830152606482018490527f00000000000000000000000000000000000000000000000000000000000000001690633dbb202b907f00000000000000000000000000000000000000000000000000000000000000009060840160408051601f198184030181529181526020820180516001600160e01b03166332b3a98760e01b179052516001600160e01b031960e085901b168152611c209291908690600401612d49565b600060405180830381600087803b158015611c3a57600080fd5b505af1158015611c4e573d6000803e3d6000fd5b50506040805185815263ffffffff851660208201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116945087811693508816917fb8fa5fd165287d2cb897cb3ee53488b768ead242c87070b349394d2639824d4c910160405180910390a450505050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611d5057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611d44600080516020612f3c833981519152546001600160a01b031690565b6001600160a01b031614155b15610fff5760405163703e46dd60e11b815260040160405180910390fd5b61181d611edb565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611dd0575060408051601f3d908101601f19168201909252611dcd91810190612d83565b60015b611df857604051634c9c8ce360e01b81526001600160a01b038316600482015260240161106e565b600080516020612f3c8339815191528114611e2957604051632a87526960e21b81526004810182905260240161106e565b610af883836121a2565b6040516001600160a01b03838116602483015260448201839052610af891859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506121f8565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610fff5760405163703e46dd60e11b815260040160405180910390fd5b33611f0d7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614610fff5760405163118cdaa760e01b815233600482015260240161106e565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1028054606091600080516020612f1c83398151915291611fe690612d9c565b80601f016020809104026020016040519081016040528092919081815260200182805461201290612d9c565b801561205f5780601f106120345761010080835404028352916020019161205f565b820191906000526020600020905b81548152906001019060200180831161204257829003601f168201915b505050505091505090565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1038054606091600080516020612f1c83398151915291611fe690612d9c565b6120b161225b565b61181d816122a4565b6120c261225b565b610c2982826122ac565b60006120f96120d961230d565b8360405161190160f01b8152600281019290925260228201526042902090565b92915050565b600080600061210e858561231c565b509092509050600081600381111561212857612128612c36565b1480156121465750856001600160a01b0316826001600160a01b0316145b806121575750612157868686612369565b925050505b9392505050565b6040516001600160a01b03848116602483015283811660448301526064820183905261219c9186918216906323b872dd90608401611e60565b50505050565b6121ab82612444565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a28051156121f057610af882826124a9565b610c2961251f565b600061220d6001600160a01b0384168361253e565b905080516000141580156122325750808060200190518101906122309190612ce9565b155b15610af857604051635274afe760e01b81526001600160a01b038416600482015260240161106e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610fff57604051631afcd79f60e31b815260040160405180910390fd5b6117ea61225b565b6122b461225b565b600080516020612f1c8339815191527fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1026122ee8482612e1e565b50600381016122fd8382612e1e565b5060008082556001909101555050565b600061231761254c565b905090565b600080600083516041036123565760208401516040850151606086015160001a612348888285856125c0565b955095509550505050612362565b50508151600091506002905b9250925092565b6000806000856001600160a01b0316858560405160240161238b929190612ede565b60408051601f198184030181529181526020820180516001600160e01b0316630b135d3f60e11b179052516123c09190612eff565b600060405180830381855afa9150503d80600081146123fb576040519150601f19603f3d011682016040523d82523d6000602084013e612400565b606091505b509150915081801561241457506020815110155b801561215757508051630b135d3f60e11b906124399083016020908101908401612d83565b149695505050505050565b806001600160a01b03163b60000361247a57604051634c9c8ce360e01b81526001600160a01b038216600482015260240161106e565b600080516020612f3c83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516124c69190612eff565b600060405180830381855af49150503d8060008114612501576040519150601f19603f3d011682016040523d82523d6000602084013e612506565b606091505b509150915061251685838361268f565b95945050505050565b3415610fff5760405163b398979f60e01b815260040160405180910390fd5b606061215c838360006126eb565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61257761277e565b61257f6127e8565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156125fb5750600091506003905082612685565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa15801561264f573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661267b57506000925060019150829050612685565b9250600091508190505b9450945094915050565b6060826126a45761269f8261282c565b61215c565b81511580156126bb57506001600160a01b0384163b155b156126e457604051639996b31560e01b81526001600160a01b038516600482015260240161106e565b508061215c565b6060814710156127105760405163cd78605960e01b815230600482015260240161106e565b600080856001600160a01b0316848660405161272c9190612eff565b60006040518083038185875af1925050503d8060008114612769576040519150601f19603f3d011682016040523d82523d6000602084013e61276e565b606091505b509150915061215786838361268f565b6000600080516020612f1c83398151915281612798611fa7565b8051909150156127b057805160209091012092915050565b815480156127bf579392505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470935050505090565b6000600080516020612f1c8339815191528161280261206a565b80519091501561281a57805160209091012092915050565b600182015480156127bf579392505050565b80511561283c5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b038116811461181d57600080fd5b803563ffffffff8116811461287e57600080fd5b919050565b60008060008060008060008060e0898b03121561289f57600080fd5b88356128aa81612855565b975060208901356128ba81612855565b965060408901359550606089013567ffffffffffffffff808211156128de57600080fd5b818b0191508b601f8301126128f257600080fd5b81358181111561290157600080fd5b8c602082850101111561291357600080fd5b6020830197508096505050506080890135925060a0890135915061293960c08a0161286a565b90509295985092959890939650565b60008060006060848603121561295d57600080fd5b833561296881612855565b9250602084013561297881612855565b929592945050506040919091013590565b60008060006060848603121561299e57600080fd5b83356129a981612855565b9250602084013591506129be6040850161286a565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156129f057600080fd5b82356129fb81612855565b9150602083013567ffffffffffffffff80821115612a1857600080fd5b818501915085601f830112612a2c57600080fd5b813581811115612a3e57612a3e6129c7565b604051601f8201601f19908116603f01168101908382118183101715612a6657612a666129c7565b81604052828152886020848701011115612a7f57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60008060408385031215612ab457600080fd5b8235612abf81612855565b946020939093013593505050565b600060208284031215612adf57600080fd5b61215c8261286a565b60005b83811015612b03578181015183820152602001612aeb565b50506000910152565b60008151808452612b24816020860160208601612ae8565b601f01601f19169290920160200192915050565b60ff60f81b881681526000602060e06020840152612b5960e084018a612b0c565b8381036040850152612b6b818a612b0c565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b81811015612bbf57835183529284019291840191600101612ba3565b50909c9b505050505050505050505050565b60208152600061215c6020830184612b0c565b600060208284031215612bf657600080fd5b5035919050565b60008060408385031215612c1057600080fd5b8235612c1b81612855565b91506020830135612c2b81612855565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b6020810160048310612c6e57634e487b7160e01b600052602160045260246000fd5b91905290565b600060208284031215612c8657600080fd5b813561215c81612855565b60008060008060808587031215612ca757600080fd5b8435612cb281612855565b93506020850135612cc281612855565b9250612cd06040860161286a565b9150612cde6060860161286a565b905092959194509250565b600060208284031215612cfb57600080fd5b8151801515811461215c57600080fd5b600060208284031215612d1d57600080fd5b815161215c81612855565b808201808211156120f957634e487b7160e01b600052601160045260246000fd5b6001600160a01b0384168152606060208201819052600090612d6d90830185612b0c565b905063ffffffff83166040830152949350505050565b600060208284031215612d9557600080fd5b5051919050565b600181811c90821680612db057607f821691505b602082108103612dd057634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610af8576000816000526020600020601f850160051c81016020861015612dff5750805b601f850160051c820191505b8181101561143657828155600101612e0b565b815167ffffffffffffffff811115612e3857612e386129c7565b612e4c81612e468454612d9c565b84612dd6565b602080601f831160018114612e815760008415612e695750858301515b600019600386901b1c1916600185901b178555611436565b600085815260208120601f198616915b82811015612eb057888601518255948401946001909101908401612e91565b5085821015612ece5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b828152604060208201526000612ef76040830184612b0c565b949350505050565b60008251612f11818460208701612ae8565b919091019291505056fea16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212200ddb033b58a89d5a64fdf537a01b9b42b244de4dc988b6956399f187bffe09bf64736f6c63430008190033608060405260405161040a38038061040a83398101604081905261002291610268565b61002c8282610033565b5050610352565b61003c82610092565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a280511561008657610081828261010e565b505050565b61008e610185565b5050565b806001600160a01b03163b6000036100cd57604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b03168460405161012b9190610336565b600060405180830381855af49150503d8060008114610166576040519150601f19603f3d011682016040523d82523d6000602084013e61016b565b606091505b50909250905061017c8583836101a6565b95945050505050565b34156101a45760405163b398979f60e01b815260040160405180910390fd5b565b6060826101bb576101b682610205565b6101fe565b81511580156101d257506001600160a01b0384163b155b156101fb57604051639996b31560e01b81526001600160a01b03851660048201526024016100c4565b50805b9392505050565b8051156102155780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b600052604160045260246000fd5b60005b8381101561025f578181015183820152602001610247565b50506000910152565b6000806040838503121561027b57600080fd5b82516001600160a01b038116811461029257600080fd5b60208401519092506001600160401b03808211156102af57600080fd5b818501915085601f8301126102c357600080fd5b8151818111156102d5576102d561022e565b604051601f8201601f19908116603f011681019083821181831017156102fd576102fd61022e565b8160405282815288602084870101111561031657600080fd5b610327836020830160208801610244565b80955050505050509250929050565b60008251610348818460208701610244565b9190910192915050565b60aa806103606000396000f3fe6080604052600a600c565b005b60186014601a565b6051565b565b6000604c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e808015606f573d6000f35b3d6000fdfea264697066735822122033b4da528499851fa7a71d76c9379fa5c3858f229a179c9593045387f3d7985b64736f6c63430008190033a2646970667358221220e15270d5393a96ba7fba6637667ee8daa124a62133229b037fde0281b63fac1864736f6c63430008190033

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

0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238

-----Decoded View---------------
Arg [0] : _usdc (address): 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238


Libraries Used


Deployed Bytecode Sourcemap

190729:5238:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;191594:27;;;;;;;;-1:-1:-1;;;;;192:32:1;;;174:51;;162:2;147:18;191594:27:0;;;;;;;;190815:88;;190861:42;190815:88;;191038:45;;;;;;;;;;;;;;;-1:-1:-1;;;191038:45:0;;;;;;;;;;;;:::i;193638:2326::-;;;;;;:::i;:::-;;:::i;:::-;;;;-1:-1:-1;;;;;2881:15:1;;;2863:34;;2933:15;;;2928:2;2913:18;;2906:43;2985:15;;2965:18;;;2958:43;;;;2813:2;2798:18;193638:2326:0;2623:384:1;191664:37:0;;;;;;;;;3158:25:1;;;3146:2;3131:18;191664:37:0;3012:177:1;190946:49:0;;;;;;;;;;;;;;;-1:-1:-1;;;190946:49:0;;;;;193638:2326;193811:18;;;-1:-1:-1;;;194057:26:0;;;;:14;:26;:::i;:::-;194084:1;194057:29;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;194050:37;;;:::i;:::-;-1:-1:-1;;;;;;194050:61:0;;194046:107;;194120:33;;-1:-1:-1;;;194120:33:0;;;;;;;;;;;194046:107;194280:21;194330:1;194304:22;;:27;;;;;;;:::i;:::-;;;;;;;194280:51;;194403:77;194459:4;194466:13;194403:47;:77::i;:::-;194390:90;;194603:61;194667:148;;;;;;;;194724:9;;;;;;;;;;;;;-1:-1:-1;;;194724:9:0;;;194745:10;;194710:51;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;194667:148;;;;194763:11;;;;;;;;;;;;;-1:-1:-1;;;194763:11:0;;;194667:148;;;;194776:4;-1:-1:-1;;;;;194776:13:0;;:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;194776:15:0;;;;;;;;;;;;:::i;:::-;194667:148;;;;194793:4;-1:-1:-1;;;;;194793:13:0;;:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;194667:148;;;;194603:212;-1:-1:-1;194947:13:0;194923;195083:10;195102:29;;;;:14;:29;:::i;:::-;195140:27;;;;;;;;:::i;:::-;195176:19;195204:26;;;;:14;:26;:::i;:::-;195064:173;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;195034:203;;195300:21;:37;195346:14;195362:5;195369:12;190861:42;195404:14;:32;;;;;;;;;;:::i;:::-;195300:143;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;195288:155;;195509:88;195557:9;191550:1;195509:47;:88::i;:::-;195496:101;;195689:22;195756:4;195763:12;195777:10;195722:66;;;;;:::i;:::-;-1:-1:-1;;;;;2881:15:1;;;2863:34;;2933:15;;;2928:2;2913:18;;2906:43;2985:15;;;2980:2;2965:18;;2958:43;2813:2;2798:18;195722:66:0;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;195829:63:0;;-1:-1:-1;;;;;192:32:1;;195829:63:0;;;174:51:1;195689:100:0;;-1:-1:-1;195689:100:0;;147:18:1;;195829:63:0;;;-1:-1:-1;;195829:63:0;;;;;;;;;;;;;;-1:-1:-1;;;;;195829:63:0;-1:-1:-1;;;195829:63:0;;;195796:97;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;195907:51:0;;;-1:-1:-1;;;;;2881:15:1;;;2863:34;;2933:15;;;2928:2;2913:18;;2906:43;2985:15;;2965:18;;;2958:43;195907:51:0;;;;;;;2813:2:1;195907:51:0;;;193870:2094;;;;;193638:2326;;;;;;;;;:::o;188054:2076::-;188162:29;188200:18;188407:4;188397:6;:14;188393:1656;;188430:62;;-1:-1:-1;;;188430:62:0;;;11752:28:1;-1:-1:-1;;;11796:11:1;;;11789:36;-1:-1:-1;;;;;;11862:2:1;11858:15;;;11854:53;11841:11;;;11834:74;11734:3;11942:16;;;-1:-1:-1;;;;;;11938:25:1;11924:12;;;11917:47;11980:12;;188430:62:0;;;;;;;;;;;;;188422:70;;188393:1656;;;188983:15;188973:25;;188969:1080;;189017:76;;-1:-1:-1;;;189017:76:0;;;12266:28:1;-1:-1:-1;;;12310:11:1;;;12303:36;-1:-1:-1;;;;;;12376:2:1;12372:15;;;12368:53;12355:11;;;12348:74;-1:-1:-1;;;12438:12:1;;;12431:37;12248:3;12502:16;;;-1:-1:-1;;;;;;12498:25:1;12484:12;;;12477:47;12540:12;;189017:76:0;12003:555:1;188969:1080:0;189121:16;189111:26;;189107:942;;189156:77;;-1:-1:-1;;;189156:77:0;;;12828:28:1;-1:-1:-1;;;12872:11:1;;;12865:36;-1:-1:-1;;;;;;12938:2:1;12934:15;;;12930:53;12917:11;;;12910:74;-1:-1:-1;;;13000:12:1;;;12993:37;-1:-1:-1;;;;;;13086:3:1;13064:16;;;13060:38;13046:12;;;13039:60;13115:12;;189156:77:0;12563:570:1;189107:942:0;189261:16;189251:26;;189247:802;;189296:77;;-1:-1:-1;;;189296:77:0;;;13403:28:1;-1:-1:-1;;;13447:11:1;;;13440:36;-1:-1:-1;;;;;;13513:2:1;13509:15;;;13505:53;13492:11;;;13485:74;-1:-1:-1;;;13575:12:1;;;13568:37;-1:-1:-1;;;;;;13661:3:1;13639:16;;;13635:41;13621:12;;;13614:63;13693:12;;189296:77:0;13138:573:1;189247:802:0;189401:16;189391:26;;189387:662;;189436:77;;-1:-1:-1;;;189436:77:0;;;13981:28:1;-1:-1:-1;;;14025:11:1;;;14018:36;-1:-1:-1;;;;;;14091:2:1;14087:15;;;14083:53;14070:11;;;14063:74;-1:-1:-1;;;14153:12:1;;;14146:37;-1:-1:-1;;;;;;14239:3:1;14217:16;;;14213:43;14199:12;;;14192:65;14273:12;;189436:77:0;13716:575:1;189387:662:0;189541:16;189531:26;;189527:522;;189576:77;;-1:-1:-1;;;189576:77:0;;;14561:28:1;-1:-1:-1;;;14605:11:1;;;14598:36;-1:-1:-1;;;;;;14671:2:1;14667:15;;;14663:53;14650:11;;;14643:74;-1:-1:-1;;;14733:12:1;;;14726:37;-1:-1:-1;;;;;;14819:3:1;14797:16;;;14793:45;14779:12;;;14772:67;14855:12;;189576:77:0;14296:577:1;189527:522:0;189681:16;189671:26;;189667:382;;189716:77;;-1:-1:-1;;;189716:77:0;;;15143:28:1;-1:-1:-1;;;15187:11:1;;;15180:36;-1:-1:-1;;;;;;15253:2:1;15249:15;;;15245:53;15232:11;;;15225:74;-1:-1:-1;;;15315:12:1;;;15308:37;-1:-1:-1;;;;;;15401:3:1;15379:16;;;15375:47;15361:12;;;15354:69;15439:12;;189716:77:0;14878:579:1;189667:382:0;189821:16;189811:26;;189807:242;;189856:77;;-1:-1:-1;;;189856:77:0;;;15727:28:1;-1:-1:-1;;;15771:11:1;;;15764:36;-1:-1:-1;;;;;;15837:2:1;15833:15;;;15829:53;15816:11;;;15809:74;-1:-1:-1;;;15899:12:1;;;15892:37;-1:-1:-1;;;;;;15985:3:1;15963:16;;;15959:49;15945:12;;;15938:71;16025:12;;189856:77:0;15462:581:1;189807:242:0;189964:77;;-1:-1:-1;;;189964:77:0;;;16313:28:1;-1:-1:-1;;;16357:11:1;;;16350:36;-1:-1:-1;;;;;;16423:2:1;16419:15;;;16415:53;16402:11;;;16395:74;-1:-1:-1;;;16485:12:1;;;16478:37;-1:-1:-1;;;;;;16571:3:1;16549:16;;;16545:51;16531:12;;;16524:73;16613:12;;189964:77:0;;;;;;;;;;;;189956:85;;189807:242;190105:16;;;;;;;;188054:2076;-1:-1:-1;;;188054:2076:0:o;-1:-1:-1:-;;;;;;;;:::o;:::-;;;;;;;;:::o;444:250:1:-;529:1;539:113;553:6;550:1;547:13;539:113;;;629:11;;;623:18;610:11;;;603:39;575:2;568:10;539:113;;;-1:-1:-1;;686:1:1;668:16;;661:27;444:250::o;699:271::-;741:3;779:5;773:12;806:6;801:3;794:19;822:76;891:6;884:4;879:3;875:14;868:4;861:5;857:16;822:76;:::i;:::-;952:2;931:15;-1:-1:-1;;927:29:1;918:39;;;;959:4;914:50;;699:271;-1:-1:-1;;699:271:1:o;975:220::-;1124:2;1113:9;1106:21;1087:4;1144:45;1185:2;1174:9;1170:18;1162:6;1144:45;:::i;:::-;1136:53;975:220;-1:-1:-1;;;975:220:1:o;1200:131::-;-1:-1:-1;;;;;1275:31:1;;1265:42;;1255:70;;1321:1;1318;1311:12;1255:70;1200:131;:::o;1336:162::-;1402:5;1447:3;1438:6;1433:3;1429:16;1425:26;1422:46;;;1464:1;1461;1454:12;1422:46;-1:-1:-1;1486:6:1;1336:162;-1:-1:-1;1336:162:1:o;1503:1115::-;1634:6;1642;1650;1658;1666;1719:3;1707:9;1698:7;1694:23;1690:33;1687:53;;;1736:1;1733;1726:12;1687:53;1775:9;1762:23;1794:31;1819:5;1794:31;:::i;:::-;1844:5;-1:-1:-1;1901:2:1;1886:18;;1873:32;1914:33;1873:32;1914:33;:::i;:::-;1966:7;-1:-1:-1;2024:2:1;2009:18;;1996:32;2047:18;2077:14;;;2074:34;;;2104:1;2101;2094:12;2074:34;2142:6;2131:9;2127:22;2117:32;;2187:7;2180:4;2176:2;2172:13;2168:27;2158:55;;2209:1;2206;2199:12;2158:55;2249:2;2236:16;2275:2;2267:6;2264:14;2261:34;;;2291:1;2288;2281:12;2261:34;2336:7;2331:2;2322:6;2318:2;2314:15;2310:24;2307:37;2304:57;;;2357:1;2354;2347:12;2304:57;2388:2;2384;2380:11;2370:21;;2410:6;2400:16;;;2469:2;2458:9;2454:18;2441:32;2425:48;;2498:2;2488:8;2485:16;2482:36;;;2514:1;2511;2504:12;2482:36;;2537:75;2604:7;2593:8;2582:9;2578:24;2537:75;:::i;:::-;2527:85;;;1503:1115;;;;;;;;:::o;3194:556::-;3298:4;3304:6;3364:11;3351:25;3458:2;3454:7;3443:8;3427:14;3423:29;3419:43;3399:18;3395:68;3385:96;;3477:1;3474;3467:12;3385:96;3504:33;;3556:20;;;-1:-1:-1;3599:18:1;3588:30;;3585:50;;;3631:1;3628;3621:12;3585:50;3664:4;3652:17;;-1:-1:-1;3715:1:1;3711:14;;;3695;3691:35;3681:46;;3678:66;;;3740:1;3737;3730:12;3678:66;3194:556;;;;;:::o;3755:127::-;3816:10;3811:3;3807:20;3804:1;3797:31;3847:4;3844:1;3837:15;3871:4;3868:1;3861:15;3887:521;3964:4;3970:6;4030:11;4017:25;4124:2;4120:7;4109:8;4093:14;4089:29;4085:43;4065:18;4061:68;4051:96;;4143:1;4140;4133:12;4051:96;4170:33;;4222:20;;;-1:-1:-1;4265:18:1;4254:30;;4251:50;;;4297:1;4294;4287:12;4251:50;4330:4;4318:17;;-1:-1:-1;4361:14:1;4357:27;;;4347:38;;4344:58;;;4398:1;4395;4388:12;4413:323;-1:-1:-1;;;;;;4533:19:1;;4609:11;;;;4640:1;4632:10;;4629:101;;;4717:2;4711;4704:3;4701:1;4697:11;4694:1;4690:19;4686:28;4682:2;4678:37;4674:46;4665:55;;4629:101;;;4413:323;;;;:::o;4741:222::-;4806:9;;;4827:10;;;4824:133;;;4879:10;4874:3;4870:20;4867:1;4860:31;4914:4;4911:1;4904:15;4942:4;4939:1;4932:15;4824:133;4741:222;;;;:::o;4968:832::-;5427:3;5465:6;5459:13;5481:66;5540:6;5535:3;5528:4;5520:6;5516:17;5481:66;:::i;:::-;-1:-1:-1;;;5569:16:1;;;5594:18;;;-1:-1:-1;;;5639:1:1;5628:13;;5621:26;5692:6;5684;5680:1;5669:13;;5656:43;-1:-1:-1;;;5718:18:1;;5760:1;5752:10;;5745:23;;;;-1:-1:-1;;5792:1:1;5784:10;;;-1:-1:-1;;4968:832:1:o;5805:127::-;5866:10;5861:3;5857:20;5854:1;5847:31;5897:4;5894:1;5887:15;5921:4;5918:1;5911:15;5937:897;6017:6;6070:2;6058:9;6049:7;6045:23;6041:32;6038:52;;;6086:1;6083;6076:12;6038:52;6119:9;6113:16;6148:18;6189:2;6181:6;6178:14;6175:34;;;6205:1;6202;6195:12;6175:34;6243:6;6232:9;6228:22;6218:32;;6288:7;6281:4;6277:2;6273:13;6269:27;6259:55;;6310:1;6307;6300:12;6259:55;6339:2;6333:9;6361:2;6357;6354:10;6351:36;;;6367:18;;:::i;:::-;6442:2;6436:9;6410:2;6496:13;;-1:-1:-1;;6492:22:1;;;6516:2;6488:31;6484:40;6472:53;;;6540:18;;;6560:22;;;6537:46;6534:72;;;6586:18;;:::i;:::-;6626:10;6622:2;6615:22;6661:2;6653:6;6646:18;6701:7;6696:2;6691;6687;6683:11;6679:20;6676:33;6673:53;;;6722:1;6719;6712:12;6673:53;6735:68;6800:2;6795;6787:6;6783:15;6778:2;6774;6770:11;6735:68;:::i;:::-;6822:6;5937:897;-1:-1:-1;;;;;;;5937:897:1:o;6839:273::-;6907:6;6960:2;6948:9;6939:7;6935:23;6931:32;6928:52;;;6976:1;6973;6966:12;6928:52;7008:9;7002:16;7058:4;7051:5;7047:16;7040:5;7037:27;7027:55;;7078:1;7075;7068:12;7117:247;7176:6;7229:2;7217:9;7208:7;7204:23;7200:32;7197:52;;;7245:1;7242;7235:12;7197:52;7284:9;7271:23;7303:31;7328:5;7303:31;:::i;7369:266::-;7457:6;7452:3;7445:19;7509:6;7502:5;7495:4;7490:3;7486:14;7473:43;-1:-1:-1;7561:1:1;7536:16;;;7554:4;7532:27;;;7525:38;;;;7617:2;7596:15;;;-1:-1:-1;;7592:29:1;7583:39;;;7579:50;;7369:266::o;7640:1047::-;7717:3;7748;7772:6;7767:3;7760:19;7798:4;7827;7822:3;7818:14;7811:21;;7885:4;7875:6;7872:1;7868:14;7861:5;7857:26;7853:37;7913:5;7936:1;7946:715;7960:6;7957:1;7954:13;7946:715;;;8025:16;;;-1:-1:-1;;8021:30:1;8009:43;;8091:20;;8166:14;8162:26;;;-1:-1:-1;;8158:40:1;8134:65;;8124:93;;8213:1;8210;8203:12;8124:93;8245:30;;8353:16;;;;8304:21;8398:18;8385:32;;8382:52;;;8430:1;8427;8420:12;8382:52;8483:8;8467:14;8463:29;8454:7;8450:43;8447:63;;;8506:1;8503;8496:12;8447:63;8531:50;8576:4;8566:8;8557:7;8531:50;:::i;:::-;8639:12;;;;8523:58;-1:-1:-1;;;8604:15:1;;;;7982:1;7975:9;7946:715;;;-1:-1:-1;8677:4:1;;7640:1047;-1:-1:-1;;;;;;;7640:1047:1:o;8692:1372::-;9048:4;9094:1;9090;9085:3;9081:11;9077:19;9135:2;9127:6;9123:15;9112:9;9105:34;9187:2;9179:6;9175:15;9170:2;9159:9;9155:18;9148:43;9239:2;9231:6;9227:15;9222:2;9211:9;9207:18;9200:43;;9279:3;9274:2;9263:9;9259:18;9252:31;9318:6;9312:13;9362:4;9356:3;9345:9;9341:19;9334:33;9390:52;9437:3;9426:9;9422:19;9408:12;9390:52;:::i;:::-;9376:66;;9491:2;9483:6;9479:15;9473:22;9518:3;9514:8;9587:2;9575:9;9567:6;9563:22;9559:31;9553:3;9542:9;9538:19;9531:60;9614:41;9648:6;9632:14;9614:41;:::i;:::-;9600:55;;9704:2;9696:6;9692:15;9686:22;9664:44;;9773:2;9761:9;9753:6;9749:22;9745:31;9739:3;9728:9;9724:19;9717:60;;9800:41;9834:6;9818:14;9800:41;:::i;:::-;9786:55;;;9906:4;9900:2;9892:6;9888:15;9882:22;9878:33;9872:3;9861:9;9857:19;9850:62;9962:9;9954:6;9950:22;9943:4;9932:9;9928:20;9921:52;9990:68;10051:6;10043;10035;9990:68;:::i;:::-;9982:76;8692:1372;-1:-1:-1;;;;;;;;;8692:1372:1:o;10069:276::-;10127:6;10180:2;10168:9;10159:7;10155:23;10151:32;10148:52;;;10196:1;10193;10186:12;10148:52;10235:9;10222:23;10285:10;10278:5;10274:22;10267:5;10264:33;10254:61;;10311:1;10308;10301:12;10350:584;10615:3;10604:9;10597:22;10578:4;10636:46;10677:3;10666:9;10662:19;10654:6;10636:46;:::i;:::-;10713:2;10698:18;;10691:34;;;;-1:-1:-1;;;;;;10799:15:1;;;10794:2;10779:18;;10772:43;10851:15;;;;10846:2;10831:18;;10824:43;10916:10;10904:23;;;10898:3;10883:19;;;10876:52;10691:34;10628:54;-1:-1:-1;10350:584:1:o;10939:251::-;11009:6;11062:2;11050:9;11041:7;11037:23;11033:32;11030:52;;;11078:1;11075;11068:12;11030:52;11110:9;11104:16;11129:31;11154:5;11129:31;:::i;11195:315::-;-1:-1:-1;;;;;11370:32:1;;11352:51;;11439:2;11434;11419:18;;11412:30;;;-1:-1:-1;;11459:45:1;;11485:18;;11477:6;11459:45;:::i;:::-;11451:53;11195:315;-1:-1:-1;;;;11195:315:1:o

Swarm Source

ipfs://e15270d5393a96ba7fba6637667ee8daa124a62133229b037fde0281b63fac18

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
0xC0A9A6cf5d6873523da5B372e326e0668871d377
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ 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.