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";
}
}
Submitted on: 2025-09-24 16:36:59
Comments
Log in to comment.
No comments yet.