diff --git a/foundations/fees.mdx b/foundations/fees.mdx
index 4b4179451..2272e8610 100644
--- a/foundations/fees.mdx
+++ b/foundations/fees.mdx
@@ -4,165 +4,110 @@ title: "Transaction fees"
import { Aside } from '/snippets/aside.jsx';
-## Transaction fees
+Fees in TON align with the [execution phases](/foundations/phases) of a transaction:
-Fees on TON are calculated using this formula:
+- Storage fees are charged in the [storage phase](/foundations/phases#storage-phase).
+- Compute fees are charged in the [compute phase](/foundations/phases#compute-phase).
+- Forward and action fees are charged in the [action](/foundations/phases#action-phase) and [bounce phases](/foundations/phases#bounce-phase).
+- Import fees apply at the start of smart contract execution, not a specific phase.
-```cpp title="FORMULAS"
-transaction_fee = storage_fees
- + in_fwd_fees // also called import fee
- + computation_fees
- + action_fees
- + out_fwd_fees
-```
-
-All fees are denominated in nanotons (often scaled by `2^16` for precision) and come from network configuration:
-
-- `storage_fees`: param [18](https://tonviewer.com/config#18)
-
-- `in_fwd_fees`: params [24](https://tonviewer.com/config#24) and [25](https://tonviewer.com/config#25)
-
-- `computation_fees`: params [20](https://tonviewer.com/config#20) and [21](https://tonviewer.com/config#21)
-
-- `action_fees`: params [24](https://tonviewer.com/config#24) and [25](https://tonviewer.com/config#25)
-
-- `out_fwd_fees`: params [24](https://tonviewer.com/config#24) and [25](https://tonviewer.com/config#25)
-
-- `storage_fees` is the amount you pay for storing a smart contract on 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.
-
-- `in_fwd_fees` is a charge for importing messages only from outside the blockchain, for example, `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 does not apply. Read [the TON Blockchain paper](/resources/pdfs/tblkch.pdf) to learn more about inbound messages.
- - _Example_: each transaction you make with your wallet app (like Tonkeeper) must first be distributed among validators.
-
-- `computation_fees` is the amount you pay for executing code in the virtual machine. Computation fees depend on executed operations (gas used), not code size.
- - _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, updating the smart contract code, updating libraries, etc.
+The total transaction fee is the sum of these components.
-- `out_fwd_fees` is a charge for forwarding outgoing internal messages within TON between shardchains; it depends on message size.
+Validators set fee levels through voting:
-## Storage fee
+- Storage fees are set in [config parameter 18](/foundations/config#param-18:-storage-prices).
+- Compute fees are set in [config parameters 20 and 21](/foundations/config#param-20-and-21:-gas-prices).
+- Forward, import, and action fees are set in [config parameters 24 and 25](/foundations/config#param-24-and-25:-message-price).
-Storage fee for smart contracts is calculated using the following formula, values are defined in network config param [`18`](https://tonviewer.com/config#18):
+## Storage fees
-```cpp title="FORMULAS"
-storage_fee = ceil(
- (account.bits * bit_price
- + account.cells * cell_price)
- * time_delta / 2^16)
+```cpp
+basic_price = (account.bits * bit_price +
+ account.cells * cell_price)
+storage_fee = ceil(basic_price * time_delta / 2^16)
```
-```ts title="TypeScript example"
-import { Cell, beginCell } from '@ton/core';
+The storage fee uses `account.bits` and `account.cells` from `AccountStorage`, excluding `ExtraCurrencyCollection` stored in the `other` field. The `other` field is replaced with a single `0` bit that represents an empty `HashmapE`.
-// Read latest storage prices (config param 18)
-const storage = getStoragePrices(configCell);
+```tlb
+extra_currencies$_ dict:(HashmapE 32 (VarUInteger 32))
+ = ExtraCurrencyCollection;
+currencies$_ grams:Grams other:ExtraCurrencyCollection
+ = CurrencyCollection;
-// Account state as a Cell (e.g., code+data root)
-const accountRoot: Cell = /* load from blockchain */;
-const stats = collectCellStats(accountRoot, []);
-
-// Charge for one hour
-const fee = shr16ceil(
- (stats.bits * storage.bit_price_ps + stats.cells * storage.cell_price_ps) *
- 3600n
-);
+account_storage$_ last_trans_lt:uint64
+ balance:CurrencyCollection state:AccountState
+ = AccountStorage;
```
-> See [Helper functions appendix](/foundations/fees#helper-functions) for full implementations.
-
-## Gas fee
+## Compute fees
-All computation is measured in gas units; each TVM operation has a fixed gas cost.\
-The gas price is defined by network configuration and **can not be set by users**.
+All computation is measured in gas units. A TVM operation typically has a fixed gas cost, but that is [not always the case](/tvm/gas). Network configuration defines gas prices; users cannot override them.
-- Basechain: 1 gas = `26214400 / 2^16` nanotons = 0.0000004 TON
-- Masterchain: 1 gas = `655360000 / 2^16` nanotons = 0.00001 TON
+### Flat gas limit
-See config parameters [`20`](https://tonviewer.com/config#20) and [`21`](https://tonviewer.com/config#21) for current gas prices.\
-The values can change through validator governance.
+A contract invocation pays for at least `flat_gas_limit` gas units. Spending up to that limit costs `flat_gas_price` TON. If the contract spends `gasUsed` gas units, the fee is:
-```ts title="TypeScript example"
+```ts
const gasUsed = 50_000n;
-const prices = getGasPrices(configCell, 0); // 0 = basechain
+// 0 = basechain, -1 = masterchain
+const prices = getGasPrices(configCell, 0);
const gasFee =
- gasUsed <= prices.flat_gas_limit
+ gasUsed <= prices.flat_gas_limit
? prices.flat_gas_price
: prices.flat_gas_price +
- (prices.gas_price * (gasUsed - prices.flat_gas_limit)) / 65536n;
+ (prices.gas_price * (gasUsed - prices.flat_gas_limit)) / 65536n;
```
-> See [Helper functions appendix](/foundations/fees#helper-functions) for full implementations.
-
## Forward fee
-Forward fee for message size (`msg.bits`, `msg.cells`) per params [`24`](https://tonviewer.com/config#24)/[`25`](https://tonviewer.com/config#25):
-
-```cpp title="FORMULAS"
-// bits in the root cell of a message are not included in msg.bits (lump_price pays for them)
-msg_fwd_fees = (lump_price
- + ceil(
- (bit_price * msg.bits + cell_price * msg.cells) / 2^16)
- );
+Forward fee is calculated with this formula:
```
+bodyFwdFee = priceForCells * (msgSizeInCells - 1)
+ + priceForBits * (msgSizeInBits - bitsInRoot)
-```ts title="TypeScript example"
-const msgPrices = getMsgPrices(configCell, 0);
-const total =
- msgPrices.lumpPrice +
- shr16ceil(
- msgPrices.bitPrice * BigInt(bits) +
- msgPrices.cellPrice * BigInt(cells)
- );
-const actionFee = (total * msgPrices.firstFrac) >> 16n;
-const forwardFee = total - actionFee;
-
-// From a Cell or Message:
-const fwdFromCell = computeCellForwardFees(msgPrices, messageRootCell);
-// For a full internal Message object (validates default lump case, handles init):
-const details = computeMessageForwardFees(msgPrices, internalMessage);
+fwdFee = lumpPrice + ceil(bodyFwdFee / 2^16)
```
-
+where:
-### Import fee
+- `lumpPrice` is the fixed value [from config](/foundations/config#param-24-and-25%3A-message-price) paid once for the message.
+- `msgSizeInCells` is the number of cells in the message.
+- `msgSizeInBits` is the number of bits in all the cells of the message.
+- `bitsInRoot` is the number of bits in the root cell of the message.
-Import fee is the same as forward fee for inbound external messages.
+The formula excludes the message root cell because it mainly contains headers. `lumpPrice` covers that root cell.
-## Action fee
+### Action fee
-Action fee is charged in the Action phase and is the sender’s share of the forward fee.\
-You pay it for `SENDRAWMSG`; actions like `RAWRESERVE`, `SETCODE` do not incur the fees.
+Action fee is the portion of `fwdFee` granted to the validator of the message's source [shard](/foundations/shards#blockchain-sharding). The remaining `fwdFee - actionFee` amount goes to the validator of the destination shard.
-```cpp title="FORMULAS"
-action_fee = floor((msg_fwd_fees * first_frac)/ 2^16); // internal
+Action fee exists only for [internal messages](/foundations/messages/internal#internal-messages).
-action_fee = msg_fwd_fees; // external
+```cpp
+action_fee = floor(fwd_fee * first_frac / 2^16)
```
-`first_frac` (params [`24`](https://tonviewer.com/config#24)/[`25`](https://tonviewer.com/config#25)) divided by `2^16` ≈ 1/3 of `msg_fwd_fees`.
-
-Action fine (failed send): Starting with Global Version 4, a failed "send message" action incurs a penalty proportional to the attempted message size. It is calculated as:
+Starting with Global Version 4, a failed [SENDMSG action](/foundations/actions/send#send-message) incurs a penalty proportional to the attempted message size. It is calculated as:
-```cpp title="FORMULAS"
+```cpp
fine_per_cell = floor((cell_price >> 16) / 4)
max_cells = floor(remaining_balance / fine_per_cell)
action_fine = fine_per_cell * min(max_cells, cells_in_msg);
```
+## Import fee
+
+Import fee mirrors forward fee for inbound external messages. The root cell and its contents are covered by `lumpPrice` in the same way as internal messages.
+
## Helper functions (full code)
```ts expandable