iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 18
0
Blockchain

30天30個Smart contract 系列 第 18

Day17-BlindAuction

導言

此範例參考solidity example其中一個,為Auction合約的升級版,場景設定在不知展示的投標物價值為多少,每個參與者可以針對有興趣的投標物出價並將錢放進合約
當投標時間結束後才會開始依照每個參與者的投標價格來判定,誰出價最高並且最有機會得標,其中出價低於標準,會將錢退還給參與者

Blind Auction reference

程式碼

pragma solidity^0.4.25;
contract BlindAuction{
    
    struct Bid{
        bytes32 bidHash;
        uint deposit;
    }
    
    address public beneficiary; // 受益人
    uint public biddingEndTime; // 投標結束時間
    uint public revealEndTime; // 展示結束時間
    bool public ended; //合約結束狀態
    
    address public highestBidder; //最高出價者
    uint public highestBid; //最高出價
    
    mapping (address => Bid[]) bids; //參與者投標多個項目
    mapping (address => uint ) pendingReturn; // record all bid of bidder
    
    event AuctionEnd(address winner,uint highestBid);
    
    modifier onlyBefore(uint _time){ require(now < _time); _;}
    modifier onlyAfter(uint _time){ require(now > _time); _;}
    
    //參數輸入受益人、投標時間、展示時間
    constructor(     
        address _beneficiary,
        uint _biddingTime,
        uint _revealTime
        
    ) public {
        
        beneficiary =_beneficiary;
        biddingEndTime = now + _biddingTime;
        revealEndTime = biddingEndTime + _revealTime;
        
    }
    
    //投標出價的function,參與者要在投標結束時間前執行
    //bidHash  = keccak256(abi.encodePacked(value,fake,key));
    function bid(
        bytes32 _bidHash 
    ) 
        public 
        payable 
        onlyBefore(biddingEndTime)
    {
        bids[msg.sender].push(
            Bid(
                _bidHash,
                msg.value
            )
        );
    }
    
    //輸入展示項目的資料,只限定在投標時間後,展示時間前可以呼叫function
    //將目前展示的所有項目和參與者投標的項目做比對,出價沒有符合標準會退錢給參與者,出價最高將會做好紀錄
    function reveal(
        uint[] _value,
        bool[] _fake,
        bytes32[] _secret
    
    ) 
        public
        onlyAfter(biddingEndTime) 
        onlyBefore(revealEndTime)
    {
        // 計算msg.sender投標多少個項目
        uint length = bids[msg.sender].length;
        
        
        uint refund;
        
        //判斷展示的數量和msg.sender投標的數量相符合
        require(_value.length == length,"value length isn't match");
        require(_fake.length == length,"fake length isn't match");
        require(_secret.length == length,"secret length isn't match");
        
        
        
        for(uint8 i = 0; i < length ; i++){
            
            Bid storage bid_ = bids[msg.sender][i]; 
            
            (uint value, bool fake, bytes32 secret) = (_value[i],_fake[i],_secret[i]);
            
            //確認第i個投標項目的hash是不是和展示項目的hash一致
            if(bid_.bidHash == keccak256(abi.encodePacked(value,fake,secret))){
              continue;  
            }
            //增加msg.sender退錢額度
            refund += bid_.deposit;
            
            //確認fake為false 或是出價高於本身價值
            if(!fake && bid_.deposit >= value){

                //如果為true代表為最高出價
                if(placeBid(msg.sender,value)){

                    /
                    refund -= value;
                }
                //將賣家投標的項目hash清除,表示已經執行過
                bid_.bidHash = bytes32(0);
            }
            //將投標項目沒有達到標準的出價退錢給參與者
            msg.sender.transfer(refund);
        }
             
    }
    
    
    function placeBid(address _bidder,uint _value) internal returns(bool success){
        
        // 確認投標的出價大於目前最高出價
        if(_value <= highestBid){
            return false;
        }
        
        // 確認目前最高投標者address是否為有效address
        if(highestBidder != 0){
           //因為有更高出價的投標者, 所以會退錢給目前最高投標者
           pendingReturn[highestBidder] += highestBid;
        }
        
        //設定最新的出價及投標者
        highestBid = _value;
        highestBidder = _bidder;
        return true;
    }
    
    //提款
    function withdraw() public {
        uint amount = pendingReturn[msg.sender];
        //確認msg.sender 的pending有無超過0
        if(amount > 0 ){
            
            //初始化pending return 的 value
            pendingReturn[msg.sender] = 0;
            
            msg.sender.transfer(amount);
        }
    }
    
    //拍賣結束受益人拿回價格,只能在拍賣時間結束、合約狀態還沒終止後執行
    function auctionEnded() public onlyAfter(revealEndTime){
        //確認拍賣合約狀態
        require(!ended);
        //teigger event to log winner address and highestBid
        emit AuctionEnd(highestBidder,highestBid);
        ended = true;
        beneficiary.transfer(highestBid);
    }
}

解說

(待補)


上一篇
Day16-ERC721
下一篇
Day18-Decentralize Exchange (1/2)
系列文
30天30個Smart contract 20
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言