> For the complete documentation index, see [llms.txt](https://docs.somnia.network/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.somnia.network/developer/deployment-and-production/sustained-use-gas-discounts.md).

# Sustained Use Gas Discounts

Somnia automatically reduces the base gas price paid by accounts that consistently consume a lot of gas. The more gas you use over a sustained period, the less you pay for each unit of gas.

There is nothing to opt into, claim, stake or sign. Discounts are computed by the network from observed gas usage and applied automatically when your transactions execute.

## How the discount is applied

A discount is a percentage off the **base gas price only**. Any priority fee you pay is added on top, undiscounted:

```
price charged per gas = base_gas_price * (100 - discount_percent) / 100  +  priority_fee
```

Discounts never reach 100% - gas is never free.

The discount changes the **price** you pay per unit of gas. It never changes how many units of gas an operation costs, and it does not raise any gas limit.

## How usage is measured

Usage is tracked per **sender address** - the `from` of the transaction, which is the account that pays. Gas consumed by contracts you call counts toward your usage, not theirs.

Somnia divides time into **epochs**. On mainnet and testnet an epoch is 3000 ledger blocks, which is roughly **5 minutes** of wall-clock time.

* **Every epoch, the gas used by each account is tracked.** An account is only recorded for that epoch if it consumed more than ten million gas units in that epoch, and only the 1000 heaviest gas consumers of the epoch are recorded.
* **Your discount is derived from your total tracked gas across the most recent 16 epochs** - a rolling window of roughly **80 minutes**. As each epoch passes, the oldest epoch's usage drops out of the window.
* That rolling total is compared against a table of tiers. Each tier names a total amount of gas and the discount earned by reaching it; you get the discount of the highest tier your rolling total reaches. Below the lowest tier, your discount is zero.

A newly earned discount applies to every transaction you send from the **start of the next epoch**, so it takes effect at the next 5-minute boundary and reflects roughly your last 80 minutes of activity.

### Current tiers

The tier table on mainnet:

| Gas units used over the rolling window | Discount |
| -------------------------------------- | -------- |
| 900,000,000                            | 70%      |
| 4,000,000,000                          | 90%      |

At a base gas price of 6 gwei, sustaining those rates costs roughly **100 SOMI** and **430 SOMI** per day on gas at the undiscounted price.

Tiers are network configuration and may be retuned over time; the authoritative table is always the live one returned by `getTiers()` (see [Reading discounts on chain](#reading-discounts-on-chain)).

### Which transactions accrue usage

| Transaction type                                          | Accrues usage                       | Receives a discount |
| --------------------------------------------------------- | ----------------------------------- | ------------------- |
| Ordinary transactions you sign and send                   | Yes                                 | Yes                 |
| Transactions that revert or run out of gas                | Yes - you paid for the gas          | Yes                 |
| [Reactivity](/developer/reactivity.md) handler executions | Yes, to the subscription owner      | Yes                 |
| Reactivity subscription deactivations                     | No - they consume no chargeable gas | n/a                 |
| Protocol-level and zero-gas transactions                  | No                                  | No                  |

Because a Reactivity subscription owner may be a contract, contract accounts can accrue usage and earn discounts for the handler executions they pay for.

## Keeping and losing a discount

Your discount is derived from a rolling window, not from a single epoch, so it is stable across quiet periods. If you stop transacting entirely, your usage ages out gradually and your discount only reaches zero after the full window - 16 epochs, roughly 80 minutes - has passed with no activity.

There is no penalty for bursty traffic. Usage accumulates into the window whenever you are busy, and a spike is credited in full.

## What this means for sending transactions

{% hint style="warning" %}
**You must still submit a `gasPrice` at or above the full, undiscounted base fee.** The discount is applied when your transaction executes, not when it is accepted.
{% endhint %}

Concretely:

* **Transaction admission is undiscounted.** A transaction whose `gasPrice` is below the current base fee is rejected from the mempool, whatever your discount. Keep quoting `eth_gasPrice` (or your wallet's estimate) as normal.
* **Balance requirements are undiscounted while pending.** The node reserves `gasPrice * gas` at the full price for in-flight transactions, so you need to be able to cover the undiscounted cost even though you will be charged less.
* **You are charged the discounted price.** The saving shows up as a smaller balance deduction, and in `effectiveGasPrice` on the receipt.

The practical upshot for a dApp is that no change to your submission logic is needed. Fee estimation, `gasPrice` selection and balance checks all continue to work against the undiscounted base fee; your users simply pay less.

## RPC behaviour

No new RPC methods or response fields are involved. Existing fields reflect the discount where - and only where - they describe an actual charge.

| Method / field                                                                     | Reflects the sender's discount?                                                                                            |
| ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `effectiveGasPrice` on a transaction receipt                                       | **Yes** - the price actually charged. This is the authoritative record.                                                    |
| `gasPrice` on `eth_getTransactionByHash` / `...ByBlock...`                         | **Yes** - note this reports the price *charged*, which for a discounted sender is lower than the `gasPrice` you submitted. |
| `debug_traceTransaction`, `debug_traceBlockByHash`, `debug_traceBlockByNumber`     | **Yes** - replayed with exactly the discount that was charged at the time.                                                 |
| `eth_call`, `eth_estimateGas`, `eth_createAccessList` against `latest` / `pending` | **Yes** - simulated with the `from` account's current discount.                                                            |
| `eth_call` or `debug_traceCall` pinned to a **past** block                         | **No** - historical simulations deliberately run undiscounted.                                                             |
| `eth_gasPrice`                                                                     | **No** - the request has no sender, so it returns the network base price.                                                  |
| `eth_feeHistory`, `block.baseFeePerGas`                                            | **No** - these describe blocks, not senders.                                                                               |
| `eth_maxPriorityFeePerGas`                                                         | Unchanged (priority fees are never discounted).                                                                            |

{% hint style="info" %}
Because receipts record the discount that was applied, a transaction's `effectiveGasPrice` is reproducible forever, even after the sender's discount has changed or expired.
{% endhint %}

## Reading discounts on chain

Discounts live in the enshrined `GasDiscounts` contract, at a per-network address. The contract is a UUPS proxy, so the address is stable across upgrades.

Look the address up for the network you are on, rather than hardcoding it, using the `somnia_getProtocolParameters` method:

```bash
cast rpc somnia_getProtocolParameters '["latest"]' \
  --rpc-url https://api.infra.testnet.somnia.network \
  | jq -r '.protocol_parameters.gas_discounts_contract_address'
```

The useful read-only views are:

| View                                                                                                                                            | Returns                                                                                                                                                                                               |
| ----------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `getTiers() → (uint256 gasThreshold, uint256 discountBps)[]`                                                                                    | The live tier table. `gasThreshold` is gas used **over the whole rolling window**; thresholds are inclusive, and the highest one you reach applies.                                                   |
| `getAccountsWithDiscountsForEpoch() → (address[] accounts, uint256[] discountBps, uint256 hotAccountGasThreshold, uint256 maxReportedAccounts)` | The discount set active for the current epoch - only accounts earning a non-zero discount, in ascending address order - plus the per-epoch minimum gas and the number of accounts recorded per epoch. |
| `getTrackedAccounts() → (address[] accounts, uint256[] discountBps, uint256[] rollingGasUsed)`                                                  | Every account with a live usage window, including those not yet earning a discount, with each window's total.                                                                                         |
| `lastReportedEpoch() → uint256`                                                                                                                 | The epoch of the most recent update.                                                                                                                                                                  |

Discount values in these responses are in basis points, where `10000` is 100% - so a 70% discount reads as `7000`.

For example, to fetch the tier table and the current discount set:

```bash
PROXY=$(cast rpc somnia_getProtocolParameters '["latest"]' \
  --rpc-url $RPC | jq -r '.protocol_parameters.gas_discounts_contract_address')

cast call $PROXY "getTiers()((uint256,uint256)[])" --rpc-url $RPC
cast call $PROXY "getAccountsWithDiscountsForEpoch()(address[],uint256[],uint256,uint256)" --rpc-url $RPC
```

{% hint style="info" %}
There is deliberately no per-account lookup function. To find your own discount, read the full set and filter client-side; both arrays are sorted ascending by address, so a binary search is possible. `rollingGasUsed` from `getTrackedAccounts()` is each window's total **as of the last update**, not aged forward to the current epoch.
{% endhint %}

The simplest way to confirm a discount is being applied to real transactions is to compare `effectiveGasPrice` on one of your receipts against the block's base gas price.

### Events

| Event                                                                                                                     | Emitted                                                                                                                      |
| ------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `DiscountSetComputed(uint256 indexed epochReceivingDiscounts, uint256 indexed setCounter, uint256 numDiscountedAccounts)` | Once per epoch, naming the epoch the new discount set applies to.                                                            |
| `HotAccountsReported(uint256 indexed epoch, address[] accounts, uint256[] gasUsedInEpoch)`                                | Once per epoch, with that epoch's tracked usage. Addresses are in the payload, not indexed, so you cannot filter by address. |
| `TiersUpdated(Tier[] newTiers)`                                                                                           | When the tier table changes.                                                                                                 |
| `ReportingParametersUpdated(uint256 hotAccountGasThreshold, uint256 maxReportedAccounts)`                                 | When the per-epoch minimum gas or the number of accounts recorded per epoch changes.                                         |

Indexing `DiscountSetComputed` and `TiersUpdated` is the cheapest way to keep a dashboard in sync without polling the full set every epoch.

## See also

* [Somnia Gas Differences To Ethereum](/developer/deployment-and-production/somnia-gas-differences-to-ethereum.md) - how Somnia's gas costs per operation differ from Ethereum's
* [SOMI coin](/developer/network-info/somi-coin.md) - denominations and the native gas currency


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.somnia.network/developer/deployment-and-production/sustained-use-gas-discounts.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
