Google スプレッドシートで送金可能なNEMアドレス帳を作る方法

Google スプレッドシートを使った送金可能なアドレス帳をGAS(Google Apps Script) & NEM Catapultで実現しましたのでその方法を紹介します。

GASとNEMの連携については先日投稿した、[Google Apps Script(GAS)でNEM Catapultを使う](https://qiita.com/nem_takanobu/items/dc8089b18da9e0891d3e)を参考にしてください。今回はさらに一歩進展させて、GoogleスプレッドシートとNEM Catapultの連携を行います。

なお、今回もWEBIRD PROGRAMMING.TECHさんの記事、[【GAS】WebアプリやAPIも作れちゃう！HtmlServiceについて、できることをまとめてみた。　～ その③ スプレッドシートのUI ～](https://webird-programming.tech/archives/501)を参考にさせていただきました。


# 画面イメージ

今回作成したツールの画面イメージです。

<img width="888" alt="スクリーンショット 2020-01-03 13.00.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29187/96154ec5-9f29-ee00-3e9c-83d53f396d63.png">

スプレッドシートに送信先、モザイクID(トークン)、送信量を一覧形式で記述しておきます。どんな用途に使用するのかのメモ書きも残しておくことができます。スプレッドシートはメニューからサイドバー表示を選択することができ、送信IDを選択してメッセージwぽ追加してモザイクを送信することができます。

# プログラム構成

今回紹介するツールは2つのプログラムで構成されています。

- コード.gs
- sidebar.html

### コード.gs
- メニューへの追加
- サイドバーコンテンツの表示
- 一覧データを取得しサイドバーへデータ転送

### sidebar.html
- サイドバーコンテンツ
- NEM送信

# プログラム詳細

スプレッドシートを開き1行目に
- ID
- 送信先
- モザイクID
- 送信量

と入力します。以降の列は無視されるのでメモ書きに利用してください。
次にメニューからツール->スクリプトエディタを選択し、Google Apps Script編集画面を開き、以下に紹介する２つのファイルを作成します。ファイルを作成したら、公開->ウェブアプリケーションとして導入を選択して、ビルドしてください。（スプレッドシートのアドオンとして配置などもう少し適切な方法があるかと思いますが短時間では探しきれませんでした）

### gsスクリプト

```js:コード.gs

//メニューに追加
function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('UI表示')
    .addItem('サイドバーを表示', 'showSidebar')
    .addToUi();
}

//サイドバーコンテンツ表示
function showSidebar() {
  var sidebar = HtmlService
    .createTemplateFromFile('sidebar.html')
    .evaluate()
    .setSandboxMode(HtmlService.SandboxMode.IFRAME)
    .setTitle('サイドバー')
  SpreadsheetApp.getUi().showSidebar(sidebar);
}

//IDリストの取得
function getIds() {
  var values = getData();
  var ids = [];
  for(var i = 1, l = values.length; i < l; i++) {
    ids.push(values[i][0]);
  }
  return ids;
}

//送信データの取得
function sendNEM(id) {

  var prop = {};
  var values   = getData();
  prop.address = values[id][1];
  prop.mosaicId = values[id][2];
  prop.amount    = values[id][3];
  
  return prop;
} 

//データ取得
function getData() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getActiveSheet();
  var value = sheet.getDataRange().getValues();
  return value;
}

```

### htmlコンテンツ

```sidebar.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
  </head>
  <body>
    <label for="send-id">送信ID</label>
    <br>
    <select id="send-id" name="send-id" style="margin-bottom: 10px;" >
      <?
        var ids = getIds();
        for(var i = 0, l = ids.length; i < l; i++) {
          output.append('<option value="' + ids[i] + '">' + ids[i] + '</option>');
        }
      ?>
    </select>
    <br>
    
    <label for="message">メッセージ</label><br>
    <textarea id="message"></textarea><br>

    <button class="action" onclick="sendNEM()">送信！</button><br>
    <div id="send-status"></div>
    
<script src="https://s3-ap-northeast-1.amazonaws.com/xembook.net/nem2-sdk/nem2-sdk-0.16.1.js"></script>
<script>
const NODE = 'https://jp5.nemesis.land:3001';
const nem = require("/node_modules/nem2-sdk");
const alice  = nem.Account.createFromPrivateKey('DF1A2101A6BA32F33C60B6A59AA72170BB0AC5A4E1057FBA706DC2B999E902C4', nem.NetworkType.TEST_NET);      
const GENERATION_HASH = "CC42AAD7BD45E8C276741AB2524BC30F5529AF162AD12247EF9A98D6B54A385B";

function sendNEM() {
        
    var id = $("#send-id").val();
        
    google.script.run
    .withFailureHandler(function(err) {
          $("#send-status").html(err);
    })
    .withSuccessHandler(function(res) {

        const tx = nem.TransferTransaction.create(
            nem.Deadline.create(),
            nem.Address.createFromRawAddress(res.address),
            [
            new nem.Mosaic(
                new nem.MosaicId(res.mosaicId),
                nem.UInt64.fromUint(res.amount)
            )
            ],
            nem.PlainMessage.create($("#message").val()),
            nem.NetworkType.TEST_NET,
            nem.UInt64.fromUint(100000)
        );

        const signedTx = alice.sign(tx,GENERATION_HASH);
        const txHttp = new nem.TransactionHttp(NODE);
        console.log(NODE + "/transaction/" + signedTx.hash + "/status");

        txHttp
        .announce(signedTx)
        .subscribe(_ => console.log("ネットワーク通知"), err => console.error(err));

        console.log(res);
        $("#send-status").html('送信しました！');
    })
    .sendNEM(id);  // GAS側のsendNEM関数を呼び出し
}
    </script>
  </body>
</html>
```

# ツールの実行
スプレッドシートを表示しメニューからUI表示->「サイドバーを表示」を選択するとサイドバーが表示されます。送信したいIDをリストボックスから選択し、メッセージを追加して送信ボタンをクリックするとスプレッドシートに記載されたデータを元にNEMブロックチェーンの送信処理が行われます。


# 終わりに

NEMブロックチェーンのREST API機能を利用してGoogleスプレッドシート上のデータから送信する機能を実装してみました。この機会にNEMブロックチェーンの可能性を感じていただければ幸いです。