コピペで動くXYMの残高チェック【Vue.js編 初心者向け】

# はじめに

この記事ではVue.jsでSymbolのアカウントが保有しているモザイク情報(今回はXYMのみ)を表示するWEBプログラムを作成します。
Vue.jsとSymbolの非同期の親和性はそれなりに良いと思うので導入編としては扱いやすいと思います。
また、ある程度はプログラミングが出来る人を前提に話を進めます。（Vue.jsの詳しい解説はしません）
このプログラムはWEBブラウザでファイルを開くだけで実行出来るのでVue.jsはわからないけどちょっと試してみたい、と思っている人も是非やってみてください。


# 必要なもの
* PC
* インターネット接続環境
* テキストエディタ（VSCodeを推奨）
* Google Chromeブラウザ
* めげない心


いきなりソースコード全文いきます。（後で解説します）
まずは、下記のコードをindex.htmlと名前を付けてPCのデスクトップに保存してください。


```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
  <title>モザイク保有量表示</title>
</head>
<body>
  <div id="app">
    <div class="container">
      <div class="card mt-3">
        <div class="card-body">
          <h5 class="card-title">モザイク保有量表示</h5>
          <div class="card-text">
            <div class="mb-3">
              <label for="address" class="form-label">address</label>
              <input v-model="rawAddress" type="text" class="form-control" id="address" placeholder="Tから始まるテストネットのアドレス39文字" />
            </div>
          </div>
          <div class="card-text mb-3">
            モザイク保有量：{{ account.amount }}
          </div>
          <button type="button" class="btn btn-primary" @click="showInfo">モザイク保有量表示</button>
        </div>
      </div>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
  <script src="https://xembook.github.io/nem2-browserify/symbol-sdk-1.0.2.js"></script>
  <script>
    nem = require("/node_modules/symbol-sdk")
    op = require("/node_modules/rxjs/operators")
    NODE = 'https://sym-test.opening-line.jp:3001'
    var app = new Vue({
      el: '#app',
      data: {
        rawAddress: '',
        accountHttp: new nem.AccountHttp(NODE),
        account: {
          amount: 0
        },
        currencyId: '3A8416DB2D53B6C8',
      },
      methods: {
        showInfo(){
          const address = nem.Address.createFromRawAddress(this.rawAddress)
          const accountInfo = this.accountHttp.getAccountInfo(address)
          accountInfo.pipe(
            op.mergeMap(_=>_.mosaics),
            op.filter(_ => _.id.toHex() === this.currencyId),
          )
          .subscribe(_=>{
            this.account.amount =  parseFloat(this.dispAmount(_.amount.toString(),6))
          });
        },
        dispAmount(amount,divisibility){	
          const strNum = amount.toString();
          if(divisibility > 0){

            if(amount < Math.pow(10, divisibility)){

              return "0." + this.paddingAmount0(strNum,0,divisibility);

            }else{

              const r = strNum.slice(-divisibility);
              const l = strNum.substring(0,strNum.length - divisibility);
              return this.comma3(l) + "." + r;
            }
          }else{
            return this.comma3(strNum);
          }
        },
        comma3(strNum){
          return strNum.replace( /(\d)(?=(\d\d\d)+(?!\d))/g, '$1,');
        },
        paddingAmount0(val,char,n){
          for(; val.length < n; val= char + val);
          return val;
        }
      },
    })
  </script>
</body>
</html>
```

index.htmlとして保存したらファイルをGoogle Chromeへドラッグして放り込みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/1842431a-9c08-dfca-24a6-7bc45d0d952d.png)


はい、こんな感じで表示されると思います。
では、address部分にテストネットのアドレスを入れて、「アカウント情報表示」を押してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/eef83de5-d66c-160c-3858-61dffaf862a9.png)


こんな感じで、入力したアドレスのモザイク保有量が表示されると思います。

# ソースコードの解説

### bootstrap、vuejs、nem2-browserifyの準備

```html
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">

...略

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script src="https://xembook.github.io/nem2-browserify/symbol-sdk-1.0.2.js"></script>
<script>

...略

</script>
```

