SingularityDocs
Reference

Reference · Reference

Fees and limits

Budget for the transaction's executed work as well as its signed envelope. The default executor charges a signature component, consumed compute and an optional priority fee. RPC's getFeeForMessage reports only signature plus priority fees, so it is not a complete execution-cost quotation.

All values below describe inspected source defaults. Consensus-affecting configuration must agree across validators; endpoint and proxy limits can impose additional restrictions. Use availability to identify the build being queried.

For exact simulation and receipt fields, use RPC contracts. To investigate a saved transaction's actual fee and outcome, follow Inspect a transaction. CLI input units are specified separately for the public and Rust utilities in the CLI reference.

Units and fee calculation

One SING is 1,000,000,000 lamports. A compute-unit price instruction uses micro-lamports per CU, with one million micro-lamports per lamport. Bridged-token amounts use that token's smallest unit, not necessarily nine decimals.

For an ordinary transaction under default TurboConfig:

signature fee = signature count × 5,000 lamports
execution fee = consumed CU × 1 lamport/CU
priority fee  = ceil(billed CU limit × micro-lamports/CU ÷ 1,000,000)
total debit   = signature fee + execution fee + priority fee

The priority component charges the requested/billed limit, not actual consumption. Signature and consumed-compute rates are executor configuration values; the defaults are not a fiat price guarantee. Source: default fee rates, fee calculation and failure reconstruction.

A canonical one-signature System transfer accounts for 450 CU. With no priority price, its default charge is 5,450 lamports, or 0.00000545 SING. The public CLI uses this fixed number in its balance precheck.

For another example, an instruction consuming 120,000 CU with an explicit 300,000 CU limit and a price of 1,000 micro-lamports/CU has:

5,000 + 120,000 + ceil(300,000 × 1,000 / 1,000,000)
= 125,300 lamports

This is a source-derived calculation, not a measured transaction or fee reservation.

Registry-only housekeeping transactions are an exception in the current protocol-5 source: if every instruction targets the validator registry and at least one instruction exists, the transaction is fee-exempt. Adding a non-registry instruction, including compute-budget metadata, does not satisfy that exact predicate. Registration's associated account funding and mixed transactions still need funds.

What the fee RPC returns

getFeeForMessage takes a base64-encoded canonical message:

{"jsonrpc":"2.0","id":1,"method":"getFeeForMessage","params":["<base64 message>"]}

It validates message decoding and compute-budget instructions. If the recent blockhash is expired and there is no valid durable nonce, the result contains value: null. Otherwise it returns context.slot and a lamport value calculated as required signatures × 5,000 plus priority fee.

It does not execute the message to determine consumed CU. For the transfer above it can quote 5,000 while the default executor debits 5,450. It also does not apply the registry-only executor exemption. This makes the RPC useful for its specific signature/priority components, but unsuitable as a universally exact debit estimate. See the handler.

Use simulation and the actual receipt to understand execution cost, while remembering that simulation neither reserves state nor guarantees later inclusion.

Execution failures can still cost money

The ordinary failure path discards application writes, then reconstructs the fee debit from pre-transaction state. For a canonical executed EVM revert, its nonce change may also survive. A failure before any compute is consumed returns no reconstructed fee. If the payer cannot fund the fee, the executor does not mint an unbacked debit; execution/replay bookkeeping can still record that work occurred.

Consequently, “atomic transaction” means application-state changes do not partly publish. It does not mean every failed attempt is free, or that computation and nonce effects rewind. The transaction lifecycle explains the stages at which rejection and executed failure differ.

Compute budgets

SettingDefault or hard boundBehavior
Per-instruction execution default1,400,000 CUMultiplied by non-budget instruction count, then capped at transaction ceiling
Transaction execution ceiling1,400,000 CUSVM_MAX_COMPUTE_UNIT_LIMIT can change it, up to 48,000,000
Priority-fee default without explicit CU limit200,000 CU per non-budget instructionCapped; intentionally distinct from the wider execution allowance
Explicit CU limitUnsigned 32-bit requestClamped to configured ceiling; used for both execution allowance and priority billing
Default priority price0 micro-lamports/CUOptional unsigned 64-bit price
Block requested-compute budget250,000,000 CUMempool selection budgets requested limits, not observed execution
SBF heap32 KiB default, 256 KiB maximumRequest must be within range and a multiple of 1,024 bytes
Loaded account data64 MiB maximumZero request invalid; larger request capped

