# [ERC20] ERC20を1からわかりやすく解説

> ERC20とは、「Ethereumブロックチェーンで動作する統一されたトークン規格の1つ」です。

- URL: https://cardene.dev/articles/aeefe2d89dd5332c9f43
- 公開日: 2025-11-18
- 更新日: 2025-11-18
- トピック: Blockchain
- タグ: ethereum, solidity, smartcontract, erc20

### はじめに

初めまして。
『DApps開発入門』という本や色々記事を書いているかるでねです。

https://amzn.asia/d/gxvJ0Pw

以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください！

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

https://twitter.com/cardene777

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

今回は『ERC20』についてまとめていきます。

:::message
こちらの2022年12月に書いていた記事です。
2025年11月にリライトしました。
:::

### ERC20とは

#### 統一されたトークン規格

**ERC20**とは、「**Ethereumブロックチェーンで動作する統一されたトークン規格の1つ**」です。

「**統一されたトークンの規格**」というのは、「**共通のルールを持っているトークン**」という事です。
共通のルールを持っていないと、トークンごとにウォレットが必要になります。
新しいトークンを触るごとにウォレットを作っていては、だいぶめんどくさいですよね。

そこで**ERC20**というトークン規格に沿って設計することで1つのウォレットで管理できるようになります。

また、**ERC20**は「**代替性トークン**」とも呼ばれています。
「**代替性トークン**」とは、あるトークンと同じ価値を持つ他のトークンと交換できるということです。
反対に交換できないのでNFTを代表する「**非代替性トークン**」です。

#### 誰でも作成可能

**ERC20**トークンは誰でも作ることができます。
そのため現在存在する**ERC20**トークンの種類はめちゃくちゃ多いです。

https://etherscan.io/tokens

上記から現在の**ERC20**トークンの種類を確認できるのですが、現在（2025年11月17日）では177万9821種類の**ERC20**トークンがあります。

#### 追加機能を実装可能

この章の前半で説明したように、**ERC20**は統一された規格ですが、あくまで最低限の機能は統一された規格で設計されています。
そのため、トークンごとに追加機能を実装することが可能です。

新規発行する**ERC20**トークンごとに以下のように役割が異なってくるため、役割に応じて追加機能を実装することが可能になります。

##### ステーブルコイン

ドルや日本円などの法定通貨や市場で取引されるコモディティ（金やプラチナなど）などの価格に連動するように設計された暗号通貨。

##### DeFiトークン

分散型金融（DeFi）プロトコルを支援するトークン。

スマートコントラクトで管理されているため中央管理者が存在しない。

仮想通貨を預け入れて利息を得たり、流動性を提供して独自トークンを得る、仮想通貨を貸し出して利回りを得るなどして稼ぐことができる。

##### ユーティリティトークン

特定のコミュニティやサービスなどを利用するにあたり実用性があるトークンのこと。
具体的には以下のような用途が想定される。

- サービス内で物を購入したり利用料を支払う
- 利用者の行動に対してインセンティブを支払う
- 所有することでコミュニティの意思決定に関われる
- 保有している量や期間に応じて報酬が発生する

### 代表的なERC20トークン

この章では代表的な**ERC20**トークンについて一覧にしていきます。

- Tether（USDT）
    https://tether.to/en/
- Binance Coin（BNB）
    https://www.binance.com/en
- USD Coin（USDC）
    https://www.centre.io/usdc
- DAI（DAI）
    https://makerdao.com/ja/
- Basic Attention Token（BAT）
    https://basicattentiontoken.org/
- Polygon（MATIC）
    https://polygon.technology/
- Shiba Inu（SHIB）
    https://shibatoken.com/
- Uniswap（UNI）
    https://uniswap.org/
- ChainLink（LINK）
    https://chain.link/

### EIP20

#### EIPとは

前章まで**ERC20**といってきましたが、**EIP20**とは何でしょうか？

EIPとは「**Ethereum Improvement Proposals**」の略で、「**Ethereumの新しい機能やプロセスに関する提案を規定する標準規格**」のことです。

EIPの細かい説明は以下に書かれています。

https://eips.ethereum.org/

簡単に言うと以下になります。

