Перейти к основному содержимому

Отслеживание на основе хешей

В этом разделе рассмотрим, как использовать хеши для отслеживания сообщений и транзакций в блокчейне. Вы узнаете, чем различаются разновидности хешей, как вычислять их и применять для верификации активности в блокчейне.

Хеши

Хеши играют ключевую роль, обеспечивая идентификацию и верификацию на всех уровнях блокчейна. Понимание того, как работает хеширование, поможет вам эффективно отслеживать транзакции, проверять сообщения и интегрировать ваши приложения с TON.

Что такое хеш?

В TON хеш — это уникальный криптографический слепок данных, вычисленный с помощью алгоритма SHA-256. У каждой ячейки, сообщения или транзакции — свой уникальный хеш, который служит цифровой подписью.

Типы хешей

Важно

Хеши в TON работают односторонним образом: исходные данные не могут быть восстановлены из хеша. Однако они детерминированы: один и тот же ввод всегда приводит к одному и тому же хешу.

Хеш тела сообщения

Хеш тела сообщения — это уникальный идентификатор содержимого сообщения. Он вычисляется из ячейки, содержащей данные сообщения.

Тело относится к полю body: (Either X ^X) в схеме TL-B:

message$_ {X:Type} info:CommonMsgInfo
init:(Maybe (Either StateInit ^StateInit))
body:(Either X ^X) = Message X;

Давайте для примера рассмотрим тело сообщения с комментарием «Hello, TON!» и вычислим его хеш.

msg_body_hash.ts
import { beginCell } from '@ton/core';

// Create the message body to increment the counter
const messageBody = beginCell()
.storeUint(0, 32) // op code
.storeStringTail('Hello TON!')
.endCell();

console.log('Message body hash:', messageBody.hash().toString('hex'));

Ожидаемый вывод в консоль

Message body hash: d989794fa90c9817a63a22e00554574f3c4a347dcfd2e2886980a294de15f2af

Когда полезен хеш тела сообщения:

  • для проверки целостности данных
  • для отладки и логирования операций
  • для дедупликации сообщений в вашем приложении

Хеш полного сообщения

Полное сообщение включает не только тело, но и заголовки с метаданными, такими как отправитель, получатель, сумма и комиссии. Его хеш — уникальный идентификатор всего сообщения.

Для внутренних сообщений это соответствует структуре Message X, определённой в этой схеме TL-B:

message$_ {X:Type} info:CommonMsgInfo
init:(Maybe (Either StateInit ^StateInit))
body:(Either X ^X) = Message X;


int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
src:MsgAddressInt dest:MsgAddressInt
value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
created_lt:uint64 created_at:uint32 = CommonMsgInfo;

Пример:

full_msg_hash.ts
import { storeMessage, beginCell, Address, Message } from '@ton/ton';
import { toNano } from '@ton/core';

const messageBody = beginCell()
.storeUint(0, 32) // op code
.storeStringTail('Hello TON!')
.endCell();

// Create a complete message object
const message: Message = {
info: {
type: 'internal',
dest: Address.parse('UQAi....'), // Insert recipient address
value: { coins: toNano('0.1') },
bounce: true,
src: Address.parse('UQA1....'), // Insert sender address
ihrDisabled: true,
bounced: false,
ihrFee: 0n,
forwardFee: 0n,
createdAt: 0,
createdLt: 0n,
},
body: messageBody,
};

// Get the complete message hash
const messageCell = beginCell().store(storeMessage(message)).endCell();

const fullMessageHash = messageCell.hash();
console.log('Full message hash:', fullMessageHash.toString('hex'));

Ожидаемый вывод в консоль (конкретный хеш зависит от введённого адреса):

Full message hash: 40b1477f90d702af223f15194724e0c12b51028bc622444959e155e77903b12c

Когда полезен хеш полного сообщения:

  • для отслеживания конкретных сообщений в блокчейне
  • при использовании TON Center API для поиска транзакций
  • для проверки того, что никто не изменил сообщение

