Symbol入門 その4
はじめてのアプリケーションを作成
少しずつSymbolの技術について勉強中です。
まずは、入門ということで下記の公式ドキュメントを読んでいくことにしました。
日本語になっているのは非常にありがたいですね。
—
Symbol入門 その3にて開発環境を構築したので、今回は実際にサンプルアプリケーションを作ってみたいと思います。
作成したコードは下記のリポジトリにアップしています。
typescriptのコーディング環境整備
前回作成したプロジェクトのフォルダにコーディング環境を整備します。
// ソースコード格納用フォルダ、ビルド格納用フォルダを作成
$ mkdir src build
// tsconfigを生成
$ tsc --init
tsconfigを以下のとおり編集し、ビルド用の設定を行います。
"outDir": "./build",
"rootDirs": ["src"],
以上で準備は完了です。
サンプルアプリケーション作成
今回作成するサンプルアプリケーションはチケットの売買を行うようなサンプルのようです。
イメージは以下のような感じです。
ユーザアカウントの作成
まずは、販売者用のアカウントは前回作成しているので、ユーザ用のアカウントを追加で作成します。
$ symbol-cli account generate --network TEST_NET --save --url http://api-01.us-east-1.testnet.symboldev.network:3000 --profile customer
ユーザを作成したあと、下記コマンドを実行するとプロファイルが2つになっていることが確認できます。
$ symbol-cli profile list
┌──────────────────┬──────────────────────────────────────────────────────────────────┐
│ Property │ Value │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Name │ testnet │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Address │ TBJHBF-KL5NL4-UDGN63-6KG5PD-CKXPCO-YTYYWN-YEA │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Network │ TEST_NET │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Node URL │ http://api-01.us-east-1.testnet.symboldev.network:3000 │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Generation Hash │ 45FBCF2F0EA36EFA7923C9BC923D6503169651F7FA4EFC46A8EAF5AE09057EBD │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Network Currency │ name: symbol.xym, divisibility: 6 │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Profile type │ PrivateKey │
└──────────────────┴──────────────────────────────────────────────────────────────────┘
┌──────────────────┬──────────────────────────────────────────────────────────────────┐
│ Property │ Value │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Name │ customer │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Address │ TDDH3J-UCWMFW-2VSKLD-JM7GB3-P7LIDI-L54RBS-2QA │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Network │ TEST_NET │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Node URL │ http://api-01.us-east-1.testnet.symboldev.network:3000 │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Generation Hash │ 45FBCF2F0EA36EFA7923C9BC923D6503169651F7FA4EFC46A8EAF5AE09057EBD │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Network Currency │ name: symbol.xym, divisibility: 6 │
├──────────────────┼──────────────────────────────────────────────────────────────────┤
│ Profile type │ PrivateKey │
└──────────────────┴──────────────────────────────────────────────────────────────────┘
Default profile:testnet
販売者アカウントのモニタリング
トランザクションを監視してみます。
$ symbol-cli monitor all --address TBJHBF-KL5NL4-UDGN63-6KG5PD-CKXPCO-YTYYWN-YEA
以下のような表示になっていればモニタできています。 新しいブロックができたり、トランザクションが発行されたりするとリアルタイムに表示されます。
Monitoring TBJHBF-KL5NL4-UDGN63-6KG5PD-CKXPCO-YTYYWN-YEA using http://api-01.us-east-1.testnet.symboldev.network:3000
チケットの作成
モザイクにてチケットを作成してみます。 下記コマンドで作成します。
$ symbol-cli transaction mosaic --amount 10 --supply-mutable --divisibility 0 --duration 1000 --max-fee 2000000 --sync --profile testnet
いくつか質問されますので、下記のように答えると下記の通り作成されます。
✔ Enter your wallet password: … ********
✔ Do you want a non-expiring mosaic? … yes
✔ Do you want this mosaic to be transferable? … yes
✔ Do you want this mosaic to be restrictable? … yes
✔ Select the transaction announce mode: › normal
┌───────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ AGGREGATE_COMPLETE │
├────────────────────────────────────┬──────────────────────────────────────────────────────────────────┤
│ Max fee: │ 2,000,000 │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ Network type: │ TEST_NET │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ Deadline: │ 2021-03-21 15:52:48.094 │
├────────────────────────────────────┴──────────────────────────────────────────────────────────────────┤
│ Inner transaction 1 of 2 - MOSAIC_DEFINITION │
├────────────────────────────────────┬──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 1 of 2] Mosaic Id: │ 7460F899DF487963 │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 1 of 2] Duration: │ unlimited │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 1 of 2] Divisibility: │ 0 │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 1 of 2] Supply mutable: │ true │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 1 of 2] Transferable: │ true │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 1 of 2] Restrictable: │ true │
├────────────────────────────────────┴──────────────────────────────────────────────────────────────────┤
│ Inner transaction 2 of 2 - MOSAIC_SUPPLY_CHANGE │
├────────────────────────────────────┬──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 2 of 2] Mosaic Id: │ 7460F899DF487963 │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 2 of 2] Direction: │ Increase supply │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 2 of 2] Delta: │ 10 │
├────────────────────────────────────┴──────────────────────────────────────────────────────────────────┤
│ Signature details │
├────────────────────────────────────┬──────────────────────────────────────────────────────────────────┤
│ Payload: │ 38010000000000005595EB3AF43B1EFE84B2FBDF3F0E1DC39774C141469C17E4 │
│ │ 233788E0C94308E16C125CC93C83C208AED0B90EEF671C064EF1164489B76EC8 │
│ │ 6FD924C2363FCA04347EE9E8B84918559FBA9BEA2538D8AEB1D3FA1583EB75F1 │
│ │ 3C0246DB5D4CE181000000000198414180841E00000000005E2ECCFB09000000 │
│ │ 04DD29FB90F7CD7F25DF01A2402D7479F7AFF888F840724B2F15156202180F9A │
│ │ 90000000000000004600000000000000347EE9E8B84918559FBA9BEA2538D8AE │
│ │ B1D3FA1583EB75F13C0246DB5D4CE1810000000001984D41637948DF99F86074 │
│ │ 000000000000000039E1BF11070000004100000000000000347EE9E8B8491855 │
│ │ 9FBA9BEA2538D8AEB1D3FA1583EB75F13C0246DB5D4CE1810000000001984D42 │
│ │ 637948DF99F860740A000000000000000100000000000000 │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ Hash: │ 2565DD6494FD3428E24195553B1A956C8D9501428785149910D4EF9E4A57EC67 │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ Signer: │ 347EE9E8B84918559FBA9BEA2538D8AEB1D3FA1583EB75F13C0246DB5D4CE181 │
└────────────────────────────────────┴──────────────────────────────────────────────────────────────────┘
✔ Do you want to announce this transaction? … yes
SUCCESS Transaction announced
SUCCESS Transaction confirmed
作成に成功すると、モニタしていた側にも結果が表示されます。
New transaction confirmed:
┌───────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ AGGREGATE_COMPLETE │
├────────────────────────────────────┬──────────────────────────────────────────────────────────────────┤
│ Hash: │ 2565DD6494FD3428E24195553B1A956C8D9501428785149910D4EF9E4A57EC67 │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ Max fee: │ 2,000,000 │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ Height (Block): │ 205,909 │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ Network type: │ TEST_NET │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ Deadline: │ 2021-03-21 15:52:48.094 │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ Signer: │ TBJHBF-KL5NL4-UDGN63-6KG5PD-CKXPCO-YTYYWN-YEA │
├────────────────────────────────────┴──────────────────────────────────────────────────────────────────┤
│ Inner transaction 1 of 2 - MOSAIC_DEFINITION │
├────────────────────────────────────┬──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 1 of 2] Mosaic Id: │ 7460F899DF487963 │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 1 of 2] Duration: │ unlimited │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 1 of 2] Divisibility: │ 0 │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 1 of 2] Supply mutable: │ true │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 1 of 2] Transferable: │ true │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 1 of 2] Restrictable: │ true │
├────────────────────────────────────┴──────────────────────────────────────────────────────────────────┤
│ Inner transaction 2 of 2 - MOSAIC_SUPPLY_CHANGE │
├────────────────────────────────────┬──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 2 of 2] Mosaic Id: │ 7460F899DF487963 │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 2 of 2] Direction: │ Increase supply │
├────────────────────────────────────┼──────────────────────────────────────────────────────────────────┤
│ [Inner tx. 2 of 2] Delta: │ 10 │
└────────────────────────────────────┴──────────────────────────────────────────────────────────────────┘
チケットの送信
コードを作成する前に、networkGenerationHashを取得しておきます。 networkGenerationHashは以下URLにアクセスすることで取得できます。
http://api-01.us-east-1.testnet.symboldev.network:3000/node/info
上記にアクセスすると、以下のようなjsonが取得できるので、その中からnetworkGenerationHashSeedをコピーしておきます。
{"version":655624,"publicKey":"31D7A021B0C8BFBAAA64AD040E332BE24421541004E9F01D0E0F459925342475","networkGenerationHashSeed":"45FBCF2F0EA36EFA7923C9BC923D6503169651F7FA4EFC46A8EAF5AE09057EBD","roles":2,"port":7900,"networkIdentifier":152,"host":"","friendlyName":"api-01-us-east-1","nodePublicKey":"F57FB70C3F51663D0DDF47303C93ADC8FDD266DC61BBA67B983052D075FD900E"}
以下のようにソースコードを書きます。
import { MosaicId, Address, NetworkType, TransferTransaction, Deadline, Mosaic, UInt64, PlainMessage, Account, RepositoryFactoryHttp } from "symbol-sdk";
// replace with mosaic id
const mosaicIdHex = '7460F899DF487963';
const mosaicId = new MosaicId(mosaicIdHex);
// replace with customer address
const rawAddress = 'TDDH3J-UCWMFW-2VSKLD-JM7GB3-P7LIDI-L54RBS-2QA';
const recipientAddress = Address.createFromRawAddress(rawAddress);
// replace with network type
const networkType = NetworkType.TEST_NET;
const transferTransaction = TransferTransaction.create(
Deadline.create(1573430400),
recipientAddress,
[new Mosaic(mosaicId, UInt64.fromUint(1))],
PlainMessage.create('enjoy your ticket'),
networkType,
UInt64.fromUint(2000000),
);
// replace with ticket vendor private key
const privateKey = 'A1C760B38DA4F36A1FE1825C5B355D03223B84163D01ABAEDAF11B119DAB3ACB';
const account = Account.createFromPrivateKey(privateKey, networkType);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
'45FBCF2F0EA36EFA7923C9BC923D6503169651F7FA4EFC46A8EAF5AE09057EBD';
const signedTransaction = account.sign(
transferTransaction,
networkGenerationHash,
);
// replace with node endpoint
const nodeUrl = 'http://api-01.us-east-1.testnet.symboldev.network:3000';
const repositoryFactory = new RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();
transactionHttp.announce(signedTransaction).subscribe(
(x) => console.log(x),
(err) => console.error(err),
);
実行
ts-nodeにて上記のコードを実行してみます。
$ ts-node src/transfer-ticket.ts
実行してみると、utf8パッケージがないとエラーが発生したため、追加でutf8パッケージをインストールします。
$ npm install utf8
再度実行すると以下のように表示されました。
TransactionAnnounceResponse {
message: 'packet 9 was pushed to the network via /transactions'
}
ユーザの情報を表示すると、モザイクが付与されていることが確認できます。
$ symbol-cli account info --profile customer
Account Information
┌───────────────────┬──────────────────────────────────────────────────────────────────┐
│ Property │ Value │
├───────────────────┼──────────────────────────────────────────────────────────────────┤
│ Address │ TDDH3J-UCWMFW-2VSKLD-JM7GB3-P7LIDI-L54RBS-2QA │
├───────────────────┼──────────────────────────────────────────────────────────────────┤
│ Address Height │ 205964 │
├───────────────────┼──────────────────────────────────────────────────────────────────┤
│ Public Key │ 0000000000000000000000000000000000000000000000000000000000000000 │
├───────────────────┼──────────────────────────────────────────────────────────────────┤
│ Public Key Height │ 0 │
├───────────────────┼──────────────────────────────────────────────────────────────────┤
│ Importance │ 0 │
├───────────────────┼──────────────────────────────────────────────────────────────────┤
│ Importance Height │ 0 │
└───────────────────┴──────────────────────────────────────────────────────────────────┘
Balance Information
┌──────────────────┬─────────────────┬─────────────────┬───────────────────┐
│ Mosaic Id │ Relative Amount │ Absolute Amount │ Expiration Height │
├──────────────────┼─────────────────┼─────────────────┼───────────────────┤
│ 7460F899DF487963 │ 1 │ 1 │ Never │
└──────────────────┴─────────────────┴─────────────────┴───────────────────┘
ひとまず、今日はここまでにします。
明日は今回作成したコードについてもう少し深堀りしたいと思います。
その後、もう少し実践的なサンプルシステムを今回のお題をもとに作ってみたいと思います。