Skip to content

Assets

Create new asset

ts
/**
 * Creates a new asset on the chain.
 * @param admin The owner of the asset.
 * @param minBalance Minimum balance that is required for this asset.
 * @param decimals Number of decimal places to keep.
 * @param name Descriptive name of the asset.
 * @param symbol Short symbol for the token.
 * @returns The call to be submitted to the chain.
 */
export const createAssetCall = async (
  admin: MultiAddress,
  minBalance: bigint,
  decimals: number,
  name: string,
  symbol: string,
) => {
  const assetId = (await typedApi.query.Assets.NextAssetId.getValue()) ?? 1;

  const extrinsic = typedApi.tx.Utility.batch_all({
    calls: [
      typedApi.tx.Assets.create({
        id: assetId,
        admin,
        min_balance: minBalance,
      }).decodedCall,
      typedApi.tx.Assets.set_metadata({
        id: assetId,
        name: Binary.fromText(name),
        symbol: Binary.fromText(symbol),
        decimals,
      }).decodedCall,
    ],
  });

  return {
    assetId,
    extrinsic,
  };
};

List assets

ts
export const listAssets = async () => {
  const assets = await typedApi.query.Assets.Asset.getEntries();

  for (const asset of assets) {
    const assetId = asset.keyArgs[0];
    const metadata = await typedApi.query.Assets.Metadata.getValue(assetId);

    console.log(
      `- ${assetId}: ${metadata.name.asText()} (${metadata.symbol.asText()})`,
    );
  }
};

List asset holders

ts
export const formatAsset = (
  balance: bigint,
  decimals: number,
  symbol: string,
) => {
  if (decimals > 0) {
    const divisor = BigInt(10) ** BigInt(decimals);
    return `${balance / divisor}.${(balance % divisor).toString().padEnd(decimals, "0")} ${symbol}`;
  } else {
    return `${balance.toString()} ${symbol}`;
  }
};

export const listAssetHolders = async (assetId: number) => {
  const metadata = await typedApi.query.Assets.Metadata.getValue(assetId);
  const accounts = await typedApi.query.Assets.Account.getEntries(assetId);

  const symbol = metadata.symbol.asText();
  const decimals = metadata.decimals;

  for (const account of accounts) {
    const address = account.keyArgs[1];
    console.log(
      `${address}: ${formatAsset(account.value.balance, decimals, symbol)}`,
    );
  }
};

Mint asset

ts
/**
 * Creates a new asset on the chain.
 * @param admin The owner of the asset.
 * @param minBalance Minimum balance that is required for this asset.
 * @param decimals Number of decimal places to keep.
 * @param name Descriptive name of the asset.
 * @param symbol Short symbol for the token.
 * @returns The call to be submitted to the chain.
 */
export const createAssetCall = async (
  admin: MultiAddress,
  minBalance: bigint,
  decimals: number,
  name: string,
  symbol: string,
) => {
  const assetId = (await typedApi.query.Assets.NextAssetId.getValue()) ?? 1;

  const extrinsic = typedApi.tx.Utility.batch_all({
    calls: [
      typedApi.tx.Assets.create({
        id: assetId,
        admin,
        min_balance: minBalance,
      }).decodedCall,
      typedApi.tx.Assets.set_metadata({
        id: assetId,
        name: Binary.fromText(name),
        symbol: Binary.fromText(symbol),
        decimals,
      }).decodedCall,
    ],
  });

  return {
    assetId,
    extrinsic,
  };
};

Transfer asset

ts
/**
 * Creates a transfer call for the given asset.
 * @param assetId The unique asset ID.
 * @param address The address to receive the assets.
 * @param amount Amount of tokens to receive. (1 EXAMPL = 10 ^ 12)
 * @returns The extrinsic to be called.
 */
export const transferAssetCall = (
  assetId: number,
  address: MultiAddress,
  amount: bigint,
) => {
  const extrinsic = typedApi.tx.Assets.transfer({
    id: assetId,
    target: address,
    amount,
  });

  return {
    extrinsic,
  };
};