Хеш транзакции

Хеш транзакции — это уникальный идентификатор всей транзакции. Он выводится из всех задействованных в ней данных, включая входящие и исходящие сообщения, изменения состояния и комиссии. Эти данные становятся доступны только после того, как блокчейн выполнит транзакцию, поэтому хеш вычисляется после её записи.

Получение хеша транзакции:

trx_hash.ts
import { TonClient, beginCell, storeMessage } from '@ton/ton';
import { Address } from '@ton/core';

async function main() {
const client = new TonClient({
// Testnet endpoint; if you're working on Mainnet, don't forget to update this
endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC',
apiKey: 'insert your api key', // Get your API key via the toncenter.com bot
});

const transactions = await client.getTransactions(
Address.parse('0QD3o...'), // Insert your wallet address here
{ archival: true, limit: 10 },
);

for (const tx of transactions) {
const txHash = tx.hash();
console.log('Transaction hash:', txHash.toString('hex'));

// You can also get the hash of the incoming message
if (tx.inMessage) {
const inMsgCell = beginCell().store(storeMessage(tx.inMessage)).endCell();
const inMsgHash = inMsgCell.hash();
console.log('Incoming message hash:', inMsgHash.toString('hex'));
}
}
}

main().catch(console.error);

Ожидаемый вывод в консоль

Отображает последние 10 транзакций для указанного адреса. Для каждой из них выводит хеш транзакции. Если в ней существует входящее сообщение, также выводится его хеш.

Transaction hash: 79a6406e5544e95bbe5db8c7e8189daaca240b2d6b4f21cc479c3082dd4c5cce
Incoming message hash: 4557aa15e21cf0501f3d82eaa26a23ab61c08a544490154bd12a1814d492db42
Transaction hash: 1a86894bbe2f5af090d97f761f0367a16b713e93247056003e6d8b6a68a5165e
Incoming message hash: dfa0916ceee9dd26c6966d55446b23f88950e118432f870d092cfcde83a3b864
:
:

Нормализованный хеш сообщения

Нормализация — это процесс стандартизации, преобразующий различные представления в единый формат. Хотя сообщения в разных интерфейсах следуют одной схеме TL-B, структурные различия в реализации иногда приводят к коллизиям.

Чтобы решить эту проблему, в экосистеме определён стандарт, обеспечивающий консистентное вычисление хеша. Правила нормализации подробно описаны в TEP-467.

Проблема, которую решает нормализация:

Функционально идентичные сообщения могут отличаться тем, как в них представлены поля src, import_fee и init. Эти вариации приводят к тому, что у сообщений с эквивалентным содержимым могут получаться разные хеши. Это усложняет отслеживание транзакций и дедупликацию.

Как работает нормализация:

Нормализованный хеш вычисляется с помощью применения к внешнему входящему сообщению таких правил стандартизации:

  1. Адрес источника (src): установить addr_none$00
  2. Комиссия за импорт (import_fee): установить 0
  3. Начальное состояние (init): установить пустое значение
  4. Тело: всегда хранить как ссылку

Практический пример вычисления нормализованного хеша:

norm_hash.ts
import { beginCell, Cell, Address } from '@ton/core';

function normalizeExternalMessage(destAddress: Address, bodyCell: Cell): Cell {
try {
const normalizedExtMessage = beginCell()
.storeUint(0b10, 2) // Set external message prefix (10 in binary)
.storeUint(0, 2) // Set src to addr_none (normalization)
.storeAddress(destAddress) // Set destination address
.storeCoins(0) // Set import_fee to 0 (normalization)
.storeBit(false) // Set init to nothing$0 (normalization)
.storeBit(true) // Use right$1 to store body by reference (normalization)
.storeRef(bodyCell) // Store body as a reference (normalization)
.endCell();

return normalizedExtMessage;
} catch (error: any) {
console.error('Error in normalization:', error.message);
throw error;
}
}

