はじめに
こんにちは。OpeningLineの坂本です。symbol-sdkの3系が出ました。学習のために、様々なトランザクションを作ってみようと思います。
全部いっぺんに書くと長くなってしまうので、少しずつ分けて書いていく予定です。
今回は、転送トランザクションについて書いてみたいと思います。
注意事項
書いてあるコードについて、正確性や完全性を保証するものではありません。あくまで参考程度として頂き、最新情報は公式ドキュメンテーションをご確認ください。
Transfer Transaction
まずは共通となる個所について。デッドラインと鍵ペアです。
import symbolSdk from 'symbol-sdk';
const network = symbolSdk.symbol.Network.TESTNET;
const deadline = network.fromDatetime(new Date(Date.now() + 7200000)).timestamp;
const facade = new symbolSdk.facade.SymbolFacade(network.name);
const privateKey = new symbolSdk.PrivateKey(PRIVATE_KEY);
const keyPair = new facade.constructor.KeyPair(privateKey);
シンプル
最もシンプルな形です。モザイクもメッセージもありません。
const transaction = facade.transactionFactory.create({
type: 'transfer_transaction_v1',
signerPublicKey: keyPair.publicKey.toString(),
fee: 1000000n,
deadline,
recipientAddress: 'TARDV42KTAIZEF64EQT4NXT7K55DHWBEFIXVJQY',
});
モザイク
モザイクを送信してみます。
このように、モザイクIDをBigIntで指定して、
const currencyMosaicId = 0x72C0212E67A08BCEn;
mosaics
として渡します。
const transaction = facade.transactionFactory.create({
type: 'transfer_transaction_v1',
signerPublicKey: keyPair.publicKey.toString(),
fee: 1000000n,
deadline,
recipientAddress: 'TARDV42KTAIZEF64EQT4NXT7K55DHWBEFIXVJQY',
mosaics: [
{ mosaicId: currencyMosaicId, amount: 1000000n },
],
});
ネームスペース
ネームスペースで送る場合は、以下のようなユーティリティが提供されていました。
const xymNamespaceId = symbolSdk.symbol.generateMosaicAliasId('symbol.xym');
これを使って、以下のようにします。
mosaics: [
{ mosaicId: currencyMosaicId, amount: 1000000n },
{ mosaicId: xymNamespaceId, amount: 1000000n },
],
メッセージ
文字列をutf-8にするために、Node.jsのパッケージをインポートします。
import { TextEncoder } from 'util';
const textEncoder = new TextEncoder();
平文
先頭に0x00をつけてエンコードしたデータを用います。
const message = new Uint8Array([0x00, ...textEncoder.encode('あいうえお')]);
トランザクション作成は以下のようになります。
const transaction = facade.transactionFactory.create({
type: 'transfer_transaction_v1',
signerPublicKey: keyPair.publicKey.toString(),
fee: 1000000n,
deadline,
recipientAddress: 'TARDV42KTAIZEF64EQT4NXT7K55DHWBEFIXVJQY',
mosaics: [
{ mosaicId: currencyMosaicId, amount: 1000000n },
],
message,
});
暗号化メッセージ
メッセージを暗号化するクラスを使います。このとき、暗号化メッセージを送る際には、受信者の公開鍵が必要になります。
const messageEncoder = new symbolSdk.symbol.MessageEncoder(keyPair);
const message = messageEncoder.encode(
new symbolSdk.PublicKey(PUBLIC_KEY_RECEIVER),
textEncoder.encode('message')
)
メッセージを復号するには、以下のようにします。
const [result, decodedMessage] = messageEncoder.tryDecode(
new symbolSdk.PublicKey(PUBLIC_KEY_RECEIVER),
message
)
ただ、これを使ってトランザクションを送ってみたものの、Symbolデスクトップウォレットではうまく復号できませんでした。原因はまだ追い切れてません。何か知ってる方おられましたら教えてください。
受取人
アドレス
受取人をアドレスで指定する場合は、文字列で指定すればいいようです。
const transaction = facade.transactionFactory.create({
type: 'transfer_transaction_v1',
signerPublicKey: keyPair.publicKey.toString(),
fee: 1000000n,
deadline,
recipientAddress: 'TARDV42KTAIZEF64EQT4NXT7K55DHWBEFIXVJQY',
});
ネームスペース
受取人をネームスペースで指定する場合は、ちょっとうまいやり方がわかりませんでした。
とりあえず、 recipientAddress
に UnresolvedAddress
型が使われているのはわかりました。なので、データを作ってすごく強引にトランザクションに入れ込んだら、とりあえずは動きました。
const addressAliasId = symbolSdk.symbol.generateMosaicAliasId('address.alias');
const hexByteArray = addressAliasId.toString(16).toUpperCase().match(/../g);
hexByteArray.reverse();
const addressAliasIdLE = hexByteArray.join('');
const addressAlias = `99${addressAliasIdLE}`.padEnd(48, '0');
const unresolvedAddress = new symbolSdk.symbol.UnresolvedAddress(symbolSdk.utils.hexToUint8(addressAlias));
const transaction = facade.transactionFactory.create({
type: 'transfer_transaction_v1',
signerPublicKey: keyPair.publicKey.toString(),
fee: 1000000n,
deadline,
});
transaction.recipientAddress = unresolvedAddress;
アグリゲートトランザクション
転送トランザクションをアグリゲートトランザクションにしてみます。
詳細は別にアグリゲートトランザクションの回でやってみたいと思いますので、今回はシンプルに。
まずは createEmbedded
で内部トランザクションを作成。
const innerTransaction1 = facade.transactionFactory.createEmbedded({
type: 'transfer_transaction_v1',
signerPublicKey: keyPair.publicKey.toString(),
recipientAddress: ADDRESS_RECEIVER_1,
mosaics: [
{ mosaicId: currencyMosaicId, amount: 1000000n },
],
message,
});
const innerTransaction2 = facade.transactionFactory.createEmbedded({
type: 'transfer_transaction_v1',
signerPublicKey: keyPair.publicKey.toString(),
recipientAddress: ADDRESS_RECEIVER_2,
mosaics: [
{ mosaicId: currencyMosaicId, amount: 2000000n },
],
message,
});
ここで、内部トランザクションのマークルルートを計算します。
const innerTransactions = [ innerTransaction1, innerTransaction2 ];
const transactionsHash = symbolSdk.facade.SymbolFacade.hashEmbeddedTransactions(innerTransactions)
あとはこれらをアグリゲートトランザクションに渡します。
const transaction = facade.transactionFactory.create({
type: 'aggregate_complete_transaction_v2',
signerPublicKey: keyPair.publicKey.toString(),
fee: 1000000n,
deadline: BigInt(Date.now()) - epochAdjustment + 7200000n,
transactions: innerTransactions,
transactionsHash,
});
そして、これに署名をして完了です。
おわりに
今回は転送トランザクションについて書いてみました。
これだけでもまぁまぁな量がありました。まだうまく行ってない個所もありますが、また進捗ありましたら更新したいと思います。