コンテンツにスキップ
上級

モザイクの作成⚓︎

モザイク は、通貨、コレクターズアイテム、アクセス権などをSymbolブロックチェーン上の資産を表します。 他のプラットフォームのトークンとは異なり、Symbolのモザイクはプロトコルレベルで直接サポートされているため、使用するために追加のコーディングは必要ありません。 単純な通貨から制限付きトークンまで、さまざまなユースケースをサポートするためにプロパティを構成できます。

このチュートリアルでは、モザイクを作成し、その初期供給量をミント(鋳造)する方法を説明します。

前提条件⚓︎

開始する前に、以下を確認してください。

さらに、トランザクションがどのようにアナウンスされ承認されるかを理解するために、転送トランザクション のチュートリアルを復習しておいてください。

完全なコード⚓︎

このチュートリアルの完全なコード一覧を以下に示します。 詳細な手順ごとの説明は次のセクションで行います。

import json
import os
import time
import urllib.request

from symbolchain.CryptoTypes import PrivateKey
from symbolchain.facade.SymbolFacade import SymbolFacade
from symbolchain.symbol.Network import NetworkTimestamp
from symbolchain.symbol.IdGenerator import generate_mosaic_id
from symbolchain.sc import Amount

NODE_URL = os.getenv(
    'NODE_URL', 'https://reference.symboltest.net:3001')
print(f'Using node {NODE_URL}')


# Helper function to announce a transaction
def announce_transaction(payload, label):
    print(f'Announcing {label} to /transactions')
    request = urllib.request.Request(
        f'{NODE_URL}/transactions',
        data=payload.encode(),
        headers={'Content-Type': 'application/json'},
        method='PUT'
    )
    with urllib.request.urlopen(request) as response:
        print(f'  Response: {response.read().decode()}')


# Helper function to wait for transaction confirmation
def wait_for_confirmation(transaction_hash, label):
    print(f'Waiting for {label} confirmation...')
    for attempt in range(60):
        time.sleep(1)
        try:
            url = f'{NODE_URL}/transactionStatus/{transaction_hash}'
            with urllib.request.urlopen(url) as response:
                status = json.loads(response.read().decode())
                print(f'  Transaction status: {status["group"]}')
                if status['group'] == 'confirmed':
                    print(f'{label} confirmed in {attempt} seconds')
                    return
                if status['group'] == 'failed':
                    raise Exception(f'{label} failed: {status["code"]}')
        except urllib.error.HTTPError:
            print('  Transaction status: unknown')
    raise Exception(f'{label} not confirmed after 60 seconds')


SIGNER_PRIVATE_KEY = os.getenv(
    'SIGNER_PRIVATE_KEY',
    '0000000000000000000000000000000000000000000000000000000000000000')
signer_key_pair = SymbolFacade.KeyPair(
    PrivateKey(SIGNER_PRIVATE_KEY))

facade = SymbolFacade('testnet')
signer_address = facade.network.public_key_to_address(
    signer_key_pair.public_key)
print(f'Signer address: {signer_address}')

