문제 풀기 솔리디티 코드

Lumi·2021년 12월 8일
0
post-thumbnail

이 코드는 인프런 강의 자료를 통해서 작성을 하였습니다.

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.4.24;

contract CoinToFlip {

    uint constant MAX_CASE = 2;
    uint constant MIN_BET = 0.01 ether;
    uint constant MAX_BET = 10 ether;
    uint constant HOUSE_FEE_PERCENT = 5;
    uint constant HOUSE_MIN_FEE = 0.005 ether;

    address public owner;
    uint public lockedInBets;

    struct Bet {
        uint amount;
        uint8 numOfBetBit;
        uint placeBlockNumber;
        uint8 mask;
        address gambler;
    }

    mapping (address => Bet) bets;

    event Reveal(uint reveal);
    event Payment(address indexed beneficiary, uint amount);
    event FailedPayment(address indexed beneficiary, uint amount);

    constructor () public {
        owner = msg.sender;
    }

    modifier onlyOwner {
        require(msg.sender == owner, "오너만 실행 가능합니다.");
        _;
    }

    // 이더를 인출하는 함수
    function withdrawFunds(address beneficiary, uint withdrawAmount) external onlyOwner {
        require(withdrawAmount + lockedInBets <= address(this).balance, "금액보다 많습니다.");
        sendFunds(beneficiary, withdrawAmount);
    }

    // 금액 이동이 발생할떄 발생하는 함수
    function sendFunds(address beneficiary, uint amount) private {
        if(beneficiary.send(amount)){
            emit Payment(beneficiary, amount);
        } else{
            emit FailedPayment(beneficiary, amount);
        }
    }

    // 현재 진행중이 게임이 없을경우에만 가능
    function kill() external onlyOwner {
        require(lockedInBets == 0, "맡겨둔 금액이 있습니다.");
        selfdestruct(owner);
    }

    function () public payable{}

    // 금액을 배팅하는 함수
    function placeBet(uint8 betMask) external payable{
        uint amount = msg.value;

    require(amount >= MIN_BET && amount <= MAX_BET, "정해진 범위에서만 배팅 가능합니다.");
    require(betMask > 0 && betMask < 256, "배팅 가능한 금액이 정해져 있습니다.");

    Bet storage bet = bets[msg.sender];

    // null인지 체크하는 부분
    require (bet.gambler == address(0),"계좌 오류");
    

    uint8 numOfBetBit = countBits(betMask);

    bet.amount = amount;
    bet.numOfBetBit = numOfBetBit;
    bet.placeBlockNumber = block.number;
    bet.mask = betMask;
    bet.gambler = msg.sender;

    uint possibleWinningAmount = getWinningAmount(amount, numOfBetBit);

    lockedInBets += possibleWinningAmount;

    require(lockedInBets < address(this).balance, "배팅된 금액보다 큽니다.");
    }

    function getWinningAmount(uint amount, uint8 numOfBetBit) private pure returns (uint winningAmount) {
        require (0 < numOfBetBit && numOfBetBit <MAX_CASE);

        uint houseFee = amount * HOUSE_FEE_PERCENT / 100;

        if(houseFee < HOUSE_MIN_FEE){
            houseFee = HOUSE_MIN_FEE;
        }

        uint reward = amount / (MAX_CASE + (numOfBetBit - 1));

        winningAmount = (amount - houseFee) + reward;
    }

    function revealResult(uint8 seed) external {
        Bet storage bet = bets[msg.sender];
        uint amount = bet.amount;
        uint8 numOfBetBit = bet.numOfBetBit;
        uint placeBlockNumber = bet.placeBlockNumber;
        address gambler = bet.gambler;

        require(amount>0);

        require(block.number > placeBlockNumber);

        //난수ㅡㄹ 생성
        bytes32 random = keccak256(abi.encodePacked(blockhash(block.number-seed), blockhash(placeBlockNumber)));
 
        uint reveal = uint(random) % MAX_CASE;

        uint winningAmount = 0;
        uint possibleWinningAmount = 0;
        possibleWinningAmount = getWinningAmount(amount, numOfBetBit);

        if((2**reveal) & bet.mask != 0){
            winningAmount = possibleWinningAmount;
        }

        emit Reveal(2**reveal);

        if(winningAmount>0){
            sendFunds(gambler, winningAmount);
        }

        lockedInBets -= possibleWinningAmount;
        clearBet(msg.sender);
    }

    function clearBet(address player) private{
        Bet storage bet = bets[player];

        if(bet.amount >0 ){
            return;
        }

        bet.amount = 0;
        bet.numOfBetBit = 0;
        bet.placeBlockNumber = 0;
        bet.mask = 0;
        bet.gambler = address(0);
    
    }

    function refundbet() external {
        require(block.number > bet.placeBlockNumber);

        Bet storage bet = bets[msg.sender];
        uint amount = bet.amount;

        require (amount > 0);

        uint8 numOfBetBit = bet.numOfBetBit;

        sendFunds(bet.gambler, amount);

        uint possibleWinningAmount;
        possibleWinningAmount = getWinningAmount(amount, numOfBetBit);

        lockedInBets-= possibleWinningAmount;
        clearBet(msg.sender);
    }

    function checkHouseFund() public view onlyOwner returns(uint){
        return address(this).balance;
    }

    function countBits(uint8 _num) internal pure returns (uint8) {
        uint8 count;
        while(_num >0){
            count+= _num & 1;
            _num >>= 1;
        }
        return count;
    }



}
profile
[기술 블로그가 아닌 하루하루 기록용 블로그]

0개의 댓글