**EIP**は、Ethereum Improvement Proposalsの略でEthereumをより良いものにするために議論される改善提案のこと。
Ethereumは、特定の誰かによって管理されるものではないため、世界中の誰もが**EIP**を提出することで、Ethereumの発展に貢献することができる。
20という数字は20番目の提案ということです。

**ERC**は、**EIP**の中の1カテゴリです。
そのため、**ERC20**と**EIP20**は同じものを指しています。

### ERC20の関数

#### ERC20のオプション関数

**ERC20**には必須の関数とオプション関数の2つがあります。
まずは実装してもしなくても良い、オプション機能について紹介していきます。

##### `name`

トークンの名前を返す関数です。

例）Tether

```js
function name() public view returns (string)
```

##### `symbol`

トークンのシンボルを返す関数。

例）USDT

```js
function symbol() public view returns (string)
```

##### `decimals`

トークンが使用する小数点以下の桁数を返す関数。

例えば8を指定すると、トークンの金額を100000000で割って表示し、ユーザーに対してより読みやすい方法でトークン数を表示することができる。

```js
function decimals() public view returns (uint8)
```

#### ERC20の必須関数

では次に**ERC20**の必須関数について確認していきます。

##### `totalSupply`

トークンの総供給量を返す関数。

```js
function totalSupply() public view returns (uint256)
```

##### `balanceOf`

特定アドレスが保持しているトークン残高を返す関数。

```js
function balanceOf(address _owner) public view returns (uint256 balance)
```

##### `transfer`

`_to`に送り先のアドレス、`_value`に送りたいトークンの量を指定して送付し、送付結果が成功か失敗か返す関数。

**条件**
- `_to`に0アドレスを指定できない
- transfer関数の実行アドレスは`_value`以上のトークンを保有している必要がある

```js
function transfer(address _to, uint256 _value) public returns (bool success)
```

##### `transferFrom`

`_from`に送り元アドレス、`_to`に送り先のアドレス、`_value`に送りたいトークンの量を指定して送付し、送付結果が成功か失敗か返す関数。
`transferFrom`関数の用途としては、コントラクトがトークン保有者に代わってトークンを送付する。
コントラクトを実行するアドレスは`_value`以上のトークンの送付権限が必要。

**条件**
- `_from`と`_to`に0アドレスを指定できない
- `_from`で指定したアドレスは`_value`以上のトークンを保有している必要がある
- コントラクトを実行するアドレスは`_value`以上のトークンの送付権限が必要

```js
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
```

##### `approve`

`_spender`に資金引き出し許可を与えるアドレス、`_value`に引き出せるトークンを指定して、指定したアドレスに資金の引き出し許可を与える関数。
`_spender`に指定されたアドレスは、`_value`に指定されたトークン量の範囲内であれば何度でも送付できる。

**条件**
- `_spender`には0アドレスを指定できない

```js
function approve(address _spender, uint256 _value) public returns (bool success)
```

##### `allowance`

`_owner`に送付許可を与えたアドレス、`_spender`に送付許可を与えられたアドレスを格納し、`transferFrom`関数を通じて、`_spender`が`_owner`から引き出すことができるトークン量を返す関数。

```js
function allowance(address _owner, address _spender) public view returns (uint256 remaining)
```

### ERC20のコード確認

ではこの章から実際に**ERC20**の実装コードを見ていきましょう！
今回は**ERC20**を実装する上でほとんどの人が使用している「**OpenZeppelin**」を使用していきます。

「**OpenZeppelin**」とは、Solidityで安全なスマートコントラクトを構築できるオープンフレームワークです。

分散型アプリケーションの構築や自動化、運用のためのセキュリティ製品を主に提供している企業です。

今回は以下のページを使用しながらコードの確認をしていきます。

https://docs.openzeppelin.com/contracts/4.x/api/token/erc20

#### IERC20

**IERC20**とは、**ERC20**を実装する上で必要な関数やイベントが定義されているinterfaceです。

Solidityにおけるイベントとは、簡単にいうと「**スマートコントラクトでの動作結果をフロントに伝える**」役割を持った機能です。

詳しくは以下の公式ドキュメントを参考にしてください。

https://solidity-jp.readthedocs.io/ja/latest/contracts.html#events

##### interface

interfaceとは、コントラクトに似ていますが実行することはできません。
interfaceには関数名やひきすうなどのみ定義されていて中身は一切定義されていません。
そのため、interfaceを継承したコントラクト内で関数を再度定義して中身を記述する必要があります。

