LINE Blockchain APIでサービストークンの情報を取得してみる

# はじめに

[前回](https://qiita.com/bathtimefish/items/86991137a0752c93619d)の続きです。LINE Blockchainサービスを作成してAPI KeyやSecretが取得できたので[LINE Blockchain Developers SDK for JavaScript](https://docs-blockchain.line.biz/ja/sdk/javascript-guide)を使用してサービストークンの情報を取得してみましょう

なお、LINE Blockchain Developers SDK for JavaScript自体のドキュメントは現時点で存在しないようで、メソッドやオブジェクト型などはソースコードやLINE Blockchain APIのリファレンスを参照しながら探りました。公式の[examples](https://github.com/line/line-blockchain-developers-sdk-js/tree/develop/examples)もしょぼすぎて当てにならず。なので微妙に間違っているところがあるかもしれませんのでご容赦ください。処理は通っているので多分大丈夫だと思うけど。。

# LINE Blockchain Developers SDK for JavaScriptをセットアップする

前回も記載していますが念の為。TypeScriptでJavaScriptライブラリを利用する環境をセットアップします

```shell
mkdir lbd-sdk && cd $_
yarn init
yarn add -D typescript ts-node
yarn add @line/lbd-sdk-js
yarn run tsc --init
mkdir src
```

# サービストークンを取得する

作成したBlockchainサービスが発行したサービストークンの一覧をAPIで取得し、最初に発行されたサービストークンの情報を表示しています

```src/index.ts
import * as devSdk from '@line/lbd-sdk-js';
import { ServiceToken } from '@line/lbd-sdk-js';

const BASE_URL = 'https://test-api.blockchain.line.me';
const SERVICE_API_KEY = 'your own service api-key';
const SERVICE_API_SECRET = 'your own service api-secret';

const httpClient = new devSdk.HttpClient(BASE_URL, SERVICE_API_KEY, SERVICE_API_SECRET);

const getServiceToken = async (): Promise<ServiceToken> => {
  const srvs = await httpClient.serviceTokens();
  if (!srvs.responseData || srvs.responseData?.length < 1) throw new Error('No response data');
  const results = srvs.responseData;
  if (!results || results.length < 1) throw new Error('No service tokens');
  return results[0];
}; 

const main = async () => {
  const st = await getServiceToken();
  console.log(st);
};

main();
```

実行すると最初のサービストークンの情報が取得できます。`contructId`などがあとで必要になります

```shell
yarn run ts-node src/index.ts
{
  contractId: '[contract ID]',
  ownerAddress: '[owner address]',
  name: 'BTFCoin',
  symbol: 'BTF',
  imgUri: '[icon image url]',
  meta: '',
  decimals: 6,
  createdAt: 1660370014467,
  totalSupply: '10000',
  totalMint: '10000',
  totalBurn: '0',
  serviceId: '[service ID]'
}
```

# サービスウォレットの情報を取得する

上記にサービスウォレットの情報を取得するコードを追加します。

```src/index.ts
import * as devSdk from '@line/lbd-sdk-js';
import { ServiceToken, WalletResponse } from '@line/lbd-sdk-js';

const BASE_URL = 'https://test-api.blockchain.line.me';
const SERVICE_API_KEY = 'your own service api-key';
const SERVICE_API_SECRET = 'your own service api-secret';

const httpClient = new devSdk.HttpClient(BASE_URL, SERVICE_API_KEY, SERVICE_API_SECRET);

const getServiceToken = async (): Promise<ServiceToken> => {
  const srvs = await httpClient.serviceTokens();
  if (!srvs.responseData || srvs.responseData?.length < 1) throw new Error('No response data');
  const results = srvs.responseData;
  if (!results || results.length < 1) throw new Error('No service tokens');
  return results[0];
};

const getWallet = async (): Promise<WalletResponse> => {
  const wallets = await httpClient.wallets()
  if (!wallets.responseData || wallets.responseData?.length < 1) throw new Error('No response data');
  const result = wallets.responseData[0];
  if (!result) throw new Error('No wallet');
  return result;
}

const main = async () => {
  const st = await getServiceToken();
  const wal = await getWallet();
  console.log(wal);
};

main();
```

```shell
yarn run ts-node src/index.ts
{
  name: 'bathtimefish',
  walletAddress: '[your wallet address]',
  createdAt: 1660361831000
}
```

なお、以下の`getWalletDetail()`のようにすれば指定したウォレットアドレスの情報のみを取得することもできます。

```src/index.ts
const getWallet = async (): Promise<WalletResponse> => {
  const wallets = await httpClient.wallets()
  if (!wallets.responseData || wallets.responseData?.length < 1) throw new Error('No response data');
  const result = wallets.responseData[0];
  if (!result) throw new Error('No wallet');
  return result;
}

const getWalletDetail = async (address: string): Promise<WalletResponse> => {
  const detail = await httpClient.walletDetail(address);
  if (!detail || !detail.responseData) throw new Error('No response data');
  const result = detail.responseData;
  if (!result) throw new Error('No wallet');
  return result;
}

const main = async () => {
  const wal = await getWallet();
  // console.log(wal);
  console.log(await getWalletDetail(wal.walletAddress));
};

main();
```

# サービスウォレットのトランザクション履歴を取得する

サービスウォレットのトランザクション履歴を取得してみます

```src/index.ts
import * as devSdk from '@line/lbd-sdk-js';
import { PageRequest, ServiceToken, TxHashResponse, WalletResponse } from '@line/lbd-sdk-js';

const BASE_URL = 'https://test-api.blockchain.line.me';
const SERVICE_API_KEY = 'your own service api-key';
const SERVICE_API_SECRET = 'your own service api-secret';

const httpClient = new devSdk.HttpClient(BASE_URL, SERVICE_API_KEY, SERVICE_API_SECRET);

const getServiceToken = async (): Promise<ServiceToken> => {
  const srvs = await httpClient.serviceTokens();
  if (!srvs.responseData || srvs.responseData?.length < 1) throw new Error('No response data');
  const results = srvs.responseData;
  if (!results || results.length < 1) throw new Error('No service tokens');
  return results[0];
};

const getWallet = async (): Promise<WalletResponse> => {
  const wallets = await httpClient.wallets()
  if (!wallets.responseData || wallets.responseData?.length < 1) throw new Error('No response data');
  const result = wallets.responseData[0];
  if (!result) throw new Error('No wallet');
  return result;
}

const getWalletDetail = async (address: string): Promise<WalletResponse> => {
  const detail = await httpClient.walletDetail(address);
  if (!detail || !detail.responseData) throw new Error('No response data');
  const result = detail.responseData;
  if (!result) throw new Error('No wallet');
  return result;
}

const getTransactionsOfWallet = async (address: string): Promise<TxHashResponse> => {
  const pr: PageRequest = {
    page: 5,
    limit: 100,
    orderBy: devSdk.OrderBy.DESC,
  };
  const trans = await httpClient.walletTransactions(address, pr);
  if (!trans || !trans.responseData) throw new Error('No response data');
  const result = trans.responseData;
  if (!result) throw new Error('No wallet');
  return result;
}

const main = async () => {
  const st = await getServiceToken();
  const wal = await getWallet();
  const trans = await getTransactionsOfWallet(wal.walletAddress);
  console.log(trans);
};

main();
```

まだこのウォレットで取引していないのでトランザクションは発生してませんでした

```shell
yarn run ts-node src/index.ts
[]
```

# サービスウォレットの残高を取得する

サービスウォレットの中のサービストークンの残高を取得します

```src/index.ts
import * as devSdk from '@line/lbd-sdk-js';
import { PageRequest, ServiceToken, ServiceTokenBalance, TxHashResponse, WalletResponse } from '@line/lbd-sdk-js';

const BASE_URL = 'https://test-api.blockchain.line.me';
const SERVICE_API_KEY = 'your own service api-key';
const SERVICE_API_SECRET = 'your own service api-secret';

const httpClient = new devSdk.HttpClient(BASE_URL, SERVICE_API_KEY, SERVICE_API_SECRET);

const getServiceToken = async (): Promise<ServiceToken> => {
  const srvs = await httpClient.serviceTokens();
  if (!srvs.responseData || srvs.responseData?.length < 1) throw new Error('No response data');
  const results = srvs.responseData;
  if (!results || results.length < 1) throw new Error('No service tokens');
  return results[0];
};

const getWallet = async (): Promise<WalletResponse> => {
  const wallets = await httpClient.wallets()
  if (!wallets.responseData || wallets.responseData?.length < 1) throw new Error('No response data');
  const result = wallets.responseData[0];
  if (!result) throw new Error('No wallet');
  return result;
}

const getWalletDetail = async (address: string): Promise<WalletResponse> => {
  const detail = await httpClient.walletDetail(address);
  if (!detail || !detail.responseData) throw new Error('No response data');
  const result = detail.responseData;
  if (!result) throw new Error('No wallet');
  return result;
}

const getTransactionsOfWallet = async (address: string): Promise<TxHashResponse> => {
  const pr: PageRequest = {
    page: 5,
    limit: 100,
    orderBy: devSdk.OrderBy.DESC,
  };
  const trans = await httpClient.walletTransactions(address, pr);
  if (!trans || !trans.responseData) throw new Error('No response data');
  const result = trans.responseData;
  if (!result) throw new Error('No wallet');
  return result;
}

const getBalanceOfService = async (address: string, contructId: string): Promise<ServiceTokenBalance> => {
  const balance = await httpClient.serviceTokenBalanceOfWallet(address, contructId);
  if (!balance || !balance.responseData) throw new Error('No response data');
  const result = balance.responseData;
  if (!result) throw new Error('No balance data');
  return result;
}

const main = async () => {
  const st = await getServiceToken();
  const wal = await getWallet();
  // const trans = await getTransactionsOfWallet(wal.walletAddress);
  const swBal = await getBalanceOfService(wal.walletAddress, st.contractId);
  console.log(swBal);
};

main();
```

サービス作成時に発行した10000が残高となっているのがわかります

```shell
yarn run ts-node src/index.ts
{
  contractId: '[contruct ID]',
  name: 'BTFCoin',
  symbol: 'BTF',
  imgUri: '[image icon url]',
  decimals: 6,
  amount: '10000'
}
```

# サービスウォレットのBase Coinの残高を取得する

BaseCoinの残高を取得してみます

```src/index.ts
import * as devSdk from '@line/lbd-sdk-js';
import { BaseCoinBalance, PageRequest, ServiceToken, ServiceTokenBalance, TxHashResponse, WalletResponse } from '@line/lbd-sdk-js';

const BASE_URL = 'https://test-api.blockchain.line.me';
const SERVICE_API_KEY = 'your own service api-key';
const SERVICE_API_SECRET = 'your own service api-secret';

const httpClient = new devSdk.HttpClient(BASE_URL, SERVICE_API_KEY, SERVICE_API_SECRET);

const getServiceToken = async (): Promise<ServiceToken> => {
  const srvs = await httpClient.serviceTokens();
  if (!srvs.responseData || srvs.responseData?.length < 1) throw new Error('No response data');
  const results = srvs.responseData;
  if (!results || results.length < 1) throw new Error('No service tokens');
  return results[0];
};

const getWallet = async (): Promise<WalletResponse> => {
  const wallets = await httpClient.wallets()
  if (!wallets.responseData || wallets.responseData?.length < 1) throw new Error('No response data');
  const result = wallets.responseData[0];
  if (!result) throw new Error('No wallet');
  return result;
}

const getWalletDetail = async (address: string): Promise<WalletResponse> => {
  const detail = await httpClient.walletDetail(address);
  if (!detail || !detail.responseData) throw new Error('No response data');
  const result = detail.responseData;
  if (!result) throw new Error('No wallet');
  return result;
}

const getTransactionsOfWallet = async (address: string): Promise<TxHashResponse> => {
  const pr: PageRequest = {
    page: 5,
    limit: 100,
    orderBy: devSdk.OrderBy.DESC,
  };
  const trans = await httpClient.walletTransactions(address, pr);
  if (!trans || !trans.responseData) throw new Error('No response data');
  const result = trans.responseData;
  if (!result) throw new Error('No wallet');
  return result;
}

const getBalanceOfService = async (address: string, contructId: string): Promise<ServiceTokenBalance> => {
  const balance = await httpClient.serviceTokenBalanceOfWallet(address, contructId);
  if (!balance || !balance.responseData) throw new Error('No response data');
  const result = balance.responseData;
  if (!result) throw new Error('No balance data');
  return result;
}

const getBaseCoinBalanceOfWallet = async (address: string): Promise<BaseCoinBalance> => {
  const balance = await httpClient.baseCoinBalanceOfWallet(address);
  if (!balance || !balance.responseData) throw new Error('No response data');
  const result = balance.responseData;
  if (!result) throw new Error('No balance data');
  return result;
}

const main = async () => {
  const st = await getServiceToken();
  const wal = await getWallet();
  // const trans = await getTransactionsOfWallet(wal.walletAddress);
  // const swBal = await getBalanceOfService(wal.walletAddress, st.contractId);
  const bc = await getBaseCoinBalanceOfWallet(wal.walletAddress);
  console.log(bc);
};

main();
```

```shell
yarn run ts-node src/index.ts
{ symbol: 'TC', decimals: 6, amount: '0' }
```

# おわりに

JavaScript SDKを利用してざっとサービストークンの情報を取得してみました。次回はここから転送して残高確認などをやってみたいと思います。