[ERC677] ERC223をベースにトークンを受け取ったことを通知する幻の規格を理解しよう！

# はじめに

初めまして。
**CryptoGames**というブロックチェーンゲーム企業でエンジニアをしている **cardene（かるでね）** です！
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームは**クリプトスペルズ**というブロックチェーンゲームです。

https://cryptospells.jp/

今回は、**ERC20**と互換性を持たせつつ**ERC223**の仕組みを活用して、トークンを受け取ったことを通知する仕組みを提案している幻の**ERC677**についてまとめていきます！

:::note info
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
:::

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

他にも様々なEIPについてまとめています。

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

:::note alert
この規格はGithubでの議論にとどまっていて、正式なERC標準としてまとめられていません。
以下のGithubで色々議論されていますが、数年前に**Closed**となっているため正式なERCとして採用されるのは難しそうです。
ただ、仕組みとしては使えると思うので今回記事にまとめました。
あくまでERC（仮）と認識した上で記事を読んでください。
:::

https://github.com/ethereum/EIPs/issues/677

# 概要

この規格では、**ERC20**トークンに`transferAndCall`という関数を追加する提案をしています。
この関数は、**ERC20**トークンをコントラクトに`transfer`し、追加のデータを渡すことができます。
これにより、トークンが`transfer`された後にコントラクトが特定の処理を実行することが可能になります。

:::note info
**ERC20**については以下の記事を参考にしてください。
:::

https://chaldene.net/erc20

# 動機

現在（当時）、**ERC20**トークンをContractに`transfer`するには以下の複数の手順が必要です。

1. **ERC20**コントラクトで`approve`関数を実行して、コントラクトがトークンの`transfer`をできるようにします。
2. コントラクトに通知をして、**ERC20**トークンを`transfer`できるようになったことを知らせます。
3. コントラクトが実際に**ERC20**トークンを`transfer`し、**ERC20**トークンの受け取りに関連する処理を実行します。

上記の手順は2~3ステップ必要なため、非効率でUXが悪いです。

**ERC223**はこの問題を解決するために設計されましたが、既存の**ERC20**トークンを互換性がありません。
**ERC223**では、**ERC20**コントラクトの`transfer`関数を拡張して、`onTokenTransfer`を実装していないコントラクトに`transfer`する場合エラーを返すようにしています。
これにより、マルチシグウォレットのような既存のコントラクトがトークンを受け取る時、トークンの`transfer`元のコントラクトにロックされる可能性があります。

:::note info
**ERC223**では、**ERC20**トークンを`transfer`する時、送り先のアドレスがコントラクトの場合にそのトークンを受け取ることができるかをチェックします。
チェック方法としては、`tokenReceived`という関数を実行して`transfer`処理を実行し、もしなければエラーを返すというような仕組みです。
**ERC223**については以下の記事を参考にしてください。
:::

https://qiita.com/cardene/items/0e0ef7a1c17989689796

この規格では、**ERC223**の機能を提供しながら、**ERC223**の問題を回避する提案をしています。
この提案では、`transferAndCall(address receiver, uint amount, bytes data)`という新しい関数を導入します。
この関数は、トークンを受け取りアドレスに`transfer`し、追加のデータと共に受け取りコントラクトの`onTokenTransfer`関数を呼び出します。
この規格で提案されている`transferAndCall`関数は、**ERC223**の`transfer(address,uint256,bytes)`関数と似ていますが、名前が異なるため明確に区別できます。
これにより、既存の**ERC20**コントラクトとの互換性を維持しながら、トークン`transfer`時の新しい機能を提供できます。
将来的には、より多くのコントラクトが`tokenReceived`を実装し、**ERC223**トークンを取り扱えるようになります。

# 仕様

## トークンコントラクト

```js
function transferAndCall(address receiver, uint amount, bytes data) returns (bool success)
```

**ERC20**の`transfer`関数を使ってトークンを`receiver`に指定されたアドレスに`transfer`します。
その後、以下の処理を行います。

まず、`Transfer(address, address, uint256, bytes)`というイベントをログに記録します。
次に、トークンコントラクトはトークン受け取りコントラクトの`onTokenTransfer`関数を呼び出します。
この関数には以下のパラメータが渡されます。
- `sender`
    - トークンを送ったアドレス
- `amount`
    - `transfer`されたトークンの量
- `data`
    - 追加のデータ（例えば、トークンの`transfer`理由を示すためのもの）

## トークン受け取りコントラクト

```js
function onTokenTransfer(address from, uint256 amount, bytes data) returns (bool success)
```

この関数は、トークンを受け取るコントラクトに追加され、単一のトランザクション内でトークンを受け取ったことを通知できるようにします。

# 互換性

この規格は全ての**ERC20**トークンとコントラクトに対して互換性があります。
新しく作成されたトークンとコントラクトは`transferAndCall`機能を実装でき、既存のコントラクトでは`approve` + `transferFrom`ワークフローを使用することができ、特に何か変更をしたり追加の手順は不要です。

# 実装

以下のGithubに実装コードが格納されています。

https://github.com/smartcontractkit/LinkToken/blob/master/contracts/v0.4/ERC677Token.sol

# 最後に

今回は「**ERC20**と互換性を持たせつつ**ERC223**の仕組みを活用して、トークンを受け取ったことを通知する仕組みを提案している幻の**ERC677**」についてまとめてきました！
いかがだったでしょうか？

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください！

[Twitter @cardene777](https://twitter.com/cardene777)

他の媒体でも情報発信しているのでぜひ他も見ていってください！

https://chaldene.net/

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

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