准备消息
在使用TON Connect时,您应该为在各种交易中使用的Payload构造消息体。在此页面上,您可以找到与TON Connect SDK一起使用的payload的最相关示例。
期望您学习了创建TON Connect连接的基础知识。了解更多请参阅集成手册。
TON Connect JS SDK 示例
交易模板
无论开发者正在解决的任务级别如何,通常都需要使用来自@tonconnect/sdk或@tonconnect/ui的连接器实体。 基于@tonconnect/sdk和@tonconnect/ui创建的示例:
- @tonconnect/ui-react
- @tonconnect/ui
- @tonconnect/sdk
import { useTonConnectUI } from '@tonconnect/ui-react';
const [tonConnectUI] = useTonConnectUI();
const transaction = {
    //transaction body
})
export const Settings = () => {
    const [tonConnectUI, setOptions] = useTonConnectUI();
    return (
        <div>
            <button onClick={() => tonConnectUI.sendTransaction(transaction)}>
                Send transaction
            </button>
        </div>
    );
};
import TonConnectUI from '@tonconnect/ui';
const tonConnectUI = new TonConnectUI({ //连接应用
    manifestUrl: 'https://<YOUR_APP_URL>/tonconnect-manifest.json',
    buttonRootId: '<YOUR_CONNECT_BUTTON_ANCHOR_ID>'
});
const transaction = {
    //transaction body
}
const result = await tonConnectUI.sendTransaction(transaction)
import TonConnect from '@tonconnect/sdk';
const connector = new TonConnect();
await connector.sendTransaction({
    //transaction body
})
常规 TON 转账
TON Connect SDK提供了发送消息的封装器,使准备两个钱包之间的Toncoin的常规转账作为默认交易无需载荷变得容易。
使用TON Connect JS SDK执行常规TON转账如下所示:
- @tonconnect/react-ui
- @tonconnect/ui
- @tonconnect/sdk
import { useTonConnectUI } from '@tonconnect/ui-react';
const [tonConnectUI] = useTonConnectUI();
const transaction = {
    messages: [
        {
            address: "0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F", // 目的地址
            amount: "20000000" //以nanotons计的Toncoin
        }
    ]
}
export const Settings = () => {
    const [tonConnectUI, setOptions] = useTonConnectUI();
    return (
        <div>
            <button onClick={() => tonConnectUI.sendTransaction(transaction)}>
                Send transaction
            </button>
        </div>
    );
};
import TonConnectUI from '@tonconnect/ui';
const tonConnectUI = new TonConnectUI({ //连接应用
    manifestUrl: 'https://<YOUR_APP_URL>/tonconnect-manifest.json',
    buttonRootId: '<YOUR_CONNECT_BUTTON_ANCHOR_ID>'
});
const transaction = {
    messages: [
        {
            address: "0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F", // 目的地址
            amount: "20000000" //以nanotons计的Toncoin
        }
    ]
}
const result = await tonConnectUI.sendTransaction(transaction)
import TonConnect from '@tonconnect/sdk';
const connector = new TonConnect();
await connector.sendTransaction({
    messages: [
        {
            address: "0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F", // 目的地址
            amount: "20000000" //以nanotons计的Toncoin
        }
    ]
})
了解更多信息请参阅TON智能合约地址。
对于特定的自定义交易,必须定义特定的载荷。
添加评论的转账
最简单的例子是添加一个包含评论的载荷。更多详情请查看此页面。
在交易之前,需要通过@ton/ton JavaScript库准备一个body cell。
import { beginCell } from '@ton/ton'
const body = beginCell()
  .storeUint(0, 32) // 写入32个零位以表示后面将跟随文本评论
  .storeStringTail("Hello, TON!") // 写下我们的文本评论
  .endCell();
