diff --git a/docs/develop/dapps/asset-processing/README.md b/docs/develop/dapps/asset-processing/README.md
index 85805bd952..f16970ae4f 100644
--- a/docs/develop/dapps/asset-processing/README.md
+++ b/docs/develop/dapps/asset-processing/README.md
@@ -256,6 +256,10 @@ To generate a transaction link in the explorer, the service needs to get the lt
`https://explorer.toncoin.org/transaction?account={account address}<={lt as int}&hash={txhash as base64url}`
+Note that tonviewer and tonscan supports external-in msg hash instead of transaction hash for link in explorer.
+That can become useful when you generate external message and want instant link generation.
+More about transactions and messages hashes [here](/develop/dapps/cookbook#how-to-find-transaction-or-message-hash)
+
## Best Practices
### Wallet creation
@@ -569,4 +573,4 @@ if __name__ == "__main__":
## SDKs
-You can find a list of SDKs for various languages (JS, Python, Golang, C#, Rust, etc.) list [here](/develop/dapps/apis/sdk).
\ No newline at end of file
+You can find a list of SDKs for various languages (JS, Python, Golang, C#, Rust, etc.) list [here](/develop/dapps/apis/sdk).
diff --git a/docs/develop/dapps/cookbook.mdx b/docs/develop/dapps/cookbook.mdx
index 984a8df114..93fdd77556 100644
--- a/docs/develop/dapps/cookbook.mdx
+++ b/docs/develop/dapps/cookbook.mdx
@@ -855,7 +855,7 @@ Smart contracts for collections allow deploying up to 250 NFTs in a single trans
#### Batch mint NFT
:::info
Does not specified by NFT standard for /ton-blockchain /token-contract
-:::
+:::
-## Basics of incoming message processing
+## Basics of message processing
### How to parse transactions of an account (Transfers, Jettons, NFTs)?
@@ -1703,17 +1703,17 @@ async def parse_transactions(transactions):
value = transaction.in_msg.info.value_coins
if value != 0:
value = value / 1e9
-
+
if len(transaction.in_msg.body.bits) < 32:
print(f"TON transfer from {sender} with value {value} TON")
else:
body_slice = transaction.in_msg.body.begin_parse()
op_code = body_slice.load_uint(32)
-
+
# TextComment
if op_code == 0:
print(f"TON transfer from {sender} with value {value} TON and comment: {body_slice.load_snake_string()}")
-
+
# Jetton Transfer Notification
elif op_code == 0x7362d09c:
body_slice.load_bits(64) # skip query_id
@@ -1723,7 +1723,7 @@ async def parse_transactions(transactions):
forward_payload = body_slice.load_ref().begin_parse()
else:
forward_payload = body_slice
-
+
jetton_master = (await provider.run_get_method(address=sender, method="get_wallet_data", stack=[]))[2].load_address()
jetton_wallet = (await provider.run_get_method(address=jetton_master, method="get_wallet_address",
stack=[
@@ -1733,7 +1733,7 @@ async def parse_transactions(transactions):
if jetton_wallet != sender:
print("FAKE Jetton Transfer")
continue
-
+
if len(forward_payload.bits) < 32:
print(f"Jetton transfer from {jetton_sender} with value {jetton_amount} Jetton")
else:
@@ -1742,7 +1742,7 @@ async def parse_transactions(transactions):
print(f"Jetton transfer from {jetton_sender} with value {jetton_amount} Jetton and comment: {forward_payload.load_snake_string()}")
else:
print(f"Jetton transfer from {jetton_sender} with value {jetton_amount} Jetton and unknown payload: {forward_payload} ")
-
+
# NFT Transfer Notification
elif op_code == 0x05138d91:
body_slice.load_bits(64) # skip query_id
@@ -1825,7 +1825,7 @@ export async function retry(fn: () => Promise, options: { retries: number,
```
-Create listener function which will assert specific transaction on certain account with specific incoming external message, equal to body message in boc:
+Create listener function which will assert specific transaction on certain account with specific incoming external message, equal to body message in boc:
@@ -1883,10 +1883,83 @@ export async function getTxByBOC(exBoc: string): Promise {
txRes = getTxByBOC(exBOC);
console.log(txRes);
-
-
```
-
\ No newline at end of file
+
+
+### How to find transaction or message hash?
+
+:::info
+Be careful with the hash definition. It can be either a transaction hash or a message hash. These are different things.
+:::
+
+To get transaction hash you need to use `hash` method of a transaction. To get external message hash you need
+to build message cell using `storeMessage` method and then use `hash` method of this cell.
+
+
+
+
+```typescript
+import { storeMessage, TonClient } from '@ton/ton';
+import { Address, beginCell } from '@ton/core';
+
+const tonClient = new TonClient({ endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC' });
+
+const transactions = await tonClient.getTransactions(Address.parse('[ADDRESS]'), { limit: 10 });
+for (const transaction of transactions) {
+ // ful transaction hash
+ const transactionHash = transaction.hash();
+
+ const inMessage = transaction.inMessage;
+ if (inMessage?.info.type === 'external-in') {
+ const inMessageCell = beginCell().store(storeMessage(inMessage)).endCell();
+ // external-in message hash
+ const inMessageHash = inMessageCell.hash();
+ }
+
+ // also you can get hash of out messages if needed
+ for (const outMessage of transaction.outMessages.values()) {
+ const outMessageCell = beginCell().store(storeMessage(outMessage)).endCell();
+ const outMessageHash = outMessageCell.hash();
+ }
+}
+```
+
+
+
+
+
+Also you can get hash of message when building it. Note, this is the same hash as the hash of the message sent to initiate transaction
+like in previous example.
+
+
+
+
+```typescript
+import { mnemonicNew, mnemonicToPrivateKey } from '@ton/crypto';
+import { internal, TonClient, WalletContractV4 } from '@ton/ton';
+import { toNano } from '@ton/core';
+
+const tonClient = new TonClient({ endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC' });
+
+const mnemonic = await mnemonicNew();
+const keyPair = await mnemonicToPrivateKey(mnemonic);
+const wallet = tonClient.open(WalletContractV4.create({ publicKey: keyPair.publicKey, workchain: 0 }));
+const transfer = await wallet.createTransfer({
+ secretKey: keyPair.secretKey,
+ seqno: 0,
+ messages: [
+ internal({
+ to: wallet.address,
+ value: toNano(1)
+ })
+ ]
+});
+const inMessageHash = transfer.hash();
+```
+
+
+
+