symbol-sdk@3.0.7で作る転送トランザクション

symbol-sdk@3.0.7で作る転送トランザクション

タグ
SymbolNode.js
公開日
May 13, 2023

はじめに

こんにちは。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',
});

ネームスペース

受取人をネームスペースで指定する場合は、ちょっとうまいやり方がわかりませんでした。

とりあえず、 recipientAddressUnresolvedAddress 型が使われているのはわかりました。なので、データを作ってすごく強引にトランザクションに入れ込んだら、とりあえずは動きました。

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,
});

そして、これに署名をして完了です。

おわりに

今回は転送トランザクションについて書いてみました。

これだけでもまぁまぁな量がありました。まだうまく行ってない個所もありますが、また進捗ありましたら更新したいと思います。