通过以下方式创建交易体:
- @tonconnect/react-ui
- @tonconnect/ui
- @tonconnect/sdk
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") // body中带有评论的载荷
        }
    ]
}
export const Settings = () => {
    const [tonConnectUI, setOptions] = useTonConnectUI();
    return (
        <div>
            <button onClick={() => tonConnectUI.sendTransaction(myTransaction)}>
                Send transaction
            </button>
        </div>
    );
};
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") // body中带有评论的载荷
        }
    ]
}
const result = await tonConnectUI.sendTransaction(transaction)
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") // body中带有评论的载荷
    }
  ]
})
Jetton 转账
根据以下方式进行的 Jetton 转账操作的 body(TEP-74) 通常应如下所示:
    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 转账操作码
        .storeUint(0, 64)                         // query_id:uint64
        .storeCoins(1000000)                      // amount:(VarUInteger 16) -  转账的 Jetton 金额(小数位 = 6 - jUSDT, 9 - 默认)
        .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();
然后,将带有此 body 的交易发送到发送者的 jettonWalletContract 执行:
- @tonconnect/react-ui
- @tonconnect/ui
- @tonconnect/sdk
import { useTonConnectUI } from '@tonconnect/ui-react';
const myTransaction = {
    validUntil: Math.floor(Date.now() / 1000) + 360,
    messages: [
        {
            address: jettonWalletContract, // 发送方 Jetton 钱包
            amount: toNano("0.05"), // 用于手续费,超额部分将被退回
            payload: body.toBoc().toString("base64") // 带有 Jetton 转账 body 的载荷
        }
    ]
}
export const Settings = () => {
    const [tonConnectUI, setOptions] = useTonConnectUI();
    return (
        <div>
            <button onClick={() => tonConnectUI.sendTransaction(myTransaction)}>
                Send transaction
            </button>
        </div>
    );
};
import TonConnectUI from '@tonconnect/ui'
const transaction = {
    validUntil: Math.floor(Date.now() / 1000) + 360,
    messages: [
        {
            address: jettonWalletContract,  // 发送方 Jetton 钱包
            amount: toNano("0.05"),         // 用于手续费,超额部分将被退回
            payload: body.toBoc().toString("base64") // 带有 Jetton 转账 body 的载荷
        }
    ]
}
const result = await tonConnectUI.sendTransaction(transaction)
import TonConnect from '@tonconnect/sdk';
const connector = new TonConnect();
//...
await connector.sendTransaction({
  validUntil: Math.floor(Date.now() / 1000) + 360,
  messages: [
    {
      address: jettonWalletContract,            // 发送方 Jetton 钱包
      amount: toNano("0.05"),                   // 用于手续费,超额部分将被退回
      payload: body.toBoc().toString("base64")  // 带有 Jetton 转账 body 的载荷
    }
  ]
})
- validUntil- 消息有效的 UNIX 时间
- jettonWalletAddress- 地址,基于 JettonMaser 和 Wallet 合约定义的 JettonWallet 地址
- balance- 整数,用于gas费用的 Toncoin 金额,以 nanotons 计。
- body- 用于 jettonContract 的载荷
Jetton 钱包状态初始化和地址准备示例
import { Address, TonClient, beginCell, StateInit, storeStateInit } from '@ton/ton'
async function main() {
    const client = new TonClient({
        endpoint: 'https://toncenter.com/api/v2/jsonRPC',
        apiKey: '放置你的 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 销毁
Jetton 销毁(TEP-74) 的body通常应该按照以下方式完成:
    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 销毁操作码
        .storeUint(0, 64)                         // query_id:uint64
        .storeCoins(1000000)                      // amount:(VarUInteger 16) -  以小数形式的 Jetton 金额
        .storeAddress(Wallet_SRC)                 // response_destination:MsgAddress - 持有者的钱包
        .storeUint(0, 1)                          // custom_payload:(Maybe ^Cell) - 通常没有载荷
        .endCell();
消息放入以下请求中:
- @tonconnect/react-ui
- @tonconnect/ui
- @tonconnect/sdk
import { useTonConnectUI } from '@tonconnect/ui-react';
const myTransaction = {
    validUntil: Math.floor(Date.now() / 1000) + 360,
    messages: [
        {
            address: jettonWalletContract, // 持有者的 Jetton 钱包
            amount: toNano("0.05"),  // 用于手续费,超额部分将被退回
            payload: body.toBoc().toString("base64") // 带有 Jetton 销毁 body 的载荷
        }
    ]
}
export const Settings = () => {
    const [tonConnectUI, setOptions] = useTonConnectUI();
    return (
        <div>
            <button onClick={() => tonConnectUI.sendTransaction(myTransaction)}>
                Send transaction
            </button>
        </div>
    );
};
import TonConnectUI from '@tonconnect/ui'
const transaction = {
    validUntil: Math.floor(Date.now() / 1000) + 360,
    messages: [
        {
            address: jettonWalletContract,  // 持有者的 Jetton 钱包
            amount: toNano("0.05"),         // 用于手续费,超额部分将被退回
            payload: body.toBoc().toString("base64") // 带有 Jetton 销毁 body 的载荷
        }
    ]
}
const result = await tonConnectUI.sendTransaction(transaction)
await connector.sendTransaction({
  validUntil: Math.floor(Date.now() / 1000) + 360,
  messages: [
    {
      address: jettonWalletContract, // 持有者的 Jetton 钱包
      amount: toNano("0.05"), // 用于手续费,超额部分将被退回
      payload: body.toBoc().toString("base64") // 带有 Jetton 销毁 body 的载荷
    }
  ]
})
- jettonWalletAddress- Jetton 钱包合约地址,基于 JettonMaser 和 Wallet 合约定义
- amount- 整数,用于gas费用的 Toncoin 金额,以 nanotons 计。
- body- 带有- burn#595f07bc操作码的 Jetton 钱包载荷
NFT 转移
body 消息通常应按照以下方式进行:
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 转移操作码 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 - 地址 - 初始 NFT 持有者地址,用于接收超额资金
将 NFTitem 转移给新所有者 NEW_OWNER_WALLET。
- @tonconnect/react-ui
- @tonconnect/ui
- @tonconnect/sdk
import { useTonConnectUI } from '@tonconnect/ui-react';
const myTransaction = {
    validUntil: Math.floor(Date.now() / 1000) + 360,
    messages: [
        {
            address: jettonWalletContract, // 将要转移的 NFT 物品地址
            amount: toNano("0.05"),  // 用于佣金费,超额部分将被返回
            payload: body.toBoc().toString("base64") // 带有 NFT 转移 body 的 payload
        }
    ]
}
export const Settings = () => {
    const [tonConnectUI, setOptions] = useTonConnectUI();
    return (
        <div>
            <button onClick={() => tonConnectUI.sendTransaction(myTransaction)}>
                Send transaction
            </button>
        </div>
    );
};
import TonConnectUI from '@tonconnect/ui'
const transaction = {
    validUntil: Math.floor(Date.now() / 1000) + 360,
    messages: [
        {
            address: NFTitem,  // 将要转移的 NFT 物品地址
            amount: toNano("1.08"), // 用于佣金费,超额部分将被返回
            payload: transferNftBody.toBoc().toString("base64") // 带有 transferNftBody 消息的 payload
        }
    ]
}
const result = await tonConnectUI.sendTransaction(transaction)
await connector.sendTransaction({
  validUntil: Math.floor(Date.now() / 1000) + 360,
  messages: [
    {
      address: NFTitem, // 将要转移的 NFT 物品地址
      amount: toNano("1.08"), // 用于佣金费,超额部分将被返回
      payload: transferNftBody.toBoc().toString("base64") // 带有 transferNftBody 消息的 payload
    }
  ]
})
- NFTitem- 地址 - 我们希望转移到新所有者- NEW_OWNER_Wallet的NFT项目智能合约的地址。
- balance- 整数,用于gas支付的 Toncoin 数量(单位是nanotons)。
- body- 用于 NFT 合约的载荷
NFT 销售(GetGems)
以下是根据合约nft-fixprice-sale-v3r2准备消息和交易以在GetGems市场上进行销售的示例。
要将 NFT 放置在 GetGems 销售合约上,我们应该准备特殊消息体 transferNftBody,它将 NFT 转移到特殊的 NFT 销售合约。
    const transferNftBody = beginCell()
        .storeUint(0x5fcc3d14, 32) // NFT 转移操作码
        .storeUint(0, 64) // query_id
        .storeAddress(destinationAddress) // new_owner - GetGems 销售合约部署者,此操作不应更改
        .storeAddress(walletAddress) // 超额资金的响应目的地
        .storeBit(0) // 我们没有 custom_payload
        .storeCoins(toNano("1")) // forward_amount
        .storeBit(0) // 我们在此cell中存储 forward_payload
        .storeUint(0x0fe0ede, 31) // 非 32,因为之前存储的 0 位将作为销售操作码读取
        .storeRef(stateInitCell)
        .storeRef(saleBody)
        .endCell();
因为消息需要很多步骤,整个算法庞大,可以在此处找到:
显示创建 NFT 销售消息体的整个算法
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=');
    const marketplaceAddress = Address.parse('EQBYTuYbLf8INxFtD8tQeNk5ZLy-nAX9ahQbG_yl1qQ-GEMS'); // GetGems 地址
    const marketplaceFeeAddress = Address.parse('EQCjk1hh952vWaE9bRguFkAhDAL5jj3xj9p0uPWrFBq_GEMS'); // GetGems 收费地址
    const destinationAddress = Address.parse("EQAIFunALREOeQ99syMbO6sSzM_Fa1RsPD5TBoS0qVeKQ-AR"); // GetGems 销售合约部署者
    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 收费
        .storeCoins(price / BigInt(100) * BigInt(5))
        .storeAddress(royaltyAddress)
        // 5% - 版权费,可更改
        .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) // 以nanotons计的全价
        .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();
    // 仅示例,非必需
    const saleContractAddress = new Address(0, stateInitCell.hash());
    const saleBody = beginCell()
        .storeUint(1, 32) // 只是接收硬币
        .storeUint(0, 64)
        .endCell();
    const transferNftBody = beginCell()
        .storeUint(0x5fcc3d14, 32) // NFT 转移操作码
        .storeUint(0, 64) // query_id
        .storeAddress(destinationAddress) // new_owner
        .storeAddress(walletAddress) // 超额资金的响应目的地
        .storeBit(0) // 我们没有 custom_payload
        .storeCoins(toNano("1")) // forward_amount
        .storeBit(0) // 我们在此cell中存储 forward_payload
        // 非 32,因为我们存储了 0 位 | 部署者的销售操作码
        .storeUint(0x0fe0ede, 31)
        .storeRef(stateInitCell)
        .storeRef(saleBody)
        .endCell();
准备好的 transferNftBody 应发送到 NFT 物品合约,至少需要 1.08 TON,以成功处理。多余的部分将退还给发件人钱包。
- @tonconnect/react-ui
- @tonconnect/ui
- @tonconnect/sdk
import { useTonConnectUI } from '@tonconnect/ui-react';
const myTransaction = {
    validUntil: Math.floor(Date.now() / 1000) + 360,
    messages: [
        {
            address: NFTitem, // NFT 物品合约地址,应该放置于市场上
            amount: toNano("1.08"), // 需要的gas费金额,多余的部分将返回
            payload: transferNftBody.toBoc().toString("base64") // 带有 transferNftBody 消息的 payload
        }
    ]
}
export const Settings = () => {
    const [tonConnectUI, setOptions] = useTonConnectUI();
    return (
        <div>
            <button onClick={() => tonConnectUI.sendTransaction(myTransaction)}>
                Send transaction
            </button>
        </div>
    );
};
import TonConnectUI from '@tonconnect/ui'
const transaction = {
    validUntil: Math.floor(Date.now() / 1000) + 360,
    messages: [
        {
            address: NFTitem, // NFT 物品合约地址,应该放置于市场上
            amount: toNano("1.08"), // 需要的gas费金额,多余的部分将返回
            payload: transferNftBody.toBoc().toString("base64") // 带有 transferNftBody 消息的 payload
        }
    ]
}
const result = await tonConnectUI.sendTransaction(transaction)
await connector.sendTransaction({
  validUntil: Math.floor(Date.now() / 1000) + 360,
  messages: [
    {
      address: NFTitem, // NFT 物品合约地址,应该放置于市场上
      amount: toNano("1.08"), // 需要的gas费金额,多余的部分将返回
      payload: transferNftBody.toBoc().toString("base64") // 带有 transferNftBody 消息的 payload
    }
  ]
})
NFT 购买 (GetGems)
购买 nft-fixprice-sale-v3r2 销售合约的 NFT 的过程可以通过常规转账进行,无需负荷,唯一重要的是准确的 TON 数量,按如下计算:
buyAmount = Nftprice TON + 1.0 TON。
- @tonconnect/react-ui
- @tonconnect/ui
- @tonconnect/sdk
import { useTonConnectUI } from '@tonconnect/ui-react';
const myTransaction = {
    validUntil: Math.floor(Date.now() / 1000) + 360,
    messages: [
        {
            address: nftSaleContract,  // 当前希望购买的 NFT 销售合约地址
            amount: toNano(buyAmount), // NFT 价格 +  1 TON, 多余的会被返回
        }
    ]
}
export const Settings = () => {
    const [tonConnectUI, setOptions] = useTonConnectUI();
    return (
        <div>
            <button onClick={() => tonConnectUI.sendTransaction(myTransaction)}>
                Send transaction
            </button>
        </div>
    );
};
import TonConnectUI from '@tonconnect/ui'
const transaction = {
    validUntil: Math.floor(Date.now() / 1000) + 360,
    messages: [
        {
            address: nftSaleContract,  // 当前希望购买的 NFT 销售合约地址
            amount: toNano(buyAmount), // NFT 价格 +  1 TON, 多余的会被返回
        }
    ]
}
const result = await tonConnectUI.sendTransaction(transaction)
await connector.sendTransaction({
validUntil: Math.floor(Date.now() / 1000) + 360,
messages: [
    {
        address: nftSaleContract,  // 当前希望购买的 NFT 销售合约地址
        amount: toNano(buyAmount), // NFT 价格 +  1 TON, 多余的会被返回
    }
]
})
TON Connect Python SDK
Python 示例使用 PyTonConnect 和 pytoniq。
    from pytoniq_core import Address
    from pytonconnect import TonConnect
阅读示例 源码。
常规 TON 转账
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', # 目的地址
            'amount' : 1000000000,  # 1 TON,数额应以nanocoins计
        )
    ]
}
附带评论的转账
首先,通过以下函数实现带有评论的消息:
    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)  # 评论消息的操作码
                .store_string(comment)  # 储存评论
                .end_cell()  # 结束 cell
                .to_boc()  # 转换成 boc
            )
            .decode()  # 编码成 url 安全的 base64
        }
        return data
带有评论的转账的最终交易体:
transaction = {
    'valid_until': int(time.time() + 3600),
    'messages': [
        get_comment_message(
            destination_address='0:0000000000000000000000000000000000000000000000000000000000000000',
            amount=int(0.01 * 10**9),  # 数额应以纳币指定
            comment='hello world!'
        )
    ]
}
了解更多关于 TON 智能合约地址。
Jetton 转账
构建 jetton 转账交易的函数示例:
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)  # jetton 转账消息的操作码
        .store_uint(0, 64)  # query_id
        .store_coins(jettons_amount)
        .store_address(recipient_address)  # 目的地址
        .store_address(response_address or recipient_address)  # 超额资金发送到的地址
        .store_uint(0, 1)  # 自定义负载
        .store_coins(1)  # 转发金额
        .store_uint(0, 1)  # 转发负载
        .end_cell()  # 结束 cell
        .to_boc()  # 转换成 boc
        )
        .decode()  # 编码成 url 安全的 base64
    }
    return data
最终的交易体:
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),  # 将jetton十进制数替换为9。例如对于 jUSDT 应该是 (amount * 10**6),
        response_address=wallet_address
        ),
    ]
}
Jetton 销毁
构建 jetton 销毁交易的函数示例:
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)  # jetton 转账消息的操作码
            .store_uint(0, 64)  # query_id
            .store_coins(jettons_amount)
            .store_address(response_address)  # # 超额资金发送到的地址
            .end_cell()  # 结束 cell
            .to_boc()  # 转换成 boc
        )
        .decode()  # 编码成 url 安全的 base64
    }
    return data