const messageBody = beginCell()
.storeUint(0, 32) // Set opcode for a simple transfer
.storeStringTail('Normalized hash example')
.endCell();

const destinationAddress = Address.parse('EQB...');
const normalizedExternalMessage = normalizeExternalMessage(destinationAddress, messageBody);
const normalizedHash = normalizedExternalMessage.hash().toString('hex');

console.log('Normalized message hash:', normalizedHash);

Ожидаемый вывод в консоль

Normalized message hash: ee53ccd1224c315597bdbafb2e722316d9471490b13dd9e1834903b094eb5964

Практический пример вычисления ненормализованного хеша:

До апреля 2025 года хеши сообщений в экосистеме TON не были нормализованы. Если ваш код конструирует сообщения без применения нормализации, он может создавать несогласованные хеши. В таких случаях обновите логику, чтобы следовать правилам нормализации, описанным в TEP-467.

Ниже приведён пример ненормализованного конструирования сообщения, не применяйте такой подход:

Избегайте этого подхода
non_norm_hash.ts

import { mnemonicToWalletKey } from '@ton/crypto';
import { WalletContractV4, TonClient, toNano, beginCell, Address, internal } from '@ton/ton';

// Create a client instance for accessing Testnet via TonCenter
const client = new TonClient({
endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC',
apiKey: 'your api key', // Get your API key via the toncenter.com bot
});

// Construct the message body — arbitrary opcode and payload string
const messageBody = beginCell()
.storeUint(0, 32) // op-code — arbitrary, e.g., 0
.storeStringTail('Hello TON!') // Payload string in the message body
.endCell();

// Wrap the body into an internal message
const internalMessage = internal({
to: Address.parse('0QD3....'), // recipient
value: toNano('0.1'), // 0.1 TON
body: messageBody,
});

async function main() {
// Derive wallet keys from the mnemonic phrase
const mnemonic = 'your seed phrase';
const keyPair = await mnemonicToWalletKey(mnemonic.split(' ')); // Insert your seed phrase here

// Create a WalletContractV4 instance from the public key
const wallet = WalletContractV4.create({
publicKey: keyPair.publicKey,
workchain: 0,
});

const contract = client.open(wallet);
const seqno = await contract.getSeqno();

// Create an external message using the wallet contract
const externalMessage = await wallet.createTransfer({
seqno,
secretKey: keyPair.secretKey,
messages: [internalMessage],
});

console.log('Non-normalized external message hash:', externalMessage.hash().toString('hex'));
}

main();

Ожидаемый вывод в консоль

Non-normalized external message hash: 8dd5c85be08e33341553cb1e5a2f08323e9ae9314d5ceac2e3a6c79f11151b5e

Алгоритм может как угодно отличаться от нормализованной версии. Если отсутствие нормализации вызывает проблемы в существующем проекте, правильный подход — перевести всю его кодовую базу на нормализованные хеши.

Хеши для проверки на бэкенде

Один из распространённых сценариев — отправка сообщения и проверка того, что блокчейн принял и обработал его.

Вот весь процесс по шагам
send_and_verify_msg.ts
import { internal, TonClient, Address, beginCell, WalletContractV4, SendMode } from '@ton/ton';
import { mnemonicToPrivateKey } from '@ton/crypto';

