Skip to content

Querying an Account Balance⚓︎

BEGINNER

Accounts on NEM can hold mosaics (fungible tokens), including the native currency XEM.

This tutorial shows how to query an account's mosaic balances and display NEM's whole-number atomic amounts in decimal form.

Prerequisites⚓︎

This tutorial uses the NEM REST API without requiring an SDK. You only need a way to make HTTP requests.

Full Code⚓︎

import json
import os
import urllib.request

NODE_URL = os.getenv('NODE_URL', 'http://libertalia.nemtest.net:7890')
print(f'Using node {NODE_URL}')


def get_mosaic_balances(address):
    """
    Fetch all mosaic balances owned by an account.

    Args:
        address: The account address

    Returns:
        List of mosaics, each with a structured mosaicId and quantity
    """
    balances_path = f'/account/mosaic/owned?address={address}'
    with urllib.request.urlopen(f'{NODE_URL}{balances_path}') as response:
        balances_info = json.loads(response.read().decode())
        return balances_info['data']


def get_mosaic_definitions(address):
    """
    Fetch mosaic definitions for every mosaic owned by an account.

    Args:
        address: The account address

    Returns:
        Dictionary mapping "namespace:name" to the mosaic definition
    """
    definitions_path = '/account/mosaic/owned/definition'
    with urllib.request.urlopen(
        f'{NODE_URL}{definitions_path}?address={address}'
    ) as response:
        definitions_info = json.loads(response.read().decode())
        # Build a dictionary mapping "namespace:name" to its definition
        definitions_map = {}
        for entry in definitions_info['data']:
            entry_id = entry['id']
            entry_key = f'{entry_id["namespaceId"]}:{entry_id["name"]}'
            definitions_map[entry_key] = entry
        return definitions_map


def format_amount(amount, divisibility):
    """
    Format an atomic amount with decimal places.

    Args:
        amount: The atomic amount as an integer
        divisibility: Number of decimal places

    Returns:
        Formatted amount as a string
    """
    if divisibility == 0:
        return str(amount)
    whole_part = amount // (10 ** divisibility)
    fractional_part = amount % (10 ** divisibility)
    return f'{whole_part}.{fractional_part:0{divisibility}d}'


# The account address to query
ADDRESS = os.getenv('ADDRESS', 'TBONKWCOWBZYZB2I5JD3LSDBQVBYHB757VN3SKPP')
print(f'Fetching balances for {ADDRESS}')

try:
    # Fetch mosaic balances and definitions for the account
    account_mosaics = get_mosaic_balances(ADDRESS)
    mosaic_definitions = get_mosaic_definitions(ADDRESS)

    if not account_mosaics:
        print('Account holds no mosaics')
    else:
        print(f'Account holds {len(account_mosaics)} mosaic(s):')

        for mosaic_entry in account_mosaics:
            mosaic_id = mosaic_entry['mosaicId']
            key = f'{mosaic_id["namespaceId"]}:{mosaic_id["name"]}'
            balance = int(mosaic_entry['quantity'])

            # Get mosaic divisibility from the definition
            definition = mosaic_definitions[key]
            properties = {
                p['name']: p['value']
                for p in definition['properties']
            }
            mosaic_divisibility = int(
                properties.get('divisibility', '0'))

            # Format and display the balance
            formatted_balance = format_amount(
                balance, mosaic_divisibility)
            print(f'- Mosaic {key}')
            print(f'  Balance: {formatted_balance}')
            print(f'  Balance (atomic): {balance}')
            print(f'  Divisibility: {mosaic_divisibility}')
except urllib.error.URLError as e:
    print(e.reason)

Download source

const NODE_URL = process.env.NODE_URL ||
    'http://libertalia.nemtest.net:7890';
console.log('Using node', NODE_URL);


/**
 * Fetch all mosaic balances owned by an account.
 * @param {string} address - Account address
 * @returns {Promise<object[]>} List of mosaics with id and quantity
 */
