본문 바로가기

TIL

TIL) ERC-20 토큰 배포 및 추가기능 구현(OwnerHelper, TokenLock)

#ERC-20이란?
- ethereum request for comment 20의 약자
- 이더리움 블록체인 네트워크에서 정한 표준 토큰 스펙
- 이더리움 네트워크의 개선안을 제안하는 EIPs(ethereum improvement proposals)에서 관리하는 공식 프로토콜
- 이더리움 블록체인을 활용하는 토큰은 ERC-20 기준을 맞춰야 함

#ERC vs EIP
- ERC는 기능 표준
- EIP는 개선 제안

 

#관리자 전용 함수 - OwnerHelper
abstract contract는 contract의 구현된 기능과 interface의 추상화 기능 모두를 포함.

-> 상속받은 자식객체에서 owner함수와 transferownership 함수 사용 + onlyOwner modifier 사용

// interface 부분 생략

abstract contract OwnerHelper {
  	address private _owner;

  	event OwnershipTransferred(address indexed preOwner, address indexed nextOwner);

  	modifier onlyOwner {
			require(msg.sender == _owner, "OwnerHelper: caller is not owner");
			_;
  	}
    
  	constructor() {
      _owner = msg.sender;
  	}

    function owner() public view virtual returns (address) {
      return _owner;
    }

  	function transferOwnership(address newOwner) onlyOwner public {
      require(newOwner != _owner);
      require(newOwner != address(0x0));
      address preOwner = _owner;
	    _owner = newOwner;
	    emit OwnershipTransferred(preOwner, newOwner);
  	}
}

 

#simpleToken - lock 관련

_transfer 함수

- 토큰이 lock되어 있는지 확인하고, false일 때 전송가능

 

isTokenLock 함수

- token lock이 해제되어 있는지 + sender와 recipient의 lock이 풀려있는지 확인

- 둘 다 만족해야 lock이 풀림

// (생략)

	function _transfer(address sender, address recipient, uint256 amount) internal virtual {
      require(sender != address(0), "ERC20: transfer from the zero address");
      require(recipient != address(0), "ERC20: transfer to the zero address");
      require(isTokenLock(sender, recipient) == false, "TokenLock: invalid token transfer");
      uint256 senderBalance = _balances[sender];
      require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
      _balances[sender] = senderBalance.sub(amount);
      _balances[recipient] = _balances[recipient].add(amount);
    }

    function isTokenLock(address from, address to) public view returns (bool lock) {
      lock = false;

      if(_tokenLock == true)
      {
           lock = true;
      }

      if(_personalTokenLock[from] == true || _personalTokenLock[to] == true) {
           lock = true;
      }
    }

    function tokenLock() onlyOwner public {
      require(_tokenLock == false);
      _tokenLock = true;
    }

    function removeTokenLock() onlyOwner public {
      require(_tokenLock == true);
      _tokenLock = false;
    }

    function removePersonalTokenLock(address _who) onlyOwner public {
      require(_personalTokenLock[_who] == true);
      _personalTokenLock[_who] = false;
    }

    
    function personalTokenLock(address _who) onlyOwner public {
      require(_personalTokenLock[_who] == false);
      _personalTokenLock[_who] = true;
    }

    function _approve(address owner, address spender, uint256 currentAmount, uint256 amount) internal virtual {
      require(owner != address(0), "ERC20: approve from the zero address");
      require(spender != address(0), "ERC20: approve to the zero address");
      require(currentAmount == _allowances[owner][spender], "ERC20: invalid currentAmount");
      _allowances[owner][spender] = amount; 
      emit Approval(owner, spender, currentAmount, amount);
    }
}

 

#simpleToken - 관리자 추가(코드참조: https://mybc.tistory.com/95)

// 관리자 추가
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;
}

// 투표하기
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);
        voteResult[voteforAddress]+=1;
        voteCount[sender]+=1;
        return true;
 }
 
 // 투표 결과확인
 function result() public view returns (uint8){
        return voteResult[msg.sender];
}

// 투표 결과로 owner 변경
function transferOwnership() onlyOwner public returns (bool) {

            if(voteResult[_owners[1]] > voteResult[_owners[2]]){
            require(_owners[1] != _owner);
            require(_owners[1] != address(0x0));
            address preOwner = _owner;
    	    _owner = _owners[1];
    	    emit OwnershipTransferred(preOwner, _owners[1]);
            }
            else if(voteResult[_owners[2]] > voteResult[_owners[0]]){
            require(_owners[2] != _owner);
            require(_owners[2] != address(0x0));
            address preOwner = _owner;
    	    _owner = _owners[2];
    	    emit OwnershipTransferred(preOwner, _owners[2]);
            }
    return true;
  }