#初めに
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/
#流れ
以下の順番で行っていきます。
- metamaskとの接続を行いウォレットのアドレスの取得
- アドレスを元にトークンの所有量を調べる
- 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"を表示するようにします。
<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>
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)
トークンを所持してる場合(iPhone)
トークンを所持していない場合(PC)