try:
    # Fetch current network time
    time_path = '/node/time'
    print(f'Fetching current network time from {time_path}')
    with urllib.request.urlopen(f'{NODE_URL}{time_path}') as response:
        response_json = json.loads(response.read().decode())
        receive_timestamp = (
            response_json['communicationTimestamps']['receiveTimestamp'])
        timestamp = NetworkTimestamp(int(receive_timestamp))
        print(f'  Network time: {timestamp.timestamp} ms since nemesis')

    # Fetch recommended fees
    fee_path = '/network/fees/transaction'
    print(f'Fetching recommended fees from {fee_path}')
    with urllib.request.urlopen(f'{NODE_URL}{fee_path}') as response:
        response_json = json.loads(response.read().decode())
        median_mult = response_json['medianFeeMultiplier']
        minimum_mult = response_json['minFeeMultiplier']
        fee_mult = max(median_mult, minimum_mult)
        print(f'  Fee multiplier: {fee_mult}')

    # --- CREATING MOSAIC DEFINITION ---
    print('\n--- Creating mosaic definition ---')

    nonce = int(time.time()) & 0xFFFFFFFF
    print(f'Mosaic nonce: {nonce}')

    definition_tx = facade.transaction_factory.create({
        'type': 'mosaic_definition_transaction_v1',
        'signer_public_key': signer_key_pair.public_key,
        'deadline': timestamp.add_hours(2).timestamp,
        'duration': 0,
        'divisibility': 2,
        'nonce': nonce,
        'flags': 'transferable restrictable'
    })
    definition_tx.fee = Amount(fee_mult * definition_tx.size)

    mosaic_id = generate_mosaic_id(signer_address, nonce)
    print(f'Mosaic ID: {mosaic_id} ({hex(mosaic_id)})')

    # Sign and generate final payload
    signature = facade.sign_transaction(signer_key_pair, definition_tx)
    json_payload = facade.transaction_factory.attach_signature(
            definition_tx, signature)
    print('Built mosaic definition transaction:')
    print(json.dumps(definition_tx.to_json(), indent=2))

    # Announce and wait for confirmation
    definition_hash = facade.hash_transaction(definition_tx)
    print(f'Transaction hash: {definition_hash}')
    announce_transaction(json_payload, 'mosaic definition')
    wait_for_confirmation(definition_hash, 'mosaic definition')

    # --- INCREASING MOSAIC SUPPLY ---
    print('\n--- Increasing mosaic supply ---')

    supply_tx = facade.transaction_factory.create({
        'type': 'mosaic_supply_change_transaction_v1',
        'signer_public_key': signer_key_pair.public_key,
        'deadline': timestamp.add_hours(2).timestamp,
        'mosaic_id': mosaic_id,
        'action': 'increase',
        'delta': 100_00
    })
    supply_tx.fee = Amount(fee_mult * supply_tx.size)

    # Sign and generate final payload
    signature = facade.sign_transaction(signer_key_pair, supply_tx)
    json_payload = facade.transaction_factory.attach_signature(
            supply_tx, signature)
    print(
        'Built mosaic supply change transaction:')
    print(json.dumps(supply_tx.to_json(), indent=2))

    # Announce and wait for confirmation
    supply_hash = facade.hash_transaction(supply_tx)
    print(f'Transaction hash: {supply_hash}')
    announce_transaction(json_payload, 'mosaic supply change')
    wait_for_confirmation(supply_hash, 'mosaic supply change')

    # --- VERIFYING MOSAIC ---
    print('\n--- Verifying mosaic ---')

    mosaic_id_hex = f'{mosaic_id:016x}'
    mosaic_path = f'/mosaics/{mosaic_id_hex}'
    print(f'Fetching mosaic information from {mosaic_path}')
    with urllib.request.urlopen(f'{NODE_URL}{mosaic_path}') as response:
        response_json = json.loads(response.read().decode())
        mosaic_info = response_json['mosaic']
        print('Mosaic information:')
        print(f'  Mosaic ID: {mosaic_info["id"]}')
        print(f'  Supply: {mosaic_info["supply"]}')
        print(f'  Flags: {mosaic_info["flags"]}')
        print(f'  Divisibility: {mosaic_info["divisibility"]}')
        print(f'  Duration: {mosaic_info["duration"]}')

except Exception as e:
    print(e)

Download source

import { PrivateKey } from 'symbol-sdk';
import {
    SymbolFacade,
    NetworkTimestamp,
    models,
    generateMosaicId
} from 'symbol-sdk/symbol';

const NODE_URL = process.env.NODE_URL ||
    'https://reference.symboltest.net:3001';
console.log('Using node', NODE_URL);

// Helper function to announce a transaction
async function announceTransaction(payload, label) {
    console.log(`Announcing ${label} to /transactions`);
    const response = await fetch(`${NODE_URL}/transactions`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: payload
    });
    console.log('  Response:', await response.text());
}

