👻

Metamaskでログイン&フロントアプリからNFTを発行する

2022/01/28に公開

前回は、NFTを発行する独自コントラクトをInfuraのテストネット(Ropsten)にデプロイするところまでやりました。
もしまだやってない人は前回書いた記事からやってください。

この記事では、ローカルからそのスマコンにアクセスし、NFTを発行してみたいと思います。

必要なもの

  • Node
  • Metamask
    • ropstenネットワークの残高が必要になります。無料配布してくれているサイトがいくつかあるので、そこからクレクレしておいてください。
  • RopstenネットワークのETH残高

出来上がり

以下リポジトリにデプロイまで行ったコードを入れてあります。
https://github.com/tkyatg/nft-front-example

プロジェクト作成

Nuxtアプリで進めていきます。React触ったことないので、お許しを。

$ npx create-nuxt-app
Need to install the following packages:
  create-nuxt-app
Ok to proceed? (y) y

create-nuxt-app v3.7.1
✨  Generating Nuxt.js project in .
? Project name: nuxt
? Programming language: JavaScript
? Package manager: Yarn
? UI framework: Vuetify.js
? Nuxt.js modules: (Press <space> to select, <a> to toggle all, <i> to invert se
lection)
? Linting tools: (Press <space> to select, <a> to toggle all, <i> to invert sele
ction)
? Testing framework: None
? Rendering mode: Single Page App
? Deployment target: Server (Node.js hosting)
? Development tools: jsconfig.json (Recommended for VS Code if you're not using 
typescript)
? What is your GitHub username? 
? Version control system: None

実装の準備

layouts/default.vueを以下のように書き換えます。
(不要コードを削除しただけです)

<template>
  <v-app>
    <v-main>
      <nuxt />
    </v-main>
  </v-app>
</template>

web3jsのインストール

npm install web3

Metamaskでログイン

pages/index.vueを以下のように書き換えて、初期表示時にwalletの情報を取得するようにします。

<template>
  <v-container></v-container>
</template>

<script>
import Web3 from "web3";
export default {
  data() {
    return {
      web3: null,
    };
  },
  async created() {
    const web3 = new Web3(this.endpoint);
    this.web3 = web3;
    try {
      const newAccounts = await ethereum.request({
        method: "eth_requestAccounts",
      });
      const accounts = newAccounts;
      if (accounts[0] !== "") {
        this.web3.eth.defaultAccount = accounts[0];
      } else {
        console.error("ログインに失敗");
      }
    } catch (error) {
      console.error(error);
    }
  },
};
</script>

アプリ起動

yarn dev

アプリ起動後、localhost:3000にアクセスすると、Metamaskのログイン画面が開きます。
既にログインしている場合&Metamaskがインストールされていない場合も何も起きません。(エラーハンドリング可)
image

contractアクセス用のABIをコピーしてくる

前回作成したプロジェクトの/artifacts/contracts/Nft.sol/Nft.jsonにABIが作成されています。

ABIとは
イーサリアムエコシステム内でコントラクトに接続するスタンダードなインターフェースのこと

もし無い場合は以下コマンドで作成できます。

npx hardhat compile

hadhatプロジェクトの/artifacts/contracts/Nft.sol/Nft.jsonNft.jsonを今回のアプリの/abi/Nft.jsonにコピーします。

contractに接続

pages/index.vueを以下のように編集して、対象のコントラクトに接続します。


  data() {
    return {
      web3: null,
+      nftContract: null,
+      endpoint: "{infura の endpoint}",
+      contractAddress: "{infura へ contract deploy する時に表示される文字列}",
    };
  },
  async created() {
    const web3 = new Web3(this.endpoint);
+    const json = require("../abi/Nft.json");
+    const nftContract = new web3.eth.Contract(json.abi, this.contractAddress);
    this.web3 = web3;
+    this.nftContract = nftContract;
    try {
      const newAccounts = await ethereum.request({
        method: "eth_requestAccounts",
      });

dataの部分のみ以下のように変更してください。

  • endpoint
    • infura のダッシュボードに記載されているhttps://ropsten.infura.io/v3/...
  • contract address
    • local から infura へデプロイした際に log に表示される文字列

この変更後、検証を開いて、エラーが出ていなければ接続自体は成功しています。

NFT作成コードの追記

実際にNFTを作ってみます。
NFT作成するコードをpages/index.vueに追記します。

 <template>
  <v-container>
+    <v-row>
+      <v-col cols="12">
+        <v-card>
+          <v-list-item>
+            <v-list-item-title> NFT作成 </v-list-item-title>
+          </v-list-item>
+          <v-list-item>
+            <v-text-field v-model="uri" label="URI"></v-text-field>
+          </v-list-item>
+          <v-card-actions>
+            <v-spacer></v-spacer>
+            <v-btn rounded color="primary" large @click="createNft()">
+              作成
+            </v-btn>
+          </v-card-actions>
+        </v-card>
+      </v-col>
+    </v-row>
  </v-container>
 </template>

 <script>
 import Web3 from "web3";
 export default {
...
+  methods: {
+    async createNft() {
+      const tx = {
+        from: this.web3.eth.defaultAccount,
+        to: this.contractAddress,
+        data: this.nftContract.methods.mint(this.uri).encodeABI(),
+      };
+      try {
+        await window.ethereum.request({
+          method: "eth_sendTransaction",
+          params: [tx],
+        });
+        alert("NFT作成成功");
+      } catch (error) {
+        alert("NFT作成失敗");
+      }
+    },
+  },
};
 </script>

NFT作成してみる

localhost:3000からぽちぽちする。

  1. 画面表示
    image

  2. 「作成」ボタン押下

  3. MetamaskでのSignを求められる。「確認」ボタンを押下(ropsten残高が必要)
    image

  4. 作成完了(したっぽい
    image

作成したNFTを確認してみる

メッセージ的には作成完了したっぽいが
ひねくれ者たちは、作成できたのか信用できないと思うので、実際にスマコンに問い合わせてみる。

作成したコントラクトでは取得methodは書いてないが、継承元に処理が書いてあるため取得できます。
詳しく知りたい人はopenzeppelinのコードを読んでください。

async created() {
.....
+    await this.getMyNfts();
  },
  methods: {
+   async getMyNfts() {
+     const myNftCount = await this.nftContract.methods
+      .balanceOf(this.web3.eth.defaultAccount)
+      .call();
+     for (let i = 0; i < myNftCount; i++) {
+      let myNftTokenId = await this.nftContract.methods
+        .tokenOfOwnerByIndex(this.web3.eth.defaultAccount, i)
+        .call();
+      let myNftTokenUri = await this.nftContract.methods
+        .tokenURI(myNftTokenId)
+        .call();
+       console.log("あなたのNFT");
+       console.log("tokenId: " + myNftTokenId);
+       console.log("tokenUri: " + myNftTokenUri);
+     }
+   },
    async createNft() {

初期表示時に、tokenを取得しに行くと
検証>コンソールで、以下のように表示されるはずです。

image

これでテストネットにデプロイした独自コントラクトをlocalのアプリから実行し、NFTを作成するところまで完了しました!

最後に

NFT生成してみるだけなら割と簡単にできる。
フロントアプリからスマコン実行するなら、ローカルで開発するよりもテストネットにあげて開発した方が何かと便利だなーと思いました。

twitterのフォローお願いします!
https://twitter.com/takuya_develop

あと定期的に渋谷でブロックチェーンもくもく会やるので、ぜひ参加してください〜。
ブロックチェーンについて語り合いましょう!
https://block-chain.connpass.com/event/236396/

GitHubで編集を提案

Discussion