Skip to content

refactor(contract-dev): port gas article code samples to Tolk#2101

Open
delovoyhomie wants to merge 9 commits into
mainfrom
pr-1003-gas-tolk
Open

refactor(contract-dev): port gas article code samples to Tolk#2101
delovoyhomie wants to merge 9 commits into
mainfrom
pr-1003-gas-tolk

Conversation

@delovoyhomie
Copy link
Copy Markdown
Contributor

@delovoyhomie delovoyhomie commented Apr 20, 2026

Closes #1003

Summary by CodeRabbit

  • Documentation
    • Refreshed gas-estimation walkthrough and code examples to reflect current APIs and patterns.
    • Added clear sections on value flow, receiver requirements, fee limits, forward fees, and storage fee handling.
    • Expanded complex fee calculation guidance and updated fee validation examples to improve correctness and safety.

Review Change Stack

@mintlify
Copy link
Copy Markdown

mintlify Bot commented Apr 20, 2026

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
mintlify-ton-docs 🟢 Ready View Preview Apr 20, 2026, 8:19 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 2026

Warning

Rate limit exceeded

@delovoyhomie has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 47 minutes and 13 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 443027bc-0c5f-4aa1-b20f-5c006521a9d2

📥 Commits

Reviewing files that changed from the base of the PR and between a907b2d and c63924c.

📒 Files selected for processing (1)
  • contract-dev/techniques/gas.mdx
📝 Walkthrough

Walkthrough

The documentation migrated gas estimation examples from Tact to Tolk, adding a Value flow section and updating fee, forward-fee, storage-fee, and receiver validation examples to use Tolk APIs and assert-based errors.

Changes

Documentation Code Examples

Layer / File(s) Summary
Intro and document structure
contract-dev/techniques/gas.mdx
Rewrote title/intro to match the revised article terminology and structure.
Value flow
contract-dev/techniques/gas.mdx
Added “Value flow” section clarifying message vs contract balance and updated diagram text.
Receiver requirements & fee limits
contract-dev/techniques/gas.mdx
Introduce receiver requirements and define fee limits using Tolk constants.
Compute fees and constants
contract-dev/techniques/gas.mdx
Replace fee constants and compute examples with Tolk imports and calculateGasFee(workchain, ...).
Forward fee calculation
contract-dev/techniques/gas.mdx
Rewrite forward-fee estimation to use msg.toCell(), calculateSizeStrict(8192), and calculateForwardFee(...); add strict-size caution.
Complex forward fee example
contract-dev/techniques/gas.mdx
Show complex forward-fee computation in onInternalMessage using calculateForwardFeeWithoutLumpPrice and workchain derivation.
Storage fee examples and reserve
contract-dev/techniques/gas.mdx
Overhaul storage fee handling to use calculateStorageFee, reserveToncoinsOnBalance, and assert-based ERR_NOT_ENOUGH_TONS checks.
Cover storage on demand flow
contract-dev/techniques/gas.mdx
Replace cover-storage examples with contract.getStorageDuePayment(), reserveToncoinsOnBalance(), createMessage(...).send(SEND_MODE_CARRY_ALL_BALANCE) and FreezeDueLimit checks.
Receiver fee validation example
contract-dev/techniques/gas.mdx
Rewrite final receiver example to onInternalMessage, parse request from slice, compute minFees across multiple calculateGasFee calls plus forward/freeze, and assert attached TON with ERR_INSUFFICIENT_TON_ATTACHED.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • kay-is

Poem

🐰 From Tact to Tolk I hopped with glee,

I rewrote fees and handlers, one, two, three.
Msgs now fit cells, reserves sit tight,
Assertions stand guard through day and night.
A tiny rabbit cheers—docs gleam bright!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: porting gas article code samples from Tact to Tolk, which matches the primary objective.
Linked Issues check ✅ Passed The pull request successfully translates all illustrative code examples from Tact to Tolk throughout the gas documentation article as required by issue #1003.
Out of Scope Changes check ✅ Passed All changes are scoped to converting Tact code examples to Tolk in the gas article; no unrelated modifications are present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pr-1003-gas-tolk

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@novusnota novusnota marked this pull request as ready for review April 22, 2026 09:01
@novusnota novusnota requested a review from a team as a code owner April 22, 2026 09:01
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
contract-dev/gas.mdx (2)