// Helper function to wait for transaction confirmation
async function waitForConfirmation(transactionHash, label) {
    console.log(`Waiting for ${label} confirmation...`);
    for (let attempt = 0; attempt < 60; attempt++) {
        await new Promise(resolve => setTimeout(resolve, 1000));
        try {
            const response = await fetch(
                `${NODE_URL}/transactionStatus/${transactionHash}`);
            const status = await response.json();
            console.log('  Transaction status:', status.group);
            if (status.group === 'confirmed') {
                console.log(`${label} confirmed in`, attempt, 'seconds');
                return;
            }
            if (status.group === 'failed') {
                throw new Error(`${label} failed: ${status.code}`);
            }
        } catch (e) {
            if (e.message.includes('failed'))
                throw e;
            console.log('  Transaction status: unknown');
        }
    }
    throw new Error(`${label} not confirmed after 60 seconds`);
}

const SIGNER_PRIVATE_KEY = process.env.SIGNER_PRIVATE_KEY || (
    '0000000000000000000000000000000000000000000000000000000000000000');
const signerKeyPair = new SymbolFacade.KeyPair(
    new PrivateKey(SIGNER_PRIVATE_KEY));

const facade = new SymbolFacade('testnet');
const signerAddress =facade.network.publicKeyToAddress(
    signerKeyPair.publicKey);
console.log('Signer address:', signerAddress.toString());

try {
    // Fetch current network time
    const timePath = '/node/time';
    console.log('Fetching current network time from', timePath);
    const timeResponse = await fetch(`${NODE_URL}${timePath}`);
    const timeJSON = await timeResponse.json();
    const timestamp = new NetworkTimestamp(
        timeJSON.communicationTimestamps.receiveTimestamp);
    console.log('  Network time:', timestamp.timestamp,
        'ms since nemesis');

    // Fetch recommended fees
    const feePath = '/network/fees/transaction';
    console.log('Fetching recommended fees from', feePath);
    const feeResponse = await fetch(`${NODE_URL}${feePath}`);
    const feeJSON = await feeResponse.json();
    const medianMult = feeJSON.medianFeeMultiplier;
    const minimumMult = feeJSON.minFeeMultiplier;
    const feeMult = Math.max(medianMult, minimumMult);
    console.log('  Fee multiplier:', feeMult);

    // --- CREATING MOSAIC DEFINITION ---
    console.log('\n--- Creating mosaic definition ---');

    const nonce = Math.floor(Date.now() / 1000) & 0x7FFFFFFF;
    console.log('Mosaic nonce:', nonce);

    const definitionTx =
        facade.transactionFactory.create({
            type: 'mosaic_definition_transaction_v1',
            signerPublicKey: signerKeyPair.publicKey.toString(),
            deadline: timestamp.addHours(2).timestamp,
            duration: 0n,
            divisibility: 2,
            nonce: nonce,
            flags: 'transferable restrictable'
        });
    definitionTx.fee = new models.Amount(feeMult * definitionTx.size);

    const mosaicId = generateMosaicId(signerAddress, nonce);
    console.log(`Mosaic ID: ${mosaicId} (0x${mosaicId.toString(16)})`);

    // Sign and generate final payload
    const defSignature = facade.signTransaction(
        signerKeyPair, definitionTx);
    const defPayload = facade.transactionFactory.static.attachSignature(
        definitionTx, defSignature);
    console.log('Built mosaic definition transaction:');
    console.dir(definitionTx.toJson(), { colors: true });

    // Announce and wait for confirmation
    const definitionHash =
        facade.hashTransaction(definitionTx).toString();
    console.log('Transaction hash:', definitionHash);
    await announceTransaction(defPayload, 'mosaic definition');
    await waitForConfirmation(definitionHash, 'mosaic definition');

    // --- INCREASING MOSAIC SUPPLY ---
    console.log('\n--- Increasing mosaic supply ---');

    const supplyTx =
        facade.transactionFactory.create({
            type: 'mosaic_supply_change_transaction_v1',
            signerPublicKey: signerKeyPair.publicKey.toString(),
            deadline: timestamp.addHours(2).timestamp,
            mosaicId: mosaicId,
            action: 'increase',
            delta: 100_00n
        });
    supplyTx.fee = new models.Amount(feeMult * supplyTx.size);

    // Sign and generate final payload
    const supSignature = facade.signTransaction(
        signerKeyPair, supplyTx);
    const supPayload = facade.transactionFactory.static.attachSignature(
        supplyTx, supSignature);
    console.log('Built mosaic supply change transaction:');
    console.dir(supplyTx.toJson(), { colors: true });

    // Announce and wait for confirmation
    const supplyHash = facade.hashTransaction(supplyTx).toString();
    console.log('Transaction hash:', supplyHash);
    await announceTransaction(supPayload, 'mosaic supply change');
    await waitForConfirmation(supplyHash, 'mosaic supply change');

    // --- VERIFYING MOSAIC ---
    console.log('\n--- Verifying mosaic ---');

    const mosaicIdHex = mosaicId.toString(16).padStart(16, '0');
    const mosaicPath = `/mosaics/${mosaicIdHex}`;
    console.log('Fetching mosaic information from', mosaicPath);
    const mosaicResponse = await fetch(`${NODE_URL}${mosaicPath}`);
    const mosaicJSON = await mosaicResponse.json();
    const mosaicInfo = mosaicJSON.mosaic;
    console.log('Mosaic information:');
    console.log('  Mosaic ID:', mosaicInfo.id);
    console.log('  Supply:', mosaicInfo.supply);
    console.log('  Flags:', mosaicInfo.flags);
    console.log('  Divisibility:', mosaicInfo.divisibility);
    console.log('  Duration:', mosaicInfo.duration);
} catch (e) {
    console.error(e.message);
}