最终的交易体:
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),  # 将jetton十进制数替换为9。例如对于 jUSDT 应该是 (amount * 10**6),
            response_address=wallet_address
        ),
    ]
}
NFT 转账
NFT 转账交易函数的示例:
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)  # nft 转账消息的操作码
            .store_uint(0, 64)  # query_id
            .store_address(recipient_address)  # 新主人
            .store_address(response_address or recipient_address)  # 超额资金发送到的地址
            .store_uint(0, 1)  # custom payload
            .store_coins(1)  # forward amount
            .store_uint(0, 1)  # forward payload
            .end_cell()  # 结束 cell
            .to_boc()  # 转换成 boc
        )
        .decode()  # 编码成 url 安全的 base64
    }
    return data
最终的交易体:
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
        ),
    ]
}
NFT 销售 (GetGems)
以下是在 GetGems 市场上进行销售时准备消息和交易的示例,根据合约 nft-fixprice-sale-v3r2。
为了将 NFT 放置在 GetGems 销售合约上,我们应该准备特殊的消息体 transferNftBody,该消息体将 NFT 转移给特殊的 NFT 销售合约。
创建 NFT NFT Sale Body的示例
import time
from base64 import urlsafe_b64encode
from pytoniq_core.boc import Cell, begin_cell, Address
from pytoniq_core.tlb import StateInit
def get_sale_body(wallet_address: str, royalty_address: str, nft_address: str, price: int, amount: int):
    # 合约代码
    nft_sale_code_cell = Cell.one_from_boc('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=')
    # 费用cell
    marketplace_address = Address('EQBYTuYbLf8INxFtD8tQeNk5ZLy-nAX9ahQbG_yl1qQ-GEMS')
    marketplace_fee_address = Address('EQCjk1hh952vWaE9bRguFkAhDAL5jj3xj9p0uPWrFBq_GEMS')
    destination_address = Address('EQAIFunALREOeQ99syMbO6sSzM_Fa1RsPD5TBoS0qVeKQ-AR')
    wallet_address = Address(wallet_address)
    royalty_address = Address(royalty_address)
    nft_address = Address(nft_address)
    marketplace_fee = int(price * 5 / 100)  # 5%
    royalty_fee = int(price * 5 / 100)  # 5%
    fees_data_cell = (begin_cell()
                      .store_address(marketplace_fee_address)
                      .store_coins(marketplace_fee)
                      .store_address(royalty_address)
                      .store_coins(royalty_fee)
                      .end_cell())
    sale_data_cell = (begin_cell()
                      .store_bit_int(0)
                      .store_uint(int(time.time()), 32)
                      .store_address(marketplace_address)
                      .store_address(nft_address)
                      .store_address(wallet_address)
                      .store_coins(price)
                      .store_ref(fees_data_cell)
                      .store_bit_int(0)
                      .end_cell())
    state_init_cell = StateInit(code=nft_sale_code_cell, data=sale_data_cell).serialize()
    sale_body = (begin_cell()
                 .store_uint(1, 32)
                 .store_uint(0, 64)
                 .end_cell())
    transfer_nft_body = (begin_cell()
                         .store_uint(0x5fcc3d14, 32)
                         .store_uint(0, 64)
                         .store_address(destination_address)
                         .store_address(wallet_address)
                         .store_bit_int(0)
                         .store_coins(int(1 * 10**9))
                         .store_bit_int(0)
                         .store_uint(0x0fe0ede, 31)
                         .store_ref(state_init_cell)
                         .store_ref(sale_body)
                         .end_cell())
    data = {
        'address': nft_address.to_str(),
        'amount': str(amount),
        'payload': urlsafe_b64encode(transfer_nft_body.to_boc()).decode()
    }
    return data
最终交易体:
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
        ),
    ]
}
NFT 购买 (GetGems)
使用 nft-fixprice-sale-v3r2 销售合约购买 NFT 的过程可以通过不含有效负载的常规转账进行,唯一重要的是准确的 TON 数额,计算方式如下:
buyAmount = Nftprice TON + 1.0 TON。
transaction = {
    'valid_until': int(time.time() + 3600),
    'messages': [
        {
            'address': nft_address,
            'amount': buyAmount,
    ]
}