Skip to content

Rework fees articles #527

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 124 additions & 19 deletions docs/develop/howto/fees-low-level.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,107 @@ This document provides a general idea of transaction fees on TON and particularl

## Transactions and phases

As was described in the [TVM overview](/learn/tvm-instructions/tvm-overview), transaction execution consists of a few phases. During those phases, the corresponding fees may be deducted.
As was described in the [TVM overview](/learn/tvm-instructions/tvm-overview), transaction execution consists of a few phases. During those phases, the corresponding fees may be deducted. There is a [high-level fees overview](docs/develop/smart-contracts/fees).

## Storage fee

TON validators collect storage fees from smart contracts.

Storage fees are collected from the smart contract balance at the **Storage phase** of any transaction due storage payments for the account state
(including smart-contract code and data, if present) up to the present time. The smart contract may be frozen as a result.

It’s important to keep in mind that on TON you pay for both the execution of a smart contract and for the **used storage**, according to the [@thedailyton article](https://telegra.ph/Commissions-on-TON-07-22):

```cpp
bytes * second
```

It means you have to pay a storage fee for having TON Wallet (even if it's very-very small).

If you have not used your TON Wallet for a significant period of time (1 year), _you will have to pay a significantly larger commission than usual because the wallet pays commission on sending and receiving transactions_.

### Formula

You can approximately calculate storage fees for smart contracts using this formula:


Generally:
```cpp
transaction_fee = storage_fees
+ in_fwd_fees
+ computation_fees
+ action_fees
+ out_fwd_fees
storage_fee = (cells_count * cell_price + bits_count * bit_price)
/ 2^16 * time_delta
```
where:
* `storage_fees`—fees corresponding to occupation of some space in chain state by contract
* `in_fwd_fees`—fees for importing to blockchain incoming message (it is only relevant for messages which were not previously on-chain, that is, `external` messages. For ordinary messages from contract to contract this fee is not applicable)
* `computation_fees`—fees corresponding to execution of TVM instructions
* `action_fees`—fees related to processing of action list (sending messages, setting libraries etc.)
* `out_fwd_fees`—fees related to importing to blockchain of outcoming message

Let's examine each value more closely:

* `storage_fee`—price for storage for `time_delta` seconds
* `cells_count`—count of cells used by smart contract
* `bits_count`—count of bits used by smart contract
* `cell_price`—price of single cell
* `bit_price`—price of single bit

Both `cell_price` and `bit_price` could be obtained from Network Config [param 18](/develop/howto/blockchain-configs#param-18).

Current values are:

* Workchain.
```cpp
bit_price_ps:1
cell_price_ps:500
```
* Masterchain.
```cpp
mc_bit_price_ps:1000
mc_cell_price_ps:500000
```

### Calculator Example

You can use this JS script to calculate storage price for 1 MB in the workchain for 1 year

```js live

// Welcome to LIVE editor!
// feel free to change any variables

function storageFeeCalculator() {

const size = 1024 * 1024 * 8 // 1MB in bits
const duration = 60 * 60 * 24 * 365 // 1 Year in secs

const bit_price_ps = 1
const cell_price_ps = 500

const pricePerSec = size * bit_price_ps +
+ Math.ceil(size / 1023) * cell_price_ps

let fee = (pricePerSec * duration / 2**16 * 10**-9)
let mb = (size / 1024 / 1024 / 8).toFixed(2)
let days = Math.floor(duration / (3600 * 24))

let str = `Storage Fee: ${fee} TON (${mb} MB for ${days} days)`

return str
}

```

## Forward fees

Internal messages define an `ihr_fee` in Toncoins, which is subtracted from the value attached to the message and awarded to the validators of the destination shardchain if they include the message by the IHR mechanism. The `fwd_fee` is the original total forwarding fee paid for using the HR mechanism; it is automatically computed from some configuration parameters and the size of the message at the time the message is generated. Notice that the total value carried by a newly-created internal outbound message equals the sum of value, `ihr_fee`, and `fwd_fee`. This sum is deducted from the balance of the source account. Of these components, only value is always credited to the destination account on message delivery. The `fwd_fee` is collected by the validators on the HR path from the source to the destination, and the `ihr_fee` is either collected by the validators of the destination shardchain (if the message is delivered via IHR), or credited to the destination account.

:::info
`fwd_fee` covers 2/3 of the cost, as 1/3 is allocated to the `action_fee` when the message is created.

```cpp
auto fwd_fee_mine = msg_prices.get_first_part(fwd_fee);
auto fwd_fee_remain = fwd_fee - fwd_fee_mine;

fees_total = fwd_fee + ihr_fee;
fees_collected = fwd_fee_mine;

ap.total_action_fees += fees_collected;
ap.total_fwd_fees += fees_total;
```
:::

## Computation fees

Expand All @@ -32,7 +117,7 @@ All computation costs are nominated in gas units. The price of gas units is dete

Current settings in basechain are as follows: 1 unit of gas costs 1000 nanotons.

## TVM instructions cost
### TVM instructions cost
On the lowest level (TVM instruction execution) the gas price for most primitives
equals the _basic gas price_, computed as `P_b := 10 + b + 5r`,
where `b` is the instruction length in bits and `r` is the
Expand All @@ -52,7 +137,7 @@ Apart from those basic fees, the following fees appear:
| Moving stack elements | **1** | Price for moving stack elements between continuations. It will charge correspond gas price for every element. However, the first 32 elements moving is free. |


## FunC constructions gas fees
### FunC constructions gas fees

Almost all functions used in FunC are defined in [stdlib.func](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/stdlib.fc) which maps FunC functions to Fift assembler instructions. In turn, Fift assembler instructions are mapped to bit-sequence instructions in [asm.fif](https://github.com/ton-blockchain/ton/blob/master/crypto/fift/lib/Asm.fif). So if you want to understand how much exactly the instruction call will cost you, you need to find `asm` representation in `stdlib.func`, then find bit-sequence in `asm.fif` and calculate instruction length in bits.

Expand Down Expand Up @@ -136,7 +221,20 @@ will be translated into a few instructions which changes the order of elements o

When the number of stack entries is substantial (10+), and they are actively used in different orders, stack operations fees may become non-negligible.

## Fee's calculation Formulas
## Action fee

Action fee is deducted from the balance of the source account during processing action list which is perfomed after Computing phase.
These are the actions that lead to pay fees:

* `SENDRAWMSG` sends a raw message.
* `RAWRESERVE` creates an output action which would reserve N Nanotons.
* `RAWRESERVEX` similar to `RAWRESERVE`, but also accepts a dictionary with extra currencies.
* `SETCODE` creates an output action that would change this smart contract code.
* `SETLIBCODE` creates an output action that would modify the collection of this smart contract libraries by adding or removing library with given code.
* `CHANGELIB` creates an output action similarly to `SETLIBCODE`, but instead of the library code accepts its hash.
* `FB08–FB3F` reserved for output action primitives.

## Fee's calculation formulas

### storage_fees
```cpp
Expand All @@ -145,8 +243,8 @@ storage_fees = ceil(
+ account.cells * cell_price)
* period / 2 ^ 16)
```
### in_fwd_fees, out_fwd_fees

### in_fwd_fees, out_fwd_fees
```cpp
msg_fwd_fees = (lump_price
+ ceil(
Expand All @@ -162,7 +260,7 @@ ihr_fwd_fees = ceil((msg_fwd_fees * ihr_price_factor) / 2^16)
action_fees = sum(out_ext_msg_fwd_fee) + sum(int_msg_mine_fee)
```

### Config file
## Fee's config file

All fees are nominated for a certain gas amount and may be changed. The config file represents the current fee cost.

Expand All @@ -176,4 +274,11 @@ All fees are nominated for a certain gas amount and may be changed. The config f
[A direct link to the mainnet config file](https://explorer.toncoin.org/config?workchain=-1&shard=8000000000000000&seqno=22185244&roothash=165D55B3CFFC4043BFC43F81C1A3F2C41B69B33D6615D46FBFD2036256756382&filehash=69C43394D872B02C334B75F59464B2848CD4E23031C03CA7F3B1F98E8A13EE05)
:::

*Based on @thedailyton [article](https://telegra.ph/Fees-calculation-on-the-TON-Blockchain-07-24) from 24.07*
## References

* Based on @thedailyton [article](https://telegra.ph/Fees-calculation-on-the-TON-Blockchain-07-24) from 24.07*

## See Also

* [TON Fees overview](/develop/smart-contracts/fees)
* [Transactions and Phases](/learn/tvm-instructions/tvm-overview#transactions-and-phases)
2 changes: 1 addition & 1 deletion docs/develop/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ If you're new to TON Blockchain development, it's recommended that you start fro
- [Cells as a Data Structure](/learn/overviews/cells) - A high-level explanation of data structures.
- [TON Networking](/learn/networking/overview) - A high-level overview of TON peer-to-peer protocols.
- [TON Virtual Machine (TVM)](/learn/tvm-instructions/tvm-overview) - A high-level overview of TON Virtual Machine.
- [Transactions and Phases](/learn/tvm-instructions/tvm-overview#transactions-and-phases) - A detailed explanation of transactions and phases.
- [Transactions and Phases](/learn/tvm-instructions/tvm-overview#transactions-and-phases) - A detailed explanation of transactions and phases.
- [Transaction Fees](/develop/smart-contracts/fees) - A high-level explanation of transaction fees.

### Infrastructure
Expand Down
99 changes: 12 additions & 87 deletions docs/develop/smart-contracts/fees.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,15 @@ Fees on TON are difficult to calculate in advance, as their amount depends on tr

That is why even NFT marketplaces usually take an extra amount of TON (_~1 TON_) and return (_`1 - transaction_fee`_) later.

:::info
Please use [new TVM opcodes](/learn/tvm-instructions/fee-calculation-instructions#opcodes-to-process-config-parameters) in your smart contracts to dynamically calculate fees and do not hardcode fees in Toncoins in the smart contract code
:::

However, let's read more about how fees are supposed to function on TON.

## Basic Fees Formula

According to the [low-level fees overview](/develop/howto/fees-low-level), fees on TON are calculated by this formula:
Fees on TON are calculated by this formula:

```cpp
transaction_fee = storage_fees
Expand All @@ -60,94 +64,12 @@ transaction_fee = storage_fees

* `storage_fees` is the amount you pay for storing a smart contract in the blockchain. In fact, you pay for every second the smart contract is stored on the blockchain.
* _Example_: your TON Wallet is also a smart contract, and it pays a storage fee every time you receive or send a transaction. Read more about [how storage fees are calculated](/develop/smart-contracts/fees#storage-fee).
* `in_fwd_fees` is a charge for importing messages from outside the blockchain. Every time you make a transaction, it must be delivered to the validators who will process it.
* `in_fwd_fees` is a charge for importing messages only from outside the blockchain, e.g. `external` messages. Every time you make a transaction, it must be delivered to the validators who will process it. For ordinary messages from contract to contract this fee is not applicable. Read [the TON Blockchain paper](https://docs.ton.org/tblkch.pdf) to learn more about inbound messages.
* _Example_: each transaction you make with your wallet app (like Tonkeeper) requires first to be distributed among validation nodes.
* `computation_fees` is the amount you pay for executing code in the virtual machine. The larger the code, the more fees must be paid.
* _Example_: each time you send a transaction with your wallet (which is a smart contract), you execute the code of your wallet contract and pay for it.
* `action_fees` is a charge for sending outgoing messages made by a smart contract.
* `action_fees` is a charge for sending outgoing messages made by a smart contract, updating the smart contract code, updating the libraries, etc.
* `out_fwd_fees` stands for a charge for sending messages outside from TON Blockchain to interact with off-chain services (e.g., logs) and external blockchains.
* Not used because it's not implemented. So today is equal to 0.

## Storage fee

TON validators collect storage fees from smart contracts.

Storage fees are collected from the smart contract balance at the **Storage phase** of any transaction. Read more about phases and how TVM works [here](/learn/tvm-instructions/tvm-overview#transactions-and-phases).

It’s important to keep in mind that on TON you pay for both the execution of a smart contract and for the **used storage**:

```cpp
bytes * second
```

It means you have to pay a storage fee for having TON Wallet (even if it's very-very small).

If you have not used your TON Wallet for a significant period of time (1 year), _you will have to pay a significantly larger commission than usual because the wallet pays commission on sending and receiving transactions_.

### Formula

You can approximately calculate storage fees for smart contracts using this formula:


```cpp
storage_fee = (cells_count * cell_price + bits_count * bit_price)
/ 2^16 * time_delta
```

Let's examine each value more closely:

* `price`—price for storage for `time_delta` seconds
* `cells_count`—count of cells used by smart contract
* `bits_count`—count of bits used by smart contract
* `cell_price`—price of single cell
* `bit_price`—price of single bit

Both `cell_price` and `bit_price` could be obtained from Network Config [param 18](https://explorer.toncoin.org/config?workchain=-1&shard=8000000000000000&seqno=22185244&roothash=165D55B3CFFC4043BFC43F81C1A3F2C41B69B33D6615D46FBFD2036256756382&filehash=69C43394D872B02C334B75F59464B2848CD4E23031C03CA7F3B1F98E8A13EE05#configparam18).

Current values are:

* Workchain.
```cpp
bit_price_ps:1
cell_price_ps:500
```
* Masterchain.
```cpp
mc_bit_price_ps:1000
mc_cell_price_ps:500000
```

### Calculator Example

You can use this JS script to calculate storage price for 1 MB in the workchain for 1 year

```js live

// Welcome to LIVE editor!
// feel free to change any variables

function storageFeeCalculator() {

const size = 1024 * 1024 * 8 // 1MB in bits
const duration = 60 * 60 * 24 * 365 // 1 Year in secs

const bit_price_ps = 1
const cell_price_ps = 500

const pricePerSec = size * bit_price_ps +
+ Math.ceil(size / 1023) * cell_price_ps

let fee = (pricePerSec * duration / 2**16 * 10**-9)
let mb = (size / 1024 / 1024 / 8).toFixed(2)
let days = Math.floor(duration / (3600 * 24))

let str = `Storage Fee: ${fee} TON (${mb} MB for ${days} days)`

return str
}


```

## FAQ

Expand Down Expand Up @@ -175,5 +97,8 @@ Saving 1 MB of data for one year on TON will cost you 6.01 TON. Note that you do

## References

* ["Low-level fees overview"](/develop/howto/fees-low-level#fees-calculation-formulas)—read about the formulas for calculating commissions.
* *Based on the [@thedailyton article](https://telegra.ph/Commissions-on-TON-07-22) originally written by [menschee](https://github.com/menschee)*
* Based on the [@thedailyton article](https://telegra.ph/Commissions-on-TON-07-22) originally written by [menschee](https://github.com/menschee)*

## See Also

* ["Low-level fees overview"](/develop/howto/fees-low-level)—read about the formulas for calculating commissions.
2 changes: 1 addition & 1 deletion docs/develop/smart-contracts/tutorials/wallet.md
Original file line number Diff line number Diff line change
Expand Up @@ -2176,7 +2176,7 @@ Note that if a value is found, `f` is always equal to -1 (true). The `~ -1` oper

### Removing Expired Queries

Typically, [smart contracts on TON pay for their own storage](develop/smart-contracts/fees#storage-fee). This means that the amount of data smart contracts can store is limited to prevent high network transaction fees. To allow the system to be more efficient, transactions that are more than 64 seconds old are removed from the storage. This is conducted as follows:
Typically, [smart contracts on TON pay for their own storage](/develop/howto/fees-low-level#storage-fee). This means that the amount of data smart contracts can store is limited to prevent high network transaction fees. To allow the system to be more efficient, transactions that are more than 64 seconds old are removed from the storage. This is conducted as follows:

```func
bound -= (64 << 32); ;; clean up records that have expired more than 64 seconds ago
Expand Down
Loading