Skip to content

Changing Mosaic Supply⚓︎

INTERMEDIATE

Mosaics created with a mutable supply can have their total supply increased or decreased after creation.

Only the mosaic creator can change the supply. Supply changes affect only the creator's balance: minted units are added to it, and burned units are removed from it. The balances of all other accounts that hold the mosaic remain unchanged.

This tutorial shows how to change a mosaic's supply by minting and burning units.

Prerequisites⚓︎

Before you start, make sure to:

Full Code⚓︎

import json
import os
import time
import urllib.request

from symbolchain.CryptoTypes import PrivateKey
from symbolchain.facade.NemFacade import NemFacade
from symbolchain.nc import Amount
from symbolchain.nem.FeeCalculator import calculate_transaction_fee
from symbolchain.nem.Network import NetworkTimestamp

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


# Helper function to announce a transaction
def announce_transaction(payload, label):
    announce_path = '/transaction/announce'
    print(f'Announcing {label} to {announce_path}')
    request = urllib.request.Request(
        f'{NODE_URL}{announce_path}',
        data=payload.encode(),
        headers={'Content-Type': 'application/json'},
        method='POST'
    )
    with urllib.request.urlopen(request) as announce_response:
        result = json.loads(announce_response.read().decode())
    print(f'  Result: {result["message"]}')
    return result['message']


# Helper function to fetch the current mosaic supply
def fetch_supply(mosaic):
    supply_path = f'/mosaic/supply?mosaicId={mosaic}'
    with urllib.request.urlopen(
        f'{NODE_URL}{supply_path}'
    ) as supply_response:
        supply_info = json.loads(supply_response.read().decode())
    return supply_info['supply']


# Helper function to wait for transaction confirmation
def wait_for_confirmation(tx_hash, label):
    status_path = f'/transaction/get?hash={tx_hash}'
    print(f'Waiting for {label} confirmation from {status_path}')
    is_confirmed = False
    for _ in range(120):
        try:
            with urllib.request.urlopen(
                f'{NODE_URL}{status_path}'
            ) as status_response:
                confirmed = json.loads(status_response.read().decode())
                height = confirmed['meta']['height']
                print(f'{label} confirmed in block {height}')
                is_confirmed = True
                break
        except urllib.error.HTTPError:
            print('  Transaction status: pending')
        time.sleep(1)
    if not is_confirmed:
        print(f'{label} confirmation took too long.')


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

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

namespace_name = os.getenv('NAMESPACE', 'my_namespace')
mosaic_name = os.getenv('MOSAIC', 'token')
mosaic_id = f'{namespace_name}:{mosaic_name}'
print(f'Mosaic ID: {mosaic_id}')

try:
    # Fetch current network time
    time_path = '/time-sync/network-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())
        network_time = response_json['receiveTimeStamp'] // 1000
        print(f'  Network time: {network_time} s since the nemesis block')

    # Derived fields from network time
    timestamp = NetworkTimestamp(network_time)
    deadline = timestamp.add_hours(2)

    # --- INCREASING SUPPLY (MINTING) ---
    print('\n--- Increasing supply (minting) ---')

    print(f'Supply before minting: {fetch_supply(mosaic_id)}')

    increase_tx = facade.transaction_factory.create({
        'type': 'mosaic_supply_change_transaction_v1',
        'signer_public_key': signer_key_pair.public_key,
        'timestamp': timestamp.timestamp,
        'deadline': deadline.timestamp,
        'mosaic_id': {
            'namespace_id': {'name': namespace_name},
            'name': mosaic_name
        },
        'action': 'increase',
        'delta': 500
    })
    increase_tx.fee = Amount(calculate_transaction_fee(increase_tx))

    signature = facade.sign_transaction(signer_key_pair, increase_tx)
    json_payload = facade.transaction_factory.attach_signature(
        increase_tx, signature)
    print('Built supply increase transaction:')
    print(json.dumps(increase_tx.to_json(), indent=2))
    if 'SUCCESS' == announce_transaction(json_payload, 'supply increase'):
        wait_for_confirmation(
            facade.hash_transaction(increase_tx), 'supply increase')
        print(f'Supply after minting: {fetch_supply(mosaic_id)}')
    else:
        print('Supply increase rejected')

    # --- DECREASING SUPPLY (BURNING) ---
    print('\n--- Decreasing supply (burning) ---')

    decrease_tx = facade.transaction_factory.create({
        'type': 'mosaic_supply_change_transaction_v1',
        'signer_public_key': signer_key_pair.public_key,
        'timestamp': timestamp.timestamp,
        'deadline': deadline.timestamp,
        'mosaic_id': {
            'namespace_id': {'name': namespace_name},
            'name': mosaic_name
        },
        'action': 'decrease',
        'delta': 500
    })
    decrease_tx.fee = Amount(calculate_transaction_fee(decrease_tx))

    signature = facade.sign_transaction(signer_key_pair, decrease_tx)
    json_payload = facade.transaction_factory.attach_signature(
        decrease_tx, signature)
    print('Built supply decrease transaction:')
    print(json.dumps(decrease_tx.to_json(), indent=2))
    if 'SUCCESS' == announce_transaction(json_payload, 'supply decrease'):
        wait_for_confirmation(
            facade.hash_transaction(decrease_tx), 'supply decrease')
        print(f'Supply after burning: {fetch_supply(mosaic_id)}')
    else:
        print('Supply decrease rejected')

except urllib.error.URLError as e:
    print(e.reason)

Download source

import { PrivateKey } from 'symbol-sdk';
import {
    NemFacade,
    NetworkTimestamp,
    calculateTransactionFee,
    models
} from 'symbol-sdk/nem';

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

// Helper function to announce a transaction
async function announceTransaction(payload, label) {
    const announcePath = '/transaction/announce';
    console.log(`Announcing ${label} to ${announcePath}`);
    const announceResponse = await fetch(`${NODE_URL}${announcePath}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: payload
    });
    const result = await announceResponse.json();
    console.log('  Result:', result.message);
    return result.message;
}

// Helper function to fetch the current mosaic supply
async function fetchSupply(mosaic) {
    const supplyPath = `/mosaic/supply?mosaicId=${mosaic}`;
    const supplyResponse = await fetch(`${NODE_URL}${supplyPath}`);
    const supplyInfo = await supplyResponse.json();
    return supplyInfo.supply;
}

// Helper function to wait for transaction confirmation
async function waitForConfirmation(transactionHash, label) {
    const statusPath = `/transaction/get?hash=${transactionHash}`;
    console.log(`Waiting for ${label} confirmation from`, statusPath);
    let isConfirmed = false;
    for (let attempt = 1; 120 >= attempt; ++attempt) {
        const response = await fetch(`${NODE_URL}${statusPath}`);
        if (response.ok) {
            const confirmed = await response.json();
            console.log(`${label} confirmed in block`,
                confirmed.meta.height);
            isConfirmed = true;
            break;
        }
        console.log('  Transaction status: pending');
        await new Promise(resolve => { setTimeout(resolve, 1000); });
    }
    if (!isConfirmed)
        console.warn(`${label} confirmation took too long.`);
}

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

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

const namespaceName = process.env.NAMESPACE || 'my_namespace';
const mosaicName = process.env.MOSAIC || 'token';
const mosaicId = `${namespaceName}:${mosaicName}`;
console.log('Mosaic ID:', mosaicId);

try {
    // Fetch current network time
    const timePath = '/time-sync/network-time';
    console.log('Fetching current network time from', timePath);
    const timeResponse = await fetch(`${NODE_URL}${timePath}`);
    const timeJSON = await timeResponse.json();
    const networkTime = Math.floor(timeJSON.receiveTimeStamp / 1000);
    console.log('  Network time:', networkTime,
        's since the nemesis block');

    // Derived fields from network time
    const timestamp = new NetworkTimestamp(networkTime);
    const deadline = timestamp.addHours(2);

    // --- INCREASING SUPPLY (MINTING) ---
    console.log('\n--- Increasing supply (minting) ---');

    console.log('Supply before minting:', await fetchSupply(mosaicId));

    const increaseTx = facade.transactionFactory.create({
        type: 'mosaic_supply_change_transaction_v1',
        signerPublicKey: signerKeyPair.publicKey.toString(),
        timestamp: timestamp.timestamp,
        deadline: deadline.timestamp,
        mosaicId: {
            namespaceId: { name: namespaceName },
            name: mosaicName
        },
        action: 'increase',
        delta: 500n
    });
    increaseTx.fee = new models.Amount(
        calculateTransactionFee(increaseTx));

    const increaseSignature = facade.signTransaction(
        signerKeyPair, increaseTx);
    const increasePayload = facade.transactionFactory.static
        .attachSignature(increaseTx, increaseSignature);
    console.log('Built supply increase transaction:');
    console.dir(increaseTx.toJson(), { colors: true });
    const increaseResult = await announceTransaction(
        increasePayload, 'supply increase');
    if ('SUCCESS' === increaseResult) {
        await waitForConfirmation(
            facade.hashTransaction(increaseTx).toString(),
            'supply increase');
        console.log('Supply after minting:', await fetchSupply(mosaicId));
    } else {
        console.log('Supply increase rejected');
    }

    // --- DECREASING SUPPLY (BURNING) ---
    console.log('\n--- Decreasing supply (burning) ---');

    const decreaseTx = facade.transactionFactory.create({
        type: 'mosaic_supply_change_transaction_v1',
        signerPublicKey: signerKeyPair.publicKey.toString(),
        timestamp: timestamp.timestamp,
        deadline: deadline.timestamp,
        mosaicId: {
            namespaceId: { name: namespaceName },
            name: mosaicName
        },
        action: 'decrease',
        delta: 500n
    });
    decreaseTx.fee = new models.Amount(
        calculateTransactionFee(decreaseTx));

    const decreaseSignature = facade.signTransaction(
        signerKeyPair, decreaseTx);
    const decreasePayload = facade.transactionFactory.static
        .attachSignature(decreaseTx, decreaseSignature);
    console.log('Built supply decrease transaction:');
    console.dir(decreaseTx.toJson(), { colors: true });
    const decreaseResult = await announceTransaction(
        decreasePayload, 'supply decrease');
    if ('SUCCESS' === decreaseResult) {
        await waitForConfirmation(
            facade.hashTransaction(decreaseTx).toString(),
            'supply decrease');
        console.log('Supply after burning:', await fetchSupply(mosaicId));
    } else {
        console.log('Supply decrease rejected');
    }

} catch (e) {
    console.error(e.message, '| Cause:', e.cause?.code ?? 'unknown');
}

Download source

Code Explanation⚓︎

Changing a mosaic's supply uses the MosaicSupplyChangeTransactionV1 transaction. This tutorial announces two of them: one to mint new units and one to burn them.

Because both transactions are submitted the same way, the snippet defines two helpers, and , which announce a transaction and then poll the network until it is included in a block.

A third helper, , reads the mosaic's current supply from /mosaic/supply GET, so that the effect of each transaction can be observed.

Setting Up the Account and the Mosaic⚓︎

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

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

namespace_name = os.getenv('NAMESPACE', 'my_namespace')
mosaic_name = os.getenv('MOSAIC', 'token')
mosaic_id = f'{namespace_name}:{mosaic_name}'
print(f'Mosaic ID: {mosaic_id}')
const SIGNER_PRIVATE_KEY = process.env.SIGNER_PRIVATE_KEY ||
    '0000000000000000000000000000000000000000000000000000000000000000';
const signerKeyPair = new NemFacade.KeyPair(
    new PrivateKey(SIGNER_PRIVATE_KEY));

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

const namespaceName = process.env.NAMESPACE || 'my_namespace';
const mosaicName = process.env.MOSAIC || 'token';
const mosaicId = `${namespaceName}:${mosaicName}`;
console.log('Mosaic ID:', mosaicId);

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 must be the creator of the mosaic.

The mosaic to update is read from the NAMESPACE and MOSAIC environment variables, which default to my_namespace:token.

Use a mosaic created by the signer

By default, the code uses the test account referenced by SIGNER_PRIVATE_KEY and a mosaic named my_namespace:token.

If you come from the Creating a Mosaic tutorial, set the SIGNER_PRIVATE_KEY, NAMESPACE, and MOSAIC environment variables to match the account and mosaic you created there, or any other mosaic that the signer owns.

Fetching Network Time⚓︎

    # Fetch current network time
    time_path = '/time-sync/network-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())
        network_time = response_json['receiveTimeStamp'] // 1000
        print(f'  Network time: {network_time} s since the nemesis block')

    # Derived fields from network time
    timestamp = NetworkTimestamp(network_time)
    deadline = timestamp.add_hours(2)
    // Fetch current network time
    const timePath = '/time-sync/network-time';
    console.log('Fetching current network time from', timePath);
    const timeResponse = await fetch(`${NODE_URL}${timePath}`);
    const timeJSON = await timeResponse.json();
    const networkTime = Math.floor(timeJSON.receiveTimeStamp / 1000);
    console.log('  Network time:', networkTime,
        's since the nemesis block');

    // Derived fields from network time
    const timestamp = new NetworkTimestamp(networkTime);
    const deadline = timestamp.addHours(2);

Network time is fetched from /time-sync/network-time GET, and the transaction's timestamp and deadline fields are derived from it, following the process described in the Transfer XEM tutorial.

Increasing Supply (Minting)⚓︎

    print(f'Supply before minting: {fetch_supply(mosaic_id)}')

    increase_tx = facade.transaction_factory.create({
        'type': 'mosaic_supply_change_transaction_v1',
        'signer_public_key': signer_key_pair.public_key,
        'timestamp': timestamp.timestamp,
        'deadline': deadline.timestamp,
        'mosaic_id': {
            'namespace_id': {'name': namespace_name},
            'name': mosaic_name
        },
        'action': 'increase',
        'delta': 500
    })
    increase_tx.fee = Amount(calculate_transaction_fee(increase_tx))

    signature = facade.sign_transaction(signer_key_pair, increase_tx)
    json_payload = facade.transaction_factory.attach_signature(
        increase_tx, signature)
    print('Built supply increase transaction:')
    print(json.dumps(increase_tx.to_json(), indent=2))
    if 'SUCCESS' == announce_transaction(json_payload, 'supply increase'):
        wait_for_confirmation(
            facade.hash_transaction(increase_tx), 'supply increase')
        print(f'Supply after minting: {fetch_supply(mosaic_id)}')
    else:
        print('Supply increase rejected')
    console.log('Supply before minting:', await fetchSupply(mosaicId));

    const increaseTx = facade.transactionFactory.create({
        type: 'mosaic_supply_change_transaction_v1',
        signerPublicKey: signerKeyPair.publicKey.toString(),
        timestamp: timestamp.timestamp,
        deadline: deadline.timestamp,
        mosaicId: {
            namespaceId: { name: namespaceName },
            name: mosaicName
        },
        action: 'increase',
        delta: 500n
    });
    increaseTx.fee = new models.Amount(
        calculateTransactionFee(increaseTx));

    const increaseSignature = facade.signTransaction(
        signerKeyPair, increaseTx);
    const increasePayload = facade.transactionFactory.static
        .attachSignature(increaseTx, increaseSignature);
    console.log('Built supply increase transaction:');
    console.dir(increaseTx.toJson(), { colors: true });
    const increaseResult = await announceTransaction(
        increasePayload, 'supply increase');
    if ('SUCCESS' === increaseResult) {
        await waitForConfirmation(
            facade.hashTransaction(increaseTx).toString(),
            'supply increase');
        console.log('Supply after minting:', await fetchSupply(mosaicId));
    } else {
        console.log('Supply increase rejected');
    }

The snippet first reads the mosaic's supply, so that the newly minted units can be seen once the transaction is confirmed.

To mint new units, the transaction sets:

  • : Mosaic supply change transactions use the type MosaicSupplyChangeTransactionV1.

  • : The account that signs the transaction and pays the fees. It must be the creator of the mosaic.

  • and : The values computed in the network time step.

  • : The fully qualified name of the mosaic to update.

  • : The value increase mints new units.

  • : The number of whole units to add. The resulting total supply cannot exceed the maximum supply.

    The cap is expressed in atomic units

    The maximum supply is fixed at \(9 \cdot 10^{15}\) atomic units, while is expressed in whole units.

    The maximum value of therefore depends on the mosaic's divisibility:

    \[ \text{max\_whole\_units} = \frac{9 \cdot 10^{15}}{10^{\text{divisibility}}} \]

    The mosaic in this tutorial has a divisibility of 2, so one whole unit corresponds to \(100\) atomic units and the supply can grow up to \(9 \cdot 10^{13}\) whole units.

The transaction fee is then calculated and the transaction is signed, announced, and confirmed, following the same process as in the Transfer XEM tutorial.

Mosaic supply change transactions pay a fixed transaction fee of 0.15 XEM, as shown in the fee schedule.

Once confirmed, the supply is read again to show the resulting supply. The minted units are credited to the creator's account.

Decreasing Supply (Burning)⚓︎

    decrease_tx = facade.transaction_factory.create({
        'type': 'mosaic_supply_change_transaction_v1',
        'signer_public_key': signer_key_pair.public_key,
        'timestamp': timestamp.timestamp,
        'deadline': deadline.timestamp,
        'mosaic_id': {
            'namespace_id': {'name': namespace_name},
            'name': mosaic_name
        },
        'action': 'decrease',
        'delta': 500
    })
    decrease_tx.fee = Amount(calculate_transaction_fee(decrease_tx))

    signature = facade.sign_transaction(signer_key_pair, decrease_tx)
    json_payload = facade.transaction_factory.attach_signature(
        decrease_tx, signature)
    print('Built supply decrease transaction:')
    print(json.dumps(decrease_tx.to_json(), indent=2))
    if 'SUCCESS' == announce_transaction(json_payload, 'supply decrease'):
        wait_for_confirmation(
            facade.hash_transaction(decrease_tx), 'supply decrease')
        print(f'Supply after burning: {fetch_supply(mosaic_id)}')
    else:
        print('Supply decrease rejected')
    const decreaseTx = facade.transactionFactory.create({
        type: 'mosaic_supply_change_transaction_v1',
        signerPublicKey: signerKeyPair.publicKey.toString(),
        timestamp: timestamp.timestamp,
        deadline: deadline.timestamp,
        mosaicId: {
            namespaceId: { name: namespaceName },
            name: mosaicName
        },
        action: 'decrease',
        delta: 500n
    });
    decreaseTx.fee = new models.Amount(
        calculateTransactionFee(decreaseTx));

    const decreaseSignature = facade.signTransaction(
        signerKeyPair, decreaseTx);
    const decreasePayload = facade.transactionFactory.static
        .attachSignature(decreaseTx, decreaseSignature);
    console.log('Built supply decrease transaction:');
    console.dir(decreaseTx.toJson(), { colors: true });
    const decreaseResult = await announceTransaction(
        decreasePayload, 'supply decrease');
    if ('SUCCESS' === decreaseResult) {
        await waitForConfirmation(
            facade.hashTransaction(decreaseTx).toString(),
            'supply decrease');
        console.log('Supply after burning:', await fetchSupply(mosaicId));
    } else {
        console.log('Supply decrease rejected');
    }

To burn existing units, the same transaction type is used with set to decrease and set to the number of whole units to remove.

The burned units are taken from the creator's account, so only units the creator still holds can be burned. Units already distributed to other accounts remain in their balances, and the transaction fails if the creator's own balance does not cover .

Once confirmed, the supply is read again to show the burned units. Because this tutorial increases and then decreases the supply by the same amount, the final supply matches the value before the changes.

Output⚓︎

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

Using node http://libertalia.nemtest.net:7890
Signer address: TBONKWCOWBZYZB2I5JD3LSDBQVBYHB757VN3SKPP
Mosaic ID: my_namespace:token
Fetching current network time from /time-sync/network-time
  Network time: 356366691 s since the nemesis block

--- Increasing supply (minting) ---
Supply before minting: 1000
Built supply increase transaction:
{
  "type": 16386,
  "version": 1,
  "network": 152,
  "timestamp": 356366691,
  "signer_public_key": "462EE976890916E54FA825D26BDD0235F5EB5B6A143C199AB0AE5EE9328E08CE",
  "signature": "47A61EFCFFBF72C84F4BC06D45422F62CF4A1173D2F58820A3A9EE7B1EECD85641E3EAAC6260F3D3B90FBD5EB167921F4FFF5952BF17DF583BED6C9355D4ED08",
  "fee": "150000",
  "deadline": 356373891,
  "mosaic_id": {
    "namespace_id": {
      "name": "6d795f6e616d657370616365"
    },
    "name": "746f6b656e"
  },
  "action": 1,
  "delta": "500"
}
Announcing supply increase to /transaction/announce
  Result: SUCCESS
Waiting for supply increase confirmation from /transaction/get?hash=7D9EAF91CF91F699E2BD50F16F3F21872319570D64BECA35F24742F6C8F03993
  Transaction status: pending
  Transaction status: pending
  Transaction status: pending
supply increase confirmed in block 699605
Supply after minting: 1500

--- Decreasing supply (burning) ---
Built supply decrease transaction:
{
  "type": 16386,
  "version": 1,
  "network": 152,
  "timestamp": 356366691,
  "signer_public_key": "462EE976890916E54FA825D26BDD0235F5EB5B6A143C199AB0AE5EE9328E08CE",
  "signature": "F3383125C6849AD2C4AFC020331B44F489F0A62302DF76AD15363350C2E99507CD04F6AD3F4026157FF42719EBFC6A7B49122AAC5696338DBCFE07E56A25E509",
  "fee": "150000",
  "deadline": 356373891,
  "mosaic_id": {
    "namespace_id": {
      "name": "6d795f6e616d657370616365"
    },
    "name": "746f6b656e"
  },
  "action": 2,
  "delta": "500"
}
Announcing supply decrease to /transaction/announce
  Result: SUCCESS
Waiting for supply decrease confirmation from /transaction/get?hash=2E5F803F30B941671C86481B6646B8AD252D05CBF41F77B438D508F1232E99B5
  Transaction status: pending
  Transaction status: pending
  Transaction status: pending
supply decrease confirmed in block 699606
Supply after burning: 1000

Some highlights from the output:

  • Supply before minting (line 8): The mosaic starts with a supply of 1000 whole units.

  • Supply increase (lines 25-26): The increase action with a delta of 500 mints new units into the creator's balance.

  • Supply after minting (line 35): The supply rises to 1500 whole units.

  • Supply decrease (lines 54-55): The decrease action with the same delta burns those units.

  • Supply after burning (line 64): The supply returns to 1000, because the increase and decrease cancel out.

Conclusion⚓︎

This tutorial showed how to:

Step Related documentation
Mint mosaic supply , MosaicSupplyChangeTransactionV1
Burn mosaic supply , MosaicSupplyChangeTransactionV1
Calculate the transaction fee
Read the mosaic supply /mosaic/supply GET

Next Steps⚓︎

Now that you can change a mosaic's supply, you can: