경매

suhan cho·2022년 5월 24일
0
post-custom-banner

Blind Auction

  • 하나의 작품을 경매로 판매
  • 경매 단계(init, bidding, reveal, done)
  • beneficiary가 경매를 시작하고 bidding단계 동안 입찰 진행
  • 입찰은 보안이 보장되고, private하게 진행
    • beneficiary제외하고 입찰의 내용 확인 불가
  • beneficiary가 경매를 reveal 단계로 변경하면 입찰자의 입찰 내역 공개
    가장 높은 가격을 제시한 입찰자와 입찰가격을 찾음
  • beneficiary는 done으로 단계 변경 경매 종료
  • beneficiary는 어카운트로 최고 입찰가 전송
  • 낙찰된 입찰자를 제외한 나머지는 입찰자는 자시느이 예치금 출금 가능
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract BlindAuction {
    struct Bid {    //입찰정보
        bytes32 blindedBid;
        uint deposit;
    }
    // beneficiary에 의해 설정됨
    enum Phase {Init, Bidding, Reveal, Done}
    Phase public currentPhase = Phase.Init;

    // Owner
    address payable public beneficiary; //contract 배포자
    mapping(address => Bid) public bids; //주소당 오직 1회 입찰

    // 최고가 입찰자의 정보
    address public highestBidder;
    uint public highestBid = 0;
   
    //낙찰 탈락자의 예치금 반환
    mapping(address => uint) pendingReturns;

   // 수정자
    modifier validPhase(Phase phase) { //경매단계를 위한 수정자
        require(currentPhase == phase, "phaseError");
        _;
    }
    modifier onlyBeneficiary() { //수혜자를 확인하는 수정자
        require(msg.sender == beneficiary, "onlyBeneficiary");
        _;
    }

    // Events
    event AuctionEnded(address winner, uint highestBid);
    event BiddingStarted();
    event RevealStarted();
    event AuctionInit();
    
    

constructor() public { //constructor가  beneficiary를 설정
        beneficiary = payable(msg.sender);
        // advancePhase();
    }

    function advancePhase() public onlyBeneficiary {
        // If already in done phase, reset to init phase
        if (currentPhase == Phase.Done) {
            currentPhase = Phase.Init;
        } else {
            // else, increment the phase
            // Conversion to uint needed as enums are internally uints
            uint nextPhase = uint(currentPhase) + 1;
            currentPhase = Phase(nextPhase);
        }
        // Emit appropriate events for the new phase
        if (currentPhase == Phase.Reveal) emit RevealStarted();
        if (currentPhase == Phase.Bidding) emit BiddingStarted();
        if (currentPhase == Phase.Init) emit AuctionInit();
    }
    function bid(bytes32 blindBid) public payable validPhase(Phase.Bidding) { //블라인드 경매 함수
        require(msg.sender != beneficiary,'beneficiaryBid');    // Beneficiary should not be allowed to place bids
        bids[msg.sender] = Bid({blindedBid: blindBid, deposit: msg.value});
    }

    function reveal(uint value, bytes32 secret) public validPhase(Phase.Reveal) { //입찰가격이 최고가인지 확인
        require(msg.sender != beneficiary,'beneficiaryReveal');                   //입찰자의 입찰가와 시크릿 패스워드 공개
        uint refund = 0;
        Bid storage bidToCheck = bids[msg.sender];
        if (bidToCheck.blindedBid == keccak256(abi.encodePacked(value, secret))) {
            refund += bidToCheck.deposit;
            if (bidToCheck.deposit >= value*1000000000000000000) {
                if (placeBid(msg.sender, value*1000000000000000000))
                    refund -= value * 1000000000000000000;
            }
        }
        payable(msg.sender).transfer(refund);
    }

    // This is an "internal" function which means that it
    // can only be called from the contract itself (or from
    // derived contracts).
    function placeBid(address bidder, uint value) internal returns (bool success)
    {
        if (value <= highestBid) {
            return false;
        }
        if (highestBidder != address(0)) {
            // 이전 최고가 입찰자에게 환불
            pendingReturns[highestBidder] += highestBid;
        }
        highestBid = value;
        highestBidder = bidder;
        return true;
    }

    // 낙찰 탈락 입찰 출금
    // withdraw()는 낙찰 탈락자에 의해 호출
    function withdraw() public {
        uint amount = pendingReturns[msg.sender];
        if (amount > 0) {
            pendingReturns[msg.sender] = 0;
            payable(msg.sender).transfer(amount);
        }
    }

    // 경매를 종료하고 수혜자에게 최고가 입찰액을 전송
    //done단계에서 호출된다
    function auctionEnd() public validPhase(Phase.Done) {
        if(address(this).balance >= highestBid){
            beneficiary.transfer(highestBid);
        }
        emit AuctionEnded(highestBidder, highestBid);
    }
    function closeAuction() public onlyBeneficiary {
        selfdestruct(beneficiary);
    }
}
profile
안녕하세요
post-custom-banner

0개의 댓글