【僕が作ったスマコン最強ちゅーとりある】自作通貨でNFTを購入できるようにしたいにゃあ🐱

## 記事を書いたきっかけ

にゃあ。猫になりたいです。大学生をやったり渋谷でエンジニアをやったりしてます、lowzzyです。最近は友達とNFTをせかせか作っております。

NFTを作っている人なら一度は思うでしょう
「NFTを自分たちが発行した通貨で買えるようにしたい、、、！」

はい。僕も思いました。調べるとそれっぽいやつはちょこちょこ出てきますが、大体英語だったり、コードが微妙だったりと、もう少しわかりやすい日本語版書けばNFT挑戦するハードル下がるよなあ。。。

と思ったので書いた所存です。

## 使用する言語とかの説明

いわゆるスマートコントラクトを書きます。solidity。
スマートコントラクトは「契約を締結して自動で処理が走る〜」みたいな説明されることが多いけど、あんまり好きじゃないです。分かりにくいので。誰かが言ってたんですけど、スマートコントラクトは「ちっちゃいプログラム」みたいに思ってくれたら多分大丈夫です。

NFTを生成することを「mint」すると言います。

NFTはERC721とかERC1155とかいろんな規格がありますが、今回はERC1155を採用します。
また、通貨はERC20という規格を採用します。

今回はETHのテストネットであるRinkebyを使います。
rinkebyはテスト環境なのでここでのネイティブ通貨ETHは金銭的価値を持ちません。
https://rinkebyfaucet.com/
faucetというところでETHが貰えるので「rinkeby faucet」みたいに調べてもらってきてください。

NFTはLowzzy, 通貨はLWZという名前で発行します。LWZはとりあえず1000枚発行します。

余談ですが、2021年の終わりにAdidasとコラボしてたBoredApeYachtClub通称BAYCは10億枚発行しているみたいです。

## コード

コードはこちら

### NFT

```
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract Lowzzy is ERC1155, Ownable{
    string baseMetadataURIPrefix;
    string baseMetadataURISuffix;

    uint256 constant SampleTokenId = 0;

    constructor() ERC1155("") {

        // メタデータが取得できるURIをここで定義している
        // URI -> baseMetadataURIPrefix + トークンID + baseMetadataURISuffix

        baseMetadataURIPrefix = "https://staging--goldfish-japan.netlify.app/.netlify/functions/tokenURI/";
        baseMetadataURISuffix = "";
    }

　　// 使用する通貨と、1個当たりの価格を定義してる
    struct TokenInfo {
        IERC20 paytoken;
        uint256 costvalue;
    }

    // publicにしてることで変数callできる
    TokenInfo[] public AllowedCrypto;
    using Strings for uint256;

　　// tokenInfo追加する関数
    function addCurrency(
        IERC20 _paytoken,
        uint256 _costvalue
    ) public onlyOwner {
        AllowedCrypto.push(
            TokenInfo({
                paytoken: _paytoken,
                costvalue: _costvalue
            })
        );
    }

    // uri確かめる関数。
    function uri(uint256 _id) public view override returns (string memory) {
        return string(abi.encodePacked(
            baseMetadataURIPrefix,
            Strings.toString(_id),
            baseMetadataURISuffix
        ));
    }
      // お金払わずにNFTを生成することができる関数です。
     // onlyOwnerとあるように、ownerしか使用できないようにしてます。
　　 //  いらなかったら消してください
    function ownerMint(uint256 _amount) public onlyOwner() {
        _mint(msg.sender, SampleTokenId, _amount, "");
    }

　　// この記事の1番理解して欲しいところ
　　// 第1引数 -> _mintAmount : 生成する数
　　// 第2引数 -> _pid : 使用する通貨
    function publicMint(uint256 _mintAmount, uint256 _pid) public payable {
        TokenInfo storage tokens = AllowedCrypto[_pid];
        IERC20 paytoken;
        paytoken = tokens.paytoken;
        uint256 cost;
        cost = tokens.costvalue;
        require(!paused); // pausedされてたら(paused == trueだったら)エラー吐かせる
        require(_mintAmount > 0);// 0以上かどうか確かめてる(じゃないならエラー)

        // paytoken(この記事だとLWZ)のコントラクトに生えている関数「allowance」を呼び出し
        // おろす許可があるLWZはどれくらいあるかを取得している
        uint256 allowCost = paytoken.allowance(msg.sender,address(this));

        // 許可されているLWZがNFTをmintするのに必要分足りているかを確認している(足りなかったらエラー吐く)
        require(allowCost >= cost * _mintAmount, "Not enough balance to complete transaction.");

        // ここでLWZをこのスマコンのアドレスにtransferしてもらっている(支払い処理)
        paytoken.transferFrom(msg.sender, address(this), cost * _mintAmount);
        // msg.senderのアドレスに_mintAmount個のSampleTokenId番目のトークンをmint(生成)している
        _mint(msg.sender, SampleTokenId, _mintAmount, "");
    }
　　// この関数を使うとトークンのURIが変更できます。
    function setBaseMetadataURI(string memory _prefix, string memory _suffix) public onlyOwner(){
        baseMetadataURIPrefix = _prefix;
        baseMetadataURISuffix = _suffix;
    }
}

```


