Nember ArtのNFTを一覧取得する

:::note warn
Nember Artはサービスを終了しており、本記事の内容は投稿時点での内容となります。
:::

# はじめに

Nember Artとは、Symbolブロックチェーンのテストネットを使ってNFTアートを扱うことができるプラットフォームです。（私の解釈）

https://nember.art/

作成されたNFTは、ブロックチェーンに乗っかっているデータなので、他のサイトでも見れたりするのが必然かなと思います。そういう閲覧用のサイトをいろんな人が作っていくのを見てみたい気がします。

そのようなものを作るためには、NFTの一覧を取得することが必要になってくるような気がします。しかし、SymbolブロックチェーンにはNFTの専用機能はないため、Nember ArtがどのようにNFTを作成（表現）しているのかを調べ、そこから一括で取得できる方法を探っていく感じになります。

なので、実際に出品してみて、どのようなトランザクションが送信されたかを見ていこうと思います。

# まずは試しに出品してみる

nember.artにログイン（新規登録）し、クレジットを入金、NFTを作成します。次に、アグリゲートボンデッドトランザクションが送信されるので、Symbolウォレットを使って連署します。

そしてこれが作成したNFTになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/9117e039-d0a7-e23c-2ba1-b2ee1d16f924.png)

https://nember.art/en/art?id=62ABCEEE8DE18772

画像が表示されないかもしれませんが、そちらはIPFSの仕様によるものかもしれません。

サムネイルの下にある「Check NFT on Symbol Explorer」をクリックすると、ブロックエクスプローラーでモザイクの情報が表示されます。

http://explorer.testnet.symboldev.network/mosaics/62ABCEEE8DE18772

また、作成時に送信されたアグリゲートボンデッドトランザクションはこちらです。

http://explorer.testnet.symboldev.network/transactions/C172817D4B78D179872B5CC588C81D462DBA6C9C64FDC14550B9690DC45CE7EE

# 情報を見ていく

さて、nember.artで作成されたNFTを一括取得できるような情報がないかを探していきます。

## モザイクメタデータから収集

モザイクの基本的な情報です。

発行者は私のアドレス（TAAN～）に、発行数量（Supply）は1に、期限切れ（Expired）はなく、数量変更（Supply Mutable）もできないようになっています。

ちなみに、いま誰が所有しているかは表示されません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/d8df8429-0caf-3753-8af2-fa9b07e8ce90.png)

（なぜかSupplyが2つありますね。）

次に、リストリクションとメタデータです。リストリクションはできない設定になっているためついておらず、メタデータにはNFTのタイトルと説明、IPFSハッシュが記録されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/37744f92-e570-ddba-9d80-a38d14487d47.png)

また、メタデータのScoped Metadata Keyについて、他のいくつかのNFTを見ましたが、すべて`F692E3C90BF01257`固定のようです。

なので、これを使って一覧取得することができますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/9c2c7a71-9b31-3a3b-8479-0b29d974b09b.png)

URLを貼っておきます。いつか見れなくなるかもしれません。

http://ngl-api-001.testnet.symboldev.network:3000/metadata?scopedMetadataKey=F692E3C90BF01257&metadataType=1&pageSize=20&pageNumber=1

## アグリゲートボンデッドトランザクションから収集

こちらは、NFTを作成したときのトランザクションです。

アグリゲートボンデッドトランザクションがNEMBER ART側から送信されますので、自分のウォレットでそれに連署をしました。

http://explorer.testnet.symboldev.network/transactions/C172817D4B78D179872B5CC588C81D462DBA6C9C64FDC14550B9690DC45CE7EE

ブロックエクスプローラーのグラフィック表示の箇所を見ていきます。こちらは、アグリゲートボンデッドトランザクションの内部トランザクションなどが視覚的に表現されています。


「Aggregate Bonded」の下には、送信者がサービス側のアドレス（TAKP）であり、連署者が私（TAAN）であることが表示されています。

その下に内部トランザクションが表示されており、1つ目では、サービス側のアドレス（TAKP）が自分自身に0XYMを送信しており、残り3つで私のアドレス（TAAN）がモザイクを作成してメタデータを付与しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/b3fcfeba-6d3f-6cfd-d8ae-945d247792cf.png)

いくつかのNFTを作成したときのトランザクションを見てみましたが、以下のような共通点がありました。

* 送信者は必ずサービス側のアドレス（TAKP）です。
* アグリゲートボンデッドトランザクションです。
* モザイク作成とメタデータ作成が同時に行われます。

※1つめの内部トランザクションで、メッセージに`NEMBER.ART`という内容が添えられていますが、これはNFTを作成するとき以外にも付いているようです。

なので、TAKPのアドレスが送信したアグリゲートボンデッドトランザクションを取得して、その中にモザイク作成やモザイクメタデータの内部トランザクションがあるものをフィルターすると取得することができます。

これをすべてAPIで取得することはできないので、プログラムを書くことになります。以下は、TAKPのアドレスのアグリゲートボンデッドトランザクション一覧です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/56c03b37-6016-efa7-1b03-446d99417d0b.png)

http://ngl-api-001.testnet.symboldev.network:3000/transactions/confirmed?address=TAKPHWV4SIXXWLIGU2XVIS2Y4XH2ECM4SGYAO7A&type=16961&pageSize=20&pageNumber=1

しかし、このエンドポイントでは内部トランザクションまでは見れないので、`POST /transactions/confirmed`などを使ってさらに詳細を取得する必要があります。

# 考察

## モザイクメタデータ

モザイクメタデータをフィルターして一覧を取得する方法について考えます。

この方法の利点は、お手軽な点だと思います。ブラウザ完結のビューワなんかに使えるかもしれません。

欠点としては、NFTでも何でもないモザイクに、同じキーでメタデータが追加された場合に判別ができないことです。この対策のためにモザイクの情報を取ってきて検証しなければなりません。

あまり重要ではないかもしれませんが、ソートなどをすることが難しいです。作成者順やタイトル順にするなどはできないかもしれません。（API応答にはmongoDBのIDが入っていて、さらにこれでソートされてるので、日付順には並んでいる）

そしてさらに、メタデータが書き換えられた場合に、それを検知することができません。

## トランザクションデータ

トランザクションをフィルターして一覧を取得する方法について考えます。

この方法の利点は、バッチ処理化しやすい点だと思います。例えば新しいブロックが生成されたタイミングで、その中にあるトランザクションを対象にフィルターして、順次データベースに追加していくようなことができると思います。

メタデータが途中で書き換えられたとしても、トランザクション送信者はサービス側のアドレスではないでしょうから、そういうのはフィルターで弾けばよいです。

欠点としては、サーバーサイドが必要になるため少しお手軽感が減る点だと思います。

あとは、サービス側が使用しているアドレスが1つとは限らないこと、また変更される可能性があるということでしょうか。

もしサーバー無しで、ブラウザ等からリクエストを投げることを考えると、アグリゲートボンデッドトランザクションを一括取得して、さらに内部トランザクションを取得するために個別でリクエストを投げなければならないので、リクエスト量がとても多くなってしまうので、あまり良いやり方ではないですね。