ENSBidPermit2

Description:

Smart contract deployed on Ethereum.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:


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

interface IERC20 {
    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

// Permit2 interface (corrected)
interface IPermit2 {
    struct PermitTransferFrom {
        TokenPermissions permitted;
        uint256 nonce;
        uint256 deadline;
    }

    struct TokenPermissions {
        address token;
        uint256 amount;
    }

    struct SignatureTransferDetails {
        address to;
        uint256 requestedAmount;
    }

    function permitTransferFrom(
        PermitTransferFrom memory permit,
        SignatureTransferDetails calldata transferDetails,
        address owner,
        bytes calldata signature
    ) external;

    function allowance(address owner, address token, address spender) 
        external view returns (uint160 amount, uint48 expiration, uint48 nonce);
}

// ENS interfaces
interface IENS {
    function owner(bytes32 node) external view returns (address);
    function setOwner(bytes32 node, address owner) external;
}

interface INameWrapper {
    function ownerOf(uint256 tokenId) external view returns (address);
    function safeTransferFrom(address from, address to, uint256 tokenId, uint256 amount, bytes calldata data) external;
}

contract ENSBidPermit2 {
    // Constants
    address public constant ENS = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
    address public constant NAME_WRAPPER = 0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401;
    address public constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
    
    // Contract state
    string public ensName;
    bytes32 public ensNode;
    address public buyer;
    address public token;
    uint256 public amount;
    uint256 public deadline;
    bytes public permit2Signature;
    uint256 public permit2Nonce;
    bool public permitSet;
    bool public executed;
    
    // Events
    event OfferCreated(string indexed ensName, address indexed buyer, address indexed token, uint256 amount);
    event PermitSet(address indexed buyer, uint256 nonce, uint256 deadline);
    event OfferAccepted(address indexed seller, address indexed buyer, string ensName, uint256 amount);
    
    constructor(
        string memory _ensName,
        bytes32 _ensNode,
        address _buyer,
        address _token,
        uint256 _amount
    ) {
        ensName = _ensName;
        ensNode = _ensNode;
        buyer = _buyer;
        token = _token;
        amount = _amount;
        
        emit OfferCreated(_ensName, _buyer, _token, _amount);
    }
    
    // Buyer submits Permit2 signature
    function setPermit2(
        uint256 _deadline,
        uint256 _nonce,
        bytes calldata _signature
    ) external {
        require(msg.sender == buyer, "Only buyer");
        require(!executed, "Already executed");
        
        deadline = _deadline;
        permit2Nonce = _nonce;
        permit2Signature = _signature;
        permitSet = true;
        
        emit PermitSet(buyer, _nonce, _deadline);
    }
    
    // Check if address is the owner of the ENS (supports wrapped and unwrapped)
    function isENSOwner(address user) public view returns (bool) {
        address registryOwner = IENS(ENS).owner(ensNode);
        
        // If the registry owner is the NameWrapper, check the NameWrapper ownership
        if (registryOwner == NAME_WRAPPER) {
            return INameWrapper(NAME_WRAPPER).ownerOf(uint256(ensNode)) == user;
        }
        
        // Otherwise, check direct registry ownership
        return registryOwner == user;
    }
    
    // ENS owner accepts: Permit2 transfer + ENS transfer in one atomic transaction
    function accept() external {
        require(permitSet, "No permit");
        require(!executed, "Already executed");
        require(isENSOwner(msg.sender), "Not ENS owner");
        
        // Execute Permit2 transfer
        IPermit2.PermitTransferFrom memory permit = IPermit2.PermitTransferFrom({
            permitted: IPermit2.TokenPermissions({
                token: token,
                amount: amount
            }),
            nonce: permit2Nonce,
            deadline: deadline
        });
        
        IPermit2.SignatureTransferDetails memory transferDetails = IPermit2.SignatureTransferDetails({
            to: msg.sender,
            requestedAmount: amount
        });
        
        // Execute the Permit2 transfer
        IPermit2(PERMIT2).permitTransferFrom(
            permit,
            transferDetails,
            buyer,
            permit2Signature
        );
        
        // Transfer ENS (wrapped or unwrapped)
        address registryOwner = IENS(ENS).owner(ensNode);
        if (registryOwner == NAME_WRAPPER) {
            // Wrapped ENS: transfer via NameWrapper
            INameWrapper(NAME_WRAPPER).safeTransferFrom(msg.sender, buyer, uint256(ensNode), 1, "");
        } else {
            // Unwrapped ENS: transfer via registry
            IENS(ENS).setOwner(ensNode, buyer);
        }
        
        executed = true;
        
        emit OfferAccepted(msg.sender, buyer, ensName, amount);
    }
    
    // Check if bid can be executed
    function canExecute() external view returns (bool) {
        address registryOwner = IENS(ENS).owner(ensNode);
        return permitSet && !executed && registryOwner != address(0);
    }
    
    // Get bid status
    function getStatus() external view returns (string memory) {
        if (executed) return "EXECUTED";
        if (permitSet) return "ACTIVE";
        return "PENDING_PERMIT";
    }
    
    // Get contract version
    function version() external pure returns (string memory) {
        return "PERMIT2_V1";
    }
}

Tags:
addr:0x16b3828d9b72f11ae26da2eb63f7fba6a9ba89dc|verified:true|block:23426150|tx:0x2b551fb9976d37d89e7bf9127e078eb6e9144696a810e03796654e7580dc73ce|first_check:1758724614

Submitted on: 2025-09-24 16:36:59

Comments

Log in to comment.

No comments yet.