「**interfaceいらなくね？**」こう思う方もいると思います。

interfaceを使用するメリットは、実装で必要な関数を確認できることにあります。
最初で述べたように、interfaceには実装する上で必要な関数が定義されているので、開発者やコントラクトを実行するユーザーからどんな機能があるのかを簡単に確認できます。
有名なプロジェクトでもinterfaceはよく使用されているので、この機会に理解しておくと後々役に立ちます。

公式ドキュメントは以下になります。

https://solidity-jp.readthedocs.io/ja/latest/contracts.html#interfaces

##### 関数

ではまずはIERC20に定義されている関数から確認していきましょう。

**関数一覧:**
- totalSupply()
- balanceOf(account)
- transfer(to, amount)
- allowance(owner, spender)
- approve(spender, amount)
- transferFrom(from, to, amount)

上記の6つ関数が定義されています。
**EIP20**の解説部分で取り上げた関数と同じなため詳細はそちらを参照してください！

##### イベント

IERC20には2つのイベントが定義されています。

##### `Transfer(from, to, value)`

`value`分のトークンを保有している、`from`に指定されたアドレスから`to`に指定されたアドレスへトークンが送付されたときに発行される。
値は0であっても良い。

##### `Approval(owner, spender, value)`

approve関数が呼び出され、`owner`に指定されたアドレスから`spender`に指定されたアドレスへ`value`分のトークンの送付許可が設定されたときに発行される。

#### IERC20Metadata

次にIERC20メタデータについて確認していきます。
こちらもIERC20同様interfaceが定義されています。
以下の関数も**ERC20**で解説している関数です。

**関数一覧**
- `name()`
- `symbol()`
- `decimals()`

上記の3つの関数はオプション関数のため必須の機能ではありません。

#### ERC20

ではここから念願の**ERC20**について確認していきます！
IERC20でも述べているように、この**ERC20**はIERC20とIERC20Metadataを継承しています。
そのためIERC20の6つの関数とIERC20Metadataの3つの関数が定義されています。

そして、もちろんそれ以外の関数もたくさん定義されているので、簡単な説明も添えていきます。

**関数一覧:**
- `constructor(name_, symbol_)`
- `name()`
- `symbol()`
- `decimals()`
- `totalSupply()`
- `balanceOf(account)`
- `transfer(to, amount)`
- `allowance(owner, spender)`
- `approve(spender, amount)`
- `transferFrom(from, to, amount)`
- `increaseAllowance(spender, addedValue)`
- `decreaseAllowance(spender, subtractedValue)`
- `_transfer(from, to, amount)`
- `_mint(account, amount)`
- `_burn(account, amount)`
- `_approve(owner, spender, amount)`
- `_spendAllowance(owner, spender, amount)`
- `_beforeTokenTransfer(from, to, amount)`
- `_afterTokenTransfer(from, to, amount)`

説明も合わせて書くとだいぶ長くなってしまうので分割して説明していきます。

##### `constructor`

トークンの名前（name）とシンボル（symbol）をデプロイ時に渡し、デプロイ後は変更できない。
小数値（decimals）のデフォルト値は18になっているため、別の値に設定したいときは上書きする必要がある。

```js
string private _name;
string private _symbol;

constructor(string memory name_, string memory symbol_) {
    _name = name_;
    _symbol = symbol_;
}
```

##### `name`

`_name`変数の値を返す関数。

```js
function name() public view virtual override returns (string memory) {
    return _name;
}
```

##### `symbol`

`_symbol`変数の値を返す関数。

```js
function symbol() public view virtual override returns (string memory) {
    return _symbol;
}
```

##### `decimals`

`decimals` に指定した値（デフォルトは18）を返す関数。

```js
function decimals() public view virtual override returns (uint8) {
    return 18;
}
```

##### `totalSupply`

トークンの総供給量を返す関数。

```js
uint256 private _totalSupply;

function totalSupply() public view virtual override returns (uint256) {
    return _totalSupply;
}
```

##### `balanceOf`

`account`で指定したアドレスが保有するトークンの量を返す関数。

```js
function balanceOf(address account) public view virtual override returns (uint256) {
    return _balances[account];
}
```

##### `transfer`

`_msgSender`関数は`msg.sender`の結果を返す関数です。

