Skip to content

Modifying a Mosaic Definition⚓︎

As long as no units of a mosaic exist on the network, its creator can still change its definition properties (flags, divisibility, and duration) by sending a second definition transaction with the same identifier.

For example, adding a flag that was not set initially, changing its divisibility, or extending its duration before distribution.

Zero supply requirement

A mosaic definition can only be modified when its total supply is 0. No units of the mosaic can exist anywhere on the network, otherwise the transaction fails with Failure_Mosaic_Modification_Disallowed.

This tutorial shows how to modify an existing mosaic's flags. To change the mosaic's supply instead of its definition, see Changing Mosaic Supply.

Consider creating a new mosaic instead

Creating a new mosaic is easier than modifying an existing one. Understanding how modification works is still important to know when a mosaic's definition can no longer be edited.

Prerequisites⚓︎

Before you start, make sure to:

Additionally, review the Transfer transaction tutorial to understand how transactions are announced and confirmed.

Full Code⚓︎

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}')

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}')

    # Build the modification transaction
    MOSAIC_NONCE = int(os.getenv('MOSAIC_NONCE', '0'))
    print(f'Mosaic nonce: {MOSAIC_NONCE}')

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

    modify_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': 0,
        'nonce': MOSAIC_NONCE,
        'flags': 'revokable'
    })
    modify_tx.fee = Amount(fee_mult * modify_tx.size)

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

    modify_hash = facade.hash_transaction(modify_tx)
    print(f'Transaction hash: {modify_hash}')

    # Announce transaction
    print('Announcing mosaic modification to /transactions')
    request = urllib.request.Request(
        f'{NODE_URL}/transactions',
        data=json_payload.encode(),
        headers={'Content-Type': 'application/json'},
        method='PUT'
    )
    with urllib.request.urlopen(request) as response:
        print(f'  Response: {response.read().decode()}')

    # Wait for confirmation
    print('Waiting for mosaic modification confirmation...')
    for attempt in range(60):
        time.sleep(1)
        try:
            status_url = (
                f'{NODE_URL}/transactionStatus/{modify_hash}')
            with urllib.request.urlopen(status_url) as response:
                status = json.loads(response.read().decode())
                print(f'  Transaction status: {status["group"]}')
            if status['group'] == 'confirmed':
                print('Mosaic modification confirmed in',
                    attempt, 'seconds')
                break
            if status['group'] == 'failed':
                raise Exception(
                    'Mosaic modification failed:', status['code'])
        except urllib.error.HTTPError:
            print('  Transaction status: unknown')

    # Retrieve the mosaic
    mosaic_id_hex = f'{mosaic_id:x}'
    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'  Divisibility: {mosaic_info["divisibility"]}')
        print(f'  Flags: {mosaic_info["flags"]}')
        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);

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

    // Build the modification transaction
    const MOSAIC_NONCE = parseInt(process.env.MOSAIC_NONCE || '0', 10);
    console.log('Mosaic nonce:', MOSAIC_NONCE);

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

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

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

    const modifyHash =
        facade.hashTransaction(modifyTx).toString();
    console.log('Transaction hash:', modifyHash);

    // Announce transaction
    console.log(
        'Announcing mosaic modification to /transactions');
    const announceResponse = await fetch(
        `${NODE_URL}/transactions`, {
            method: 'PUT',
            headers: { 'Content-Type': 'application/json' },
            body: jsonPayload
        });
    console.log('  Response:', await announceResponse.text());

    // Wait for confirmation
    console.log('Waiting for mosaic modification confirmation...');
    for (let attempt = 0; attempt < 60; attempt++) {
        await new Promise(resolve => setTimeout(resolve, 1000));

        try {
            const statusUrl =
                `${NODE_URL}/transactionStatus/${modifyHash}`;
            const statusResponse = await fetch(statusUrl);

            if (!statusResponse.ok) {
                console.log('  Transaction status: unknown');
                continue;
            }

            const status = await statusResponse.json();
            console.log('  Transaction status:', status.group);

            if (status.group === 'confirmed') {
                console.log('Mosaic modification confirmed in',
                    attempt, 'seconds');
                break;
            }

            if (status.group === 'failed') {
                throw new Error(
                    `Mosaic modification failed: ${status.code}`);
            }
        } catch (error) {
            if (error.message.includes('failed:')) {
                throw error;
            }
            console.log('  Transaction status: unknown');
        }
    }

    // Retrieve the mosaic
    const mosaicIdHex = mosaicId.toString(16);
    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('  Divisibility:', mosaicInfo.divisibility);
    console.log('  Flags:', mosaicInfo.flags);
    console.log('  Duration:', mosaicInfo.duration);
} catch (e) {
    console.error(e.message);
}

Download source

Code Explanation⚓︎

Setting Up the Account⚓︎

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

