見出し画像

Lisk SDK (lisk-client)を使いながらJavaScriptを勉強してみない? - その3 -

おっはろーございます!万博おじです。
今回は4回目、内容は「非同期処理:APIからアカウント情報を取得」です。

  1. 準備

  2. JavaScriptの基本:パスフレーズを生成

  3. 文字列操作:パスフレーズからアドレスを取得

  4. 非同期処理:APIからアカウント情報を取得

  5. ループ処理:APIからトランザクション情報を取得

  6. トランザクションの生成と送信

  7. トランザクション手数料の取得

はじめに

今回は非同期処理をやっていきます。
内容的にも難しいと思うのでのんびりごらんください~。
それではしばしお付き合いください😊

前回

非同期処理とは

ざっくり言うと、なんらかの処理の結果を待たずに他の処理を行うことができる処理のことです。
逆に同期処理はなんらかの処理の結果を待ってから他の処理を行う処理です。
うん、よくわからんと思うので下図をどうぞ

非同期処理と同期処理

というのを軽く頭に入れてから以下をどうぞ!

今回のお勉強用ソースコード

<!DOCTYPE html>
<html lang="ja">
	<head>
		<meta charset="utf-8"/>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>画面タイトルです</title>
		<script src="https://js.lisk.com/lisk-client-5.2.2.min.js" defer></script>
		<style>
			html { font-size: 10px; }
			
			body { font-size: 1.6rem; }

			input[type="text"],
			input[type="number"],
			input[type="password"],
			textarea,
			button {
				font-size: 1.6rem;
				padding: 5px;
			}
		</style>
	</head>
	<body>
		<div>
			<input type="password" id="enter-passphrase" style="width: 300px;" placeholder="パスフレーズを入力してください" oninput="checkPassphrase(this.value)" />
		</div>
		<div>
			<button type="button" id="btn-login" style="width: 150px;" onclick="login()" disabled="true">ログイン</button>
			<button type="button" style="width: 150px;" onclick="createAccount()">アカウントを作成</button>
		</div>
		<div>
			<a href="https://testnet-faucet.lisk.com/" target="_blank" rel="noopener noreferrer">テストネット用のLSKを受け取ります</a>
		</div>
		<hr>
		<!-- (1)パスフレーズの表示場所 -->
		<h4>パスフレーズ:</h4>
		<div id="lisk-passphrase"></div>

		<!-- (2)アドレスの表示場所 -->
		<h4>アドレス:</h4>
		<div id="lisk-address"></div>
		<div id="lisk-bufferAddress"></div>

		<!-- (3)公開鍵の表示場所 -->
		<h4>公開鍵:</h4>
		<div id="lisk-publicKey"></div>
		
		<!-- (4)残高の表示場所 -->
		<h4>残高:</h4>
		<div id="lisk-balance"></div>

		<script>
			/*
			 * アカウント作成処理
			 */
			function createAccount() {
				// (1)パスフレーズを生成して画面に表示
				const mnemonic = lisk.passphrase.Mnemonic.generateMnemonic();
				document.querySelector("#lisk-passphrase").innerHTML = mnemonic;

				// (2)アドレスと公開鍵を取得して画面に表示
				const addressAndPublicKey = lisk.cryptography.getAddressAndPublicKeyFromPassphrase(mnemonic);
				const bufferAddress = addressAndPublicKey.address;
				const publicKey = addressAndPublicKey.publicKey;
				document.querySelector("#lisk-bufferAddress").innerHTML = `(${bufferAddress.toString("hex")})`;
				document.querySelector("#lisk-publicKey").innerHTML = publicKey.toString("hex");

				// (3)アドレスを取得して画面に表示
				const address = lisk.cryptography.getLisk32AddressFromAddress(bufferAddress);
				document.querySelector("#lisk-address").innerHTML = address;

				// (4)残高は0LSKとする
				document.querySelector("#lisk-balance").innerHTML = "0LSK";
			}

			/*
			 * ログイン 
			 */
			async function login() {
				// (1)入力されたパスフレーズを取得
				const passphrase = document.querySelector("#enter-passphrase").value;

				// (2)パスフレーズからlsk始まりのアドレスを取得
				const address = lisk.cryptography.getLisk32AddressFromPassphrase(passphrase);

				// (3)Lisk Service API の accounts を使用してアカウント情報を取得
				const response = await fetch(`https://testnet-service.lisk.com/api/v2/accounts?address=${address}`);
				const json = await response.json();

				// (4)見つからなかった場合は終了
				if (json.error) {
					alert("アカウントが見つかりませんでした。");
					return;
				}

				// (5)見つかった場合は画面に表示
				const account = json.data[0];
				document.querySelector("#lisk-address").innerHTML = account.summary.address;
				document.querySelector("#lisk-balance").innerHTML = `${lisk.transactions.convertBeddowsToLSK(account.summary.balance)}LSK`;
				document.querySelector("#lisk-passphrase").innerHTML = "ひみつ";
				
				// (6)公開鍵とバッファアドレスはパスフレーズから取得して表示
				const addressAndPublicKey = lisk.cryptography.getAddressAndPublicKeyFromPassphrase(passphrase);
				document.querySelector("#lisk-bufferAddress").innerHTML = `(${addressAndPublicKey.address.toString("hex")})`;
				document.querySelector("#lisk-publicKey").innerHTML = addressAndPublicKey.publicKey.toString("hex");
			} 

			/*
			 * パスフレーズチェック
			 */
			function checkPassphrase(val) {
				// (1)現在の入力値をチェック
				const ret = lisk.passphrase.Mnemonic.validateMnemonic(val);

				// (2)パスフレーズが正しくない場合はログインボタンを入力不可、正しい場合は入力可に変更
				document.querySelector("#btn-login").disabled = !ret;
			}
		</script>
	</body>
</html>

前回からの変更点

HTMLで変わったのは以下の通りです

  • パスフレーズの入力欄の追加

  • ログインボタンの追加

  • テストネット用のLSKを受け取りリンクを追加

JavaScriptで変わったのは以下の通りです

  • ログイン処理(function login)の追加

  • パスフレーズチェック処理(function checkPassphrase)の追加

画面を開くとこんな感じ

変更後の画面
パスフレーズを入力して「ログイン」ボタン押下後

⚠️試す場合のパスフレーズを記載します。
最よわパスフレーズなのでメインネットなどには絶対に使用しないようにしましょう。

パスフレーズ
abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about

アドレス
lsk9g3k58b3gzcykjyaob9ekbt3a7b3e586h4gkxj

ソースコードの説明:HTML

<input type="password">

パスワード入力欄を表示します。
入力した文字が●などでマスクされるため、入力中の内容を見られたくないようなものに使用します。

ℹ️password以外のtype例
text:入力欄を表示します。入力した文字がマスクされずにそのまま表示されます。

checkbox:チェックボックスを表示します。

file:ファイル選択欄を表示します。

number:数値入力欄を表示します。スマホなどでは数値入力用キーボードが表示されます。

tel:電話番号入力欄を表示します。スマホなどでは電話番号入力用のキーボードが表示されます。

button:<button type="button">と同じくボタンを表示します。WEBデザインを考慮すると<button type="button">を使用する方が良いと思います。

submit:<button>と同じく送信ボタンを表示します。WEBデザインを考慮すると<button>を使用する方が良いと思います。

他にもいろいろあるので興味のある人は検索してみてね!

placeholder=""

入力欄が未入力の場合に設定した内容を入力欄に表示します。

ℹ️ユーザーの入力のヒント(入力例など)になるようなものを書いてあげるといいと思います。
お勉強用ソースコードではplaceholder="パスフレーズを入力してください"としているので、パスワード入力欄に「パスフレーズを入力してください」と表示されていますね。

oninput=""

入力中に発生するイベントを定義します。

ℹ️お勉強用ソースコードでは oninput="checkPassphrase(this.value)" となっているので、パスフレーズを入力するたびにcheckPassphrase関数がよびだされます。

ちなみに、checkPassphrase関数にthis.valueを渡していますが、このthisはパスフレーズ入力欄を指します。
なので、this.valueはパスフレーズ入力欄の入力値です。

⚠️thisは使う場所や使う方法によって中身が変わります。
お勉強の例として書いていますがthisを使わなくて良い場合は(バグ発生や可読性も考慮して)使わない方が良いと思います。
今回の場合は、checkPassphrase内でdocument.querySelector("#enter-passphrase").valueとすることで値が取得できます。

disabled="true"

入力欄やボタンなどにつけると使用不可になります。
disabled="false" または つけない場合は使用可です。

ℹ️今回の場合はログインボタンについています。
有効なパスフレーズが入力された場合にcheckPassphrase関数でdisabled="false"となります。

<a href=""></a>

リンクを表示するタグです。
リンクをクリックした際に開く画面のURLをhrefに設定します。

⚠️target="_blank"について
target="_blank" は別タブで画面を開くためによく使われますが、セキュリティおよびパフォーマンスに問題があります。
この問題を解消するために rel="noopener noreferrer" を付けましょう。
興味のある人は「target _blank 危険性」などで検索してみてね!

ℹ️お勉強用ソースコードで指定しているリンク先はLisk公式のテストネット用のLSKがもらえるサイトです。
lskから始まるアドレスを入力後にボタンを押すと750LSKほどもらえます。(時々サーバーが落ちたりしてます😅)
なお、テストネットで使うアカウントはメインネットで使用しているアカウントとは別(パスフレーズが別)にすることをおすすめします。

ソースコードの説明:JavaScript(lisk-client)

lisk.cryptography.getLisk32AddressFromPassphrase

パスフレーズからlsk始まりのアドレスを取得します。

lisk.passphrase.Mnemonic.validateMnemonic

ニーモニック(パスフレーズ)が有効なものかどうかを判定します。
有効な場合はtrue、無効な場合はfalseを返します。

lisk.transactions.convertBeddowsToLSK

アカウント情報などにある残高を1/100000000するための関数です。

ℹ️Liskは内部的に残高を100000000倍した値で保持しているため、画面に表示する場合はこの関数で変換しましょう。
なお、lisk.transactions.convertLSKtoBeddowsは逆に100000000倍します。

ソースコードの説明:JavaScript

function checkPassphrase

パスフレーズをチェックする関数です。
パスフレーズを入力する度に実行され、有効なパスフレーズの場合にログインボタンを使用可能にします。

function login

ログイン処理(アカウント情報の取得)を行う関数です。
ログインボタンのクリックイベントから実行されます。

ℹ️ログインボタン、ログイン処理としていますが、ブロックチェーン自体にはログインという考え方はありません。(アクセスしたからと言ってブロックチェーンに情報が書き込まれるわけではないため、2段階認証のようなこともできません。)
ログインを行うのはウォレットだったりブロックチェーンを使用したサービスに対してです。
が、じゃあなんというのが正しいかといわれると悩ましいので「ログイン」としています。

async

非同期処理ですよという宣言です。

ℹ️asyncはログイン処理を行う関数についています。

await

awaitが宣言された関数の結果が返却されるまでasyncが宣言されている関数の処理が待ち状態になります。(同期処理と同じような動きになります)
asyncが宣言された関数内でのみ利用可能です。

ℹ️awaitはログイン処理内のfetchについています。

fetch

指定のURLにアクセス(リクエスト)し、その結果(レスポンス)を取得する機能です。

ℹ️以前JavaScriptをやったことがある人はXMLHttpRequestやJQuery.ajaxなどでやっていたかもしれませんが、こちらで覚えなおしましょう。

response.json

fetchの実行結果responseからjsonを取得します。

ℹ️jsonの取得も非同期で実施されるためawaitを付与しています。

⚠️responseは今回のfetchの結果を格納している定数を指します。

if

条件判定を行います。
()に記載した内容がtrueになる場合に処理が実行されます。

⚠️jsonは今回のfetchの結果を格納している定数response内にあるjsonを格納した定数を指します。
ℹ️今回は if(json.error) { … } となっているので json内のerrorがtrueだった場合という意味になります。
なお、LiskサービスのAPIで情報が取得できないような場合は以下のようなJSONが返却されるため、json.errorで判断すると良いと思います。

{
    "error": true,
    "message": "Data not found"
}

json.data[0]

json内のdataの1件目の情報という意味になります。
[]は配列であることを指し、その中の数字は0始まりです。

⚠️json.data[0]となっていますが、実際に使用するAPIなどによってjsonの中身は変わるので注意しましょう。

ℹ️https://testnet-service.lisk.com/api/v2/accountsで取得できる情報が配列になっており、1件目の情報が欲しいため[0]と指定しています。
※今回はアドレスを指定しているのでアカウントが存在する場合はそのアカウント1件の情報のみを取得できます。

ソースコードの説明:Liskサービス API

https://testnet-service.lisk.com/api/v2/accounts

テストネットのアカウント情報を取得するLisk公式のLiskサービスAPIです。
詳しくはこちらをご覧ください。
アカウント情報が取得できた時は以下のようなJSONが返却されます。

{
    "data": [
        {
            "summary": {
                "address": "lsk9g3k58b3gzcykjyaob9ekbt3a7b3e586h4gkxj",
                "balance": "0",
                ....
            },
            ....
        },
        {
            "summary": {
                ....
            },
            ....
        },
        {
            "summary": {
                ....
            },
            ....
        },
    ]
}

エラー時は以下のようなJSONが返却されます。

{
    "error": true,
    "message": "Data not found"
}

おわりに

今回はここまで!お疲れさまでした!
非同期処理とLiskサービスのAPIが出てきたので前回より難しかったですね😅
非同期処理はWEBアプリを作る際にとても重要なのでasync/awaitは抑えておきましょう!(昔JavaScriptをやっていた人はPromiseとかコールバック地獄で悩まされたと思いますが、使うだけならだいぶ楽になりましたね~)
次回はものんびりご覧ください😉

万博おじについて

Liskに関するツールなど開発したりノード管理したりしています。
何かあればTwitter等でご連絡ください。

個人アカウント
Twitter:ys_mdmg
GitHub:lisknonanika
Discord:ys_mdmg#5646
Lisk Explorer:lisk observerlisk scan

デリゲートアカウント(共同管理)
Twitter:liskcommulab
Discord:CommuLab#0097
Lisk Explorer:lisk observerlisk scan

管理
ノード:Mainnet / Testnet
Lisk Service:Mainnet / Testnet
デリゲートサイト:Lisk CommuLab

個人やデリゲート宛ての寄付ありがとうございます!
ノード管理や開発資金に充てさせて頂いています😊

この記事が気に入ったらサポートをしてみませんか?