处理 TON Jetton
Jetton实践最佳做法
Jettons 是 TON 区块链上的代币--可以将其视为类似于以太坊上的 ERC-20 代币。
TON 交易只需确认一次就不可逆转。为获得最佳用户体验/用户界面,请避免额外等待。
提款
Highload Wallet v3 - 这是 TON 区块链的最新解决方案,是 jetton 提款的黄金标准。它允许您利用分批提款的优势。
分批提款 - 指分批发送多笔提款,从而实现快速、廉价的提款。
存款
建议设置多个 MEMO 存款钱包,以提高性能。
Memo Deposits - 这可以让你保留一个存款钱包,用户添加 memo 以便被你的系统识别。这意味着您不需要扫描整个区块链,但对用户来说稍显不便。
Memo-less deposits - 这种解决方案也存在,但整合起来比较困难。不过,如果您希望采用这种方法,我们可以提供协助。请在决定采用这种方法之前通知我们。
其他信息
在进行 jetton 提取时,生态系统中的每项服务都应将 forward_ton_amount 设置为 0.000000001 TON (1 nanotons ),以便在成功转账 时发送 Jetton 通知,否则转账将不符合标准,其他 CEX 和服务将无法处理。
-
请参见 JS 库示 例 - tonweb - 这是 TON 基金会的官方 JS 库。
-
如果您想使用 Java,可以参考 ton4j。
-
对于 Go,应考虑 tonutils-go。目前,我们推荐使用 JS lib.
内容列表
以下文档详细介绍了 Jettons 架构的总体情况,以及 TON 的核心概念,这些概念可能与 EVM 类区块链和其他区块链不同。要想很好地理解 TON,阅读这些文档至关重要,会对你有很大帮助。
本文件依次介绍了以下内容:
- 概述
- 架构
- Jetton 主合约 (Token Minter)
- Jetton 钱包合约 (User Wallet)
- 信息布局
- Jetton 处理(链下)
- Jetton 处理(链上)
- 钱包处理
- 最佳做法
概述
为获得最佳用户体验,建议在 TON 区块链上完成交易后避免等待其他区块。更多信息请参阅 Catchain.pdf。
快速跳转到 jetton 处理的核心描述:
集中处理
链上处理
TON 区块链及其底层生态系统将可替代代币(FT)归类为 jetton 。由于分片应用于 TON 区块链,与类似的区块链模型相比,我们对可替代代币的实现是独一无二的。
在本分析中,我们将深入探讨详细说明 jetton 行为 和 元数据 的正式标准。 关于 jetton 架构不那么正式的分片概述,请参阅我们的 anatomy of jettons 博客文章。
我们还提供了讨论我们的第三方开源 TON 支付处理器(bicycle)的具体细节,该处理器允许用户使用单独的存款地址存取 Toncoin 和 Jettons,而无需使用文本 memo 。
Jetton 架构
TON 上的标准化代币是通过一套智能合约实现的,其中包括
- Jetton master 智能合约
- Jetton wallet 智能合约

