はじめに
前回の続きです。LINE Blockchain Developers SDK for JavaScriptでサービストークンを取り扱ってみます。
前回のソースコードからAPI SECRETなどはdotenvに移行しました。
.env
は以下のように記述します
BASE_URL='https://test-api.blockchain.line.me'
SERVICE_API_KEY='[Your API Key]'
SERVICE_API_SECRET='[Your API Secret]'
OWNER_WALLET_ADDRESS='[Your Owner Wallet Address]'
OWNER_WALLET_SECRET='[Your Owner Wallet Secret]'
サービストークンを鋳造する
サービストークンを鋳造して指定のウォレットに発行します。まずは指定するウォレットの残高を確認しましょう。
import * as dotenv from 'dotenv';
import * as devSdk from '@line/lbd-sdk-js';
import {
ServiceToken,
WalletResponse,
MintServiceTokenRequest,
TxHashResponse,
ServiceTokenBalance
} from '@line/lbd-sdk-js';
dotenv.config();
const httpClient = new devSdk.HttpClient(
process.env.BASE_URL as string,
process.env.SERVICE_API_KEY as string,
process.env.SERVICE_API_SECRET as string
);
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 getWallets = 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;
if (!result) throw new Error('No wallet');
return result;
};
const getWalletByName = (name: string, wallets: WalletResponse[]): WalletResponse|undefined => {
return wallets.find((w) => { return w.name === name });
};
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 wallets = await getWallets();
const wallet = getWalletByName('bathtimefish', wallets);
if (!wallet) throw new Error('Wallet not found');
const bal = await getBalanceOfService(wallet.walletAddress, st.contractId);
console.log(bal);
};
main();
bathtimefish
ウォレットの残高は10000
のようです
yarn run ts-node src/index.ts
{
contractId: '[contruct ID]',
name: 'BTFCoin',
symbol: 'BTF',
imgUri: '[image icon url]',
decimals: 6,
amount: '10000'
}
mintServiceToken()
を追加してBTFCoinを1000
鋳造してbathtimefish
ウォレットに発行します
s dotenv from 'dotenv';
import * as devSdk from '@line/lbd-sdk-js';
import {
ServiceToken,
WalletResponse,
MintServiceTokenRequest,
TxHashResponse,
ServiceTokenBalance
} from '@line/lbd-sdk-js';
dotenv.config();
const httpClient = new devSdk.HttpClient(
process.env.BASE_URL as string,
process.env.SERVICE_API_KEY as string,
process.env.SERVICE_API_SECRET as string
);
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 mintServiceToken =async ( contructId: string, req: MintServiceTokenRequest): Promise<TxHashResponse> => {
const res = await httpClient.mintServiceToken(contructId, req);
const result = res.responseData;
if (!result) throw new Error('Error');
return result;
};
const getWallets = 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;
if (!result) throw new Error('No wallet');
return result;
};
const getWalletByName = (name: string, wallets: WalletResponse[]): WalletResponse|undefined => {
return wallets.find((w) => { return w.name === name });
};
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();
console.log(st);
const wallets = await getWallets();
const wallet = getWalletByName('bathtimefish', wallets);
if (!wallet) throw new Error('Wallet not found');
const bal = await getBalanceOfService(wallet.walletAddress, st.contractId);
console.log(bal);
const mintRequest: MintServiceTokenRequest = {
toAddress: wallet.walletAddress,
amount: '1000',
ownerAddress: process.env.OWNER_WALLET_ADDRESS as string,
ownerSecret: process.env.OWNER_WALLET_SECRET as string,
};
const mintResult = await mintServiceToken(st.contractId, mintRequest);
console.log(mintRequest);
};
main();
mintResult
を確認すると正常に処理できた感じです
yarn run ts-node src/index.ts
{
toAddress: '[To Wallet Address]',
amount: '1000',
ownerAddress: '[Owner Wallet Address]',
ownerSecret: '[Owner Wallet Secret]'
}
結果は即時反映されないようなので、すこし経ってからもう一度残高を確認します
import * as dotenv from 'dotenv';
import * as devSdk from '@line/lbd-sdk-js';
import {
ServiceToken,
WalletResponse,
MintServiceTokenRequest,
TxHashResponse,
ServiceTokenBalance
} from '@line/lbd-sdk-js';
dotenv.config();
const httpClient = new devSdk.HttpClient(
process.env.BASE_URL as string,
process.env.SERVICE_API_KEY as string,
process.env.SERVICE_API_SECRET as string
);
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 mintServiceToken =async ( contructId: string, req: MintServiceTokenRequest): Promise<TxHashResponse> => {
const res = await httpClient.mintServiceToken(contructId, req);
const result = res.responseData;
if (!result) throw new Error('Error');
return result;
};
const getWallets = 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;
if (!result) throw new Error('No wallet');
return result;
};
const getWalletByName = (name: string, wallets: WalletResponse[]): WalletResponse|undefined => {
return wallets.find((w) => { return w.name === name });
};
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();
console.log(st);
const wallets = await getWallets();
const wallet = getWalletByName('bathtimefish', wallets);
if (!wallet) throw new Error('Wallet not found');
const bal = await getBalanceOfService(wallet.walletAddress, st.contractId);
console.log(bal);
};
main();
残高が11000
に増えました
yarn run ts-node src/index.ts
{
contractId: '[contruct ID]',
name: 'BTFCoin',
symbol: 'BTF',
imgUri: '[image icon url]',
decimals: 6,
amount: '11000'
}
サービストークンを転送する
サービストークンを他のウォレットに転送します。ここではあらかじめ転送先のAlice
ウォレットをLINE Blockchain Developersコンソールで作成しておきます
まず、Alice
ウォレットの残高を確認します
rt * as dotenv from 'dotenv';
import * as devSdk from '@line/lbd-sdk-js';
import {
ServiceToken,
WalletResponse,
ServiceTokenBalance
} from '@line/lbd-sdk-js';
dotenv.config();
const httpClient = new devSdk.HttpClient(
process.env.BASE_URL as string,
process.env.SERVICE_API_KEY as string,
process.env.SERVICE_API_SECRET as string
);
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 getWallets = 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;
if (!result) throw new Error('No wallet');
return result;
};
const getWalletByName = (name: string, wallets: WalletResponse[]): WalletResponse|undefined => {
return wallets.find((w) => { return w.name === name });
};
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 wallets = await getWallets();
const ownerWallet = getWalletByName('bathtimefish', wallets);
const aliceWallet = getWalletByName('Alice', wallets);
if (!ownerWallet) throw new Error('Wallet not found');
if (!aliceWallet) throw new Error('Wallet not found');
const bal = await getBalanceOfService(aliceWallet.walletAddress, st.contractId);
console.log(bal);
};
main();
Alice
の残高は0
です
yarn run ts-node src/index.ts
{
contractId: '[contruct ID]',
name: 'BTFCoin',
symbol: 'BTF',
imgUri: '[image icon url]',
decimals: 6,
amount: '0'
}
bathtimefish
からAlice
へサービストークン1000
を転送します
import * as dotenv from 'dotenv';
import * as devSdk from '@line/lbd-sdk-js';
import {
ServiceToken,
WalletResponse,
ServiceTokenBalance,
TransferServiceTokenRequest,
} from '@line/lbd-sdk-js';
dotenv.config();
const httpClient = new devSdk.HttpClient(
process.env.BASE_URL as string,
process.env.SERVICE_API_KEY as string,
process.env.SERVICE_API_SECRET as string
);
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 getWallets = 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;
if (!result) throw new Error('No wallet');
return result;
};
const getWalletByName = (name: string, wallets: WalletResponse[]): WalletResponse|undefined => {
return wallets.find((w) => { return w.name === name });
};
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 transferServiceToken = async (walletAddress: string, contractId: string, request: TransferServiceTokenRequest) => {
const res = await httpClient.transferServiceTokenOfWallet(walletAddress, contractId, request);
if (!res || !res.responseData) throw new Error('No response data');
const result = res.responseData;
if (!result) throw new Error('No balance data');
return result;
}
const main = async () => {
const st = await getServiceToken();
const wallets = await getWallets();
const ownerWallet = getWalletByName('bathtimefish', wallets);
const aliceWallet = getWalletByName('Alice', wallets);
if (!ownerWallet) throw new Error('Wallet not found');
if (!aliceWallet) throw new Error('Wallet not found');
const transferRequest: TransferServiceTokenRequest = {
walletSecret: process.env.OWNER_WALLET_SECRET as string,
toAddress: aliceWallet.walletAddress,
amount: '1000',
};
const transferResult = await transferServiceToken(ownerWallet.walletAddress, st.contractId, transferRequest);
console.log(transferRequest);
main();
転送できたようです
yarn run ts-node src/index.ts
{
walletSecret: '[Wallet Secret]',
toAddress: '[To Wallet Address]',
amount: '1000'
}
結果は即時反映されないようなので、すこし経ってからもう一度残高を確認します
import * as dotenv from 'dotenv';
import * as devSdk from '@line/lbd-sdk-js';
import {
ServiceToken,
WalletResponse,
ServiceTokenBalance,
TransferServiceTokenRequest,
} from '@line/lbd-sdk-js';
dotenv.config();
const httpClient = new devSdk.HttpClient(
process.env.BASE_URL as string,
process.env.SERVICE_API_KEY as string,
process.env.SERVICE_API_SECRET as string
);
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 getWallets = 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;
if (!result) throw new Error('No wallet');
return result;
};
const getWalletByName = (name: string, wallets: WalletResponse[]): WalletResponse|undefined => {
return wallets.find((w) => { return w.name === name });
};
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 wallets = await getWallets();
const ownerWallet = getWalletByName('bathtimefish', wallets);
const aliceWallet = getWalletByName('Alice', wallets);
if (!ownerWallet) throw new Error('Wallet not found');
if (!aliceWallet) throw new Error('Wallet not found');
const bal = await getBalanceOfService(aliceWallet.walletAddress, st.contractId);
console.log(bal);
};
main();
残高が増えました
{
contractId: '[contruct ID]',
name: 'BTFCoin',
symbol: 'BTF',
imgUri: '[image icon url]',
decimals: 6,
amount: '1000'
}
サービストークンを焼却する
指定したウォレットのサービストークンを焼却します。bathtimefish
のトークンを1000
焼却します
import * as dotenv from 'dotenv';
import * as devSdk from '@line/lbd-sdk-js';
import {
ServiceToken,
WalletResponse,
ServiceTokenBalance,
BurnFromServiceTokenRequest,
TxHashResponse,
} from '@line/lbd-sdk-js';
dotenv.config();
const httpClient = new devSdk.HttpClient(
process.env.BASE_URL as string,
process.env.SERVICE_API_KEY as string,
process.env.SERVICE_API_SECRET as string
);
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 getWallets = 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;
if (!result) throw new Error('No wallet');
return result;
};
const getWalletByName = (name: string, wallets: WalletResponse[]): WalletResponse|undefined => {
return wallets.find((w) => { return w.name === name });
};
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 burnServiceToken = async (contractId: string, request: BurnFromServiceTokenRequest): Promise<TxHashResponse> => {
const res = await httpClient.burnFromServiceToken(contractId, request);
if (!res || !res.responseData) throw new Error('No response data');
const result = res.responseData;
if (!result) throw new Error('No data');
return result;
}
const main = async () => {
const st = await getServiceToken();
const wallets = await getWallets();
const wallet = getWalletByName('bathtimefish', wallets);
if (!wallet) throw new Error('Wallet not found');
const burnRequest: BurnFromServiceTokenRequest = {
fromAddress: wallet.walletAddress,
amount: '1000',
ownerAddress: process.env.OWNER_WALLET_ADDRESS as string,
ownerSecret: process.env.OWNER_WALLET_SECRET as string,
};
const burnResult = await burnServiceToken(st.contractId, burnRequest);
console.log(burnRequest);
};
main();
焼却できたようです
{
fromAddress: '[From Wallet Address]',
amount: '1000',
ownerAddress: '[Owner Wallet Address]',
ownerSecret: '[Owner Wallet Secret]'
}
結果は即時反映されないようなので、すこし経ってからもう一度残高を確認します
import * as dotenv from 'dotenv';
import * as devSdk from '@line/lbd-sdk-js';
import {
ServiceToken,
WalletResponse,
ServiceTokenBalance,
BurnFromServiceTokenRequest,
TxHashResponse,
} from '@line/lbd-sdk-js';
dotenv.config();
const httpClient = new devSdk.HttpClient(
process.env.BASE_URL as string,
process.env.SERVICE_API_KEY as string,
process.env.SERVICE_API_SECRET as string
);
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 getWallets = 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;
if (!result) throw new Error('No wallet');
return result;
};
const getWalletByName = (name: string, wallets: WalletResponse[]): WalletResponse|undefined => {
return wallets.find((w) => { return w.name === name });
};
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 burnServiceToken = async (contractId: string, request: BurnFromServiceTokenRequest): Promise<TxHashResponse> => {
const res = await httpClient.burnFromServiceToken(contractId, request);
if (!res || !res.responseData) throw new Error('No response data');
const result = res.responseData;
if (!result) throw new Error('No data');
return result;
}
const main = async () => {
const st = await getServiceToken();
const wallets = await getWallets();
const wallet = getWalletByName('bathtimefish', wallets);
if (!wallet) throw new Error('Wallet not found');
const bal = await getBalanceOfService(wallet.walletAddress, st.contractId);
console.log(bal);
};
main();
残高が減りました
{
contractId: '[contruct ID]',
name: 'BTFCoin',
symbol: 'BTF',
imgUri: '[image icon url]',
decimals: 6,
amount: '9000'
}
おわりに
サービストークンはERC-20規格に似ているため仮想通貨のようなものを作ることができます。LINE BrockchainのJavaScript SDKを使って上記のように簡単に扱うことができるので仮想通貨を初学者は勉強に使のもいいかもしれません。