```js
function transfer(address to, uint256 amount) public virtual override returns (bool) {
    address owner = _msgSender();
    _transfer(owner, to, amount);
    return true;
}
```

`_msgSender`関数の定義は以下です。

```js
function _msgSender() internal view virtual returns (address) {
    return msg.sender;
}
```

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.0/contracts/utils/Context.sol

`_transfer`関数は後述しています。

##### `allowance`

`_allowances`マッピングにて保管されている、`owner`に指定されたアドレスが`spender`で指定されたアドレスにどれくらいの量のトークンの送付許可を与えているかを確認できる関数。

```js
mapping(address => mapping(address => uint256)) private _allowances;

function allowance(address owner, address spender) public view virtual override returns (uint256) {
    return _allowances[owner][spender];
}
```

##### `approve`

`_spender`に資金引き出し許可を与えるアドレス、`_value`に引き出せるトークンを指定して、指定したアドレスに資金の引き出し許可を与える関数。

`_approve`関数については後述しています。

```js
function approve(address spender, uint256 amount) public virtual override returns (bool) {
    address owner = _msgSender();
    _approve(owner, spender, amount);
    return true;
}
```

##### `transferFrom`

`from`で指定したアドレスから`to`で指定したアドレスへ`amount`分のトークンを送る関数。

`_spendAllowance`関数と`_transfer`関数は後述しています。

```js
function transferFrom(
    address from,
    address to,
    uint256 amount
) public virtual override returns (bool) {
    address spender = _msgSender();
    _spendAllowance(from, spender, amount);
    _transfer(from, to, amount);
    return true;
}
```

##### `increaseAllowance`

`spender`に指定したアドレスが送付できるトークン量を増やす関数。

**条件**
- `spender`は0アドレスにできない

`_approve`関数は後述しています。

```js
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
    address owner = _msgSender();
    _approve(owner, spender, allowance(owner, spender) + addedValue);
    return true;
}
```

##### `decreaseAllowance`

`spender`に指定したアドレスが送付できるトークン量を減らす関数。

**条件**
- `spender`は0アドレスにすることはできない
- `spender`は`subtractedValue`よりも多くのトークン量を送付許可されている必要がある

`_approve`関数は後述しています。

`unchecked`は、オーバフローとアンダーフローのチェックを行わないというマークです。
チェックを行わないことでガス代が節約されるため、チェックが不要な箇所では積極的に使用すると良いです。

```js
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
    address owner = _msgSender();
    uint256 currentAllowance = allowance(owner, spender);
    require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
    unchecked {
        _approve(owner, spender, currentAllowance - subtractedValue);
    }

    return true;
}
```

https://ethereum.stackexchange.com/questions/113221/what-is-the-purpose-of-unchecked-in-solidity

オーバフローとアンダーフローについては以下を参考にしてください。

https://note.com/cardene/n/nc1db4e04b257

##### `_transfer`

`from`に指定されたアドレスから、`to`に指定されたアドレスに `amount` 分のトークンを送付する関数。

**条件**
- `from` を0アドレスにできない
- `to` を0アドレスにできない
- `from` に指定されたアドレスは、`amount` 以上のトークンを保有している必要がある

```js
function _transfer(
    address from,
    address to,
    uint256 amount
) internal virtual {
    require(from != address(0), "ERC20: transfer from the zero address");
    require(to != address(0), "ERC20: transfer to the zero address");

    _beforeTokenTransfer(from, to, amount);

    uint256 fromBalance = _balances[from];
    require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
    unchecked {
        _balances[from] = fromBalance - amount;
        // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
        // decrementing then incrementing.
        _balances[to] += amount;
    }

    emit Transfer(from, to, amount);

    _afterTokenTransfer(from, to, amount);
}
```

##### `_mint`

`amount` 分のトークンを生成し、`account` に指定されたアドレスに送ることでトークンの総供給量を増やす関数。

**条件**
- `account` を0アドレスにできない

`_beforeTokenTransfer` 関数と `_afterTokenTransfer` 関数については後述しています。

```js
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`

`account` で指定したアドレスから `amount` 分のトークンを破棄してトークンの総供給量を減らす関数。

**条件**
- 送り先は0アドレスに指定されている
- `account` を0アドレスにできない
- `account` で指定したアドレスは、`amount` 分以上のトークンを保有してある必要がある

