5. モザイク

速習Symbolブロックチェーン4章、モザイク編です。

URLとしてはこちら

今回はテストネットの

http://sym-test-01.opening-line.jp/

をお借りしました。

オープニングライン社さんですね。

ブロックチェーンを使用した、ファイルを受け渡すJUGGLEが話題(2023/05/27時点)です。

テストネットを用意している方は素敵な方ではあるので、一言紹介していきたいんですよね。

ただ、このまま続けていくと(僕が誰か判別できる)テストネットノードはすぐに枯渇しちゃいそうです。

うちのノード使ってもいいよ、という方がいたら教えてください。(ここで一言紹介してもしょうがないかもしれませんけど。

それではやっていきます。

実践編

5.1 モザイク作成

モザイクの作成と、作成された状態を確認していきます。

まずコード。

// aliceのアカウントを作成する。
var alice = await Account.createFromPrivateKey(
  PrivateKey(alicePrivateKey), NetworkTypeEnum.testnet);

print("[送信元] alice address: ${alice.address}");

// モザイクの設定を指定する。
// 指定したフラグは有効状態とする。
var mosaicFlag = 
  MosaicFlagsEnum.supplyMutable +     // 供給量変更可能
  MosaicFlagsEnum.restrictable +      // 制限設定可能
  MosaicFlagsEnum.revocable;          // 発行者からの回収可能
// ここでは指定していないが、transferable(第三者への譲渡)も設定できるらしい。

var nonce = MosaicNonce.createRandom();

var mosaicId = MosaicId.createNew(nonce, alice.address);

// tx1
// モザイクの設定を行う。
var mosaicDefInfo = MosaicDefinitionInfoV1.create(alice.publicAccount, mosaicId, 
    BlockDuration(0), nonce, mosaicFlag, Int8(2));

// tx2
// モザイクの数量を増加する。(おそらく、設定だけでは0? そもそも設定だけでは受け取らない?)
var mosaicSupplyInfo = MosaicSupplyChangeInfoV1.create(alice.publicAccount, mosaicId, 
    Amount(100000000), MosaicSupplyChangeActionEnum.increase);

// トランザクションをまとめる。
var aggregate = [mosaicDefInfo, mosaicSupplyInfo];

// Transaction設定を行う。
var transSetting = TransactionSetting(
  signer: alice, 
  generationHash: "49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4", 
  networkType: NetworkTypeEnum.testnet, 
  deadline: Deadline.create(1667250467),
  fee:FeeMultiplier(100) );     // 手数料は100%。          

var mosaicWorker = MosaicWorker();

await mosaicWorker.sendTransaction(transSetting, aggregate);

基本的な設定はほぼ、速習Symbolと同じだと思っています。

作成するモザイクは

  • 供給量変更可能
  • 制限設定可能
  • 発行者からの回収可能

※これらを具体的に実行できる条件はわからないのですが。

nonceはランダム、

tx1は速習通りモザイクの設定、

tx2はモザイク数量の増加としています。

divisibilityに2を設定したため小数点以下は2桁まで、

数量は100000000としたため、発行量は1,000,000.00としました。百万。

細かいソースを追っても仕方ないのですが、トランザクション発行部分は下記。


var availableHost = await _getNetworkHost();

var aggCompleteInfo = AggregateCompleteInfoV2(availableHost.networkType, transInfos);

var aggregateTransaction = await AggregateTransaction.create(transSetting, aggCompleteInfo);

print("実行ペイロード");
print(aggregateTransaction.payload);
print("トランザクションハッシュ");
print(aggregateTransaction.transactionHash.value);   

var transRouteHttp = TransactionRoutesHttp(availableHost.networkHost);

// トランザクションをノードに通知する。
var result = await transRouteHttp.announceNewTransaction(aggregateTransaction.payload.toUpperCase());

print("トランザクションのアナウンスに成功した。");
print(result.message);

print("トランザクションの承認ステータスを確認する。");
var transStateRouteHttp = TransactionStateRoutesHttp(availableHost.networkHost);

var processing = true;

while(processing){
  await Future.delayed(const Duration(seconds: 1));

  // 結果の確認を行う。
  var resultState = await transStateRouteHttp.getStatus(aggregateTransaction.transactionHash);

  // 未認証の場合のみ、終わるまで継続。
  switch (resultState.group){
    case TransactionGroupEnum.confirmed:
      print("トランザクションが承認されました。やったぜ!");
      processing = false;
      break;
    case TransactionGroupEnum.unconfirmed:
      print("トランザクションは未承認です。");
      break;
    case TransactionGroupEnum.failed:
      print("トランザクションにエラーがありました。");
      if (resultState.code != null) print(resultState.code!.value);
      return;
    default:
      print("パーシャル!!! パーシャル……?");
      return;
  }
}

print("承認後はTransactionRouteから承認トランザクションの内容を取得することが可能になっている。");

var confirmedInfo = await transRouteHttp.getConfirmedInformation(aggregateTransaction.transactionHash.value);

print("取得結果。");
print(jsonEncode(confirmedInfo.baseMap));

(前の章で実施した)アグリゲートコンプリートトランザクションで発行し、その承認結果を確認します。

それでは実行します。

こんな感じです。少なくともトランザクションの承認は行われたようです。

これを、念のためにウォレットでも確認してみます。

aliceのウォレットのアセット欄に、symbol.xym以外のトークンが表示されていますね。

見づらいかもしれませんが、先ほどの一部を抜粋すると、

mosaicIdとしてある50E29F813AA1B901ということみたいです。

これでとりあえず、モザイクの生成は行われているようです。

また、数も1,000,000となっているため100万とでています。

たぶんこれで発行数の変更も実行されているかな、と思います。

5.3 現場で使えるヒント

所有証明について書かれています。ブロックチェーンがあると所有証明も可能であるとともに、NFTの発行方法などが記載されています。

NFT

というわけで、速習Symbolに倣ってNFTを発行したいと思います。

といっても、複製や数量変更できない、唯一のトークンを発行するということでしかないようですが。

以下のようにコードを設定しました。

// aliceのアカウントを作成する。
var alice = await Account.createFromPrivateKey(
  PrivateKey(alicePrivateKey), NetworkTypeEnum.testnet);

print("[送信元] alice address: ${alice.address}");

// モザイクの設定を指定する。
// 指定したフラグは有効状態となる。
var mosaicFlag = 
  MosaicFlagsEnum.restrictable +      // 制限設定可能
  MosaicFlagsEnum.revocable;          // 発行者からの回収可能
// MosaicFlagsEnum.supplyMutable      // 供給量変更可能は指定しない。
// MosaicFlagsEnum.transferable       // 第三者への譲渡不可。

var nonce = MosaicNonce.createRandom();
// var nonce = MosaicNonce.create(Uint8List.fromList([210,53,66,166]));

var mosaicId = MosaicId.createNew(nonce, alice.address);

// tx1
// モザイクの設定を行う。
// 可分性0、有効期限無制限。
var mosaicDefInfo = MosaicDefinitionInfoV1.create(alice.publicAccount, mosaicId, 
    BlockDuration(0), nonce, mosaicFlag, Int8(0));

// tx2
// モザイクの数量を増加する。
// 数量は1。可分性が0のため、1は1。
var mosaicChangeInfo = MosaicSupplyChangeInfoV1.create(alice.publicAccount, mosaicId, 
    Amount(1), MosaicSupplyChangeActionEnum.increase);

// tx3
// NFTデータ
var transInfo = TransferInfoV1.create(alice.publicAccount, alice.publicAccount.address, [],
  PlainMessage.create("Hello Symbol!!!"));

// トランザクションをまとめる。
var aggregate = [mosaicDefInfo, mosaicChangeInfo, transInfo];

// Transaction設定を行う。
var transSetting = TransactionSetting(
  signer: alice, 
  generationHash: "49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4", 
  networkType: NetworkTypeEnum.testnet, 
  deadline: Deadline.create(1667250467),
  fee:FeeMultiplier(100) );     // 手数料は100%。          

var mosaicWorker = MosaicWorker();

// トランザクションの通知。
await mosaicWorker.sendTransaction(transSetting, aggregate);

mosaicWorkerについては省略します。

同じように? 設定したつもりのため、これで実行してみます。

実行されました。ウォレットで確認すると先ほどの通り、数量は1となっています。

そして生成と同じブロックに投入したメッセージ=NFTのデータとすることで、データ付きのNFTにすることができる、ということのようです。うーむ、なるほど。。。

回収可能なポイント

先ほどの唯一発行したトークンをbobへと送信しておきます。

以下、bobのウォレット状態です。

365~~が先ほどのNFTですね。たぶん。

さて、こいつを回収できるらしいので、aliceが回収を行います。

さくっとこんな感じ。

// aliceのアカウントを作成する。
var alice = await Account.createFromPrivateKey(
  PrivateKey(alicePrivateKey), NetworkTypeEnum.testnet);

print("[送信元] alice address: ${alice.address}");

// 回収トランザクション。対象アドレスはbob。数量は1。
var revocationTx = MosaicSupplyRevocationInfoV1.create(alice.publicAccount, 
  Address("TBZ7AEGPLAP2YCVPSS6CJR27EVOQ7M4AXULACRY"), 
  Mosaic(id: MosaicId("365F2BE795816BAE"), amount: Amount(1)));

// Transaction設定を行う。
var transSetting = TransactionSetting(
  signer: alice, 
  generationHash: "49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4", 
  networkType: NetworkTypeEnum.testnet, 
  deadline: Deadline.create(1667250467),
  fee:FeeMultiplier(100) );     // 手数料は100%。          

var mosaicWorker = MosaicWorker();

// トランザクションの通知。
await mosaicWorker.sendTransaction(transSetting, revocationTx);

トランザクションの通知周りはもう省略していきます。

特に変更がなければ、アグリゲートもベーシックも通知 -> 承認を探す、取得の流れのため。

実行します。

実行完了は特に実感がなかったのですが、bobのウォレットを見るときっちりモザイクが消えていました。

Explorerで見るとちゃんと、回収したトランザクションは掲載されていました。

なお、このトークンは消滅させるわけではなくあくまでも回収のため、

aliceの元へと戻っていました。

モザイクの実践編は以上です。

感想編

おお、モザイク作成って手ごろなんだなぁ。ってところです。名前を付けるのはまだ先なので、MosaicIdのみでの表示ですが。

モザイク=あらゆるものの動きや状態を示すことができるのだろうなぁ、と実感を持ちました。

別に本筋とは関係ないのですが、MosaicIdは先頭ビットが0、NamespaceIdは先頭ビットが0にするというメモが僕の手元にありました。どこで見たのか覚えてないのですが。

ビット演算なんてそうそう使う機会ない? もんな。。。

モザイクの使い方としては、会員証・権利のようなものや、ポイントのようなもの。

アドレス=場所と紐づけたらトレーサビリティにも使用できるでしょうし、カンバン的にも使用できるかもしれないですね。あとは在庫管理とか?

これをパブリックでやるかどうかという話はあるかと思いますが、とても奥が深そうだなと思います。

以上です。