TEP-74 Fungible Token/Jettons Standard
🍉

TEP-74 Fungible Token/Jettons Standard

TEP: 74
概要
Jettons(TON 可替代代币)标准接口。
标准接口将极大简化不同代币化资产的交互和显示。
Jetton 标准描述了以下内容:
  • Jetton 转账的方式。
  • 检索给定 Jetton 资产的常见信息(名称、流通供应量等)的方式。
规范
在本标准中,用“Jetton”表示同类型代币的整体,用“jetton”表示某类型代币的数量。
Jettons 组织结构如下:每个 Jetton 都有一个主智能合约用于铸造新 jettons,记录流通供应量并提供常见信息。
同时,每个用户持有的 jettons 数量信息是以去中心化方式存储在各个用户的智能合约中,这些合约称为“jetton-wallets”(jetton 钱包)。
例如:如果你发行一个流通供应量为 200 jetton 的 Jetton,并且这些 jetton 被 3 个人持有,那么将部署 4 个合约:1 个 Jetton-master(Jetton 主合约)和 3 个 jetton-wallets(Jetton 钱包合约)。

Jetton 钱包智能合约

必须实现:
内部消息处理器
  1. transfer(转账)
      • 请求
        • TL-B(Telegram Language-Bitstream)架构的入站消息
          • 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;
      • query_id:任意请求编号。
      • amount:以基本单位表示的转账 jetton 数量。
      • destination:jetton 新持有者的地址。
      • response_destination:发送确认成功转账的响应地址,并返回剩余的 Toncoins。
      • custom_payload:可选的自定义数据(由发送方或接收方 jetton 钱包用于内部逻辑)。
      • forward_ton_amount:要发送到目标地址的 nanotons 数量。
      • forward_payload:要发送到目标地址的可选自定义数据。
      应拒绝的情况:
      • 消息不是来自所有者。
      • 发送方钱包中没有足够的 jettons。
      • 没有足够的 TON(根据 jetton 自身存储费指南和操作成本)来处理操作,部署接收方的钱包并发送 forward_ton_amount
      操作要求:
      • 处理请求后,接收方的钱包必须至少发送 in_msg_value - forward_ton_amount - 2 * max_tx_gas_price - 2 * fwd_feeresponse_destination 地址。如果发送方的钱包无法保证这一点,必须立即停止执行请求并抛出错误。max_tx_gas_price 是 FT habitat 工作链的最大交易 gas 限制的 Toncoins 价格。在 basechain 中,它可以从 ConfigParam 21 中的 gas_limit 字段获取。fwd_fee 是转账请求的转发费用,可以通过解析转账请求消息获得。
      否则应该:
      • 从发送方钱包中减少 amount 数量的 jetton 并发送消息以增加接收方钱包中的 jetton 数量(并可选地部署它)。
      • 如果 forward_amount > 0,确保接收方钱包发送带有 forward_amount nanotons 的消息到目标地址,并具有以下布局:TL-B 架构:
        • transfer_notification#7362d09c query_id:uint64 amount:(VarUInteger 16) sender:MsgAddress forward_payload:(Either Cell ^Cell) = InternalMsgBody;
        • query_id 应与请求的 query_id 相同。
        • amount 表示转账的 jetton 数量。
        • sender 是转账 jetton 的前所有者地址。
        • forward_payload 应与请求的 forward_payload 相同。
      如果 forward_amount 为零,则不应发送通知消息。
      接收方的钱包应将所有多余的入站消息中的 coins 发送到 response_destination,其布局如下:TL-B 架构:
      excesses#d53276db query_id:uint64 = InternalMsgBody;
      • query_id 应与请求的 query_id 相同。
      forward_payload 格式
      • 如果你想在 forward_payload 中发送简单的评论,则 forward_payload 必须以 0x00000000(32 位无符号整数,等于零)开头,并且评论内容包含在 forward_payload 的其余部分中。
      • 如果评论不是以字节 0xff 开头,则评论为文本,可以“按原样”显示给钱包的最终用户(在过滤无效和控制字符并确保它是有效的 UTF-8 字符串后)。例如,用户可以在从他们的钱包转账到其他用户的钱包的简单转账中,在此文本字段中指出用途(“用于咖啡”)。
      • 另一方面,如果评论以字节 0xff 开头,则剩余部分为“二进制评论”,不应作为文本显示给最终用户(仅在必要时显示为十六进制转储)。“二进制评论”的预期用途是,例如,包含商店支付的购买标识符,由商店软件自动生成和处理。
      • 如果 forward_payload 包含与目标智能合约交互的二进制消息(例如与 DEX 的交互),则不需要前缀。
      这些规则与从常规钱包发送 Toncoins 时的有效载荷格式相同(智能合约指南:内部消息,3)。
  1. burn(销毁)
      • 请求
        • TL-B 架构的入站消息
          • burn#595f07bc query_id:uint64 amount:(VarUInteger 16) response_destination:MsgAddress custom_payload:(Maybe ^Cell) = InternalMsgBody;
      • query_id:任意请求编号。
      • amount:销毁的 jetton 数量。
      • response_destination:发送确认成功销毁的响应地址,并返回剩余的 coins。
      • custom_payload:可选的自定义数据。
      应拒绝的情况:
      • 消息不是来自所有者。
      • 发送方钱包中没有足够的 jettons。
      • 没有足够的 TONs 在处理请求后至少发送 in_msg_value - max_tx_gas_priceresponse_destination 地址。如果发送方的钱包无法保证这一点,必须立即停止执行请求并抛出错误。
      否则应该:
      • 从销毁者钱包中减少 amount 数量的 jetton 并向 Jetton 主合约发送通知,告知销毁信息。
      • Jetton 主合约应将所有多余的入站消息中的 coins 发送到 response_destination,其布局如下:TL-B 架构:
        • excesses#d53276db query_id:uint64 = InternalMsgBody;
      • query_id 应与请求的 query_id 相同。
Get-methods(查询方法)
  • get_wallet_data() 返回 (int balance, slice owner, slice jetton, cell jetton_wallet_code)
    • balance:(uint256)钱包中的 jetton 数量。
    • owner:(MsgAddress)钱包所有者的地址。
    • jetton:(MsgAddress)Jetton 主合约的地址。
    • jetton_wallet_code:(cell)钱包的代码。

Jetton 主合约

Get-methods(查询方法)
  • get_jetton_data() 返回 (int total_supply, int mintable, slice admin_address, cell jetton_content, cell jetton_wallet_code)
    • total_supply -(整数)- 发行的 jetton 总数量。
    • mintable -(-1/0)- 标志,指示 jetton 的数量是否可以增加。
    • admin_address -(MsgAddressInt)- 控制 Jetton 的智能合约地址。
    • jetton_content - cell - 根据 Token Data Standard #64 的数据。
    • jetton_wallet_code - cell - 该 Jetton 钱包的代码。
  • get_wallet_address(slice owner_address) 返回 slice jetton_wallet_address:返回此所有者地址(MsgAddressInt)的 jetton 钱包地址(MsgAddressInt)。
TL-B 架构
  • nothing$0 {X:Type} = Maybe X;
  • just$1 {X:Type} value:X = Maybe X;
  • left$0 {X:Type} {Y:Type} value:X = Either X Y;
  • right$1 {X:Type} {Y:Type} value:Y = Either X Y;
  • var_uint$_ {n:#} len:(#< n) value:(uint (len * 8)) = VarUInteger n;
  • addr_none$00 = MsgAddressExt;
  • addr_extern$01 len:(## 9) external_address:(bits len) = MsgAddressExt;
  • anycast_info$_ depth:(#<= 30) { depth >= 1 } rewrite_pfx:(bits depth) = Anycast;
  • addr_std$10 anycast:(Maybe Anycast) workchain_id:int8 address:bits256 = MsgAddressInt;
  • addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9) workchain_id:int32 address:(bits addr_len) = MsgAddressInt;
  • _ _:MsgAddressInt = MsgAddress;
  • _ _:MsgAddressExt = MsgAddress;
  • transfer 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;
  • transfer_notification query_id:uint64 amount:(VarUInteger 16) sender:MsgAddress forward_payload:(Either Cell ^Cell) = InternalMsgBody;
  • excesses query_id:uint64 = InternalMsgBody;
  • burn query_id:uint64 amount:(VarUInteger 16) response_destination:MsgAddress custom_payload:(Maybe ^Cell) = InternalMsgBody;
// 未由标准指定,但建议的内部消息格式
  • internal_transfer query_id:uint64 amount:(VarUInteger 16) from:MsgAddress response_address:MsgAddress forward_ton_amount:(VarUInteger 16) forward_payload:(Either Cell ^Cell) = InternalMsgBody;
  • burn_notification query_id:uint64 amount:(VarUInteger 16) sender:MsgAddress response_destination:MsgAddress = InternalMsgBody;
  • crc32('transfer 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') = 0x8f8a7ea5 & 0x7fffffff = 0xf8a7ea5
  • crc32('transfer_notification query_id:uint64 amount:VarUInteger 16 sender:MsgAddress forward_payload:Either Cell ^Cell = InternalMsgBody') = 0xf362d09c & 0x7fffffff = 0x7362d09c
  • crc32('excesses query_id:uint64 = InternalMsgBody') = 0x553276db | 0x80000000 = 0xd53276db
  • crc32('burn query_id:uint64 amount:VarUInteger 16 response_destination:MsgAddress custom_payload:Maybe ^Cell = InternalMsgBody') = 0x595f07bc & 0x7fffffff = 0x595f07bc
  • crc32('internal_transfer query_id:uint64 amount:VarUInteger 16 from:MsgAddress response_address:MsgAddress forward_ton_amount:VarUInteger 16 forward_payload:Either Cell ^Cell = InternalMsgBody') = 0x978d4519 & 0x7fffffff = 0x178d4519
  • crc32('burn_notification query_id:uint64 amount:VarUInteger 16 sender:MsgAddress response_destination:MsgAddress = InternalMsgBody') = 0x7bdd97de & 0x7fffffff = 0x7bdd97de
缺点
无法在链上获取实际钱包余额,因为当余额消息到达时,钱包余额可能不再是最新的。