144-152: ⚠️ Potential issue | 🟡 Minor

Stale prose references computeDataSize() after Tolk port.

The Aside still talks about computeDataSize() and its "second argument: maximum number of cells to visit", but the code at Lines 134-135 now uses cell.calculateSizeStrict(8192). Similarly, Line 152's "In Tolk, both computations can be performed with a call to msg.send() with mode 1024" is disconnected from the preceding snippet (no msg.send() example is shown) and the old Tact-era phrasing leaks through.

Please rewrite this Aside and the following paragraph to reference calculateSizeStrict() / calculateForwardFee() by their Tolk names so readers can actually find them in the stdlib.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contract-dev/gas.mdx` around lines 144 - 152, The Aside and following
paragraph still reference the old computeDataSize() API and Tact-era phrasing;
update them to mention Tolk stdlib functions calculateSizeStrict(maxCells) and
calculateForwardFee() instead (replace “computeDataSize” and its "second
argument" wording with calculateSizeStrict(8192) and explain the maxCells
parameter), and change the Tolk example text to reference using msg.send() with
mode 1024 as a way to perform the same computations in Tolk while keeping the
TVM reference to SENDRAWMSG; ensure the prose points readers to the stdlib names
calculateSizeStrict and calculateForwardFee so links/searches work.

165-189: ⚠️ Potential issue | 🟠 Major

Fix function name and parameters to match Tolk stdlib signature.

Two issues here:

  1. Line 179 calls getSimpleForwardFee(...), but the prose at line 169 and the Tolk stdlib reference both confirm the canonical function is calculateForwardFeeWithoutLumpPrice.

  2. The function call passes isAccountInMasterchain as a parameter, but examining the parallel function calculateForwardFee(workchain, bits, cells) at lines 137–142 establishes the correct pattern: all parameters should be explicit, with workchain as the first parameter, followed by bits and cells.

🔧 Suggested fix
-    val additionalFwdFee = getSimpleForwardFee(
-        additionalFieldsSize.cells,
-        additionalFieldsSize.bits,
-        isAccountInMasterchain
-    );
+    val additionalFwdFee = calculateForwardFeeWithoutLumpPrice(
+        workchain,
+        additionalFieldsSize.bits,
+        additionalFieldsSize.cells,
+    );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contract-dev/gas.mdx` around lines 165 - 189, The call to getSimpleForwardFee
should be renamed to calculateForwardFeeWithoutLumpPrice and its arguments
reordered to match the Tolk stdlib: pass the workchain identifier as the first
argument, then bits, then cells (i.e., use the same signature pattern as
calculateForwardFee(workchain, bits, cells)); replace the isAccountInMasterchain
argument with the actual workchain value for the account/message and pass
additionalFieldsSize.bits and additionalFieldsSize.cells in that order.
🧹 Nitpick comments (1)
contract-dev/gas.mdx (1)

234-258: Unused msg binding and missing lazy in message-parse examples.

Minor refactor consistency items across the ported onInternalMessage samples (Lines 215, 238, 279, 300, 331):

  • The recommended Tolk idiom per tolk/features/message-handling.mdx:7-62 is val msg = lazy X.fromSlice(in.body); — readers copying from these docs miss the perf benefit without the lazy keyword.
  • In the samples on Lines 238 and 279 the parsed msg is declared but never referenced. Either use it (e.g. in msg.amount or similar) or drop the binding so the snippet doesn't read as dead code.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contract-dev/gas.mdx` around lines 234 - 258, The sample onInternalMessage
