You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ERC721代币拍卖后转入获胜者钱包的合约开发架构咨询

Hey there, let's work through your ERC721 auction contract architecture—you’ve already got a solid start with splitting things into Wallet, AuctionFactory, and Auction contracts, so let’s flesh out the missing parts and refine what you’ve got so far.

ERC721 Auction System Architecture Breakdown

1. Refining the WALLET Contract

First, let’s clarify the purpose here: since standard ERC721 tokens already track ownership via ownerOf(), a standalone "address to tokens held" mapping might be redundant unless you’re building a custom managed wallet layer (for users to hold assets and interact exclusively with your auction system). If that’s your goal, here’s how to refine it:

  • Core State & Logic:
    • Use a nested mapping: mapping(address => mapping(uint256 => bool)) public tokenOwned; to track which tokens a user holds in this wallet (remember, the ERC721 contract is still the source of truth for on-chain ownership).
    • Add a transferIntoWallet(address _erc721, uint256 _tokenId) function that lets users transfer their ERC721 tokens into this wallet. This should call safeTransferFrom on the target ERC721 contract and update your tokenOwned mapping.
    • Store the AuctionFactory address as an immutable variable during deployment—this ensures your wallet only interacts with trusted auction contracts spawned by your factory.

2. AUCTIONFACTORY Contract Design

Your factory’s job is to spawn and track auction contracts for specific ERC721 tokens. Here’s a robust structure:

  • State Variables:

    • mapping(address => address[]) public auctionsForToken;: Tracks all auction contracts created for a given ERC721 token address (great for frontend UIs to list all active auctions for a collection).
    • An event AuctionCreated(address indexed auctionContract, address indexed erc721Token, uint256 tokenId): Emitted every time a new auction is deployed to help with off-chain tracking and notifications.
  • Core Functions:

    • createAuction(address _erc721, uint256 _tokenId, uint256 _startingBid, uint256 _auctionDuration):
      • Deploys a new Auction contract, passing in all required parameters.
      • Add a check to ensure the caller (seller) either owns the token or has approved the factory/auction contract to transfer it—otherwise the auction can’t take custody of the NFT.
    • Optional: getAuctionsForToken(address _erc721) external view returns(address[]): Returns all auction addresses for a specific ERC721 contract to simplify UI integration.

3. AUCTION Contract (The Core Auction Logic)

This is where all the auction mechanics live—let’s build out the key components step by step:

State Variables

address public immutable erc721Token; // The ERC721 contract of the NFT being auctioned
uint256 public immutable tokenId;
address public seller;
uint256 public startingBid;
uint256 public auctionEndTime;
address public highestBidder;
uint256 public highestBid;
mapping(address => uint256) public pendingReturns; // Tracks bids that need to be refunded
bool public auctionEnded;

Core Functions

Constructor

When deployed by the factory, the constructor initializes state and takes custody of the NFT (make sure the seller has approved the auction contract beforehand):

constructor(
    address _erc721,
    uint256 _tokenId,
    address _seller,
    uint256 _startingBid,
    uint256 _duration
) {
    erc721Token = _erc721;
    tokenId = _tokenId;
    seller = _seller;
    startingBid = _startingBid;
    auctionEndTime = block.timestamp + _duration;

    // Transfer NFT to auction contract (ensure seller approved this contract)
    IERC721(_erc721).safeTransferFrom(_seller, address(this), _tokenId);
}

Place Bid

Allows users to place bids with critical checks:

function placeBid() external payable {
    require(!auctionEnded, "Auction already concluded");
    require(block.timestamp < auctionEndTime, "Auction hasn't ended yet");
    require(msg.value > highestBid, "Bid must exceed current highest bid");
    require(msg.sender != seller, "Seller cannot bid on their own auction");

    // Refund the previous highest bidder
    if (highestBidder != address(0)) {
        pendingReturns[highestBidder] += highestBid;
    }

    highestBidder = msg.sender;
    highestBid = msg.value;
}

End Auction

Can be called by anyone once the auction time elapses—handles NFT and fund distribution:

function endAuction() external {
    require(block.timestamp >= auctionEndTime, "Auction hasn't ended yet");
    require(!auctionEnded, "Auction already concluded");

    auctionEnded = true;

    if (highestBidder != address(0)) {
        // Transfer NFT to the winning bidder
        IERC721(erc721Token).safeTransferFrom(address(this), highestBidder, tokenId);
        // Send auction proceeds to the seller
        payable(seller).transfer(highestBid);
    } else {
        // No bids placed: return NFT to the seller
        IERC721(erc721Token).safeTransferFrom(address(this), seller, tokenId);
    }
}

Withdraw Refunds

Lets users claim their refunded bids:

function withdrawRefund() external {
    uint256 refundAmount = pendingReturns[msg.sender];
    require(refundAmount > 0, "No refund available for your address");

    pendingReturns[msg.sender] = 0;
    payable(msg.sender).transfer(refundAmount);
}

Key Safety & Optimization Tips

  • Reentrancy Protection: We use the Checks-Effects-Interactions pattern (updating pendingReturns before transferring funds) to prevent reentrancy attacks.
  • Time Manipulation: Block timestamps can be slightly adjusted by miners—avoid relying on ultra-precise timing for critical logic.
  • Gas Efficiency: Deploying a new Auction contract per NFT is straightforward but gas-heavy. If you want to optimize, consider a single Auction contract that handles multiple NFTs (this adds complexity but reduces deployment costs).
  • Access Control: If needed, add access control to the factory (e.g., only verified sellers can create auctions) using a library like OpenZeppelin’s Ownable or AccessControl.

内容的提问来源于stack exchange,提问作者Mark Romano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:06:26