`_beforeTokenTransfer` 関数と `_afterTokenTransfer` 関数については後述しています。

```js
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);
}
```

##### `_approve`

`owner` で指定したアドレスから、`spender` に指定したアドレスに `amount` 分のトークンの送付許可を与える関数。

**条件**
- `owner` を0アドレスにできない
- `spender` を0アドレスにできない

```js
function _approve(
    address owner,
    address spender,
    uint256 amount
) internal virtual {
    require(owner != address(0), "ERC20: approve from the zero address");
    require(spender != address(0), "ERC20: approve to the zero address");

    _allowances[owner][spender] = amount;
    emit Approval(owner, spender, amount);
}
```

##### `_spendAllowance`

`owner` に指定されたアドレスが、`spender` に指定されたアドレスへ送付許可していたトークンの量を `amount` に更新する関数。

**条件**
- 現在 `spender` に指定されたアドレスに送付許可されている値が最大値の場合は更新しない
- `owner` に指定されたアドレスが、`amount` で指定した量のトークンを保有していない場合は処理を戻す

```js
function _spendAllowance(
    address owner,
    address spender,
    uint256 amount
) internal virtual {
    uint256 currentAllowance = allowance(owner, spender);
    if (currentAllowance != type(uint256).max) {
        require(currentAllowance >= amount, "ERC20: insufficient allowance");
        unchecked {
            _approve(owner, spender, currentAllowance - amount);
        }
    }
}
```

##### `_beforeTokenTransfer`

トークン送付前に呼び出される関数。
この関数に任意の追加処理を実装することができる。

- `from` と `to` が0アドレスでないとき `from` で指定されたアドレスから `to` に指定したアドレスへ `amount` 分のトークンが送付される
- `from` に0アドレスが指定されると、`to` で指定されたアドレスに `amount` 分のトークンが生成されたのち送付される
- `to` に0アドレスが指定されると、`from` で指定されたアドレスから `amount` 分のトークンがBurnされる
- `from` と `to` の両方が0アドレスになることはない

```js
function _beforeTokenTransfer(
    address from,
    address to,
    uint256 amount
) internal virtual {}
```

##### `_afterTokenTransfer`

トークン送付後に呼び出される関数。
この関数に任意の追加処理を実装することができる。

- `from` と `to` が0アドレスでないとき `from` で指定されたアドレスから `to` に指定したアドレスへ `amount` 分のトークンが送付される
- `from` に0アドレスが指定されると、`to` で指定されたアドレスに `amount` 分のトークンが生成されたのち送付される
- `to` に0アドレスが指定されると、`from` で指定されたアドレスから `amount` 分のトークンがBurnされる
- `from` と `to` の両方が0アドレスになることはない

```js
function _afterTokenTransfer(
    address from,
    address to,
    uint256 amount
) internal virtual {}
```

#### Extension

ここまで**ERC20**について確認できました。
**ERC20**には拡張機能がたくさんあるのですが、ここで紹介するにはあまりにも多すぎるため、今後時間あるときに別記事でまとめていきます。
とりあえずは基本的な**ERC20**を知っておけば問題ありません。

### ERC20の実装

前章までで**ERC20**の概要とコードの理解ができました。
この章では実際に**ERC20**の実装をしていきたいと思います。
前章が相当長かったと思うので覚悟して取り掛かってください！

```js
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract Cardene is ERC20 {
    constructor() ERC20("Cardene", "CARD") {
        _mint(msg.sender, 100000 * 10 ** decimals());
    }
}
```

はい…。
嘘つきました。
このたった7行のコードで**ERC20**の実装は完了です。

「**え？さっきの大量の関数はどこに？**」と思う方もいると思いますが、先ほどの長い関数たちを定義したコントラクトを継承しています。
4行目でopenzeppelinが提供している**ERC20**のコントラクトを読み込んでいます。
6行目で`Cardene is ERC20`と4行目で読み込んだコントラクトを継承しています。

継承すると継承元のコントラクトで定義されている関数を全て使用することができるため、先ほど解説した関数を全て使用することができます。
納得していただけたでしょうか？

では次の章で実行していきましょう！
ちなみに以下のOpenzeppelinのサイトから簡単にコードを生成できるので、触ってみると理解が深まるかもしれいないです。

