AlchemyでNFTをMintする。

ここを参考に補足しました。
https://docs.alchemy.com/alchemy/tutorials/how-to-create-an-nft

## Metaファイル
まずは適当なイメージを、例えばGoogle Cloud Storageなどにアップロードして公開します。
その後、下記のようなJSONファイルを作って、こちらも公開しておきます

大事なのはJSONファイルを格納するフォルダで、フォルダのURLが `BASE TOKEN URL` となります。ファイル名は必ず  **数字(uint256)** にします。**拡張子はつけません**。数字は0からでなくてもよいです。

```json:/base_url/0
{
    "name": "Item Name",
    "description": "Description",
    "image": "https://url.png"
}
```

## プロジェクト作成
nvm や yarn は設定済みだとします。nodeは17.xx はエラーが出るので16.xxを使います。


```bash
nvm use 16.14.0 # DO NOT USE 17.xx.xx
mkdir my-nft
cd my-nft
yarn init –y
yarn add --dev hardhat
yarn hardhat
# SELECT => Create an empty hardhat.config.js
yarn add @openzeppelin/contracts ethers @alch/alchemy-web3
yarn add --dev dotenv @nomiclabs/hardhat-ethers

mkdir contracts
mkdir scripts
```

ここ使っている [Hardhat](https://hardhat.org/) はローカルChainなどを起動できるBlockchain用の開発ツール群です。類似プロダクトに[Truffle](https://github.com/trufflesuite/truffle/tree/master/packages/contract)があります。

[OpenZeppelin](https://openzeppelin.com/) はBlockchain用のライブラリ集です。

## Contract

NFTをChain上に生成するにはContractが必要になります。Solidityという言語で書き、BinaryにコンパイルしChain上にdeployします。

Contractには最低限、下記の情報が必要になります。

- コントラクト名（MyNFTとか）
- シンボル （MYTとか）
- BASE TOKEN URL （メタJSONの格納フォルダ） 


```solidity:contracts/MyNFT.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;
import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol";
contract MyNFT is ERC721PresetMinterPauserAutoId {
  constructor()
    ERC721PresetMinterPauserAutoId(
      "MyNFT",
      "MYT",
      "https://storage.for.meta/"
    )
  {}
}
```

##  Deploy Script
`contracts/MyNFT.sol`と`hardhat.config.js`のSolidityのバージョンの整合性を取るよう修正します。
デプロイファイルを作成します。

```js:scripts/deploy.js
async function main() {
  const MyNFT = await ethers.getContractFactory('MyNFT');
  const myNFT = await MyNFT.deploy(); // Instance of the contract
  console.log('Contract deployed to address:', myNFT.address);
}

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

##  Localhostへデプロイ
まずはLocalhostへデプロイしてみます。まずは、ローカルにBlockchainのノードを起動します。

```bash
yarn hardhat node
# Account #0: 0x012abc... (10000 ETH)
# Private Key: 0x012abc...
```
アカウント情報が表示されるので、１番目の公開アドレスとプライベートキーをメモしておきます。

nodeプロセスはそのままにして、別ターミナルなどで下記スクリプトを実行するとローカルへデプロイできます。

```bash
yarn hardhat run scripts/deploy.js
# Contract deployed to address: 0x0123abc...
```

ここで表示されるアドレスが`CONTRACT ADDRESS`です。

## 設定ファイル
実際Mintするにはこの`CONTRACT ADDRESS`アドレスや自分の`PRIVATE KEY`などが必要になるんですが、LocalhostとRinkebyの両方にデプロイしたいので、設定ファイルを作りたいと思います。このファイルには秘密鍵が書かれるので**絶対公開しない**でください。

```json:config/default.json
{
  "localhost": {
    "public_key": "0x0123abc...",
    "private_key": "0x0123abc...",
    "provider_url": "http://localhost:8545",
    "contract": {
      "address": "0x0123abc..."
    }
  }
}
```

それぞれ次の値を設定します。
- public_key : ローカルノードのアカウントの公開鍵（アドレス）
- private_key : ローカルノードのアカウントの秘密鍵
- provider_url : ロカールは変更しなくていいです。
- contract / address : ここに先ほどデプロイした`CONTRACT ADDRESS`を設定します。


## ローカルにMint
mintファイルを作成します。

```js:scripts/mint.js
const hre = require('hardhat');
const Web3 = require('web3');
const Config = require('config');
const { createAlchemyWeb3 } = require('@alch/alchemy-web3');
const Contract = require('../artifacts/contracts/MyNFT.sol/MyNFT.json');

async function main() {
  const config = Config[hre.network.name];
  const web3 = createAlchemyWeb3(config.provider_url);
  const contract = new web3.eth.Contract(Contract.abi, config.contract.address);
  const nonce = await web3.eth.getTransactionCount(config.public_key, 'latest');

  const tx = {
    from: config.public_key,
    to: config.contract.address,
    nonce: nonce,
    gas: 500000,
    data: contract.methods.mint(config.public_key).encodeABI(),
  };

  const signedTx = await web3.eth.accounts.signTransaction(
    tx,
    config.private_key
  );
  const transactionReceipt = await web3.eth.sendSignedTransaction(
    signedTx.rawTransaction
  );
  console.log(`Transaction Hash: ${transactionReceipt.transactionHash}`);
}
main();
```

Mint on local network.

```bash
yarn hardhat run scripts/mint.js
```

## RinkebyのETH取得

テストネットワークでも、デプロイするためにはガス代が必要になります。現金は必要なく、下記のようなFaucet（蛇口）と呼ばれるサイトで取得することができます。

[Goerli Testnet Faucet](https://goerli-faucet.slock.it/).

## Rinkeby APIキー取得

[Alchemy](https://dashboard.alchemyapi.io/) にアカウントを作って `API URL` を取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55938/2f89dc5c-a552-1f1c-045b-8757eb066f3f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55938/8fe3fe85-227a-849e-1925-27a9751ade3f.png)

## 設定ファイル
Rinkebyの設定を記入します。

```json:config/default.json
{
  "localhost": {
  ...
  },
  "rinkeby": {
    "public_key": "0x0123abc...",
    "private_key": "0x0123abc...",
    "provider_url": "https://eth-rinkeby.alchemyapi.io/v2/0x0123abc...",
  }
}
```

それぞれ次の値を設定します。
- public_key : 自分のWalletの公開鍵（アドレス）
- private_key : 自分のWalletのアカウントの秘密鍵
- provider_url : Alchemyの `API URL`

## Rinkebyへデプロイ
Rinkebyでデプロイします。少し時間がかかります。ETHがある程度無いとガス代不足のエラーになります。

```bash
yarn hardhat run scripts/deploy.js --network rinkeby
# Contract deployed to address: 0x0123abc
```

デプロイが終わると `CONTRACT ADDRESS`が得られるので、そのアドレスを設定ファイルに記載します。

```json:config/default.json
{
  "rinkeby": {
    "public_key": "0x0123abc...",
    "private_key": "0x0123abc...",
    "provider_url": "https://eth-rinkeby.alchemyapi.io/v2/0x0123abc...",
    "contract": {
      "address": "0x0123abc"
    }
  }
}
```


## RinkebyへMint
Mintはデプロイと同じようにするだけです。

```bash
yarn hardhat run scripts/mint.js --network rinkeby
# Transaction Hash: 0x0123abc
```

トランザクションのHashが表示されるので、[Rinkeby Etherscan](https://rinkeby.etherscan.io/)で処理の状態を確認します。

その後、[OpenSea Testnets](https://testnets.opensea.io/)で画像が出ているかどうかを確認します。画像が出てない場合、メタファイルへのパスが間違ってる場合があります。メタファイル拡張子がついてると参照できません。メタファイルを変更した場合、OpenSea上でメタファイルのリフレッシュ機能を利用することができます。