### 通貨

```
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

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

contract LWZ is ERC20 {

    constructor(
        string memory name,
        string memory symbol,
        uint256 totalSupply_
    ) ERC20(name, symbol) {
        _mint(msg.sender, totalSupply_);
    }

}

```



コードは以上です。

次はRinkebyチェーンへのデプロイについて書きます。

## デプロイ

RemixってIDEを使います。

コード書く~デプロイ~関数呼び出し
など、色々できます。これできればNFTコレクション作れる。

https://remix.ethereum.org


2つのファイルのコードコピペする
![ 2022-08-13 1.47.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/1c2b5750-7cab-ffdf-8698-87a0a3b0d179.png)

左のタブで、上から4番目を押す
![ 2022-08-13 1.47.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/003e587e-d3aa-9ab5-2bbe-044281da2353.png)

environmentとか色々ぽちぽち
![ 2022-08-13 1.48.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/8d17c6ee-953b-0629-c22b-2fd8095ecbd8.png)


Deployボタン押すとメタマスクが発火するので確認してお金を払う。
![ 2022-08-13 1.48.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/3373cc7c-e659-a7ad-77f7-1128504878ba.png)

右上からConfirmed transactionってきたので成功。
![ 2022-08-13 1.48.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/b2d7c5a8-80d4-d3b3-725c-cbe71f6750ff.png)

次は通貨をデプロイするために、LWZを選択。
![ 2022-08-13 1.48.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/28453cfe-d3da-14b8-4b77-f08dbc3e17d3.png)

Deployする時に、1000枚しかLWZ発行しないって言ってたのに、0がめちゃめちゃ多いやん！まちがっているやん！と言われそうですが、これは違います。10^18をつけるのがERC20では一般的です。なので発行総量が1000枚の場合は1000x10^18、つまり1000 000000000000000000をtotal supplyに入れましょう。NameとかSymbolとかはなんでも好きなので良きです。


メタマスクが発火するのでまた同じように確認ボタンを押す。
![ 2022-08-13 3.45.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/588d903b-aed0-e9c1-7dfb-44d76a1e3e63.png)


![ 2022-08-13 3.46.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/a71d3b05-4e49-d13b-c379-ebf042fd30c3.png)



成功。
![ 2022-08-13 1.50.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/1ab17d4e-53e9-2e9c-9298-4f1aad710a37.png)

そしたら、左の方にデプロイされたコントラクトが2つあるはず。Lowzzyって方がNFTで、LWZが通貨。
タブを開くと、生えている関数が見れたりしますね。

![ 2022-08-13 3.48.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/61fe4b69-90d7-6944-8f3b-d7a5dcf322b8.png)


デプロイが終わったら今度はpublicMint(通貨を使用してmint)をしてみましょう。

コントラクトアドレスをコピーして

![ 2022-08-13 3.49.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/8ff9efca-e8e3-dcdc-93a5-2ee98fda2813.png)

AddCurrencyをします。価格(costValue)を10^18するのをお忘れなく(今回は30x10^18にしてる)。第一引数は通貨のコントラクトアドレス(コピーしたやつ)です。


![ 2022-08-13 3.50.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/d9ce210b-8073-56a0-070c-4ddad0cbc9a4.png)

Approveします。お金使っていいよ〜って許可出す処理です。今回は面倒なので全部(1000x10^18)を入力しました。


![ 2022-08-13 3.50.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/efc1629b-947d-1020-bcdb-0676fafccfee.png)


そしたらついにpublicMintです。
先ほど追加した通貨は配列のindex = 0(pid = 0)だと思うので、第一引数に0を入力。
なんとなく5枚欲しいので第二引数には5を入力。

![ 2022-08-13 3.51.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/24c95a47-713f-3458-af72-1aef249a2818.png)

わーい、5枚mintできていました。https://testnets.opensea.io/assets/rinkeby/0x55b9e5c2880c9d7bd31efc385ca6f664df009fa5/0



![ 2022-08-13 3.52.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/52bcb720-1394-8e54-1425-6082a3f2e3d6.png)


1000枚あったLWZ、850枚になっているはずだなあ、確認するか〜ってなったので、トークンをメタマスクにimportして、、


![ 2022-08-13 2.05.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/ba7ea6cb-f08b-1c83-a121-fdb69d7397b6.png)
わあ！850枚になっている！

![ 2022-08-13 2.05.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624133/e3b6ced6-9425-48fd-c906-efdc585889a5.png)

ってことでmint成功ですにゃ


間違えてたりしたら教えてください〜

それでは！