Accounts
0xd1...69F6
0xd1...69F6

0xd1...69F6

$500
This contract's source code is verified!
Contract Metadata
Compiler
0.8.26+commit.8a97fa7a
Language
Solidity
Contract Source Code
File 1 of 12: Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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;
    }
}
Contract Source Code
File 2 of 12: ENSRent.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import { ERC1155Holder } from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

import { IBaseRegistrar } from "./interfaces/IBaseRegistrar.sol";
import { INameWrapper } from "./interfaces/INameWrapper.sol";
import { IENSRent } from "./interfaces/IENSRent.sol";

/**
 * @title ENSRent
 * @author Alex Netto (@alextnetto)
 * @author Lucas Picollo (@pikonha)
 * @notice ENS domain rental contract with a fixed price per second
 * @dev Implements rental functionality for both wrapped (ERC1155) and unwrapped (ERC721) ENS names
 */
contract ENSRent is IENSRent, ERC721Holder, ERC1155Holder, Ownable {
    /**
     * @notice Fee percentage taken from rental payments
     */
    uint256 public feeBasisPoints;

    /**
     * @notice The ENS base registrar contract for managing .eth domains
     * @dev Used for handling ERC721 transfers and domain management
     */
    IBaseRegistrar public immutable baseRegistrar;

    /**
     * @notice The ENS name wrapper contract for handling wrapped domains
     * @dev Used for ERC1155 transfers and wrapped domain management
     */
    INameWrapper public immutable nameWrapper;

    /**
     * @notice Storage structure for domain rental information
     * @param lender Owner of the domain
     * @param minPricePerSecond Floor price set by owner
     * @param maxEndTimestamp Latest possible rental end date
     * @param currentBorrower Address currently renting the domain
     * @param rentalEnd Current rental end timestamp (or auction start if never rented)
     * @param nameNode Namehash of the ENS domain
     * @param tokenId ERC721 token ID of the domain
     */
    struct RentalTerms {
        address lender;
        uint256 minPricePerSecond;
        uint256 maxEndTimestamp;
        address currentBorrower;
        uint256 rentalEnd;
        bytes32 nameNode;
        uint256 tokenId;
    }

    /**
     * @notice Maps domain token IDs to their rental terms
     * @dev Primary storage for rental information
     */
    mapping(uint256 => RentalTerms) public rentalTerms;

    /**
     * @notice Initialize the rental contract
     * @param _nameWrapper Address of ENS NameWrapper contract
     * @param _baseRegistrarAddress Address of ENS BaseRegistrar contract
     * @param _feeBasisPoints Fee percentage taken from rentals (100 = 1%)
     * @dev Sets up immutable contract references
     */
    constructor(
        address _nameWrapper,
        address _baseRegistrarAddress,
        uint256 _feeBasisPoints,
        address _owner
    )
        Ownable(_owner)
    {
        nameWrapper = INameWrapper(_nameWrapper);
        baseRegistrar = IBaseRegistrar(_baseRegistrarAddress);
        _setFeeBasisPoints(_feeBasisPoints);
    }

    /**
     * @notice List domain for rent and start initial auction
     * @param tokenId Domain's ERC721 token ID
     * @param minPricePerSecond Minimum rental price per second
     * @param maxEndTimestamp Latest possible rental end time
     * @param nameNode Domain's namehash
     * @dev Handles both wrapped and unwrapped domains
     */
    function listDomain(
        uint256 tokenId,
        uint256 minPricePerSecond,
        uint256 maxEndTimestamp,
        bytes32 nameNode,
        string calldata name
    )
        external
    {
        // Validate listing parameters
        if (minPricePerSecond == 0) revert ZeroPriceNotAllowed();
        if (maxEndTimestamp <= block.timestamp) revert MaxEndTimeMustBeFuture();
        if (maxEndTimestamp >= baseRegistrar.nameExpires(tokenId)) revert MaxEndTimeExceedsExpiry();

        // Handle domain transfer based on wrapper status
        if (baseRegistrar.ownerOf(tokenId) == address(nameWrapper)) {
            // For wrapped domains: transfer ERC1155 and unwrap
            nameWrapper.safeTransferFrom(msg.sender, address(this), uint256(nameNode), 1, "");
            nameWrapper.unwrapETH2LD(bytes32(tokenId), address(this), address(this));
        } else {
            // For unwrapped domains: transfer ERC721 and claim ownership
            baseRegistrar.safeTransferFrom(msg.sender, address(this), tokenId);
            baseRegistrar.reclaim(tokenId, address(this));
        }

        // Store rental terms and start auction
        rentalTerms[tokenId] = RentalTerms({
            lender: msg.sender,
            minPricePerSecond: minPricePerSecond,
            maxEndTimestamp: maxEndTimestamp,
            currentBorrower: address(0),
            rentalEnd: block.timestamp, // Start first auction immediately
            nameNode: nameNode,
            tokenId: tokenId
        });

        emit DomainListed(name, tokenId, msg.sender, minPricePerSecond, maxEndTimestamp, nameNode);
    }

    /**
     * @notice Rent domain at current auction price
     * @param tokenId Domain's ERC721 token ID
     * @param desiredEndTimestamp Requested rental end time
     * @dev Handles both initial auction and post-rental auctions
     */
    function rentDomain(uint256 tokenId, uint256 desiredEndTimestamp) external payable {
        RentalTerms storage terms = rentalTerms[tokenId];

        // Validate rental request
        if (terms.lender == address(0)) revert DomainNotListed();
        if (desiredEndTimestamp > terms.maxEndTimestamp) revert ExceedsMaxEndTime();
        if (desiredEndTimestamp <= block.timestamp) revert EndTimeMustBeFuture();
        if (terms.currentBorrower != address(0)) {
            if (block.timestamp < terms.rentalEnd) revert DomainCurrentlyRented();
        }

        uint256 duration = desiredEndTimestamp - block.timestamp;
        uint256 totalPrice = terms.minPricePerSecond * duration;

        // Verify payment
        if (msg.value < totalPrice) revert InsufficientPayment();

        // Calculate fee
        uint256 fee = (totalPrice * feeBasisPoints) / 10_000;
        uint256 lenderPayment = totalPrice - fee;

        // Transfer domain control
        baseRegistrar.reclaim(tokenId, msg.sender);

        // Update rental terms
        terms.currentBorrower = msg.sender;
        terms.rentalEnd = desiredEndTimestamp;

        // Transfer payment to domain owner
        (bool sent,) = payable(terms.lender).call{ value: lenderPayment }("");
        if (!sent) revert EtherTransferFailed();

        // Refund excess payment
        if (msg.value > totalPrice) {
            (bool refundSent,) = payable(msg.sender).call{ value: msg.value - totalPrice }("");
            if (!refundSent) revert EtherTransferFailed();
        }

        emit DomainRented(tokenId, msg.sender, desiredEndTimestamp, totalPrice, terms.minPricePerSecond);
    }

    /**
     * @notice Returns the ownership to the Rent contract to be rented again
     * @param tokenId Domain's ERC721 token ID
     */
    function handleRentalEnd(uint256 tokenId) external {
        RentalTerms storage terms = rentalTerms[tokenId];

        if (terms.lender == address(0) || block.timestamp > terms.maxEndTimestamp) revert DomainNotListed();
        if (block.timestamp < terms.rentalEnd) revert DomainCurrentlyRented();

        baseRegistrar.reclaim(tokenId, address(this));
        terms.currentBorrower = address(0);
        terms.rentalEnd = 0;
    }

    /**
     * @notice Allow owner to reclaim domain after rental
     * @param tokenId Domain's ERC721 token ID
     * @dev Can only be called after rental period ends
     */
    function reclaimDomain(uint256 tokenId) external {
        RentalTerms storage terms = rentalTerms[tokenId];

        // Validate reclaim request
        if (msg.sender != terms.lender) revert NotLender();
        if (block.timestamp < terms.rentalEnd) revert DomainCurrentlyRented();

        // Return domain control
        baseRegistrar.reclaim(terms.tokenId, terms.lender);
        baseRegistrar.safeTransferFrom(address(this), terms.lender, tokenId);

        // Clean up storage
        delete rentalTerms[tokenId];

        emit DomainReclaimed(tokenId, terms.lender);
    }

    /**
     * @notice Update the fee percentage taken from rentals
     * @param _feeBasisPoints New fee in basis points
     * @dev Can only be called by contract owner
     */
    function setFeeBasisPoints(uint256 _feeBasisPoints) external onlyOwner {
        _setFeeBasisPoints(_feeBasisPoints);
    }

    /**
     * @notice Internal function to validate and set fee basis points
     * @param _feeBasisPoints New fee in basis points
     */
    function _setFeeBasisPoints(uint256 _feeBasisPoints) private {
        require(_feeBasisPoints <= 1000, "Fee cannot exceed 10%");
        feeBasisPoints = _feeBasisPoints;
    }

    receive() external payable { }

    function withdraw() external onlyOwner {
        (bool sent,) = payable(owner()).call{ value: address(this).balance }("");
        if (!sent) revert EtherTransferFailed();
    }
}
Contract Source Code
File 3 of 12: ERC1155Holder.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/utils/ERC1155Holder.sol)