Download source

コード解説⚓︎

モザイクの作成には、2つのトランザクションをアナウンスする必要があります。

  1. モザイクとそのプロパティを登録するための モザイク定義 トランザクション。
  2. 初期ユニットをミントするための モザイク供給量変更 トランザクション。

アカウントの設定⚓︎

SIGNER_PRIVATE_KEY = os.getenv(
    'SIGNER_PRIVATE_KEY',
    '0000000000000000000000000000000000000000000000000000000000000000')
signer_key_pair = SymbolFacade.KeyPair(
    PrivateKey(SIGNER_PRIVATE_KEY))

facade = SymbolFacade('testnet')
signer_address = facade.network.public_key_to_address(
    signer_key_pair.public_key)
print(f'Signer address: {signer_address}')
const SIGNER_PRIVATE_KEY = process.env.SIGNER_PRIVATE_KEY || (
    '0000000000000000000000000000000000000000000000000000000000000000');
const signerKeyPair = new SymbolFacade.KeyPair(
    new PrivateKey(SIGNER_PRIVATE_KEY));

const facade = new SymbolFacade('testnet');
const signerAddress =facade.network.publicKeyToAddress(
    signerKeyPair.publicKey);
console.log('Signer address:', signerAddress.toString());

このスニペットは、署名者の 秘密鍵SIGNER_PRIVATE_KEY 環境変数から読み取ります。設定されていない場合はデフォルトのテストキーが使用されます。 署名者の アドレス公開鍵 から派生します。 このアカウントが作成されたモザイクを所有することになります。

ネットワーク時間と手数料の取得⚓︎

    # Fetch current network time
    time_path = '/node/time'
    print(f'Fetching current network time from {time_path}')
    with urllib.request.urlopen(f'{NODE_URL}{time_path}') as response:
        response_json = json.loads(response.read().decode())
        receive_timestamp = (
            response_json['communicationTimestamps']['receiveTimestamp'])
        timestamp = NetworkTimestamp(int(receive_timestamp))
        print(f'  Network time: {timestamp.timestamp} ms since nemesis')

    # Fetch recommended fees
    fee_path = '/network/fees/transaction'
    print(f'Fetching recommended fees from {fee_path}')
    with urllib.request.urlopen(f'{NODE_URL}{fee_path}') as response:
        response_json = json.loads(response.read().decode())
        median_mult = response_json['medianFeeMultiplier']
        minimum_mult = response_json['minFeeMultiplier']
        fee_mult = max(median_mult, minimum_mult)
        print(f'  Fee multiplier: {fee_mult}')
    // Fetch current network time
    const timePath = '/node/time';
    console.log('Fetching current network time from', timePath);
    const timeResponse = await fetch(`${NODE_URL}${timePath}`);
    const timeJSON = await timeResponse.json();
    const timestamp = new NetworkTimestamp(
        timeJSON.communicationTimestamps.receiveTimestamp);
    console.log('  Network time:', timestamp.timestamp,
        'ms since nemesis');

    // Fetch recommended fees
    const feePath = '/network/fees/transaction';
    console.log('Fetching recommended fees from', feePath);
    const feeResponse = await fetch(`${NODE_URL}${feePath}`);
    const feeJSON = await feeResponse.json();
    const medianMult = feeJSON.medianFeeMultiplier;
    const minimumMult = feeJSON.minFeeMultiplier;
    const feeMult = Math.max(medianMult, minimumMult);
    console.log('  Fee multiplier:', feeMult);

