2
1

More than 1 year has passed since last update.

symbol-sdk@3.0.7で作るメタデータトランザクション

Last updated at Posted at 2023-07-22

はじめに

こんにちは。

symbol-sdkの3系、トランザクションシリーズ第六弾です。

今回はメタデータをやっていきます。

注意事項

書いてあるコードについて、正確性や完全性を保証するものではありません。あくまで参考程度として頂き、最新情報は公式ドキュメンテーションをご確認ください。

デッドラインなど

まずは各トランザクションで共通となる個所について。デッドラインと鍵ペアです。

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

TextEncoder も必要になりますので用意しておきます。

import { TextEncoder } from 'util';

const textEncoder = new TextEncoder();

メタデータのキー

メタデータはキーとバリューが必要になります。

キーの方はBigIntで4バイト。任意の値が設定できます。

const scopedMetadataKey = 0x0000000012345678n;

メタデータのバリュー

バリューのほうは、 metadataUpdateValue という関数があるのでそれを使っていきます。

仕様的には古い値と新しい値でXORをとるみたいです。新しくメタデータを追加するなど、古い値がない場合はXORは考えずに値そのままで大丈夫です。

const value = symbolSdk.symbol.metadataUpdateValue(
	textEncoder.encode("oldValue"),
	textEncoder.encode("newValue")
);

ほかにも、Uint8Arrayをそのまま使うことができます。

const value = textEncoder.encode("fuga");

文字列でもよいです。

const value = "hoge";

valueSizeDelta

メタデータの値のバイトサイズに関するパラメータです。(英数字だと基本的に1文字1バイトです。)

古いメタデータの値と新しいメタデータの値で、サイズが異なる場合、それをトランザクションに記述する必要があります。

(確か)古い値が4バイトで、新しい値が5バイトだった場合、 valueSizeDelta = 1 となるはずです。

もし新しくメタデータを追加するなど、古い値がない場合は、新しいメタデータの値のサイズを指定します。

const valueSizeDelta = 4;

アカウントメタデータトランザクション

targetAddress にメタデータを付けたいアドレスを指定します。

const accountMetadataTransaction = facade.transactionFactory.createEmbedded({
  type: 'account_metadata_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  targetAddress: network.publicKeyToAddress(keyPair.publicKey),
  scopedMetadataKey,
  valueSizeDelta,
  value
});

モザイクメタデータトランザクション

モザイクのメタデータですが、 targetAddress が必要になります。

targetMosaicId にモザイクIDを指定します。これはBigIntで指定しています。

const mosaicMetadataTransaction = facade.transactionFactory.createEmbedded({
  type: 'mosaic_metadata_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  targetAddress: network.publicKeyToAddress(keyPair.publicKey),
  scopedMetadataKey: 0x0000000012345678n,
  targetMosaicId: 0x500952FEB9E8A682n,
  valueSizeDelta: 4,
  value: symbolSdk.symbol.metadataUpdateValue(textEncoder.encode(""), textEncoder.encode("fuga")),
});

targetMosaicIdUnresolvedMosaicId でも大丈夫です。

targetMosaicId: new symbolSdk.symbol.UnresolvedMosaicId(0x500952FEB9E8A682n),

ネームスペースメタデータトランザクション

ネームスペースのメタデータですが、 targetAddress が必要になります。

targetNamespaceId にネームスペースIDを指定します。これはBigIntです。

const namespaceMetadataTransaction = facade.transactionFactory.createEmbedded({
  type: 'namespace_metadata_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  targetAddress: network.publicKeyToAddress(keyPair.publicKey),
  scopedMetadataKey: 0x0000000012345678n,
  targetNamespaceId: 0xFBE54EC2AAA8EFDFn,
  valueSizeDelta: 4,
  value: symbolSdk.symbol.metadataUpdateValue(textEncoder.encode(""), textEncoder.encode("fuga")),
});

targetNamespaceIdNamespaceId でも大丈夫です。

targetNamespaceId: new symbolSdk.symbol.NamespaceId(0xFBE54EC2AAA8EFDFn),

共通

ここまでそれぞれメタデータのトランザクションを作りました。ここからは共通です。

アグリゲートトランザクションでラップ

送信するにあたっては、アグリゲートトランザクションでラップする必要があるみたいです。

(ラップしなかったら送信しても受理されなかった)

今回は、メタデータを付ける対象(targetAddress)がすべてトランザクションの署名者と一致しているので、アグリゲート コンプリート トランザクションで行います。

もしそうでない場合は、アグリゲート ボンデッド トランザクションにする必要があるかと思います。

// 必要に応じてどれか選択
const innerTransactions = [ accountMetadataTransaction ];
const innerTransactions = [ mosaicMetadataTransaction ];
const innerTransactions = [ namespaceMetadataTransaction ];

今回はアグリゲートコンプリートトランザクションにします。

const transactionsHash = symbolSdk.facade.SymbolFacade.hashEmbeddedTransactions(innerTransactions)

const transaction = facade.transactionFactory.create({
  type: 'aggregate_complete_transaction_v2',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  transactions: innerTransactions,
  transactionsHash
});

署名とハッシュ

署名をして、トランザクションにアタッチします。

ハッシュを計算します。

const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.constructor.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);

送信

axios を使います。

const sendRes = await axios.put(`${NODE_URL}/transactions`, jsonPayload).then((res) => res.data);
console.log(sendRes);

ステータス取得

トランザクションが正しくネットワークに受理されたかを確認します。

await axios.get(`${NODE_URL}/transactionStatus/${hash}`)
  .then((res) => res.data)
  .then((statusRes) => {
    console.log(statusRes)
  })
  .catch((e) => {
    console.log(e.message, e.response.data)
  });

おわりに

メタデータのトランザクションを作りました。 valueSizeDelta を自分で計算するのは少し大変ですね。

シリーズ

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1