async function getMosaicBalances(address) {
    const path = `/account/mosaic/owned?address=${address}`;
    const response = await fetch(`${NODE_URL}${path}`);
    const info = await response.json();
    return info.data;
}

/**
 * Fetch mosaic definitions for every mosaic owned by an account.
 * @param {string} address - Account address
 * @returns {Promise<Map>} Map of "namespace:name" to mosaic definition
 */
async function getMosaicDefinitions(address) {
    const path = `/account/mosaic/owned/definition?address=${address}`;
    const response = await fetch(`${NODE_URL}${path}`);
    const info = await response.json();
    // Build a map from "namespace:name" to mosaic definition
    const definitionsMap = new Map();
    for (const entry of info.data) {
        const key = `${entry.id.namespaceId}:${entry.id.name}`;
        definitionsMap.set(key, entry);
    }
    return definitionsMap;
}

/**
 * Format an atomic amount with decimal places.
 * @param {bigint} amount - The atomic amount
 * @param {number} divisibility - Number of decimal places
 * @returns {string} The formatted amount
 */
function formatAmount(amount, divisibility) {
    if (0 === divisibility)
        return amount.toString();

    const divisor = 10n ** BigInt(divisibility);
    const wholePart = amount / divisor;
    const fractionalPart = amount % divisor;
    const fractionalStr = fractionalPart.toString()
        .padStart(divisibility, '0');
    return `${wholePart}.${fractionalStr}`;
}

// The account address to query
const ADDRESS = process.env.ADDRESS ||
    'TBONKWCOWBZYZB2I5JD3LSDBQVBYHB757VN3SKPP';
console.log('Fetching balances for', ADDRESS);

try {
    // Fetch mosaic balances and definitions for the account
    const accountMosaics = await getMosaicBalances(ADDRESS);
    const mosaicDefinitions = await getMosaicDefinitions(ADDRESS);

    if (0 === accountMosaics.length) {
        console.log('Account holds no mosaics');
    } else {
        console.log(`Account holds ${accountMosaics.length} mosaic(s):`);

        for (const mosaicEntry of accountMosaics) {
            const { mosaicId } = mosaicEntry;
            const key = `${mosaicId.namespaceId}:${mosaicId.name}`;
            const balance = BigInt(mosaicEntry.quantity);

            // Get mosaic divisibility from the definition
            const definition = mosaicDefinitions.get(key);
            const properties = Object.fromEntries(
                definition.properties.map(p => [p.name, p.value])
            );
            const divisibility = parseInt(
                properties.divisibility || '0', 10);

            // Format and display the balance
            const formattedBalance = formatAmount(balance, divisibility);
            console.log(`- Mosaic ${key}`);
            console.log(`  Balance: ${formattedBalance}`);
            console.log(`  Balance (atomic): ${balance.toString()}`);
            console.log(`  Divisibility: ${divisibility}`);
        }
    }
} catch (e) {
    console.error(e.message, '| Cause:', e.cause?.code ?? 'unknown');
}

Download source

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

The tutorial defines the following functions:

  • : Fetches all mosaics owned by an account.
  • : Fetches mosaic definitions, including divisibility.
  • : Formats amounts with the appropriate number of decimal places, according to their divisibility.

Code Explanation⚓︎

Fetching Mosaic Balances⚓︎

def get_mosaic_balances(address):
    """
    Fetch all mosaic balances owned by an account.

    Args:
        address: The account address

    Returns:
        List of mosaics, each with a structured mosaicId and quantity
    """
    balances_path = f'/account/mosaic/owned?address={address}'
    with urllib.request.urlopen(f'{NODE_URL}{balances_path}') as response:
        balances_info = json.loads(response.read().decode())
        return balances_info['data']
/**
 * Fetch all mosaic balances owned by an account.
 * @param {string} address - Account address
 * @returns {Promise<object[]>} List of mosaics with id and quantity
 */
