이더리움에서 가장 유명하면서도 널리 사용되는 토큰 표준 중 하나로 ERC20이 있습니다. ERC20을 따르면 자산을 보다 쉽게 교환할 수 있고 다양한 Dapp끼리 동일한 표준에 따라 상호 연동할 수 있습니다. ERC20 토큰을 생성하기 위하여 어떠한 규칙을 따라야 하는지 알아보겠습니다.
ERC20 표준
ERC20 토큰은 대체 가능 토큰(fungible token)으로 고유하지 않으면서 동일한 가치의 다른 토큰으로 완벽히 대체할 수 있는 토큰입니다. 따라서 ERC20 기반 토큰을 생성하려면 아래의 함수를 반드시 제공해야 합니다.
totalSupply()
balanceOf(address _owner)
transfer(address _to, uint256 _value)
transferFrom(address _from, address _to, uint256 _value)
approve(address _spender, uint256 _value)
allowance(address _owner, address _spender)
위에서부터 각 함수의 역할을 설명하자면 아래와 같습니다.
totalSupply는 토큰의 총 발행량
balanceOf는 _owner가 소지하고 있는 토큰의 수량 확인
transfer은 _to에게 _value만큼 토큰을 전송
transferFrom은 _from으로부터 _to에게 _value만큼 토큰 전달
approve는 _spender에게 _value만큼 토큰의 권한을 부여
allowance는 _owner가 _spender에게 권한을 부여한 토큰 수량 확인
또한 위의 함수 이외에도 사용되는 이벤트는 아래와 같습니다.
transfer(address indexed _from, address indexed _to, uint256 _value)
approval(address indexed _owner, address indexed _spender, uint256 _value)
토큰 전송 및 권한 부여를 하게 되면 두 이벤트를 발생시켜 로그에 기록합니다. 이를 통하여 토큰을 전송하였는지 권한을 부여하였는지 이벤트의 로그를 통하여 확인할 수 있습니다.
mint와 burn
mint 함수는 새로운 토큰을 발행하는 기능을 구현할 때 사용될 수 있습니다.
burn 함수는 특정 주소가 소유한 토큰을 감소시키는 역할을 합니다.
mint와 burn함수는 ERC-20 표준에서는 제공되지 않고, 프로젝트의 특정 요구에 따라 사용자 정의 함수로 구현되어야 합니다. 따라서 mint와 burn 기능이 필요한 경우, ERC-20 토큰을 개발하는 프로젝트에서는 해당 기능을 자체적으로 추가하여 스마트 계약을 구현해야 합니다. 이러한 기능을 구현하기 위해서는 프로젝트의 개발자가 토큰의 로직을 수정하고, mint와 burn 기능을 구현하는 함수를 추가하여야 합니다.
*Openzeppelin에서 제공하는 ERC20의 경우 _mint함수와 _burn함수가 존재합니다.
_mint
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
_burn
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
최대 발행량 제한
bitcoin의 경우 총발행량이 2100만 개로 제한되어 있습니다. ERC-20을 이용하여 총발행량을 제한하려면 스마트 계약에서 해당 로직을 구현해야 합니다. 일반적으로 ERC-20 토큰의 총공급량은 totalSupply() 함수를 통해 조회하므로 다음과 같은 방법으로 토큰의 총발행량을 제한할 수 있습니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract RainbowBearToken is ERC20 {
uint256 public maxSupply;
constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {
maxSupply = 1000000; // 총 발행량을 1,000,000으로 설정
}
function mint(address _to, uint256 _amount) public {
require(totalSupply() + _amount <= maxSupply, "Max supply exceeded");
_mint(_to, _amount);
emit Transfer(address(0), msg.sender, _amount);
}
}
- openzeppelin을 이용하여 ERC20을 import 합니다.
- import 한 ERC20을 is를 이용하여 RainbowBearToken에 상속합니다.
- constructor를 이용하여 maxSupply를 설정해 줍니다.
- 상속받은 ERC20도 선언을 하기 위하여 constructor의 매개변수인 _name과 _sybol을 ERC20(_name, _sybol)을 통하여 전달합니다.
- mint라는 함수를 만들고 require문을 통하여 총발행량을 확인 후 상속받은 ERC20의 함수인 _mint를 통하여 토큰을 발행합니다.
'BlockChain > solidity' 카테고리의 다른 글
[Solidity] ERC-2771이란? (ERC-2771Context란?) (0) | 2023.07.02 |
---|---|
[Solidity] EIP-712란? (0) | 2023.07.02 |
[Solidity] ERC20 Permit이란? (0) | 2023.06.17 |
[Solidity] ERC-1155란? (0) | 2023.05.18 |
[Solidity] ERC-721이란? (0) | 2023.05.18 |