転送トランザクション チュートリアルで説明されているプロセスに従い、ネットワーク時間と推奨手数料をそれぞれ /node/time GET および /network/fees/transaction GET から取得します。

モザイク定義トランザクションの構築⚓︎

    nonce = int(time.time()) & 0xFFFFFFFF
    print(f'Mosaic nonce: {nonce}')

    definition_tx = facade.transaction_factory.create({
        'type': 'mosaic_definition_transaction_v1',
        'signer_public_key': signer_key_pair.public_key,
        'deadline': timestamp.add_hours(2).timestamp,
        'duration': 0,
        'divisibility': 2,
        'nonce': nonce,
        'flags': 'transferable restrictable'
    })
    definition_tx.fee = Amount(fee_mult * definition_tx.size)

    mosaic_id = generate_mosaic_id(signer_address, nonce)
    print(f'Mosaic ID: {mosaic_id} ({hex(mosaic_id)})')
    const nonce = Math.floor(Date.now() / 1000) & 0x7FFFFFFF;
    console.log('Mosaic nonce:', nonce);

    const definitionTx =
        facade.transactionFactory.create({
            type: 'mosaic_definition_transaction_v1',
            signerPublicKey: signerKeyPair.publicKey.toString(),
            deadline: timestamp.addHours(2).timestamp,
            duration: 0n,
            divisibility: 2,
            nonce: nonce,
            flags: 'transferable restrictable'
        });
    definitionTx.fee = new models.Amount(feeMult * definitionTx.size);

    const mosaicId = generateMosaicId(signerAddress, nonce);
    console.log(`Mosaic ID: ${mosaicId} (0x${mosaicId.toString(16)})`);

モザイク定義トランザクションは、以下のプロパティを使用してネットワークに新しいモザイクを登録します。

  • Type: モザイク定義トランザクションにはタイプ mosaic_definition_transaction_v1 を使用します。

  • Duration (有効期間): モザイクがアクティブな状態を維持するブロック数。値が 0 の場合、モザイクは期限切れになりません。 有効期間を指定する場合、最大許容値は 約10年 です(デフォルトの30秒ブロックターゲットで、3,650日、または約10,512,000ブロック)。

    期限切れのモザイクは使用できなくなります

    期限のあるモザイクがその期間に達すると、転送やトランザクションでの使用ができなくなります。 残高はアカウントに残りますが、事実上凍結された状態になります。 期間を設定する前に、ユースケースで本当にそれが必要かどうかを検討してください。

  • Divisibility (可分性): モザイクがサポートする小数点以下の桁数。 例えば、値が 2 の場合、各整数単位は 100 (\(10^2\)) の絶対単位に分割できます。 詳細については、テキストブックの 可分性 を参照してください。

  • Nonce (ノンス): 同じアカウントによって作成されたモザイクの、ローカルで一意な識別子として機能する任意の32ビット無符号整数(0 から 4,294,967,295)です。 モザイクID は、 を使用して所有者のアドレスと ノンス から決定論的に派生するため、一意のノンスごとに異なるモザイクが生成されます。

    このチュートリアルでのノンスの選択

    このチュートリアルでは、実行ごとに一意のモザイクが作成されるように、現在のタイムスタンプをノンスとして使用しています。 & 0xFFFFFFFF ビットマスクは、値を32ビットに収まるように切り詰めます。 実際には、同じアカウントがそのノンスをまだ使用していない限り、どのような値でも機能します。

  • Flags (フラグ): モザイクの動作制限を指定するフラグのセット。 'transferable restrictable' のように、複数のフラグを一つの文字列で組み合わせることができます。

    利用可能なフラグは以下の通りです。

    • transferable: モザイクを任意のアカウント間で自由に送信できます。
    • supply_mutable: 作成後に総供給量を変更できます。
    • restrictable: 所有者が モザイク制限 を適用して、どのオプションがモザイクを保持または転送できるかを制御できます。
    • revokable: 作成者が任意のアカウントからモザイクを回収(取り戻す)できます。

    この例では、 transferable restrictable を使用しています。

