diff --git a/docs/develop/dapps/ton-connect/developers.md b/docs/develop/dapps/ton-connect/developers.md index ea9e1f7fed..d8d23f7d63 100644 --- a/docs/develop/dapps/ton-connect/developers.md +++ b/docs/develop/dapps/ton-connect/developers.md @@ -1,25 +1,21 @@ -# Supported SDKs +# TON Connect SDKs -This page contents the list of supported libraries for TON Connect. - -* [TON Connect JS SDK](/develop/dapps/ton-connect/developers#ton-connect-js-sdk) -* [TON Connect Python SDK](/develop/dapps/ton-connect/developers#ton-connect-python) -* [TON Connect Dart SDK](/develop/dapps/ton-connect/developers#ton-connect-dart) - -## TON Connect JS SDK +## SDK List +:::info +If possible, it is recommended to use the [@tonconnect/ui-react](/develop/dapps/ton-connect/developers#ton-connect-ui-react) kit for your dApps. Only switch to lower levels of the SDK or reimplement your version of the protocol if it is really necessary for your product. +::: -The TON Connect repository contains the following main packages: +This page contents the list of useful libraries for TON Connect. -- [@tonconnect/ui-react](/develop/dapps/ton-connect/developers#ton-connect-ui-react) - TON Connect User Interface (UI) for React *(recommended)* -- [@tonconnect/ui](/develop/dapps/ton-connect/developers#ton-connect-ui) - TON Connect User Interface (UI) -- [@tonconnect/sdk](/develop/dapps/ton-connect/developers#ton-connect-sdk) - low-level TON Connect SDK -- [@tonconnect/protocol](/develop/dapps/ton-connect/developers#ton-connect-protocol-models) - TON Connect protocol specifications - -It is recommended to use the [@tonconnect/ui-react](/develop/dapps/ton-connect/developers#ton-connect-ui-react) kit for your DApps. Only switch to lower levels of the SDK if it is really necessary for your product. +* [TON Connect React](/develop/dapps/ton-connect/developers#ton-connect-react) +* [TON Connect JS SDK](/develop/dapps/ton-connect/developers#ton-connect-js-sdk) +* [TON Connect Python SDK](/develop/dapps/ton-connect/developers#ton-connect-python) +* [TON Connect Dart](/develop/dapps/ton-connect/developers#ton-connect-dart) +## TON Connect React -### TON Connect UI React +- [@tonconnect/ui-react](/develop/dapps/ton-connect/developers#ton-connect-ui-react) - TON Connect User Interface (UI) for React applications TonConnect UI React is a React UI kit for TonConnect SDK. Use it to connect your app to TON wallets via TonConnect protocol in React apps. @@ -34,6 +30,16 @@ npm i @tonconnect/ui-react - [NPM](https://www.npmjs.com/package/@tonconnect/ui-react) - [API Documentation](https://ton-connect.github.io/sdk/modules/_tonconnect_ui_react.html) + +## TON Connect JS SDK + +The TON Connect repository contains following main packages: + +- [@tonconnect/ui](/develop/dapps/ton-connect/developers#ton-connect-ui) - TON Connect User Interface (UI) +- [@tonconnect/sdk](/develop/dapps/ton-connect/developers#ton-connect-sdk) - TON Connect SDK +- [@tonconnect/protocol](/develop/dapps/ton-connect/developers#ton-connect-protocol-models) - TON Connect protocol specifications + + ### TON Connect UI TonConnect UI is a UI kit for TonConnect SDK. Use it to connect your app to TON wallets via TonConnect protocol. It allows you to integrate TonConnect to your app easier using our UI elements such as "connect wallet button", "select wallet dialog" and confirmation modals. @@ -109,6 +115,8 @@ If you experience any additional issues, or would like to present a proposal on ## See Also +* [Step by step guide for building your first web client](https://ton-community.github.io/tutorials/03-client/) +* [[YouTube] TON Smart Contracts | 10 | Telegram dapp [EN]](https://www.youtube.com/watch?v=D6t3eZPdgAU&t=254s&ab_channel=AlefmanVladimir%5BEN%5D) * [Ton Connect Getting started](https://github.com/ton-connect/sdk/tree/main/packages/sdk) * [Integration Manual](/develop/dapps/ton-connect/integration) -* [[YouTube] TON Dev Study TON Connect Protocol [RU]](https://www.youtube.com/playlist?list=PLyDBPwv9EPsCJ226xS5_dKmXXxWx1CKz_) \ No newline at end of file +* [[YouTube] TON Dev Study TON Connect Protocol [RU]](https://www.youtube.com/playlist?list=PLyDBPwv9EPsCJ226xS5_dKmXXxWx1CKz_) diff --git a/docs/develop/dapps/ton-connect/message-builders.mdx b/docs/develop/dapps/ton-connect/message-builders.mdx new file mode 100644 index 0000000000..cced9e4d04 --- /dev/null +++ b/docs/develop/dapps/ton-connect/message-builders.mdx @@ -0,0 +1,833 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Preparing Messages + +While using TON Connect, you should construct the Message Body for the Payload used in various transactions. On this page you can find the most relevant examples of payload for use with the TON Connect SDKs. + +:::warning +The page is under development. +::: + +:::info +It is expected, that you learn basics on the creating TON Connect connection. Learn more with the [integration manual](/develop/dapps/ton-connect/integration). +::: + + +## TON Connect JS SDK Examples + +### Transaction Template + +No matter what level of the task developer are solving, typically it is necessary to use connector entity from @tonconnect/sdk or @tonconnect/ui. +Examples created based on @tonconnect/sdk and @tonconnect/ui: + + + + + +```js +import { useTonConnectUI } from '@tonconnect/ui-react'; +const [tonConnectUI] = useTonConnectUI(); + +const transaction = { + //transaction body +}) + +export const Settings = () => { + const [tonConnectUI, setOptions] = useTonConnectUI(); + + return ( +
+ +
+ ); +}; +``` + +
+ + +```js +import TonConnect from '@tonconnect/ui'; + +const tonConnectUI = new TonConnectUI({ //connect application + manifestUrl: 'https:///tonconnect-manifest.json', + buttonRootId: '' +}); + +transaction = { + //transaction body +} + +const result = await tonConnectUI.sendTransaction(transaction) + +``` + + + + +```js +import TonConnect from '@tonconnect/sdk'; +const connector = new TonConnect(); + +await connector.sendTransaction({ + //transaction body +}) + +``` + + + +
+ +### Regular TON Transfer + +TON Connect SDKs include wrappers for sending messages, making it easy to prepare regular transfers of Toncoins between two wallets as default transaction without payload. + +A regular TON transfer using the TON Connect JS SDKs can be executed as follows: + + + + + +```js +import { useTonConnectUI } from '@tonconnect/ui-react'; +const [tonConnectUI] = useTonConnectUI(); + +const transaction = { + messages: [ + { + address: "0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F", // destination address + amount: "20000000" //Toncoin in nanotons + } + ] + +} + +export const Settings = () => { + const [tonConnectUI, setOptions] = useTonConnectUI(); + + return ( +
+ +
+ ); +}; +``` + +
+ + + +```js +import TonConnect from '@tonconnect/ui'; + +const tonConnectUI = new TonConnectUI({ //connect application + manifestUrl: 'https:///tonconnect-manifest.json', + buttonRootId: '' +}); + +transaction = { + messages: [ + { + address: "0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F", // destination address + amount: "20000000" //Toncoin in nanotons + } + ] +} + +const result = await tonConnectUI.sendTransaction(transaction) +``` + + + + + + +```js +import TonConnect from '@tonconnect/sdk'; +const connector = new TonConnect(); + +await connector.sendTransaction({ + messages: [ + { + address: "0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F", // destination address + amount: "20000000" //Toncoin in nanotons + } + ] +}) + +``` + +
+ +:::tip +Learn more about [TON Smart Contract Addresses](/learn/overviews/addresses). +::: + +For specific custom transaction, a certain payload must be defined. + + + + +### Transfer With a Comment + +The simplest example is adding a payload with a comment. See more details on [this page](/develop/smart-contracts/guidelines/internal-messages#simple-message-with-comment). +Before transaction, it is necessary prepare a `body` [cell](/develop/data-formats/cell-boc) via the [@ton/ton](https://github.com/ton-org/ton) JavaScript library. + +```js +import { beginCell } from '@ton/ton' + +const body = beginCell() + .storeUint(0, 32) // write 32 zero bits to indicate that a text comment will follow + .storeStringTail("Hello, TON!") // write our text comment + .endCell(); +``` + +The transaction body is created by the following: + + + + + +```js +import { useTonConnectUI } from '@tonconnect/ui-react'; + +const myTransaction = { + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: destination, + amount: toNano("0.05"), + payload: body.toBoc().toString("base64") + } + ] +} + +export const Settings = () => { + const [tonConnectUI, setOptions] = useTonConnectUI(); + + return ( +
+ +
+ ); +}; +``` +
+ + + +```js +import TonConnectUI from '@tonconnect/ui' + +const transaction = { + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: destination, + amount: toNano("0.05"), + payload: body.toBoc().toString("base64") + } + ] +} + +const result = await tonConnectUI.sendTransaction(transaction) +``` + + + + + +```js +import TonConnect from '@tonconnect/sdk'; +const connector = new TonConnect(); + +await connector.sendTransaction({ + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: destination, + amount: toNano("0.05"), + payload: body.toBoc().toString("base64") + } + ] +}) +``` + +
+ + +### Jetton Transfer + +The `body` for Jetton Transfer([TEP-74](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md#1-transfer)) typically should be done according the following way: + +```js + import {beginCell, toNano} from '@ton/ton' + // transfer#0f8a7ea5 query_id:uint64 amount:(VarUInteger 16) destination:MsgAddress + // response_destination:MsgAddress custom_payload:(Maybe ^Cell) + // forward_ton_amount:(VarUInteger 16) forward_payload:(Either Cell ^Cell) + // = InternalMsgBody; + + const body = beginCell() + .storeUint(0xf8a7ea5, 32) // jetton transfer op code + .storeUint(0, 64) // query_id:uint64 + .storeCoins(1000000) // amount:(VarUInteger 16) - Jetton amount for transfer (decimals = 6 - jUSDT, 9 - default) + .storeAddress(Wallet_DST) // destination:MsgAddress + .storeAddress(Wallet_SRC) // response_destination:MsgAddress + .storeUint(0, 1) // custom_payload:(Maybe ^Cell) + .storeCoins(toNano(0.05)) // forward_ton_amount:(VarUInteger 16) + .storeUInt(0,1) // forward_payload:(Either Cell ^Cell) + .endCell(); +``` + +Next, sending the transaction with this body to jettonWalletContract destination executed: + + + +```js +//react version +``` + + + + +// tonconnect-ui version + + + +```js +import TonConnect from '@tonconnect/sdk'; +const connector = new TonConnect(); +//... +await connector.sendTransaction({ + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: jettonWalletContract, // dst jetton wallet + amount: toNano("0.05"), // for commission fees, excess will be returned + payload: body.toBoc().toString("base64") + } + ] +}) +``` + + + + +- `validUntil` - UNIX-time until message valid +- `jettonWalletAddress` - Address, JettonWallet address, that defined based on JettonMaser and Wallet contracts +- `balance` - Integer, amount of Toncoin for gas payments in nanotons. +- `body` - payload for the jettonContract + + +
+ Jetton Wallet State Init and Address preparation example + + +```js +import { Address, TonClient, beginCell, StateInit, storeStateInit } from '@ton/ton' + +async function main() { + const client = new TonClient({ + endpoint: 'https://toncenter.com/api/v2/jsonRPC', + apiKey: 'put your api key' + }) + + const jettonWalletAddress = Address.parse('Sender_Jetton_Wallet'); + let jettonWalletDataResult = await client.runMethod(jettonWalletAddress, 'get_wallet_data'); + jettonWalletDataResult.stack.readNumber(); + const ownerAddress = jettonWalletDataResult.stack.readAddress(); + const jettonMasterAddress = jettonWalletDataResult.stack.readAddress(); + const jettonCode = jettonWalletDataResult.stack.readCell(); + const jettonData = beginCell() + .storeCoins(0) + .storeAddress(ownerAddress) + .storeAddress(jettonMasterAddress) + .storeRef(jettonCode) + .endCell(); + + const stateInit: StateInit = { + code: jettonCode, + data: jettonData + } + + const stateInitCell = beginCell() + .store(storeStateInit(stateInit)) + .endCell(); + + console.log(new Address(0, stateInitCell.hash())); +} +``` + +
+ +### Jetton Burn + +The `body` for Jetton Burn([TEP-74](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md#2-burn)) typically should be done according the following way: + + +```js + import {beginCell} from '@ton/ton' +// burn#595f07bc query_id:uint64 amount:(VarUInteger 16) +// response_destination:MsgAddress custom_payload:(Maybe ^Cell) +// = InternalMsgBody; + + const body = beginCell() + .storeUint(0x595f07bc, 32) // jetton burn op code + .storeUint(0, 64) // query_id:uint64 + .storeCoins(1000000) // amount:(VarUInteger 16) - Jetton amount in decimal + .storeAddress(Wallet_SRC) // response_destination:MsgAddress - owner's wallet + .storeUint(0, 1) // custom_payload:(Maybe ^Cell) - w/o payload typically + .endCell(); +``` + +Message places into the following request: + + + + +```js +//react version +``` + + + + +// tonconnect-ui version + + + +```js +await connector.sendTransaction({ + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: jettonWalletContract, + amount: toNano("0.05"), + payload: body.toBoc().toString("base64") + } + ] +}) +``` + + + + +- `jettonWalletAddress` - Address, jettonWalletContract - which desire to burn his jettons +- `amount` - Integer, amount of Toncoin for gas payments in nanotons. +- `body` - payload for the jetton wallet with the `burn#595f07bc` op code + +### NFT Transfer + +The `body` message typically should be done according the following way: + +```js +import { beginCell, toNano} from '@ton/ton' + +// transfer#5fcc3d14 query_id:uint64 new_owner:MsgAddress response_destination:MsgAddress custom_payload:(Maybe ^Cell) +// forward_amount:(VarUInteger 16) forward_payload:(Either Cell ^Cell) = InternalMsgBody; + + const body = beginCell() + .storeUint(0x5fcc3d14, 32) // NFT transfer op code 0x5fcc3d14 + .storeUint(0, 64) // query_id:uint64 + .storeAddress(NEW_OWNER_WALLET) // new_owner:MsgAddress + .storeAddress(Wallet_DST) // response_destination:MsgAddress + .storeUint(0, 1) // custom_payload:(Maybe ^Cell) + .storeCoins(toNano('0.000000001')) // forward_amount:(VarUInteger 16) + .storeUint(0,1) // forward_payload:(Either Cell ^Cell) + .endCell(); +``` + +`WALLET_DST` - Address - The address of the initial NFT owner for the receiving excess +Transfer the `NFTitem` to a new owner `NEW_OWNER_WALLET`. + + + +```js +//react version +``` + + + + +// tonconnect-ui version + + + +```js +await connector.sendTransaction({ + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: NFTitem, + amount: toNano("0.05"), + payload: body.toBoc().toString("base64") + } + ] +}) +``` + + + +- `NFTitem` - Address - The address of NFT item smart contract which we want transfer to a new owner `NEW_OWNER_WALLET`. +- `balance` - Integer, amount of Toncoin for gas payments in nanotons. +- `body` - payload for the NFT contract + +### NFT Sale (GetGems) + +Here is an example of preparing message and transaction for sale on GetGems marketplace, according to contract [nft-fixprice-sale-v3r2](https://github.com/getgems-io/nft-contracts/blob/main/packages/contracts/sources/nft-fixprice-sale-v3r2.fc). + +To place NFT on GetGems Sale Contract, we should prepare special message body `transferNftBody` that will be transfer NFT to special NFT Sale Contract. +```js + const transferNftBody = beginCell() + .storeUint(0x5fcc3d14, 32) // Opcode for NFT transfer + .storeUint(0, 64) // query_id + .storeAddress(destinationAddress) // new_owner + .storeAddress(walletAddress) // response_destination for excesses + .storeBit(0) // we do not have custom_payload + .storeCoins(toNano("1")) // forward_amount + .storeBit(0) // we store forward_payload is this cell + .storeUint(0x0fe0ede, 31) // not 32, because previous 0 will be read as do_sale opcode in deployer + .storeRef(stateInitCell) + .storeRef(saleBody) + .endCell(); +``` + +Because message requires a lot of steps, the entire algorithm huge and could be found here: +
+ Show entire script for creating message + + +```js +import { Address, beginCell, StateInit, storeStateInit, toNano, Cell } from '@ton/ton' + +async function main() { +const fixPriceV3R2Code = Cell.fromBase64('te6cckECCwEAArkAART/APSkE/S88sgLAQIBIAIDAgFIBAUAfvIw7UTQ0wDTH/pA+kD6QPoA1NMAMMABjh34AHAHyMsAFssfUATPFljPFgHPFgH6AszLAMntVOBfB4IA//7y8AICzQYHAFegOFnaiaGmAaY/9IH0gfSB9AGppgBgYaH0gfQB9IH0AGEEIIySsKAVgAKrAQH30A6GmBgLjYSS+CcH0gGHaiaGmAaY/9IH0gfSB9AGppgBgYOCmE44BgAEqYhOmPhW8Q4YBKGATpn8cIxbMbC3MbK2QV44LJOZlvKAVxFWAAyS+G8BJrpOEBFcCBFd0VYACRWdjYKdxjgthOjq+G6hhoaYPqGAD9gHAU4ADAgB92YIQO5rKAFJgoFIwvvLhwiTQ+kD6APpA+gAwU5KhIaFQh6EWoFKQcIAQyMsFUAPPFgH6AstqyXH7ACXCACXXScICsI4XUEVwgBDIywVQA88WAfoCy2rJcfsAECOSNDTiWnCAEMjLBVADzxYB+gLLaslx+wBwIIIQX8w9FIKAejy0ZSzjkIxMzk5U1LHBZJfCeBRUccF8uH0ghAFE42RFrry4fUD+kAwRlAQNFlwB8jLABbLH1AEzxZYzxYBzxYB+gLMywDJ7VTgMDcowAPjAijAAJw2NxA4R2UUQzBw8AXgCMACmFVEECQQI/AF4F8KhA/y8AkA1Dg5ghA7msoAGL7y4clTRscFUVLHBRWx8uHKcCCCEF/MPRQhgBDIywUozxYh+gLLassfFcs/J88WJ88WFMoAI/oCE8oAyYMG+wBxUGZFFQRwB8jLABbLH1AEzxZYzxYBzxYB+gLMywDJ7VQAlsjLHxPLPyPPFlADzxbKAIIJycOA+gLKAMlxgBjIywUmzxZw+gLLaszJgwb7AHFVUHAHyMsAFssfUATPFljPFgHPFgH6AszLAMntVNZeZYk='); +// GetGems Address +const marketplaceAddress = Address.parse('EQBYTuYbLf8INxFtD8tQeNk5ZLy-nAX9ahQbG_yl1qQ-GEMS'); +// GetGems Address for Fees +const marketplaceFeeAddress = Address.parse('EQCjk1hh952vWaE9bRguFkAhDAL5jj3xj9p0uPWrFBq_GEMS'); +// GetGems sale contracts deployer +const destinationAddress = Address.parse("EQAIFunALREOeQ99syMbO6sSzM_Fa1RsPD5TBoS0qVeKQ-AR"); + + const walletAddress = Address.parse('EQArLGBnGPvkxaJE57Y6oS4rwzDWuOE8l8_sghntXLkIt162'); + const royaltyAddress = Address.parse('EQArLGBnGPvkxaJE57Y6oS4rwzDWuOE8l8_sghntXLkIt162'); + const nftAddress = Address.parse('EQCUWoe7hLlklVxH8gduCf45vPNocsjRP4wbX42UJ0Ja0S2f'); + const price = toNano('5'); // 5 TON + + const feesData = beginCell() + .storeAddress(marketplaceFeeAddress) + // 5% - GetGems fee + .storeCoins(price / BigInt(100) * BigInt(5)) + .storeAddress(royaltyAddress) + // 5% - Royalty, can be changed + .storeCoins(price / BigInt(100) * BigInt(5)) + .endCell(); + + const saleData = beginCell() + .storeBit(0) // is_complete + .storeUint(Math.round(Date.now() / 1000), 32) // created_at + .storeAddress(marketplaceAddress) // marketplace_address + .storeAddress(nftAddress) // nft_address + .storeAddress(walletAddress) // previous_owner_address + .storeCoins(price) // full_price + .storeRef(feesData) // fees_cell + .storeBit(0) // can_be_deployed_externally + .endCell(); + + const stateInit: StateInit = { + code: fixPriceV3R2Code, + data: saleData + }; + const stateInitCell = beginCell() + .store(storeStateInit(stateInit)) + .endCell(); + + // not needed, just for example + const saleContractAddress = new Address(0, stateInitCell.hash()); + + const saleBody = beginCell() + .storeUint(1, 32) // just accept coins on deploy + .storeUint(0, 64) + .endCell(); + + const transferNftBody = beginCell() + .storeUint(0x5fcc3d14, 32) // Opcode for NFT transfer + .storeUint(0, 64) // query_id + .storeAddress(destinationAddress) // new_owner + .storeAddress(walletAddress) // response_destination for excesses + .storeBit(0) // we do not have custom_payload + .storeCoins(toNano("1")) // forward_amount + .storeBit(0) // we store forward_payload is this cell + // not 32, because we stored 0 bit before | do_sale opcode for deployer + .storeUint(0x0fe0ede, 31) + .storeRef(stateInitCell) + .storeRef(saleBody) + .endCell(); +``` + +
+ +Prepared `transferNftBody` should be sent to NFT Item with at least `1.08` Tons, that expected for success processing. Excess will be returned to a sender's wallet. + +```js +await connector.sendTransaction({ + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: nftItemAddress, //address of NFT Item contract, that should be placed on market + amount: toNano("1.08"), // amount that will require on gas fees, excess will be return + payload: transferNftBody.toBoc().toString("base64") + } + ] +}) +``` + +### NFT Buy (GetGems) + +The process of buy NFT for [nft-fixprice-sale-v3r2](https://github.com/getgems-io/nft-contracts/blob/main/packages/contracts/sources/nft-fixprice-sale-v3r2.fc) sale contract could be carry out with regular transfer without payload, only important thing to send correct amount, that calculates as follows: +`buyAmount = Nftprice TON + 1.0 TON`. + +```js +await connector.sendTransaction({ +validUntil: Math.floor(Date.now() / 1000) + 360, +messages: [ + { + address: nftSaleContract, + amount: toNano(buyAmount), + } +] +}) +``` + +## TON Connect Python SDK + +For Python examples are using [PyTonConnect](https://github.com/XaBbl4/pytonconnect) and [pytoniq](https://github.com/yungwine/pytoniq). + +```python + from pytoniq_core import Address + from pytonconnect import TonConnect +``` + +:::tip +Read examples [source](https://github.com/yungwine/ton-connect-examples/blob/master/main.py). +::: + +### Regular TON Transfer + + +```python +connector = TonConnect( + manifest_url='https://raw.githubusercontent.com/XaBbl4/pytonconnect/main/pytonconnect-manifest.json') +is_connected = await connector.restore_connection() + +transaction = { + 'valid_until': int(time.time() + 3600), + 'messages': [ + 'address' :'0:0000000000000000000000000000000000000000000000000000000000000000', # destination address + 'amount' : 1000000000, # amount should be specified in nanocoins, 1 TON + ) + ] +} +``` + + +### Transfer With Comment + +At first order, implement a message with comment via the following function: + +```python + def get_comment_message(destination_address: str, amount: int, comment: str) -> dict: + + data = { + 'address': destination_address, + 'amount': str(amount), + 'payload': urlsafe_b64encode( + begin_cell() + .store_uint(0, 32) # op code for comment message + .store_string(comment) # store comment + .end_cell() # end cell + .to_boc() # convert it to boc + ) + .decode() # encode it to urlsafe base64 + } + + return data +``` + +Final transaction body for transfer with comment: + +```python +transaction = { + 'valid_until': int(time.time() + 3600), + 'messages': [ + get_comment_message( + destination_address='0:0000000000000000000000000000000000000000000000000000000000000000', + amount=int(0.01 * 10**9), # amount should be specified in nanocoins + comment='hello world!' + ) + ] +} +``` +:::tip +Learn more about [TON Smart Contract Addresses](/learn/overviews/addresses). +::: + +### Jetton Transfer + +To carry out jetton transfer need prepare the following message: + +```python +from pytoniq_core import begin_cell +from base64 import urlsafe_b64encode + +def get_jetton_transfer_message(jetton_wallet_address: str, recipient_address: str, transfer_fee: int, jettons_amount: int, response_address: str = None) -> dict: + data = { + 'address': jetton_wallet_address, + 'amount': str(transfer_fee), + 'payload': urlsafe_b64encode( + begin_cell() + .store_uint(0xf8a7ea5, 32) # op code for jetton transfer message + .store_uint(0, 64) # query_id + .store_coins(jettons_amount) + .store_address(recipient_address) # destination address + .store_address(response_address or recipient_address) # address send excess to + .store_uint(0, 1) # custom payload + .store_coins(1) # forward amount + .store_uint(0, 1) # forward payload + .end_cell() # end cell + .to_boc() # convert it to boc + ) + .decode() # encode it to urlsafe base64 + } + + return data +``` + +Final transaction body: + + +```python +transaction = { + 'valid_until': int(time.time() + 3600), + 'messages': [ + get_jetton_transfer_message( + jetton_wallet_address='EQCXsVvdxTVmSIvYv4tTQoQ-0Yq9mERGTKfbsIhedbN5vTVV', + recipient_address='0:0000000000000000000000000000000000000000000000000000000000000000', + transfer_fee=int(0.07 * 10**9), + jettons_amount=int(0.01 * 10**9), # replace 9 for jetton decimal. For example for jUSDT it should be (amount * 10**6) + response_address=wallet_address + ), + ] +} + +``` + + +### Jetton Burn + +To carry out Jetton Transfer need prepare the following message: + +```python +from pytoniq_core import begin_cell +from base64 import urlsafe_b64encode + +def get_jetton_burn_message(jetton_wallet_address: str, transfer_fee: int, jettons_amount: int, response_address: str = None) -> dict: + data = { + 'address': jetton_wallet_address, + 'amount': str(transfer_fee), + 'payload': urlsafe_b64encode( + begin_cell() + .store_uint(0x595f07bc, 32) # op code for jetton transfer message + .store_uint(0, 64) # query_id + .store_coins(jettons_amount) + .store_address(response_address) # address send excess to + .end_cell() # end cell + .to_boc() # convert it to boc + ) + .decode() # encode it to urlsafe base64 + } + return data +``` + +Final transaction: + +```python +transaction = { + 'valid_until': int(time.time() + 3600), + 'messages': [ + get_jetton_burn_message( + jetton_wallet_address='EQCXsVvdxTVmSIvYv4tTQoQ-0Yq9mERGTKfbsIhedbN5vTVV', + transfer_fee=int(0.07 * 10 ** 9), + jettons_amount=int(0.01 * 10 ** 9), # replace 9 for jetton decimal. For example for jUSDT it should be (amount * 10**6) + response_address=wallet_address + ), + ] +} +``` + + +### NFT Transfer + +For the NFT transfer it is required to prepare the following message: + + +```python +from pytoniq_core import begin_cell +from base64 import urlsafe_b64encode + + +def get_nft_transfer_message(nft_address: str, recipient_address: str, transfer_fee: int, response_address: str = None) -> dict: + data = { + 'address': nft_address, + 'amount': str(transfer_fee), + 'payload': urlsafe_b64encode( + begin_cell() + .store_uint(0x5fcc3d14, 32) # op code for nft transfer message + .store_uint(0, 64) # query_id + .store_address(recipient_address) # new owner + .store_address(response_address or recipient_address) # address send excess to + .store_uint(0, 1) # custom payload + .store_coins(1) # forward amount + .store_uint(0, 1) # forward payload + .end_cell() # end cell + .to_boc() # convert it to boc + ) + .decode() # encode it to urlsafe base64 + } + return data + +``` + + +```python +transaction = { + 'valid_until': int(time.time() + 3600), + 'messages': [ + get_nft_transfer_message( + nft_address='EQDrA-3zsJXTfGo_Vdzg8d07Da4vSdHZllc6W9qvoNoMstF-', + recipient_address='0:0000000000000000000000000000000000000000000000000000000000000000', + transfer_fee=int(0.07 * 10**9), + response_address=wallet_address + ), + ] +} +``` + + +## Authors +- JavaScript examples provided by [@aSpite](https://t.me/aspite) +- Python examples provided by [@yunwine](https://t.me/yungwine) + +## See Also + +* [TON Connect SDKs](/develop/dapps/ton-connect/developers) +* [TON Connect - Sending Messages](/develop/dapps/ton-connect/transactions) +* [Smart Contract Developmet - Sending Messages (Low Level)](/develop/smart-contracts/messages) diff --git a/docs/develop/dapps/ton-connect/transactions.md b/docs/develop/dapps/ton-connect/transactions.md index 6552609ec7..b044389370 100644 --- a/docs/develop/dapps/ton-connect/transactions.md +++ b/docs/develop/dapps/ton-connect/transactions.md @@ -155,3 +155,7 @@ After confirmation, we may see our transaction complete at [tonscan.org](https:/ It's pretty easy to handle request rejection, but when you're developing some project it's better to know what would happen in advance. When a user clicks "Cancel" in the popup in the wallet application, an exception is thrown: `Error: [TON_CONNECT_SDK_ERROR] Wallet declined the request`. This error can be considered final (unlike connection cancellation) - if it has been raised, then the requested transaction will definitely not happen until the next request is sent. + +## See Also + +* [Preparing Messages](/develop/dapps/ton-connect/message-builders) \ No newline at end of file diff --git a/docs/develop/smart-contracts/examples.md b/docs/develop/smart-contracts/examples.md index 1e6ac958ae..562b24b24b 100644 --- a/docs/develop/smart-contracts/examples.md +++ b/docs/develop/smart-contracts/examples.md @@ -61,19 +61,19 @@ Make sure you have thoroughly tested contracts before using them in a production * [Blueprint jetton_minter.fc](https://github.com/liminalAngel/func-blueprint-tutorial/blob/master/6/contracts/jetton_minter.fc) * [Simple TON DNS Subdomain manager](https://github.com/Gusarich/simple-subdomain) -### Ton Smart Challenge Solutions +### TON Smart Challenge Solutions -#### Ton Smart Challenge 1 +#### TON Smart Challenge 1 * https://github.com/nns2009/TON-FunC-contest-1/tree/main * https://github.com/pyAndr3w/func-contest1-solutions * https://github.com/crazyministr/TonContest-FunC/tree/master/func-contest1 -#### Ton Smart Challenge 2 +#### TON Smart Challenge 2 * https://github.com/ton-blockchain/func-contest2-solutions * https://github.com/nns2009/TON-FunC-contest-2 * https://github.com/crazyministr/TonContest-FunC/tree/master/func-contest2 -#### Ton Smart Challenge 3 +#### TON Smart Challenge 3 * https://github.com/nns2009/TON-FunC-contest-3 * https://github.com/shuva10v/func-contest3-solutions * https://github.com/crazyministr/TonContest-FunC/tree/master/func-contest3 diff --git a/sidebars.js b/sidebars.js index 317a078aa2..883e1db1a0 100644 --- a/sidebars.js +++ b/sidebars.js @@ -275,7 +275,6 @@ const sidebars = { }, ], }, - ], }, @@ -373,6 +372,7 @@ const sidebars = { 'develop/dapps/ton-connect/developers', 'develop/dapps/ton-connect/integration', 'develop/dapps/ton-connect/transactions', + 'develop/dapps/ton-connect/message-builders', ], }, {