忙しい人のためのSolana Compressed NFT (cNFT)

gm! ELSOUL LABO, Epics DAOの kishi.sol です。

Solanaチェーンはデフォルトでも比較的安価ですが、それでもNFT一つのMintに対して0.012 SOL(35円:SOL=20ドル、1ドル147円で計算)が、線形にスケールするので、10,000個のNFTコレクションでは350,000円、10億個のNFTを作ると350億円(!!!)必要になってしまい、これは現実的ではありません。

ゲーム製作を考えてみても、すべてのアイテムやすべてのプレイヤープロフィールをNFTというデジタル資産にしていこうとする中、この金銭的なコストを削減していく必要があります。

そこで開発されたのが、Compressed NFT (cNFT) という新しいNFTを作る方法です。つい先週、Magic EdenでもcNFTの売買が可能になり、注目の技術となっています。

https://help.magiceden.io/en/articles/8352134-introducing-cnfts-on-magic-eden


cNFTであれば、10,000個のNFTコレクションを約10,290円(34倍)、10億個であっても約147万円(24,000倍)と、現実的なコストでNFTコレクションを発行することができます。

と、とても優れた技術なのですが、絶賛開発中の技術であるため、情報が分散しています。

今回は忙しい人のために、Solana Compressed NFTをMintして使っていくために必要な情報をまとめました。

## Solana Compressed NFT (cNFT) の Mint に必要なもの

Solana Compressed NFT（圧縮NFT, cNFT）は、データ量を削減しながらもその真正性を保証するために、Merkle Tree(マークルツリー)などのデータ構造を用いて効率的に管理されるNFTで、通常のNFTとは違ったアプローチで実現されています。

Read API という機能に対応したSolana RPC エンドポイントが必要です。

https://developers.metaplex.com/bubblegum/rpcs

上記URLにRead API対応のRPCプロバイダが載っています。弊DAOではHeliusを採用しています。

今回はTypeScriptを使ってcNFTをMintしていきますが、それに役立つのが下記のツール・ドキュメント群です。

https://developers.metaplex.com/bubblegum

https://developers.metaplex.com/token-metadata

https://github.com/metaplex-foundation/umi


## cNFT を Mint していく

結論のコードから見たい方はこちら:

https://github.com/elsoul/skeet-solana-mobile-stack/tree/main/scripts/solana/cNFT

Mint 手順としては、下記3ステップです。

1. NFTコレクションの作成 (createNFTCollection.ts)
2. マークルツリーの作成 (createMerkleTree.ts)
3. cNFTのMint (mintCNFT.ts)


#### 手を動かして実際にcNFTをMintしてみましょう、Skeetを使えば、cNFTを含めたSolana開発の環境をすぐに手元へ用意することができます。

```shell
$ npm i -g @skeet-framework/cli
$ skeet create your-app-name
```

![Screenshot 2023-09-18 at 16.01.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780317/e08145d7-964c-ac9d-c271-6aac240d680e.png)

Solana Mobile Stackを選んでください。環境のインストールが始まります。

まずは.envの設定

```shell
NODE_ENV=development
SOLANA_MAINNET_RPC_URL=https://rpc.helius.xyz/?api-key=
SOLANA_DEVNET_RPC_URL=https://devnet.helius-rpc.com/?api-key=
WALLET_FILE=./key.json
# See: nft.storage/docs/quickstart/#get-an-api-token
NFT_STORAGE_KEY=
```

今回はRPCにHelius、ストレージにNft Storageを使います。
どちらもすぐに無料で使い始めることができます。

https://www.helius.dev/

https://nft.storage/

WalletはSolana CLIで作ったものがあれば使用できます。

https://docs.solana.com/cli/install-solana-cli-tools

また、Phantomで作った財布がある場合、jsonに変換するscriptもありますので、ご活用ください。
下記コマンドを流すと、Phantomの Show Private Keyで入手できる文字列を聞かれるプロンプトに入りますので、コピペしてエンターをお願いします。

```shell
$ yarn solana:key:convert (default: key.json)
// 鍵の名前を指定したい場合
$ yarn solana:key:convert -- keyfile.json
```

`your-app-name/scripts/solana/cNFT/config.ts`

