💰

ERC-20日本語訳と解説

2023/02/19に公開

ERC-20: Token Standard

https://eips.ethereum.org/EIPS/eip-20

はじめに

dApp開発などをしているときに、ちょっと不安になったときの参照用としてご利用ください。原文の抄訳と筆者のコメントを混ぜながら書きました。
間違いは優しくご指摘いただけると幸いです。

推奨知識

  • Ethereumの利用経験
  • 静的型付け言語の経験

ERCって?

初めての投稿なので一応説明します。
ERCとはざっくりいうと、Ethereum上のアプリケーションに関するお約束事リストのことです。主にスマートコントラクトのインターフェースを定義するものが多いです。
ERC-20についていうと、Ethereum上の"トークン"がこの規格に基づいているために、DEX(分散型取引所)のようなスマートコントラクトを可能にしています。
EIPというEthereumの標準規格の1つのカテゴリーなので、「ERC-20」と「EIP-20」の意味は全く同じです。
以下本題

一言でいうと

「スマートコントラクトでトークンを表現するときはこれらを満たすように書きましょう。」

概要

スマートコントラクト内のトークンの標準的なAPIを実装するための規格。
トークンのTransfer(移動)と第三者にそれを許可する仕組みを提供する。

仕様

メソッド(コントラクトというクラスに属する関数)

name (optional)

function name() public view returns (string)
トークンの名前を返す。(例:”MyToken”)
これが実装されていなくても、この規格に対応するプログラムはエラーを出してはいけない。以下、”optional”はこの意味を持つ。

symbol (optional)

function symbol() public view returns (string)
トークンのシンボルを返す。(例:”HIX”)

decimals (optional)

function decimals() public view returns (uint8)
トークンのゼロの数を返す
8の場合、そのユーザー表現は実際のトークン量を10^8で割った値になる。
ユーザー表現とは、ウォレットやアプリケーションで表示されるトークンの量のこと。
EIPの仕様の文面では、トークンの量とはユーザー表現ではなく、実際の整数値とする。

totalSupply

function totalSupply() public view returns (uint256)
トークンの総供給量を返す。

balanceOf

function balanceOf(address _owner) public view returns (uint256 balance)
アドレス _ownerの保有量を返す。

transfer

function transfer(address _to, uint256 _value) public returns (bool success)
_valueの分だけアドレス_toにトークンを移動させる。このとき、Transferイベントを発火しなくてはいけない。この関数は呼び出し側の保有量が十分でないときにエラーを投げるべきである。

注)_valueが0でもTransferイベントを発火しなくてはいけない。

transferFrom

function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
transferにトークンの送り主アドレスである_fromを追加する。
これは自分のアドレスに代わって他のコントラクトがトークンを移動するときに利用される。これは事前に送信者がその代理のコントラクトを認証していない場合はエラーを投げるべきである。その認証方法が次の関数である。

approve

function approve(address _spender, uint256 _value) public returns (bool success)
_spenderに自分のアカウントからのトークンの引き出しを_value分まで許可する。
同じ_spenderでもう一度この関数が呼ばれた場合、引き出し上限を_valueにアップデートする。(追加するわけではない)
**注意)ここで説明された攻撃を避けるために、引き出し上限をアップデートするときは一度それを0にするべき。
もしくは、その説明文にあるようにfunction approve(address _spender, uint256 _currentValue, uint256 _value) returns (bool success)とそれに対応するイベントを追加で実装すべきである

allowance

function allowance(address _owner, address _spender) public view returns (uint256 remaining)
_spenderが現在_ownerから引き出すことができるトークンの最大量を返す。

イベント (主にフロントエンドやテストの際にキャッチされる情報)

Transfer

event Transfer(address indexed _from, address indexed _to, uint256 _value)
トークンが移動したときに発火されなくてはいけない。移動する量がゼロのときでも。
新しくトークンを生成するときは_from0x0としてこのイベントを発火すべきである。

Approval

event Approval(address indexed _owner, address indexed _spender, uint256 _value)
approve(address _spender, uint256 _value)trueを返すときに必ず発火しなくてはいけない。

OpenZeppelinによる実装がよく使われる

IERC20.sol

以上の仕様に過不足なくインターフェースを定義している。
仕様とは違って、引数名にアンダースコアのプレフィックスがない。

ERC20.sol

以上の仕様を満たす実装で、さらに以下の追加要素を持つ。

  • increaseAllowance()やdecreaseAllowance()による第三者トークン最大使用量のアトミックな変更。
  • _mint(), _burn()というinternal関数。mintは新しくtotalSupplyを増やすことで、burnは減らすことである。この機能を有効化するにはコントラクト作成ウィザードを利用するといい。
  • トークンの移動の前後に呼び出されるフック
  • 拡張系

他にもPermit, Votes, Flash Mintingなどの興味深い拡張があるが割愛する。OpenZeppelinによる実装については、開発の際に集中的に調べて継承するものを選ぶというアプローチになるだろう。

小ネタ

Standadized_Contract_APIsで最初期のコントラクト実装の標準化に対するアプローチをみることができる。
Vitalik氏による最初のコミットはEthereumが稼働開始した2015/7/30の1ヶ月半前で、当初から彼の頭には今でいうDeFi, DEX, ENSの構想があったことが伺える。天才。

GitHubで編集を提案

Discussion