Ton API
Transaction tracking

Transaction Tracking

To reliably find a transaction from an external message (external-in) in the TON blockchain, use a normalized hash instead of a regular hash. External messages may slightly alter metadata when included in the blockchain, causing regular hashes to fail in locating the transaction.

Swagger documentation for Blockchain operations can be found here.

TypeScript
Go
import { TonApiClient } from '@ton-api/client';
import { Message, beginCell } from '@ton/core';
 
const ta = new TonApiClient({
    baseUrl: 'https://tonapi.io',
    apiKey: 'YOUR_API_KEY', // Optional, improves limits and access
});
 
function normalizeHash(message: Message): Buffer {
    if (message.info.type !== 'external-in') {
        return message.body.hash();
    }
 
    const cell = beginCell()
        .storeUint(2, 2)    // external-in
        .storeUint(0, 2)    // addr_none
        .storeAddress(message.info.dest)
        .storeUint(0, 4)    // import_fee = 0
        .storeBit(false)    // no StateInit
        .storeBit(true)     // store body as reference
        .storeRef(message.body)
        .endCell();
 
    return cell.hash();
}
 
async function trackTransaction(message: Message) {
    const msgHashHex = normalizeHash(message).toString('hex');
    const transaction = await ta.blockchain.getBlockchainTransactionByMessageHash(msgHashHex);
 
    console.log('Transaction:', transaction);
}

Use this method to reliably track, verify, or monitor transactions based on external messages.

Getting the Message object

From a BOC

You may encounter BOC strings from various sources, for example, TonConnect (specifically after methods like sendTransaction or send), or from your own transaction logs. Here's how to parse a BOC string into a Message object:

TypeScript
import { loadMessage, Cell } from '@ton/core';
 
const boc = "te6cckECBgEAAPYAAeWIAW7m9GMNMJnjJLq86chyLJWpEZh3KHlgHyzaMJzYP4z8A5tLO3P////rPqB8UAAA..."; // truncated example
const slice = Cell.fromBase64(boc).beginParse();
const message = loadMessage(slice);

Manual creation with ton/core

To manually create a Message, follow these steps:

TypeScript
import { WalletContractV5R1 } from '@ton/ton';
import { Address, internal, SendMode, external, beginCell } from '@ton/core';
import { mnemonicToPrivateKey } from '@ton/crypto';
 
// Initialize wallet keys from mnemonic
const mnemonics = 'word1 word2 ...'.split(' ');
const keyPair = await mnemonicToPrivateKey(mnemonics);
 
// Set up wallet
const wallet = WalletContractV5R1.create({ workchain: 0, publicKey: keyPair.publicKey });
const contract = adapter.open(wallet);
 
// Create internal transfer
const seqno = await contract.getSeqno();
const destination = Address.parse('UQDNzlh0XSZdb5_Qrlx5QjyZHVAO74v5oMeVVrtF_5Vt1rIt');
 
const transfer = contract.createTransfer({
    seqno,
    secretKey: keyPair.secretKey,
    sendMode: SendMode.PAY_GAS_SEPARATELY + SendMode.IGNORE_ERRORS,
    messages: [
        internal({
            to: destination,
            value: 100_000n,
        })
    ]
});
 
await contract.send(transfer);
 
// Wrap transfer in an external message
const message = external({
    to: contract.address,
    body: transfer
});

Use this method to reliably track, verify, or monitor transactions based on external messages.