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_feeDiscounts 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:
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).
Which transactions accrue usage
Ordinary transactions you sign and send
Yes
Yes
Transactions that revert or run out of gas
Yes - you paid for the gas
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
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.
Concretely:
Transaction admission is undiscounted. A transaction whose
gasPriceis below the current base fee is rejected from the mempool, whatever your discount. Keep quotingeth_gasPrice(or your wallet's estimate) as normal.Balance requirements are undiscounted while pending. The node reserves
gasPrice * gasat 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
effectiveGasPriceon 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.
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).
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:
The useful read-only views are:
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:
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
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 - how Somnia's gas costs per operation differ from Ethereum's
SOMI coin - denominations and the native gas currency
Last updated