본문으로 바로가기

[이더리움] 로또 프로젝트

category BlockChain 2021. 1. 21. 22:10
개발 개요
스마트 계약을 통하여 공정성 있는 로또 배팅 프로그램을 구축하여 사용자에게 조작이라는 의심 없이 운영할 수 있다.
MetaMaskRopsten의 테스트 환경에서 프로젝트를 진행하였다.
프로그램의 코드는 Solidty로 작성되었다.
실제의 환경에서 사용된다면 사용자 입금을 하여 입금한 금액 만큼 배팅을 하여 로또 당첨이 되었을 경우 사용자들이 투자한 금액들을 취득할 수 있다. 이러한 프로그램의 응용은 추첨이나 다양한 경품응모에서도 사용된다면 사용자에게 높은 공정성을 제공하여 사용자의 만족감을 얻을 수 있다.
로또 프로젝트의 목표는 Solidty 코드에 대한 이해와 테스트넷 환경에서의 송금 방법에 대한 것들을 이용하였다.

 

소스 구동흐름
서버 측에서 로또 서버를 열어, 클라이언트들의 접속을 기다림.
서버에서 한 회차의 로또 이용 시간을 제한하여 회차마다 진행할 수 있도록 함.
클라이언트 사용자들이 로또 서버에 접속함.
사용자가 가지고 있는 일정한 금액과 원하는 로또 번호를 입력하여 배팅함.
화폐단위는 finney를 사용하여 1000 finney = 1 Ethereum
Case 1
사용자의 로또 번호와 로또 서버에 저장된 숫자가 일치하지 않을 경우
사용자가 배팅한 금액을 계약에 있는 속성에 배팅한 금액 만큼 쌓인다.

Case 2
사용자의 로또 번호와 로또 서버에 저장된 숫자가 일치할 경우
서버의 계약 속성의 쌓인 배팅한 금액들을 전송한다.

pragma solidity >=0.4.22 <0.7.0;

contract Lotto {
    address payable public organizer;
    address payable public winner;
    uint public lottoEndTime;  
    uint8 public randomNumber;  

    bool ended;

    event AnswerCorrected(address winner, uint8 selectedNumber, uint winnings);
    event LottoEnded(address winner, uint winnings);

    constructor(uint _lottoEndTime) public { 
        require(_lottoEndTime >= 30, "제한시간은 30초 이상 입력해주세요."); 
        organizer = msg.sender; 
        lottoEndTime = now + _lottoEndTime;  
        randomNumber = random();   
    }
    
    function random() private view returns (uint8) {
        return uint8(uint256(keccak256(abi.encodePacked(block.timestamp, block.difficulty))) % 10 + 1);
    }  

    function lotto(uint8 _selectedNumber) public payable {
        require(now <= lottoEndTime, "로또는 이미 끝났습니다.");
        require(msg.value > 0, "0원 이하를 걸 수는 없습니다.");
        require(winner == address(0), "당첨자가 이미 결정되었습니다.");
        // lotto 버튼누를 시의 조건문들
        if (_selectedNumber == randomNumber) {
            winner = msg.sender;
            emit AnswerCorrected(winner, _selectedNumber, address(this).balance);
        }
    }
    
    modifier onlyOrganizer() {
        require(msg.sender == organizer);
        _;
    }

    function lottoEnd() public onlyOrganizer {
        require(now >= lottoEndTime, "로또는 아직 끝나지 않았습니다.");
        require(!ended, "lottoEnd는 이미 호출된 적이 있습니다.");

        ended = true;
        emit LottoEnded(winner, address(this).balance);
        
        if (winner != address(0)) {
            winner.transfer(address(this).balance);
        } else {
            organizer.transfer(address(this).balance);
        }
    }
}
소스 설명

pragma solidity >=0.4.22 <0.7.0;

solidity의 버전을 결정해준다.

 

address payable public organizer;

address payable public winner;

uint public lottoEndTime;

uint8 public randomNumber;

bool ended;

lottoEndTime : 로또 한 회차의 종료 시간이 설정되는 변수

randomNumber : 로또 한 회차의 로또 당첨번호가 저장되는 변수

 

constructor(uint _lottoEndTime) public

로또 한 회차의 경매 지속 30초 이상이라는 조건을 걸고, 종료 시간은 현재시간에 마감시간을 더해서 끝나는 시간을 정한다.

한 회차의 로또 번호의 정답을 Random 함수로 정하게 된다.

 

function lotto(uint8 _selectedNumber) public payable 함수

배팅할 수 있는 조건문들에 대해서 정리해둔 함수이다.

당첨자가 이미 결정 되었는데 배팅할 경우의 예외처리

로또의 한 회차가 끝났는데 배팅할 경우의 예외처리

최소 금액 0원 이상을 걸지 않았을 경우의 예외처리