pragma solidity ^0.8.20;

import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol";
import {IERC1155Receiver} from "../IERC1155Receiver.sol";

/**
 * @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC-1155 tokens.
 *
 * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be
 * stuck.
 */
abstract contract ERC1155Holder is ERC165, IERC1155Receiver {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
    }

    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes memory
    ) public virtual override returns (bytes4) {
        return this.onERC1155Received.selector;
    }

    function onERC1155BatchReceived(
        address,
        address,
        uint256[] memory,
        uint256[] memory,
        bytes memory
    ) public virtual override returns (bytes4) {
        return this.onERC1155BatchReceived.selector;
    }
}
Contract Source Code
File 4 of 12: ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}
Contract Source Code
File 5 of 12: ERC721Holder.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC721Receiver} interface.
 *
 * Accepts all token transfers.
 * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or
 * {IERC721-setApprovalForAll}.
 */
abstract contract ERC721Holder is IERC721Receiver {
    /**
     * @dev See {IERC721Receiver-onERC721Received}.
     *
     * Always returns `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) {
        return this.onERC721Received.selector;
    }
}
Contract Source Code
File 6 of 12: IBaseRegistrar.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

interface IBaseRegistrar {
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
    event ControllerAdded(address indexed controller);
    event ControllerRemoved(address indexed controller);
    event NameMigrated(uint256 indexed id, address indexed owner, uint256 expires);
    event NameRegistered(uint256 indexed id, address indexed owner, uint256 expires);
    event NameRenewed(uint256 indexed id, uint256 expires);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    function GRACE_PERIOD() external view returns (uint256);
    function addController(address controller) external;
    function approve(address to, uint256 tokenId) external;
    function available(uint256 id) external view returns (bool);
    function balanceOf(address owner) external view returns (uint256);
    function baseNode() external view returns (bytes32);
    function controllers(address) external view returns (bool);
    function ens() external view returns (address);
    function getApproved(uint256 tokenId) external view returns (address);
    function isApprovedForAll(address owner, address operator) external view returns (bool);
    function name() external view returns (string memory);
    function nameExpires(uint256 id) external view returns (uint256);
    function owner() external view returns (address);
    function ownerOf(uint256 tokenId) external view returns (address);
    function reclaim(uint256 id, address owner) external;
    function register(uint256 id, address owner, uint256 duration) external returns (uint256);
    function registerOnly(uint256 id, address owner, uint256 duration) external returns (uint256);
    function removeController(address controller) external;
    function renew(uint256 id, uint256 duration) external returns (uint256);
    function renounceOwnership() external;
    function safeTransferFrom(address from, address to, uint256 tokenId) external;
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) external;
    function setApprovalForAll(address operator, bool approved) external;
    function setResolver(address resolver) external;
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
    function symbol() external view returns (string memory);
    function tokenURI(uint256 tokenId) external view returns (string memory);
    function transferFrom(address from, address to, uint256 tokenId) external;
    function transferOwnership(address newOwner) external;
}
Contract Source Code
File 7 of 12: IENSRent.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IENSRent {
    //// EVENTS ////

    /**
     * @notice Emitted when a domain is listed for rent
     * @param tokenId Domain's ERC721 token ID
     * @param lender Domain owner's address
     * @param minPricePerSecond Floor price for rentals
     * @param maxEndTimestamp Latest allowed rental end time
     * @param nameNode Domain's namehash
     * @dev Triggered in listDomain function when domain is first listed
     */
    event DomainListed(
        string name,
        uint256 indexed tokenId,
        address indexed lender,
        uint256 minPricePerSecond,
        uint256 maxEndTimestamp,
        bytes32 nameNode
    );

    /**
     * @notice Emitted when a domain is rented
     * @param tokenId Domain's ERC721 token ID
     * @param borrower Renter's address
     * @param rentalEnd Rental end timestamp
     * @param totalPrice Total price paid for rental
     * @param pricePerSecond Rate paid per second
     * @dev Includes actual price paid from Dutch auction
     */
    event DomainRented(
        uint256 indexed tokenId, address indexed borrower, uint256 rentalEnd, uint256 totalPrice, uint256 pricePerSecond
    );

    /**
     * @notice Emitted when owner reclaims their domain
     * @param tokenId Domain's ERC721 token ID
     * @param lender Owner's address
     * @dev Only emitted after rental period ends
     */
    event DomainReclaimed(uint256 indexed tokenId, address indexed lender);

    //// ERRORS ////

    /**
     * @notice Minimum price must be greater than zero
     * @dev Thrown in listDomain when minPricePerSecond = 0
     */
    error ZeroPriceNotAllowed();

    /**
     * @notice Maximum rental end time must be future timestamp
     * @dev Thrown when maxEndTimestamp <= current time
     */
    error MaxEndTimeMustBeFuture();

    /**
     * @notice Maximum end time cannot exceed domain expiry
     * @dev Ensures domain doesn't expire during rental period
     */
    error MaxEndTimeExceedsExpiry();

    /**
     * @notice Domain must be listed before renting
     * @dev Thrown when attempting to rent unlisted domain
     */
    error DomainNotListed();

    /**
     * @notice Rental end time exceeds maximum allowed
     * @dev Enforces owner-set maximum rental duration
     */
    error ExceedsMaxEndTime();

    /**
     * @notice Rental end time must be in the future
     * @dev Basic timestamp validation
     */
    error EndTimeMustBeFuture();

    /**
     * @notice Cannot rent domain during active rental
     * @dev Prevents overlapping rentals
     */
    error DomainCurrentlyRented();

    /**
     * @notice Payment must cover calculated rental cost
     * @dev Ensures sufficient payment for desired duration
     */
    error InsufficientPayment();

    /**
     * @notice ETH transfer failed
     * @dev Safety check for ETH transfers
     */
    error EtherTransferFailed();

    /**
     * @notice Only domain owner can perform action
     * @dev Access control for owner operations
     */
    error NotLender();
}
Contract Source Code
File 8 of 12: IERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Interface that must be implemented by smart contracts in order to receive
 * ERC-1155 token transfers.
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC-1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC-1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}
Contract Source Code
File 9 of 12: IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
Contract Source Code
File 10 of 12: IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.20;

