Skip to content

Querying Currency Supply⚓︎

Exchanges and market data aggregators need accurate supply figures to display market capitalization and token metrics.

The Symbol network exposes the maximum, total, and circulating supply of XYM, the native currency, through dedicated REST endpoints.

This tutorial shows how to query each value and derive additional metrics from them.

Prerequisites⚓︎

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

Full Code⚓︎

import os
import urllib.request

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

SUPPLY_PATH = '/network/currency/supply'

try:
    with urllib.request.urlopen(
            f'{NODE_URL}{SUPPLY_PATH}/max') as response:
        maximum = float(response.read().decode().strip())
    print(f'Maximum supply: {maximum:,.6f} XYM')

    with urllib.request.urlopen(
            f'{NODE_URL}{SUPPLY_PATH}/total') as response:
        total = float(response.read().decode().strip())
    print(f'Total supply: {total:,.6f} XYM')

    with urllib.request.urlopen(
            f'{NODE_URL}{SUPPLY_PATH}/circulating') as response:
        circulating = float(response.read().decode().strip())
    print(f'Circulating supply: {circulating:,.6f} XYM')

    non_circulating = total - circulating
    print(f'Non-circulating: {non_circulating:,.6f} XYM')

    unminted = maximum - total
    print(f'Unminted: {unminted:,.6f} XYM')

except Exception as error:
    print(error)

Download source

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

const SUPPLY_PATH = '/network/currency/supply';

const fmt = (v) => v.toLocaleString('en-US', { minimumFractionDigits: 6 });

const maxResponse = await fetch(`${NODE_URL}${SUPPLY_PATH}/max`);
const maximum = parseFloat((await maxResponse.text()).trim());
console.log(`Maximum supply: ${fmt(maximum)} XYM`);

const totalResponse = await fetch(`${NODE_URL}${SUPPLY_PATH}/total`);
const total = parseFloat((await totalResponse.text()).trim());
console.log(`Total supply: ${fmt(total)} XYM`);

const circResponse = await fetch(`${NODE_URL}${SUPPLY_PATH}/circulating`);
const circulating = parseFloat((await circResponse.text()).trim());
console.log(`Circulating supply: ${fmt(circulating)} XYM`);

const nonCirculating = total - circulating;
console.log(`Non-circulating: ${fmt(nonCirculating)} XYM`);

const unminted = maximum - total;
console.log(`Unminted: ${fmt(unminted)} XYM`);

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.

Using a mainnet node

The default node points to testnet. For production supply data, set NODE_URL to a mainnet node. For a list of available mainnet nodes, see symbol.fyi/nodes.

Code Explanation⚓︎

Fetching Supply Values⚓︎

    with urllib.request.urlopen(
            f'{NODE_URL}{SUPPLY_PATH}/max') as response:
        maximum = float(response.read().decode().strip())
    print(f'Maximum supply: {maximum:,.6f} XYM')

    with urllib.request.urlopen(
            f'{NODE_URL}{SUPPLY_PATH}/total') as response:
        total = float(response.read().decode().strip())
    print(f'Total supply: {total:,.6f} XYM')

    with urllib.request.urlopen(
            f'{NODE_URL}{SUPPLY_PATH}/circulating') as response:
        circulating = float(response.read().decode().strip())
    print(f'Circulating supply: {circulating:,.6f} XYM')
const fmt = (v) => v.toLocaleString('en-US', { minimumFractionDigits: 6 });

const maxResponse = await fetch(`${NODE_URL}${SUPPLY_PATH}/max`);
const maximum = parseFloat((await maxResponse.text()).trim());
console.log(`Maximum supply: ${fmt(maximum)} XYM`);

const totalResponse = await fetch(`${NODE_URL}${SUPPLY_PATH}/total`);
const total = parseFloat((await totalResponse.text()).trim());
console.log(`Total supply: ${fmt(total)} XYM`);

const circResponse = await fetch(`${NODE_URL}${SUPPLY_PATH}/circulating`);
const circulating = parseFloat((await circResponse.text()).trim());
console.log(`Circulating supply: ${fmt(circulating)} XYM`);

Each supply value is available through a dedicated endpoint:

All three endpoints return a plain-text number (not JSON), already expressed in whole units with decimal places (e.g. 8999999999.000000), not in atomic units.

Circulating supply is node-dependent

The list of non-circulating accounts is configured by each node operator (in the node's rest.json file), so different nodes could report different circulating supply values. If you are integrating supply data, ensure you query a trusted node with the default configuration.

Deriving Additional Metrics⚓︎

    non_circulating = total - circulating
    print(f'Non-circulating: {non_circulating:,.6f} XYM')

    unminted = maximum - total
    print(f'Unminted: {unminted:,.6f} XYM')
const nonCirculating = total - circulating;
console.log(`Non-circulating: ${fmt(nonCirculating)} XYM`);

const unminted = maximum - total;
console.log(`Unminted: ${fmt(unminted)} XYM`);

After fetching all three values, the code derives two additional metrics:

  • Non-circulating: The difference between total and circulating supply.
  • Unminted: The difference between maximum and total supply, representing the XYM that remains to be minted.

Output⚓︎

The following output shows a typical run querying the currency supply:

Using node https://reference.symboltest.net:3001
Maximum supply: 8,999,999,999.000000 XYM
Total supply: 8,323,505,878.695894 XYM
Circulating supply: 8,323,495,854.693871 XYM
Non-circulating: 10,024.002024 XYM
Unminted: 676,494,120.304106 XYM

These values come from a testnet node and do not reflect mainnet supply figures.

The output shows the full breakdown of the XYM supply:

  • The maximum supply is the hard cap for XYM.
  • The total supply is lower, because not all XYM has been minted yet.
  • The circulating supply is lower still, because some minted XYM is held by non-circulating accounts.
  • The non-circulating value accounts for the difference between total and circulating supply.
  • The unminted value shows the remaining XYM that will be gradually minted through inflation rewards.

Conclusion⚓︎

This tutorial showed how to:

Step Related documentation
Fetch maximum supply /network/currency/supply/max GET
Fetch total supply /network/currency/supply/total GET
Fetch circulating supply /network/currency/supply/circulating GET
Derive additional metrics -

Next steps⚓︎

To check a specific account's XYM balance, see the Query Account Balance tutorial.