メインコンテンツへスキップ

ERC-20トークンのスマートコントラクトを理解する

スマートコントラクト
トークン
Solidity
ERC-20
初級
jdourlens
2020年4月5日
7 分の読書

イーサリアムにおける最も重要なスマートコントラクト標準の1つはERC-20として知られており、これは、代替可能なトークン実装のためにイーサリアムブロックチェーン上のすべてのスマートコントラクトで使用される技術標準として登場しました。

ERC-20は、すべての代替可能なイーサリアムトークンが準拠すべき共通のルールリストを定義します。 その結果、このトークン標準により、あらゆる種類の開発者が、より大きなイーサリアムシステム内で新しいトークンがどのように機能するかを正確に予測できるようになります。 これにより開発者のタスクは簡素化され、容易になります。トークンがルールに従っている限り、新しいトークンがリリースされるたびに、それぞれの新しいプロジェクトをやり直す必要がないと分かった上で、作業を進めることができるからです。

以下は、ERC-20が実装しなければならない関数をインターフェイスとして提示したものです。 インターフェイスが何であるかよくわからない場合は、SolidityでのOOPプログラミング (opens in a new tab)に関する私たちの記事を確認してください。

1pragma solidity ^0.6.0;
2
3interface IERC20 {
4
5 function totalSupply() external view returns (uint256);
6 function balanceOf(address account) external view returns (uint256);
7 function allowance(address owner, address spender) external view returns (uint256);
8
9 function transfer(address recipient, uint256 amount) external returns (bool);
10 function approve(address spender, uint256 amount) external returns (bool);
11 function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
12
13
14 event Transfer(address indexed from, address indexed to, uint256 value);
15 event Approval(address indexed owner, address indexed spender, uint256 value);
16}
すべて表示

ここでは、すべての関数が何のためにあるのかを一行ずつ解説します。 この後、ERC-20トークンの簡単な実装を紹介します。

ゲッター

1function totalSupply() external view returns (uint256);

存在するトークンの総量を返します。 この関数はゲッターであり、コントラクトの状態を変更しません。 Solidityには浮動小数点数がないことに注意してください。 したがって、ほとんどのトークンは18桁の小数を採用しており、1トークンに対して1000000000000000000のように総供給量やその他の結果を返します。 すべてのトークンが18桁の小数を持つわけではなく、これはトークンを扱う際に本当に注意する必要があることです。

1function balanceOf(address account) external view returns (uint256);

アドレス(account)が所有するトークンの量を返します。 この関数はゲッターであり、コントラクトの状態を変更しません。

1function allowance(address owner, address spender) external view returns (uint256);

ERC-20標準では、あるアドレスが別のアドレスに対し、そのアドレスからトークンを取得できる許可(allowance)を与えることができます。 このゲッターは、spenderownerに代わって使用できる、許可されたトークンの残量を返します。 この関数はゲッターであり、コントラクトの状態を変更しません。デフォルトでは0を返すべきです。

関数

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

amountのトークンを、関数呼び出し元のアドレス(msg.sender)から受取人アドレスに移動します。 この関数は、後で定義されるTransferイベントを発行します。 送金が可能だった場合は、trueを返します。

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

spenderが関数呼び出し元(msg.sender)の残高から送金できるallowance(許可額)を設定します。 この関数はApprovalイベントを発行します。 この関数は、allowanceが正常に設定されたかどうかを返します。

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

allowanceの仕組みを使い、amountのトークンをsenderからrecipientに移動させます。 amountは、呼び出し元のallowanceから差し引かれます。 この関数はTransferイベントを発行します。

イベント

1event Transfer(address indexed from, address indexed to, uint256 value);

このイベントは、トークンの量(value)がfromアドレスからtoアドレスに送金されたときに発行されます。

新しいトークンをミントする場合、送金は通常fromが0x00..0000アドレスとなり、トークンをバーンする場合はtoが0x00..0000となります。

1event Approval(address indexed owner, address indexed spender, uint256 value);

このイベントは、トークンの量(value)がownerによってspenderに使用されることが承認されたときに発行されます。

ERC-20トークンの基本的な実装

ERC-20トークンのベースとなる最もシンプルなコードを以下に示します。

1pragma solidity ^0.8.0;
2
3interface IERC20 {
4
5 function totalSupply() external view returns (uint256);
6 function balanceOf(address account) external view returns (uint256);
7 function allowance(address owner, address spender) external view returns (uint256);
8
9 function transfer(address recipient, uint256 amount) external returns (bool);
10 function approve(address spender, uint256 amount) external returns (bool);
11 function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
12
13
14 event Transfer(address indexed from, address indexed to, uint256 value);
15 event Approval(address indexed owner, address indexed spender, uint256 value);
16}
17
18
19contract ERC20Basic is IERC20 {
20
21 string public constant name = "ERC20Basic";
22 string public constant symbol = "ERC";
23 uint8 public constant decimals = 18;
24
25
26 mapping(address => uint256) balances;
27
28 mapping(address => mapping (address => uint256)) allowed;
29
30 uint256 totalSupply_ = 10 ether;
31
32
33 constructor() {
34 balances[msg.sender] = totalSupply_;
35 }
36
37 function totalSupply() public override view returns (uint256) {
38 return totalSupply_;
39 }
40
41 function balanceOf(address tokenOwner) public override view returns (uint256) {
42 return balances[tokenOwner];
43 }
44
45 function transfer(address receiver, uint256 numTokens) public override returns (bool) {
46 require(numTokens <= balances[msg.sender]);
47 balances[msg.sender] = balances[msg.sender]-numTokens;
48 balances[receiver] = balances[receiver]+numTokens;
49 emit Transfer(msg.sender, receiver, numTokens);
50 return true;
51 }
52
53 function approve(address delegate, uint256 numTokens) public override returns (bool) {
54 allowed[msg.sender][delegate] = numTokens;
55 emit Approval(msg.sender, delegate, numTokens);
56 return true;
57 }
58
59 function allowance(address owner, address delegate) public override view returns (uint) {
60 return allowed[owner][delegate];
61 }
62
63 function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {
64 require(numTokens <= balances[owner]);
65 require(numTokens <= allowed[owner][msg.sender]);
66
67 balances[owner] = balances[owner]-numTokens;
68 allowed[owner][msg.sender] = allowed[owner][msg.sender]-numTokens;
69 balances[buyer] = balances[buyer]+numTokens;
70 emit Transfer(owner, buyer, numTokens);
71 return true;
72 }
73}
すべて表示

ERC-20トークン標準のもう一つの優れた実装として、OpenZeppelinのERC-20実装 (opens in a new tab)があります。

最終更新: 2025年8月21日

このチュートリアルは役に立ちましたか?