🌊
【Solidity × React.js × Ethers.js】ReadOnlyなdAppsの開発
変数を読み取って表示するだけの雑dAppsが作りたい!
雑なdApps記事が欲しい!ということで、変数を呼び出すだけのdAppsを作ります。
【スマートコントラクト側】 Solidity
思想
ただ変数を定義するコントラクトをSolidityで作成します。
コード
para.sol
pragma solidity ^0.8.4;
contract read {
uint public para = 20;
}
解説
コントラクトで定義されたpublic変数は自動で、getter関数(読み上げのみ)が生成されます。
【フロントエンド側】 React.js × Ethers.js
思想
基本的には以下の流れで実装していきます。
- Metamaskの確認
- Metamaskの接続
- 変数のgetter関数を実行
コード
App.js
import { useState } from "react";
import { ethers } from "ethers";
const App = () => {
//コントラクトアドレスを指定
const contractAddress = "0x6579087893F1a0B2428A73A7934C2d7c037D5380";
//コントラクトのAbiを指定
const paraAbi = [
{
inputs: [],
name: "para",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
];
//各変数の設定
const [errorMessage, setErrorMessage] = useState(null);
const [account, setAccount] = useState(null);
const [piyo, setPiyo] = useState("");
//メタマスクの接続の設定
const [provider, setProvider] = useState(null);
const [signer, setSigner] = useState(null);
const [contract, setContract] = useState(null);
//メタマスクの接続
const connectWalletHandler = () => {
if (window.ethereum && window.ethereum.isMetaMask) {
window.ethereum
.request({ method: "eth_requestAccounts" })
.then((result) => {
accountChangedHandler(result[0]);
})
.catch((error) => {
setErrorMessage(error.message);
});
} else {
console.log("Need to install MetaMask");
setErrorMessage(
"Please install MetaMask browser extension to interact"
);
}
};
//メタマスクのウォレットアドレスが変わった時に実行する関数
const accountChangedHandler = (newAccount) => {
setAccount(newAccount);
updateEthers();
};
//接続されているチェーンが切り替わった時に実行する関数
const chainChangedHandler = () => {
window.location.reload();
};
//アカウントが切り替わった時のイベントを拾う
window.ethereum.on("accountsChanged", accountChangedHandler);
//接続されているチェーンが切り替わった時のイベントを拾う
window.ethereum.on("chainChanged", chainChangedHandler);
//provider,signer,contractの設定
const updateEthers = () => {
let tempProvider = new ethers.providers.Web3Provider(window.ethereum);
setProvider(tempProvider);
let tempSigner = tempProvider.getSigner();
setSigner(tempSigner);
let tempContract = new ethers.Contract(
contractAddress,
paraAbi,
tempSigner
);
setContract(tempContract);
};
//パラメータを読み出す関数
const readPara = async () => {
let val = await contract.para().toString();
setPara(val);
};
return (
<div>
<div>Hello Contract!</div>
<button onClick={connectWalletHandler}>Connect Wallet</button>
<div>
<h3>Address: {account}</h3>
</div>
<button onClick={readPara}>read para</button>
{para}
</div>
);
}
export default App;
解説
エラー1
最初は以下のように実行しようとしたが上手くいかなかった...
const readPara = async () => {
let val = await contract.para();
console.log(val);
};
console.logの内容
▼ BigNumber {_hex: '0x14', _isBigNumber: true}
_hex: "0x14"
_isBigNumber: true
▶︎ [[Prototype]]: Object
なんかよくわからんものが出てきた...
エラー1の解決策
戻り値はBigNumberという形式らしい...
BigNumber.toString( ) ⇒ stringsource
Returns the value of BigNumber as a base-10 string.
ということで以下のようにすることで スマコン内で指定した"20"を受け取ることができます。
//パラメータを読み出す関数
const readPara = async () => {
let val = await contract.para().toString();
setPara(val);
};
エラー2
以下のコード
const readPara = async () => {
let val = await contract.para();
setPara(val);
};
return(
<div>{para}</div>
);
エラーコード
Error: Objects are not valid as a React child (found: object with keys {id, name, slug}).
If you meant to render a collection of children, use an array instead.
エラー2の解決策
<div>{para}</div>の中身がオブジェクト形式であると以下のエラーが出るので、中身の確認重要
Discussion
para is undefined.