본문 바로가기
솔리디티

솔리디티 OwnerHelper, TokenLock

by gun_poo 2022. 2. 4.

OwnerHelper

관리자만 사용할 수 있는 함수가 필요
특정 함수를 관리자만 사용할 수 있도록 설정하는 OwnerHelper 함수를 구현
OwnerHelper를 사용하여 public으로 공개되어 있는 함수 중, 관리자만 접근 가능한 함수 구현

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);
  	}

OwnerHelper 컨트랙트는 abstract contract라고 하는 추상 컨트랙트이다

abstract contract는 contract의 구현된 기능과 interface의 추상화 기능 모두를 포함한다
abstract contract는 만약 실제 contract에서 사용하지 않는다면 추상으로 표시되어 사용되지 않는다

_owner는 관리자를 나타낸다.

address private _owner;

OwnershipTransferred이벤트는 관리자가 변경되었을때 이전 관리자의 주소와 새로운 관리자의 주소 로그를 남긴다

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

onlyOwner 함수 변경자는 함수 실행 이전에 함수를 실행시키는 사람이 관리자인지 확인

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

메인컨트렉트 수정

contract SimpleToken is ERC20Interface, OwnerHelper {
    using SafeMath for uint256;
    mapping (address => uint256) private _balances;
    mapping (address => mapping (address => uint256)) public _allowances;

    uint256 public _totalSupply;
    string public _name;
    string public _symbol;
    uint8 public _decimals;
    bool public _tokenLock;
    mapping (address => bool) public _personalTokenLock;

    constructor(string memory getName, string memory getSymbol) {
        _name = getName;
        _symbol = getSymbol;
        _decimals = 18;
        _totalSupply = 100000000e18;
        _balances[msg.sender] = _totalSupply;
        _tokenLock = true;
    }
    
    ........
    
    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;
        }
    }

    // 다음의 코드에서 함수로 전달되는 파라미터 브라켓 뒤에 오는 onlyOwner가 예시입니다.
    function removeTokenLock() onlyOwner public {
        require(_tokenLock == true);
        _tokenLock = false;
    }

    // 다음의 코드에서 함수로 전달되는 파라미터 브라켓 뒤에 오는 onlyOwner가 예시입니다.
    function removePersonalTokenLock(address _who) onlyOwner public {
        require(_personalTokenLock[_who] == true);
        _personalTokenLock[_who] = false;
    }
  }

TokenLock

isTokenLock

bool public _tokenLock;
    mapping (address => bool) public _personalTokenLock;

    constructor(string memory getName, string memory getSymbol) {
        // ~~
        _tokenLock = true;
    }

    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;
        }
    }

tokenLock은 토큰의 전체 락에 대한 처리, tokenPersonalLock은 토큰의 개인 락에 대한 처리
함수 isTokenLock은 전체 락과, 보내는 사람의 락, 받는 사람의 락을 검사하여 락이 걸려 있는지 확인

_transfer에 락 검사하기

_transfer에 검사를 추가해, 보내는 사람과 받는 사람 중 락이 걸려있다면 토큰은 이동이 불가

 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);
    }

락들을 제거 할 수 있는 removeTokenLock과 removePersonalTokenLock도 존재
해당 함수들은 onlyOwner를 적용하여 관리자만 락을 해제할 수 있도록 해야 한다.
락을 적용하게 되면 모든 락을 해제할 때만 토큰의 이동이 가능

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

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

다음 블로깅에 블로깅한 기능들을 조합하여 전체 코드를 조합해보자

댓글