Jetton 主智能合约
jetton 主智能合约存储有关 jetton 的一般信息(包括总供应量、元数据链接或元数据本身)。
具有 symbol 等于 TON 的 Jetton,或者包含系统通知消息(如 ERROR、SYSTEM 等)的 Jetton,务必确保这些 Jetton 在界面中以明确的方式显示,以避免它们与 TON 转账、系统通知等混淆。有时,甚至 symbol、name 和 image 都会被设计得与原版极为相似,试图误导用户。
为了消除 TON 用户被骗的可能性,请查询特定 Jetton 类型的原始 Jetton 地址(Jetton 主合约地址),或者关注项目的官方社交媒体渠道或网站以获取正确信息。您还可以通过 Tonkeeper ton-assets 列表 检查资产,进一步降低被骗的风险。
检索 Jetton 数据
要检索更具体的 Jetton 数据,请使用合约的 get 方法 get_jetton_data()。
该方法返回以下数据:
| 名称 | 类型 | 说明 |
|---|---|---|
total_supply | int | 以不可分割单位计量的已发行净 TON 总数。 |
mintable | int | 详细说明是否可以铸造新 jetton。该值为-1(可以铸造)或 0(不能铸造)。 |
admin_address | slice | |
jetton_content | cell | 根据 TEP-64,您可以查看 jetton 元数据解析页面 获取更多信息。 |
jetton_wallet_code | cell |
还可以使用 Toncenter API 中的 /jetton/masters 方法来检索已解码的 Jetton 数据和元数据。我们还为 (js) tonweb 和 (js) ton-core/ton, (go) tongo 还有 (go) tonutils-go, (python) pytonlib 以及许多其他 SDKs 开发了方法。
使用 Tonweb 运行获取方法和获取链外元数据的 URL 的示例:
import TonWeb from "tonweb";
const tonweb = new TonWeb();
const jettonMinter = new TonWeb.token.jetton.JettonMinter(tonweb.provider, {address: "<JETTON_MASTER_ADDRESS>"});
const data = await jettonMinter.getJettonData();
console.log('Total supply:', data.totalSupply.toString());
console.log('URI to off-chain metadata:', data.jettonContentUri);
Jetton minter
如前所述,jettons 既可以是 可铸 (minable) 也可以是 不可铸 (non-mintable) 。
如果它们是不可铸币的,逻辑就变得很简单--没有办法铸入更多代币。要首次铸造代币,请参阅铸造第一个代币 页面。
如果是可铸币,铸币者合约 中会有一个特殊函数来铸造额外的铸币。可以通过从管理员地址发送带有指定操作码的 "内部信息 "来调用该函数。
如果 jetton 管理员希望限制 jetton 的创建,有三种方法:
- 如果您不能或不想更新合约代码,则需要将当前管理员的所有权转移到零地址。这将使合约失去一个有效的管理员,从而阻止任何人铸币。不过,这也会阻止对 jetton 元数据的任何更改。
- 如果您可以访问源代码并对其进行修改,您可以在合约中创建一个方法,设置一个标志,在调用该方法后中止任何造币过程,并在造币函数中添加一条语句来检查该标志。
- 如果可以更新合约的代码,就可以通过更新已部署合约的代码来添加限制。
Jetton 钱包智能合约
Jetton wallet 合约用于发送、接收 和 销毁 jetton 。每个 Jetton wallet 合约都存储了特定用户的钱包余额信息。
在特定情况下, jetton TON 钱包用于每种 jetton TON 类型的单个 jetton TON 持有者。
Jetton wallets 不应该与钱包混淆,钱包是为了区块链交互和存储
Toncoin 资产(例如,v3R2钱包,高负载钱包和其他),它只负责支持和管理特定的 jetton 类型。
部署 Jetton 钱包
在钱包之间 传输 jettons 时,交易(消息)需要一定数量的 TON
作为网络 gas fees 和根据 jetton 钱包合约代码执行操作的付款。
这意味着接收方在 接收 jetton 之前无需部署 jetton 钱包。
只要发送方的 Jetton 钱包中持有足够的 TON
来支付所需的 gas 费,接收方的 Jetton 钱包就会自动部署。
检索指定用户的 Jetton 钱包地址
要使用 "所有者地址"(TON 钱包地址)检索 "jetton 钱包 "的 "地址",
,Jetton master contract 提供了获取方法 get_wallet_address(slice owner_address)。
- API
- js
通过 Toncenter API 中的
/runGetMethod方法运行get_wallet_address(slice owner_address)。在实际情况下(而非测试情况下),必须始终检查钱包是否确实归属于所需的 Jetton Master。请查看代码示例了解更多信息。
import TonWeb from 'tonweb';
const tonweb = new TonWeb();
const jettonMinter = new TonWeb.token.jetton.JettonMinter(tonweb.provider, { address: '<JETTON_MASTER_ADDRESS>' });
const jettonWalletAddress = await jettonMinter.getJettonWalletAddress(new TonWeb.utils.Address('<OWNER_WALLET_ADDRESS>'));
// It is important to always check that wallet indeed is attributed to desired Jetton Master:
const jettonWallet = new TonWeb.token.jetton.JettonWallet(tonweb.provider, {
address: jettonWalletAddress
});
const jettonData = await jettonWallet.getData();
if (jettonData.jettonMinterAddress.toString(false) !== jettonMinter.address.toString(false)) {
throw new Error('jetton minter address from jetton wallet doesnt match config');
}
console.log('Jetton wallet address:', jettonWalletAddress.toString(true, true, true));
更多示例请阅读 TON Cookbook。
检索特定 Jetton 钱包的数据
要检索钱包的账户余额、所有者身份信息以及与特定 jetton 钱包合约相关的其他信息,请使用 jetton 钱包合约中的 get_wallet_data() 获取方法。
该方法返回以下数据:
| 名称 | 类型 |
|---|---|
balance | int |
owner | slice |
jetton | slice |
jetton_wallet_code | cell |
- API
- js
使用 Toncenter API 中的
/jetton/wallets获取方法,检索先前解码的 jetton 钱包数据。
import TonWeb from "tonweb";
const tonweb = new TonWeb();
const walletAddress = "EQBYc3DSi36qur7-DLDYd-AmRRb4-zk6VkzX0etv5Pa-Bq4Y";
const jettonWallet = new TonWeb.token.jetton.JettonWallet(tonweb.provider,{address: walletAddress});
const data = await jettonWallet.getData();
console.log('Jetton balance:', data.balance.toString());
console.log('Jetton owner address:', data.ownerAddress.toString(true, true, true));
// It is important to always check that Jetton Master indeed recognize wallet
const jettonMinter = new TonWeb.token.jetton.JettonMinter(tonweb.provider, {address: data.jettonMinterAddress.toString(false)});
const expectedJettonWalletAddress = await jettonMinter.getJettonWalletAddress(data.ownerAddress.toString(false));
if (expectedJettonWalletAddress.toString(false) !== new TonWeb.utils.Address(walletAddress).toString(false)) {
throw new Error('jetton minter does not recognize the wallet');
}
console.log('Jetton master address:', data.jettonMinterAddress.toString(true, true, true));
信息布局
点击此处 阅读更多信息。
Jetton 钱包和 TON 钱包之间通过以下通信顺序进行通信:

