ERC-20 토큰은 이더리움 블록체인 네트워크에서 대체 가능한 토큰을 발행하는 기술 표준입니다. 이더(ETH)와 교환가능하며, 이더리움 블록체인 위에서 발행된 토큰들과 SWAP이 가능한 토큰을 발행하기 위해서는 ERC-20 표준을 지켜서 토큰을 발행해야 합니다.
토큰을 발행하는 ERC-20에는 관리자 계정이 존재합니다. 관리자는 자신의 권한을 다른 사용자에게 넘길 수 있고, 계정의 Lock 을 잠그거나 해제할 수도 있습니다. 1명의 관리자에 의해 관리자 권한이 관리될 수 있지만 좀 더 민주적인 방법인 투표를 통해 관리자 권한을 관리할 수 있습니다.
① 총 3명의 사용자가 관리자 후보로 등록됩니다. 이 때 관리자 후보로 등록하는 권한은 현재 관리자만이 할 수 있습니다.
② 총 3명의 관리자가 투표하고 가장 많은 투표를 받은 후보자가 관리자로 선임됩니다.
③ 투표는 1번만 가능하며, 자기 자신에게 투표는 금지됩니다. 투표수가 동일하거나 0명의 후보자가 나오는 경우 기존 관리자가 연임합니다.
관리자 추가 구현
ⓐ 추상 계약인 OwnerHelper 생성자 함수를 수정합니다. 상태 변수로 _owners(address 형 동적 배열), voteCount(mapping), voteResult(mapping)를 선언합니다.
address public _owner;
address[3] private _owners;
mapping(address=>uint8) private voteCount;
mapping(address=>uint8) private voteResult;
ⓑ 생성자 함수에는 기존 관리자를 0번 후보자로 등록합니다. 0번 후보자의 voteCount와 voteResult를 초기화합니다.
constructor() {
_owner = msg.sender;
_owners[0] = msg.sender;
voteCount[msg.sender] = 0;
voteResult[msg.sender] = 0;
}
ⓒ 후보자를 추가하는 함수를 선언합니다. 인자로는 후보자 번호와 후보자 계정 주소를 받습니다. 현재 관리자만 사용할 수 있는 함수이며, 후보자 번호는 0~2번 사이값을 가지게 됩니다. voteCount, voteResult는 0으로 초기화됩니다.
function addOwner(uint8 _ownerNumber, address _newOwner) onlyOwner public returns(bool){
require(_ownerNumber > 0 && _ownerNumber < 3);
_owners[_ownerNumber] = _newOwner;
voteCount[_newOwner] = 0;
voteResult [_newOwner] = 0;
return true;
}
ⓓ 등록한 후보자를 대상으로 투표를 진행합니다. voteForOwner 내부에서는 내부함수 _voteForOwner()함수를 실행합니다. 투표를 받은 후보자는 등록된 후보여야 하며, 계정당 1번의 투표만 가능합니다. 또한 자기 자신에게 투표는 금지됩니다.
투표가 종료되면 해당 후보자가 얻은 투표수(voteResult)는 1씩 증가하며, 유권자의 투표가능 횟수는 1이 올라가면서추가로 투표가 불가능해집니다.
function voteForOwner(address _voteForAddress) public virtual returns(bool){
_voteForOwner(msg.sender, _voteForAddress);
return true;
}
function _voteForOwner(address sender, address voteForAddress) internal virtual returns(bool){
require(_owners[0] == sender || _owners[1] == sender || _owners[2] == sender);
require(voteCount[sender] == 0);
require(sender != voteForAddress);
voteResult[voteForAddress] += 1;
voteCount[sender] += 1;
return true;
}
ⓔ 투표 결과를 확인하는 함수 result() 를 선언합니다. 스토리지를 건드리지 않고, 단순히 조회만 하므로 view 속성을 사용합니다.
function result() public view returns(uint8) {
return voteResult[msg.sender];
}
ⓕ 투표 결과를 바탕으로 실제 관리자 권한을 위임하는 transferOwnershipByVote() 함수를 선언합니다. 후보자 중 가장 많은 득표를 한 후보자가 maxCandidates가 되며, 관리자 권한을 받은 후 OwnershipTransferred 이벤트가 실행됩니다.
function transferOwnershipByVote() onlyOwner public returns(bool){
uint8 max = 0;
address maxCandidates;
for(uint8 i=0; i<_owners.length; i++){
if(voteResult[_owners[i]] > max){
max = voteResult[_owners[i]];
maxCandidates = _owners[i];
}
}
require(maxCandidates != _owner);
require(maxCandidates != address(0x0));
address preOwner = _owner;
_owner = maxCandidates;
emit OwnershipTransferred(preOwner, maxCandidates);
return true;
}
작동 영상
재사용 가능 Lock 구현
관리자는 전송 계정과 수신 계정에 대해 Lock 상태를 관리할 수 있습니다. 최초 Lock 걸려 있고, Lock 을 제거해야만 토큰 전송이 가능한 구조입니다.
Lock을 재사용 하기 위해서는 Lock을 추가하는 함수를 구현해야 합니다. 기본 로직은 RemoveLock과 동일합니다. require문을 활용해서 현재 해당 계정 Lock이 걸려 있지 않으면 다시 Lock을 걸어줍니다.
function addTokenLock() onlyOwner public{
require(_tokenLock == false);
_tokenLock = true;
}
function addPersonalTokenLock(address _who) onlyOwner public{
require(_personalTokenLock[_who] == false);
_personalTokenLock[_who] = true;
}
Reference
'Blockchain' 카테고리의 다른 글
[Blockchain] ERC-721 vs ERC-20 차이점 (NFT vs FT) (0) | 2022.07.19 |
---|---|
[Blockchain] KIP-7 vs ERC-20 차이점? (0) | 2022.07.18 |
[Blockchain] Truffle(트러플) 프레임워크 사용법(개발 배포 테스트) (0) | 2022.07.15 |
[Blockchain] 가나슈(Ganache) 로컬 테스트 환경 구축하기(설치방법 사용법 메타마스크 연동) (0) | 2022.07.15 |
[Blockchain] 이더리움 토큰 발행하기 (ERC-20 라이브러리 사용) (0) | 2022.07.14 |
댓글