Skip to content

Getting Mosaic Information⚓︎

Every mosaic on Symbol has a set of on-chain properties such as supply, divisibility, and behavior flags.

This tutorial shows how to retrieve a mosaic's properties and any namespace aliases linked to it.

Prerequisites⚓︎

This tutorial only reads data from the network. No account is required.

Before you start, make sure to set up your development environment.

Full Code⚓︎

import json
import os
import urllib.request

from symbolchain.sc import MosaicFlags

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

MOSAIC_ID = os.getenv('MOSAIC_ID', '72C0212E67A08BCE')
print(f'Mosaic ID: {MOSAIC_ID}')

try:
    # Fetch mosaic information
    mosaic_path = f'/mosaics/{MOSAIC_ID}'
    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 = response_json['mosaic']
        print('Mosaic information:')
        print(f'  Mosaic ID: {mosaic["id"]}')
        print(f'  Supply: {mosaic["supply"]}')
        divisibility = mosaic['divisibility']
        print(f'  Divisibility: {divisibility}')
        flags = MosaicFlags(mosaic['flags'])
        print(f'  Flags: {flags.value} ({flags.name.lower()})')
        print(f'  Duration: {mosaic["duration"]}')
        print(f'  Start height: {mosaic["startHeight"]}')
        print(f'  Revision: {mosaic["revision"]}')

    # Display formatted supply
    supply = int(mosaic['supply'])
    whole = supply // (10 ** divisibility)
    fractional = supply % (10 ** divisibility)
    formatted = f'{whole}.{fractional:0{divisibility}d}'
    print(f'\nSupply in whole units: {formatted}')

    # Fetch namespace names linked to the mosaic
    print(f'\nFetching namespace names for mosaic {MOSAIC_ID}')
    request_body = json.dumps({'mosaicIds': [MOSAIC_ID]}).encode()
    request = urllib.request.Request(
        f'{NODE_URL}/namespaces/mosaic/names',
        data=request_body,
        headers={'Content-Type': 'application/json'}
    )
    with urllib.request.urlopen(request) as response:
        names_info = json.loads(response.read().decode())
        for entry in names_info['mosaicNames']:
            names = entry['names']
            if names:
                print(f'  Namespace aliases: {", ".join(names)}')
            else:
                print('  No namespace aliases linked')

except Exception as e:
    print(e)

Download source

import { models } from 'symbol-sdk/symbol';

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

const MOSAIC_ID = process.env.MOSAIC_ID || '72C0212E67A08BCE';
console.log('Mosaic ID:', MOSAIC_ID);

try {
    // Fetch mosaic information
    const mosaicPath = `/mosaics/${MOSAIC_ID}`;
    console.log('Fetching mosaic information from', mosaicPath);
    const mosaicResponse = await fetch(`${NODE_URL}${mosaicPath}`);
    if (!mosaicResponse.ok) {
        throw new Error(
            `HTTP error! status: ${mosaicResponse.status}`);
    }
    const mosaicJSON = await mosaicResponse.json();
    const mosaic = mosaicJSON.mosaic;
    console.log('Mosaic information:');
    console.log('  Mosaic ID:', mosaic.id);
    console.log('  Supply:', mosaic.supply);
    const divisibility = mosaic.divisibility;
    console.log('  Divisibility:', divisibility);
    const flags = new models.MosaicFlags(mosaic.flags);
    const flagNames = flags.toString()
        .replace(/MosaicFlags\./g, '').toLowerCase();
    console.log(`  Flags: ${mosaic.flags} (${flagNames})`);
    console.log('  Duration:', mosaic.duration);
    console.log('  Start height:', mosaic.startHeight);
    console.log('  Revision:', mosaic.revision);

    // Display formatted supply
    const supply = BigInt(mosaic.supply);
    const divisor = 10n ** BigInt(divisibility);
    const whole = supply / divisor;
    const fractional = supply % divisor;
    const fractionalStr = fractional.toString()
        .padStart(divisibility, '0');
    console.log(`\nSupply in whole units: ${whole}.${fractionalStr}`);

    // Fetch namespace names linked to the mosaic
    console.log(`\nFetching namespace names for mosaic ${MOSAIC_ID}`);
    const namesResponse = await fetch(
        `${NODE_URL}/namespaces/mosaic/names`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ mosaicIds: [MOSAIC_ID] })
        });
    const namesInfo = await namesResponse.json();
    for (const entry of namesInfo.mosaicNames) {
        if (entry.names.length > 0) {
            console.log('  Namespace aliases:', entry.names.join(', '));
        } else {
            console.log('  No namespace aliases linked');
        }
    }
} catch (e) {
    console.error(e.message);
}

