Gas consumption
As you develop and iterate on a contract, even small changes to its logic can affect both gas usage and data size. Monitoring these changes helps ensure that your contract remains efficient and cost-effective.For a deeper breakdown of how fees work in TON, refer to:
Gas metrics reporting
To simplify tracking changes in gas usage and data size, we’ve introduced a reporting system that lets you collect and compare metrics across different versions of a contract. To enable this, write test scenarios that cover the contract’s primary usage patterns and verify expected behavior. This approach is sufficient to gather relevant metrics, which you can later use to compare performance changes after updating the implementation. Before running the tests, a store is created to collect metrics from all transactions generated during the tests. After test execution, the collected metrics are supplemented with ABI information from the snapshot, and a report is generated based on this data. While more metrics are collected, the current report format includesgasUsed
, cells
, and bits
, which correspond to the internal metrics compute.phase
, state.code
, and state.data
.
Metrics comparison example
To see how gas metrics can be collected and compared in practice, let’s walk through a complete example. Start by creating a new project usingnpm create ton@latest
:
- The
-y
flag skips prompts and accepts defaults. --type
specifies the template (e.g.,func-counter
).--contractName
sets the contract name.
contracts/sample.fc
.
It defines a simple stateful contract that stores an id
and a counter
and supports an increase
operation.
sample.fc
Generate a gas report
Let’s now generate a gas usage report for the contract. Run the following command:gas-report.json
with transaction metrics.
…
PASS Comparison metric mode: gas depth: 1
Gas report write in ‘gas-report.json’
┌───────────┬──────────────┬───────────────────────────┐
│ │ │ current │
│ Contract │ Method ├──────────┬────────┬───────┤
│ │ │ gasUsed │ cells │ bits │
├───────────┼──────────────┼──────────┼────────┼───────┤
│ │ sendDeploy │ 1937 │ 11 │ 900 │
│ ├──────────────┼──────────┼────────┼───────┤
│ │ send │ 515 │ 11 │ 900 │
│ Sample ├──────────────┼──────────┼────────┼───────┤
│ │ sendIncrease │ 1937 │ 11 │ 900 │
│ ├──────────────┼──────────┼────────┼───────┤
│ │ 0x7e8764ef │ 2681 │ 11 │ 900 │
└───────────┴──────────────┴──────────┴────────┴───────┘
Storage fee calculation
You can use thecells
and bits
values from the report to estimate the storage fee for your contract.
Here’s the formula:
Regenerate the gas report
Note that theop::increase
method appears in the report as the raw opcode 0x7e8764ef
.
To display a human-readable name in the report, update the generated contract.abi.json
by replacing the raw opcode with the name increase in both the messages
and types
sections:
contract.abi.json
file, rerun the command to regenerate the gas report:
increase
, making it easier to read:
…
│ ├──────────────┼──────────┼────────┼───────┤
│ │ increase │ 2681 │ 11 │ 900 │
└───────────┴──────────────┴──────────┴────────┴───────┘
Save a snapshot for future comparison
To track how gas usage evolves, you can create a named snapshot of the current metrics. This allows you to compare future versions of the contract against this baseline:.snapshot/
:
Optimize the contract and compare the metrics
Let’s try a simple optimization — adding theinline
specifier to some functions.
An inline specifier is directly substituted into the code wherever it’s called, which can help reduce gas usage by eliminating the overhead of a function call.
v1
, this report will include a comparison with the previous version:
PASS Comparison metric mode: gas depth: 2
Gas report write in ‘gas-report.json’
┌───────────┬──────────────┬─────────────────────────────────────────┬───────────────────────────┐
│ │ │ current │ v1 │
│ Contract │ Method ├──────────────┬───────────┬──────────────┼──────────┬────────┬───────┤
│ │ │ gasUsed │ cells │ bits │ gasUsed │ cells │ bits │
├───────────┼──────────────┼──────────────┼───────────┼──────────────┼──────────┼────────┼───────┤
│ │ sendDeploy │ 1937 same │ 7 -36.36% │ 1066 +18.44% │ 1937 │ 11 │ 900 │
│ ├──────────────┼──────────────┼───────────┼──────────────┼──────────┼────────┼───────┤
│ │ send │ 446 -13.40% │ 7 -36.36% │ 1066 +18.44% │ 515 │ 11 │ 900 │
│ Sample ├──────────────┼──────────────┼───────────┼──────────────┼──────────┼────────┼───────┤
│ │ sendIncrease │ 1937 same │ 7 -36.36% │ 1066 +18.44% │ 1937 │ 11 │ 900 │
│ ├──────────────┼──────────────┼───────────┼──────────────┼──────────┼────────┼───────┤
│ │ increase │ 1961 -26.86% │ 7 -36.36% │ 1066 +18.44% │ 2681 │ 11 │ 900 │
└───────────┴──────────────┴──────────────┴───────────┴──────────────┴──────────┴────────┴───────┘
Project setup instructions
If your project already exists, you need to configure jest to collect gas metrics. You can do this in one of two ways:Option 1: update the existing jest.config.ts
Add the necessary environment and reporter settings:
jest.config.ts
See the full list of options in the Sandbox jest config docs.
Option 2: create a separate config gas-report.config.ts
If you prefer not to modify your main jest.config.ts
, you can create a dedicated config file:
gas-report.config.ts
--config
option:
Collect metrics manually
You can collect metrics manually using the low-level API from@ton/sandbox
.
collect-metrics.ts