async function getMosaicBalances(address) {
    const path = `/account/mosaic/owned?address=${address}`;
    const response = await fetch(`${NODE_URL}${path}`);
    const info = await response.json();
    return info.data;
}

The /account/mosaic/owned GET endpoint returns every mosaic the account holds, together with its quantity in atomic units.

Fetching Mosaic Definitions⚓︎

def get_mosaic_definitions(address):
    """
    Fetch mosaic definitions for every mosaic owned by an account.

    Args:
        address: The account address

    Returns:
        Dictionary mapping "namespace:name" to the mosaic definition
    """
    definitions_path = '/account/mosaic/owned/definition'
    with urllib.request.urlopen(
        f'{NODE_URL}{definitions_path}?address={address}'
    ) as response:
        definitions_info = json.loads(response.read().decode())
        # Build a dictionary mapping "namespace:name" to its definition
        definitions_map = {}
        for entry in definitions_info['data']:
            entry_id = entry['id']
            entry_key = f'{entry_id["namespaceId"]}:{entry_id["name"]}'
            definitions_map[entry_key] = entry
        return definitions_map
/**
 * Fetch mosaic definitions for every mosaic owned by an account.
 * @param {string} address - Account address
 * @returns {Promise<Map>} Map of "namespace:name" to mosaic definition
 */
async function getMosaicDefinitions(address) {
    const path = `/account/mosaic/owned/definition?address=${address}`;
    const response = await fetch(`${NODE_URL}${path}`);
    const info = await response.json();
    // Build a map from "namespace:name" to mosaic definition
    const definitionsMap = new Map();
    for (const entry of info.data) {
        const key = `${entry.id.namespaceId}:${entry.id.name}`;
        definitionsMap.set(key, entry);
    }
    return definitionsMap;
}

To format mosaic balances correctly, the snippet fetches their definitions from the network. The key property required is divisibility, which defines how many decimal places a mosaic supports.

The /account/mosaic/owned/definition GET endpoint returns the definition for every mosaic owned by the account in a single request, including divisibility and other properties.

Formatting Amounts⚓︎

def format_amount(amount, divisibility):
    """
    Format an atomic amount with decimal places.

    Args:
        amount: The atomic amount as an integer
        divisibility: Number of decimal places

    Returns:
        Formatted amount as a string
    """
    if divisibility == 0:
        return str(amount)
    whole_part = amount // (10 ** divisibility)
    fractional_part = amount % (10 ** divisibility)
    return f'{whole_part}.{fractional_part:0{divisibility}d}'
/**
 * Format an atomic amount with decimal places.
 * @param {bigint} amount - The atomic amount
 * @param {number} divisibility - Number of decimal places
 * @returns {string} The formatted amount
 */
function formatAmount(amount, divisibility) {
    if (0 === divisibility)
        return amount.toString();

    const divisor = 10n ** BigInt(divisibility);
    const wholePart = amount / divisor;
    const fractionalPart = amount % divisor;
    const fractionalStr = fractionalPart.toString()
        .padStart(divisibility, '0');
    return `${wholePart}.${fractionalStr}`;
}

This utility function converts atomic amounts into human-friendly representations:

  • Atomic amount: The raw value stored on the blockchain, expressed as an integer.
  • Formatted amount: The display format with decimal places determined by the mosaic's divisibility.

The formatting splits the atomic amount into whole and fractional parts by dividing and taking the remainder with respect to \(10^{\text{divisibility}}\). The fractional part is then zero-padded to ensure it always displays the correct number of decimal places.

Putting It All Together⚓︎

# The account address to query
ADDRESS = os.getenv('ADDRESS', 'TBONKWCOWBZYZB2I5JD3LSDBQVBYHB757VN3SKPP')
print(f'Fetching balances for {ADDRESS}')