examples declare val msg = UserIn.fromSlice(in.body) but omit the recommended
lazy and in some snippets the binding is unused; update the parsing to use the
lazy idiom (e.g., make the binding lazy by changing the declaration to use lazy
with UserIn.fromSlice) and either reference msg where needed (e.g., use msg
fields in the fee/assert logic) or remove the unused val msg binding so there is
no dead code; target the onInternalMessage examples and the val msg declarations
to apply these changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@contract-dev/gas.mdx`:
- Around line 298-308: Replace the invalid placeholder and the non-existent
function: in onInternalMessage (and any other places using getFreezeLimit), set
otherFees to a concrete value (e.g., 0) instead of `...`, and replace calls to
getFreezeLimit(workchain) with the actual freeze_due_limit configuration value
(100000000 nanotons) or a call to the real config accessor if one exists in your
codebase; ensure the assertion uses the concrete freeze_due_limit and the
concrete otherFees variable so the snippet compiles (references:
onInternalMessage, InMessage, Operation.fromSlice, otherFees, getFreezeLimit,
freeze_due_limit).

---

Outside diff comments:
In `@contract-dev/gas.mdx`:
- Around line 144-152: The Aside and following paragraph still reference the old
computeDataSize() API and Tact-era phrasing; update them to mention Tolk stdlib
functions calculateSizeStrict(maxCells) and calculateForwardFee() instead
(replace “computeDataSize” and its "second argument" wording with
calculateSizeStrict(8192) and explain the maxCells parameter), and change the
Tolk example text to reference using msg.send() with mode 1024 as a way to
perform the same computations in Tolk while keeping the TVM reference to
SENDRAWMSG; ensure the prose points readers to the stdlib names
calculateSizeStrict and calculateForwardFee so links/searches work.
- Around line 165-189: The call to getSimpleForwardFee should be renamed to
calculateForwardFeeWithoutLumpPrice and its arguments reordered to match the
Tolk stdlib: pass the workchain identifier as the first argument, then bits,
then cells (i.e., use the same signature pattern as
calculateForwardFee(workchain, bits, cells)); replace the isAccountInMasterchain
argument with the actual workchain value for the account/message and pass
additionalFieldsSize.bits and additionalFieldsSize.cells in that order.

---

Nitpick comments:
In `@contract-dev/gas.mdx`:
- Around line 234-258: The sample onInternalMessage examples declare val msg =
UserIn.fromSlice(in.body) but omit the recommended lazy and in some snippets the
binding is unused; update the parsing to use the lazy idiom (e.g., make the
binding lazy by changing the declaration to use lazy with UserIn.fromSlice) and
either reference msg where needed (e.g., use msg fields in the fee/assert logic)
or remove the unused val msg binding so there is no dead code; target the
onInternalMessage examples and the val msg declarations to apply these changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 11f81afa-db6f-4112-958b-800aa0af4475

📥 Commits

Reviewing files that changed from the base of the PR and between fd9c051 and 14fd2e7.

📒 Files selected for processing (1)
  • contract-dev/gas.mdx

Comment thread contract-dev/techniques/gas.mdx
Comment thread contract-dev/techniques/gas.mdx Outdated
Copy link
Copy Markdown
Collaborator

@Shvandre Shvandre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only one comment. Otherwise looks good

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
contract-dev/techniques/gas.mdx (1)

179-183: ⚠️ Potential issue | 🟠 Major

Replace the non-existent getSimpleForwardFee API with the Tolk stdlib function.

The code at line 179 uses getSimpleForwardFee(), which does not exist in Tolk's stdlib. The correct function is calculateForwardFeeWithoutLumpPrice(workchain: int8, bits: int, cells: int), mentioned in the preceding paragraph. However, the function signature onInternalMessage(in: InMessage) does not have access to a workchain parameter. Determine the appropriate workchain value (or how to obtain it from the context) before applying the fix. See Tolk gas-payments stdlib for the correct API signature.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contract-dev/techniques/gas.mdx` around lines 179 - 183, Replace the
nonexistent getSimpleForwardFee call in onInternalMessage with the Tolk stdlib
calculateForwardFeeWithoutLumpPrice and pass a proper workchain value: derive
workchain as int8 from isAccountInMasterchain (use -1 for masterchain, 0 for
basic workchain) and call calculateForwardFeeWithoutLumpPrice(workchain,
additionalFieldsSize.bits, additionalFieldsSize.cells) so the argument order
matches the stdlib signature.
♻️ Duplicate comments (1)
contract-dev/techniques/gas.mdx (1)

302-303: ⚠️ Potential issue | 🟡 Minor

Replace the unresolved freeze-limit placeholder.

getFreezeLimit(workchain) is not a Tolk stdlib helper, and ... is not valid Tolk syntax. Use a real config parser or a concrete freeze_due_limit constant, and reuse it in the final validation snippet too. This duplicates a prior review comment but remains unresolved. Refs: Tolk stdlib docs, TON limits docs.

🔧 Possible illustrative fix
+const FreezeDueLimit = ton("0.1");
+
 fun onInternalMessage(in: InMessage) {
     val msg = Operation.fromSlice(in.body);
     // The trace is still receiver -> A -> B
-    val freezeLimit = getFreezeLimit(workchain);
-    val otherFees = ...;
+    val freezeLimit = FreezeDueLimit;
+    val otherFees = 0;  // compute + forward fees go here
     // n equals 3 because receiver -> A -> B
     assert (in.valueCoins >= freezeLimit * 3 + otherFees)
         throw ERR_NOT_ENOUGH_TONS;
 }
-        3 * getFreezeLimit(workchain);
+        3 * FreezeDueLimit;

Verification:

#!/bin/bash
set -euo pipefail

gas="$(curl -fsSL https://raw.githubusercontent.com/ton-blockchain/ton/master/crypto/smartcont/tolk-stdlib/gas-payments.tolk)"

if printf '%s\n' "$gas" | grep -n 'getFreezeLimit'; then
  echo "Unexpected getFreezeLimit API found in Tolk stdlib" >&2
  exit 1
else
  echo "getFreezeLimit is not present in Tolk gas-payments stdlib"
fi

curl -fsSL https://docs.ton.org/foundations/limits | grep -E 'freeze_due_limit|100000000'

Also applies to: 348-348

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contract-dev/techniques/gas.mdx` around lines 302 - 303, The snippet uses a
non-existent helper getFreezeLimit(workchain) and an invalid '...' placeholder;
replace them by declaring a concrete constant (e.g. freeze_due_limit =
<value_from_TON_limits_or_config>) or parsing it from a real config parser, then
assign val freezeLimit = freeze_due_limit and compute val otherFees explicitly
instead of '...'; update the final validation snippet to reuse
freeze_due_limit/freezeLimit (and remove getFreezeLimit and '...') so all
references (freezeLimit, otherFees) are real values derived from the declared
constant or parsed config.
🧹 Nitpick comments (1)
contract-dev/techniques/gas.mdx (1)

288-288: Use BounceMode.NoBounce instead of deprecated boolean bounce.

Current Tolk stdlib marks false as deprecated for the bounce field; documentation examples should use the enum form. The Tolk stdlib deprecation notice explicitly recommends BounceMode.NoBounce instead.

♻️ Proposed refactor
-        bounce: false,
+        bounce: BounceMode.NoBounce,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contract-dev/techniques/gas.mdx` at line 288, The example uses the deprecated
boolean bounce flag; replace the boolean usage (bounce: false) with the enum
form (bounce: BounceMode.NoBounce) and ensure the BounceMode symbol is in scope
(import or reference the enum where the message/transaction object is
constructed). Update the object property to use BounceMode.NoBounce and remove
the boolean literal so the code uses the recommended enum constant.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@contract-dev/techniques/gas.mdx`:
- Around line 107-109: The snippet uses the helper function calculateGasFee but
Tolk only auto-imports common.tolk, so add the explicit import for the fee
helpers by inserting import "@stdlib/gas-payments"; immediately before the
calculateGasFee usage (ensure the import appears at the top of the tolk code
block containing calculateGasFee so the fee helper symbols are available).

---

Outside diff comments:
In `@contract-dev/techniques/gas.mdx`:
- Around line 179-183: Replace the nonexistent getSimpleForwardFee call in
onInternalMessage with the Tolk stdlib calculateForwardFeeWithoutLumpPrice and
pass a proper workchain value: derive workchain as int8 from
isAccountInMasterchain (use -1 for masterchain, 0 for basic workchain) and call
calculateForwardFeeWithoutLumpPrice(workchain, additionalFieldsSize.bits,
additionalFieldsSize.cells) so the argument order matches the stdlib signature.

---

Duplicate comments:
In `@contract-dev/techniques/gas.mdx`:
- Around line 302-303: The snippet uses a non-existent helper
getFreezeLimit(workchain) and an invalid '...' placeholder; replace them by
declaring a concrete constant (e.g. freeze_due_limit =
<value_from_TON_limits_or_config>) or parsing it from a real config parser, then
assign val freezeLimit = freeze_due_limit and compute val otherFees explicitly
instead of '...'; update the final validation snippet to reuse
freeze_due_limit/freezeLimit (and remove getFreezeLimit and '...') so all
references (freezeLimit, otherFees) are real values derived from the declared
constant or parsed config.

---

Nitpick comments:
In `@contract-dev/techniques/gas.mdx`:
- Line 288: The example uses the deprecated boolean bounce flag; replace the
boolean usage (bounce: false) with the enum form (bounce: BounceMode.NoBounce)
and ensure the BounceMode symbol is in scope (import or reference the enum where
the message/transaction object is constructed). Update the object property to
use BounceMode.NoBounce and remove the boolean literal so the code uses the
recommended enum constant.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e08d6a54-9838-4ca1-9864-22043048c71e

📥 Commits

Reviewing files that changed from the base of the PR and between 14fd2e7 and 917dd07.

📒 Files selected for processing (1)
  • contract-dev/techniques/gas.mdx

Comment thread contract-dev/techniques/gas.mdx
@aigerimu
Copy link
Copy Markdown
Contributor

/review

Comment thread contract-dev/techniques/gas.mdx
Comment thread contract-dev/techniques/gas.mdx
Comment thread contract-dev/techniques/gas.mdx
Comment thread contract-dev/techniques/gas.mdx
Comment on lines +243 to +268
fun onInternalMessage(in: InMessage) {
val workchain = contract.getAddress().getWorkchain();
val minTonsForStorage = calculateStorageFee(
workchain,
secondsInFiveYears,
isAccountInMasterchain
maxBits,
maxCells,
);
nativeReserve(
val oldBalance = contract.getOriginalBalance() - in.valueCoins;
reserveToncoinsOnBalance(
max(oldBalance, minTonsForStorage),
ReserveAtMost
RESERVE_MODE_AT_MOST,
);
// Process operation with remaining value...
}
// Also this contract probably will require some code, that will allow owner to withdraw TONs from this contract.
// This contract probably also requires some code allowing the owner to withdraw TONs from it.
```

In this approach, a receiver contract should calculate maximum possible storage fees for all contracts in trace.

```tact
const secondsInFiveYears: Int = 5 * 365 * 24 * 60 * 60;
receive(msg: UserIn) {
// Suppose trace will be
```tolk
import "@stdlib/gas-payments";

const secondsInFiveYears = 5 * 365 * 24 * 60 * 60;

fun onInternalMessage(in: InMessage) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] Error identifiers in prose not formatted as code

Lines 243–268 describe Tolk error handling using identifiers such as ERR_NOT_ENOUGH_TONS and ERR_INSUFFICIENT_TON_ATTACHED in running text, but they are not consistently wrapped in code formatting. The style guide requires that error codes and identifiers be rendered in code font so they stand out visually, remain copy‑pasteable, and are clearly distinguished from surrounding prose. Leaving them as plain text decreases readability and can make it harder to spot exact names.

Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!

Comment thread contract-dev/techniques/gas.mdx
Comment on lines +331 to 341
```tolk
const FreezeDueLimit = ton("0.1"); // Current mainnet freeze_due_limit; adjust for other networks if needed.

```tact
receive(msg: Operation) {
fun onInternalMessage(in: InMessage) {
// The trace is still receiver -> A -> B
let freezeLimit = getFreezeLimit(isAccountsInMasterchain);
let otherFees = ...;
val freezeLimit = FreezeDueLimit;
val otherFees = 0; // Compute + forward fees go here.
// n equals 3 because receiver -> A -> B
require(
messageValue() >= freezeLimit * 3 + otherFees,
"Not enough TONs"
);
assert (in.valueCoins >= freezeLimit * 3 + otherFees)
throw ERR_NOT_ENOUGH_TONS;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] Hardcoded FreezeDueLimit requires explicit network-scope safety callout

The example on lines 331–341 hardcodes const FreezeDueLimit = ton("0.1"); and comments that this reflects the “Current mainnet freeze_due_limit; adjust for other networks if needed.” Without an explicit safety callout, this may encourage readers to copy the value verbatim across networks, which can misprice storage reservation and affect funds, contrary to the style guidance for safety‑critical content. Because the code is illustrative, the primary risk is misunderstanding the network-specific nature of the constant, not the numeric value itself.

Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!

Comment on lines +287 to 289
assert (in.valueCoins >= totalStorageFees + otherFees)
throw ERR_NOT_ENOUGH_TONS;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] Receiver reserve check uses generic error identifier without quoted mapping

The example check on lines 287–289 throws ERR_NOT_ENOUGH_TONS without showing the corresponding user-facing error string, while similar examples later introduce identifiers like ERR_INSUFFICIENT_TON_ATTACHED. For consistency and grep‑ability, the style rules favor either using a clearly named identifier everywhere or showing how it maps to a literal error message in comments or surrounding text. Making this mapping explicit in the snippet avoids ambiguity when correlating documentation with runtime errors.

Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!

@github-actions
Copy link
Copy Markdown
Contributor

Thanks for the detailed work on contract-dev/techniques/gas.mdx; I’ve left several focused suggestions to tighten terminology, headings, and example clarity—please apply the inline suggestions where they align with your intent.


Per-comment submission: 8 posted, 5 failed.

Unposted inline comments (raw text):

  • contract-dev/techniques/gas.mdx:L43-L49

    [HIGH] “user message” phrasing violates impersonal style in receiver requirements

    Lines 43–49 in the “Receiver requirements” section state that “If an entry contract accepts a user message it must guarantee that the message will not later fail…”. This “user message” phrasing introduces a user-centric frame that the style guide discourages, which prefers neutral, technical language about external or inbound messages. Maintaining impersonal terminology avoids anthropomorphizing users and keeps descriptions focused on system behavior.

    Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!

  • contract-dev/techniques/gas.mdx:L65-L71

    [HIGH] Tolk fee limit constants lack explicit type annotations

    Lines 65–71 show a Tolk code snippet that declares const GasSwapRequest = 0; without an explicit type annotation. In this documentation set, Tolk examples for numeric constants typically include explicit integer types (for example, : Int) so that examples are idiomatic and clearly typed. Omitting the type can make the snippet less realistic or potentially ambiguous in a broader context, undermining the requirement that examples be precise and copy‑pasteable.

    Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!

  • contract-dev/techniques/gas.mdx:L92-L98

    [HIGH] Tolk constant GasSwapRequest later also lacks type annotation

    Lines 92–98 contain a second Tolk example where GasSwapRequest is reassigned a value (const GasSwapRequest = 12000;) again without a type annotation. Maintaining explicit typing across all such examples keeps the code consistent and prevents readers from inferring that untyped numeric constants are the recommended style. Aligning this later snippet with the earlier recommendation preserves copy‑pasteability and clarity.

    Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!

  • contract-dev/techniques/gas.mdx:L177-L187

    [HIGH] Error identifier uses non‑canonical “TONs” in Tolk example

    Lines 177–187 define a Tolk snippet with throw ERR_NOT_ENOUGH_TONS;, and the identifier encodes “TONS”, which pluralizes TON instead of using the canonical term “Toncoin”. The terminology rules require consistent, canonical naming for the currency in both prose and code identifiers to avoid confusion and stylistic drift. Using “TONS” here conflicts with those conventions and may encourage inconsistent naming in downstream contracts.

    Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!

  • contract-dev/techniques/gas.mdx:L228-L233

    [MEDIUM] Reserve description uses “user interaction” instead of neutral interaction term

    The explanatory paragraph on lines 228–233 states, “The reserve get replenished with each user interaction,” which uses “user” in a way that implicitly centers the reader rather than describing the system behavior in neutral terms. This is a softer form of personalization than direct second-person pronouns but still conflicts with the depersonalization preference in the style rules. Adjusting the phrase to describe external interactions preserves clarity while aligning with the neutral, role-based tone.

    Please leave a reaction 👍/👎 to this suggestion to improve future reviews for everyone!

@skywardboundd
Copy link
Copy Markdown
Contributor

do we have some tests for these contracts?

@aigerimu
Copy link
Copy Markdown
Contributor

do we have some tests for these contracts?

no, should we?

@skywardboundd
Copy link
Copy Markdown
Contributor

do we have some tests for these contracts?

no, should we?

yes, it is open source

https://github.com/ton-org/docs-examples

@delovoyhomie delovoyhomie requested review from ijonele and kay-is and removed request for ijonele and skywardboundd May 11, 2026 08:16
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@contract-dev/techniques/gas.mdx`:
- Around line 373-387: The fee formula in minFees reuses the forward-fee
estimate (fwdFee / in.originalForwardFee) across hops but lacks the
same-workchain precondition, so add a guard before or alongside the minFees
calculation (near messageCount/minFees) that verifies all hops remain in the
same workchain as workchain (e.g., check that receiver, vault, pool and final
vault workchain IDs equal workchain); if they are not equal, fall back to a
conservative fee calculation or refuse to use the reused fwdFee estimate so you
don't under-estimate attached value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 684d77de-feb6-4255-a50d-2f82d8077a4e

📥 Commits

Reviewing files that changed from the base of the PR and between 917dd07 and a907b2d.

📒 Files selected for processing (1)
  • contract-dev/techniques/gas.mdx

Comment on lines +373 to +387
// Count all messages in the operation chain.
// IMPORTANT: we know that each of these messages is
// less than or equal to `SwapRequest`.
val messageCount = 3; // receiver -> vault -> pool -> vault

// Calculate minimum required
let minFees =
// Calculate the minimum required value
val minFees =
messageCount * fwdFee +
// Operation in first vault
getComputeFee(GasSwapRequest, isInMasterchain) +
// Operation in pool
getComputeFee(GasPoolSwap, isInMasterchain) +
// Operation in second vault
getComputeFee(GasVaultPayout, isInMasterchain) +
3 * getFreezeLimit();

require(
ctx.value >= msg.amount + minFees,
"Insufficient TON attached"
);
// Operation in the first vault
calculateGasFee(workchain, GasSwapRequest) +
// Operation in the pool
calculateGasFee(workchain, GasPoolSwap) +
// Operation in the second vault
calculateGasFee(workchain, GasVaultPayout) +
3 * FreezeDueLimit;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the missing same-workchain precondition next to the minFees formula.

This formula reuses in.originalForwardFee across hops, but that estimate is only valid when all hops stay in the same workchain (in addition to the message-size bound). Without that guard, this can under-estimate attached value.

Suggested doc-level fix
     // Count all messages in the operation chain.
     // IMPORTANT: we know that each of these messages is
     // less than or equal to `SwapRequest`.
+    // IMPORTANT: all hops are in the same workchain.
     val messageCount = 3;  // receiver -> vault -> pool -> vault
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Count all messages in the operation chain.
// IMPORTANT: we know that each of these messages is
// less than or equal to `SwapRequest`.
val messageCount = 3; // receiver -> vault -> pool -> vault
// Calculate minimum required
let minFees =
// Calculate the minimum required value
val minFees =
messageCount * fwdFee +
// Operation in first vault
getComputeFee(GasSwapRequest, isInMasterchain) +
// Operation in pool
getComputeFee(GasPoolSwap, isInMasterchain) +
// Operation in second vault
getComputeFee(GasVaultPayout, isInMasterchain) +
3 * getFreezeLimit();
require(
ctx.value >= msg.amount + minFees,
"Insufficient TON attached"
);
// Operation in the first vault
calculateGasFee(workchain, GasSwapRequest) +
// Operation in the pool
calculateGasFee(workchain, GasPoolSwap) +
// Operation in the second vault
calculateGasFee(workchain, GasVaultPayout) +
3 * FreezeDueLimit;
// Count all messages in the operation chain.
// IMPORTANT: we know that each of these messages is
// less than or equal to `SwapRequest`.
// IMPORTANT: all hops are in the same workchain.
val messageCount = 3; // receiver -> vault -> pool -> vault
// Calculate the minimum required value
val minFees =
messageCount * fwdFee +
// Operation in the first vault
calculateGasFee(workchain, GasSwapRequest) +
// Operation in the pool
calculateGasFee(workchain, GasPoolSwap) +
// Operation in the second vault
calculateGasFee(workchain, GasVaultPayout) +
3 * FreezeDueLimit;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contract-dev/techniques/gas.mdx` around lines 373 - 387, The fee formula in
minFees reuses the forward-fee estimate (fwdFee / in.originalForwardFee) across
hops but lacks the same-workchain precondition, so add a guard before or
alongside the minFees calculation (near messageCount/minFees) that verifies all
hops remain in the same workchain as workchain (e.g., check that receiver,
vault, pool and final vault workchain IDs equal workchain); if they are not
equal, fall back to a conservative fee calculation or refuse to use the reused
fwdFee estimate so you don't under-estimate attached value.

@github-actions
Copy link
Copy Markdown
Contributor

To fix the formatting issues:

  1. Install necessary dependencises: npm ci
  2. Then, run this command:
    npm run fmt:some -- contract-dev/techniques/gas.mdx

Alternatively, a maintainer can comment /fmt in this PR to auto-apply fixes in a new commit from the bot.

Copy link
Copy Markdown
Collaborator

@kay-is kay-is left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just added some suggestions to improve consistency or cosmetics.


```mermaid
flowchart LR
User1((User)) --> Receiver((Receiver)) --> A((A)) --> B((B)) --> User2((User))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added arrows to the flow chart.

Suggested change
User1((User)) -->> Receiver((Receiver)) -->> A((A)) -->> B((B)) -->> User2((User))


```mermaid
flowchart LR
User1((User)) --> A((A)) --> B((B)) --> User2((User))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added arrows to the flow chart.

Suggested change
User1((User)) -->> A((A)) -->> B((B)) -->> User2((User))


```tact
const GasSwapRequest: Int = 0;
```tolk
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```tolk
```tolk title="Tolk"

- Extract resource consumption from the `send()` method's return value. The sections below describe ways to compute consumption of different kinds of resources.
- Use `expect(extractedValue).toBeLessThanOrEqual(hardcodedConstant)` to verify that the hardcoded limit was not exceeded.

```ts
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```ts title="TypeScript"


```tact
const GasSwapRequest: Int = 12000;
```tolk
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```tolk
```tolk title="Tolk"

Comment on lines +14 to +16
1. receiver;
1. internal contract A;
1. internal contract B.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. receiver;
1. internal contract A;
1. internal contract B.
1. Receiver contract
1. Internal contract A
1. Internal contract B

Comment thread contract-dev/techniques/gas.mdx Outdated

### Receiver requirements

Receiver contracts must verify that the attached Toncoin is sufficient to cover fees for all contracts in the subsequent trace. If an entry contract accepts a user message it must guarantee that the message will not later fail due to insufficient attached TON. "Accept" doesn't mean the call to `accept_message()`, but semantic acceptance, i.e., no throw and no asset returns.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Receiver contracts must verify that the attached Toncoin is sufficient to cover fees for all contracts in the subsequent trace. If an entry contract accepts a user message it must guarantee that the message will not later fail due to insufficient attached TON. "Accept" doesn't mean the call to `accept_message()`, but semantic acceptance, i.e., no throw and no asset returns.
Receiver contracts must verify that the attached Toncoin is sufficient to cover fees for all contracts in the subsequent trace. If an entry contract accepts a user message it must guarantee that the message will not later fail due to insufficient attached Toncoin. "Accept" doesn't mean the call to `accept_message()`, but semantic acceptance, i.e., no throw and no asset returns.

Comment thread contract-dev/techniques/gas.mdx Outdated
// Process operation with remaining value...
}
// Also this contract probably will require some code, that will allow owner to withdraw TONs from this contract.
// This contract probably also requires some code allowing the owner to withdraw TON from it.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// This contract probably also requires some code allowing the owner to withdraw TON from it.
// This contract probably also requires some code allowing the owner to withdraw Toncoins from it.

Comment thread contract-dev/techniques/gas.mdx Outdated
});
```

This confirms that all incoming value was consumed or forwarded, with none left behind. It helps identify any bugs that cause accumulation of TON on any contract.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This confirms that all incoming value was consumed or forwarded, with none left behind. It helps identify any bugs that cause accumulation of Toncoins on any contract.

Comment thread contract-dev/techniques/gas.mdx Outdated
// It may also be necessary to handle fees on this exact
// contract if it is not supposed to hold users' TONs.
// That can be done in either of the two approaches
// contract if it is not supposed to hold users' TON.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// contract if it is not supposed to hold users' TON.
// contract if it is not supposed to hold users' Toncoin.

@novusnota
Copy link
Copy Markdown
Collaborator

Warning

There are quite a few suggested changes, which is great, but I must warn us not to apply them via buttons in GitHub's interface. Instead, treat them as nicely presented steps that could be taken, and apply changes locally only!

That is because GitHub's suggestions are completely broken and, when applied, hurt the PR — actually committed lines and changes differ from their representation in the UI!

@delovoyhomie
Copy link
Copy Markdown
Contributor Author

@novusnota regarding to your last comment, how should we merge this PR?

@novusnota
Copy link
Copy Markdown
Collaborator

novusnota commented May 15, 2026

@novusnota regarding to your last comment, how should we merge this PR?

@delovoyhomie As usual — the comment was only a warning to not apply GitHub suggestions in the interface, and instead make changes directly, locally :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Contract dev > Gas] Translate code examples to Tolk

6 participants