Upgrade to Pro — share decks privately, control downloads, hide ads and more …

NFTのインデクシングとGraphQLのすゝめ / NFT indexing and GraphQL

NFTのインデクシングとGraphQLのすゝめ / NFT indexing and GraphQL

no plan inc. CTO @_serinuntius

2022.07.12, TOKYO BLOCKCHAIN TECH MEETUP 2022 登壇資料

8d6c54ebb889a5fe3f77b763d563fd9f?s=128

serinuntius

July 12, 2022
Tweet

More Decks by serinuntius

Other Decks in Technology

Transcript

  1. NFTのインデクシングと GraphQLのすゝめ Presentation by @_serinuntius 2022.07.12, TOKYO BLOCKCHAIN TECH MEETUP

    2022
  2. 今日話すこと 自己紹介 NFTのインデクシングとは? なぜインデクシングが必要なのか? インデクシングの実装 GraphQLのすゝめ まとめ

  3. 自己紹介 芹川葵: @_serinuntius no plan inc. CTO JPYC 技術顧問 趣味:

    キャンプ スノボ
  4. 興味ある技術とか、最近やってる技術とか(雑)

  5. NFTのインデクシングとは? NFTが持つ情報や付随する情報を、検索し易いよ うにDBに格納すること tokenId address metadata 1 0xabc {"image": "ipfs://..."}

    2 0x123 {"image": "ipfs://..."} 3 0x456 {"image": "ipfs://..."} 4 0x789 {"image": "ipfs://..."}
  6. なぜインデクシングが必要なのか? 一般的にNFTの情報にアクセスするには、コントラクトに生えてるview関数を叩く function ownerOf(uint256 tokenId) public view virtual override returns

    (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: invalid token ID"); return owner; } function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; }
  7. なぜインデクシングが必要なのか? 一般的にNFTの情報にアクセスするには、コントラクトに生えてるview関数を叩く function ownerOf(uint256 tokenId) public view virtual override returns

    (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: invalid token ID"); return owner; } function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; }
  8. なぜインデクシングが必要なのか? 一般的にNFTの情報にアクセスするには、コントラクトに生えてるview関数を叩く function tokenURI(uint256 tokenId) public view virtual override returns

    (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: invalid token ID"); return owner; }
  9. なぜインデクシングが必要なのか? 一般的にNFTの情報にアクセスするには、コントラクトに生えてるview関数を叩く function ownerOf(uint256 tokenId) public view virtual override returns

    (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: invalid token ID"); return owner; } function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; }
  10. なぜインデクシングが必要なのか? 一般的にNFTの情報にアクセスするには、コントラクトに生えてるview関数を叩く 情報が欲しくなった時にview関数を叩きまくるのは色々と現実的ではない ノードの負担増🆙, Infura, Alchemy等のノードプロバイダーのコスト増🆙 時間もかかる function ownerOf(uint256 tokenId)

    public view virtual override returns (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: invalid token ID"); return owner; } function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; }
  11. なぜインデクシングが必要なのか? 一般的にNFTの情報にアクセスするには、コントラクトに生えてるview関数を叩く 情報が欲しくなった時にview関数を叩きまくるのは色々と現実的ではない ノードの負担増🆙, Infura, Alchemy等のノードプロバイダーのコスト増🆙 時間もかかる ERC1155対応の闇😈 function ownerOf(uint256

    tokenId) public view virtual override returns (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: invalid token ID"); return owner; } function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; }
  12. ERC1155対応の闇😈

  13. ERC1155対応の闇😈 ERC721みたいな ownerOf(tokenId) が生えてないので、 tokenId の所有者情報をview関数だけでは 調べることができない😇 ` ` `

    `
  14. ERC1155対応の闇😈 ERC721みたいな ownerOf(tokenId) が生えてないので、 tokenId の所有者情報をview関数だけでは 調べることができない😇 name() が生えてないのも地味にだるい ノードの情報だけでは何のコントラクトなのかわからない

    ERC721は規格としてマストにはなってないものの、OpenZeppelinの ERC721Metadata が普及して いるため、大体取れる気がする ` ` ` ` ` ` ` `
  15. どうやってインデクシングするのか?

  16. 闇の魔術😈に対する防衛術をお教えします👍

  17. インデクシングの実装

  18. インデクシングの実装 EVMには 「event」 という概念がある

  19. インデクシングの実装 EVMには 「event」 という概念がある ノードに対してイベントをリッスンしておくことで、コントラクトからイベントが発火した時に何かを実行 できる

  20. インデクシングの実装 EVMには 「event」 という概念がある ノードに対してイベントをリッスンしておくことで、コントラクトからイベントが発火した時に何かを実行 できる ex) ERC721 event Transfer(address

    indexed from, address indexed to, uint256 indexed tokenId);
  21. インデクシングの実装 EVMには 「event」 という概念がある ノードに対してイベントをリッスンしておくことで、コントラクトからイベントが発火した時に何かを実行 できる ex) ERC721 indexed というキーワードをつけると、その変数は検索できるようになる

    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); ` `
  22. インデクシングの実装 EVMには 「event」 という概念がある ノードに対してイベントをリッスンしておくことで、コントラクトからイベントが発火した時に何かを実行 できる ex) ERC721 indexed というキーワードをつけると、その変数は検索できるようになる

    eth_getLogs というAPIを呼び出すことによってイベントを取得できる event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); ` ` ` `
  23. インデクシングの実装 EVMには 「event」 という概念がある ノードに対してイベントをリッスンしておくことで、コントラクトからイベントが発火した時に何かを実行 できる ex) ERC721 indexed というキーワードをつけると、その変数は検索できるようになる

    eth_getLogs というAPIを呼び出すことによってイベントを取得できる どのブロック高でそのイベントが発生したかがわかる event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); ` ` ` `
  24. インデクシングの実装 - ERC721

  25. インデクシングの実装 - ERC721 1ブロック目から、

  26. インデクシングの実装 - ERC721 1ブロック目から、 event Transfer(address indexed from, address indexed

    to, uint256 indexed tokenId);
  27. インデクシングの実装 - ERC721 1ブロック目から、 これを順に追って行けば良い event Transfer(address indexed from, address

    indexed to, uint256 indexed tokenId);
  28. インデクシングの実装 - ERC721 1ブロック目から、 これを順に追って行けば良い 最後に同期したブロック高をdbに入れて、次回以降は差分更新で良い event Transfer(address indexed from,

    address indexed to, uint256 indexed tokenId);
  29. インデクシングの実装 - ERC1155

  30. インデクシングの実装 - ERC1155 ERC1155の場合はイベントが2種類ある

  31. インデクシングの実装 - ERC1155 ERC1155の場合はイベントが2種類ある event TransferSingle(address indexed operator, address indexed

    from, address indexed to, uint256 id, uint256 value); event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values );
  32. インデクシングの実装 - ERC1155 ERC1155の場合はイベントが2種類ある event TransferSingle(address indexed operator, address indexed

    from, address indexed to, uint256 id, uint256 value); event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values );
  33. インデクシングの実装 - ERC1155 ERC1155の場合はイベントが2種類ある event TransferBatch( address indexed operator, address

    indexed from, address indexed to, uint256[] ids, uint256[] values ); event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
  34. インデクシングの実装 - ERC1155 ERC1155の場合はイベントが2種類ある event TransferSingle(address indexed operator, address indexed

    from, address indexed to, uint256 id, uint256 value); event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values );
  35. インデクシングの実装 - ERC1155 ERC1155の場合はイベントが2種類ある これらを順に追って行けば良い event TransferSingle(address indexed operator, address

    indexed from, address indexed to, uint256 id, uint256 value); event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values );
  36. GraphQLのすゝめ (時間なかった) 先程行ったインデクシングでDBに保管してGraphQLで返すように実装してみました 型付のクライアントが自動生成できるのでオススメ🔥 Nestjs / PlanetScale / Prisma /

    Cloud Run 辺りで実装しています
  37. この辺りを全部気をつけて 実装するの面倒では?🤔🤔🤔

  38. その通り!

  39. 面倒ごとを全部うちが引き受けて インデクシングするSaaS始めます!

  40. NFT GraphQL API (仮)

  41. NFT GraphQL API (仮) ⛓ 任意のEVM互換のチェーンに対応できる(サポートして欲しいチェーンがあればお気軽に連絡くださ い)

  42. NFT GraphQL API (仮) ⛓ 任意のEVM互換のチェーンに対応できる(サポートして欲しいチェーンがあればお気軽に連絡くださ い) 💰 実装コストやら、ノードのメンテコストやら考えると圧倒的コスパ

  43. NFT GraphQL API (仮) ⛓ 任意のEVM互換のチェーンに対応できる(サポートして欲しいチェーンがあればお気軽に連絡くださ い) 💰 実装コストやら、ノードのメンテコストやら考えると圧倒的コスパ ¥

    ボラの高い草コインじゃなくて、日本円で払えます(円も実質草コイ・・・🤫
  44. NFT GraphQL API (仮) ⛓ 任意のEVM互換のチェーンに対応できる(サポートして欲しいチェーンがあればお気軽に連絡くださ い) 💰 実装コストやら、ノードのメンテコストやら考えると圧倒的コスパ ¥

    ボラの高い草コインじゃなくて、日本円で払えます(円も実質草コイ・・・🤫 🚀 もう少しでリリースするのでちぇけら
  45. 興味ある方はこちら

  46. 参考文献 EIP721 EIP1155 OpenZeppelin - IERC721.sol OpenZeppelin - IERC1155.sol

  47. ご静聴ありがとうございました🙌