try:
    # Fetch mosaic balances and definitions for the account
    account_mosaics = get_mosaic_balances(ADDRESS)
    mosaic_definitions = get_mosaic_definitions(ADDRESS)

    if not account_mosaics:
        print('Account holds no mosaics')
    else:
        print(f'Account holds {len(account_mosaics)} mosaic(s):')

        for mosaic_entry in account_mosaics:
            mosaic_id = mosaic_entry['mosaicId']
            key = f'{mosaic_id["namespaceId"]}:{mosaic_id["name"]}'
            balance = int(mosaic_entry['quantity'])

            # Get mosaic divisibility from the definition
            definition = mosaic_definitions[key]
            properties = {
                p['name']: p['value']
                for p in definition['properties']
            }
            mosaic_divisibility = int(
                properties.get('divisibility', '0'))

            # Format and display the balance
            formatted_balance = format_amount(
                balance, mosaic_divisibility)
            print(f'- Mosaic {key}')
            print(f'  Balance: {formatted_balance}')
            print(f'  Balance (atomic): {balance}')
            print(f'  Divisibility: {mosaic_divisibility}')
except urllib.error.URLError as e:
    print(e.reason)
// The account address to query
const ADDRESS = process.env.ADDRESS ||
    'TBONKWCOWBZYZB2I5JD3LSDBQVBYHB757VN3SKPP';
console.log('Fetching balances for', ADDRESS);

try {
    // Fetch mosaic balances and definitions for the account
    const accountMosaics = await getMosaicBalances(ADDRESS);
    const mosaicDefinitions = await getMosaicDefinitions(ADDRESS);

    if (0 === accountMosaics.length) {
        console.log('Account holds no mosaics');
    } else {
        console.log(`Account holds ${accountMosaics.length} mosaic(s):`);

        for (const mosaicEntry of accountMosaics) {
            const { mosaicId } = mosaicEntry;
            const key = `${mosaicId.namespaceId}:${mosaicId.name}`;
            const balance = BigInt(mosaicEntry.quantity);

            // Get mosaic divisibility from the definition
            const definition = mosaicDefinitions.get(key);
            const properties = Object.fromEntries(
                definition.properties.map(p => [p.name, p.value])
            );
            const divisibility = parseInt(
                properties.divisibility || '0', 10);

            // Format and display the balance
            const formattedBalance = formatAmount(balance, divisibility);
            console.log(`- Mosaic ${key}`);
            console.log(`  Balance: ${formattedBalance}`);
            console.log(`  Balance (atomic): ${balance.toString()}`);
            console.log(`  Divisibility: ${divisibility}`);
        }
    }
} catch (e) {
    console.error(e.message, '| Cause:', e.cause?.code ?? 'unknown');
}

The main code reads the ADDRESS environment variable to determine which account to query. If no value is provided, it uses a default sample address.

It orchestrates the helper functions to:

  1. Fetch the mosaic balances for the account.
  2. Retrieve the mosaic definitions to determine each mosaic's divisibility.
  3. Iterate through each mosaic and format its balance with the appropriate number of decimal places.

Output⚓︎

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

Using node http://libertalia.nemtest.net:7890
Fetching balances for TBONKWCOWBZYZB2I5JD3LSDBQVBYHB757VN3SKPP
Account holds 2 mosaic(s):
- Mosaic nem:xem
  Balance: 9883.200000
  Balance (atomic): 9883200000
  Divisibility: 6
- Mosaic company:token
  Balance: 1000000
  Balance (atomic): 1000000
  Divisibility: 0

The output displays all mosaics the account holds. Notice how different mosaics have different divisibility values:

  • The first mosaic is nem:xem, the network's native currency, which has divisibility 6 and is therefore displayed with six decimal places (9883.200000).
  • The second mosaic is company:token, a user-defined mosaic with divisibility 0, displayed as an integer (1000000).

Conclusion⚓︎

This tutorial showed how to:

Step Related documentation
Fetch mosaic balances /account/mosaic/owned GET
Fetch mosaic definitions /account/mosaic/owned/definition GET