BlockChain

(BlockChain) Interface IERC20 / ERC20 Token 구현

JJeongHyun 2023. 3. 9. 19:35
반응형

Solidity의 interface

  • 다른 컨트랙트와 상호작용이 가능
    • You can interact with other contracts by declaring an interface
    • 자식 컨트랙트를 위한 틀, 추상 함수로만 구성되어야 한다
      • 추상 함수 : 함수이름, 매개변수, 출력만 선언해 두고 내용이 없는 함수를 뜻
  • TS에서의 interface처럼 정의를 하지 않고 선언만 한다
  • 특징
    • 함수의 기능은 정의하지 않는다, 구현하지 못한다
    • 다른 interface에서 상속이 가능하다
      • 다른 interface으로부터 상속을 받을 수 없다
    • 함수는 무조건 external 옵션을 설정해야 한다
    • 생성자를 선언할 수 없다
    • 상태변수를 선언할 수 없다

interface IERC20.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

interface IERC20 {
  function totalSupply() external view returns (uint);

  function balanceOf(address account) external view returns (uint);

  function transfer(address recipient, uint amount) external returns (bool);

  function allowance(address owner, address spender) external returns (uint);

  function approve(address spender, uint amount) external returns (bool);

  function transferFrom(address sender, address recipient, uint amount) external returns (bool);

  event Transfer(address indexed from, address indexed to, uint amount);
  event Approval(address indexed owner, address indexed spender, uint amount);
}
  • totalSupply() : 토큰(코인)의 총 수량, 토큰의 총 수량을 반환
  • balanceOf(address account) : 지갑 계정의 잔액(토큰)
  • transfer(address recipient, uint amount) : 토큰(코인) 보내기
    • 수령인(recipient)에게 n(amount)개의 토큰을 보낸다
    • 트랜잭션 발생
  • allowance(address owner, address spender) : 권한을 위임받은 토큰을 관리하는 데이터 공간
    • 현재 지갑 계정(owner)이 다른 누구(다른 지갑 계정 | CA)(spender)에게 얼마의 토큰에 대한 권한을 줬는지 반환
  • approve(address spender, uint amount) : 권한을 위임하는 메서드
    • allowance에서 확인할 수 있는 권한 위임을 실행하는 메서드. 누구(spender)에게 얼마(amount)만큼의 토큰에 대한 권한 위임
    • spender가 인출할 수 있는 한도를 지정해준다(카드의 한도처럼)
  • transferFrom(address sender, address recipient, uint amount) : 권한을 위임받은 토큰에 대해 거래(보내기)
    • 위임받은 지갑 계정(spender)이 누구(recipient)에게 얼마(amount)만큼의 토큰을 보낸다
    • sender주소에서 recipient주소로 amount만큼의 Ether를 전송
  • event Transfer(address indexed from, address indexed to, uint amount) : 거래 시 기록하는 이벤트
  • event Approval(address indexed from, address indexed to, uint amount) :  권한 위임 시 기록하는 이벤트

ERC20 Token 구현

  • IERC20.sol를 상속받아 구현
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "./IERC20.sol";

contract ERC20 is IERC20 {
  string public name;
  string public symbol;
  uint8 public decimals = 18;

  uint public override totalSupply;
  mapping(address => uint) public balances;
  mapping(address => mapping(address => uint)) public override allowance;

  function balanceOf(address account) external view override returns (uint) {
    return balances[account];
  }

  function transfer(
    address recipient,
    uint amount
  ) external override returns (bool) {
    balances[msg.sender] -= amount;
    balances[recipient] += amount;
    emit Transfer(msg.sender, recipient, amount);
    return true;
  }

  function approve(
    address spender,
    uint amount
  ) external override returns (bool) {
    allowance[msg.sender][spender] = amount;
    emit Approval(msg.sender, spender, amount);
    return true;
  }

  function transferFrom(
    address sender,
    address recipient,
    uint amount
  ) external override returns (bool) {
    require(allowance[sender][msg.sender] >= amount);
    allowance[sender][msg.sender] -= amount;
    balances[recipient] += amount;
    balances[sender] -= amount;
    emit Transfer(sender, recipient, amount);
    return true;
  }

  function mint(uint amount) internal {
    balances[msg.sender] += amount;
    totalSupply += amount;
    emit Transfer(address(0), msg.sender, amount);
  }

  function burn(uint amount) external {
    balances[msg.sender] -= amount;
    totalSupply -= amount;
    emit Transfer(msg.sender, address(0), amount);
  }
}
  • import "./IERC20.sol"; : 미리 선언해 둔 interface IERC20 파일을 가져온다
  • contract ERC20 is IERC20 : solidity에서 상속받을 때 is 옵션을 사용
    ※ interface에서 선언된 함수는 default 설정으로 virtual 옵션을 갖는다. 이러한 옵션을 가진 메서드를 상속할 경우 override 옵션을 추가해서 상속을 받아야 한다.
    즉, 상속을 할 경우 상속을 받는 컨트랙트에서 override옵션을 사용하여 메서드를 다시 작성하여 덮어쓸 경우 상속하는 메서드는 virtual 옵션이어야 한다
  • mapping(address => mapping(address => uint)) public override allowance; : { address : { address : uint } } 형식
  • override 옵션으로 상속받는 메서드들
    • function balanceOf(address account) : 계정 잔액 조회 함수
    • function transfer(address recipient,uint amount) external override returns (bool) : 토큰 전송 함수
    • function approve(address spender,uint amount) external override returns (bool) : 위임 권한을 주는 함수
      • allowance[msg.sender][spender] = amount; : msg.sender 트랜잭션을 보낸 지갑의 계정의 토큰을 spender에게 amount 만큼 사용할 수 있도록 권한을 위임
    • function transferFrom(address sender,address recipient,uint amount) external override returns (bool) : approve 메서드로 토큰에 대해 권한을 부여받은 지갑 계정(spender)이 위임받은 토큰을 다른 계정에 보낼 때 사용하는 메서드
      • approve메서드의 msg.sender > transferFrom메서드의 sender
      • approve메서드의 sender > transferFrom메서드의 msg.sender
  • function mint(uint amount) internal : 토큰 발행 메서드
    • balances[msg.sender] += amount; : 트랜잭션을 보낸 지갑 계정에 원하는 만큼 토큰 추가
    • totalSupply += amount; : 총 수량에 추가
    • emit Transfer(address(0), msg.sender, amount); : mint함수는 토큰의 발행과 수량의 관련된 함수, 특정 계정에서 토큰이 빠져나가는 게 아니기에 Transfer 이벤트 메서드의 from값에 address(0)을 매개변수로 넘겨준다
      ※ address(0)은 주소에서의 null과 같다
  • function burn(uint amount) external : 토큰 삭제 메서드, 토큰을 소각한다고 한다
    • mint메서드와 반대로 더했던 거를 여기 burn메서드에서는 빼주고 from에 주소값이 address(0)인 것을 여기서는 to에 매개변수로 바꿔서 채워준다