• Home
  • libra-coreを使ってリブラウォレットをNode.jsで作る

libra-coreを使ってリブラウォレットをNode.jsで作る

Node.jsのLibra Clientであるlibra-coreの使い方。

libra-core とは

仮想通貨Libraの非公式Node.jsクライアント。

Testnet でのアカウント生成や送信などの操作を、Node.js から実行できる。

セットアップ

環境情報

この記事の環境は以下の通り。

$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.14.5
BuildVersion: 18F132

$ node --version
v12.7.0

$ npm --version
6.10.3

libra-core を使うには node.js v12 以降が必須なので注意。

インストール

npm install 実行、2019/09/02 現在のバージョンは v1.0.7

$ npm install libra-core

> grpc@1.23.3 install

...

+ libra-core@1.0.7

added 140 packages from 107 contributors and audited 283 packages in 9.589s
found 0 vulnerabilities

使い方

ライブラリ読み込み

公式ドキュメントでは TypeScript 前提で import となっているが、以下はすべて Node.js 上でのサンプルのため require に変更している。

import { LibraWallet, LibraClient } from 'libra-core';

上記であれば、以下のように変更。

const libra_core = require("libra-core");
const LibraWallet = libra_core.LibraWallet;
const LibraClient = libra_core.LibraClient;

ウォレット生成

新規生成

new LibraWallet() で新規ウォレットの生成。config.mnemonic にニーモニック(ウォレットを復元するためのキーワード群)が入っているので、復元したい場合には保存しておく。

const libra_core = require("libra-core");
const LibraWallet = libra_core.LibraWallet;

const wallet = new LibraWallet();
console.log(`wallet mnemonic: ${wallet.config.mnemonic}`);
// => wallet mnemonic: potato slice ...

ニーモニックから復元

new LibraWallet({mnemonic: <mnemonic>}) でニーモニックからウォレットを復元。

const libra_core = require("libra-core");
const LibraWallet = libra_core.LibraWallet;
const mnemonic = "potato slice ...";

const wallet = new LibraWallet({mnemonic: mnemonic});
console.log(`wallet mnemonic: ${wallet.config.mnemonic}`);
// =&amp;gt; wallet mnemonic: potato slice ...

アカウント(アドレス)生成

新規生成

LibraWallet.newAcount() で新規アカウント生成。

アドレスは getAddress() で取得できるが Uint8Array なので toHex() で変換する。

秘密鍵は keyPair.getSecretKey() で取得可能。こちらも Uint8Array だが、変換メソッドが用意されてないので、Buffer.from().toString("hex") で変換する。秘密鍵からアカウントを復元したい場合には保存しておく。

※ニーモニックからウォレットを復元した場合は、秘密鍵を使わなくても同じアカウントが生成される。

const libra_core = require("libra-core");
const LibraWallet = libra_core.LibraWallet;

const wallet = new LibraWallet();
const account = wallet.newAccount();
console.log(`account address: ${account.getAddress().toHex()}`);
// =&amp;gt; account address: 58f0ef...

const secretKey = account.keyPair.getSecretKey(); // Uint8Array
const secretKeyStr = Buffer.from(secretKey).toString('hex');
console.log(`account secret: ${secretKeyStr}`);
// =&amp;gt; account secret: ec210c...

秘密鍵から復元

LibraAccount.fromSecretKey(<secretKey>) で秘密鍵からの復元。

const libra_core = require("libra-core");
const LibraAccount = libra_core.Account;
const secretKey = "ec210c...";

const account = LibraAccount.fromSecretKey(secretKey);
console.log(`account address: ${account.getAddress().toHex()}`);
// =&amp;gt; account address: 58f0ef...

入金(鋳造)

LibraClient.mintWithFaucetService(<address>, <amount>) でテスト用コインの入金(鋳造)。

<amount> は Libra の最小単位(0.000001)を基準に入力、例えば 1.05 Libra Coin の場合は 1050000 となる。そのため mint 関数の内部で amount * 1e6 として単位の変換を行っている。

const libra_core = require("libra-core");
const LibraWallet = libra_core.LibraWallet;
const LibraClient = libra_core.LibraClient;
const LibraNetwork = libra_core.LibraNetwork;

const wallet = new LibraWallet();
const account = wallet.newAccount();

async function mint(account, amount) {
const client = new LibraClient({ network: LibraNetwork.Testnet });
await client.mintWithFaucetService(account.getAddress(), amount * 1e6);
}

mint(account, 1.23456);
console.log(`account address: ${account.getAddress().toHex()}`);
// =&amp;gt; account address: 58f0ef...

実行後の出力は特にないため、残高は LibraVistaLibExplorer などを使うか、この後のコードを実行して確認。

残高確認

LibraClient.getAccountState(<address>) でアカウント情報を取得。balance.toNumber() で残高を取得。入金同様に 1e6 で割ることで単位変換。

const libra_core = require("libra-core");
const LibraWallet = libra_core.LibraWallet;
const LibraClient = libra_core.LibraClient;
const LibraNetwork = libra_core.LibraNetwork;

const wallet = new LibraWallet();
const account = wallet.newAccount();

