본문 바로가기
Blockchain/Ethereum

[Ethereum] ERC-20

by AustinProd 2022. 3. 23.

지난 포스트에서 ERC에 대해 알아보았다. 이번에는 ERC 토큰 그룹 중 시장에서 가장 활발하게 거래되고 있는 ERC-20 토큰에 대해 알아보려고 한다.

 

ERC-20

ERC-20 토큰이란 이더리움 네트워크에 배포된 대체 가능 토큰(Fungible Token) 중 하나다. 이더리움 네트워크에서 가장 많이 사용되는 토큰 그룹이며, 마치 우리가 사용하는 화폐처럼 계정(Account)들 간의 거래에 사용된다.

 

여기서 대체 가능 토큰(Fungible Token)이란 1개의 토큰은 다른 1개와 그 가치가 동일함을 의미한다. 실생활에서 100원짜리 동전을 생각하면 된다. 내가 가지고 있는 100원은 다른 사람이 가지고 있는 100원과 같다. 그렇기 때문에 지금 가지고 있는 100원이 다른 사람의 100원으로 바뀌어도 똑같이 100원이기 때문에 대체 가능(Fungible)하다는 의미다.

 

이더리움 네트워크에서의 ERC-20 토큰 표준에 대해 정리하면 총 4가지로 정리할 수 있다.

 

  • 계정(Account) 사이의 토큰 교환이 가능하다.
  • 계정(Account)이 보유한 토큰 수량(Balance)을 확인이 가능하다.
  • 네트워크에 발행된 총 토큰 수량(Total Supply) 확인이 가능하다.
  • 토큰이 다른 계정으로 전달될 때, 그 수량이 유효한지 검증이 가능하다. (현재 보유한 토큰 수량보다 많은 양을 보낼 수 없기 때문)

 

만약, 어느 개발자가 ERC-20 표준에 따라 이더리움 네트워크에 토큰을 발행(배포)하면 위 기능들이 전부 반영되어 있을 것이다. 해당 토큰은 ERC-20 표준 인터페이스에 맞춰 구현되었기 때문이다.

 

ERC-20 인터페이스

아래 코드는 ERC-20 표준 인터페이스 소스 코드이다. 총 6개 함수와 2개의 이벤트가 있다. 이 중 3개는 필수 구현 함수이고, 나머지 3개는 꼭 구현하지 않아도 되는 선택 함수들이다.

 

필수 함수

  • totalSupply : 이더리움 네트워크에 발행된 총 토큰 수량을 반환
  • balanceOf : 인자 값으로 계정 주소 값을 받으며, 해당 주소에 매핑된 보유 토큰 수량을 반환
  • transfer : 인자값으로 전달된 계정 주소에 요청한 만큼의 토큰을 전송하며, 트렌젝션 결과에 대한 성공 여부를 반환

 

선택 함수

  • allowance : 계정과 계정 사이에 토큰을 전송할 수 있는 권한 설정하며, mapping 계정 index를 반환
  • approve : 권한이 있는 계정에 전송할 수 있는 토큰 제한 수량 설정하며, 트렌젝션 결과에 대한 성공 여부를 반환
  • transfer : 토큰 교환이 이루어질 두 계정 주소와 토큰 수량을 입력받아 토큰을 전송하며, 트렌젝션 결과에 대한 성공 여부를 반환

 

이벤트

  • Transfer : 토큰 전송이 성공적으로 이루어졌을 때, 애플리케이션(DApp)에 이벤트 전송(프론트 웹에 결과 알림)
  • Approve : 계정에 토큰 제한 수량 설정이 성공적으로 이루어졌을 때, 에플리케이션(DApp)에 이벤트 전송(프론트 웹에 결과 알림)

 

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

// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/token/ERC20/IERC20.sol
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 view 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 value);
    event Approval(address indexed owner, address indexed spender, uint value);
}

 

ERC-20 토큰

아래 코드는 ERC-20 인터페이스를 구현하여 작성한 커스텀 토큰 소스코드다. 각 상태 변수의 선언과 생성자, 함수 내 로직이 참고가 되었으면 좋겠다.

 

// 토큰 컨트렉트
contract Token is IERC20 {
    string public name = "Log4DayToken";
    string public symbol = "LDT";

    uint public decimals = 0; // [ 0 ~ 18 ] 범위의 Decimal 상태 변수
    uint public override totalSupply;
    address public founder;
    mapping(address => uint) public balances;
    mapping(address => mapping(address => uint)) allowed;
    
    // 생성자
    constructor() {
        totalSupply = 1000000; // = 1,000,000
        founder = msg.sender;
        balances[founder] = totalSupply;
    }
    
    // 보유 토큰 확인
    function balanceOf(address owner) public view override returns (uint balance) {
        return balances[owner];
    }
    
    // 토큰 전송(받는 사람, 수량)
    function transfer(address recipient, uint amount) public override returns (bool success) {
        require(balances[msg.sender] >= amount);

        balances[recipient] += amount;
        balances[msg.sender] -= amount;

        emit Transfer(msg.sender, recipient, amount);

        return true;
    }
    
    // 토큰 전송 권한 설정
    function allowance(address owner, address spender) view public override returns  (uint) {
        return allowed[owner][spender];
    }
    
    // 토큰 전송 수량 설정
    function approve(address spender, uint amount) public override returns (bool success) {
        require(balances[msg.sender] >= amount);
        require(amount > 0);

        allowed[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }
    
    // 토큰 전송(보내는 사람, 받는 사람, 수량)
    function transferFrom(address sender, address recipient, uint amount) public override returns (bool success) {
        require(allowed[sender][recipient] >= amount);
        require(balances[sender] >= amount);

        balances[sender] -= amount;
        balances[recipient] += amount;
        allowed[sender][recipient] -= amount;

        return true;
    }
}

 

'Blockchain > Ethereum' 카테고리의 다른 글

[Ethereum] ERC-721 소스 분석(1) - 인터페이스  (0) 2022.03.23
[Ethereum] ERC-721  (0) 2022.03.23
[Ethereum] ERC란?  (0) 2022.03.22
[Ethereum] Web3.js 라이브러리  (0) 2022.03.17
[Ethereum] 트렌젝션(Transaction)과 콜(Call)  (0) 2022.03.17

댓글