レンタル手数料

標準の トランザクション手数料 に加えて、モザイクの作成には XYM で支払う一回限りのレンタル手数料が必要です。

トランザクション手数料とは異なり、レンタル手数料はトランザクションリクエストには 含まれません。 モザイク定義トランザクションが承認されると、ネットワークによって署名者のアカウントから自動的に差し引かれます。

レンタル手数料の額は、 /network/fees/rental GET エンドポイント( effectiveMosaicRentalFee プロパティ)から照会できます。

モザイク定義の送信⚓︎

    # Sign and generate final payload
    signature = facade.sign_transaction(signer_key_pair, definition_tx)
    json_payload = facade.transaction_factory.attach_signature(
            definition_tx, signature)
    print('Built mosaic definition transaction:')
    print(json.dumps(definition_tx.to_json(), indent=2))

    # Announce and wait for confirmation
    definition_hash = facade.hash_transaction(definition_tx)
    print(f'Transaction hash: {definition_hash}')
    announce_transaction(json_payload, 'mosaic definition')
    wait_for_confirmation(definition_hash, 'mosaic definition')
    // Sign and generate final payload
    const defSignature = facade.signTransaction(
        signerKeyPair, definitionTx);
    const defPayload = facade.transactionFactory.static.attachSignature(
        definitionTx, defSignature);
    console.log('Built mosaic definition transaction:');
    console.dir(definitionTx.toJson(), { colors: true });

    // Announce and wait for confirmation
    const definitionHash =
        facade.hashTransaction(definitionTx).toString();
    console.log('Transaction hash:', definitionHash);
    await announceTransaction(defPayload, 'mosaic definition');
    await waitForConfirmation(definitionHash, 'mosaic definition');

モザイク定義トランザクションは、 転送トランザクションの作成 と同じプロセスに従って署名され、アナウンスされます。

コードはその後、ステータスが confirmed に変わるまで /transactionStatus/{hash} GET エンドポイントをポーリングして、トランザクションが承認されるのを待ちます。

モザイク供給量変更トランザクションの構築⚓︎

    supply_tx = facade.transaction_factory.create({
        'type': 'mosaic_supply_change_transaction_v1',
        'signer_public_key': signer_key_pair.public_key,
        'deadline': timestamp.add_hours(2).timestamp,
        'mosaic_id': mosaic_id,
        'action': 'increase',
        'delta': 100_00
    })
    supply_tx.fee = Amount(fee_mult * supply_tx.size)
    const supplyTx =
        facade.transactionFactory.create({
            type: 'mosaic_supply_change_transaction_v1',
            signerPublicKey: signerKeyPair.publicKey.toString(),
            deadline: timestamp.addHours(2).timestamp,
            mosaicId: mosaicId,
            action: 'increase',
            delta: 100_00n
        });
    supplyTx.fee = new models.Amount(feeMult * supplyTx.size);

モザイク定義が承認されると、2番目のトランザクションでモザイクの供給量を増加させます。

  • Type: モザイク供給量変更トランザクションにはタイプ mosaic_supply_change_transaction_v1 を使用します。

  • Mosaic ID: 署名者のアドレスとノンスから を使用して計算されたモザイクの識別子。

  • Action: increase(増加)という値は、署名者のアカウントに直接新しいユニットをミントします。

  • Delta (差分): 追加する絶対単位の数。 モザイクの 可分性2 であるため、デルタを 10000 にすると、整数単位では 100.00 になります (\(10000 / 10^2\))。

