creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/DestraDNSRegistrarRX02.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./IDestraDNSRegistrarRX02.sol\";\n\ncontract DestraDNSRegistrarRX02 is\n  ReentrancyGuard,\n  Ownable,\n  IDestraDNSRegistrarRX02\n{\n  struct Domain {\n    address owner;\n    uint expiryDate;\n    address resolverAddress;\n  }\n\n  struct TransferRequest {\n    address newOwner;\n    uint256 unlockTime;\n  }\n\n  struct Reservation {\n    bytes32 hash;\n    uint256 timestamp;\n  }\n\n  mapping(bytes32 => Domain) private domains;\n  mapping(uint => uint) public pricePerLength;\n\n  mapping(bytes32 => TransferRequest) private transferRequests;\n\n  mapping(string => address) public approvedResolvers;\n\n  mapping(address => mapping(bytes32 => Reservation)) private reservations;\n\n  uint public maxLengthPrice = 4;\n\n  uint public reservationPhaseDuration = 90 seconds;\n  uint public reservationExpiryDuration = 7 days;\n\n  address public proofOfSyncFactory;\n\n  constructor() Ownable(msg.sender) {\n    pricePerLength[1] = 0.1 ether;\n    pricePerLength[2] = 0.05 ether;\n    pricePerLength[3] = 0.025 ether;\n    pricePerLength[4] = 0.005 ether;\n  }\n\n  modifier domainAvailable(string memory domain) {\n    bytes32 domainHash = keccak256(abi.encodePacked(domain));\n    bool isExpired = domains[domainHash].expiryDate < block.timestamp;\n    bool isGracePeriodOver = block.timestamp >\n      domains[domainHash].expiryDate + 21 days;\n    require(\n      domains[domainHash].owner == address(0) ||\n        (isExpired && isGracePeriodOver),\n      \"Domain not available\"\n    );\n    _;\n  }\n\n  function setPrices(\n    uint[] memory lengths,\n    uint[] memory prices,\n    uint _maxLengthPrice\n  ) public onlyOwner {\n    require(\n      lengths.length == prices.length,\n      \"Lengths and prices must match in size\"\n    );\n\n    maxLengthPrice = _maxLengthPrice;\n    for (uint i = 0; i < lengths.length; i++) {\n      uint length = lengths[i];\n      uint price = prices[i];\n      require(length > 0 && length <= maxLengthPrice, \"Invalid length\");\n      pricePerLength[length] = price;\n    }\n  }\n\n  function getPrice(string memory domain) public view returns (uint) {\n    uint length = bytes(domain).length;\n    if (length > maxLengthPrice || pricePerLength[length] == 0) {\n      return pricePerLength[maxLengthPrice];\n    }\n    return pricePerLength[length];\n  }\n\n  function reserveDomain(bytes32 reservationId, bytes32 hash) public {\n    require(\n      reservations[msg.sender][reservationId].timestamp == 0,\n      \"Reservation ID already in use\"\n    );\n    reservations[msg.sender][reservationId] = Reservation(\n      hash,\n      block.timestamp\n    );\n  }\n\n  function generateReservationsHash(\n    string memory domain,\n    string memory secret\n  ) public pure returns (bytes32) {\n    return keccak256(abi.encodePacked(domain, secret));\n  }\n\n  function buyDomain(\n    string memory domain,\n    uint _years,\n    string memory secret,\n    bytes32 reservationId\n  ) public payable domainAvailable(domain) {\n    Reservation memory userReservation = reservations[msg.sender][\n      reservationId\n    ];\n    require(userReservation.timestamp != 0, \"No reservation found\");\n    require(\n      block.timestamp >= userReservation.timestamp + reservationPhaseDuration,\n      \"Minimum delay not met\"\n    );\n    require(\n      block.timestamp <= userReservation.timestamp + reservationExpiryDuration,\n      \"Reservation expired\"\n    );\n\n    bytes32 providedHash = generateReservationsHash(domain, secret);\n    require(providedHash == userReservation.hash, \"Invalid name or secret\");\n\n    bytes32 domainHash = keccak256(abi.encodePacked(domain));\n    uint price = getPrice(domain) * _years;\n    require(msg.value >= price, \"Insufficient payment\");\n\n    domains[domainHash] = Domain(\n      msg.sender,\n      block.timestamp + (_years * 365 days),\n      address(0)\n    );\n    delete reservations[msg.sender][reservationId];\n\n    emit DomainPurchased(\n      domainHash,\n      msg.sender,\n      domains[domainHash].expiryDate\n    );\n  }\n\n  function renewDomain(string memory domain, uint _years) public payable {\n    bytes32 domainHash = keccak256(abi.encodePacked(domain));\n    require(domains[domainHash].owner == msg.sender, \"Not the domain owner\");\n    uint price = getPrice(domain) * _years;\n    require(msg.value >= price, \"Insufficient payment\");\n\n    if (\n      domains[domainHash].expiryDate < block.timestamp &&\n      domains[domainHash].expiryDate + 21 days > block.timestamp\n    ) {\n      domains[domainHash].expiryDate = block.timestamp + (_years * 365 days);\n    } else {\n      domains[domainHash].expiryDate += _years * 365 days;\n    }\n\n    emit DomainRenewed(domainHash, domains[domainHash].expiryDate);\n  }\n\n  function initiateTransferOwnership(\n    string memory domain,\n    address newOwner\n  ) public {\n    bytes32 domainHash = keccak256(abi.encodePacked(domain));\n    require(domains[domainHash].owner == msg.sender, \"Not the domain owner\");\n    transferRequests[domainHash] = TransferRequest(\n      newOwner,\n      block.timestamp + 72 hours\n    );\n    emit DomainOwnershipTransferQueued(\n      domainHash,\n      newOwner,\n      block.timestamp + 72 hours\n    );\n  }\n\n  function completeTransferOwnership(string memory domain) public {\n    bytes32 domainHash = keccak256(abi.encodePacked(domain));\n    TransferRequest memory request = transferRequests[domainHash];\n    require(\n      block.timestamp >= request.unlockTime,\n      \"Transfer lock period has not expired\"\n    );\n    require(\n      request.newOwner != address(0),\n      \"Transfer request not found or already completed\"\n    );\n    require(\n      domains[domainHash].owner == msg.sender || request.newOwner == msg.sender,\n      \"Unauthorized to complete transfer\"\n    );\n\n    domains[domainHash].owner = request.newOwner;\n    emit OwnershipTransferred(\n      domainHash,\n      domains[domainHash].owner,\n      request.newOwner\n    );\n    delete transferRequests[domainHash];\n  }\n\n  function cancelTransferRequest(string memory domain) public {\n    bytes32 domainHash = keccak256(abi.encodePacked(domain));\n    require(\n      domains[domainHash].owner == msg.sender ||\n        transferRequests[domainHash].newOwner == msg.sender,\n      \"Only the current or proposed new owner can cancel the transfer request\"\n    );\n\n    require(\n      transferRequests[domainHash].newOwner != address(0),\n      \"Transfer request does not exist\"\n    );\n\n    emit DomainOwnershipTransferCancelled(domainHash);\n    delete transferRequests[domainHash];\n  }\n\n  function approveResolver(\n    string memory tld,\n    address resolverAddress\n  ) public onlyOwner {\n    require(resolverAddress != address(0), \"Resolver address cannot be zero\");\n    approvedResolvers[tld] = resolverAddress;\n    emit ResolverApproved(resolverAddress, tld);\n  }\n\n  function setResolver(\n    string memory domain,\n    address resolverAddress,\n    string memory tld\n  ) public {\n    bytes32 domainHash = keccak256(abi.encodePacked(domain));\n    require(domains[domainHash].owner == msg.sender, \"Not the domain owner\");\n\n    require(\n      approvedResolvers[tld] == resolverAddress,\n      \"Resolver not approved for TLD\"\n    );\n\n    domains[domainHash].resolverAddress = resolverAddress;\n    emit ResolverSet(domainHash, resolverAddress);\n  }\n\n  function isDomainAvailable(string memory domain) public view returns (bool) {\n    return domains[keccak256(abi.encodePacked(domain))].owner == address(0);\n  }\n\n  function getDomainDetails(\n    string memory domain\n  )\n    public\n    view\n    returns (address owner, uint expiryDate, address resolverAddress)\n  {\n    bytes32 domainHash = keccak256(abi.encodePacked(domain));\n    Domain memory domainDetails = domains[domainHash];\n    return (\n      domainDetails.owner,\n      domainDetails.expiryDate,\n      domainDetails.resolverAddress\n    );\n  }\n\n  function setReservationPhaseDuration(\n    uint _reservationPhaseDuration\n  ) external onlyOwner {\n    reservationPhaseDuration = _reservationPhaseDuration;\n\n    emit ReservationPhaseDurationUpdated(_reservationPhaseDuration);\n  }\n\n  function setReservationExpiryDuration(\n    uint _reservationExpiryDuration\n  ) external onlyOwner {\n    reservationExpiryDuration = _reservationExpiryDuration;\n\n    emit ReservationExpiryDurationUpdated(_reservationExpiryDuration);\n  }\n\n  function withdrawBalance(\n    address payable recipient,\n    uint256 amount\n  ) external onlyOwner nonReentrant {\n    require(proofOfSyncFactory == address(0), \"Withdrawal rights transferred\");\n    require(address(this).balance >= amount, \"Insufficient balance\");\n\n    (bool success, ) = recipient.call{value: amount}(\"\");\n    require(success, \"Failed to send ETH\");\n    emit Withdrawal(recipient, amount);\n  }\n\n  function setDestraFactory(address _proofOfSyncFactory) external onlyOwner {\n    proofOfSyncFactory = _proofOfSyncFactory;\n    emit ProofOfSyncFactorySet(proofOfSyncFactory);\n  }\n\n  function claimBalance() external {\n    require(\n      msg.sender == proofOfSyncFactory,\n      \"Caller is not the Destra factory\"\n    );\n\n    uint256 amount = address(this).balance;\n    require(amount > 0, \"No funds available\");\n\n    (bool success, ) = proofOfSyncFactory.call{value: amount}(\"\");\n    require(success, \"Failed to send ETH\");\n    emit Withdrawal(proofOfSyncFactory, amount);\n  }\n\n  function transferForeignToken(\n    address _token,\n    address _to\n  ) external onlyOwner returns (bool _sent) {\n    require(_token != address(0), \"_token address cannot be 0\");\n    require(_token != address(this), \"Can't withdraw native tokens\");\n    uint256 _contractBalance = IERC20(_token).balanceOf(address(this));\n    _sent = IERC20(_token).transfer(_to, _contractBalance);\n    emit TransferForeignToken(_token, _contractBalance);\n  }\n\n  function getResolverForTLD(string memory tld) public view returns (address) {\n    return approvedResolvers[tld];\n  }\n}\n"
      },
      "contracts/IDestraDNSRegistrarRX02.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\ninterface IDestraDNSRegistrarRX02 {\n  event DomainPurchased(\n    bytes32 indexed domainHash,\n    address indexed owner,\n    uint expiryDate\n  );\n\n  event DomainRenewed(bytes32 indexed domainHash, uint newExpiryDate);\n  event OwnershipTransferred(\n    bytes32 indexed domainHash,\n    address indexed oldOwner,\n    address indexed newOwner\n  );\n  event ResolverSet(\n    bytes32 indexed domainHash,\n    address indexed resolverAddress\n  );\n\n  event DomainOwnershipTransferQueued(\n    bytes32 indexed domainHash,\n    address indexed newOwner,\n    uint256 eta\n  );\n  event DomainOwnershipTransferCancelled(bytes32 indexed domainHash);\n\n  event ResolverApproved(address indexed resolverAddress, string tld);\n  event ResolverRevoked(address indexed resolverAddress);\n\n  event ReservationPhaseDurationUpdated(uint newDuration);\n  event ReservationExpiryDurationUpdated(uint newDuration);\n\n  event Withdrawal(address indexed to, uint256 amount);\n  event ProofOfSyncFactorySet(address indexed proofOfSyncFactory);\n  event TransferForeignToken(address token, uint256 amount);\n\n  /**\n   * @dev Sets the prices for domain registrations based on their length.\n   * @param lengths An array of domain lengths.\n   * @param prices Corresponding prices for each domain length.\n   */\n  function setPrices(\n    uint[] memory lengths,\n    uint[] memory prices,\n    uint maxLengthPrice\n  ) external;\n\n  /**\n   * @dev Retrieves the registration price for a given domain name based on its length.\n   * @param domain The domain name whose price is to be retrieved.\n   * @return The price for registering the given domain.\n   */\n  function getPrice(string memory domain) external view returns (uint);\n\n  /**\n   * @dev Reserves a domain by creating a hash reservation with the domain and a secret.\n   * @param reservationId A unique identifier for the reservation.\n   * @param hash The keccak256 hash of the domain and secret.\n   */\n  function reserveDomain(bytes32 reservationId, bytes32 hash) external;\n\n  /**\n   * @dev Generates a hash used for reserving a domain. This hash includes the domain name and a secret.\n   * @param domain The domain name to be hashed.\n   * @param secret A secret value to be hashed with the domain name.\n   * @return The resulting hash of the domain and secret.\n   */\n  function generateReservationsHash(\n    string memory domain,\n    string memory secret\n  ) external pure returns (bytes32);\n\n  /**\n   * @dev Registers a domain after a successful reservation and reservation phase.\n   * @param domain The domain name to register.\n   * @param _years The number of years to register the domain for.\n   * @param secret The secret used in the reservation hash.\n   * @param reservationId The unique identifier for the reservation.\n   */\n  function buyDomain(\n    string memory domain,\n    uint _years,\n    string memory secret,\n    bytes32 reservationId\n  ) external payable;\n\n  /**\n   * @dev Renews the registration of a domain.\n   * @param domain The domain name to renew.\n   * @param _years The number of additional years to renew the domain for.\n   */\n  function renewDomain(string memory domain, uint _years) external payable;\n\n  /**\n   * @dev Initiates the transfer of domain ownership to a new owner.\n   * @param domain The domain name whose ownership is to be transferred.\n   * @param newOwner The address of the new owner.\n   */\n  function initiateTransferOwnership(\n    string memory domain,\n    address newOwner\n  ) external;\n\n  /**\n   * @dev Completes the transfer of domain ownership after the unlock time.\n   * @param domain The domain name being transferred.\n   */\n  function completeTransferOwnership(string memory domain) external;\n\n  /**\n   * @dev Cancels a pending transfer request for a domain.\n   * @param domain The domain name whose transfer is to be cancelled.\n   */\n  function cancelTransferRequest(string memory domain) external;\n\n  /**\n   * @dev Approves a resolver address, allowing it to be used for domains.\n   * @param resolverAddress The address of the resolver to approve.\n   */\n  function approveResolver(string memory tld, address resolverAddress) external;\n\n  /**\n   * @dev Sets the resolver address for a domain.\n   * @param domain The domain name to set the resolver for.\n   * @param resolverAddress The address of the resolver.\n   */\n  function setResolver(\n    string memory domain,\n    address resolverAddress,\n    string memory tld\n  ) external;\n\n  /**\n   * @dev Checks if a domain is available for registration.\n   * @param domain The domain name to check availability for.\n   * @return True if the domain is available, false otherwise.\n   */\n  function isDomainAvailable(string memory domain) external view returns (bool);\n\n  /**\n   * @dev Retrieves details for a given domain.\n   * @param domain The domain name to query.\n   * @return owner The address of the domain owner.\n   * @return expiryDate The expiration date of the domain registration.\n   * @return resolverAddress The address of the domain resolver.\n   */\n  function getDomainDetails(\n    string memory domain\n  )\n    external\n    view\n    returns (address owner, uint expiryDate, address resolverAddress);\n\n  /**\n   * @dev Allows the contract owner to update the reservation phase duration.\n   * @param _reservationPhaseDuration The new duration in seconds.\n   */\n  function setReservationPhaseDuration(uint _reservationPhaseDuration) external;\n\n  /**\n   * @dev Allows the contract owner to update the reservation expiry duration.\n   * @param _reservationExpiryDuration The new expiry duration in seconds.\n   */\n  function setReservationExpiryDuration(\n    uint _reservationExpiryDuration\n  ) external;\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\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    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) 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 a `value` amount of tokens as the allowance of `spender` over the\n     * 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 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` 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 from, address to, uint256 value) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/utils/ReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant NOT_ENTERED = 1;\n    uint256 private constant ENTERED = 2;\n\n    uint256 private _status;\n\n    /**\n     * @dev Unauthorized reentrant call.\n     */\n    error ReentrancyGuardReentrantCall();\n\n    constructor() {\n        _status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be NOT_ENTERED\n        if (_status == ENTERED) {\n            revert ReentrancyGuardReentrantCall();\n        }\n\n        // Any calls to nonReentrant after this point will fail\n        _status = ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == ENTERED;\n    }\n}\n"
      },
      "@openzeppelin/contracts/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\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 * The initial owner is set to the address provided by the deployer. This can\n * 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    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    constructor(address initialOwner) {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\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 the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(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        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\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        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      }
    }
  }}