在 Solidity 中,合约开发人员并不太关心GAS问题。如果用户提供的GAS太少,一切都会恢复原状,就像什么都没发生过一样(但GAS不会退还)。如果用户提供了足够的GAS,实际成本将自动计算并从余额中扣除。 在 TON,情况有所不同: 如果 "合约组 "交换信息,则必须在每个信息中进行控制和计算。TON 无法自动计算GAS。完整执行交易及其所有后果可能需要很长时间,到最后,用户钱包中可能没有足够的TON币。这里使用的是携带价值原则。 计算GAS并检查 msg_value我们可以使用消息流程图来估算每种情况下每个处理程序的成本,并插入 msg_value 的充分性检查。 假设你的合约发送了三条信息,那么每条信息只能发送 0.33 TON。这意味着他们的 "需求 "应该更少。仔细计算整个合约的GAS需求量非常重要。 如果在开发过程中,您的代码开始发送更多信息,情况就会变得更加复杂。需要重新检查和更新GAS要求。 小心地退回多余GAS如果不将多余的GAS退还给发送者,这些资金就会在您的合约中长期累积。 这并不可怕,但并不理想。您可以添加一个功能,用于归还多余GAS。 像 TON Jetton 这样的知名合约,会将 op::excesses 消息返回给发送者。 0 ?, X o& r* a' A' }
如果不将多余的GAS退还给发送者,这些资金就会在您的合约中长期累积。从原则上讲,这并不可怕,但这只是一种次优做法。您可以添加一个功能来清除多余的GAS,但像 TON Jetton 这样的常用合约仍会以 op::excesses 消息返回发送方。 send_raw_message(msg, SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE) 传递其余GAS。 如果消息流是线性的:每个处理程序只发送一条消息,则此功能非常有用。
( ~( q/ `5 K2 F
TON 有一个有用的机制:
9 F. c4 U$ U' y( @. h, _send_mode_carry_all_remaining_message_value = 64。在 send_raw_message() 中使用这种模式时,剩余的GAS将与消息一起(或返回)转发给新的收件人。如果消息流是线性的:每个消息处理程序只发送一条消息,那么这种模式就很方便。但在某些情况下,不建议使用这种机制: 不建议携带所有剩余GAS时storage_fee 从合约余额中扣除,而不是从输入的天然气中扣除。因此,如果合约中没有其他非线性处理程序,那么随着时间的推移、 storage_fee 会耗尽所有余额,因为所有进来的东西都要出去。 发出事件消耗的是合约余额,而不是GAS。
. b4 G3 z. \ _7 f# H' N) s/ T, F
如果您的合约发出事件,即向外部地址发送信息。该操作的费用将从合约余额中扣除,而不是从 msg_value 中扣除。 # Y7 |! Q# x; X* ] s
- var msg = begin_cell().store_uint(0x18, 6).store_slice(destination)
" [' z3 g$ {# [8 v* x- Y$ k - .store_coins(10000000) ;; This will be deducted from contract balance, y, Y# C7 k0 U, G
- .store_uint(1, 1 + 4 + 4 + 64 + 32 + 1 + 1).store_ref(msg_body);& h9 s; c+ W5 G4 n$ \5 ~
- send_raw_message(msg.end_cell(), 0);3 @6 x4 t0 M2 Y
; d3 A7 x2 u& q) Q- emit_log_cell_ref(query_id, ... ;; This also spends contract balance
复制代码如果您的合约在发送信息时附加价值或使用 SEND_MODE_PAY_FEES_SEPARETELY = 1。这些操作会从合约余额中扣除,这意味着未使用的返回是 "亏本工作"。 计算GAS成本的常用方法下面是 TON Wallet 的代码片段。这是保持合约余额稳定的常用方法。 - int ton_balance_before_msg = my_ton_balance - msg_value;& S W1 i% I) N! m
- int storage_fee = const::min_tons_for_storage - min(ton_balance_before_msg, const::min_tons_for_storage);. i6 ?/ A0 @& \+ d* e
- msg_value -= storage_fee + const::gas_consumption;% G( B8 v! V9 d. Z8 S0 u1 A
$ _/ J E* t; W8 {9 K- if(forward_ton_amount) {
! `: G/ f ^( Y8 m - msg_value -= (forward_ton_amount + fwd_fee);
" L+ b+ r* o$ Z - ...
9 J6 y5 Y- r# m - }* b8 _, h% z- K% F; g$ Y$ I9 |. X
5 U/ z8 a2 p# I1 ?! f" n- if (msg_value > 0) { ;; there is still something to return, Q. b0 }" k, G4 U1 C" J9 F
- var msg = begin_cell()
# a8 K7 z% ~+ A: {0 Q- e0 n - .store_uint(0x10, 6)& v7 u# e- i' W; K
- .store_slice(response_address)% `% b* x5 h/ S3 n2 y& W
- .store_coins(msg_value)
! A* v7 K( D7 \3 w' ]1 x& ~ - ...
复制代码请记住,如果合约余额用完,交易将被部分执行,这是不允许的。 摘要TON 需要开发人员有意识地管理GAS:计算支出并检查是否提供了足够的GAS。 如果使用 "无限制数据结构",GAS成本会随着时间推移而增加。 TON 建议将超出部分退还给发送方--这也是开发者的责任。 如果GAS耗尽,交易将被部分执行。这可能是一个关键问题。
- u4 a0 [3 V* F9 _; @4 m 7 M7 G& g% c8 ?7 ^& E0 S
0 o% M; D0 U, J |