【Node.js】コードからNFTを作成する方法


Alchemyのサイトを参考に、Node.jsでNFTをミントしてみました。
https://docs.alchemy.com/docs/how-to-mint-an-nft-from-code

## 私の環境
- Node.js: v20.0.0
- テストネットワーク：Goerli　
- 開発環境： VS Code

※2024年に入りGoerli　が使えなくなりました。
テストネットSepoliaについてはこちらをご確認ください。
https://www.alchemy.com/overviews/migrate-to-sepolia


## 準備

### 画像

NFTにしたい画像を用意する
<IMG SRC="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291592/ce5e14bd-acf0-df40-84fb-5cde4900f206.jpeg" width=50%></IMG>

<br>
画像を簡単にIPFSにできるPinataを使う。

https://www.pinata.cloud/

Pinataはアカウントなくても（ログインしなくても）使える。
「Start Building」をクリック
[![Image from Gyazo](https://i.gyazo.com/80c17e5494039fdc736a3c2164019e85.png)](https://gyazo.com/80c17e5494039fdc736a3c2164019e85)

「Upload」をクリック
[![Image from Gyazo](https://i.gyazo.com/7699dca751a510f1e7270c7e83de3896.png)](https://gyazo.com/7699dca751a510f1e7270c7e83de3896)

アップロード後
ハッシュ値をコピーする
[![Image from Gyazo](https://i.gyazo.com/3bdb8f8d4f94b0569f0a68a56a7d3146.png)](https://gyazo.com/3bdb8f8d4f94b0569f0a68a56a7d3146)

アップロードしたファイルは、以下のサイトで見ることができる。
```
https://gateway.pinata.cloud/ipfs/<ハッシュ値>
```

<br>

### NFTのメタデータ作成

OpenSea の標準を参考に
メタデータのJSONファイルを作成する。

OpenSea の標準はこちら参照
https://docs.opensea.io/docs/metadata-standards

```nft-metadata.json
{
  "description": " ", 
  "external_url": "", 
  "image": "https://gateway.pinata.cloud/ipfs/<ハッシュ値>", 
  "name": "Cats",
  "attributes": [ ... ]
}
```

このJSONファイルを再度Pinataにアップロードする。

アップロード後、JSONファイルのハッシュ値をコピーしてどこかに控える。


以下が、のちほどのコードの変数tokenUriの値になる
```
https://gateway.pinata.cloud/ipfs/<メタデータJSONファイルのハッシュ値>
```

<br>

### Remixでスマートコントラクト作成

こちらを参考
https://qiita.com/tatsuya1970/items/2381d21399a19f349e57

作成したコントラクトのABIをコピーしてどこかに控えておく。
<IMG SRC="https://i.gyazo.com/00b1a464c01088f56ade3bd89c96fdcb.png" width=50%></IMG>

<br>

### Alchemy API キーの作成

Alchemy にアクセスする。
https://www.alchemy.com/

「Apps」 > 「Create App」

[![Image from Gyazo](https://i.gyazo.com/641b7ba716e20f3947e8a99477a37886.png)](https://gyazo.com/641b7ba716e20f3947e8a99477a37886)


チェーンとネットワークを選び、
アプリ名前を記入し
「Create app」をクリックする。

[![Image from Gyazo](https://i.gyazo.com/9a4c2932e55ca02f79dfc2e939572949.png)](https://gyazo.com/9a4c2932e55ca02f79dfc2e939572949)

API Key をクリック
[![Image from Gyazo](https://i.gyazo.com/0efb6e704cd6a58774f4dad85efdd5f6.png)](https://gyazo.com/0efb6e704cd6a58774f4dad85efdd5f6)

API Key と　HTTPSをどこかに控えておく。

[![Image from Gyazo](https://i.gyazo.com/184e88fd5f4c22bc07115625ace35ef9.png)](https://gyazo.com/184e88fd5f4c22bc07115625ace35ef9)


### 環境変数の設定

ルートディレクトリで
Ethereumブロックチェーンのライブラリ ethers.js と
環境変数設定のライブラリ dotenv をインストールする。

```
$ npm install --save ethers
$ npm install --save dotenv
```

ルートディレクトリに .envファイルを作成し、
環境変数を設定する。

```.env
API_URL = "AlchemyのHTTP"
API_KEY = "AlchemyのAPIキー"
PRIVATE_KEY = "自分のMetamaskの秘密鍵"
```
<br>

同じくルートディレクトリに先ほどRemixで作成したNFTのコントラクトのABIをコピーして「abi.json」　というファイルを作る。



## スクリプトの作成


```mint-nft.js
'use strict';
require('dotenv').config();
const { ethers } = require("ethers");

// Get Alchemy API Key
const API_KEY = process.env.API_KEY;
const provider = new ethers.AlchemyProvider('goerli', API_KEY)
const privateKey = process.env.PRIVATE_KEY

const signer = new ethers.Wallet(privateKey, provider)
const abi = require("./abi.json")

const contractAddress = 'さきほどRemixで作成したNFTのコントラクトアドレス' 

// Create a contract instance
const myNftContract = new ethers.Contract(contractAddress, abi, signer)

const tokenUri = "https://gateway.pinata.cloud/ipfs/<メタデータJSONファイルのハッシュ値>"

// Call mintNFT function
const mintNFT = async () => {  
    let nftTxn = await myNftContract.safeMint(signer.address, tokenUri)
    await nftTxn.wait()
    console.log(`NFT Minted! Check it out at: https://goerli.etherscan.io/tx/${nftTxn.hash}`)
}

mintNFT()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });
```

<br>

実行
```
$ node mint-nft.js
```

このメッセージがでたら、NFTのミント成功です。
```
NFT Minted! Check it out at: https://goerli.etherscan.io/tx/........
```

<br>

Openseaのテストネットで確認すると、NFTができてます。

https://testnets.opensea.io/ja


![スクリーンショット 2023-10-30 22.35.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291592/b0df0cbe-260c-1f72-0504-68a6741be480.png)



 以上です。