【Solana NFT】@metaplex-foundation/js によってビルドが失敗するようになったら【Umiへの移行】

gm! kishi.solです。

Solana上のNFTデータ取得に @metaplex-foundation/js (https://github.com/metaplex-foundation/js) を利用していましたが、最近このパッケージが原因でビルドがコケるようになりました。

```
- error ./node_modules/@solana/spl-account-compression/dist/cjs/events/index.js:7:0
Module not found: Can't resolve '@project-serum/anchor/dist/cjs/utils/bytes'

https://nextjs.org/docs/messages/module-not-found

Import trace for requested module:
./node_modules/@solana/spl-account-compression/dist/cjs/index.js
./node_modules/@metaplex-foundation/js/dist/esm/plugins/nftModule/operations/createCompressedNft.mjs
./node_modules/@metaplex-foundation/js/dist/esm/index.mjs
```

Metaplex チームに問い合わせてみると、上記パッケージから、Umiフレームワークへの移行を勧められました。
今後の開発でメインとなるのはUmiフレームワークであるとのことです。
UmiフレームワークではNFTのみではなく、幅広いSolanaの利用が可能になっています。

GitHub (Umi): https://github.com/metaplex-foundation/umi

また、cNFT(compressedNFT)と呼ばれる話題の新技術もUmiとmpl-bubblegumというプラグインを使い、実装することが可能です。cNFTではこれまでのSolanaでは120万SOL(現在のSOL価値(28ドル)に換算すると3360万ドル)必要だった1億個のNFTの発行が、およそ50SOL(同じく1400ドル)で行えるようになりました。
大量のNFTを使用することが予想されるゲーム業界においても革新的なアップデートです。

GitHub (Bubblegum):https://github.com/metaplex-foundation/mpl-bubblegum

Bubblegum TypeDocs: https://mpl-bubblegum-js-docs-883v135p0-metaplex.vercel.app/

What's Bubblegum?: https://github.com/metaplex-foundation/mpl-bubblegum/blob/main/programs/bubblegum/README.md


## @metaplex-foundation/jsからUmiへの移行

Solana WalletのPublicKeyから、そのアドレスが所持しているNFTを取得する例を使って、移行方法について説明します。

まずはパッケージのインストール (`@metaplex-foundation/js`はアンインストールしてください)

```
yarn add @metaplex-foundation/umi \
@metaplex-foundation/umi-bundle-defaults \
@metaplex-foundation/umi-web3js-adapters \
@metaplex-foundation/mpl-token-metadata@v3.0.0-alpha.24 
```


以前のコードはこんな感じでした。
```typescript
import { Metaplex } from "@metaplex-foundation/js";
import { Connection, clusterApiUrl, PublicKey } from "@solana/web3.js";

const connection = new Connection(clusterApiUrl("mainnet-beta"));
const metaplex = new Metaplex(connection);
const getUserNFTs = async (publicKey: PublicKey) => {
  const nfts = await metaplex.nfts().findAllByOwner({ owner: publicKey })
  return nfts
}
```

これが、こう変わります。

```typescript
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { fetchAllDigitalAssetByOwner } from '@metaplex-foundation/mpl-token-metadata'
import { clusterApiUrl, PublicKey } from "@solana/web3.js";
import { fromWeb3JsPublicKey } from '@metaplex-foundation/umi-web3js-adapters'

const endpoint = clusterApiUrl("mainnet-beta")
const umi = createUmi(endpoint)

const getUserNFTs = async (publicKey: PublicKey) => {
  const nfts = await fetchAllDigitalAssetByOwner(umi,
  fromWeb3JsPublicKey(publicKey)
)
  return nfts
}
```

※以前と同じ戻り値が欲しい場合は、`nfts.metadata`に格納されています。

モジュール化が進み、`@metaplex-foundation/mpl-token-metadata`などのプラグイン(関数が格納されている)を使うスタイルになっています。
基本的にcreateUmiで作ったUmiインスタンスを目的の関数に渡して使用していきます。


また、注意点として`@solana/web3.js`の`PublicKey`の型とUmiフレームワーク上のPublicKeyの型が違うため、`@metaplex-foundation/umi-web3js-adapters`を使ってUmi用のPublicKeyに変換をしています。

詳しくは下記ドキュメントをご参照ください:
https://github.com/metaplex-foundation/umi/blob/main/docs/web3js-adapters.md

その他のNFTトークンメタデータ関連の扱いについては、下記ドキュメントが参考になります:
https://mpl-token-metadata-js-docs.vercel.app/index.html

※ちなみに`@metaplex-foundation/mpl-token-metadata`は通常ダウンロードするとversion2xが入りますが、チームはversion3xの利用を勧めています。今回使用している`fetchAllDigitalAssetByOwner`もversion2xにはなく、version3xの関数です。



以上になります。

Solana開発全般に言えることですが、新しい技術がたくさん出ている中、まだ各種ドキュメントなど情報がまとまりきっていない節がありますので、今後もぜひみんなで共有していければと思っております。

引き続きよろしくお願いします！