The snippet reads the signer's private key from the SIGNER_PRIVATE_KEY environment variable, which defaults to a test key if not set. The signer's address is derived from the public key. This account must be the original creator of the mosaic.

Fetching Network Time and Fees⚓︎

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

Network time and recommended fees are fetched from /node/time GET and /network/fees/transaction GET respectively, following the process described in the Transfer Transaction tutorial.

Building the Modification Transaction⚓︎

Modifying a mosaic definition requires knowing its current values (flags, divisibility, and duration), because the network combines them with the values in the transaction rather than replacing them. The mosaic can be retrieved using the /mosaics/{mosaicId} GET endpoint or looked up in the Symbol Explorer.

In this tutorial, the current values are already known because the mosaic was just created and retrieved in the previous tutorial.

    # Build the modification transaction
    MOSAIC_NONCE = int(os.getenv('MOSAIC_NONCE', '0'))
    print(f'Mosaic nonce: {MOSAIC_NONCE}')

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

    modify_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': 0,
        'nonce': MOSAIC_NONCE,
        'flags': 'revokable'
    })
    modify_tx.fee = Amount(fee_mult * modify_tx.size)
    // Build the modification transaction
    const MOSAIC_NONCE = parseInt(process.env.MOSAIC_NONCE || '0', 10);
    console.log('Mosaic nonce:', MOSAIC_NONCE);

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

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

The MOSAIC_NONCE environment variable specifies the nonce of the mosaic to modify. The nonce must match the one used when creating the mosaic to target the same mosaic.

The modification transaction uses the same mosaic_definition_transaction_v1 type as the original creation. The key difference is that the nonce targets an existing mosaic instead of creating a new one.

When processing the transaction, each property is combined with the mosaic's current value using the following rules:

  • Flags are XOR'd with the current flags. Setting a flag that is already active removes it; setting a flag that is not active adds it. For a description of each available flag, see Building the Mosaic Definition Transaction.
  • Divisibility is XOR'd with the current divisibility. The resulting value must be between 0 and 6.
  • Duration is added to the current remaining duration. Duration can only be extended, not reduced, because the field is unsigned. A value of 0 leaves the duration unchanged. Eternal mosaics (duration 0) cannot have their duration modified. The resulting duration cannot exceed 10,512,000 blocks (approximately 10 years).

In this example, the existing mosaic has flags transferable restrictable (numeric value 6). The modification sets flags: 'revokable' (numeric value 8). XOR produces 6 ⊕ 8 = 14, which corresponds to transferable restrictable revokable.

The following table illustrates how XOR affects individual flags:

Flag Current Modification Result (XOR)
transferable on off on
restrictable on off on
revokable off on on

Setting divisibility to 0 results in 2 ⊕ 0 = 2 (no change), and duration: 0 adds nothing to the current duration.

Lease fee

Each mosaic definition transaction incurs the full lease fee paid in XYM, whether creating or modifying a mosaic. This is the same fee every time, in addition to the standard transaction fee. The lease fee amount can be queried from the /network/fees/rental GET endpoint (effectiveMosaicRentalFee property).

Submitting the Modification⚓︎

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

    modify_hash = facade.hash_transaction(modify_tx)
    print(f'Transaction hash: {modify_hash}')

    # Announce transaction
    print('Announcing mosaic modification to /transactions')
    request = urllib.request.Request(
        f'{NODE_URL}/transactions',
        data=json_payload.encode(),
        headers={'Content-Type': 'application/json'},
        method='PUT'
    )
    with urllib.request.urlopen(request) as response:
        print(f'  Response: {response.read().decode()}')
    // Sign and generate final payload
    const signature = facade.signTransaction(
        signerKeyPair, modifyTx);
    const jsonPayload =
        facade.transactionFactory.static.attachSignature(
            modifyTx, signature);
    console.log('Built mosaic modification transaction:');
    console.dir(modifyTx.toJson(), { colors: true });

    const modifyHash =
        facade.hashTransaction(modifyTx).toString();
    console.log('Transaction hash:', modifyHash);

    // Announce transaction
    console.log(
        'Announcing mosaic modification to /transactions');
    const announceResponse = await fetch(
        `${NODE_URL}/transactions`, {
            method: 'PUT',
            headers: { 'Content-Type': 'application/json' },
            body: jsonPayload
        });
    console.log('  Response:', await announceResponse.text());

The modification transaction is signed and announced following the same process as in Creating a Transfer Transaction.

    # Wait for confirmation
    print('Waiting for mosaic modification confirmation...')
    for attempt in range(60):
        time.sleep(1)
        try:
            status_url = (
                f'{NODE_URL}/transactionStatus/{modify_hash}')
            with urllib.request.urlopen(status_url) as response:
                status = json.loads(response.read().decode())
                print(f'  Transaction status: {status["group"]}')
            if status['group'] == 'confirmed':
                print('Mosaic modification confirmed in',
                    attempt, 'seconds')
                break
            if status['group'] == 'failed':
                raise Exception(
                    'Mosaic modification failed:', status['code'])
        except urllib.error.HTTPError:
            print('  Transaction status: unknown')
    // Wait for confirmation
    console.log('Waiting for mosaic modification confirmation...');
    for (let attempt = 0; attempt < 60; attempt++) {
        await new Promise(resolve => setTimeout(resolve, 1000));

        try {
            const statusUrl =
                `${NODE_URL}/transactionStatus/${modifyHash}`;
            const statusResponse = await fetch(statusUrl);

            if (!statusResponse.ok) {
                console.log('  Transaction status: unknown');
                continue;
            }

            const status = await statusResponse.json();
            console.log('  Transaction status:', status.group);

            if (status.group === 'confirmed') {
                console.log('Mosaic modification confirmed in',
                    attempt, 'seconds');
                break;
            }

            if (status.group === 'failed') {
                throw new Error(
                    `Mosaic modification failed: ${status.code}`);
            }
        } catch (error) {
            if (error.message.includes('failed:')) {
                throw error;
            }
            console.log('  Transaction status: unknown');
        }
    }

The code then waits for the transaction to be confirmed by polling the /transactionStatus/{hash} GET endpoint until the status changes to confirmed.

Retrieving the Mosaic⚓︎

    # Retrieve the mosaic
    mosaic_id_hex = f'{mosaic_id:x}'
    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'  Divisibility: {mosaic_info["divisibility"]}')
        print(f'  Flags: {mosaic_info["flags"]}')
        print(f'  Duration: {mosaic_info["duration"]}')
    // Retrieve the mosaic
    const mosaicIdHex = mosaicId.toString(16);
    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('  Divisibility:', mosaicInfo.divisibility);
    console.log('  Flags:', mosaicInfo.flags);
    console.log('  Duration:', mosaicInfo.duration);

To verify the modification was applied, the code retrieves the mosaic from the network using the /mosaics/{mosaicId} GET endpoint and displays its updated properties.

A successful response confirms the mosaic now has the expected flags value.

Output⚓︎

The output shown below corresponds to a typical run of the program.

Using node https://reference.symboltest.net:3001
Signer address: TCHBDENCLKEBILBPWP3JPB2XNY64OE7PYHHE32I
Fetching current network time from /node/time
  Network time: 103748303591 ms since nemesis
Fetching recommended fees from /network/fees/transaction
  Fee multiplier: 100
Mosaic nonce: 1770998662
Mosaic ID: 6619508144549180335 (0x5bdd3795f7a8b3af)
Built mosaic modification transaction:
{
  "signature": "729A40BAD69DA8B3CE38D442CFCD1258CA41B7933CF80EFE24A7A354773E0B08D7E2796DED2D93A5F1C16A5EB3298A2113601348A436A4340BFFC38BD7EEBF07",
  "signer_public_key": "3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29",
  "version": 1,
  "network": 152,
  "type": 16717,
  "fee": "15000",
  "deadline": "103755503591",
  "id": "6619508144549180335",
  "duration": "0",
  "nonce": 1770998662,
  "flags": 8,
  "divisibility": 0
}
Transaction hash: 110D3B362D76020EBCD96A5A2E7C621ADE53D98BFACEEE273DA224D8E8B07225
Announcing mosaic modification to /transactions
  Response: {"message":"packet 9 was pushed to the network via /transactions"}
Waiting for mosaic modification confirmation...
  Transaction status: unconfirmed
  Transaction status: unconfirmed
  Transaction status: confirmed
Mosaic modification confirmed in 11 seconds
Fetching mosaic information from /mosaics/5bdd3795f7a8b3af
Mosaic information:
  Mosaic ID: 5BDD3795F7A8B3AF
  Supply: 0
  Divisibility: 2
  Flags: 14
  Duration: 0

Some highlights from the output:

  • Mosaic nonce (line 7): The nonce 1770998662 matches the nonce used when the mosaic was created, targeting the same mosaic for modification.

  • Mosaic ID (line 8): The mosaic ID 0x5bdd3795f7a8b3af is derived from the nonce and signer address, confirming the correct mosaic is being modified.

  • Transaction properties (lines 19, 21-22): The modification sets duration to 0 (no change), flags to 8 (revokable), and divisibility to 0 (no change).

  • Updated properties (lines 36-38): The mosaic's divisibility remains 2 (unchanged by XOR with 0). The flags are now 14, which corresponds to transferable (2) + restrictable (4) + revokable (8). The duration remains 0 (eternal, unchanged).

The transaction hash printed in the output can be used to search for the transaction in the Symbol Testnet Explorer.

Conclusion⚓︎

This tutorial showed how to:

Step Related documentation
Generate mosaic ID
Modify mosaic flags
Verify the updated mosaic /mosaics/{mosaicId} GET