https://docs.openzeppelin.com/contracts/4.x/wizard

### ERC20の実行

この章では実際に**ERC20**を実行していきます！
remixというブラウザで使用できるエディタを使用していきます！

https://remix.ethereum.org/

実装手順を紹介していきます。

#### ファイルの作成

以下の画面の左側の「**contracts**」というディレクトリの上で右クリックすると、メニューが出てくるので「**New File**」をクリックして、「`CardeneERC20.sol`」と入力してください。

![image.png](/images/qiita-e5924bc9-1d4b-40db-89f2-9f4133a56ecb.webp)

そうするとファイルが作られるので、「`CardeneERC20.sol`」をクリックすると右の画面にファイルの中身が表示されます。

まだ何も書かれていないので以下のコードを貼り付けてください。

```js
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract Cardene is ERC20 {
    constructor() ERC20("Cardene", "CARD") {
        _mint(msg.sender, 100000 * 10 ** decimals());
    }
}
```

#### コンパイル

では次にコンパイルしていきます。

以下のように一番左の5つのアイコンの真ん中をクリックして、「**Compile CardeneERC20.sol**」をクリックしてください。

![image.png](/images/qiita-b3ef2bf4-1fb6-446c-91a0-e6a4408eb407.webp)

アイコンに緑のチェックが入ればコンパイル完了です。

#### デプロイ

一番左の5つのアイコンの下から2つ目のアイコンをクリックして、「**Deploy**」というボタンをクリックしてください。

![image.png](/images/qiita-7f055bd5-6ca5-4cdb-807a-792f7ac9b6b6.webp)

そうするとコントラクトがデプロイされて、左下の方にある「**Deployed Contracts**」の下に「**CARDENEERC20 AT 0XD91...39138**」と表示されればデプロイできています！

#### 関数の実行

ではここから早速関数を実行していきましょう！

##### 確認系

まずは確認系の関数から実行していきます。

先ほどデプロイしたコントラクト内の「**decimals**」、「**name**」、「**symbol**」、「**totalSupply**」を実行していきます。

![image.png](/images/qiita-dcf3ffdd-9837-4f7f-996e-1ae58d9d932c.webp)

それぞれ結果が出力されていますね。

トークンの名前は「**Cardene**」で、トークンのシンボルは「**CARD**」、「**decimals**」はデフォルトの「**18**」、総供給量は「**100000000000000000000000**」を膨大な数字になってしまいました。

##### `balanceOf`

ではどのユーザーがどれくらいトークンを保持しているか確認できるbalanceOf関数を実行していきましょう。

コントラクトをデプロイした以下のアドレスの右にあるコピーボタンをクリックしてください。

![image.png](/images/qiita-a51bc605-ecd1-4019-b657-8e255f660515.webp)

![image.png](/images/qiita-faaae8a6-f944-4ba2-8654-03c9ecf6e8d5.webp)

アドレスをコピーしたら、balanceOfと書かれている右上の矢印をクリックして、accountの部分に先ほどコピーしたアドレスを貼り付けてください。

貼り付けたらcallと書かれているボタンを押すことで、「`100000000000000000000000`」と表示されます。

デプロイしたアドレスが全てのトークンを所有していることが確認できました。

##### `transfer`

次にトークンを他のアドレスに送付してみます。

ここからは手順が複雑になってくるので動画で紹介していきます。

