Skip to content

Commit b53a6c9

Browse files
Add transaction and messages hashes examples (#718)
Co-authored-by: Aliaksandr Bahdanau <a.bahdanau@pixelplex.io>
1 parent 72a3ea7 commit b53a6c9

File tree

2 files changed

+92
-15
lines changed

2 files changed

+92
-15
lines changed

docs/develop/dapps/asset-processing/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,10 @@ To generate a transaction link in the explorer, the service needs to get the lt
256256

257257
`https://explorer.toncoin.org/transaction?account={account address}&lt={lt as int}&hash={txhash as base64url}`
258258

259+
Note that tonviewer and tonscan supports external-in msg hash instead of transaction hash for link in explorer.
260+
That can become useful when you generate external message and want instant link generation.
261+
More about transactions and messages hashes [here](/develop/dapps/cookbook#how-to-find-transaction-or-message-hash)
262+
259263
## Best Practices
260264

261265
### Wallet creation
@@ -569,4 +573,4 @@ if __name__ == "__main__":
569573

570574
## SDKs
571575

572-
You can find a list of SDKs for various languages (JS, Python, Golang, C#, Rust, etc.) list [here](/develop/dapps/apis/sdk).
576+
You can find a list of SDKs for various languages (JS, Python, Golang, C#, Rust, etc.) list [here](/develop/dapps/apis/sdk).

docs/develop/dapps/cookbook.mdx

Lines changed: 87 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -855,7 +855,7 @@ Smart contracts for collections allow deploying up to 250 NFTs in a single trans
855855
#### Batch mint NFT
856856
:::info
857857
Does not specified by NFT standard for /ton-blockchain /token-contract
858-
:::
858+
:::
859859
<br></br>
860860
<div class="text--center">
861861
<ThemedImage
@@ -1490,7 +1490,7 @@ async def main():
14901490
stack=[pool_type, asset_native, asset_jetton]
14911491
)
14921492
pool_address = stack[0].load_address()
1493-
1493+
14941494
swap_params = (begin_cell()
14951495
.store_uint(int(time.time() + 60 * 5), 32) # Deadline
14961496
.store_address(wallet.address) # Recipient address
@@ -1512,7 +1512,7 @@ async def main():
15121512
await wallet.transfer(destination=DEDUST_NATIVE_VAULT,
15131513
amount=TON_AMOUNT + GAS_AMOUNT, # swap amount + gas
15141514
body=swap_body)
1515-
1515+
15161516
await provider.close_all()
15171517

15181518
asyncio.run(main())
@@ -1521,7 +1521,7 @@ asyncio.run(main())
15211521
</TabItem>
15221522
</Tabs>
15231523
1524-
## Basics of incoming message processing
1524+
## Basics of message processing
15251525
15261526
### How to parse transactions of an account (Transfers, Jettons, NFTs)?
15271527
@@ -1703,17 +1703,17 @@ async def parse_transactions(transactions):
17031703
value = transaction.in_msg.info.value_coins
17041704
if value != 0:
17051705
value = value / 1e9
1706-
1706+
17071707
if len(transaction.in_msg.body.bits) < 32:
17081708
print(f"TON transfer from {sender} with value {value} TON")
17091709
else:
17101710
body_slice = transaction.in_msg.body.begin_parse()
17111711
op_code = body_slice.load_uint(32)
1712-
1712+
17131713
# TextComment
17141714
if op_code == 0:
17151715
print(f"TON transfer from {sender} with value {value} TON and comment: {body_slice.load_snake_string()}")
1716-
1716+
17171717
# Jetton Transfer Notification
17181718
elif op_code == 0x7362d09c:
17191719
body_slice.load_bits(64) # skip query_id
@@ -1723,7 +1723,7 @@ async def parse_transactions(transactions):
17231723
forward_payload = body_slice.load_ref().begin_parse()
17241724
else:
17251725
forward_payload = body_slice
1726-
1726+
17271727
jetton_master = (await provider.run_get_method(address=sender, method="get_wallet_data", stack=[]))[2].load_address()
17281728
jetton_wallet = (await provider.run_get_method(address=jetton_master, method="get_wallet_address",
17291729
stack=[
@@ -1733,7 +1733,7 @@ async def parse_transactions(transactions):
17331733
if jetton_wallet != sender:
17341734
print("FAKE Jetton Transfer")
17351735
continue
1736-
1736+
17371737
if len(forward_payload.bits) < 32:
17381738
print(f"Jetton transfer from {jetton_sender} with value {jetton_amount} Jetton")
17391739
else:
@@ -1742,7 +1742,7 @@ async def parse_transactions(transactions):
17421742
print(f"Jetton transfer from {jetton_sender} with value {jetton_amount} Jetton and comment: {forward_payload.load_snake_string()}")
17431743
else:
17441744
print(f"Jetton transfer from {jetton_sender} with value {jetton_amount} Jetton and unknown payload: {forward_payload} ")
1745-
1745+
17461746
# NFT Transfer Notification
17471747
elif op_code == 0x05138d91:
17481748
body_slice.load_bits(64) # skip query_id
@@ -1825,7 +1825,7 @@ export async function retry<T>(fn: () => Promise<T>, options: { retries: number,
18251825

18261826
```
18271827
1828-
Create listener function which will assert specific transaction on certain account with specific incoming external message, equal to body message in boc:
1828+
Create listener function which will assert specific transaction on certain account with specific incoming external message, equal to body message in boc:
18291829
18301830
<Tabs>
18311831
<TabItem value="ts" label="@ton/ton">
@@ -1883,10 +1883,83 @@ export async function getTxByBOC(exBoc: string): Promise<string> {
18831883

18841884
txRes = getTxByBOC(exBOC);
18851885
console.log(txRes);
1886-
1887-
18881886
```
18891887
18901888
</TabItem>
18911889
1892-
</Tabs>
1890+
</Tabs>
1891+
1892+
### How to find transaction or message hash?
1893+
1894+
:::info
1895+
Be careful with the hash definition. It can be either a transaction hash or a message hash. These are different things.
1896+
:::
1897+
1898+
To get transaction hash you need to use `hash` method of a transaction. To get external message hash you need
1899+
to build message cell using `storeMessage` method and then use `hash` method of this cell.
1900+
1901+
<Tabs>
1902+
<TabItem value="ts" label="@ton/ton">
1903+
1904+
```typescript
1905+
import { storeMessage, TonClient } from '@ton/ton';
1906+
import { Address, beginCell } from '@ton/core';
1907+
1908+
const tonClient = new TonClient({ endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC' });
1909+
1910+
const transactions = await tonClient.getTransactions(Address.parse('[ADDRESS]'), { limit: 10 });
1911+
for (const transaction of transactions) {
1912+
// ful transaction hash
1913+
const transactionHash = transaction.hash();
1914+
1915+
const inMessage = transaction.inMessage;
1916+
if (inMessage?.info.type === 'external-in') {
1917+
const inMessageCell = beginCell().store(storeMessage(inMessage)).endCell();
1918+
// external-in message hash
1919+
const inMessageHash = inMessageCell.hash();
1920+
}
1921+
1922+
// also you can get hash of out messages if needed
1923+
for (const outMessage of transaction.outMessages.values()) {
1924+
const outMessageCell = beginCell().store(storeMessage(outMessage)).endCell();
1925+
const outMessageHash = outMessageCell.hash();
1926+
}
1927+
}
1928+
```
1929+
1930+
</TabItem>
1931+
1932+
</Tabs>
1933+
1934+
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
1935+
like in previous example.
1936+
1937+
<Tabs>
1938+
<TabItem value="ts" label="@ton/ton">
1939+
1940+
```typescript
1941+
import { mnemonicNew, mnemonicToPrivateKey } from '@ton/crypto';
1942+
import { internal, TonClient, WalletContractV4 } from '@ton/ton';
1943+
import { toNano } from '@ton/core';
1944+
1945+
const tonClient = new TonClient({ endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC' });
1946+
1947+
const mnemonic = await mnemonicNew();
1948+
const keyPair = await mnemonicToPrivateKey(mnemonic);
1949+
const wallet = tonClient.open(WalletContractV4.create({ publicKey: keyPair.publicKey, workchain: 0 }));
1950+
const transfer = await wallet.createTransfer({
1951+
secretKey: keyPair.secretKey,
1952+
seqno: 0,
1953+
messages: [
1954+
internal({
1955+
to: wallet.address,
1956+
value: toNano(1)
1957+
})
1958+
]
1959+
});
1960+
const inMessageHash = transfer.hash();
1961+
```
1962+
1963+
</TabItem>
1964+
1965+
</Tabs>

0 commit comments

Comments
 (0)