From 6199ab2dd2793ecf71b492cf9ccd22efb8a723b6 Mon Sep 17 00:00:00 2001 From: AlexG Date: Thu, 3 Aug 2023 15:33:24 +0400 Subject: [PATCH 01/14] upd_1 --- docs/develop/dapps/ton-connect/developers.md | 37 ++++++----- .../dapps/ton-connect/message-builders.md | 64 +++++++++++++++++++ docs/develop/smart-contracts/examples.md | 8 +-- 3 files changed, 90 insertions(+), 19 deletions(-) create mode 100644 docs/develop/dapps/ton-connect/message-builders.md diff --git a/docs/develop/dapps/ton-connect/developers.md b/docs/develop/dapps/ton-connect/developers.md index 78f7981143..b314343402 100644 --- a/docs/develop/dapps/ton-connect/developers.md +++ b/docs/develop/dapps/ton-connect/developers.md @@ -1,26 +1,21 @@ -# TON Connect for Developers +# TON Connect SDKs -## SDK LIst -This page contents the list of useful libraries for TON Connect. +## SDK List -* [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 JS SDK :::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 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 applications -- [@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 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. @@ -31,6 +26,16 @@ TonConnect UI React is a React UI kit for TonConnect SDK. Use it to connect your * Example of a dApp with @tonconnect/ui-react: [GitHub](https://github.com/ton-connect/demo-dapp-with-react-ui) * Example of deployed demo-dapp-with-react-ui: [GitHub](https://ton-connect.github.io/demo-dapp-with-react-ui/) + +## 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. @@ -107,6 +112,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.md b/docs/develop/dapps/ton-connect/message-builders.md new file mode 100644 index 0000000000..69d2148b6a --- /dev/null +++ b/docs/develop/dapps/ton-connect/message-builders.md @@ -0,0 +1,64 @@ +# Prepare Messages + +While using TON Connect you should prepare Bag of Cells for Payload for various transactions. Here you can find most relatable examples for payload for using it in TON Connect SDKs. + +## Regular TON Transfer +As ton-connect SDK is already wrapper above messages, we have no problem to prepare regular Transfer. For the following actions we should specify Payload(Message Body) + + +## TON Connect React UI + +Suppose, we specified simple hook built with ton-connect/react-ui + +```ts +import { CHAIN, useTonConnectUI, useTonWallet } from "@tonconnect/ui-react"; +import { Address } from "@ton/core"; +import { SenderArguments } from "@ton/core"; +import { Sender } from "@ton/core"; + +export function useTonConnect(): { + sender: Sender; + connected: boolean; + wallet: string | null; + network: CHAIN | null; +} { + const [tonConnectUI] = useTonConnectUI() + const wallet = useTonWallet() + + return { + sender: { + send: async (args: SenderArguments) => { + tonConnectUI.sendTransaction({ + messages: [ + { + address: args.to.toString(), + amount: args.value.toString(), + payload: args.body?.toBoc().toString("base64"), + }, + ], + validUntil: Date.now() + 5 * 60 * 1000, // 5 minutes for user to approve + }); + }, + address: wallet?.account?.address ? Address.parse(wallet?.account?.address as string) : undefined + }, + + connected: !!wallet?.account.address, + wallet: wallet?.account.address ?? null, + network: wallet?.account.chain ?? null + + } +} +``` + +### Jettons + +#### Transfer Jetton + + + +### NFTs + +#### Deploy NFT + +#### Sale NFT + 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 From 940c8fb3f26569955ed38858411b3c8066e055bd Mon Sep 17 00:00:00 2001 From: AlexG Date: Thu, 3 Aug 2023 16:51:03 +0400 Subject: [PATCH 02/14] upd_2 --- .../dapps/ton-connect/message-builders.md | 114 ++++++++++++------ sidebars.js | 2 +- 2 files changed, 80 insertions(+), 36 deletions(-) diff --git a/docs/develop/dapps/ton-connect/message-builders.md b/docs/develop/dapps/ton-connect/message-builders.md index 69d2148b6a..13389fc881 100644 --- a/docs/develop/dapps/ton-connect/message-builders.md +++ b/docs/develop/dapps/ton-connect/message-builders.md @@ -1,55 +1,99 @@ -# Prepare Messages +# Preparing Messages While using TON Connect you should prepare Bag of Cells for Payload for various transactions. Here you can find most relatable examples for payload for using it in TON Connect SDKs. +:::warning +Page in development. +::: + + ## Regular TON Transfer As ton-connect SDK is already wrapper above messages, we have no problem to prepare regular Transfer. For the following actions we should specify Payload(Message Body) ## TON Connect React UI -Suppose, we specified simple hook built with ton-connect/react-ui +Suppose, we specified simple hook built with ton-connect/react-ui useJettonContract.ts, which defines mint request from our application: + ```ts -import { CHAIN, useTonConnectUI, useTonWallet } from "@tonconnect/ui-react"; -import { Address } from "@ton/core"; -import { SenderArguments } from "@ton/core"; -import { Sender } from "@ton/core"; - -export function useTonConnect(): { - sender: Sender; - connected: boolean; - wallet: string | null; - network: CHAIN | null; -} { - const [tonConnectUI] = useTonConnectUI() - const wallet = useTonWallet() +import { useEffect, useState } from "react"; +import { Address, fromNano, OpenedContract, toNano } from "ton-core"; +import {Mint, SampleJetton} from "../../build/SampleJetton/tact_SampleJetton"; +import {JettonDefaultWallet} from "../../build/SampleJetton/tact_JettonDefaultWallet"; +import { useAsyncInitialize } from "./useAsyncInitialize"; +import { useTonClient } from "./useTonClient"; +import { useTonConnect } from "./useTonConnect"; + +const sleep = (time: number) => new Promise((resolve) => setTimeout(resolve, time)) + +export function useJettonContract() { + const {client} = useTonClient() + const {wallet, sender} = useTonConnect() + const [balance, setBalance] = useState() + + const jettonContract = useAsyncInitialize(async()=>{ + if(!client || !wallet) return; + + const contract = SampleJetton.fromAddress(Address.parse("EQB8StgTQXidy32a8xfu7j4HMoWYV0b0cFM8nXsP2cza_b7Y")) + + return client.open(contract) as OpenedContract + }, [client, wallet]) + + const jettonWalletContract = useAsyncInitialize(async()=>{ + if(!jettonContract || !client) return; + + const jettonWalletAddress = await jettonContract.getGetWalletAddress( + Address.parse(Address.parse(wallet!).toString()) + ) + + return client.open(JettonDefaultWallet.fromAddress(jettonWalletAddress)) + }, [jettonContract, client]) + + useEffect(()=>{ + async function getBalance() { + if(!jettonWalletContract) return + setBalance(null) + const balance = (await jettonWalletContract.getGetWalletData()).balance + setBalance(fromNano(balance)) + await sleep(5000) + getBalance() + } + + getBalance() + + }, [jettonWalletContract]) return { - sender: { - send: async (args: SenderArguments) => { - tonConnectUI.sendTransaction({ - messages: [ - { - address: args.to.toString(), - amount: args.value.toString(), - payload: args.body?.toBoc().toString("base64"), - }, - ], - validUntil: Date.now() + 5 * 60 * 1000, // 5 minutes for user to approve - }); - }, - address: wallet?.account?.address ? Address.parse(wallet?.account?.address as string) : undefined - }, - - connected: !!wallet?.account.address, - wallet: wallet?.account.address ?? null, - network: wallet?.account.chain ?? null - + jettonWalletAddress: jettonWalletContract?.address.toString(), + balance: balance, + mint: () => { + const message: Mint = { + $$type: "Mint", + amount: 150n + } + + jettonContract?.send(sender, { + value: toNano("0.05") + }, message) + } } } ``` +Here our payload defined by sending `send()` message with following specs: +`destination` - Address, JettonWallet address, that defined based on JettonMaser and Wallet contracts +`balance` - Integer, amount of Toncoin for gas payments in nanotons. +balance` + +address, amount and payload defines by the following + +```ts "title" = "destination address" + + +``` + + ### Jettons #### Transfer Jetton diff --git a/sidebars.js b/sidebars.js index 719b1dce30..310ef54c02 100644 --- a/sidebars.js +++ b/sidebars.js @@ -280,7 +280,6 @@ const sidebars = { }, ], }, - ], }, @@ -349,6 +348,7 @@ const sidebars = { 'develop/dapps/ton-connect/integration', 'develop/dapps/ton-connect/tg-bot-integration', 'develop/dapps/ton-connect/transactions', + 'develop/dapps/ton-connect/message-builders', ], }, { From 4fd6985444bb057dcfc6ce4e4484953996c199a4 Mon Sep 17 00:00:00 2001 From: AlexG Date: Thu, 3 Aug 2023 17:44:32 +0400 Subject: [PATCH 03/14] upd_3 --- .../dapps/ton-connect/message-builders.md | 108 --------- .../dapps/ton-connect/message-builders.mdx | 218 ++++++++++++++++++ 2 files changed, 218 insertions(+), 108 deletions(-) delete mode 100644 docs/develop/dapps/ton-connect/message-builders.md create mode 100644 docs/develop/dapps/ton-connect/message-builders.mdx diff --git a/docs/develop/dapps/ton-connect/message-builders.md b/docs/develop/dapps/ton-connect/message-builders.md deleted file mode 100644 index 13389fc881..0000000000 --- a/docs/develop/dapps/ton-connect/message-builders.md +++ /dev/null @@ -1,108 +0,0 @@ -# Preparing Messages - -While using TON Connect you should prepare Bag of Cells for Payload for various transactions. Here you can find most relatable examples for payload for using it in TON Connect SDKs. - -:::warning -Page in development. -::: - - -## Regular TON Transfer -As ton-connect SDK is already wrapper above messages, we have no problem to prepare regular Transfer. For the following actions we should specify Payload(Message Body) - - -## TON Connect React UI - -Suppose, we specified simple hook built with ton-connect/react-ui useJettonContract.ts, which defines mint request from our application: - - -```ts -import { useEffect, useState } from "react"; -import { Address, fromNano, OpenedContract, toNano } from "ton-core"; -import {Mint, SampleJetton} from "../../build/SampleJetton/tact_SampleJetton"; -import {JettonDefaultWallet} from "../../build/SampleJetton/tact_JettonDefaultWallet"; -import { useAsyncInitialize } from "./useAsyncInitialize"; -import { useTonClient } from "./useTonClient"; -import { useTonConnect } from "./useTonConnect"; - -const sleep = (time: number) => new Promise((resolve) => setTimeout(resolve, time)) - -export function useJettonContract() { - const {client} = useTonClient() - const {wallet, sender} = useTonConnect() - const [balance, setBalance] = useState() - - const jettonContract = useAsyncInitialize(async()=>{ - if(!client || !wallet) return; - - const contract = SampleJetton.fromAddress(Address.parse("EQB8StgTQXidy32a8xfu7j4HMoWYV0b0cFM8nXsP2cza_b7Y")) - - return client.open(contract) as OpenedContract - }, [client, wallet]) - - const jettonWalletContract = useAsyncInitialize(async()=>{ - if(!jettonContract || !client) return; - - const jettonWalletAddress = await jettonContract.getGetWalletAddress( - Address.parse(Address.parse(wallet!).toString()) - ) - - return client.open(JettonDefaultWallet.fromAddress(jettonWalletAddress)) - }, [jettonContract, client]) - - useEffect(()=>{ - async function getBalance() { - if(!jettonWalletContract) return - setBalance(null) - const balance = (await jettonWalletContract.getGetWalletData()).balance - setBalance(fromNano(balance)) - await sleep(5000) - getBalance() - } - - getBalance() - - }, [jettonWalletContract]) - - return { - jettonWalletAddress: jettonWalletContract?.address.toString(), - balance: balance, - mint: () => { - const message: Mint = { - $$type: "Mint", - amount: 150n - } - - jettonContract?.send(sender, { - value: toNano("0.05") - }, message) - } - } -} -``` - -Here our payload defined by sending `send()` message with following specs: -`destination` - Address, JettonWallet address, that defined based on JettonMaser and Wallet contracts -`balance` - Integer, amount of Toncoin for gas payments in nanotons. -balance` - -address, amount and payload defines by the following - -```ts "title" = "destination address" - - -``` - - -### Jettons - -#### Transfer Jetton - - - -### NFTs - -#### Deploy NFT - -#### Sale NFT - 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..35427cf49f --- /dev/null +++ b/docs/develop/dapps/ton-connect/message-builders.mdx @@ -0,0 +1,218 @@ +# Preparing Messages + +While using TON Connect you should prepare Bag of Cells for Payload for various transactions. Here you can find most relatable examples for payload for using it in TON Connect SDKs. + +:::warning +Page in development. +::: + + +## Regular TON Transfer +As ton-connect SDK is already wrapper above messages, we have no problem to prepare regular Transfer. For the following actions we should specify Payload(Message Body) + + +## TON Connect React UI + +### Jettons + +Suppose, we specified simple hook built with ton-connect/react-ui useJettonContract.ts, which defines mint request from our application: + +
+Open entire script + +```ts +import { useEffect, useState } from "react"; +import { Address, fromNano, OpenedContract, toNano } from "ton-core"; +import {Mint, SampleJetton} from "../../build/SampleJetton/tact_SampleJetton"; +import {JettonDefaultWallet} from "../../build/SampleJetton/tact_JettonDefaultWallet"; +import { useAsyncInitialize } from "./useAsyncInitialize"; +import { useTonClient } from "./useTonClient"; +import { useTonConnect } from "./useTonConnect"; + +const sleep = (time: number) => new Promise((resolve) => setTimeout(resolve, time)) + +export function useJettonContract() { + const {client} = useTonClient() + const {wallet, sender} = useTonConnect() + const [balance, setBalance] = useState() + + const jettonContract = useAsyncInitialize(async()=>{ + if(!client || !wallet) return; + + const contract = SampleJetton.fromAddress(Address.parse("EQB8StgTQXidy32a8xfu7j4HMoWYV0b0cFM8nXsP2cza_b7Y")) + + return client.open(contract) as OpenedContract + }, [client, wallet]) + + const jettonWalletContract = useAsyncInitialize(async()=>{ + if(!jettonContract || !client) return; + + const jettonWalletAddress = await jettonContract.getGetWalletAddress( + Address.parse(Address.parse(wallet!).toString()) + ) + + return client.open(JettonDefaultWallet.fromAddress(jettonWalletAddress)) + }, [jettonContract, client]) + + useEffect(()=>{ + async function getBalance() { + if(!jettonWalletContract) return + setBalance(null) + const balance = (await jettonWalletContract.getGetWalletData()).balance + setBalance(fromNano(balance)) + await sleep(5000) + getBalance() + } + + getBalance() + + }, [jettonWalletContract]) + + return { + jettonWalletAddress: jettonWalletContract?.address.toString(), + balance: balance, + mint: () => { + const message: Mint = { + $$type: "Mint", + amount: 150n + } + + jettonContract?.send(sender, { + value: toNano("0.05") + }, message) + } + } +} +``` + +
+ +```ts +/// previous part + return { + jettonWalletAddress: jettonWalletContract?.address.toString(), + balance: balance, + mint: () => { + const message: Mint = { + $$type: "Mint", + amount: 150n + } + + jettonContract?.send(sender, { + value: toNano("0.05") + }, message) + } + } +``` + +Here our payload defined by sending `send()` message with following specs: + +- `jettonWalletAddress` - Address, JettonWallet address, that defined based on JettonMaser and Wallet contracts +- `balance` - Integer, amount of Toncoin for gas payments in nanotons. +- `mint` - function, which invokes internal transfer from jettonContract(jetton master) to sender's Jetton Wallet + - `sender` - wallet address, which requested mint and which will receive jettons on his Jetton Wallet + - `value` - amount of Toncoins carried for gas payments between Jetton Master and new Jetton Wallet + - `message` - payload for the jettonContract, which defines what should be done + - `$$type`: string, "Mint" string (or corresponded op-code for Mint) + - `amount`: bigint, amount of Jettons should be minted + + + +```ts "title" = "destination address" + + +``` + + +#### Jetton Transfer + + + +## TON Connect JS SDK + +#### Mint Jetton + +```js +let body = beginCell() + //Mint message body + .endCell() + + +await connector.sendTransaction({ + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: jettonWalletContract, + amount: toNano("0.05"), + payload: body.toBoc().toString("base64") + } + ] +}) +``` + +- `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, which defines what should be done + - `$$type`: string, "Mint" string (or corresponded op-code for Mint) + - `amount`: bigint, amount of Jettons should be minted + + +#### Jetton Transfer + +```js +let body = beginCell() + //jetton Transfer message body + .endCell() + + +await connector.sendTransaction({ + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: jettonWalletContract, + amount: toNano("0.05"), + payload: body.toBoc().toString("base64") + } + ] +}) +``` + +- `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, which defines what should be done + - `$$type`: string, "Transfer" string (or corresponded op-code for Mint) + - `amount`: bigint, amount of Jettons should be minted + +#### Jetton Burn + + +```js +let body = beginCell() + //jetton burn message body + .endCell() + + +await connector.sendTransaction({ + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: jettonWalletContract, + amount: toNano("0.05"), + payload: body.toBoc().toString("base64") + } + ] +}) +``` + +- `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 jetton wallet, which defines what should be done + +### NFTs + + + +#### Deploy NFT + +#### Sale NFT + From 189a29f5cdcc2ac4b11792ce3523f2f03e8fd8c3 Mon Sep 17 00:00:00 2001 From: AlexG Date: Thu, 3 Aug 2023 17:49:32 +0400 Subject: [PATCH 04/14] upd_5 --- docs/develop/dapps/ton-connect/message-builders.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/develop/dapps/ton-connect/message-builders.mdx b/docs/develop/dapps/ton-connect/message-builders.mdx index 35427cf49f..242f75ecda 100644 --- a/docs/develop/dapps/ton-connect/message-builders.mdx +++ b/docs/develop/dapps/ton-connect/message-builders.mdx @@ -1,6 +1,6 @@ # Preparing Messages -While using TON Connect you should prepare Bag of Cells for Payload for various transactions. Here you can find most relatable examples for payload for using it in TON Connect SDKs. +While using TON Connect you should build Message Body for Payload for various transactions. Here you can find most relatable examples for payload for using it in TON Connect SDKs. :::warning Page in development. From 9589ba7d6e5ced50e36b0b5ef68e603bd9f0ed32 Mon Sep 17 00:00:00 2001 From: AlexG Date: Thu, 3 Aug 2023 17:52:24 +0400 Subject: [PATCH 05/14] upd_5 --- .../dapps/ton-connect/message-builders.mdx | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/docs/develop/dapps/ton-connect/message-builders.mdx b/docs/develop/dapps/ton-connect/message-builders.mdx index 242f75ecda..47e24994b9 100644 --- a/docs/develop/dapps/ton-connect/message-builders.mdx +++ b/docs/develop/dapps/ton-connect/message-builders.mdx @@ -210,9 +210,26 @@ await connector.sendTransaction({ ### NFTs - - #### Deploy NFT #### Sale NFT + +## TON Connect Python SDK + +### Jettons + +#### Jetton Transfer + +#### Jetton Mint + +#### Jetton Burn + +### NFTs + +#### NFT Transfer + +#### NFT Sale (getgems) + +#### NFT Buy (getgems) + From 462e8f5451f79545a76d123138bb0398b987d044 Mon Sep 17 00:00:00 2001 From: AlexG Date: Fri, 4 Aug 2023 18:06:04 +0400 Subject: [PATCH 06/14] added_jetton_transfer_example --- .../dapps/ton-connect/message-builders.mdx | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/develop/dapps/ton-connect/message-builders.mdx b/docs/develop/dapps/ton-connect/message-builders.mdx index 47e24994b9..fa134084ae 100644 --- a/docs/develop/dapps/ton-connect/message-builders.mdx +++ b/docs/develop/dapps/ton-connect/message-builders.mdx @@ -179,9 +179,27 @@ await connector.sendTransaction({ - `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, which defines what should be done - - `$$type`: string, "Transfer" string (or corresponded op-code for Mint) - - `amount`: bigint, amount of Jettons should be minted +- `body` - payload for the jettonContract + +`body` typically should be done according the following way: + +```js + import { Address, beginCell, Cell, 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 messageBody = beginCell() + .storeUint(0xf8a7ea5, 32) // jetton transfer op code + .storeUint(quiryId, 64) // query_id:uint64 + .storeCoins(toNano("1")) //amount:(VarUInteger 16) + .storeAddress(Jetton_Wallet_DST) //destination:MsgAddress + .storeAddress(Wallet_OWNER) //response_destination:MsgAddress + .storeUint(0, 1) //custom_payload:(Maybe ^Cell) + .storeCoins(toNano(0.05)) // forward_ton_amount:(VarUInteger 16) + .endCell(); //forward_payload:(Either Cell ^Cell) +``` #### Jetton Burn From 356a4caa40cafeab96fc26571631ed492fccb2a4 Mon Sep 17 00:00:00 2001 From: AlexG Date: Sat, 5 Aug 2023 01:02:58 +0400 Subject: [PATCH 07/14] NFT_transfer_template --- .../dapps/ton-connect/message-builders.mdx | 105 +++++++++++++++--- 1 file changed, 87 insertions(+), 18 deletions(-) diff --git a/docs/develop/dapps/ton-connect/message-builders.mdx b/docs/develop/dapps/ton-connect/message-builders.mdx index fa134084ae..9d4caa6177 100644 --- a/docs/develop/dapps/ton-connect/message-builders.mdx +++ b/docs/develop/dapps/ton-connect/message-builders.mdx @@ -160,11 +160,6 @@ await connector.sendTransaction({ #### Jetton Transfer ```js -let body = beginCell() - //jetton Transfer message body - .endCell() - - await connector.sendTransaction({ validUntil: Math.floor(Date.now() / 1000) + 360, messages: [ @@ -190,26 +185,57 @@ await connector.sendTransaction({ // forward_ton_amount:(VarUInteger 16) forward_payload:(Either Cell ^Cell) // = InternalMsgBody; - const messageBody = beginCell() + const body = beginCell() .storeUint(0xf8a7ea5, 32) // jetton transfer op code - .storeUint(quiryId, 64) // query_id:uint64 - .storeCoins(toNano("1")) //amount:(VarUInteger 16) - .storeAddress(Jetton_Wallet_DST) //destination:MsgAddress - .storeAddress(Wallet_OWNER) //response_destination:MsgAddress - .storeUint(0, 1) //custom_payload:(Maybe ^Cell) + .storeUint(0, 64) // query_id:uint64 + .storeCoins(1000000) // amount:(VarUInteger 16) - 6 decimals for jUSDT, 9 decimals as 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) - .endCell(); //forward_payload:(Either Cell ^Cell) + .endCell(); // forward_payload:(Either Cell ^Cell) ``` -#### Jetton Burn +```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('EQBXvufa5Q9HO5O8W1J5QxfDHeSryUY6zQjOI7NDt_Zr7LCV'); + 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())); +} +``` -```js -let body = beginCell() - //jetton burn message body - .endCell() +#### Jetton Burn + +```js await connector.sendTransaction({ validUntil: Math.floor(Date.now() / 1000) + 360, messages: [ @@ -228,9 +254,52 @@ await connector.sendTransaction({ ### NFTs +#### Transfer NFT + +Transfer the `NFTitem` to a new owner `NEW_OWNER_WALLET`. + +```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 + +`body` typically should be done according the following way: + +```js + import { Address, beginCell, Cell, 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(5fcc3d14, 32) // NFT transfer op code + .storeUint(0, 64) // query_id:uint64 + .storeAddress(NEW_OWNER_WALLET) // destination:MsgAddress + .storeUint(0, 1) // custom_payload:(Maybe ^Cell) + .storeCoins(toNano('0.000000001')) // forward_amount:(VarUInteger 16) + .storeAddress(Wallet_DST) // response_destination:MsgAddress + .storeUint(0,1) // forward_amount:(VarUInteger 16) + .endCell(); +``` + +`WALLET_DST` - Address - The address of the initial NFT owner for the receiving excess + + #### Deploy NFT -#### Sale NFT +#### Buy NFT ## TON Connect Python SDK From c25c068eee39d7ff4afdddd522df8236fb6868c6 Mon Sep 17 00:00:00 2001 From: AlexG Date: Sat, 5 Aug 2023 01:46:10 +0400 Subject: [PATCH 08/14] messages_fixes --- docs/develop/dapps/ton-connect/message-builders.mdx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/develop/dapps/ton-connect/message-builders.mdx b/docs/develop/dapps/ton-connect/message-builders.mdx index 9d4caa6177..3effefc7f5 100644 --- a/docs/develop/dapps/ton-connect/message-builders.mdx +++ b/docs/develop/dapps/ton-connect/message-builders.mdx @@ -193,7 +193,8 @@ await connector.sendTransaction({ .storeAddress(Wallet_SRC) // response_destination:MsgAddress .storeUint(0, 1) // custom_payload:(Maybe ^Cell) .storeCoins(toNano(0.05)) // forward_ton_amount:(VarUInteger 16) - .endCell(); // forward_payload:(Either Cell ^Cell) + .storeUInt(0,1) // forward_payload:(Either Cell ^Cell) + .endCell(); ``` ```js @@ -284,13 +285,13 @@ await connector.sendTransaction({ // forward_amount:(VarUInteger 16) forward_payload:(Either Cell ^Cell) = InternalMsgBody; const body = beginCell() - .storeUint(5fcc3d14, 32) // NFT transfer op code + .storeUint(0x5fcc3d14, 32) // NFT transfer op code 0x5fcc3d14 .storeUint(0, 64) // query_id:uint64 - .storeAddress(NEW_OWNER_WALLET) // destination:MsgAddress + .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) - .storeAddress(Wallet_DST) // response_destination:MsgAddress - .storeUint(0,1) // forward_amount:(VarUInteger 16) + .storeUint(0,1) // forward_payload:(Either Cell ^Cell) .endCell(); ``` From d9c3895e3d53bf31855ea98a8197866e99db475c Mon Sep 17 00:00:00 2001 From: AlexG Date: Mon, 7 Aug 2023 13:45:52 +0400 Subject: [PATCH 09/14] ton-connect_examples_added --- .../dapps/ton-connect/message-builders.mdx | 416 ++++++++++++------ 1 file changed, 282 insertions(+), 134 deletions(-) diff --git a/docs/develop/dapps/ton-connect/message-builders.mdx b/docs/develop/dapps/ton-connect/message-builders.mdx index 3effefc7f5..9548e0890a 100644 --- a/docs/develop/dapps/ton-connect/message-builders.mdx +++ b/docs/develop/dapps/ton-connect/message-builders.mdx @@ -3,132 +3,59 @@ While using TON Connect you should build Message Body for Payload for various transactions. Here you can find most relatable examples for payload for using it in TON Connect SDKs. :::warning -Page in development. +The page is under development. ::: -## Regular TON Transfer -As ton-connect SDK is already wrapper above messages, we have no problem to prepare regular Transfer. For the following actions we should specify Payload(Message Body) +## Regular TON Transfer Example +TON Connect SDKs include wrappers for sending messages, making it easy to prepare regular transfers of Toncoins between two wallets. For example, a regular TON transfer using the TON Connect JS SDK can be executed as follows: - -## TON Connect React UI - -### Jettons - -Suppose, we specified simple hook built with ton-connect/react-ui useJettonContract.ts, which defines mint request from our application: - -
-Open entire script +if (!connector.connected) { + alert('Please connect wallet to send the transaction!'); +} ```ts -import { useEffect, useState } from "react"; -import { Address, fromNano, OpenedContract, toNano } from "ton-core"; -import {Mint, SampleJetton} from "../../build/SampleJetton/tact_SampleJetton"; -import {JettonDefaultWallet} from "../../build/SampleJetton/tact_JettonDefaultWallet"; -import { useAsyncInitialize } from "./useAsyncInitialize"; -import { useTonClient } from "./useTonClient"; -import { useTonConnect } from "./useTonConnect"; - -const sleep = (time: number) => new Promise((resolve) => setTimeout(resolve, time)) - -export function useJettonContract() { - const {client} = useTonClient() - const {wallet, sender} = useTonConnect() - const [balance, setBalance] = useState() - - const jettonContract = useAsyncInitialize(async()=>{ - if(!client || !wallet) return; - - const contract = SampleJetton.fromAddress(Address.parse("EQB8StgTQXidy32a8xfu7j4HMoWYV0b0cFM8nXsP2cza_b7Y")) - - return client.open(contract) as OpenedContract - }, [client, wallet]) - - const jettonWalletContract = useAsyncInitialize(async()=>{ - if(!jettonContract || !client) return; - - const jettonWalletAddress = await jettonContract.getGetWalletAddress( - Address.parse(Address.parse(wallet!).toString()) - ) - - return client.open(JettonDefaultWallet.fromAddress(jettonWalletAddress)) - }, [jettonContract, client]) - - useEffect(()=>{ - async function getBalance() { - if(!jettonWalletContract) return - setBalance(null) - const balance = (await jettonWalletContract.getGetWalletData()).balance - setBalance(fromNano(balance)) - await sleep(5000) - getBalance() - } - - getBalance() - - }, [jettonWalletContract]) - - return { - jettonWalletAddress: jettonWalletContract?.address.toString(), - balance: balance, - mint: () => { - const message: Mint = { - $$type: "Mint", - amount: 150n - } +if (!connector.connected) { + alert('Please connect wallet to send the transaction!'); +} - jettonContract?.send(sender, { - value: toNano("0.05") - }, message) +const transaction = { + messages: [ + { + address: "0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F", // destination address + amount: "20000000" //Toncoin in nanotons } - } + ] } ``` -
+For other custom tasks, a specific payload should be specified. -```ts -/// previous part - return { - jettonWalletAddress: jettonWalletContract?.address.toString(), - balance: balance, - mint: () => { - const message: Mint = { - $$type: "Mint", - amount: 150n - } - - jettonContract?.send(sender, { - value: toNano("0.05") - }, message) - } - } -``` -Here our payload defined by sending `send()` message with following specs: - -- `jettonWalletAddress` - Address, JettonWallet address, that defined based on JettonMaser and Wallet contracts -- `balance` - Integer, amount of Toncoin for gas payments in nanotons. -- `mint` - function, which invokes internal transfer from jettonContract(jetton master) to sender's Jetton Wallet - - `sender` - wallet address, which requested mint and which will receive jettons on his Jetton Wallet - - `value` - amount of Toncoins carried for gas payments between Jetton Master and new Jetton Wallet - - `message` - payload for the jettonContract, which defines what should be done - - `$$type`: string, "Mint" string (or corresponded op-code for Mint) - - `amount`: bigint, amount of Jettons should be minted +## TON Connect JS SDK Examples +### Transfer with comment - -```ts "title" = "destination address" +```js +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(); +await connector.sendTransaction({ + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: jettonWalletContract, + amount: toNano("0.05"), + payload: body.toBoc().toString("base64") + } + ] +}) ``` - -#### Jetton Transfer - - - -## TON Connect JS SDK +### Jettons (Tokens) transaction #### Mint Jetton @@ -159,27 +86,10 @@ await connector.sendTransaction({ #### Jetton Transfer -```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, 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 - -`body` typically should be done according the following way: +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 { Address, beginCell, Cell, toNano} from '@ton/ton' + 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) @@ -188,7 +98,7 @@ await connector.sendTransaction({ const body = beginCell() .storeUint(0xf8a7ea5, 32) // jetton transfer op code .storeUint(0, 64) // query_id:uint64 - .storeCoins(1000000) // amount:(VarUInteger 16) - 6 decimals for jUSDT, 9 decimals as default + .storeCoins(1000000) // amount:(VarUInteger 16) - Jetton amount for transfer (6 - jUSDT, 9 - default) .storeAddress(Wallet_DST) // destination:MsgAddress .storeAddress(Wallet_SRC) // response_destination:MsgAddress .storeUint(0, 1) // custom_payload:(Maybe ^Cell) @@ -197,6 +107,28 @@ await connector.sendTransaction({ .endCell(); ``` +Next, sending the transaction with this body to jettonWalletContract destination executed: + +```js +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") + } + ] +}) +``` + +- `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' @@ -206,7 +138,7 @@ async function main() { apiKey: 'put your api key' }) - const jettonWalletAddress = Address.parse('EQBXvufa5Q9HO5O8W1J5QxfDHeSryUY6zQjOI7NDt_Zr7LCV'); + const jettonWalletAddress = Address.parse('Sender_Jetton_Wallet'); let jettonWalletDataResult = await client.runMethod(jettonWalletAddress, 'get_wallet_data'); jettonWalletDataResult.stack.readNumber(); const ownerAddress = jettonWalletDataResult.stack.readAddress(); @@ -231,10 +163,28 @@ async function main() { 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, toNano} 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(); +``` + ```js await connector.sendTransaction({ @@ -249,9 +199,9 @@ await connector.sendTransaction({ }) ``` -- `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 jetton wallet, which defines what should be done +- `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 ### NFTs @@ -298,9 +248,207 @@ await connector.sendTransaction({ `WALLET_DST` - Address - The address of the initial NFT owner for the receiving excess -#### Deploy NFT +#### Sale NFT Example + +Here example of preparing message and transaction for sale on GetGems markteplace, according to contract [nft-fixprice-sale-v3r2.fc](https://github.com/getgems-io/nft-contracts/blob/main/packages/contracts/sources/nft-fixprice-sale-v3r2.fc) + +#### Buy NFT Example + + +## TON Connect React UI (WIP) + +[//]: # (#### Jettons) + +[//]: # () +[//]: # (Suppose, we specified simple hook built with ton-connect/react-ui useJettonContract.ts, which defines mint request from our application:) + +[//]: # () +[//]: # (
) + +[//]: # ( Open entire script) + +[//]: # () +[//]: # ( ```ts) + +[//]: # ( import { useEffect, useState } from "react";) + +[//]: # ( import { Address, fromNano, OpenedContract, toNano } from "ton-core";) + +[//]: # ( import {Mint, SampleJetton} from "../../build/SampleJetton/tact_SampleJetton";) + +[//]: # ( import {JettonDefaultWallet} from "../../build/SampleJetton/tact_JettonDefaultWallet";) + +[//]: # ( import { useAsyncInitialize } from "./useAsyncInitialize";) + +[//]: # ( import { useTonClient } from "./useTonClient";) + +[//]: # ( import { useTonConnect } from "./useTonConnect";) + +[//]: # () +[//]: # ( const sleep = (time: number) => new Promise((resolve) => setTimeout(resolve, time))) + +[//]: # () +[//]: # ( export function useJettonContract() {) + +[//]: # ( const {client} = useTonClient()) + +[//]: # ( const {wallet, sender} = useTonConnect()) + +[//]: # ( const [balance, setBalance] = useState()) + +[//]: # () +[//]: # ( const jettonContract = useAsyncInitialize(async()=>{) + +[//]: # ( if(!client || !wallet) return;) + +[//]: # () +[//]: # ( const contract = SampleJetton.fromAddress(Address.parse("EQB8StgTQXidy32a8xfu7j4HMoWYV0b0cFM8nXsP2cza_b7Y"))) + +[//]: # () +[//]: # ( return client.open(contract) as OpenedContract) + +[//]: # (}, [client, wallet])) + +[//]: # () +[//]: # ( const jettonWalletContract = useAsyncInitialize(async()=>{) + +[//]: # ( if(!jettonContract || !client) return;) + +[//]: # () +[//]: # ( const jettonWalletAddress = await jettonContract.getGetWalletAddress() + +[//]: # ( Address.parse(Address.parse(wallet!).toString())) + +[//]: # ( )) + +[//]: # () +[//]: # ( return client.open(JettonDefaultWallet.fromAddress(jettonWalletAddress))) + +[//]: # (}, [jettonContract, client])) + +[//]: # () +[//]: # ( useEffect(()=>{) + +[//]: # ( async function getBalance() {) + +[//]: # ( if(!jettonWalletContract) return) + +[//]: # ( setBalance(null)) + +[//]: # ( const balance = (await jettonWalletContract.getGetWalletData()).balance) + +[//]: # ( setBalance(fromNano(balance))) + +[//]: # ( await sleep(5000)) + +[//]: # ( getBalance()) + +[//]: # (}) + +[//]: # () +[//]: # ( getBalance()) + +[//]: # () +[//]: # (}, [jettonWalletContract])) + +[//]: # () +[//]: # ( return {) + +[//]: # ( jettonWalletAddress: jettonWalletContract?.address.toString(),) + +[//]: # ( balance: balance,) + +[//]: # ( mint: () => {) + +[//]: # ( const message: Mint = {) + +[//]: # ( $$type: "Mint",) + +[//]: # ( amount: 150n) + +[//]: # (}) + +[//]: # () +[//]: # ( jettonContract?.send(sender, {) + +[//]: # ( value: toNano("0.05")) + +[//]: # (}, message)) + +[//]: # (}) + +[//]: # (}) + +[//]: # (}) + +[//]: # ( ```) + +[//]: # () +[//]: # (
) + +[//]: # () +[//]: # (```ts) + +[//]: # (/// previous part) + +[//]: # ( return {) + +[//]: # ( jettonWalletAddress: jettonWalletContract?.address.toString(),) + +[//]: # ( balance: balance,) + +[//]: # ( mint: () => {) + +[//]: # ( const message: Mint = {) + +[//]: # ( $$type: "Mint",) + +[//]: # ( amount: 150n) + +[//]: # ( }) + +[//]: # () +[//]: # ( jettonContract?.send(sender, {) + +[//]: # ( value: toNano("0.05")) + +[//]: # ( }, message)) + +[//]: # ( }) + +[//]: # ( }) + +[//]: # (```) + +[//]: # () +[//]: # (Here our payload defined by sending `send()` message with following specs:) + +[//]: # () +[//]: # (- `jettonWalletAddress` - Address, JettonWallet address, that defined based on JettonMaser and Wallet contracts) + +[//]: # (- `balance` - Integer, amount of Toncoin for gas payments in nanotons.) + +[//]: # (- `mint` - function, which invokes internal transfer from jettonContract(jetton master) to sender's Jetton Wallet) + +[//]: # (- `sender` - wallet address, which requested mint and which will receive jettons on his Jetton Wallet) + +[//]: # (- `value` - amount of Toncoins carried for gas payments between Jetton Master and new Jetton Wallet) + +[//]: # (- `message` - payload for the jettonContract, which defines what should be done) + +[//]: # (- `$$type`: string, "Mint" string (or corresponded op-code for Mint)) + +[//]: # ( - `amount`: bigint, amount of Jettons should be minted) + +[//]: # () +[//]: # () +[//]: # () +[//]: # (```ts "title" = "destination address") + +[//]: # () +[//]: # () +[//]: # (```) -#### Buy NFT ## TON Connect Python SDK From 5c531fd61ae1496472a8c90034ae051c30ba4ac2 Mon Sep 17 00:00:00 2001 From: AlexG Date: Mon, 7 Aug 2023 18:36:41 +0400 Subject: [PATCH 10/14] nft_sale_example_added --- .../dapps/ton-connect/message-builders.mdx | 290 +++++------------- 1 file changed, 79 insertions(+), 211 deletions(-) diff --git a/docs/develop/dapps/ton-connect/message-builders.mdx b/docs/develop/dapps/ton-connect/message-builders.mdx index 9548e0890a..2bd34ec4f8 100644 --- a/docs/develop/dapps/ton-connect/message-builders.mdx +++ b/docs/develop/dapps/ton-connect/message-builders.mdx @@ -129,6 +129,8 @@ await connector.sendTransaction({
Jetton Wallet State Init and Address preparation example + + ```js import { Address, TonClient, beginCell, StateInit, storeStateInit } from '@ton/ton' @@ -163,6 +165,7 @@ async function main() { console.log(new Address(0, stateInitCell.hash())); } ``` +
#### Jetton Burn @@ -229,7 +232,7 @@ await connector.sendTransaction({ `body` typically should be done according the following way: ```js - import { Address, beginCell, Cell, toNano} from '@ton/ton' +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; @@ -248,224 +251,89 @@ await connector.sendTransaction({ `WALLET_DST` - Address - The address of the initial NFT owner for the receiving excess -#### Sale NFT Example - -Here example of preparing message and transaction for sale on GetGems markteplace, according to contract [nft-fixprice-sale-v3r2.fc](https://github.com/getgems-io/nft-contracts/blob/main/packages/contracts/sources/nft-fixprice-sale-v3r2.fc) - -#### Buy NFT Example - - -## TON Connect React UI (WIP) - -[//]: # (#### Jettons) - -[//]: # () -[//]: # (Suppose, we specified simple hook built with ton-connect/react-ui useJettonContract.ts, which defines mint request from our application:) - -[//]: # () -[//]: # (
) - -[//]: # ( Open entire script) - -[//]: # () -[//]: # ( ```ts) - -[//]: # ( import { useEffect, useState } from "react";) - -[//]: # ( import { Address, fromNano, OpenedContract, toNano } from "ton-core";) - -[//]: # ( import {Mint, SampleJetton} from "../../build/SampleJetton/tact_SampleJetton";) - -[//]: # ( import {JettonDefaultWallet} from "../../build/SampleJetton/tact_JettonDefaultWallet";) - -[//]: # ( import { useAsyncInitialize } from "./useAsyncInitialize";) - -[//]: # ( import { useTonClient } from "./useTonClient";) - -[//]: # ( import { useTonConnect } from "./useTonConnect";) - -[//]: # () -[//]: # ( const sleep = (time: number) => new Promise((resolve) => setTimeout(resolve, time))) - -[//]: # () -[//]: # ( export function useJettonContract() {) - -[//]: # ( const {client} = useTonClient()) - -[//]: # ( const {wallet, sender} = useTonConnect()) - -[//]: # ( const [balance, setBalance] = useState()) - -[//]: # () -[//]: # ( const jettonContract = useAsyncInitialize(async()=>{) - -[//]: # ( if(!client || !wallet) return;) - -[//]: # () -[//]: # ( const contract = SampleJetton.fromAddress(Address.parse("EQB8StgTQXidy32a8xfu7j4HMoWYV0b0cFM8nXsP2cza_b7Y"))) - -[//]: # () -[//]: # ( return client.open(contract) as OpenedContract) - -[//]: # (}, [client, wallet])) - -[//]: # () -[//]: # ( const jettonWalletContract = useAsyncInitialize(async()=>{) - -[//]: # ( if(!jettonContract || !client) return;) - -[//]: # () -[//]: # ( const jettonWalletAddress = await jettonContract.getGetWalletAddress() - -[//]: # ( Address.parse(Address.parse(wallet!).toString())) - -[//]: # ( )) - -[//]: # () -[//]: # ( return client.open(JettonDefaultWallet.fromAddress(jettonWalletAddress))) - -[//]: # (}, [jettonContract, client])) - -[//]: # () -[//]: # ( useEffect(()=>{) - -[//]: # ( async function getBalance() {) - -[//]: # ( if(!jettonWalletContract) return) - -[//]: # ( setBalance(null)) - -[//]: # ( const balance = (await jettonWalletContract.getGetWalletData()).balance) - -[//]: # ( setBalance(fromNano(balance))) - -[//]: # ( await sleep(5000)) - -[//]: # ( getBalance()) - -[//]: # (}) - -[//]: # () -[//]: # ( getBalance()) - -[//]: # () -[//]: # (}, [jettonWalletContract])) - -[//]: # () -[//]: # ( return {) - -[//]: # ( jettonWalletAddress: jettonWalletContract?.address.toString(),) - -[//]: # ( balance: balance,) - -[//]: # ( mint: () => {) - -[//]: # ( const message: Mint = {) - -[//]: # ( $$type: "Mint",) - -[//]: # ( amount: 150n) - -[//]: # (}) - -[//]: # () -[//]: # ( jettonContract?.send(sender, {) - -[//]: # ( value: toNano("0.05")) +#### NFT Sale Example +Here example of preparing message and transaction for sale on GetGems markteplace, according to contract [nft-fixprice-sale-v3r2](https://github.com/getgems-io/nft-contracts/blob/main/packages/contracts/sources/nft-fixprice-sale-v3r2.fc). -[//]: # (}, message)) -[//]: # (}) - -[//]: # (}) - -[//]: # (}) - -[//]: # ( ```) - -[//]: # () -[//]: # (
) - -[//]: # () -[//]: # (```ts) - -[//]: # (/// previous part) - -[//]: # ( return {) - -[//]: # ( jettonWalletAddress: jettonWalletContract?.address.toString(),) - -[//]: # ( balance: balance,) - -[//]: # ( mint: () => {) - -[//]: # ( const message: Mint = {) - -[//]: # ( $$type: "Mint",) - -[//]: # ( amount: 150n) - -[//]: # ( }) - -[//]: # () -[//]: # ( jettonContract?.send(sender, {) - -[//]: # ( value: toNano("0.05")) - -[//]: # ( }, message)) - -[//]: # ( }) - -[//]: # ( }) - -[//]: # (```) - -[//]: # () -[//]: # (Here our payload defined by sending `send()` message with following specs:) - -[//]: # () -[//]: # (- `jettonWalletAddress` - Address, JettonWallet address, that defined based on JettonMaser and Wallet contracts) - -[//]: # (- `balance` - Integer, amount of Toncoin for gas payments in nanotons.) - -[//]: # (- `mint` - function, which invokes internal transfer from jettonContract(jetton master) to sender's Jetton Wallet) - -[//]: # (- `sender` - wallet address, which requested mint and which will receive jettons on his Jetton Wallet) - -[//]: # (- `value` - amount of Toncoins carried for gas payments between Jetton Master and new Jetton Wallet) - -[//]: # (- `message` - payload for the jettonContract, which defines what should be done) - -[//]: # (- `$$type`: string, "Mint" string (or corresponded op-code for Mint)) - -[//]: # ( - `amount`: bigint, amount of Jettons should be minted) - -[//]: # () -[//]: # () -[//]: # () -[//]: # (```ts "title" = "destination address") - -[//]: # () -[//]: # () -[//]: # (```) - - - -## TON Connect Python SDK +```js +import { Address, beginCell, StateInit, storeStateInit, toNano, Cell } from '@ton/ton' -### Jettons +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(); -#### Jetton Transfer + 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(); -#### Jetton Mint + const stateInit: StateInit = { + code: fixPriceV3R2Code, + data: saleData + }; + const stateInitCell = beginCell() + .store(storeStateInit(stateInit)) + .endCell(); -#### Jetton Burn + // not needed, just for example + const saleContractAddress = new Address(0, stateInitCell.hash()); -### NFTs + const saleBody = beginCell() + .storeUint(1, 32) // just accept coins on deploy + .storeUint(0, 64) + .endCell(); -#### NFT Transfer + 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(); +``` -#### NFT Sale (getgems) -#### NFT Buy (getgems) +```js +await connector.sendTransaction({ + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: nftItemAddress, + amount: toNano("1.08"), + payload: body.toBoc().toString("base64") + } + ] +}) +``` \ No newline at end of file From 752b16ef0af39208f7c085c72342142c871a91b6 Mon Sep 17 00:00:00 2001 From: AlexG Date: Tue, 8 Aug 2023 15:18:50 +0400 Subject: [PATCH 11/14] python_examples_added --- .../dapps/ton-connect/message-builders.mdx | 364 +++++++++++++++--- 1 file changed, 300 insertions(+), 64 deletions(-) diff --git a/docs/develop/dapps/ton-connect/message-builders.mdx b/docs/develop/dapps/ton-connect/message-builders.mdx index 2bd34ec4f8..56e4a5d5cd 100644 --- a/docs/develop/dapps/ton-connect/message-builders.mdx +++ b/docs/develop/dapps/ton-connect/message-builders.mdx @@ -7,34 +7,41 @@ The page is under development. ::: -## Regular TON Transfer Example -TON Connect SDKs include wrappers for sending messages, making it easy to prepare regular transfers of Toncoins between two wallets. For example, a regular TON transfer using the TON Connect JS SDK can be executed as follows: +## TON Connect JS SDK Examples -if (!connector.connected) { - alert('Please connect wallet to send the transaction!'); -} +### Regular TON Transfer +TON Connect SDKs include wrappers for sending messages, making it easy to prepare regular transfers of Toncoins between two wallets. + +All JS examples created based on connector @tonconnect/sdk: ```ts -if (!connector.connected) { - alert('Please connect wallet to send the transaction!'); -} +import TonConnect from '@tonconnect/sdk'; +const connector = new TonConnect(); +``` + +A regular TON transfer using the TON Connect JS SDK can be executed as follows: -const transaction = { +```ts +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 other custom tasks, a specific payload should be specified. -## TON Connect JS SDK Examples -### Transfer with comment + +### Transfer With Comment ```js const body = beginCell() @@ -55,36 +62,7 @@ await connector.sendTransaction({ }) ``` -### Jettons (Tokens) transaction - -#### Mint Jetton - -```js -let body = beginCell() - //Mint message body - .endCell() - - -await connector.sendTransaction({ - validUntil: Math.floor(Date.now() / 1000) + 360, - messages: [ - { - address: jettonWalletContract, - amount: toNano("0.05"), - payload: body.toBoc().toString("base64") - } - ] -}) -``` - -- `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, which defines what should be done - - `$$type`: string, "Mint" string (or corresponded op-code for Mint) - - `amount`: bigint, amount of Jettons should be minted - - -#### Jetton Transfer +### 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: @@ -110,6 +88,9 @@ The `body` for Jetton Transfer([TEP-74](https://github.com/ton-blockchain/TEPs/b Next, sending the transaction with this body to jettonWalletContract destination executed: ```js +import TonConnect from '@tonconnect/sdk'; +const connector = new TonConnect(); +//... await connector.sendTransaction({ validUntil: Math.floor(Date.now() / 1000) + 360, messages: [ @@ -121,7 +102,7 @@ await connector.sendTransaction({ ] }) ``` - +- `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 @@ -168,7 +149,7 @@ async function main() { -#### Jetton Burn +### 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: @@ -188,6 +169,7 @@ The `body` for Jetton Burn([TEP-74](https://github.com/ton-blockchain/TEPs/blob/ .endCell(); ``` +Message places into the following request: ```js await connector.sendTransaction({ @@ -206,9 +188,7 @@ await connector.sendTransaction({ - `amount` - Integer, amount of Toncoin for gas payments in nanotons. - `body` - payload for the jetton wallet with the `burn#595f07bc` op code -### NFTs - -#### Transfer NFT +### NFT Transfer Transfer the `NFTitem` to a new owner `NEW_OWNER_WALLET`. @@ -229,7 +209,7 @@ await connector.sendTransaction({ - `balance` - Integer, amount of Toncoin for gas payments in nanotons. - `body` - payload for the NFT contract -`body` typically should be done according the following way: +The `body` message typically should be done according the following way: ```js import { beginCell, toNano} from '@ton/ton' @@ -251,8 +231,29 @@ import { beginCell, toNano} from '@ton/ton' `WALLET_DST` - Address - The address of the initial NFT owner for the receiving excess -#### NFT Sale Example -Here example of preparing message and transaction for sale on GetGems markteplace, according to contract [nft-fixprice-sale-v3r2](https://github.com/getgems-io/nft-contracts/blob/main/packages/contracts/sources/nft-fixprice-sale-v3r2.fc). +#### 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 @@ -308,22 +309,24 @@ const destinationAddress = Address.parse("EQAIFunALREOeQ99syMbO6sSzM_Fa1RsPD5TBo .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 + 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(); + .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({ @@ -332,8 +335,241 @@ await connector.sendTransaction({ { address: nftItemAddress, amount: toNano("1.08"), - payload: body.toBoc().toString("base64") + payload: transferNftBody.toBoc().toString("base64") } ] }) -``` \ No newline at end of file +``` + +#### 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 + ), + ] +} +``` + + From 15dee89c300b2402d71cbc2adf2a93dff30805f3 Mon Sep 17 00:00:00 2001 From: AlexG Date: Wed, 9 Aug 2023 13:41:49 +0400 Subject: [PATCH 12/14] messages_page_updated improved description --- .../dapps/ton-connect/message-builders.mdx | 110 ++++++++++++++++-- .../develop/dapps/ton-connect/transactions.md | 4 + 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/docs/develop/dapps/ton-connect/message-builders.mdx b/docs/develop/dapps/ton-connect/message-builders.mdx index 56e4a5d5cd..da4563f639 100644 --- a/docs/develop/dapps/ton-connect/message-builders.mdx +++ b/docs/develop/dapps/ton-connect/message-builders.mdx @@ -1,27 +1,64 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + # Preparing Messages -While using TON Connect you should build Message Body for Payload for various transactions. Here you can find most relatable examples for payload for using it in TON Connect SDKs. +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 -### Regular TON Transfer -TON Connect SDKs include wrappers for sending messages, making it easy to prepare regular transfers of Toncoins between two wallets. +### Transaction Template -All JS examples created based on connector @tonconnect/sdk: +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: -```ts + + + +```js import TonConnect from '@tonconnect/sdk'; const connector = new TonConnect(); + +await connector.sendTransaction({ + //transaction body +}) + +``` + + + + + +```js +import TonConnect from '@tonconnect/ui'; + + +transaction = {} //definition of the transaction body + ``` -A regular TON transfer using the TON Connect JS SDK can be executed as follows: + + + +### 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: ```ts +import TonConnect from '@tonconnect/sdk'; +const connector = new TonConnect(); + await connector.sendTransaction({ messages: [ { @@ -30,37 +67,76 @@ await connector.sendTransaction({ } ] }) + ``` :::tip Learn more about [TON Smart Contract Addresses](/learn/overviews/addresses). ::: -For other custom tasks, a specific payload should be specified. +For specific custom transaction, a certain payload must be defined. ### Transfer With 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 TonConnect from '@tonconnect/sdk'; +const connector = new TonConnect(); await connector.sendTransaction({ validUntil: Math.floor(Date.now() / 1000) + 360, messages: [ { - address: jettonWalletContract, + address: destination, amount: toNano("0.05"), payload: body.toBoc().toString("base64") } ] }) ``` + + + + +```js +import TonConnectUI from '@tonconnect/ui' + +const transaction = { + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: jettonWalletContract, + amount: toNano("0.05"), + payload: body.toBoc().toString("base64") + } + ] +} + +const result = await tonConnectUI.sendTransaction(transaction) +``` + + + ### Jetton Transfer @@ -171,6 +247,7 @@ The `body` for Jetton Burn([TEP-74](https://github.com/ton-blockchain/TEPs/blob/ Message places into the following request: + ```js await connector.sendTransaction({ validUntil: Math.floor(Date.now() / 1000) + 360, @@ -231,7 +308,7 @@ import { beginCell, toNano} from '@ton/ton' `WALLET_DST` - Address - The address of the initial NFT owner for the receiving excess -#### NFT Sale (GetGems) +### 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). @@ -333,15 +410,15 @@ await connector.sendTransaction({ validUntil: Math.floor(Date.now() / 1000) + 360, messages: [ { - address: nftItemAddress, - amount: toNano("1.08"), + 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) +### 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`. @@ -573,3 +650,12 @@ transaction = { ``` +## 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 From e6939be6d302935a3812a5efde21e86d08bd683a Mon Sep 17 00:00:00 2001 From: AlexG Date: Wed, 9 Aug 2023 15:47:11 +0400 Subject: [PATCH 13/14] comment_react_ui-added --- .../dapps/ton-connect/message-builders.mdx | 102 +++++++++++++----- 1 file changed, 76 insertions(+), 26 deletions(-) diff --git a/docs/develop/dapps/ton-connect/message-builders.mdx b/docs/develop/dapps/ton-connect/message-builders.mdx index da4563f639..615df16c07 100644 --- a/docs/develop/dapps/ton-connect/message-builders.mdx +++ b/docs/develop/dapps/ton-connect/message-builders.mdx @@ -22,6 +22,30 @@ No matter what level of the task developer are solving, typically it is necessar Examples created based on @tonconnect/sdk and @tonconnect/ui: + + + +```js +import { useTonConnectUI } from '@tonconnect/ui-react'; +const [tonConnectUI] = useTonConnectUI(); + +tonConnectUI.sendTransaction({ + +}) + ``` + + + +```js +import TonConnect from '@tonconnect/ui'; + +transaction = { + //transaction body +} + +``` + + ```js @@ -36,17 +60,9 @@ await connector.sendTransaction({ - -```js -import TonConnect from '@tonconnect/ui'; -transaction = {} //definition of the transaction body - -``` - - ### Regular TON Transfer @@ -55,7 +71,7 @@ TON Connect SDKs include wrappers for sending messages, making it easy to prepar A regular TON transfer using the TON Connect JS SDKs can be executed as follows: -```ts +```js import TonConnect from '@tonconnect/sdk'; const connector = new TonConnect(); @@ -79,7 +95,7 @@ For specific custom transaction, a certain payload must be defined. -### Transfer With Comment +### 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. @@ -95,28 +111,40 @@ const body = beginCell() The transaction body is created by the following: - - - + + ```js -import TonConnect from '@tonconnect/sdk'; -const connector = new TonConnect(); +import { useTonConnectUI } from '@tonconnect/ui-react'; +import { Sender, SenderArguments } from 'ton-core'; + +export function useTonConnect(): { sender: Sender; connected: boolean } { + const [tonConnectUI] = useTonConnectUI(); + + return { + sender: { + send: async (args: SenderArguments) => { + tonConnectUI.sendTransaction({ + messages: [ + { + address: args.to.toString(), + amount: args.value.toString(), + payload: args.body?.toBoc().toString('base64'), + }, + ], + validUntil: Date.now() + 5 * 60 * 1000, // 5 minutes for user to approve + }); + }, + }, + connected: tonConnectUI.connected, + }; +} + -await connector.sendTransaction({ - validUntil: Math.floor(Date.now() / 1000) + 360, - messages: [ - { - address: destination, - amount: toNano("0.05"), - payload: body.toBoc().toString("base64") - } - ] -}) ``` - + ```js import TonConnectUI from '@tonconnect/ui' @@ -135,6 +163,28 @@ const transaction = { 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") + } + ] +}) +``` + + + From 83bd740642bfa3d6943685cbb020933d6cbac439 Mon Sep 17 00:00:00 2001 From: AlexG Date: Wed, 9 Aug 2023 17:21:34 +0400 Subject: [PATCH 14/14] added_switcher_update_1 --- .../dapps/ton-connect/message-builders.mdx | 238 +++++++++++++----- 1 file changed, 180 insertions(+), 58 deletions(-) diff --git a/docs/develop/dapps/ton-connect/message-builders.mdx b/docs/develop/dapps/ton-connect/message-builders.mdx index 615df16c07..cced9e4d04 100644 --- a/docs/develop/dapps/ton-connect/message-builders.mdx +++ b/docs/develop/dapps/ton-connect/message-builders.mdx @@ -23,26 +23,46 @@ Examples created based on @tonconnect/sdk and @tonconnect/ui: - + ```js import { useTonConnectUI } from '@tonconnect/ui-react'; const [tonConnectUI] = useTonConnectUI(); -tonConnectUI.sendTransaction({ - +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) + ``` @@ -60,9 +80,6 @@ await connector.sendTransaction({
- - -
### Regular TON Transfer @@ -71,6 +88,66 @@ TON Connect SDKs include wrappers for sending messages, making it easy to prepar 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(); @@ -85,6 +162,8 @@ await connector.sendTransaction({ }) ``` + +
:::tip Learn more about [TON Smart Contract Addresses](/learn/overviews/addresses). @@ -111,40 +190,39 @@ const body = beginCell() The transaction body is created by the following: - + + ```js import { useTonConnectUI } from '@tonconnect/ui-react'; -import { Sender, SenderArguments } from 'ton-core'; - -export function useTonConnect(): { sender: Sender; connected: boolean } { - const [tonConnectUI] = useTonConnectUI(); - - return { - sender: { - send: async (args: SenderArguments) => { - tonConnectUI.sendTransaction({ - messages: [ - { - address: args.to.toString(), - amount: args.value.toString(), - payload: args.body?.toBoc().toString('base64'), - }, - ], - validUntil: Date.now() + 5 * 60 * 1000, // 5 minutes for user to approve - }); - }, - }, - connected: tonConnectUI.connected, - }; -} +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' @@ -153,7 +231,7 @@ const transaction = { validUntil: Math.floor(Date.now() / 1000) + 360, messages: [ { - address: jettonWalletContract, + address: destination, amount: toNano("0.05"), payload: body.toBoc().toString("base64") } @@ -162,10 +240,10 @@ const transaction = { const result = await tonConnectUI.sendTransaction(transaction) ``` - - + + ```js import TonConnect from '@tonconnect/sdk'; @@ -183,8 +261,6 @@ await connector.sendTransaction({ }) ``` - -
@@ -202,7 +278,7 @@ The `body` for Jetton Transfer([TEP-74](https://github.com/ton-blockchain/TEPs/b 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 (6 - jUSDT, 9 - default) + .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) @@ -213,6 +289,19 @@ The `body` for Jetton Transfer([TEP-74](https://github.com/ton-blockchain/TEPs/b 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(); @@ -228,6 +317,10 @@ await connector.sendTransaction({ ] }) ``` + + + + - `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. @@ -281,7 +374,7 @@ The `body` for Jetton Burn([TEP-74](https://github.com/ton-blockchain/TEPs/blob/ ```js - import {beginCell, toNano} from '@ton/ton' + import {beginCell} from '@ton/ton' // burn#595f07bc query_id:uint64 amount:(VarUInteger 16) // response_destination:MsgAddress custom_payload:(Maybe ^Cell) // = InternalMsgBody; @@ -298,6 +391,19 @@ The `body` for Jetton Burn([TEP-74](https://github.com/ton-blockchain/TEPs/blob/ Message places into the following request: + + +```js +//react version +``` + + + + +// tonconnect-ui version + + + ```js await connector.sendTransaction({ validUntil: Math.floor(Date.now() / 1000) + 360, @@ -311,31 +417,15 @@ await connector.sendTransaction({ }) ``` + + + - `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 -Transfer the `NFTitem` to a new owner `NEW_OWNER_WALLET`. - -```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 - The `body` message typically should be done according the following way: ```js @@ -356,7 +446,39 @@ import { beginCell, toNano} from '@ton/ton' ``` `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)