creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor () {\n        address msgSender = _msgSender();\n        _owner = msgSender;\n        emit OwnershipTransferred(address(0), msgSender);\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        emit OwnershipTransferred(_owner, address(0));\n        _owner = address(0);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        emit OwnershipTransferred(_owner, newOwner);\n        _owner = newOwner;\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20 token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        // solhint-disable-next-line max-line-length\n        require((value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            uint256 newAllowance = oldAllowance - value;\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        if (returndata.length > 0) { // Return data is optional\n            // solhint-disable-next-line max-line-length\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize, which returns 0 for contracts in\n        // construction, since the code is only stored at the end of the\n        // constructor execution.\n\n        uint256 size;\n        // solhint-disable-next-line no-inline-assembly\n        assembly { size := extcodesize(account) }\n        return size > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value\n        (bool success, ) = recipient.call{ value: amount }(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain`call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n      return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.call{ value: value }(data);\n        return _verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return _verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return _verifyCallResult(success, returndata, errorMessage);\n    }\n\n    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length > 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                // solhint-disable-next-line no-inline-assembly\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n        return msg.data;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSA.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n    /* solhint-disable var-name-mixedcase */\n    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n    // invalidate the cached domain separator if the chain id changes.\n    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n    uint256 private immutable _CACHED_CHAIN_ID;\n\n    bytes32 private immutable _HASHED_NAME;\n    bytes32 private immutable _HASHED_VERSION;\n    bytes32 private immutable _TYPE_HASH;\n    /* solhint-enable var-name-mixedcase */\n\n    /**\n     * @dev Initializes the domain separator and parameter caches.\n     *\n     * The meaning of `name` and `version` is specified in\n     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n     *\n     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n     * - `version`: the current major version of the signing domain.\n     *\n     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n     * contract upgrade].\n     */\n    constructor(string memory name, string memory version) {\n        bytes32 hashedName = keccak256(bytes(name));\n        bytes32 hashedVersion = keccak256(bytes(version));\n        bytes32 typeHash = keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\");\n        _HASHED_NAME = hashedName;\n        _HASHED_VERSION = hashedVersion;\n        _CACHED_CHAIN_ID = block.chainid;\n        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n        _TYPE_HASH = typeHash;\n    }\n\n    /**\n     * @dev Returns the domain separator for the current chain.\n     */\n    function _domainSeparatorV4() internal view returns (bytes32) {\n        if (block.chainid == _CACHED_CHAIN_ID) {\n            return _CACHED_DOMAIN_SEPARATOR;\n        } else {\n            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n        }\n    }\n\n    function _buildDomainSeparator(bytes32 typeHash, bytes32 name, bytes32 version) private view returns (bytes32) {\n        return keccak256(\n            abi.encode(\n                typeHash,\n                name,\n                version,\n                block.chainid,\n                address(this)\n            )\n        );\n    }\n\n    /**\n     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n     * function returns the hash of the fully encoded EIP712 message for this domain.\n     *\n     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n     *\n     * ```solidity\n     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n     *     keccak256(\"Mail(address to,string contents)\"),\n     *     mailTo,\n     *     keccak256(bytes(mailContents))\n     * )));\n     * address signer = ECDSA.recover(digest, signature);\n     * ```\n     */\n    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        // Divide the signature in r, s and v variables\n        bytes32 r;\n        bytes32 s;\n        uint8 v;\n\n        // Check the signature length\n        // - case 65: r,s,v signature (standard)\n        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n        if (signature.length == 65) {\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            // solhint-disable-next-line no-inline-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n        } else if (signature.length == 64) {\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            // solhint-disable-next-line no-inline-assembly\n            assembly {\n                let vs := mload(add(signature, 0x40))\n                r := mload(add(signature, 0x20))\n                s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)\n                v := add(shr(255, vs), 27)\n            }\n        } else {\n            revert(\"ECDSA: invalid signature length\");\n        }\n\n        return recover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, \"ECDSA: invalid signature 's' value\");\n        require(v == 27 || v == 28, \"ECDSA: invalid signature 'v' value\");\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        require(signer != address(0), \"ECDSA: invalid signature\");\n\n        return signer;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n"
      },
      "contracts/common/cctp/ICCTPTokenMessenger.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n pragma solidity ^0.8.24;\n\ninterface ICCTPTokenMessenger {\n    function depositForBurn(\n        uint256 amount,\n        uint32 destinationDomain,\n        bytes32 mintRecipient,\n        address burnToken\n    ) external returns (uint64 nonce);\n\n    function depositForBurnWithCaller(\n        uint256 amount,\n        uint32 destinationDomain,\n        bytes32 mintRecipient,\n        address burnToken,\n        bytes32 destinationCaller\n    ) external returns (uint64 nonce);\n\n    function replaceDepositForBurn(\n        bytes calldata originalMessage,\n        bytes calldata originalAttestation,\n        bytes32 newDestinationCaller,\n        bytes32 newMintRecipient\n    ) external;\n\n    function handleReceiveMessage(\n        uint32 remoteDomain,\n        bytes32 sender,\n        bytes calldata messageBody\n    ) external returns (bool);\n\n    function addRemoteTokenMessenger(uint32 domain, bytes32 tokenMessenger) external;\n\n    function removeRemoteTokenMessenger(uint32 domain) external;\n\n    function addLocalMinter(address newLocalMinter) external;\n\n    function removeLocalMinter() external;\n\n    function localMessageTransmitter() external view returns (address);\n\n    function messageBodyVersion() external view returns (uint32);\n\n    function localMinter() external view returns (address);\n\n    function remoteTokenMessengers(uint32 domain) external view returns (bytes32);\n}\n"
      },
      "contracts/common/SafeAmount.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n// import \"@openzeppelin//contracts/token/ERC20/IERC20.sol\";\n\nlibrary SafeAmount {\n    using SafeERC20 for IERC20;\n\n    /**\n     @notice transfer tokens from. Incorporate fee on transfer tokens\n     @param token The token\n     @param from From address\n     @param to To address\n     @param amount The amount\n     @return result The actual amount transferred\n     */\n    function safeTransferFrom(\n        address token,\n        address from,\n        address to,\n        uint256 amount) internal returns (uint256 result) {\n        uint256 preBalance = IERC20(token).balanceOf(to);\n        IERC20(token).safeTransferFrom(from, to, amount);\n        uint256 postBalance = IERC20(token).balanceOf(to);\n        result = postBalance - preBalance;\n        require(result <= amount, \"SA: actual amount larger than transfer amount\");\n    }\n\n    /**\n     @notice Sends ETH\n     @param to The to address\n     @param value The amount\n     */\n\tfunction safeTransferETH(address to, uint256 value) internal {\n        (bool success, ) = to.call{value: value}(new bytes(0));\n        require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');\n    }\n}"
      },
      "contracts/common/signature/SigCheckable.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\n\n/**\n @dev Make sure to define method signatures\n */\nabstract contract SigCheckable is EIP712 {\n\n    function signerUnique(\n        bytes32 message,\n        bytes memory signature) internal view returns (address _signer) {\n        bytes32 digest;\n        (digest, _signer) = signer(message, signature);\n    }\n\n    /*\n        @dev example message;\n\n        bytes32 constant METHOD_SIG =\n            keccak256(\"WithdrawSigned(address token,address payee,uint256 amount,bytes32 salt)\");\n        bytes32 message = keccak256(abi.encode(\n          METHOD_SIG,\n          token,\n          payee,\n          amount,\n          salt\n    */\n    function signer(\n        bytes32 message,\n        bytes memory signature) internal view returns (bytes32 digest, address _signer) {\n        digest = _hashTypedDataV4(message);\n        _signer = ECDSA.recover(digest, signature);\n    }\n}"
      },
      "contracts/common/WithAdmin.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract WithAdmin is Ownable {\n\taddress public admin;\n\tevent AdminSet(address admin);\n\n\tfunction setAdmin(address _admin) external onlyOwner {\n\t\tadmin = _admin;\n\t\temit AdminSet(_admin);\n\t}\n\n\tmodifier onlyAdmin() {\n\t\trequire(msg.sender == admin || msg.sender == owner(), \"WA: not admin\");\n\t\t_;\n\t}\n}"
      },
      "contracts/multiswap-contracts/CCTPFundManager.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport \"../common/signature/SigCheckable.sol\";\nimport \"../common/WithAdmin.sol\";\nimport \"../common/SafeAmount.sol\";\nimport \"../common/cctp/ICCTPTokenMessenger.sol\";\n\ncontract CCTPFundManager is SigCheckable, WithAdmin {\n    using SafeERC20 for IERC20;\n    address public usdcToken;\n    address public cctpTokenMessenger;\n    address public fiberRouter;\n    uint32 constant WEEK = 3600 * 24 * 7;\n    string public constant NAME = \"FUND_MANAGER\";\n    string public constant VERSION = \"000.004\";\n    mapping(address => bool) public signers;\n    mapping(bytes32 => bool) public usedSalt;\n    mapping(uint256 => TargetNetwork) public targetNetworks;\n\n    bytes32 constant WITHDRAW_SIGNED_METHOD =\n        keccak256(\n            \"WithdrawSigned(address token,address payee,uint256 amount,bytes32 salt,uint256 expiry)\"\n        );\n    bytes32 constant WITHDRAW_SIGNED_WITH_SWAP_METHOD =\n        keccak256(\n            \"withdrawSignedAndSwapRouter(address to,uint256 amountIn,uint256 minAmountOut,address foundryToken,address targetToken,address router,bytes32 salt,uint256 expiry)\"\n        );\n\n    struct TargetNetwork {\n        uint32 targetNetworkDomain;\n        address targetCCTPFundManager;\n    }\n\n    event TransferBySignature(\n        address signer,\n        address receiver,\n        address token,\n        uint256 amount\n    );\n\n    /**\n     * @dev Modifier that allows only the designated fiberRouter to execute the function.\n     * It checks if the sender is equal to the `fiberRouter` address.\n     * @notice Ensure that `fiberRouter` is set before using this modifier.\n     */\n    modifier onlyRouter() {\n        require(msg.sender == fiberRouter, \"FM: Only fiberRouter method\");\n        _;\n    }\n\n    /**\n     * @dev Contract constructor that initializes the EIP-712 domain with the specified NAME, VERSION.\n     * @notice This constructor is called only once during the deployment of the contract.\n     */\n    constructor() EIP712(NAME, VERSION) {\n        // bytes memory initData = IFerrumDeployer(msg.sender).initData();\n    }\n\n    /**\n     @dev sets the fiberRouter\n     @param _fiberRouter is the FiberRouter address\n     */\n    function setRouter(address _fiberRouter) external onlyOwner {\n        require(_fiberRouter != address(0), \"FM: fiberRouter requried\");\n        fiberRouter = _fiberRouter;\n    }\n\n    /**\n     @dev sets the signer\n     @param _signer is the address that generate signatures\n     */\n    function addSigner(address _signer) public onlyOwner {\n        require(_signer != address(0), \"Bad signer\");\n        signers[_signer] = true;\n    }\n\n    /**\n     @dev removes the signer\n     @param _signer is the address that generate signatures\n     */\n    function removeSigner(address _signer) external onlyOwner {\n        require(_signer != address(0), \"Bad signer\");\n        delete signers[_signer];\n    }\n\n    /**\n     * @notice Initializes the Cross-Chain Transfer Protocol (CCTP) parameters.\n     * @dev This function should be called by the contract owner to set the necessary parameters for CCTP.\n     * @param _cctpTokenMessenger The address of the CCTP Token Messenger contract.\n     * @param _usdcToken The address of the USDC token contract.\n     **/\n    function initCCTP(\n        address _cctpTokenMessenger,\n        address _usdcToken\n    ) external onlyOwner {\n        require(_cctpTokenMessenger != address(0), \"FR: Invalid CCTP Token Messenger address\");\n        require(_usdcToken != address(0), \"FR: Invalid USDC Token address\");\n\n        cctpTokenMessenger = _cctpTokenMessenger;\n        usdcToken = _usdcToken;\n    }\n\n    /**\n     * @notice Add a new target CCTP network.\n     * @param _chainID The target network chain ID\n     * @param _targetNetworkDomain The domain of the target network.\n     * @param _targetCCTPFundManager The fund manager address for the target network.\n     */\n    function setTargetCCTPNetwork(uint256 _chainID, uint32 _targetNetworkDomain, address _targetCCTPFundManager) external onlyOwner {\n        require(_targetNetworkDomain != 0, \"FR: Invalid Target Network Domain\");\n        require(_chainID != 0, \"FR: Invalid Target Network ChainID\");\n        require(_targetCCTPFundManager != address(0), \"FR: Invalid Target CCTP Fund Manager address\");\n\n        targetNetworks[_chainID] = TargetNetwork(_targetNetworkDomain, _targetCCTPFundManager);\n    }\n\n    /**\n     * @dev Initiates a signed token withdrawal, exclusive to the router\n     * @notice Ensure valid parameters and router setup\n     * @param token The token to withdraw\n     * @param payee Address for where to send the tokens to\n     * @param amount The amount\n     * @param salt The salt for unique tx\n     * @param expiry The expiration time for the signature\n     * @param signature The multisig validator signature\n     * @return The actual amount of tokens withdrawn\n     */\n    function withdrawSigned(\n        address token,\n        address payee,\n        uint256 amount,\n        bytes32 salt,\n        uint256 expiry,\n        bytes memory signature\n    ) external onlyRouter returns (uint256) {\n        require(token != address(0), \"FM: bad token\");\n        require(payee != address(0), \"FM: bad payee\");\n        require(salt != 0, \"FM: bad salt\");\n        require(amount != 0, \"FM: bad amount\");\n        require(block.timestamp < expiry, \"FM: signature timed out\");\n        require(expiry < block.timestamp + WEEK, \"FM: expiry too far\");\n        bytes32 message =  keccak256(\n                abi.encode(WITHDRAW_SIGNED_METHOD, token, payee, amount, salt, expiry)\n            );\n        address _signer = signerUnique(message, signature);\n\n        require(signers[_signer], \"FM: Invalid signer\");\n        require(!usedSalt[salt], \"FM: salt already used\");\n        usedSalt[salt] = true;\n        // transfer the tokens to the receiver\n        IERC20(token).safeTransfer(payee, amount);\n        emit TransferBySignature(_signer, payee, token, amount);\n        return amount;\n    }\n\n    /**\n     * @dev Initiates a signed token withdrawal with swap, exclusive to the router\n     * @notice Ensure valid parameters and router setup\n     * @param to The address to withdraw to\n     * @param amountIn The amount to be swapped in\n     * @param minAmountOut The minimum amount out from the swap\n     * @param foundryToken The token used in the Foundry\n     * @param targetToken The target token for the swap\n     * @param router The router address\n     * @param salt The salt value for the signature\n     * @param expiry The expiration time for the signature\n     * @param signature The multi-signature data\n     * @return The actual amount of tokens withdrawn from Foundry\n     */\n    function withdrawSignedAndSwapRouter(\n        address to,\n        uint256 amountIn,\n        uint256 minAmountOut,\n        address foundryToken,\n        address targetToken,\n        address router,\n        bytes32 salt,\n        uint256 expiry,\n        bytes memory signature\n    ) external onlyRouter returns (uint256) {\n        require(targetToken != address(0), \"FM: bad token\");\n        require(foundryToken != address(0), \"FM: bad token\");\n        require(to != address(0), \"FM: bad payee\");\n        require(salt != 0, \"FM: bad salt\");\n        require(amountIn != 0, \"FM: bad amount\");\n        require(minAmountOut != 0, \"FM: bad amount\");\n        require(block.timestamp < expiry, \"FM: signature timed out\");\n        require(expiry < block.timestamp + WEEK, \"FM: expiry too far\");\n\n        bytes32 message =  keccak256(\n                abi.encode(\n                    WITHDRAW_SIGNED_WITH_SWAP_METHOD,\n                    to,\n                    amountIn,\n                    minAmountOut,\n                    foundryToken,\n                    targetToken,\n                    router,\n                    salt,\n                    expiry\n                )\n            );\n        address _signer = signerUnique(message, signature);\n        require(signers[_signer], \"FM: Invalid signer\");\n        require(!usedSalt[salt], \"FM: salt already used\");\n        usedSalt[salt] = true;\n         // transfer the tokens to the receiver\n        IERC20(foundryToken).safeTransfer(msg.sender, amountIn);\n        emit TransferBySignature(_signer, msg.sender, foundryToken, amountIn);\n        return amountIn;\n    }\n\n    /**\n     * @dev Verifies details of a signed token withdrawal without executing the withdrawal\n     * @param token Token address for withdrawal\n     * @param payee Intended recipient address\n     * @param amount Amount of tokens to be withdrawn\n     * @param salt Unique identifier to prevent replay attacks\n     * @param expiry Expiration timestamp of the withdrawal signature\n     * @param signature Cryptographic signature for verification\n     * @return Digest and signer's address from the provided signature\n     */\n    function withdrawSignedVerify(\n        address token,\n        address payee,\n        uint256 amount,\n        bytes32 salt,\n        uint256 expiry,\n        bytes calldata signature\n    ) external view returns (bytes32, address) {\n        bytes32 message = keccak256(\n                abi.encode(WITHDRAW_SIGNED_METHOD, token, payee, amount, salt, expiry)\n            );\n        (bytes32 digest, address _signer) = signer(message, signature);\n        return (digest, _signer);\n    }\n\n    /**\n     * @dev Verifies details of a signed token swap withdrawal without execution\n     * @param to Recipient address on the target network\n     * @param amountIn Tokens withdrawn from Foundry\n     * @param minAmountOut The minimum tokens on the target network\n     * @param foundryToken Token withdrawn from Foundry\n     * @param targetToken Token on the target network\n     * @param router The router address\n     * @param salt Unique identifier to prevent replay attacks\n     * @param expiry Expiration timestamp of the withdrawal signature\n     * @param signature Cryptographic signature for verification\n     * @return Digest and signer's address from the provided signature\n     */\n    function withdrawSignedAndSwapRouterVerify(\n        address to,\n        uint256 amountIn,\n        uint256 minAmountOut,\n        address foundryToken,\n        address targetToken,\n        address router,\n        bytes32 salt,\n        uint256 expiry,\n        bytes calldata signature\n    ) external view returns (bytes32, address) {\n        bytes32 message =  keccak256(\n                abi.encode(\n                    WITHDRAW_SIGNED_WITH_SWAP_METHOD,\n                    to,\n                    amountIn,\n                    minAmountOut,\n                    foundryToken,\n                    targetToken,\n                    router,\n                    salt,\n                    expiry\n                )\n            );\n        (bytes32 digest, address _signer) = signer(message, signature);\n        return (digest, _signer);\n    }\n\n    /**\n     * @notice Initiates a Cross-Chain Transfer Protocol (CCTP) swap.\n     * @dev This function handles the process of approving tokens and initiating a cross-chain token burn and deposit.\n     * @param amountIn The amount of tokens to be swapped.\n     * @param token The address of the token to be swapped (must be USDC).\n     * @param targetNetwork The identifier of the target network for the swap.\n     * @return depositNonce The nonce associated with the deposit for burn transaction.\n     */\n    function swapCCTP(uint256 amountIn, address token, uint256 targetNetwork) external onlyRouter returns (uint64 depositNonce){\n        TargetNetwork memory target = targetNetworks[targetNetwork];\n        require(target.targetNetworkDomain != 0, \"FR: Target network not found\");\n        require(target.targetCCTPFundManager != address(0), \"FR: Target CCTP FundManager address not found\");\n        require(token == usdcToken, \"FR: Invalid token\");\n\n        require(IERC20(token).approve(cctpTokenMessenger, amountIn), \"Approval failed\");\n\n        depositNonce = ICCTPTokenMessenger(cctpTokenMessenger).depositForBurn(\n            amountIn,\n            target.targetNetworkDomain,\n            addressToBytes32(target.targetCCTPFundManager),\n            usdcToken\n        );\n    }     \n\n    /**\n     * @notice Converts an Ethereum address to a bytes32 representation.\n     * @dev This is useful for interacting with contracts or protocols that require addresses in bytes32 format.\n     * @param addr The address to be converted.\n     * @return The bytes32 representation of the given address.\n     */\n    function addressToBytes32(address addr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(addr)));\n    }\n}"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "evmVersion": "paris",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}