Skip to content

Instantly share code, notes, and snippets.

@anxiubin
Created February 4, 2022 16:09
Show Gist options
  • Save anxiubin/e133245ea4e904b871eb968556fbf674 to your computer and use it in GitHub Desktop.
Save anxiubin/e133245ea4e904b871eb968556fbf674 to your computer and use it in GitHub Desktop.

1. NFT Contract

  • KIP17 NFT 기반
  • mint
    • 지정 주소에 토큰을 발행
    • tokenURI에 메타데이터가 담긴 IPFS 링크 주소를 작성
      • NFT 메타데이터 : 상호명, 메뉴이름, 인증날짜, 업로드 위치, 이미지 url 등
  • mintMasterBadge
    • 같은 address에 20개 NFT가 쌓였을 때, badgeContract에 마스터 배지 NFT를 mint하는 메소드 호출

2. Master Badge Contract

  • KIP17 NFT 기반
  • mint
    • 지정 주소에 토큰을 발행
    • tokenURI에 메타데이터가 담긴 IPFS 링크 주소를 작성
      • NFT 메타데이터 : 상호명, 메뉴이름, 인증날짜, 업로드 위치, 캐릭터 이미지 url, 마스터 배지 상세 설명, attribution 등

3. Vote Contract

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

contract Ballot {

	struct Proposal {
		string name;   // 메뉴 이름
		uint voteCount; // 투표 받은 수
		string imageUrl; // 메뉴 이미지 url
		address proposer; // 메뉴 제안자

	}
	struct Voter {
		bool voted;  // 투표 진행 여부 (true,false)
		uint vote;   // Menu 리스트 요소의 index (0,1,2 ...)
		uint weight; // 투표 권한

	}
	
	address public deployer; // 컨트랙트 배포자
	
	mapping(address => Voter) public voters; // 투표자 매핑

	address[] public voterList; // 투표자 리스트
	
	Proposal[] public proposals; // 메뉴 리스트

	Proposal[] public winnerProposals; // 투표로 채택된 메뉴 리스트

	constructor() {
		deployer = msg.sender;
	}


	// 메뉴 추가 함수
	function proposeMenu(string memory name, string memory imageUrl) public {
		/** 🔥 pseudocode 추가
		 	[require] msg.sender == 뱃지밀 마스터 NFT 소유자, "메뉴 추가 제안 권한이 없습니다."
		*/

		proposals.push(Proposal({
			name: name,
			voteCount: 0,
			imageUrl: imageUrl,
			proposer: msg.sender
		}));
	}

	// 투표자 리스트 추가 함수
	function addVoters(address[] memory addressList) public {
			require(
					msg.sender == deployer,
					"Only deployer can give right to vote."
			);
			require(
					voterList.length == 0,
					"Already added Voters."
			);

			/** 🔥 수정 필요
				addressList를 입력값으로 받는 것이 아니라 NFT 홀더 리스트를 가져오는 함수를 호출한 후 아래 로직을 실행하는게 좋을 것 같다.
			*/
			
			for (uint i = 0; i < addressList.length; i++) {
					voterList.push(addressList[i]);
			}
	}
    
	// 투표 권한 부여 함수
	function giveRightToVote(address voter) private {
			require(
					msg.sender == deployer,
					"Only deployer can give right to vote."
			);
			require(
					!voters[voter].voted,
					"The voter already voted."
			);
			require(voters[voter].weight == 0);
			voters[voter].weight = 1;
	}

	// 투표자 리스트 모두에게 권한 부여
    function giveVotersRightToVote() public {
        for (uint i = 0; i < voterList.length; i++) {
            giveRightToVote(voterList[i]);
        }
    }


	// 투표 함수
	function vote(uint proposal) public {
		Voter storage sender = voters[msg.sender];

		/** 🔥 pseudocode 추가
		 	[require] msg.sender == 뱃지밀 일반 NFT 소유자, "투표 권한이 없습니다."
		*/
		require(sender.weight != 0, "Has no right to vote");
		require(!sender.voted, "Already voted.");

		sender.voted = true;
		sender.vote = proposal;

		proposals[proposal].voteCount += sender.weight;
	}

	// 가장 많은 득표수를 얻은 메뉴 index 출력하는 함수
	function winningProposal() public view returns (uint winningProposal_) {
			uint winningVoteCount = 0;
			for (uint p = 0; p < proposals.length; p++) {
					if (proposals[p].voteCount > winningVoteCount) {
							winningVoteCount = proposals[p].voteCount;
							winningProposal_ = p;
					}
			}
	}

	// 가장 많은 득표수를 얻은 메뉴 이름을 리턴하는 함수
	function winnerName() public view returns (string memory winnerName_) {
			winnerName_ = proposals[winningProposal()].name;
	}

	/** 🔥 pseudocode 추가
		function 투표 마감
		1. 투표 시간이 마감되면 가장 많은 득표수를 얻은 메뉴 Proposal을 winnerProposals 에 push 한다.
		2. Proposals를 초기화한다.
	*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment