Symbol SDKを利用したXYMとモザイクの残高表示プログラム

<p>この記事では、Symbol SDKを使ってXYMとモザイクの残高表示プログラムを作ります。<br />
<p>ここでは、Webページ制作に使うHTMLファイルとブラウザに利用できるようにカスタマイズしたSymbol SDKが同じフォルダにあるものとして説明します。</p>

<p>なので、Symbol SDKを用意していない方は、以下の記事を参照してください。</p>
<p><strong><a href="https://qiita.com/YutopianF/private/f2196b844487b0e9ef7a" target="_blank" rel="noopener">ブラウザ環境でのSymbolの実行環境の構築について</a></strong></p>
<h2 style="background-color: #44004e; padding: 8px;"><strong><span style="font-size: 16pt; color: #ffffff;">残高表示プログラムについて</span></strong></h2>
<p>以下のコードについて説明します。</p>
<pre class="language-markup"><code>&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"&gt;&lt;/script&gt;
    &lt;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.5.8/dist/css/uikit.min.css" /&gt;
    &lt;script src="https://cdn.jsdelivr.net/npm/uikit@3.5.8/dist/js/uikit.min.js"&gt;&lt;/script&gt;
    &lt;script src="https://cdn.jsdelivr.net/npm/uikit@3.5.8/dist/js/uikit-icons.min.js"&gt;&lt;/script&gt;
    &lt;script src="symbol-sdk-0.21.0.js"&gt;&lt;/script&gt;
    &lt;title&gt;Symbol残高照会&lt;/title&gt;
  &lt;/head&gt;
  &lt;body style="margin:30px;"&gt;
    &lt;h1&gt;Symbolを触ってみる&lt;/h1&gt;
    
    &lt;h2&gt;残高の確認&lt;/h2&gt;
    &lt;div style="margin-top:10px;"&gt;
      Address:&lt;input type="text" id="address" class="uk-input"&gt;
    &lt;/div&gt;
    &lt;div style="margin-top:10px;"&gt;
      Balance:&lt;span id="balance"&gt;0&lt;/span&gt; xym
    &lt;/div&gt;
    &lt;div id="balance_get" class="uk-button uk-button-primary" style="margin-top:10px;"&gt;残高取得&lt;/div&gt;

    &lt;script&gt;
      const symbol=require("/node_modules/symbol-sdk");
      let address;
      const nodeAddress='http://api-01.ap-northeast-1.0.10.0.x.symboldev.network:3000';
      const networkGenerationHash="1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B";
      const repositoryFactory=new symbol.RepositoryFactoryHttp(nodeAddress);
      const accountHttp=repositoryFactory.createAccountRepository();

      $('#balance_get').click(function(){
        address=symbol.Address.createFromRawAddress($('#address').val());
        accountHttp.getAccountInfo(address)
        .subscribe(function(accountInfo){
            $('#balance').text(accountInfo.mosaics[0].amount.compact()/1000000);
            console.log(accountInfo.mosaics[0].id.toHex())
        }, err =&gt; console.error(err));
      });  
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;


</code></pre>

<p>このプログラムの完成版は以下になります。</p>

<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604584087スクリーンショット 2020-11-05 22.47.50.png" alt="" width="449" height="258" /></p>

<p>これについて説明します。</p>

<h2><span style="font-size: 18pt; background-color: #44004e; color: #ffffff;"><strong>head要素について</strong></span></h2>
<p><em><strong>&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"&gt; </strong></em><br /><em><strong>&lt;/script&gt;</strong></em></p>
<p>この要素で、jQueryを読み込みます。</p>
<p>以下の3行でCSSのフレームワークであるUIKitを読み込んでいます。</p>
<p><em><strong>&lt;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.5.8/dist/css/uikit.min.css" /&gt;</strong></em><br /><em><strong>&lt;script src="https://cdn.jsdelivr.net/npm/uikit@3.5.8/dist/js/uikit.min.js"&gt;&lt;/script&gt;</strong></em><br /><em><strong>&lt;script src="https://cdn.jsdelivr.net/npm/uikit@3.5.8/dist/js/uikit-icons.min.js"&gt;&lt;/script&gt;</strong></em></p>

<p>&nbsp;Symbol SDKをHTMLファイルと同じフォルダ内に置いている上で、このようにして書きます。</p>
<p><em><strong> &lt;script src="symbol-sdk-0.21.0.min.js"&gt;&lt;/script&gt;</strong></em></p>
<p>このように書くことで、Symbol SDKをHTMLファイルに読むこむことができるようになります。</p>
<p>また、以下のようにして書くと、Symbol SDKをネットワークからダウンロードして読む込みこともできます。</p>
<p><em><strong>&lt;script src=&ldquo;https://xembook.github.io/nem2-browserify/symbol-sdk-0.21.0.js&rdquo;&gt;&lt;/script&gt;</strong></em></p>

<h2><span style="font-size: 18pt; background-color: #44004e; color: #ffffff;"><strong>body要素について</strong></span></h2>
<p><span style="font-size: 18pt;"><strong><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604482705スクリーンショット 2020-11-04 18.38.14.png" alt="" width="346" height="276" /></strong></span></p>
<p>input要素を使う事で、アドレスの入力フォームをつくることができます。</p>
<p><em><strong>&lt;div style="margin-top:10px;"&gt;</strong></em><br /><em><strong>Address:&lt;input type="text" id="address" class="uk-input"&gt;</strong></em><br /><em><strong>&lt;/div&gt;</strong></em></p>
<p>ここでは、UIKITを使っているので入力枠を見やすくしていますが、最低限、これだけでもOKです。</p>
<p><em><strong>&lt;input type="text"&gt;</strong></em></p>

<p>また、以下のコードで残高(Balance)を表示させます。ここでは初期値として0としています。</p>
<p><em><strong> Balance:&lt;span id="balance"&gt;0&lt;/span&gt; xym</strong></em></p>

<p>以下のコードで、「残高取得」と書かれたボタンを実装しています。このボタンをクリックすることで実行できます。</p>
<p><em><strong>&lt;div id="balance_get" class="uk-button uk-button-primary" style="margin-top:10px;"&gt;残高取得&lt;/div&gt;</strong></em></p>

<h2><span style="font-size: 18pt; background-color: #44004e; color: #ffffff;"><strong>script要素について</strong></span></h2>
<p>以下の1行で、Symbol SDKを呼び出す宣言になります。</p>
<p><em><strong>const symbol=require("/node_modules/symbol-sdk");</strong></em></p>
<p>このように書く事で、symbolという定数にSymbol SDK内の情報を代入することになります。ここで、requireはnode.jsで定義されるコマンドです。<br />それ以降、symbolという定数を使う事で、Symbol SDKの中身を使えるようになります。この1行は基本的にコピペでOKです。また、ここではsymbolを定数としましたが、定数名はお好みでOKです。</p>

<p>また、アドレスを入れておく事を確保するための変数をここで用意しておきます。</p>
<p><em><strong>let address</strong></em></p>

<p>以下のコードでどこのノードアドレスに情報を問い合わせるのかを定数nodeAddressにて設定します。</p>
<p><em><strong>const nodeAddress='http://api-01.eu-central-1.096x.symboldev.network:3000';</strong></em></p>

<p>ノードアドレスを調べたい場合は、Symbol Walletにて、赤い四角で囲んだところをクリックして</p>
<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604583179スクリーンショット 2020-11-05 22.31.39.png" alt="" width="507" height="726" /></p>

<p>ノードのアドレスを確認できます。ここから、ノードを選んでください。</p>
<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604411726スクリーンショット 2020-11-03 11.21.45.png" alt="" width="729" height="441" /></p>

<p>ノードを選んだら、それに対応するネットワークジェネレーションハッシュが必要になります。</p>
<p><em><strong> const networkGenerationHash="1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B";</strong></em></p>
<p>このジェネレーションハッシュは以下のページにて見つけ方が書かれています。</p>
<p><a href="https://docs.symbolplatform.com/ja/getting-started/first-application.html" target="_blank" rel="noopener">https://docs.symbolplatform.com/ja/getting-started/first-application.html</a></p>

<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604411698スクリーンショット 2020-11-03 11.31.38.png" alt="" width="1217" height="266" /></p>

<p>つまり、ノードアドレスが、</p>
<p><em><strong>http://api-01.ap-northeast-1.0.10.0.x.symboldev.network:3000</strong></em></p>
<p>の場合は</p>
<p><em><strong>http://api-01.ap-northeast-1.0.10.0.x.symboldev.network:3000/node/info</strong></em></p>
<p>ということになります。このURLで開いてみると・・・</p>
<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604411679スクリーンショット 2020-11-03 11.47.07.png" alt="" width="1217" height="208" /></p>
<p>networkGenerationHashSeedに、ネットワークジェネレーションハッシュが書かれています。これをコードに書きます。</p>
<p>ノードのURLとネットワークジェネレーションハッシュは一対一に結びついているので、ノードURLを決めたら、必ずネットワークジェネレーションハッシュを見つけてください。</p>

<p>次に、このコードを見ます。</p>
<p><em><strong> const repositoryFactory=new symbol.RepositoryFactoryHttp(nodeAddress);</strong></em></p>
<p>これは、Symbolの中身の仕組みを使うのに、nodeAddressを引数とした<strong>r</strong>epositoryFactoryを定数としておいたものです。</p>

<p>次に、このコードを見ます。</p>
<p><em><strong>const accountHttp=repositoryFactory.createAccountRepository();</strong></em></p>
<p>定数 accountHttpは、先ほど書いたrepositoryFactoryをcreateAccountRepositoryで読んで来いというものです。</p>

<p>ここまで読んだ以下のコード</p>
<pre class="language-markup"><code>      const symbol=require("/node_modules/symbol-sdk");
      let address;
      const nodeAddress='http://api-01.eu-central-1.096x.symboldev.network:3000';;
      const networkGenerationHash="1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B";
      const repositoryFactory=new symbol.RepositoryFactoryHttp(nodeAddress);
      const accountHttp=repositoryFactory.createAccountRepository();</code></pre>
<p>は、基本的にコピペでOKで、変えるべきなのは、ノードアドレスと、そのジェネレーションハッシュということになります。</p>

<p>次に、このコードについて</p>
<p><em><strong>$('#balance_get').click(function(){</strong></em></p>
<p>これはIDがbalance_getの要素(「残高取得」と書かれたボタン)をクリックしたら、以下の処理を実行するというものです。</p>
<pre class="language-markup"><code>        address=symbol.Address.createFromRawAddress($('#address').val());
        accountHttp.getAccountInfo(address)
        .subscribe(function(accountInfo){
            $('#balance').text(accountInfo.mosaics[0].amount.compact()/1000000);
            console.log(accountInfo.mosaics[0].id.toHex())
        }, err =&gt; console.error(err));</code></pre>
<p>以上のコードについて、それぞれ説明します。</p>
<p>&nbsp;</p>
<p>まず、以下のコードについて説明します。</p>
<p><em><strong>address=symbol.Address.createFromRawAddress($('#address').val());</strong></em></p>
<p>これは、input要素のIDを「address」と指定することで、そのinput要素から取得したデータと.valを読んでくる事ができます。それをcreateFromRawAddressで、Symbol SDKの中で使うアドレスに変換されたものを、変数addressに代入するという意味です。<br />この変数addressの中身は、アドレスとネットワークのタイプ(152番)がオブジェクトデータとして入っているようです。実際にそうなっている事を調べるには、このコードのあとに、</p>
<p><em><strong>alert(JSON.stringify(address));</strong></em></p>
<p>として、input要素をクリック(残高収得をクリック)するとわかります。</p>
<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604583847スクリーンショット 2020-11-05 22.43.36.png" alt="" width="656" height="217" /></p>

<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604583753スクリーンショット 2020-11-05 22.41.49.png" alt="" width="486" height="184" /></p>
<p>調べてみると、確かにそうなっています!!</p>
<p>このコードは基本的にコピペでOKで、もしアドレスを固定で指定したい場合は<em><strong>address=symbol.Address.createFromRawAddress($('TADAFIKEA2DCTO6CJPNQHT3W543W2RBMJ6QITPI').val());</strong></em></p>
<p>として、直接アドレスを書いてもOKです。</p>

<p>今度は、このコードを見てみます。</p>
<p><em><strong>&nbsp;accountHttp.getAccountInfo(address)</strong></em><br /><em><strong>.subscribe(function(accountInfo){</strong></em><br /><em><strong>$('#balance').text(accountInfo.mosaics[0].amount.compact()/1000000);</strong></em><br /><em><strong>console.log(accountInfo.mosaics[0].id.toHex())</strong></em></p>
<p>getAccountInfo(address)でaddressの情報を取ってきて、それを非同期処理(sunscribe)(結果が返ってきた処理から順番に処理すること)により、addressに入っている情報が入ってきたら、入ってきた順番に処理をしていくことになります。その結果がaccountInfoに返ってきます。返ってきたら、IDを「balance」とした要素にテキストとして、モザイクの0番目の量をコンパクト化したものを100万で割ったものを表示することになります。</p>
<pre class="language-markup"><code> Balance:&lt;span id="balance"&gt;0&lt;/span&gt; xym</code></pre>
<p>すると、0として最初は表示していたのが、実際の残高として表示されます。</p>

<p>ここで、このコードをaccountInfoを見てみます。そのためには、(accountinfo)の後にconsole.log(accountInfo)を書きます。つまり、コードを以下のようにするということです。<em><strong>accountHttp.getAccountInfo(address).subscribe(function(accountInfo)</strong></em></p>
<p><em><strong>console.log(accountInfo);</strong></em></p>
<p>実行してみて、Google Chromeのデベロッパーツールのconsoleを見てみると・・・</p>
<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604411613スクリーンショット 2020-11-03 16.10.07.png" alt="" width="718" height="272" /></p>

<p>この中身を見てみます。</p>
<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604411579スクリーンショット 2020-11-03 16.11.05.png" alt="" width="718" height="447" /></p>

<p>ここで、mosaicsの中身をみると・・・</p>
<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604411550スクリーンショット 2020-11-03 16.11.16.png" alt="" width="733" height="554" /></p>
<p>0番目のモザイクを見てみると・・・</p>
<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604411507スクリーンショット 2020-11-03 16.11.30.png" alt="" width="688" height="579" /></p>
<p>赤い四角で囲んだものをcompactという関数で組み合わせると、残高が表示されるようになります。</p>
<p>けど、表示されるときは、&mu;XYMで表示されているので、XYMで表示するために、100万で割っています。</p>
<p>ここで、０番目のモザイクはXYMの事を指していますが、1番目と2番目はXYM以外のモザイクを表します。</p>
<p>実際にウォレットを見てみます。</p>
<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604411482スクリーンショット 2020-11-03 21.43.36.png" alt="" width="1217" height="253" /></p>

<p>SymbolではXYMとモザイクの送信方法は、IDを指定するだけで同じようにできます。<br />つまり、XYMの場合のIDは「5B66E76BECAD0860」であり、自作のモザイクのID「7DC393D57931CA69」や「519F7A167869851C」を送信するとしてやると、XYMもモザイクも同じように送信することができます。</p>
<p><strong><em>accountHttp.getAccountInfo(address).subscribe(function(accountInfo){$('#balance').text(accountInfo.mosaics[1].amount.compact()/1000000);}, err =&gt; console.error(err));</em></strong></p>
<p>とすると、モザイクの残高が表示されるようになります。</p>
<p>つまり、</p>
<p><strong><em>accountHttp.getAccountInfo(address).subscribe(function(accountInfo){　}, err =&gt; console.error(err));</em></strong></p>
<p>は、コピペでOKで、{ }の中に残高を表示するプログラムを書くとなると、<strong><em>accountHttp.getAccountInfo(address).subscribe(function(accountInfo){</em></strong></p>
<p><strong><em>$('#balance').text(accountInfo.mosaics[0].amount.compact()/1000000);</em></strong></p>
<p><strong><em>}, err =&gt; console.error(err));</em></strong></p>
<p>となるわけです。基本的に、この一文はコピペでOKであり、XYM以外のモザイクを表示したいときに、accountinfo.mosaics[1]とかにします。</p>

<p>最後に、このコードについて見てみます。</p>
<p><strong><em>console.log(accountInfo.mosaics[0].id.toHex())</em></strong></p>
<p>これは、モザイクのIDを見る事ができます。</p>
<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604411454スクリーンショット 2020-11-03 22.05.37.png" alt="" width="650" height="498" /></p>
<p>ここで、lower、higherが分かれているので、結合するために、toHEX()とすることで、16進数にして合体させる処理をしています。</p>
<p>ここで、実行させてみると・・・</p>
<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604411422スクリーンショット 2020-11-03 22.09.42.png" alt="" width="681" height="157" /></p>
<p>このように、IDが表示されています。ここでは0番目のモザイクのIDを指定しているので、XYMのIDが表示されています。</p>
<p>ここで、</p>
<p><strong><em>console.log(accountInfo.mosaics[1].id.toHex()</em></strong></p>
<p>として、1番目のモザイクのIDを調べてみると、以下のようになります。</p>
<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604411397スクリーンショット 2020-11-03 22.14.10.png" alt="" width="1217" height="187" /></p>

<p>先ほどのウォレットと比較してみると・・・</p>
<p><img src="https://s3-ap-northeast-1.amazonaws.com/nem-social/blog/50000/51000/51400/51421/1604411370スクリーンショット 2020-11-03 21.43.36.png" alt="" width="1217" height="253" /></p>
<p>これで、1番目のモザイクは何なのかがわかりました。</p>
<p>このようにして、何番目のモザイクなのかを確認することができます。</p>
<p>これは、モザイクのIDを調べたいとき、必要に応じて書いてください。</p>

<h2><span style="font-size: 18pt; background-color: #44004e; color: #ffffff;"><strong>最後に・・・</strong></span></h2>
<p>では、XYMとモザイクを一気に残高照会をしたときは、このように書きます。</p>
<pre class="language-markup"><code>&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"&gt;&lt;/script&gt;
    &lt;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.5.8/dist/css/uikit.min.css" /&gt;
    &lt;script src="https://cdn.jsdelivr.net/npm/uikit@3.5.8/dist/js/uikit.min.js"&gt;&lt;/script&gt;
    &lt;script src="https://cdn.jsdelivr.net/npm/uikit@3.5.8/dist/js/uikit-icons.min.js"&gt;&lt;/script&gt;
    &lt;script src="symbol-sdk-0.21.0.min.js"&gt;&lt;/script&gt;
    &lt;title&gt;Symbol残高照会&lt;/title&gt;
  &lt;/head&gt;
  &lt;body style="margin:30px;"&gt;
    &lt;h1&gt;Symbolを触ってみる&lt;/h1&gt;
    
    &lt;h2&gt;残高の確認&lt;/h2&gt;
    &lt;div style="margin-top:10px;"&gt;
      Address:&lt;input type="text" id="address" class="uk-input"&gt;
    &lt;/div&gt;
    
    &lt;div style="margin-top:10px;"&gt;
      Balance:&lt;span id="balance0"&gt;0&lt;/span&gt; xym
      Balance:&lt;span id="balance1"&gt;0&lt;/span&gt; xym

    &lt;/div&gt;
    &lt;div id="balance_get" class="uk-button uk-button-primary" style="margin-top:10px;"&gt;残高取得&lt;/div&gt;

    &lt;script&gt;
      const symbol=require("/node_modules/symbol-sdk");
      let address;
      const nodeAddress='http://api-01.ap-northeast-1.0.10.0.x.symboldev.network:3000';
      const repositoryFactory=new symbol.RepositoryFactoryHttp(nodeAddress);
      const accountHttp=repositoryFactory.createAccountRepository();

      $('#balance_get').click(function(){
        address=symbol.Address.createFromRawAddress($('#address').val());
        accountHttp.getAccountInfo(address)
        .subscribe(function(accountInfo){

           for(i=0;i&lt;accountInfo.mosaics.length;i++){
            $('#balance'+i).text(accountInfo.mosaics[i].amount.compact()/1000000);
           }
            

            console.log(accountInfo.mosaics[0].id.toHex())
        }, err =&gt; console.error(err));
      });  
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>&nbsp;</p>
<p>つまり、</p>
<p><strong><em>$('#balance').text(accountInfo.mosaics[0].amount.compact()/1000000)</em></strong></p>
<p>に関して、accountInfo.mosaicsに入っている配列の長さ分を繰り返せばよいので、accountInfo.mosaics.lengthと書くことになるので、for文は</p>
<p><em><strong>&nbsp;for(i=0;i&lt;accountInfo.mosaics.length;i++){</strong></em><br /><em><strong>$('#balance'+i).text(accountInfo.mosaics[i].amount.compact()/1000000);</strong></em><br /><em><strong>}</strong></em></p>
<p>となります。</p>
<p>また、それを画面に表示させたいので、</p>
<p><em><strong>&lt;div style="margin-top:10px;"&gt;</strong></em><br /><em><strong>&nbsp;Balance:&lt;span id="balance0"&gt;0&lt;/span&gt; xym</strong></em><br /><em><strong>&nbsp;Balance:&lt;span id="balance1"&gt;0&lt;/span&gt; mosaic &lt;/div&gt;</strong></em><br />と書く事になります。</p>
<p>&nbsp;</p>

※この記事は、nemlogで企画されたイベントであるしゅうさんの勉強会「しゅうさんといっしょ!」の内容の一部をまとめたものです。
  </body>
</html>