![transferの図](https://storage.googleapis.com/zenn-user-upload/635796a9d4dd-20251117.gif)


他のアドレスを指定して1000トークンを送れました！

##### `approve`

他のアドレスに自分が所有しているトークンをtransferする許可を与えたいと思います。

![approveの図](https://storage.googleapis.com/zenn-user-upload/9f28aee938e7-20251117.gif)

他のアドレスとトークン量を指定して、approve関数を実行してtransferする許可を与えることができました。

##### `allowance`

では本当にtransferする許可を与えられているのか確認していきます。

allowance関数を実行することで、transferできるトークンの量を確認できます。

トークン所有者のアドレスと先ほどtransfer許可を与えたアドレスを与えた結果、approve関数を実行したときに指定した10000という数値が表示されました。

![allowanceの図](https://storage.googleapis.com/zenn-user-upload/a73634ad272b-20251117.gif)

しっかりtransfer許可を与えることができていますね。

##### `transferFrom`

ではtransferの許可を与えられたアドレスから、別のアドレスにトークンを送りたいと思います。

![transferFrom.gif](/images/qiita-fc8b2c3b-c502-4b0e-9030-518c8dcdf840.webp)

トークン所有者のアドレスと3つ目の別のアドレスを指定して、transferの許可を与えられたアドレスからtransferFrom関数を実行して1000トークンを送ることができました。

transfer許可を与えられていないと、トークン所有者以外がtransferFrom関数を実行しても失敗してしまうのでぜひ試してみてください！

##### `decreaseAllowance`

次にtransfer許可を与えているトークンの量を減らしていきます。

![decreaseAllowance.gif](/images/qiita-bc741b91-fa59-46e0-b8fc-738142e316e8.webp)

transfer許可を与えているトークン量の調整は、再度approve関数を実行すれば良いと思うかもしれないです。

しかし、`approve` 関数はトークン量を更新してしまうため、現在transfer許可を与えているトークン量に対して増減させることはできません。

そこで `decreaseAllowance` 関数を実行することで、10000という値から5000という値に減らすことができました。

（ちょうど半分の値なので更新したように見えますが、ちゃんと減算されています。）

##### `increaseAllowance`

では最後に `decreaseAllowance` 関数の逆の処理を行う `increaseAllowance` 関数を実行して、transfer許可を与えているトークン量を増やしていきましょう！

![increaceTransfer.gif](/images/qiita-928037e3-766c-499e-b2a9-93aa169997d5.webp)

`10000` トークンを追加したところ、`15000` に増えていることが確認できました。

### Goerli Testnetにデプロイ

:::message alert
2025年11月現在Goerli Testnetは停止しているので、Sepolia Testnetなどを使用してください。
:::

では次にGoerli Testnetにデプロイしていきます！

#### Metamask

まだMetamaskを追加していない人は以下から追加してください。

https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn

#### Goerli Testnet ETH

次にGoerli TestnetのETHを取得します。
Faucetと呼ばれところから取得することができます。
いくつか取得する方法があるのですが、以下のAlchemyのFaucetから取得するのがおすすめです。

https://goerlifaucet.com/

24時間ごとに0.5Goerli ETHを受け取ることができます。

#### デプロイ準備

ではここからデプロイの準備をしていきます。

まずはMetamaskをクリックして、Goerli test networkに切り替えてください。
その後Remixに戻って、もし前回デプロイしたデータが残っている場合はゴミ箱マークがあるのでクリックしてください。

次に赤枠の部分を「**Injected Provider - Metamask**」にしてください。
こうすることで、デプロイ時にMetamaskが起動するようになります。
Goerli Testnetが選択されていると、「**Injected Provider - Metamask**」の下に「**Goerli (5) network**」と表示されて、Goerli Testnetと接続されていることが確認できます。

これで準備完了です。

#### Goerli Testnetにデプロイ

ではGoerli Testnetにデプロイしていきましょう！
上記の手順でEtherscanのサイトが確認できれて以下のように「**Success**」と表示されていればデプロイ完了です！

https://goerli.etherscan.io/tx/0x4998868509277a35c7a2bc1484177a877ed436c67ac89eb7f55a6e8e820f6ab6

以下から「**CARDトークン**」が作成されているのを確認できます。

https://goerli.etherscan.io/address/0xdb8452c7df969c6248b3e87d89d1f0d39a1e6836

## 最後に

今回は『**ERC20**』についてまとめてきました。

他でも色々記事を書いているのでぜひよろしければ読んでいってください！

https://amzn.asia/d/gxvJ0Pw

https://cardene.notion.site/EIP-2a03fa3ea33d43baa9ed82288f98d4a9?source=copy_link

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://twitter.com/cardene777

https://cardene.substack.com/

### 参考

- https://bitflyer.com/ja-jp/s/glossary/ico
- https://news.mynavi.jp/techplus/article/20210922-1969988/
- https://fisco.jp/media/erc-20/
- https://www.coindeskjapan.com/keywords/utility-token
- https://phemex.com/ja/academy/イーサリアムのerc-20トークン-知っておくべきすべてのこと
- https://www.ledger.com/ja/academy/blockchain/ercトークンとはなぜ利用すべきのか
- https://eips.ethereum.org/EIPS/eip-20