### ライブラリのインポート、ノードの宣言
ノードは [Opening Line](https://www.opening-line.co.jp) さんのノードをお借りしました。

```javascript
nem = require("/node_modules/symbol-sdk")
op = require("/node_modules/rxjs/operators")
NODE = 'https://sym-test.opening-line.jp:3001'
```

### Vuejs部分

（vuejsの書き方等はここでは解説しません）
ソースコード上にコメントを追記しましたのでそちらを参照してください。

```javascript
var app = new Vue({
  el: '#app',
  data: {
    rawAddress: '',                          //アドレス文字列が入る変数
    accountHttp: new nem.AccountHttp(NODE),  //アカウントリポジトリ
    account: {                               //アカウントリポジトリから取得したモザイク量を入れる変数
      amount: 0
    },
    currencyId: '3A8416DB2D53B6C8',          //モザイクID(テストネットのXYMモザイクID)
  },
  methods: {
    showInfo(){
      //入力されたアドレスをsymbolのアドレスに変換
      const address = nem.Address.createFromRawAddress(this.rawAddress)
      //アカウントリポジトリから指定したaddressのアカウントインフォを取得
      const accountInfo = this.accountHttp.getAccountInfo(address)
      //アカウントリポジトリから取得したアカウントインフォの情報を加工
      accountInfo.pipe(
        ※1
        op.mergeMap(_=>_.mosaics),
        op.filter(_ => _.id.toHex() === this.currencyId),  //指定モザイクのデータのみ返却
      )
      .subscribe(_=>{
        //モザイク量を取得
        this.account.amount =  parseFloat(this.dispAmount(_.amount.toString(),6))
      });
    },
    //モザイク量を整形するための関数
    dispAmount(amount,divisibility){
      const strNum = amount.toString();
      if(divisibility > 0){

        if(amount < Math.pow(10, divisibility)){

          return "0." + this.paddingAmount0(strNum,0,divisibility);

        }else{

          const r = strNum.slice(-divisibility);
          const l = strNum.substring(0,strNum.length - divisibility);
          return this.comma3(l) + "." + r;
        }
      }else{
        return this.comma3(strNum);
      }
    },
    comma3(strNum){
      return strNum.replace( /(\d)(?=(\d\d\d)+(?!\d))/g, '$1,');
    },
    paddingAmount0(val,char,n){
      for(; val.length < n; val= char + val);
      return val;
    }
  },
})
```

※1の部分で指定したモザイクのデータのみをフィルタしているので、その他アカウント情報が見てみたい方は下記のようにしてログに出力して眺めてみてください。

```javascript
...略
      //アカウントリポジトリから取得したアカウントインフォの情報を加工
      accountInfo
      .subscribe(_=>{
        //モザイク量を取得
        this.account.amount =  parseFloat(this.dispAmount(_.amount.toString(),6))
      });
```

こんな感じで、アカウントの情報が取得できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/8a5508d6-e571-9803-e510-5a64b6c3ddb7.png)

# 最後に

この記事は、これからブロックチェーンに触ってみようかな、と興味を持った人向けの導入記事として書いています。
「SymbolならSDKも扱いやすいしWebAPIも手軽に使えるよ」と言ったことが少しでも伝われば幸いです。


あと、この記事を書いた理由として、Symbolの日本語での解説記事やコード例などはリファレンスやQiitaに沢山ありますが、必要最低限のコードしか書いてなかったり、急によくわからない変数が出てきたりと、初心者が色々と情報を探すのに探すのに苦労した。という自分の体験をもとに、実装コードを全部載せにしています。Symbol初心者の方が迷わなくても良いように今後も機会があればコード全部載せで解説していきたいと思います。


また、下記のようなツールやサイトも作っていますのでもしよかったらご利用ください。

https://nemlog.nem.social/blog/65117

https://nemlog.nem.social/blog/72097

# 参考

https://docs.symbolplatform.com/ja/sdk.html

https://docs.symbolplatform.com/ja/api.html

* [Symbol from NEMやmijin Catapultで最新のアカウント情報を取得する](https://qiita.com/nem_takanobu/items/45b6972a95805afabf3a
)

# 補足

Vue.js使ってるとnpm install ～　みたいなの使いたくなることがよくあります。
もちろんSybmol SDKもnpm install --save symbol-sdkでインストールして使うことができます。
そのあたりはまた今度、記事に出来たらと思います。

今年の[nem Advent Calendar 2021](https://qiita.com/advent-calendar/2021/nem)のレベル高すぎ(笑)なのでこの記事を書くのを迷ったけど、Sybmolを始めるきっかけになれば幸いです。