プログラミングのゴミ箱

日々の学習の中で知らなかったことについて、調べたことを解説します。

ERC721のNFTをERC20のトークンでmintする

ERC721で作ったトークンをERC20のトークンを支払うことでmintする仕組みを作ろうと思ったときに、意外と手間取ったのでそのやり方を書いていきます。
この記事は、Remix IDEを使ったことがある人が対象です。

ERC20, ERC721のトークンを作る

簡単に、OpenZeppelinのwizard機能を使って作っていきます。
docs.openzeppelin.com

↓コード
ERC20.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

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

contract MyToken is ERC20 {
    constructor() ERC20("MyToken", "MTK") {
        _mint(msg.sender, 10000 * 10 ** decimals());
    }
}

ERC721.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract MyToken is ERC721, Ownable {
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIdCounter;

    constructor() ERC721("MyToken", "MTK") {}

    function safeMint(address to) public onlyOwner {
        uint256 tokenId = _tokenIdCounter.current();
        _tokenIdCounter.increment();
        _safeMint(to, tokenId);
    }
}

ERC721.solの中でERC20.solのコードを実行できるようにする。

OpenZeppelinのIERC20というライブラリをインポートすると、トークンのアドレスからそのトークンの関数を実行できるようになる。

ERC721.sol

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; // ライブラリのインポート
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract MyToken is ERC721, Ownable {
    using Counters for Counters.Counter;
    IERC20 public tokenAddress;
    uint256 rate = 100 * 10 ** 18; // NFTのmintに100 Token必要

    Counters.Counter private _tokenIdCounter;

    constructor(address _tokenAddress) ERC721("My Token", "MTK") {
        tokenAddress = IERC20(_tokenAddress); // 最初に参照先のアドレスを指定。
    }
...

safeMint内でERC20の関数を実行

safeMintの中でERC20のtransferFrom関数を実行する。
ERC721.sol

...
    function safeMint() public {
        tokenAddress.transferFrom(msg.sender, address(this), rate);
        uint256 tokenId = _tokenIdCounter.current();
        _tokenIdCounter.increment();
        _safeMint(msg.sender, tokenId);
    }
...

コントラクトのdeploy & 実行

まずは、ERC20.solをデプロイ。普通にデプロイボタンを押すだけで大丈夫。
デプロイが完了したらコントラクトアドレスをコピーしておき、ERC721のデプロイ時に使用する。
ERC721のデプロイが完了したら、早速使ってみる。
普通にsafeMintを呼び出すとエラーが起きるので、まずはERC20.solの「approve」関数を実行しておく。mintに必要なトークン量は100 Tokenなので、「100 * 10 ** 18」をapproveする。spender引数にはERC721のコントラクトを入れる。approveが成功したら、safeMintが実行できるので実行する。
safeMintが完了したら、本当にmintされているか確認する。「balanceOf」関数にsafeMintを実行したときのアカウントのアドレスを入れる。1という値が帰ってきたら成功だ。

終わり

今回の方法はコントラクトアドレスさえわかれば既存のERC20 Tokenにも応用できるので一気にコードの幅が広がります!皆もぜひやってみてね!