async function sendAndVerifyMessage() {
const client = new TonClient({
// Testnet endpoint; if you're working on Mainnet, don't forget to update this
endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC',
apiKey: 'insert your api key', // Get your API key via the toncenter.com bot
});

// Load wallet key pair from mnemonic
const mnemonic = 'your mnemonic'.split(' '); // Insert your seed phrase here
const keyPair = await mnemonicToPrivateKey(mnemonic);

const wallet = client.open(
WalletContractV4.create({
publicKey: keyPair.publicKey,
workchain: 0,
}),
);

// Create message body with comment
const messageBody = beginCell().storeUint(0, 32).storeStringTail('Hello TON!').endCell();

// Get current seqno
const seqno = await wallet.getSeqno();

// Send transaction
await wallet.sendTransfer({
secretKey: keyPair.secretKey,
seqno,
messages: [
internal({
to: Address.parse('0QD3o...'), // Insert the address here
value: '0.05',
body: messageBody,
}),
],
sendMode: SendMode.PAY_GAS_SEPARATELY + SendMode.IGNORE_ERRORS,
});

// Wait 10 seconds before checking seqno again
await new Promise((resolve) => setTimeout(resolve, 10000));

// Check if the transaction was processed
const newSeqno = await wallet.getSeqno();

if (newSeqno > seqno) {
console.log('Transaction sent successfully!');

// Fetch recent transactions for this wallet
const transactions = await client.getTransactions(wallet.address, {
archival: true,
limit: 5,
});
// Find the relevant external-in transaction
const ourTx = transactions.find(
(tx) => tx.inMessage?.info.type === 'external-in' && tx.description.type === 'generic',
);

if (ourTx) {
const txHash = ourTx.hash().toString('hex');
console.log('Transaction Hash:', txHash);
const viewerUrl = `https://testnet.tonviewer.com/transaction/${txHash}`;
console.log('Transaction link:', viewerUrl);
}
} else {
console.log('Transaction was not processed');
}
}

sendAndVerifyMessage().catch(console.error);

Ожидаемый вывод в консоль

Transaction sent successfully!
Transaction hash: 285f8df8f968f63680f8efaff004369f4e7aeb8619293da035cb8ca3899232f3
Transaction link: https://testnet.tonviewer.com/transaction/82ee8ee68d8b764105139b7b783b3d91d8344c6e44ee67a38ca5ee967615d31a

Хеши для проверки на фронтенде

Представление данных в TON

Все данные в TON хранятся в ячейках. Концептуально, ячейка — это структура, которая содержит до 1023 бит данных и до 4 ссылок на другие ячейки. Деревья ячеек сериализуются и упаковываются с использованием единого стандартного формата ячеек.

В TL-B эта структура называется bag of cells (BoC, «мешок ячеек»):

