Infura
自分のイーサリアム・ノードをプロバイダとして運営することも可能。
もっと手軽にする場合サードパーティの Infura サービスがある。
DAppのユーザーのために自分のイーサリアム・フルノードをもつ必要はない。
metamask
MetamaskはChromeとFirefoxのブラウザ拡張機能。
ユーザーは自分のイーサリアム・アカウントと秘密鍵を安全に管理し、アカウントでWeb3.jsを使用しているウェブサイトとやりとりする
MetamaskはInfuraのサーバーをWeb3プロバイダーとして使用。
(Web3プロバイダーを選択するオプションもあり。)
Metamaskのweb3プロバイダの使用
Metamaskは、web3プロバイダをJavaScriptのグローバルオブジェクト web3のブラウザにインジェクトする。
そのため web3が存在するか、プロバイダとしてweb3.currentProviderを使用しているかをアプリがチェックすることができる。
以下のMetamaskが提供するテンプレートコードは、 ユーザーがMetamaskをインストール済みかを検出し、 インストールしていなければアプリを使用するためにMetamaskのインストールが必要だと伝えるコード
window.addEventListener('load', function() { // Web3がブラウザにインジェクトされているかチェック (Mist/MetaMask) if (typeof web3 !== 'undefined') { // Mist/MetaMaskのプロバイダの使用 web3js = new Web3(web3.currentProvider); } else { // ユーザーがweb3を持たない場合の対処。 // アプリを使用するためにMetamaskをインストールするよう // 伝えるメッセージを表示。 } // アプリのスタート&Web3.jsへの自由なアクセスが可能に: startApp() })コントラクトへのアクセス
Web3.jsがコントラクトにアクセスするため、必要となるものがコントラクトアドレス と ABI 。
コントラクトアドレス
コントラクトをデプロイした際に与えられる有効なイーサリアム上の固定アドレス
コントラクトABI
ABIとは、Application Binary Interfaceの略
Solidityコンパイラはコントラクトをコンパイルする際にABIを出力。
コントラクトのメソッドをJSON形式で表していて、関数コールをコントラクトが理解できるようなフォーマット方法を、Web3.jsに伝える。
コントラクトの関数呼び出し
Web3.jsはコントラクトの関数を呼び出すための2つのメソッドcallとsendを持っている。
call
callはview関数およびpure関数に使われる。
ローカルのノードでのみ機能しブロックチェーン上のトランザクションを生成しない。
Web3.jsを使い123をパラメーターにしてmyMethodという名の関数をcallできます。 myContract.methods.myMethod(123).call()Send
sendはトランザクションを生成し、ブロックチェーン上のデータを変更する。
トランザクションをsendすることはユーザーにガスの支払いを要求。 トランザクションに署名するようMetamaskをポップアップします。 Web3プロバイダとしてMetamaskを使用する場合。 send()関数を呼び出すとこれを全部行ってくれます。function getZombieDetails(id) { return cryptoZombies.methods.zombies(id).call(); } // 関数を呼び出し、その結果を処理する: getZombieDetails(15) .then(function(result) { console.log("Zombie 15: " + JSON.stringify(result)); });cryptoZombies.methods.zombies(id).call() はWeb3プロバイダのノードと通信して コントラクトにあるZombie[] public zombiesからゾンビとそのインデックスidを返す。 外部サーバーへAPIコールの非同期であることに注意する。Web3はここでpromiseを返すことになる。 Promiseがリゾルブするとこのコードはthenステートメントで続行されresultをコンソールにログする。 リゾルブ(Web3プロバイダからの応答を受けとったという意味) result は次のようなJavaScriptオブジェクトとなる: { "name": "H4XF13LD MORRIS'S COOLER OLDER BROTHER", "dna": "1337133713371337", "level": "9999", "readyTime": "1522498671", "winCount": "999999999", "lossCount": "0" // Obviously. }<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>CryptoZombies front-end</title> <script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script language="javascript" type="text/javascript" src="web3.min.js"></script> <script language="javascript" type="text/javascript" src="cryptozombies_abi.js"></script> </head> <body> <div id="txStatus"></div> <div id="zombies"></div> <script> var cryptoZombies; var userAccount; function startApp() { var cryptoZombiesAddress = "YOUR_CONTRACT_ADDRESS"; cryptoZombies = new web3js.eth.Contract(cryptoZombiesABI, cryptoZombiesAddress); var accountInterval = setInterval(function() { // Check if account has changed if (web3.eth.accounts[0] !== userAccount) { userAccount = web3.eth.accounts[0]; // Call a function to update the UI with the new account getZombiesByOwner(userAccount) .then(displayZombies); } }, 100); cryptoZombies.events.Transfer({ filter: { _to: userAccount } }) .on("data", function(event) { let data = event.returnValues; getZombiesByOwner(userAccount).then(displayZombies); }).on("error", console.error); } function displayZombies(ids) { $("#zombies").empty(); for (id of ids) { // Look up zombie details from our contract. Returns a `zombie` object getZombieDetails(id) .then(function(zombie) { // Using ES6's "template literals" to inject variables into the HTML. // Append each one to our #zombies div $("#zombies").append(`<div class="zombie"> <ul> <li>Name: ${zombie.name}</li> <li>DNA: ${zombie.dna}</li> <li>Level: ${zombie.level}</li> <li>Wins: ${zombie.winCount}</li> <li>Losses: ${zombie.lossCount}</li> <li>Ready Time: ${zombie.readyTime}</li> </ul> </div>`); }); } } function createRandomZombie(name) { // This is going to take a while, so update the UI to let the user know // the transaction has been sent $("#txStatus").text("Creating new zombie on the blockchain. This may take a while..."); // Send the tx to our contract: return cryptoZombies.methods.createRandomZombie(name) .send({ from: userAccount }) .on("receipt", function(receipt) { $("#txStatus").text("Successfully created " + name + "!"); // Transaction was accepted into the blockchain, let's redraw the UI getZombiesByOwner(userAccount).then(displayZombies); }) .on("error", function(error) { // Do something to alert the user their transaction has failed $("#txStatus").text(error); }); } function feedOnKitty(zombieId, kittyId) { $("#txStatus").text("Eating a kitty. This may take a while..."); return cryptoZombies.methods.feedOnKitty(zombieId, kittyId) .send({ from: userAccount }) .on("receipt", function(receipt) { $("#txStatus").text("Ate a kitty and spawned a new Zombie!"); getZombiesByOwner(userAccount).then(displayZombies); }) .on("error", function(error) { $("#txStatus").text(error); }); } function levelUp(zombieId) { $("#txStatus").text("Leveling up your zombie..."); return cryptoZombies.methods.levelUp(zombieId) .send({ from: userAccount, value: web3.utils.toWei("0.001", "ether") }) .on("receipt", function(receipt) { $("#txStatus").text("Power overwhelming! Zombie successfully leveled up"); }) .on("error", function(error) { $("#txStatus").text(error); }); } function getZombieDetails(id) { return cryptoZombies.methods.zombies(id).call(); } function zombieToOwner(id) { return cryptoZombies.methods.zombieToOwner(id).call(); } function getZombiesByOwner(owner) { return cryptoZombies.methods.getZombiesByOwner(owner).call(); } window.addEventListener('load', function() { // Checking if Web3 has been injected by the browser (Mist/MetaMask) if (typeof web3 !== 'undefined') { // Use Mist/MetaMask's provider web3js = new Web3(web3.currentProvider); } else { // Handle the case where the user doesn't have Metamask installed // Probably show them a message prompting them to install Metamask } // Now you can start your app & access web3 freely: startApp() }) </script> </body> </html>出典 10分で理解した気になるDApps入門(http://ykubot.com/2018/03/05/about-dapps-in-ten-minute/)