Skip to main content
Initialize the AppKit before using examples on this page.
Jettons are fungible tokens on TON, similar to ERC-20 tokens on Ethereum. Unlike Toncoin, which is the native TON currency used in all transfers, each jetton has a separate master (minter) contract and an individual wallet contract for each holder. For example, USDT on TON is implemented as a jetton, and its minter contract address is EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs. By providing this address and the recipient’s TON wallet contract address, AppKit knows which tokens to send and to whom.
To deploy and mint a new jetton on the mainnet without writing code, use the dedicated official tool: TON MINTER.

Metadata

Retrieve metadata about a specific jetton, such as its name, symbol, and decimals:
import { useJettonInfo } from '@ton/appkit-react';

export const JettonCard = ({ jettonAddress }) => {
  const {
    data: info,
    isLoading,
    error,
  } = useJettonInfo({
    // Jetton master (minter) contract address
    address: jettonAddress,
  });

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>Error: {error.message}</div>;
  }

  return (
    <div>
      <p><em>Jetton info</em></p>
      <p>Name: {info?.name}</p>
      <p>Symbol: {info?.symbol}</p>
      <p>Decimals: {info?.decimals}</p>
    </div>
  );
};

Jetton wallet address

Each jetton holder has a dedicated jetton wallet contract. To resolve its address for a given owner:
import {
  useJettonWalletAddress,
  useSelectedWallet,
} from '@ton/appkit-react';

export const JettonWalletAddressCard = ({ jettonAddress }) => {
  const [wallet, _] = useSelectedWallet();
  const {
    data: walletAddress,
    isLoading,
    error,
  } = useJettonWalletAddress({
    // TON wallet address of the jetton holder
    ownerAddress: wallet?.getAddress() ?? '<TON_WALLET_ADDRESS>',

    // Jetton master (minter) contract address
    jettonAddress,
  });

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>Error: {error.message}</div>;
  }

  return <div>Jetton wallet address: {walletAddress?.toString()}</div>;
};

Balance

Similar to Toncoin balance checks, discrete one-off checks have limited value on their own and continuous monitoring should be used for UI display. Unlike Toncoin, the balance units and decimal places vary between jettons — use the decimals field from the jetton’s metadata to interpret raw amounts correctly. USDT has a decimal precision of 6, meaning that the fractional balance string '0.1' represents a balance of 0.1 USDT, or 100000 micro USDT (raw units).

On-demand balance check

Do not store the balance check results anywhere in the wallet service’s state, as they become outdated quickly. For UI purposes, do continuous balance monitoring.

Single jetton

Check the balance of a specific jetton for the connected TON wallet or an arbitrary address:
import {
  useJettonBalanceByAddress,
  useSelectedWallet,
} from '@ton/appkit-react';

export const JettonBalanceCard = ({ jettonAddress }) => {
  const [wallet, _] = useSelectedWallet();
  const {
    data: balance,
    isLoading,
    error,
  } = useJettonBalanceByAddress({
    // TON wallet address of the jetton holder
    ownerAddress: wallet?.getAddress() ?? '<TON_WALLET_ADDRESS>',

    // Jetton master (minter) contract address
    jettonAddress,

    // Jetton decimals to calculate raw unit amounts
    jettonDecimals: 6,
  });

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>Error: {error.message}</div>;
  }

  return <div>Jetton balance: {balance ?? '0'}</div>;
};

All jettons

Retrieve every jetton held by the connected TON wallet or an arbitrary address:
import {
  useJettonsByAddress,
  useSelectedWallet,
  // Helper function targeting the connected wallet
  useJettons,
} from '@ton/appkit-react';

export const JettonListByAddress = () => {
  const [wallet, _] = useSelectedWallet();
  const {
    data: jettons,
    isLoading,
    error,
  } = useJettonsByAddress({
    // TON wallet address of the jetton holder
    address: wallet?.getAddress() ?? '<TON_WALLET_ADDRESS>',
  });

  // Alternatively, query the connected wallet directly
  // const { data: jettons, isLoading, error } = useJettons();

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>Error: {error.message}</div>;
  }

  return (
    <div>
      <p>Jettons</p>
      <ul>
        {jettons?.jettons.map((jetton) => (
          <li key={jetton.walletAddress}>
            {jetton.info.name}: {jetton.balance ?? '0'}
          </li>
        ))}
      </ul>
    </div>
  );
};

Continuous balance monitoring

Poll the balance at regular intervals to keep the displayed value up to date. Use an appropriate interval based on UX requirements — shorter intervals provide fresher data but increase API usage. Modify the following example according to the application logic:
import {
  useJettonBalanceByAddress,
  useSelectedWallet,
} from '@ton/appkit-react';

export const JettonBalanceCard = ({ jettonAddress }) => {
  const [wallet, _] = useSelectedWallet();
  const {
    data: balance,
    isLoading,
    error,
    refetch,
  } = useJettonBalanceByAddress({
    // TON wallet address of the jetton holder
    ownerAddress: wallet?.getAddress() ?? '<TON_WALLET_ADDRESS>',

    // Jetton master (minter) contract address
    jettonAddress,
  });

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return (
      <div>
        <p>Error: {error.message}</p>
        <button onClick={() => refetch()}>Try again</button>
      </div>
    );
  }

  return <div>Jetton balance: {balance ?? '0'}</div>;
};

Transfers

Funds at riskEach jetton stores the decimals parameter in its metadata. Transferring without accounting for decimals can result in sending drastically more or fewer tokens than intended.Mitigation: Verify the correct decimals value before calculating transfer amounts. For USDTs, the decimals value is 6.
Modify the following examples according to the application logic:
// Pre-built UI component for sending jetton transactions by clicking a button.
// It handles success and error states while being customizable.
import { SendJettonButton } from '@ton/appkit-react';

export const SendJetton = () => {
  // For example: 'UQ...'
  const recipientAddress = '<TON_WALLET_ADDRESS>';
  // For example, '0.1' or '1' jetton
  const jettonAmount = '<FRACTIONAL_JETTON_AMOUNT>';
  // For example, 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs'
  const jettonAddress = '<JETTON_MINTER_ADDRESS>';

  return (
    <SendJettonButton
      // New owner of the sent jettons
      recipientAddress={recipientAddress}

      // Jetton amount in fractional units
      amount={jettonAmount}

      // What kind of jettons to send
      jetton={{
        // Jetton master (minter) contract address
        address: jettonAddress,

        // Short ticker name
        symbol: 'USDT',

        // Jetton decimals to calculate raw unit amounts
        // For example, USDT defaults to 6, while Toncoin to 9:
        decimals: 6,
      }}

      // (optional) Comment
      comment="Hello from AppKit!"

      // (optional) Add custom button title
      text="Send some jetton"

      // (optional) Handle successes
      onSuccess={(result) => console.log('Transaction sent:', result)}

      // (optional) Handle errors
      onError={(error) => console.error('Transaction failed:', error)}

      // (optional) Add custom CSS classes
      className=''

      // (optional) When set to `true`, the button is disabled
      disabled={false}
    />
  );
};

See also

Jettons: General: