2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

特定のERC20トークンの保有者のみ閲覧可能のサイトを構築する(モバイル版metamask対応もさせる)

Last updated at Posted at 2020-12-12

#初めに
vue.jsを用いて特定のERC20トークンの有無で表示を切り替えるwebサイトを構築します。
簡便な作りのため厳密な認証を行っているわけではないので注意してください。
metamaskがインストールされていることを前提としています。

完成品のgithub:
https://github.com/ramo798/erc20_authentication_vue_app

デプロイしたもの:
https://erc20-authentication-vue-app.web.app/
モバイル用のディープリンク:
https://metamask.app.link/dapp/erc20-authentication-vue-app.web.app/

#流れ
以下の順番で行っていきます。

  1. metamaskとの接続を行いウォレットのアドレスの取得
  2. アドレスを元にトークンの所有量を調べる
  3. vue.jsで構築する

##1. metamaskとの接続を行いウォレットのアドレスの取得

async function getAccount() {
  const accounts = await window.ethereum.request({
    method: "eth_requestAccounts",
  });
  return accounts[0];
}

if (window.ethereum) {
  getAccount().then((res) => {
    console.log(res);
  });
} else {
  window.addEventListener("ethereum#initialized", this.handleEthereum, {
    once: true,
  });
  setTimeout(this.handleEthereum, 3000);
}

metamaskがインストールされているとEthereum Provider APIが使用可能なのでwindow.ethereumにてmetamask有無を調べている。
インストールされてる場合に、getAccount()が実行され、ブラウザとmetamaskアカウントの接続を行い、ウォレットのアドレスを取得する。
window.ethereum.requestについてはドキュメントを参照してください。

##2. アドレスを元にトークンの所有量を調べる
ウォレットのアドレスを取得できたのでトークンの保有量を調べていきます。
ERC20にはbalanceOfという関数が用意されており、それを利用して調べていきます。
最終的に以下のgetTokenBalance()はトークンの保有数を整数で返します。

function getTokenBalance(address) {
  let minABI = [
    {
      constant: true,
      inputs: [{ name: "_owner", type: "address" }],
      name: "balanceOf",
      outputs: [{ name: "balance", type: "uint256" }],
      type: "function",
    },
    {
      constant: true,
      inputs: [],
      name: "decimals",
      outputs: [{ name: "", type: "uint8" }],
      type: "function",
    },
  ];

  const web3 = new Web3();
  web3.setProvider(
    new web3.providers.HttpProvider(
      "https://ropsten.infura.io/v3/674fa8842b484b24987e1267a15f06cc"
    )
  );

  const WALLET_ADDRESS = address;
  const CONTRACT_ADDRESS = "0xc2fdf34114fccB32dF11f0852F61b9165Ec872fF";

  const contract = new web3.eth.Contract(minABI, CONTRACT_ADDRESS);

  var balance_result = contract.methods
    .balanceOf(WALLET_ADDRESS)
    .call()
    .then((res) => {
      var balance = contract.methods
        .decimals()
        .call()
        .then((decimal) => {
          return res / 10 ** decimal;
        });
      return balance;
    })
    .then((balance) => {
      return balance;
    });
  return balance_result;
}

スマートコントラクトの関数を呼び出すにはweb3というライブラリが必要なので適宜インストールし、インポートします。
web3からスマートコントラクトの関数を呼び出すには、スマートコントラクトがどのような関数を持っているかを記述されたABIというものが必要なので宣言します。ここでは、minABIとして宣言し、今回使う関数であるbalanceOf decimalsのみ記述しておきます。
balanceOfはトークンの所有量を返す関数で、decimalsはトークンが使用する小数点以下の桁数を返す関数です。

スマートコントラクトの関数を実行する場合は下記のように実行します。

const contract = new web3.eth.Contract(ABI, CONTRACT_ADDRESS);
contract.methods.関数名().call()

##3. vue.jsで構築する
以上を元にvueにて、トークンを1以上を持ってる場合に"hello,world"を表示するようにします。

HTML
  <div id="app">
    <div>
      <img alt="Vue logo" src="./assets/logo.png" />
      <p>{{ walletAddress }}</p>
      <p>所持数は {{ howmany }} TCKMです。</p>
    </div>
    <div v-if="load">
      <div v-if="howmany > 0">
        <p>HELLO,WORLD!</p>
      </div>
      <div v-else>
        <p>You dont have token.</p>
      </div>
    </div>
  </div>
script
import Web3 from "web3";

export default {
  name: "App",
  components: {},
  data: () => ({
    walletAddress: null,
    howmany: null,
    load: false,
    sec_load: false,
  }),
  mounted() {
    if (window.ethereum) {
      this.getAccount().then((res) => {
        this.walletAddress = res;
        this.getTokenBalance(res)
          .then((res) => {
            this.howmany = res;
          })
          .finally(() => {
            this.load = true;
          });
      });
    } else {
      window.addEventListener("ethereum#initialized", this.handleEthereum, {
        once: true,
      });
      setTimeout(this.handleEthereum, 3000);
    }
  },
  methods: {
    handleEthereum: () => {
      const { ethereum } = window;
      if (ethereum && ethereum.isMetaMask) {
        // console.log("Ethereum successfully detected!");
        console.log(ethereum.selectedAddress);
        const myaddress = ethereum.selectedAddress;
        return myaddress;
      } else {
        console.log("Please install MetaMask!");
      }
    },
    getAccount: async function() {
      const accounts = await window.ethereum.request({
        method: "eth_requestAccounts",
      });
      // console.log(accounts);
      return accounts[0];
    },
    getTokenBalance: (address) => {
      const web3 = new Web3();
      web3.setProvider(
        new web3.providers.HttpProvider(
          "https://ropsten.infura.io/v3/674fa8842b484b24987e1267a15f06cc"
        )
      );
      const WALLET_ADDRESS = address;
      const CONTRACT_ADDRESS = "0xc2fdf34114fccB32dF11f0852F61b9165Ec872fF";
      let minABI = [
        {
          constant: true,
          inputs: [{ name: "_owner", type: "address" }],
          name: "balanceOf",
          outputs: [{ name: "balance", type: "uint256" }],
          type: "function",
        },
        {
          constant: true,
          inputs: [],
          name: "decimals",
          outputs: [{ name: "", type: "uint8" }],
          type: "function",
        },
      ];
      const contract = new web3.eth.Contract(minABI, CONTRACT_ADDRESS);

      var balance_result = contract.methods
        .balanceOf(WALLET_ADDRESS)
        .call()
        .then((res) => {
          var balance = contract.methods
            .decimals()
            .call()
            .then((decimal) => {
              return res / 10 ** decimal;
            });
          return balance;
        })
        .then((balance) => {
          return balance;
        });
      return balance_result;
    },
  },
};

#表示結果
トークンを所持してる場合(PC)
スクリーンショット 2020-12-13 023051.png
トークンを所持してる場合(iPhone)
S__36061186.jpg
トークンを所持していない場合(PC)
スクリーンショット 2020-12-13 023018.png

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?