web3やBlockchainとやらを始めてみる【前半】
GitHub
後半
Web3.0!ブロックチェーン!最高!?
一部の人にとっては「暗号通貨?仮想通貨?怪しい🤔」
実際にお金儲けのネタに使われているし,先行者利益があるのも事実なようです.
このTweetがとても納得できました.
僕は,人間がお金儲け話に敏感であるという背景をある程度取り除いて考えても,この技術はわくわくするものと考えているので,学びたいと考えています.皮肉ながら,このようなお金儲け話に敏感な愚かな人間の心理をシステムすなわちこのテクノロジーによって正しめることができるのではないかと考えております.
正直その仕組みは結構難しく,一般の人が理解するのが難しいので,「怪しい!考えたくない!」と思う気持ちも,数学の教員をやっていた私には少しはわかります.そして,それに屈してしまうのはとても簡単でとても苦しいことです.だから,そうではなくて,好奇心や探究心を糧により楽しい学びを実現させることができればいいなと思っているのです.
あとは政府も頑張る言うてるね.
さて,そんな御託はおいといて,この技術の使い方のスレッドを立てていきます.
とはいえ知らないといけない前提知識多すぎ問題
まずWeb3.0
Web3.0を知るために,まずはWeb1.0とWeb2.0を知らんとですよね.
かんたんです.
Web1.0→インターネットできたよ.誰でも情報をゲットできるよ!みんな見てね.(サーバーを持っている者だけが発信できる一方的な感じ)
Web2.0→インターネット使えば誰でも自分の情報を誰かが運営するサーバーに有料or無料に公開できるようになってお互い店会えるようになったよ.(SNSの誕生.インターネットを通じて互いに情報を発信できるね)
Web3.0→管理社会なんてもういや.誰かが運営するサーバーに情報を集約するのを辞めて,いろんなところにいろんな情報を分散して保存しようよ.その代わりその情報は誰でも見れるからね♥(仮想通貨/NFTの誕生.あなたが送金したという情報や〇〇を買ったという情報が誰でも閲覧可能になる代わりに改ざん不可)
ざっくり説明するとこんな感じで,Web3.0に関する理解はそんなに難しくない?
次はBlockchain
これはまじで難しい.新しい言葉を説明するのに新しい言葉が次から次から出てくる地獄.
さっき説明した「誰かが運営するサーバーに情報を集約するのを辞めて,いろんなところにいろんな情報を分散して保存しようよ.」ってときの話なんだけど,
保存するときは複数の情報を一つのブロックにまとめて保存するようにして,
各ブロックの最初と最後をつなげておくことで,情報が正しいかどうかを照合する仕組みを使っているので,
Block Chainと言います.(技術的な説明は一切省きました)
んで,このブロックの保存先は一箇所じゃなくて,そのときにインターネットにつながっているサーバーをランダムに複数選んで,そこに保存している感じ.(分散台帳に保存するって言ったりする)
ちなみにこの「サーバーをランダムに複数選んで」に当選したら報酬がもらえるのがBitcoinゴールドラッシュの正体.
あとはスマートコントラクトって言葉が出てくるよ
これはスマートな契約ってことで,日本語でそのまま「契約」と思ってもらって良くて,
「分散台帳にどんなデータを保存するのか?」というのがこの「契約」にあたります.
例えば仮想通貨だとしたら,
- 誰が
- いつ
- 誰に
- いくら渡したのか
という情報を保存しておくことで,通貨の価値が証明されます.
(こうなると「契約」はちょっとしっくりこないか?まあいいや)
御託はもういいんだやらせろ
はい
さすがに前提となるWeb2.0の知識
とはいえ,ある程度のプログラミング知識や経験はある体で話します.
- npmを使いつつJavaScriptを動かす知識(私の記事では主にReact(Next.js)をフロントエンド,バックエンドをNode.jsとして説明します.)
- Web2.0のWebアプリ開発に関する簡単な知識
- APIに関するちょっとした知識
くらいですかね.ちなみに私は学習期間2年,開発実務経験1年程度なので,それ以上の方は間違いなく大丈夫だと思います.
やる
それではやりましょう.
なにやんの?
Blockchainの技術を使ってスマートコントラクトを作成し,それを使用したアプリ.
わかりやすいのがCounterアプリかなと思います.
カウントは0から始まり,増やしたり,減らしたりする度に,
- 誰が
- いつ
- 増やしたのか/減らしたのか
と言った情報が分散台帳に保存されていつでも誰でも見れるようにしてしまいましょう.
嘘の付けない世界最高.
Ethereumを使う
ブロックチェーンといえば,Bitcoinというイメージがありますが,2番目にEthereumかなと勝手に思っています.
Bitcoinは送金系の処理の目的が主であり,通貨としての利用しかできないようですが,
Ethereumはスマートコントラクトを利用して,いろんなことに利用することができるようで,
多くのブロックチェーンゲームなどに利用されているようです.
EthereumのBlockchainを使ったアプリ開発の流れ
- スマートコントラクトを作る(コードを書く)
- スマートコントラクトをデプロイする
- スマートコントラクトをJavaScriptで以下の処理を呼び出す
- 現在のカウントを取得
- カウントアップ
- カウントダウン
ざっくりこんな感じです.
大変長らくおまたせしました.次のスレッドから,いよいよ始めます.
まずはHello world
カウント云々の前にHello worldからです.基本をなめてはいけません.
リポジトリの作成
mkdir lesson-we3-app && cd $_
npm init
私は yarn
を使います
yarn init -y
Setup
スマートコントラクトのデプロイはいろいろ大変みたいで,ライブラリを使ったほうが良さそうです.
truffleやhardhatなどいくつかあるようですが,hardhatでいきます.(よくわからんけど良いみたいです.)
依存関係のinstall
よくわからんけどいろいろ必要みたい
yarn add -D hardhat @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers
以下のコマンドで必要なファイルを自動生成してくれます.
npx hardhat
テンプレートを選びます.
👷 Welcome to Hardhat v2.9.9 👷
? What do you want to do? …
Create a basic sample project
Create an advanced sample project
Create an advanced sample project that uses TypeScript
❯ Create an empty hardhat.config.js
Quit
Create a basic sample project
を選べば簡単なスマートコントラクトのコードをサンプルとして生成してくれるので,お手本に良いのですが,
今回は1から最小構成でいきたいので,Create an empty hardhat.config.js
を選びます.
hardhat.config.js
ファイルのみ作られるはずです.
/**
* @type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
solidity: "0.8.0",
};
solidityのバージョンを"0.8.0"
に変えておきますか.
スマートコントラクトの作成
隠していたのですが,実はスマートコントラクトはJavaScriptでは書けません.
SolidityというEthereumが開発した言語で書いていくことになります.
そんなに難しくないとは思うのですが,
ゾンビのゲームで遊んだり,
文法に関する記事を漁ったりしながら
基礎を抑えておくと良いでしょう.
contracts/Hello.sol
を
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Hello {
string public message = "Hello World!!!!";
}
とします.
Helloという名前のコントラクトで,message
という変数には"Hello World!!!!"
が保存されています.
これは,message
という変数の中身の"Hello World!!!!"
を見ることしかできないクソみたいなコントラクトですが,「コントラクトをデプロイ→デプロイしたコントラクトをJavaScriptで呼び出す」を実行するためにはシンプルで良さそうです.
スマートコントラクトのデプロイ
スマートコントラクトはデプロイする前にSolidityで書いたコードをコンパイルする必要があります.
スマートコントラクトのコンパイル
npx hardhat compile
成功すれば,artifactsとcacheの2つのディレクトリが作られます.
スマートコントラクトのデプロイ
デプロイするときに実行するscriptを作成します.
scripts/deploy.js
const hre = require('hardhat');
async function main() {
const HelloContract = await hre.ethers.getContractFactory('Hello');
const helloContract = await HelloContract.deploy();
await helloContract.deployed();
console.log('Hello deployed to:', helloContract.address);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
hardhat.config.js
/**
* @type import('hardhat/config').HardhatUserConfig
*/
// 以下を追加
require('@nomiclabs/hardhat-waffle');
task('accounts', 'Prints the list of accounts', async (taskArgs, hre) => {
const accounts = await hre.ethers.getSigners();
for (const account of accounts) {
console.log(account.address);
}
});
// 以上を追加
module.exports = {
solidity: '0.8.0',
};
デプロイ
npx hardhat run scripts/deploy.js
Hello deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
のようにコントラクトアドレスが表示されれば成功🎉
コントラクトアドレスとは
コントラクトがデプロイされるときに割り振られるIDのようなものと思って良い.
このコントラクトアドレスを使用してネットワーク上にデプロイされたコントラクトを見つけることができる.
Ethereumのネットワーク上にデプロイされたものであれば,下のEtherscanというサイトでコントラクトアドレスで検索することで見つけることができます.
RinkebyのEtherscanはこれです.
コントラクト以外の様々なものがこのアドレスで検索できます.(後ほどやります.)
実はデプロイされてない?
先程の
npx hardhat run scripts/deploy.js
を実行しただけでは,単にコントラクトアドレスを作成してデプロイするムーブをしただけで,実際にはどこのネットワークにもデプロイされていません.
デプロイするネットワークを指定して実行する必要があります.
[デプロイ方法1] テストネット(HardhatNetwork)にデプロイする
hardhatの公式にHardhatNetworkにデプロイする方法が記載されています.
この通りに
npx hardhat node
でサーバーにアクセスした状態で別のターミナルで
npx hardhat run scripts/deploy.js --network localhost
を実行しましょう.
これで,localhostで起動しているHardhatNetwork?にデプロイがされます.
デプロイが終わったら,npx hardhat node
で起動したサーバーはCtrl + C
で終了して大丈夫です.
localhostのWalletと接続するために必要なので,起動したままにしておきましょう.
ちなみにこのネットワークにデプロイした場合はEthersscanの検索に引っかからないと思います.
[デプロイ方法2] テストネット(Rinkeby)にデプロイする
実務の開発などでEthereumのテストネットにデプロイする方法も書いておきます.
Ethereumのテストネットはいくつかあり,なんでもいいのですが,今回はRinkebyでいきます.
Ethereumのテストネットとはテスト用の通貨を無料で取得することができ,それを使っていろいろ実装をテストすることができるため,本番のEthereumのネットワークにデプロイする前にテストする用のものです.
デプロイする方法は
npx hardhat run scripts/deploy.js --network rinkeby
とするだけです(npx hardhat node
は不要)
デプロイ時のコントラクトアドレスを使ってEthersscanで検索すると見つかると思います.(多分)
デプロイされたコントラクトを呼び出す
さて,今度こそデプロイされているので,これからフロントエンドでデプロイされたコントラクトを呼び出してみます.
Next.jsの作成
フロントエンドはJavaScriptが動けば何でもいいですが,Next.jsを使います.
(ある程度の知識がある前提なので,コントラクトに関する説明以外は省きます.)
client作成
yarn create next-app client
呼び出す前の準備
コントラクトを呼び出す前に,あなたが,web3の世界にエントリーしている必要があります.
それはWalletと言われるものを通して,web3ユーザーであることを証明しましょう.
そのためにMetamaskと言われるツールがよく使われるので,今回はそれを使います.
Google Chromeの拡張機能を入れることですぐに始めることができます.
公式
Walletとは
通称仮想通貨ウォレットと言われ,仮想通貨を使った取引をするための財布のようなものです.
web3でやり取りをする際は仮想通貨の取引以外でも何かとこのWalletが必要になります.
今回もコントラクトを呼び出す際にWalletにログインしている必要があります.
Walletでlocalhostに接続する
Metamaskに登録してログインしたら,ネットワーク一覧を開き,「ネットワークを追加」を押します.
以下のように入力して保存すれば追加されます.
画像のエラーは新規追加の場合はおきませんので気にしないでください.
追加できたら,ネットワークを追加した「Localhost 8545」に切り替えましょう.
これで準備OK
呼び出し方
import { ethers, Contract } from 'ethers';
import helloAbi from '../../artifacts/contracts/Hello.sol/Hello.json';
const contractAddress = '0x5FbDB2315678afecb367f032d93F642f64180aa3';
const getHelloMessage = async () => {
if (typeof window === 'undefined') return;
const provider = new ethers.providers.Web3Provider(window.ethereum);
const greetContract = new Contract(contractAddress, helloAbi.abi, provider);
return await greetContract.message();
};
ポイント
- コンパイルしたときに生成された
artifacts
の中にあるJSONファイルを使用していることです.このファイルにコントラクトの呼び出しに必要な情報が記載されているようです. -
contractAddress
はデプロイしたときに表示されたものを使用します.
これで,getHelloMessage
を実行してHello World!!!!
が取得できれば成功🎊
Reactではこんな感じですかね.
useEffect(() => {
getHelloMessage().then((msg) => {
console.log(msg);
});
}, []);
なんか本当は
yarn add ethers
をしないといけない?と思うのだけど,親ディレクトリのnode_modules
にあるから,それを読み込んでいる!?
というわけで無事Hello worldできました😎
Rinkeby でも同じようにデプロイしたいよー
Ethereumのテストネットに接続をするためにはもう少し準備が必要です.
認証もろもろのもろもろのもろが必要なようで.
INFURAや
Alchemyのような
サービスを使用する必要があります.
Alchemyの方がモダンそうでワクワクするのでこっちでいきます.
ALCHEMY_API_KEYを取得
アカウントを作成し,ダッシュボードにログインしたら,「+ CREATE APP」から新しいAPPを作ります.
名前は何でもいいので,ネットワークだけEthereumのテストネットのRinkebyを選択します.
作成したAPPの「VIEW KEY」からAPI Keyを取得できるのでコピーします.(真ん中のHTTPの方をコピーします.)
.env
ファイルなどで環境変数として扱うようにした方がいいでしょう.
PRIVATE_KEYの取得
次にMetamaskの秘密鍵を取得します.
「アカウントの詳細→秘密鍵のエクスポート」より秘密鍵を取得して,こちらも環境変数としておきましょう.
当然漏洩してはいけません.
hardhat.config.js
に追記する
module.exports = {
solidity: '0.8.0',
// 以下を追加
networks: {
rinkeby: {
url: process.env.ALCHEMY_API_KEY,
accounts: [process.env.PRIVATE_KEY],
},
},
// 以上を追加
};
デプロイ先のネットワークに関する情報を追加する感じですね.
Rinkebyにデプロイ
npx hardhat run scripts/deploy.js --network rinkeby
成功したら,localhostのときとは異なるコントラクトアドレスでデプロイされているはずです.
Etherscanでも検索すれば見つかります.(当然Transactionsはないけれど)
Rinkebyの方でHello world
先にMetamaskで先程と同様にRinkebyのネットワークを以下の情報で追加して切り替えておきましょう.
あとはcontractAddress
を変更すれば,先と同様にHello World!!!!
が取れているはずです🎊
長くなりそうなので,前後半に分けました!
後半はこちら!
いよいよCounterを作っていきます.