供給量変更の送信⚓︎

    # Sign and generate final payload
    signature = facade.sign_transaction(signer_key_pair, supply_tx)
    json_payload = facade.transaction_factory.attach_signature(
            supply_tx, signature)
    print(
        'Built mosaic supply change transaction:')
    print(json.dumps(supply_tx.to_json(), indent=2))

    # Announce and wait for confirmation
    supply_hash = facade.hash_transaction(supply_tx)
    print(f'Transaction hash: {supply_hash}')
    announce_transaction(json_payload, 'mosaic supply change')
    wait_for_confirmation(supply_hash, 'mosaic supply change')
    // Sign and generate final payload
    const supSignature = facade.signTransaction(
        signerKeyPair, supplyTx);
    const supPayload = facade.transactionFactory.static.attachSignature(
        supplyTx, supSignature);
    console.log('Built mosaic supply change transaction:');
    console.dir(supplyTx.toJson(), { colors: true });

    // Announce and wait for confirmation
    const supplyHash = facade.hashTransaction(supplyTx).toString();
    console.log('Transaction hash:', supplyHash);
    await announceTransaction(supPayload, 'mosaic supply change');
    await waitForConfirmation(supplyHash, 'mosaic supply change');

モザイク供給量変更トランザクションは、モザイク定義トランザクションと同じプロセスに従って署名され、アナウンスされます。

両方のトランザクションの組み合わせ

定義と供給量変更を2つの別々のトランザクションとしてアナウンスする代わりに、単一の アグリゲートコンプリートトランザクション 内でまとめて送信することができます。

これにより、両方の操作が同じブロック内でアトミック(不可分)に承認されることが保証されます。

supply_mutable フラグがなくても、所有者が供給量全体を保持している限り、供給量の変更は許可されます。ユニットがいずれかの他のアカウントに配布されると、供給量は恒久的に固定されます。

モザイクの取得⚓︎

    mosaic_id_hex = f'{mosaic_id:016x}'
    mosaic_path = f'/mosaics/{mosaic_id_hex}'
    print(f'Fetching mosaic information from {mosaic_path}')
    with urllib.request.urlopen(f'{NODE_URL}{mosaic_path}') as response:
        response_json = json.loads(response.read().decode())
        mosaic_info = response_json['mosaic']
        print('Mosaic information:')
        print(f'  Mosaic ID: {mosaic_info["id"]}')
        print(f'  Supply: {mosaic_info["supply"]}')
        print(f'  Flags: {mosaic_info["flags"]}')
        print(f'  Divisibility: {mosaic_info["divisibility"]}')
        print(f'  Duration: {mosaic_info["duration"]}')
    const mosaicIdHex = mosaicId.toString(16).padStart(16, '0');
    const mosaicPath = `/mosaics/${mosaicIdHex}`;
    console.log('Fetching mosaic information from', mosaicPath);
    const mosaicResponse = await fetch(`${NODE_URL}${mosaicPath}`);
    const mosaicJSON = await mosaicResponse.json();
    const mosaicInfo = mosaicJSON.mosaic;
    console.log('Mosaic information:');
    console.log('  Mosaic ID:', mosaicInfo.id);
    console.log('  Supply:', mosaicInfo.supply);
    console.log('  Flags:', mosaicInfo.flags);
    console.log('  Divisibility:', mosaicInfo.divisibility);
    console.log('  Duration:', mosaicInfo.duration);

モザイクが正常に作成されたことを確認するために、コードは /mosaics/{mosaicId} GET エンドポイントを使用してネットワークからモザイクを取得し、そのプロパティを表示します。

レスポンスが成功すれば、期待通りの供給量と可分性を持ってネットワーク上にモザイクが存在することが確認されます。

出力⚓︎

以下に示す出力は、プログラムの典型的な実行結果に対応しています。

Using node https://reference.symboltest.net:3001
Signer address: TCHBDENCLKEBILBPWP3JPB2XNY64OE7PYHHE32I
Fetching current network time from /node/time
  Network time: 103504012049 ms since nemesis
Fetching recommended fees from /network/fees/transaction
  Fee multiplier: 100

--- Creating mosaic definition ---
Mosaic nonce: 1770754477
Mosaic ID: 8318126551268698739 (0x736fec06ed1daa73)
Built mosaic definition transaction:
{
  "signature": "6516FB17F162075795E8A4578595DE4745A57B151A6A6ACABF613C1ADF94DC36AF13F661E9FC356723A1F653D2ECC434E514F891A7D16502825431FE5AC17F06",
  "signer_public_key": "3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29",
  "version": 1,
  "network": 152,
  "type": 16717,
  "fee": "15000",
  "deadline": "103511212049",
  "id": "8318126551268698739",
  "duration": "0",
  "nonce": 1770754477,
  "flags": 6,
  "divisibility": 2
}
Transaction hash: 959C4FDE753700E21959CB23E46EE761937A3AFEAFB40DBD9ADFBEE2D1C85F8B
Announcing mosaic definition to /transactions
  Response: {"message":"packet 9 was pushed to the network via /transactions"}
Waiting for mosaic definition confirmation...
  Transaction status: unconfirmed
  Transaction status: unconfirmed
  Transaction status: confirmed
Mosaic definition confirmed in 12 seconds

--- Increasing mosaic supply ---
Built mosaic supply change transaction:
{
  "signature": "9704D30D6B060CB28A5A8DA3BAC40B7D02D878199C32D57FA70B6EB213735677BF7380F14A1A9B04B7DEA806D55A379CF20BAC3BDA24D16094DF2F97917A5605",
  "signer_public_key": "3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29",
  "version": 1,
  "network": 152,
  "type": 16973,
  "fee": "14500",
  "deadline": "103511212049",
  "mosaic_id": "8318126551268698739",
  "delta": "10000",
  "action": 1
}
Transaction hash: E4E002C9E4536666E47E4B98DB7307FF5715C4BD8C4579D8AD67C9CBCECC2CD2
Announcing mosaic supply change to /transactions
  Response: {"message":"packet 9 was pushed to the network via /transactions"}
Waiting for mosaic supply change confirmation...
  Transaction status: unconfirmed
  Transaction status: confirmed
Mosaic supply change confirmed in 9 seconds

--- Verifying mosaic ---
Fetching mosaic information from /mosaics/736fec06ed1daa73
Mosaic information:
  Mosaic ID: 736FEC06ED1DAA73
  Supply: 10000
  Flags: 6
  Divisibility: 2
  Duration: 0

出力の主なポイント:

  • モザイクID (10行目): ノンスが署名者のアドレスと組み合わされ、モザイクID 0x736fec06ed1daa73 が派生します。

  • 手数料 (18行目): 0.015 XYM のトランザクション手数料は、トランザクションサイズに手数料倍率を乗じて計算されます。 レンタル手数料 は、トランザクションが承認された際にネットワークによって別途差し引かれます。

  • モザイクID (20行目): id フィールドは、ノンスと署名者のアドレスからトランザクションファクトリによって自動的に計算され、10行目に印刷された値と一致します。

  • モザイクプロパティ (21、23-24行目): フラグはビットマスクとして保存され、各フラグは1ビットを占めます。 supply_mutable (1)、 transferable (2)、 restrictable (4)、 revokable (8) です。 値 6 は、 transferable (2) + restrictable (4) と等しくなります。可分性は 2 で、有効期間 0 はモザイクが期限切れにならないことを意味します。

  • 供給量デルタ (46行目): デルタ 10000 絶対単位は、モザイクの可分性が 2 であるため、 100.00 整数単位を表します。

  • 検証されたプロパティ (60-64行目): モザイクがネットワークから取得され、期待通りの供給量、フラグ、可分性、有効期間が確認されました。

出力に印刷されたトランザクション ハッシュ を使用して、 Symbol Testnet Explorer でトランザクションを検索できます。

結論⚓︎

このチュートリアルでは、以下の方法を説明しました。

ステップ 関連ドキュメント
モザイクIDを生成する
モザイクを定義する
モザイク供給量をミントする
モザイクを取得する /mosaics/{mosaicId} GET

次のステップ⚓︎

モザイクを作成したので、以下のことができます。