Thus one instruction with a price but no explicit limit can execute up to the default 1.4 million CU while its priority fee is based on 200,000 CU. With a price of 1 micro-lamport/CU, that priority component rounds up to one lamport.

A large CU request affects block packing even if the transaction later uses little compute. A transaction deferred for the remaining block budget can become eligible in a later block; requesting the maximum for every instruction is not costless to scheduling.

Compute-budget instructions must have no account operands, valid exact wire data, and no duplicate instruction of the same budget kind. The deprecated discriminator zero is rejected. See budget constants, billing and sanitization, and block selection.

The two compute-limit environment overrides are resolved once. Invalid, empty or zero values fall back with warnings; values above the hard bound are clamped. Changing them can change whether execution succeeds, so it requires a coherent validator configuration, not an independent per-node tuning experiment.

Wire, account and service bounds

BoundarySource default/boundPractical consequence
Submitted decoded transaction1 MiBSVM_MAX_TX_BYTES overrides, capped at 4 MiB; shared by public admission paths
Canonical instruction account indicesOne-byte indicesAt most 256 addressable account keys
Account data allocation10 MiB maximumA loader upload can require several transactions
HTTP request body2 MiBBase64 and JSON overhead also count; raising the decoded cap alone does not enlarge HTTP
HTTP headers32 KiBOversized or incomplete headers rejected/timed out
JSON-RPC batch256 items by defaultSVM_RPC_MAX_BATCH; zero falls back rather than making it unbounded
getMultipleAccounts100 accountsSplit larger reads
WebSocket subscriptions256 per connectionRejected beyond the per-connection bound
WebSocket connections8,192 defaultOperator-configurable; block subscriptions disabled by default
HUWM message payload4,096 bytesApplication payload, distinct from header and transaction envelope
Withdrawal minimum1,000 token base unitsNot 1,000 SING and not a universal minimum fiat value

A cap is the maximum that a layer may accept, not a promise that every lower-size object succeeds. The upstream JavaScript instruction serializer has its own buffer constraints; the SDK's larger transaction serializer cannot bypass every upstream instruction-size limit. Likewise, a 2 MiB HTTP body may be narrowed by a front proxy. Source: transaction limits, HTTP transport, RPC batching, WebSocket policy.

The WASM source's declared memory constant is not itself an installed Wasmtime memory limiter. Do not import it into an operational limit table as an enforced cap; the WASM chapter describes the active construction.

Account funding and bridge fees

The rent sysvar computes an exemption minimum from the account's data size plus a 128-byte overhead, using defaults of 3,480 lamports per byte-year and a two-year threshold. That formula gives 890,880 lamports for zero data and 1,586,880 for 100 bytes. It defines the helper's funding calculation, not evidence that every program charges recurring rent. Use the target loader/program's checks and getMinimumBalanceForRentExemption when preparing account creation. See rent calculation.

The bridge withdrawal helper charges five basis points:

total fee = floor(gross base units × 5 / 10,000)
net       = gross − total fee

For 1,000,000 token base units, net is 999,500 and the fee is 500. The helper divides that into relay and protocol portions; the withdrawal path currently consumes the net result while discarding those two split variables. Do not describe that accounting formula as proof that relayers and treasury accounts were actually paid. It also does not cover destination gas, exchange fees or another chain's protocol charges. See fee helper and withdrawal preparation.

The fee helper's “deposits are free” describes its bridge fee policy, not free foreign transactions or free local submission. For custody and settlement semantics, continue with asset bridging.

Validation scope and near-limit checks

Tests in the compute-budget module cover clamping, duplicate requests, priority rounding and the separate default billing limit. Mempool tests exercise requested-compute packing; RPC tests exercise expired-blockhash quotes and resource rejection. These source tests were inspected, not rebuilt for this documentation.

A good application acceptance check records requested CU, consumed CU, quoted components, actual receipt fee and error outcome for its representative transaction. It should test the relevant near-limit case, not assume that a successful small transfer validates an oversized upload or cross-VM workflow.

Updated Sep 8, 2026View source

On this page