# [ERC4521] ERC20コントラクトが安全にERC721形式のNFTを送付する仕組みを理解しよう！

> ERC721はEthereumブロックチェーン上でユニークなデジタル資産（NFT）を扱う標準規格です。

- URL: https://cardene.dev/articles/64f88dab5c6f513e35ca
- 公開日: 2025-05-01
- 更新日: 2025-05-01
- トピック: Blockchain
- タグ: ethereum, solidity, smartcontract, ブロックチェーン

## はじめに

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

https://amzn.asia/d/gxvJ0Pw

今回は、**ERC20**コントラクトが安全に**ERC721**トークンを送付する仕組みを提案している**ERC4521**についてまとめていきます！

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

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

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

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

## 概要

**ERC721**はEthereumブロックチェーン上でユニークなデジタル資産（NFT）を扱う標準規格です。
NFTを別のアドレスに送付するための`transferFrom()`や、移動先がコントラクトの場合に安全性を検証する`safeTransferFrom()`といった関数が用意されています。
しかし、**ERC20**という同じ価値を持つトークンを扱う規格で使用されている`transfer()`関数は定義されていません。
**ERC20**の`transfer()`は多くのコントラクトやウォレットがトークン送信の基本機能として期待しているため、このままだとNFTを**ERC20**向けのシステムで扱う時に互換性の問題が生じます。
**ERC4521**では、既存の仕組みと後方互換性を保ちつつ、NFTにも同名の`transfer()`関数を追加する方法を示しています。

### 動機

**ERC4521**の背景には二つの課題があります。  

- **誤送信によるロックリスクへの対処**  

**ERC20**用コントラクトやウォレットが`transfer()`のみをサポートしている場合、NFTを誤って送信すると取り出せなくなる可能性があります。
  NFTにも同じ`transfer()`を用意することで、こうした誤送信時のロックリスクを軽減できます。  

- **コントラクト実装の簡素化**  

開発者が**ERC20**トークンとNFTで異なる関数を実装・管理する必要があると、コントラクトが複雑になります。
どちらにも対応する共通の`transfer()`を使えるようにすることで、実装の手間を減らし、開発効率を向上させることができます。

## 仕様

**ERC4521**の`transfer`インターフェースは、**ERC20**に準拠する必要があります。
また、`transfer`関数の実行時には`Transfer`イベントを発行させる必要があります。

```js
function transfer(address to， uint256 tokenId) external returns (bool success);
```

## 補足

**ERC20**の`transfer`関数をそのまま実装することでNFT用に別途複雑な処理を追加せずに済みます。
具体的には、**ERC20**では「送信する量（`amount`）」を受け取る引数を、NFT用には「送信する識別子（`tokenId`）」に置き換えるだけです。
このように関数名やシグネチャをほぼ共通化することで、開発者は新たに別関数を実装せず、既存の`transfer`呼び出しのままNFTを扱えるようになります。結果としてコードの行数が減り、可読性や保守性が向上します。

## 参考実装

```js
function transfer(address to, uint256 tokenId) public virtual returns (bool success) {
        require(msg.sender == ownerOf[tokenId], "NOT_OWNER");

        unchecked {
            balanceOf[msg.sender]--; 
        
            balanceOf[to]++;
        }
        
        delete getApproved[tokenId];
        
        ownerOf[tokenId] = to;
        
        emit Transfer(msg.sender, to, tokenId); 
        
        success = true;
}
```

## セキュリティ

**ERC20**と同じインターフェイスを実装する場合、`transfer`関数は成功時に必ず`bool`型の戻り値を返す必要があります。
これを省略すると、既存の**ERC20**互換コントラクトが失敗と判断し、NFTが送金先でロックされたまま取り出せなくなる恐れがあります。

### `safeTransfer`との併用  
`safeTransfer()`系の関数は受け取り側コントラクトが正しく実装されていることを確認できる仕組みを持つため、ロックのリスクを軽減できます。
しかし、全てのシステムが`safeTransfer()`を利用するわけではないため、`transfer()`にも必須の戻り値を含めておくことで安全性が向上します。

## 引用

Ross Campbell (@z0r0z), "ERC-4521: 721/20-compatible transfer [DRAFT]," Ethereum Improvement Proposals, no. 4521, December 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-4521.

## 最後に

今回は「**ERC20**コントラクトが安全に**ERC721**トークンを送付する仕組みを提案している**ERC4521**」についてまとめてきました！
いかがだったでしょうか？

質問などがある方は以下の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
