Skip to content

Commit

Permalink
Add transaction and messages hashes examples (#718)
Browse files Browse the repository at this point in the history
Co-authored-by: Aliaksandr Bahdanau <[email protected]>
  • Loading branch information
pixelplex and a-bahdanau authored Aug 28, 2024
1 parent 72a3ea7 commit b53a6c9
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 15 deletions.
6 changes: 5 additions & 1 deletion docs/develop/dapps/asset-processing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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={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
Expand Down Expand Up @@ -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).
You can find a list of SDKs for various languages (JS, Python, Golang, C#, Rust, etc.) list [here](/develop/dapps/apis/sdk).
101 changes: 87 additions & 14 deletions docs/develop/dapps/cookbook.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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
:::
:::
<br></br>
<div class="text--center">
<ThemedImage
Expand Down Expand Up @@ -1490,7 +1490,7 @@ async def main():
stack=[pool_type, asset_native, asset_jetton]
)
pool_address = stack[0].load_address()

swap_params = (begin_cell()
.store_uint(int(time.time() + 60 * 5), 32) # Deadline
.store_address(wallet.address) # Recipient address
Expand All @@ -1512,7 +1512,7 @@ async def main():
await wallet.transfer(destination=DEDUST_NATIVE_VAULT,
amount=TON_AMOUNT + GAS_AMOUNT, # swap amount + gas
body=swap_body)

await provider.close_all()

asyncio.run(main())
Expand All @@ -1521,7 +1521,7 @@ asyncio.run(main())
</TabItem>
</Tabs>
## Basics of incoming message processing
## Basics of message processing
### How to parse transactions of an account (Transfers, Jettons, NFTs)?
Expand Down Expand Up @@ -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
Expand All @@ -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=[
Expand All @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -1825,7 +1825,7 @@ export async function retry<T>(fn: () => Promise<T>, 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:
<Tabs>
<TabItem value="ts" label="@ton/ton">
Expand Down Expand Up @@ -1883,10 +1883,83 @@ export async function getTxByBOC(exBoc: string): Promise<string> {

txRes = getTxByBOC(exBOC);
console.log(txRes);


```
</TabItem>
</Tabs>
</Tabs>
### 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.
<Tabs>
<TabItem value="ts" label="@ton/ton">
```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();
}
}
```
</TabItem>
</Tabs>
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.
<Tabs>
<TabItem value="ts" label="@ton/ton">
```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();
```
</TabItem>
</Tabs>

0 comments on commit b53a6c9

Please sign in to comment.