FreeShare

Viết smart contract chương trình phiên đấu giá Nft bằng solidity

Chủ nhật, 18/02/2024
image
Code solidy Bạn có thể tham khảo code tại đây

Code solidy

// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC721/ERC721.sol";
import "openzeppelin-solidity/contracts/access/Ownable.sol";
import "openzeppelin-solidity/contracts/token/ERC20/utils/SafeERC20.sol";

contract Auction is Ownable {
    ERC20 public tokenAddres;
    ERC721 public nftAddress;

    struct AutionData {
        address owner;
        uint nftId;
        uint price;
        uint timeStamp;
        uint timeEnded;
        bool isAution;
        address winner;
        uint winnerPrice;
    }

    struct UserAution {
        address owner;
        uint nftId;
        uint price;
        uint timeStamp;
        bool isActive;
    }

    mapping(uint=> AutionData) public AutionLists;
    mapping(uint => UserAution[]) public AutionUsers;
    mapping(uint => mapping(address=>uint)) public ValueLastBid;
    mapping(address => UserAution[]) public MyAuctions;
    uint8 fee = 5; // 5%

    event CreateAution(address owner, uint nftId, uint price, uint timeStamp, uint timeEnded);
    event CreateBid(address owner, uint nftId, uint price , uint timeStamp);
    event FinishAution(uint nftId, address owner, address winner, uint winnerPrice, uint timestamp);

    constructor(ERC20 _token, ERC721 _nft){
        tokenAddres = _token;
        nftAddress = _nft;
    }

    function createAution(uint _nftId, uint _price, uint time) external {
        require(time > 0,  "Time aution must greater 0");
        require(_nftId >= 0,  "Id nft must greater 0");
        require(_price > 0,  "Price must greater 0");
        AutionData memory audata = AutionLists[_nftId];
        if(audata.isAution == true) revert("Aution is in active, please cancel aution previous");
        nftAddress.transferFrom(msg.sender, address(this), _nftId);
        AutionLists[_nftId] = AutionData(msg.sender, _nftId, _price, block.timestamp, block.timestamp + time, true, address(0), 0);
        emit CreateAution(msg.sender, _nftId, _price, block.timestamp, block.timestamp + time);
    }

    function userAutionBid(uint _nftId, uint _price) external {
        require(_nftId >= 0,  "Id nft must greater 0");
        AutionData memory audata = AutionLists[_nftId];
        if(audata.isAution == false) revert("Aution is inactive");
        if(audata.timeEnded < block.timestamp) revert("Aution is ended");
        UserAution[] memory bids = AutionUsers[_nftId];
        uint lastBid = audata.price;
        if(bids.length > 0) lastBid = bids[bids.length - 1].price;
        require(_price > lastBid, "Price must greater lastBid");

        uint calPrice = _caculatorPrice(_nftId);

        SafeERC20.safeTransferFrom(tokenAddres, msg.sender, address(this), _price - calPrice);
        UserAution memory _autionUser = UserAution(msg.sender, _nftId, _price, block.timestamp, true);
        AutionUsers[_nftId].push(_autionUser);
        ValueLastBid[_nftId][msg.sender] = _price - calPrice;
        MyAuctions[msg.sender].push(_autionUser);
        emit CreateBid(msg.sender, _nftId, _price , block.timestamp);
    }

    function _caculatorPrice(uint _nftId) private view returns (uint price) {
        UserAution[] memory bids = AutionUsers[_nftId];
        price = 0;
        for(uint i=0; i<bids.length; i++){
            if(bids[i].owner == msg.sender){
                price = bids[i].price;
            }
        }
    }

    function setEndedAution(uint _nftId) external {
        AutionData memory audata = AutionLists[_nftId];
        if(audata.timeEnded > block.timestamp) revert("Aution is aution");
        if(audata.isAution == false) revert("Aution is aution");
        address winner = address(0);
        UserAution[] memory bids = AutionUsers[_nftId];
        uint winnerPrice = 0;
        if(bids.length>0){
            winner = AutionUsers[_nftId][bids.length - 1].owner;
            AutionLists[_nftId].winner = winner;
            winnerPrice = AutionUsers[_nftId][bids.length - 1].price;
        }
        AutionLists[_nftId].isAution = false;
        AutionLists[_nftId].winnerPrice = winnerPrice;
        AutionLists[_nftId].timeEnded = 0;
        AutionLists[_nftId].timeStamp = 0;
        AutionLists[_nftId].price = 0;
        _caculatorReturnToken(_nftId, winner);
        _claimNft(_nftId);
        // delete history
        delete AutionUsers[_nftId];

        emit FinishAution(_nftId, audata.owner, winner, winnerPrice, block.timestamp);
    }

    function _caculatorReturnToken(uint _nftId, address _winner) private {
        UserAution[] memory bids = AutionUsers[_nftId];
        if(bids.length == 0) return;
        for(uint i = bids.length; i>0; i--){
            if(bids[i-1].owner != _winner && ValueLastBid[_nftId][bids[i-1].owner] == bids[i-1].price){
                SafeERC20.safeTransfer(tokenAddres, bids[i-1].owner, bids[i-1].price);
            }
        }
    }

    function _claimNft(uint _nftId) private {
        AutionData memory audata = AutionLists[_nftId];
        if(audata.winner != address(0) && audata.isAution == false){
            nftAddress.transferFrom(address(this), audata.winner, _nftId);
            AutionLists[_nftId].winner = address(0);
            AutionLists[_nftId].owner = audata.winner;
            SafeERC20.safeTransfer(tokenAddres, audata.owner, audata.winnerPrice * (100 - fee)/100);
        }
    }

    fallback () external {
        revert();
    }
}

Bạn có thể tham khảo code tại đây