async function getBalance(address) {
const client = new LibraClient({ network: LibraNetwork.Testnet });
const accountState = await client.getAccountState(address);
console.log(accountState.balance.toNumber() / 1e6);
}

getBalance(account.getAddress());
// =&amp;gt; 1.23456

送信

ソース修正

libra-core v1.0.7 では送信がうまく動かない問題があるため、PR #7 の変更を取り込む。

node_modules/libra-core/build/constants/Addresses.js

exports.default = {
AddressLength: 32,
// MinterAddress: '000000000000000000000000000000000000000000000000000000000a550c18',
AssociationAddress: '000000000000000000000000000000000000000000000000000000000a550c18',
};

node_modules/libra-core/build/wallet/Accounts.js

static default() {
// return new AccountAddress(new Uint8Array(Buffer.from(Addresses_1.default.MinterAddress, 'hex')));
return new AccountAddress(new Uint8Array(Buffer.from(Addresses_1.default.AssociationAddress, 'hex')));
}

node_modules/libra-core/build/transaction/Transactions.js

        return new LibraTransaction(program, {
gasUnitPrice: new bignumber_js_1.default(0),
maxGasAmount: new bignumber_js_1.default(1000000),
// }, `${Math.floor(new Date().getTime() / 1000) + 100}`, new Uint8Array(Addresses_1.default.MinterAddress), '-1');
}, `${Math.floor(new Date().getTime() / 1000) + 100}`, new Uint8Array(Buffer.from(Addresses_1.default.AssociationAddress, 'hex')), '-1');

送信コード

LibraClient.transferCoins(<fromAccount>, <toAddress>, <amount>) で送信。response.awaitConfirmation(client) でトランザクション承認待ち。

const libra_core = require("libra-core");
const LibraWallet = libra_core.LibraWallet;
const LibraClient = libra_core.LibraClient;
const LibraNetwork = libra_core.LibraNetwork;

const wallet = new LibraWallet();
const account = wallet.newAccount();

async function send(fromAccount, toAddress, amount) {
const client = new LibraClient({ network: LibraNetwork.Testnet });
const response = await client.transferCoins(fromAccount, toAddress, amount * 1e6);
if (response.acStatus !== 0) {
console.error(`send failed: ${response.acStatus}`);
}
await response.awaitConfirmation(client);
}

send(account, account.getAddress().toHex(), 0.123);

実行後は特に何も表示されないので、次のコードか LibExplorer などで詳細を確認。

トランザクション詳細の確認

LibraClient.getAccountTransaction(<address>, <seq>) でトランザクション詳細の確認。

現在のシーケンス番号(= 次のトランザクションに使われるシーケンス番号)未満の値を指定しないとエラーになるため、比較処理を行っている。

const libra_core = require("libra-core");
const LibraWallet = libra_core.LibraWallet;
const LibraClient = libra_core.LibraClient;
const LibraNetwork = libra_core.LibraNetwork;

const wallet = new LibraWallet();
const account = wallet.newAccount();

async function getTransaction(address, seq) {
const client = new LibraClient({ network: LibraNetwork.Testnet });
const accountState = await client.getAccountState(address);
const currentSeq = accountState.sequenceNumber.toNumber();
if (currentSeq &amp;lt;= seq) {
console.error(`${currentSeq} 未満のシーケンス番号を入力してください。(0 の場合は最初に送信してください)`);
return;
}
const transaction = await client.getAccountTransaction(address, seq);
console.log(transaction);
}

const seq = 0;
getTransaction(account.getAddress(), seq);

実行結果は下記。

$ node get_transaction.js
LibraSignedTransactionWithProof {
signedTransaction: LibraSignedTransaction {
transaction: LibraTransaction {
program: [Object],
gasContraint: [Object],
expirationTime: [BigNumber],
sendersAddress: [AccountAddress],
sequenceNumber: [BigNumber]
},
publicKey: Uint8Array [
129, 112, 101, 211, 195,  52, 130,  74,
42, 197,  37, 116, 202,  68, 202, 205,
122, 167, 239,  10, 101,  33,  77, 158,
80, 164,  65, 208, 102, 223,  48,   0
],
signature: Uint8Array [
80,  22,  40, 180,  74,  24,  79,   2, 133,  86, 193,
167, 134, 164,  48, 116, 144, 181,  56,  46,  90, 157,
76, 149, 240, 212, 248, 166, 123, 147, 111, 227,  94,
49, 248, 200,  91, 103,  36, 180,  96,  17, 204,  14,
68,  50,   6,  64,  66, 207,  43, 237,  68, 174, 177,
237,  99,  79,   3, 179,  64,  21,  54,   9
]
},
proof: {
wrappers_: { '1': [Object], '2': [Object] },
messageId_: undefined,
arrayIndexOffset_: -1,
array: [ [Array], [Array] ],
pivot_: 1.7976931348623157e+308,
convertedPrimitiveFields_: {}
},
events: [
LibraTransactionEvent {
data: [Uint8Array],
sequenceNumber: [BigNumber],
address: [AccountAddress],
path: [Uint8Array]
},
LibraTransactionEvent {
data: [Uint8Array],
sequenceNumber: [BigNumber],
address: [AccountAddress],
path: [Uint8Array]
}
]
}

ご相談・お見積もり

03-5207-2689