```typescript
import { publicKey } from '@metaplex-foundation/umi'
import { format } from 'date-fns'

export const COLLECTION_NAME = 'Skeet The Epics Dev'
export const COLLECTION_SYMBOL = 'STED'
export const COLLECTION_DESCRIPTION =
  'Epics using Skeet. Welcome early adoptooooooooooooors!'
export const FEE_PERCENT = 5.5
export const EXTERNAL_URL = 'https://skeet.dev/'
export const COLLECTION_IMAGE_PATH = 'scripts/solana/cNFT/example/TheDev.png'
export const CREATORS = [
  {
    address: publicKey('YLmoXgFkKFT6V6FumUPgBJXBJ9gAPPoYtacMfoTUPpy'),
    verified: false,
    share: 40,
  },
  {
    address: publicKey('DcLN5EYHBSexnKdipnSmiFAKevcxGijURonzaWfri8Cq'),
    verified: false,
    share: 30,
  },
  {
    address: publicKey('DfCHMeHfRYMBQwMje5bLSqimMWXhArYoTomX2vRr6Ty9'),
    verified: false,
    share: 30,
  },
]
// ステップ1: NFTコレクション作成の後に手に入ります。
export const COLLECTION_MINT = publicKey(
  'itzdT5XgD9cLRtFSTbLAeEqKM3aT3UeSTCJ5h1A9cNN'
)
// ステップ2: マークルツリー作成の後に手に入ります。
export const MERKLE_TREE = publicKey(
  'AqWn6rLoJJvexv9Eyu6MiYyAjzptJqMRTiMnopjRW38Q'
)

export const MINT_ITEM_TO = publicKey(
  'ELLBGa6DTdEVui6Ydt8vqsnsyybAxyVLPwY7oH6onbUq'
)
export const NFT_ITEM_NAME = 'STED Limited Edition #0'
export const NFT_ITEM_IMAGE_URL =
  'https://bafkreihwkrj3su3r6mz5wvmu46h5iriomh2b6njwd3m2s3f6whwd3qxude.ipfs.nftstorage.link/'
export const NFT_ITEM_ATTRIBUTES = [
  {
    trait_type: 'Status',
    value: 'Early adaptooooooooooors',
  },
  {
    trait_type: 'Minted',
    value: format(new Date(), 'yyyy-MM-dd HH:mm:ss'),
  },
]

// To get cNFTs, for now we can't use umi
export const OWNER_ADDRESS = 'ELLBGa6DTdEVui6Ydt8vqsnsyybAxyVLPwY7oH6onbUq'
export const COLLECTION_MINT_ADDRESS =
  'itzdT5XgD9cLRtFSTbLAeEqKM3aT3UeSTCJ5h1A9cNN'

```

コンフィグや画像は適宜置き換えてください。

COLLECTION_MINTはステップ1、MERKLE_TREEは、ステップ2でそれぞれ入手可能です。


### 1. NFTコレクションの作成 (createNFTCollection.ts)

画像や設定を変更したら、(変更しなくても大丈夫です)下記コマンドを流します。

```shell
$ yarn solana:nft:create:collection
```
コンソールとexampleフォルダ内に、必要なアドレスが出力されます。
ここで手に入るcollectionMintのアドレスを、`config.ts`のCOLLECTION_MINTのpublicKey内文字列と置き換えてください。


### 2. マークルツリーの作成 (createMerkleTree.ts)

COLLECTION_MINTを正しく置き換えたら、マークルツリーを作成します。

コマンドは:

```shell
$ yarn solana:nft:create:merkleTree
```

同じく、これで手に入るmerkleTreeのアドレスを、`config.ts`のMERKLE_TREEのpublicKey内文字列と置き換えてください。

### 3. cNFTのMint (mintCNFT.ts)

MERKLE_TREEの文字列を正しく置き換えて、NFT_ITEM_IMAGE_URL (ステップ1で手に入るURLを使えば、コレクションと同じ画像のアイテムが作成されます。別途画像をnft.storageにアップロードすれば、アイテム画像を変えることも可能です)を設定してください。

MINT_ITEM_TO は、cNFTをMintする先のアドレスです。

NFT_ITEM_ATTRIBUTES は
```typescript
type Attribute = {
    trait_type: string,
    value: string
}
```
で、複数個追加できます。

各種設定を確認したら、下記コマンドでMint可能です

```shell
yarn solana:nft:mint:cnft
```

nftItemMint: として、Compressed NFTのトランザクションを確認できるURLが表示されます。

![Screenshot 2023-09-18 at 16.55.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780317/78e0831e-3cf4-a18a-afc5-3ddebc0bf93a.png)


## Mint された cNFT のデータを確認

Phantomウォレット上でもMintされたcNFTが確認できるはずです。

ここでは、cNFTデータを取得するNode.jsスクリプトについても確認しておきましょう。

### cNFTデータの取得 (getCNFT.ts)

`config.ts`の、OWNER_ADDRESS、COLLECTION_MINT_ADDRESSから、それぞれそのオーナーの持つアセット(OWNER_ADDRESS)、NFTコレクションに含まれるアセット(COLLECTION_MINT_ADDRESS)をReadAPIを使って取得することができます。
このスクリプトは下記コマンドで実行できます。

```shell
$ yarn solana:nft:get:cnft
```

各コードはこちらからご覧いただけます。(GitHub)

https://github.com/elsoul/skeet-solana-mobile-stack/tree/main/scripts/solana/cNFT

Skeetドキュメントはこちらです:

https://skeet.dev/ja/

今回は Solana Compressed NFT (cNFT) を Mint する方法についてまとめました。

何かありましたらぜひコメントいただければ嬉しいです。

次はこのCompressed NFTを実際にアプリへ組み込んでいく方法について書きたいと思います。

それではまた！