5.モザイク
本章ではモザイクの設定とその生成方法について解説します。 Symbolではトークンのことをモザイクと表現します。
Wikipediaによると、トークンとは「紀元前8000年頃から紀元前3000年までのメソポタミアの地層から出土する直径が1cm前後の粘土で作られたさまざまな形状の物体」のことを指します。一方でモザイクとは「小片を寄せあわせ埋め込んで、絵(図像)や模様を表す装飾美術の技法。石、陶磁器(モザイクタイル)、有色無色のガラス、貝殻、木などが使用され、建築物の床や壁面、あるいは工芸品の装飾のために施される。」とあります。SymbolにおいてモザイクとはSymbolが作りなすエコシステムの様相を表すさまざまな構成要素、と考えることができます。
5.1 モザイク生成
モザイク生成には 作成するモザイクを定義します。
// モザイクフラグ設定
f = symbolSdk.symbol.MosaicFlags.NONE.value;
f += symbolSdk.symbol.MosaicFlags.SUPPLY_MUTABLE.value; // 供給量変更の可否
// f += symbolSdk.symbol.MosaicFlags.TRANSFERABLE.value; // 第三者への譲渡可否
f += symbolSdk.symbol.MosaicFlags.RESTRICTABLE.value; // 制限設定の可否
f += symbolSdk.symbol.MosaicFlags.REVOKABLE.value; // 発行者からの還収可否
flags = new symbolSdk.symbol.MosaicFlags(f);
// ナンス設定
array = new Uint8Array(symbolSdk.symbol.MosaicNonce.SIZE);
crypto.getRandomValues(array);
nonce = new symbolSdk.symbol.MosaicNonce(
array[0] * 0x00000001 +
array[1] * 0x00000100 +
array[2] * 0x00010000 +
array[3] * 0x01000000,
);
//モザイク定義
mosaicDefTx = facade.transactionFactory.createEmbedded({
type: "mosaic_definition_transaction_v1", // Txタイプ:モザイク定義Tx
signerPublicKey: aliceKey.publicKey, // 署名者公開鍵
id: new symbolSdk.symbol.MosaicId(
symbolSdk.symbol.generateMosaicId(aliceAddress, nonce.value),
),
divisibility: 2, // divisibility:可分性
duration: new symbolSdk.symbol.BlockDuration(0n), // duration:有効期限
nonce: nonce,
flags: flags,
});
MosaicFlagsは以下の通りです。
MosaicFlags {
supplyMutable: false, transferable: false, restrictable: false, revokable: false
}
数量変更、第三者への譲渡、モザイクグローバル制限の適用、発行者からの還収の可否について指定します。 この項目は後で変更することはできません。
divisibility: 可分性
可分性は小数点第何位まで数量の単位とするかを決めます。データは整数値として保持されます。
divisibility:0 = 1
divisibility:1 = 1.0
divisibility:2 = 1.00
duration:有効期限
0を指定した場合、無期限に使用することができます。 モザイク有効期限を設定した場合、期限が切れた後も消滅することはなくデータとしては残ります。 アカウント1つにつき1000までしか所有することはできませんのでご注意ください。
次に数量を変更します
//モザイク変更
mosaicChangeTx = facade.transactionFactory.createEmbedded({
type: "mosaic_supply_change_transaction_v1", // Txタイプ:モザイク変更Tx
signerPublicKey: aliceKey.publicKey, // 署名者公開鍵
mosaicId: new symbolSdk.symbol.UnresolvedMosaicId(mosaicDefTx.id.value),
delta: new symbolSdk.symbol.Amount(10000n), // 数量
action: symbolSdk.symbol.MosaicSupplyChangeAction.INCREASE,
});
supplyMutable:falseの場合、全モザイクが発行者にある場合だけ数量の変更が可能です。 divisibility > 0 の場合は、最小単位を1として整数値で定義してください。 (divisibility:2 で 1.00 作成したい場合は100と指定)
MosaicSupplyChangeActionは以下の通りです。
{0: 'Decrease', 1: 'Increase'}
増やしたい場合はIncreaseを指定します。 上記2つのトランザクションをまとめてアグリゲートトランザクションを作成します。
// マークルハッシュの算出
embeddedTransactions = [mosaicDefTx, mosaicChangeTx];
merkleHash = facade.constructor.hashEmbeddedTransactions(embeddedTransactions);
// アグリゲートTx作成
aggregateTx = facade.transactionFactory.create({
type: "aggregate_complete_transaction_v2",
signerPublicKey: aliceKey.publicKey, // 署名者公開鍵
deadline: facade.network.fromDatetime(Date.now()).addHours(2).timestamp, //Deadline:有効期限
transactionsHash: merkleHash,
transactions: embeddedTransactions,
});
// 連署により追加される連署情報のサイズを追加して最終的なTxサイズを算出する
requiredCosignatures = 0; // 必要な連署者の数を指定
calculatedCosignatures =
requiredCosignatures > aggregateTx.cosignatures.length
? requiredCosignatures
: aggregateTx.cosignatures.length;
sizePerCosignature = 8 + 32 + 64;
calculatedSize =
aggregateTx.size -
aggregateTx.cosignatures.length * sizePerCosignature +
calculatedCosignatures * sizePerCosignature;
aggregateTx.fee = new symbolSdk.symbol.Amount(BigInt(calculatedSize * 100)); //手数料
// 署名とアナウンス
sig = facade.signTransaction(aliceKey, aggregateTx);
jsonPayload = facade.transactionFactory.constructor.attachSignature(
aggregateTx,
sig,
);
await fetch(new URL("/transactions", NODE), {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: jsonPayload,
})
.then((res) => res.json())
.then((json) => {
return json;
});
アグリゲートトランザクションの特徴として、 まだ存在していないモザイクの数量を変更しようとしている点に注目してください。 配列化した時に、矛盾点がなければ1つのブロック内で問題なく処理することができます。
確認
モザイク作成したアカウントが持つモザイク情報を確認します。
// 3.3 アカウント情報の確認 - 所有モザイク一覧の取得 を事前に実施する
accountInfo.mosaics.forEach(async (mosaic) => {
mosaicInfo = await fetch(new URL("/mosaics/" + mosaic.id, NODE), {
method: "GET",
headers: { "Content-Type": "application/json" },
})
.then((res) => res.json())
.then((json) => {
return json;
});
console.log(mosaicInfo);
});
出力例
> {mosaic: {…}, id: '64B3E2336FFE587B6D24CE90'}
id: "64B3E2336FFE587B6D24CE90"
> mosaic:
divisibility: 2 // 可分性
duration: "0" // 有効期限
flags: 13 // モザイクフラグ、有効なフラグに対応した値の合計
// 供給量変更の可否(1)
// 第三者への譲渡可否(2)
// 制限設定の可否(4)
// 発行者からの還収可否(8)
id: "663B178E904CADB8" // モザイクID
ownerAddress: "982B2AA2295B5C23528ADDEE7F29F6521944E9F2340428AB" // 作成者アドレス
revision: 1
startHeight: "640252"
supply: "10000" // 供給量
version: 1
5.2 モザイク送信
作成したモザイクを送信します。 よく、ブロックチェーンに初めて触れる方は、 モザイク送信について「クライアント端末に保存されたモザイクを別のクライアント端末へ送信」することとイメージされている人がいますが、 モザイク情報はすべてのノードで常に共有・同期化されており、送信先に未知のモザイク情報を届けることではありません。 正確にはブロックチェーンへ「トランザクションを送信」することにより、アカウント間でのトークン残量を組み替える操作のことを言います。
//受信アカウント作成
bobKey = new symbolSdk.symbol.KeyPair(symbolSdk.PrivateKey.random());
bobAddress = facade.network.publicKeyToAddress(bobKey.publicKey);
// Tx作成
tx = facade.transactionFactory.create({
type: "transfer_transaction_v1", // Txタイプ:転送Tx
signerPublicKey: aliceKey.publicKey, // 署名者公開鍵
deadline: facade.network.fromDatetime(Date.now()).addHours(2).timestamp, //Deadline:有効期限
recipientAddress: bobAddress.toString(),
mosaics: [
{ mosaicId: 0x72c0212e67a08bcen, amount: 1000000n }, // 1XYM送金
{ mosaicId: mosaicDefTx.id.value, amount: 1n }, // 5.1 で作成したモザイク
],
message: new Uint8Array(),
});
tx.fee = new symbolSdk.symbol.Amount(BigInt(tx.size * 100)); //手数料
// 署名とアナウンス
sig = facade.signTransaction(aliceKey, tx);
jsonPayload = facade.transactionFactory.constructor.attachSignature(tx, sig);
await fetch(new URL("/transactions", NODE), {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: jsonPayload,
})
.then((res) => res.json())
.then((json) => {
return json;
});
送信モザイクリスト
複数のモザイクを一度に送信できます。 XYMを送信するには以下のモザイクIDを指定します。
- メインネット:6BED913FA20223F8
- テストネット:72C0212E67A08BCE