serialized_boc#b5ee9c72 has_idx:(## 1) has_crc32c:(## 1)
has_cache_bits:(## 1) flags:(## 2) { flags = 0 }
size:(## 3) { size <= 4 }
off_bytes:(## 8) { off_bytes <= 8 }
cells:(##(size * 8))
roots:(##(size * 8)) { roots >= 1 }
absent:(##(size * 8)) { roots + absent <= cells }
tot_cells_size:(##(off_bytes * 8))
root_list:(roots * ##(size * 8))
index:has_idx?(cells * ##(off_bytes * 8))
cell_data:(tot_cells_size * [ uint8 ])
crc32c:has_crc32c?uint32
= BagOfCells;

Глубокое понимание этой структуры не требуется — инструменты разработки и SDK TON помогают, беря её обработку на себя.

Поиск транзакции с помощью BoC

Когда пользователь подтверждает отправку внешнего сообщения с помощью TON Connect, вы получаете BoC. Вы можете использовать его для поиска соответствующей транзакции в блокчейне.

Пример использования:

Давайте рассмотрим пример отправки внешнего сообщения с помощью TON Connect в приложении на React. Мы используем проект demo-dapp-with-react-ui в качестве примера для получения BoC и хеша для поиска транзакции.

В этом проекте перейдите в src/components/TxForm и замените содержимое React-файла TxForm.tsx следующим кодом:

Получение BoC и хеша в примере на React
TxForm.tsx
import React, { useState } from 'react';
import './style.scss';
import { SendTransactionRequest, useTonConnectUI } from "@tonconnect/ui-react";
import { Address, beginCell, Cell, loadMessage } from '@ton/ton';

// This example uses a predefined smart contract `stateInit`.
// to interact with an EchoContract — a contract that returns the sent value back to the sender.
// This is useful for testing, as it prevents unintentional token loss.
const defaultTx: SendTransactionRequest = {
// The transaction is valid for 10 minutes from the current time (in Unix epoch seconds).
validUntil: Math.floor(Date.now() / 1000) + 600,
messages: [
{
// Insert the recipient address
address: 'your address',
// Amount to send in nanoTON. For example, 0.005 TON is 5000000 nanoTON.
amount: '5000',
// (Optional) State initialization in BOC (base64).
stateInit: 'te6cckEBBAEAOgACATQCAQAAART/APSkE/S88sgLAwBI0wHQ0wMBcbCRW+D6QDBwgBDIywVYzxYh+gLLagHPFsmAQPsAlxCarA==',
} ,

],
};

/**
* Normalize an external message according to TEP-467:
* https://github.com/ton-blockchain/TEPs/blob/master/text/0467-normalized-message-hash.md
*
* Normalization rules:
* 1. Source Address (`src`): always set to `addr_none$00`
* 2. Import Fee (`import_fee`): always set to `0`
* 3. Init State (`init`): always set to empty
* 4. Body: always stored as a reference
*/

function normalizeExternalMessage(destAddress: Address, bodyCell: Cell): Cell {
return beginCell()
.storeUint(0b10, 2)
.storeUint(0, 2)
.storeAddress(destAddress)
.storeCoins(0)
.storeBit(false)
.storeBit(true)
.storeRef(bodyCell)
.endCell();
}

export function TxForm() {
const [boc, setBoc] = useState<string | null>(null);
const [hash, setHash] = useState<string | null>(null);
const [normalizedHash, setNormalizedHash] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [isSending, setIsSending] = useState(false);
const [tonConnectUi] = useTonConnectUI();

const send = async () => {
setIsSending(true);
setError(null);
setBoc(null);
setHash(null);
setNormalizedHash(null);
try {
const result = await tonConnectUi.sendTransaction(defaultTx);
const receivedBoc = result.boc;
setBoc(receivedBoc);
const externalMessageCell = Cell.fromBoc(Buffer.from(receivedBoc, 'base64'))[0];
const originalHash = externalMessageCell.hash().toString('hex');
setHash(originalHash);

const message = loadMessage(externalMessageCell.beginParse());
if (message.info.type !== 'external-in')
throw new Error(`Expected an external-in message, got ${message.info.type}.`);

const destAddress = message.info.dest;
if (!destAddress || !(destAddress instanceof Address)) {
throw new Error('Destination address not found in the parsed message.');
}

const bodyCell = message.body;
const normalizedExtMessage = normalizeExternalMessage(destAddress, bodyCell);
setNormalizedHash(normalizedExtMessage.hash().toString('hex'));
} catch (e) {
setError((e as Error).message);
} finally {
setIsSending(false);
}
};

return (
<div className="send-tx-form">
<button onClick={send} disabled={isSending}>
{isSending ? 'Sending...' : 'Send transaction'}
</button>

{error && <p style={{ color: 'red' }}>Error: {error}</p>}

{boc && (
<div className="boc-hash-block">
<span className="boc-label">BOC (base64):</span>
<pre className="boc-pre">{boc}</pre>

<span className="hash-label">Original hash to find a transaction:</span>
<pre>{hash}</pre>

<span className="hash-label">Normalized hash (TEP-467):</span>
<pre>{normalizedHash}</pre>

{hash && normalizedHash && (
<div
style={{
marginTop: '10px',
padding: '10px',
backgroundColor: hash === normalizedHash ? '#d4edda' : '#f8d7da',
borderRadius: '5px',
}}
>
<strong>Hashes {hash === normalizedHash ? 'MATCH' : 'DO NOT MATCH'}</strong>
{hash !== normalizedHash && (
<div style={{ fontSize: '12px', marginTop: '5px' }}>
The original message is not normalized according to TEP-467.
</div>
)}
</div>
)}
</div>
)}
</div>
);
}

При выполнении этого кода запускается демонстрационное dApp-приложение. Чтобы продолжить:

  • Подключите ваш кошелёк Tonkeeper.
  • Нажмите кнопку Отправить транзакцию.
  • Подтвердите транзакцию в вашем кошельке.

После отправки транзакции в пользовательском интерфейсе отобразятся следующие поля:

  • BOC (base64) — необработанное внешнее сообщение в формате base64.
  • Оригинальный хеш — хеш отправленного сообщения. Вы можете использовать его для поиска транзакции в блокчейне.
  • Нормализованный хеш (TEP-467) — хеш, вычисленный после нормализации, используется для консистентной идентификации сообщений.
Поиск транзакции с помощью BoC
trx_lookup_via_boc.ts
// Check transaction by its hash
async function checkTransactionStatus(txHash: string, walletAddress: string) {
try {
const response = await fetch(
`https://testnet.toncenter.com/api/v2/getTransactions?` + `address=${walletAddress}&hash=${txHash}`,
);
const data = await response.json();

if (data.result.length > 0) {
console.log('Transaction found on the blockchain');
const viewerUrl = `https://testnet.tonviewer.com/transaction/${trxHash}`;
console.log('Transaction link:', viewerUrl);
return data.result[0];
} else {
console.log('Transaction not found');
return null;
}
} catch (error) {
console.error('Error while checking transaction:', error);
return null;
}
}

const walletAddress = 'insert your wallet address';
// Here you can insert the hash that you obtained from the react example
const trxHash = 'insert the transaction hash';

checkTransactionStatus(trxHash, walletAddress);

Ожидаемый вывод в консоль

Transaction found on the blockchain
Transaction link: https://testnet.tonviewer.com/transaction/ad53eb8d1145b239d615dfd3bffb1b9cb7c8c5823530dc217d988fb89794f59a

Проверка статуса транзакции с помощью хеша

status_api.ts
// Check the transaction status by its hash
async function checkTransactionStatus(txHash: string, walletAddress: string) {
try {
const response = await fetch(
`https://testnet.toncenter.com/api/v2/getTransactions?` + `address=${walletAddress}&hash=${txHash}`,
);
const data = await response.json();

if (data.result.length > 0) {
console.log('Transaction found on the blockchain');
const viewerUrl = `https://testnet.tonviewer.com/transaction/${trxHash}`;
console.log('Transaction link:', viewerUrl);
return data.result[0];
} else {
console.log('Transaction not found');
return null;
}
} catch (error) {
console.error('Error while checking transaction status:', error);
return null;
}
}

const walletAddress = 'your address';
const trxHash = 'your trx hash';

checkTransactionStatus(trxHash, walletAddress);

Ожидаемый вывод в консоль

Transaction found on the blockchain
Transaction link: https://testnet.tonviewer.com/transaction/df51860233d75...

Валидация адреса с помощью хеша StateInit

С TON Connect часто требуется проверить, что адрес кошелька соответствует его StateInit. Хеш StateInit должен соответствовать определённой части адреса.

Практический пример проверки адреса:

Получите StateInit кошелька:

get_stateinit.ts
import { WalletContractV4, beginCell } from '@ton/ton';
import { mnemonicToPrivateKey } from '@ton/crypto';

async function getStateInit() {
try {
const mnemonic = 'your mnemonic'.split(' '); // Insert your seed phrase here
const keyPair = await mnemonicToPrivateKey(mnemonic);

// Create a wallet V4
const wallet = WalletContractV4.create({
publicKey: keyPair.publicKey,
workchain: 0,
});

// Generate the StateInit cell
const stateInitCell = beginCell().storeRef(wallet.init.code).storeRef(wallet.init.data).endCell();
const stateInitBase64 = stateInitCell.toBoc().toString('base64');

console.log('StateInit (base64):', stateInitBase64);
console.log('Wallet address:', wallet.address.toString({ bounceable: true }));
console.log('Public key (hex):', Buffer.from(keyPair.publicKey).toString('hex'));

return stateInitBase64;
} catch (error) {
console.error('Error:', error);
}
}

getStateInit().catch(console.error);

Ожидаемый вывод в консоль

StateInit (base64): te6cckECFgEAAwMAAgABFQEU/wD0pBP0vPL....
Wallet address: EQD3oTH51Tp4UNhCLfX3axyG2X9H_9wZpLoC7W--WbXwxW9m
Public key (hex): f102a5c140272019550b05e6a50b2072aa737dd3c5948622ddf1ca249b6e0f00

Теперь сравните адрес кошелька со сгенерированным StateInit.

address_verification.ts
import { Address, Cell, contractAddress } from '@ton/ton';

// Your data
const wantedAddress = Address.parse('your address');
const stateInitBase64 = 'your state init'; // Insert your StateInit (base64) here

const cell = Cell.fromBase64(stateInitBase64);
// Typically, code = cell.refs[0], data = cell.refs[1]
const stateInit = {
code: cell.refs[0],
data: cell.refs[1],
};

// Derive the address from WorkChain and StateInit
const calculatedAddress = contractAddress(wantedAddress.workChain, stateInit);

console.log('Expected address: ', wantedAddress.toString({ bounceable: false }));
console.log('Calculated address:', calculatedAddress.toString({ bounceable: false }));

if (calculatedAddress.equals(wantedAddress)) {
console.log('StateInit matches the address!');
} else {
console.log('StateInit does NOT match the address!');
}

Ожидаемый вывод в консоль

Expected address:    UQD3oTH51Tp4UNhCLfX3axyG2X9H_9wZpYoC7W--WbXxxTKj
Calculated address: UQD3oTH51Tp4UNhCLfX3axyG2X9H_9wZpYoC7W--WbXxxTKj
StateInit matches the address!

Поиск транзакции по хешу сообщения

Пример ниже показывает, как создать слушателя (listener), который получает данные о транзакции, как только они становятся доступными.

Код
trxs_monitoring.ts

import { Address, TonClient, beginCell, storeMessage } from '@ton/ton';

// Example function to monitor incoming transactions
async function monitorIncomingTransactions(walletAddress: Address, client: TonClient) {
let lastLt = 0n;

setInterval(async () => {
try {
const transactions = await client.getTransactions(walletAddress, {
limit: 10,
lt: lastLt.toString(),
});

for (const tx of transactions) {
if (tx.lt > lastLt) {
const txHash = tx.hash();
console.log('New transaction:', txHash.toString('hex'));
const viewerUrl = `https://testnet.tonviewer.com/transaction/${txHash.toString('hex')}`;
console.log('Transaction link:', viewerUrl);

// Process incoming messages
if (tx.inMessage) {
const msgCell = beginCell().store(storeMessage(tx.inMessage)).endCell();
const msgHash = msgCell.hash();
console.log('Message hash:', msgHash.toString('hex'));
}

lastLt = tx.lt;
}
}
} catch (error) {
console.error('Monitoring error:', error);
}
}, 5000); // Check every 5 seconds
}

const walletAddress = Address.parse('Insert your address here');
const client = new TonClient({ endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC' });

monitorIncomingTransactions(walletAddress, client);

Ожидаемый вывод в консоль

New transaction: 2e995e47f47bb95f1802337f4a63841b93aa8972aabba545048ef286dcc14309
Transaction link: https://testnet.tonviewer.com/transaction/2e995e47f47bb95f1802337f4a63841b93aa8972aabba545048ef286dcc14309
Message hash: 8263a63380532154a3850aa1d2dca719bf768845738c8177d889af05826626c8

Следующий шаг

Мы рассмотрели, как каждому сообщению и транзакции в TON присваивается уникальный криптографический отпечаток — хеш. Эти хеши позволяют нам верифицировать контент, обнаруживать дубликаты и отслеживать весь поток выполнения в блокчейне.

Теперь давайте рассмотрим, как получать и анализировать транзакции с помощью API, превращая хеши в данные, на основе которых можно действовать.

Обрабатывайте транзакции с помощью API

Was this article useful?