Download source

The snippet uses the NODE_URL environment variable to set the Symbol API node. If no value is provided, a default testnet node is used.

The MOSAIC_ID environment variable specifies which mosaic to query. If not set, it defaults to the XYM mosaic ID on testnet (72C0212E67A08BCE).

Code Explanation⚓︎

Fetching Mosaic Information⚓︎

    # Fetch mosaic information
    mosaic_path = f'/mosaics/{MOSAIC_ID}'
    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 = response_json['mosaic']
        print('Mosaic information:')
        print(f'  Mosaic ID: {mosaic["id"]}')
        print(f'  Supply: {mosaic["supply"]}')
        divisibility = mosaic['divisibility']
        print(f'  Divisibility: {divisibility}')
        flags = MosaicFlags(mosaic['flags'])
        print(f'  Flags: {flags.value} ({flags.name.lower()})')
        print(f'  Duration: {mosaic["duration"]}')
        print(f'  Start height: {mosaic["startHeight"]}')
        print(f'  Revision: {mosaic["revision"]}')
    // Fetch mosaic information
    const mosaicPath = `/mosaics/${MOSAIC_ID}`;
    console.log('Fetching mosaic information from', mosaicPath);
    const mosaicResponse = await fetch(`${NODE_URL}${mosaicPath}`);
    if (!mosaicResponse.ok) {
        throw new Error(
            `HTTP error! status: ${mosaicResponse.status}`);
    }
    const mosaicJSON = await mosaicResponse.json();
    const mosaic = mosaicJSON.mosaic;
    console.log('Mosaic information:');
    console.log('  Mosaic ID:', mosaic.id);
    console.log('  Supply:', mosaic.supply);
    const divisibility = mosaic.divisibility;
    console.log('  Divisibility:', divisibility);
    const flags = new models.MosaicFlags(mosaic.flags);
    const flagNames = flags.toString()
        .replace(/MosaicFlags\./g, '').toLowerCase();
    console.log(`  Flags: ${mosaic.flags} (${flagNames})`);
    console.log('  Duration:', mosaic.duration);
    console.log('  Start height:', mosaic.startHeight);
    console.log('  Revision:', mosaic.revision);

The /mosaics/{mosaicId} GET endpoint retrieves the current properties of a mosaic, including:

  • Supply: The total number of atomic units currently in circulation. Do not confuse with the initial supply.
  • Divisibility: The number of decimal places the mosaic supports. For example, XYM has a divisibility of 6, meaning 1 XYM equals 1,000,000 atomic units.
  • Flags: A bitmask encoding the mosaic's behavior restrictions. Each flag occupies a single bit: supply_mutable (1), transferable (2), restrictable (4), and revokable (8). Multiple flags combine additively. For example, a value of 6 means transferable (2) + restrictable (4).
  • Duration: The number of blocks the mosaic remains active. A value of 0 means the mosaic never expires.
  • Start height: The block height at which the mosaic was created.
  • Revision: Incremented each time the mosaic definition is modified.

Formatting the Supply⚓︎

    # Display formatted supply
    supply = int(mosaic['supply'])
    whole = supply // (10 ** divisibility)
    fractional = supply % (10 ** divisibility)
    formatted = f'{whole}.{fractional:0{divisibility}d}'
    print(f'\nSupply in whole units: {formatted}')
    // Display formatted supply
    const supply = BigInt(mosaic.supply);
    const divisor = 10n ** BigInt(divisibility);
    const whole = supply / divisor;
    const fractional = supply % divisor;
    const fractionalStr = fractional.toString()
        .padStart(divisibility, '0');
    console.log(`\nSupply in whole units: ${whole}.${fractionalStr}`);

The supply value returned by the API is expressed in atomic units. To convert it to whole units, the code divides the supply into whole and fractional parts using the mosaic's divisibility.

For XYM (divisibility 6), a supply of 8325447775994408 atomic units equals 8325447775.994408 whole units.

Fetching Namespace Aliases⚓︎

    # Fetch namespace names linked to the mosaic
    print(f'\nFetching namespace names for mosaic {MOSAIC_ID}')
    request_body = json.dumps({'mosaicIds': [MOSAIC_ID]}).encode()
    request = urllib.request.Request(
        f'{NODE_URL}/namespaces/mosaic/names',
        data=request_body,
        headers={'Content-Type': 'application/json'}
    )
    with urllib.request.urlopen(request) as response:
        names_info = json.loads(response.read().decode())
        for entry in names_info['mosaicNames']:
            names = entry['names']
            if names:
                print(f'  Namespace aliases: {", ".join(names)}')
            else:
                print('  No namespace aliases linked')
    // Fetch namespace names linked to the mosaic
    console.log(`\nFetching namespace names for mosaic ${MOSAIC_ID}`);
    const namesResponse = await fetch(
        `${NODE_URL}/namespaces/mosaic/names`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ mosaicIds: [MOSAIC_ID] })
        });
    const namesInfo = await namesResponse.json();
    for (const entry of namesInfo.mosaicNames) {
        if (entry.names.length > 0) {
            console.log('  Namespace aliases:', entry.names.join(', '));
        } else {
            console.log('  No namespace aliases linked');
        }
    }

Mosaics can be linked to human-readable namespace aliases. The /namespaces/mosaic/names POST endpoint accepts mosaic IDs and returns any namespace names currently linked to them.

A mosaic can have multiple namespace aliases if different namespaces link to the same mosaic. If no namespace is linked, the response indicates that no aliases exist.

Output⚓︎

The output shown below corresponds to a typical run of the program, querying the XYM mosaic on testnet.

Using node https://reference.symboltest.net:3001
Mosaic ID: 72C0212E67A08BCE
Fetching mosaic information from /mosaics/72C0212E67A08BCE
Mosaic information:
  Mosaic ID: 72C0212E67A08BCE
  Supply: 8325492939035652
  Divisibility: 6
  Flags: 2 (transferable)
  Duration: 0
  Start height: 1
  Revision: 1

Supply in whole units: 8325492939.035652

Fetching namespace names for mosaic 72C0212E67A08BCE
  Namespace aliases: symbol.xym

Some highlights from the output:

  • Mosaic ID (line 5): The XYM mosaic identifier on testnet (72C0212E67A08BCE).

  • Supply (line 6): The total supply in atomic units.

  • Divisibility (line 7): The value 6 means 1 XYM = 1,000,000 (106) atomic units.

  • Flags (line 8): The value 2 resolves to transferable, meaning XYM can be freely sent between accounts.

  • Duration (line 9): The value 0 means XYM never expires.

  • Supply in whole units (line 13): The supply converted from atomic units to whole units using the mosaic's divisibility.

  • Namespace alias (line 16): The mosaic is linked to the symbol.xym namespace.

Conclusion⚓︎

This tutorial showed how to:

Step Related documentation
Fetch mosaic properties /mosaics/{mosaicId} GET
Fetch namespace aliases /namespaces/mosaic/names POST

Next Steps⚓︎