Message 0
发件人 -> 发件人' jetton 钱包 意味着 转移 消息体包含以下数据:
| 名称 | 类型 | 说明 |
|---|---|---|
query_id | uint64 | 允许应用程序链接三种消息类型 Transfer, Transfer notification 和 Excesses 。 为了正确执行此进程,建议总是使用唯一的查询id。 |
amount | coins | 将与信息一起发送的 " TON coin "总量。 |
destination | address | 新所有者的地址 |
response_destination | address | 钱包地址,用于返还带有超额信息的剩余 TON 币。 |
custom_payload | maybe cell | 大小始终 >= 1 bit。自定义数据(用于发送方或接收方 jetton 钱包的内部逻辑)。 |
forward_ton_amount | coins | 如果您想要发送 transfer notification message 与 forward payload ,则必须大于0。 它是 一部分amount值 和 必须小于 amount |
forward_payload | maybe cell | 大小总是 >= 1 位。如果前 32 位 = 0x0,这只是一条简单的信息。 |
Message 2'
收款人的 jetton 钱包 -> 收款人。 转账通知信息 (Transfer notification message)。仅在forward_ton_amount不为零时发送。包含以下数据:
| 名称 | 类型 |
|---|---|
query_id | uint64 |
amount | coins |
sender | address |
forward_payload | cell |
这里的 发送者 地址是Alice的Jeton wallet的地址。
Message 2''
收款人的 jetton 钱包 -> 发件人。多余信息正文 (Excess message body)。仅在支付费用后剩余 TON 币时发送。包含以下数据:
| 名称 | 类型 |
|---|---|
query_id | uint64 |
关于 jetton 钱包合约字段的详细说明,请参阅 TEP-74 Jetton 标准接口说明。
如何发送附带评论和通知的 Jetton 转账
这次转账需要一些 TON 币作为 费用 和 转账通知信息。
要发送评论,您需要设置 "转发有效载荷"。将 前 32 位设置为 0x0,并附加 您的文本,"前向有效载荷 "将在 jetton notify 0x7362d09c 内部信息中发送。只有当 forward_ton_amount > 0 时才会生成。
建议带注释的 jetton 传输的 forward_ton_amount 为 1 nanotons 。
最后,要获取 Excess 0xd53276db 信息,必须设置 response destination。
有时,您在发送 jetton 时可能会遇到 709 错误。该错误表示信息所附的 Toncoin 数量不足以发送信息。请确保 Toncoin > to_nano(TRANSFER_CONSUMPTION) + forward_ton_amount,这通常>0.04,除非转发的有效载荷非常大。佣金取决于多种因素,包括 Jetton 代码详情以及是否需要为收款人部署新的 Jetton 钱包。
建议在消息中添加一定数量的 Toncoin 作为余量,并将您的地址设置为 response_destination,以便接收 Excess 0xd53276db 消息。例如,您可以向消息中添加 0.05 TON,同时将 forward_ton_amount 设置为 1 nanoton(此 TON 数量将附加到 jetton notify 0x7362d09c 消息中)。
你也可能会遇到 cskip_no_gas 错误,它表示成功转移了 jetton,但没有执行其他计算。当 forward_ton_amount 的值等于 1 nanotons 时,这种情况很常见。
查看 最佳实践 中的 "发送带注释的 jettons" 示例。
Jetton 链下处理
TON 交易只需确认一次就不可逆转。为获得最佳用户体验,建议在 TON 区块链上完成交易后避免等待其他区块。更多信息请参见 Catchain.pdf。
接受 jetton 有两种方式:
- 在集中式热钱包内。
- 使用为每个用户独立地址的钱包。
出于安全考虑,最好为个独立的 jetton 拥有个独立的热钱包(每种资产都有许多钱包)。
在处理资金时,还建议提供一个冷钱包,用于存储不参与自动存取款流程的多余资金。
为资产处理和初步核实添加新的 jetton
接收转账通知信息时识别未知 Jetton
如果您的钱包中收到有关未知 Jetton 的转账通知消息,则表示您的钱包 已创建用于保存特定 Jetton。
包含 "转账通知" 正文的内部信息的发件人地址是新 Jetton 钱包的地址。 它不应与 "转账通知"正文 中的 "发件人 "字段混淆。
- 通过 获取钱包数据,读取新 Jetton 钱包的 Jetton 主地址。
- 使用 Jetton 主合约为您的钱包地址(作为所有者)找回 Jetton 钱包地址:如何为指定用户找回 Jetton 钱包地址
- 比较主合约返回的地址和钱包令牌的实际地址。 如果它们匹配,那就很理想。如果不匹配,则很可能收到的是伪造的诈骗令牌。
- 检索 Jetton 元数据:如何接收 Jetton 元数据。
- 检查
symbol和name字段是否有欺诈迹象。必要时警告用户。添加新的 jetton 进行处理和初始检查。