/**
 * @title ERC-721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC-721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be
     * reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}
Contract Source Code
File 11 of 12: INameWrapper.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

interface INameWrapper {
    error CannotUpgrade();
    error IncompatibleParent();
    error IncorrectTargetOwner(address owner);
    error IncorrectTokenType();
    error LabelMismatch(bytes32 labelHash, bytes32 expectedLabelhash);
    error LabelTooLong(string label);
    error LabelTooShort();
    error NameIsNotWrapped();
    error OperationProhibited(bytes32 node);
    error Unauthorised(bytes32 node, address addr);

    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);
    event ControllerChanged(address indexed controller, bool active);
    event ExpiryExtended(bytes32 indexed node, uint64 expiry);
    event FusesSet(bytes32 indexed node, uint32 fuses);
    event NameUnwrapped(bytes32 indexed node, address owner);
    event NameWrapped(bytes32 indexed node, bytes name, address owner, uint32 fuses, uint64 expiry);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event TransferBatch(
        address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values
    );
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
    event URI(string value, uint256 indexed id);

    function _tokens(uint256) external view returns (uint256);
    function allFusesBurned(bytes32 node, uint32 fuseMask) external view returns (bool);
    function approve(address to, uint256 tokenId) external;
    function balanceOf(address account, uint256 id) external view returns (uint256);
    function balanceOfBatch(address[] memory accounts, uint256[] memory ids) external view returns (uint256[] memory);
    function canExtendSubnames(bytes32 node, address addr) external view returns (bool);
    function canModifyName(bytes32 node, address addr) external view returns (bool);
    function controllers(address) external view returns (bool);
    function ens() external view returns (address);
    function extendExpiry(bytes32 parentNode, bytes32 labelhash, uint64 expiry) external returns (uint64);
    function getApproved(uint256 id) external view returns (address operator);
    function getData(uint256 id) external view returns (address owner, uint32 fuses, uint64 expiry);
    function isApprovedForAll(address account, address operator) external view returns (bool);
    function isWrapped(bytes32 parentNode, bytes32 labelhash) external view returns (bool);
    function isWrapped(bytes32 node) external view returns (bool);
    function metadataService() external view returns (address);
    function name() external view returns (string memory);
    function names(bytes32) external view returns (bytes memory);
    function onERC721Received(address to, address, uint256 tokenId, bytes memory data) external returns (bytes4);
    function owner() external view returns (address);
    function ownerOf(uint256 id) external view returns (address owner);
    function recoverFunds(address _token, address _to, uint256 _amount) external;
    function registerAndWrapETH2LD(
        string memory label,
        address wrappedOwner,
        uint256 duration,
        address resolver,
        uint16 ownerControlledFuses
    )
        external
        returns (uint256 registrarExpiry);
    function registrar() external view returns (address);
    function renew(uint256 tokenId, uint256 duration) external returns (uint256 expires);
    function renounceOwnership() external;
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    )
        external;
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes memory data) external;
    function setApprovalForAll(address operator, bool approved) external;
    function setChildFuses(bytes32 parentNode, bytes32 labelhash, uint32 fuses, uint64 expiry) external;
    function setController(address controller, bool active) external;
    function setFuses(bytes32 node, uint16 ownerControlledFuses) external returns (uint32);
    function setMetadataService(address _metadataService) external;
    function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external;
    function setResolver(bytes32 node, address resolver) external;
    function setSubnodeOwner(
        bytes32 parentNode,
        string memory label,
        address owner,
        uint32 fuses,
        uint64 expiry
    )
        external
        returns (bytes32 node);
    function setSubnodeRecord(
        bytes32 parentNode,
        string memory label,
        address owner,
        address resolver,
        uint64 ttl,
        uint32 fuses,
        uint64 expiry
    )
        external
        returns (bytes32 node);
    function setTTL(bytes32 node, uint64 ttl) external;
    function setUpgradeContract(address _upgradeAddress) external;
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
    function transferOwnership(address newOwner) external;
    function unwrap(bytes32 parentNode, bytes32 labelhash, address controller) external;
    function unwrapETH2LD(bytes32 labelhash, address registrant, address controller) external;
    function upgrade(bytes memory name, bytes memory extraData) external;
    function upgradeContract() external view returns (address);
    function uri(uint256 tokenId) external view returns (string memory);
    function wrap(bytes memory name, address wrappedOwner, address resolver) external;
    function wrapETH2LD(
        string memory label,
        address wrappedOwner,
        uint16 ownerControlledFuses,
        address resolver
    )
        external
        returns (uint64 expiry);
}
Contract Source Code
File 12 of 12: Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * 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);
    }
}
Settings
{
  "compilationTarget": {
    "src/ENSRent.sol": "ENSRent"
  },
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 100
  },
  "remappings": [
    ":@forge-std/=node_modules/forge-std/src/",
    ":@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
    ":@src/=src/",
    ":forge-std/=node_modules/forge-std/"
  ],
  "viaIR": true
}
ABI
[{"inputs":[{"internalType":"address","name":"_nameWrapper","type":"address"},{"internalType":"address","name":"_baseRegistrarAddress","type":"address"},{"internalType":"uint256","name":"_feeBasisPoints","type":"uint256"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DomainCurrentlyRented","type":"error"},{"inputs":[],"name":"DomainNotListed","type":"error"},{"inputs":[],"name":"EndTimeMustBeFuture","type":"error"},{"inputs":[],"name":"EtherTransferFailed","type":"error"},{"inputs":[],"name":"ExceedsMaxEndTime","type":"error"},{"inputs":[],"name":"InsufficientPayment","type":"error"},{"inputs":[],"name":"MaxEndTimeExceedsExpiry","type":"error"},{"inputs":[],"name":"MaxEndTimeMustBeFuture","type":"error"},{"inputs":[],"name":"NotLender","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ZeroPriceNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"lender","type":"address"},{"indexed":false,"internalType":"uint256","name":"minPricePerSecond","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxEndTimestamp","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"nameNode","type":"bytes32"}],"name":"DomainListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"lender","type":"address"}],"name":"DomainReclaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"rentalEnd","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pricePerSecond","type":"uint256"}],"name":"DomainRented","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"baseRegistrar","outputs":[{"internalType":"contract IBaseRegistrar","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"handleRentalEnd","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"minPricePerSecond","type":"uint256"},{"internalType":"uint256","name":"maxEndTimestamp","type":"uint256"},{"internalType":"bytes32","name":"nameNode","type":"bytes32"},{"internalType":"string","name":"name","type":"string"}],"name":"listDomain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nameWrapper","outputs":[{"internalType":"contract INameWrapper","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"reclaimDomain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"desiredEndTimestamp","type":"uint256"}],"name":"rentDomain","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rentalTerms","outputs":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"uint256","name":"minPricePerSecond","type":"uint256"},{"internalType":"uint256","name":"maxEndTimestamp","type":"uint256"},{"internalType":"address","name":"currentBorrower","type":"address"},{"internalType":"uint256","name":"rentalEnd","type":"uint256"},{"internalType":"bytes32","name":"nameNode","type":"bytes32"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_feeBasisPoints","type":"uint256"}],"name":"setFeeBasisPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]