
Every activity costs 1/10 of a cent
Fees and resource metering
A governed schedule prices bytes, execution and storage, and your fee limit caps the charge.
Each activity costs 1/10 of a cent. Under that figure the kernel composes the fee from a base amount, a per-activity-type amount, and per-byte, per-execution-unit and per-storage-unit amounts, all scaled by a governed basis-point multiplier. You set a fee limit on every submission, and that limit is the most the activity can cost, even when it fails. The schedule version commits on chain, so a replay of the same batch prices it identically.
What it does
Every LayerX activity costs 1/10 of a cent. Under that headline figure the kernel composes the fee from a governed schedule: a base amount, a per-activity-type amount, a per-encoded-byte amount, a per-execution-unit amount and a per-storage-unit amount, all scaled by a basis-point multiplier. The schedule is resolved per epoch from governance parameters and committed on chain, so a replay of the same batch reprices it identically. A separate meter tracks execution units and net storage bytes against ceilings during execution and stops the activity when either ceiling is passed.
Key capabilities
- Composes each fee from base, activity-type, byte, execution and storage terms.
- Scales the composed total by a governed basis-point multiplier, rounding up.
- Prices asset and module activities from per-activity-type and per-module price tables.
- Stops execution at an execution-unit or net-storage-byte ceiling.
- Requires a fee limit up front and caps what a failed activity can be charged.
- Commits the schedule version on chain so replay reprices identically.
Who it's for
Agent developers who set a fee limit on every submission, and governance participants who set the schedule.
Why it matters
The cost of an activity is 1/10 of a cent, and the fee limit a developer sets is the most that activity can ever cost. Because the priced inputs are the encoded bytes, execution units and storage bytes of the activity itself, the price of a workload can be worked out before it is submitted rather than discovered afterwards.
Differentiators
The committed schedule is verified against the cached one on replay: lxp_fee_replay_schedule_verify re-encodes both and compares them in constant time, and it also checks the on-chain parameter-version record, so a divergent schedule fails rather than silently repricing (src/modules/governance/lxp_fee_params.c:123). Replay also reconciles the money: committed and replayed fee, actor debit, treasury credit, running treasury balance, state root and parameter version must all match, and total debits must equal total credits or the result is LXP_FATAL_SUPPLY_MISMATCH (src/protocol/lxp_fee_policy.c:79).
Outcomes
- Work out the price of a workload before you submit it
- Cap what any activity can cost with a fee limit
- Reprice a replayed batch identically from the committed schedule version
Technical notes
- Fee terms live in
lxp_fee_params:base_fee,per_activity_type_unit,per_encoded_byte,per_execution_unit,per_storage_unitandmultiplier_basis_points, all 128-bit except the multiplier (include/layerx/lxp_fee.h:32). The multiplier is applied with a round-up (lxp_u128_mul_bps_ceil). - Four schedule encodings exist. v1 is 86 bytes; v2 adds an asset price table of
LXP_ASSET_FEE_PRICE_COUNT = 10128-bit prices (87 + 16*10bytes); v3 adds 8 bytes for an eleventh asset price; v4 adds one count byte plusLXP_MODULE_FEE_PRICE_COUNT = 7module prices. Asset activities are priced by table entry (fee.asset.registerthroughfee.asset.burn, plusfee.asset.withdrawin v3) instead of by the per-activity-type term; v4 adds a per-module price for the escrow, budget, stream, service, perps, governance and bridge modules. - The schedule is resolved from the governance parameters
fee.base,fee.activity,fee.byte,fee.exec,fee.storage,fee.multiplier_bpsand the optionalfee.encoding(1-4), for a given batch epoch and cohort. All of them must resolve at the same parameter version, otherwise the resolution fails withLXP_FATAL_INVARIANT. The committed copy is stored under the governance keysfee.scheduleandfee.module-prices. - The meter (
lxp_meter_ctx) carriesexecution_ceiling,storage_ceiling, a storage rate and the fee limit. Execution units only rise; net storage bytes rise and fall with each delta. Passing a ceiling latchesexhaustedand returnsLXP_ERR_GAS_EXHAUSTED (-601); every meter entry point refuses a meter that is not markedsingle_writer_bound. - Admission requires a fee limit that is present and a canonical non-negative integer, and an actor balance at or above that limit, otherwise
LXP_ERR_MALFORMED_ENVELOPEorLXP_ERR_FEE_UNPAYABLE (-602). After execution, if the computed fee exceeds the limit the activity recordsLXP_ERR_FEE_LIMIT (-600), is charged exactly the limit, and its module effects are rolled back; the global and account sequence are still consumed. - The fee is moved as a single conserved transfer leg with reason
LXP_REASON_PROTOCOL_FEEfrom the actor's asset account to thesystem:feestreasury account, which must be of kindLX_ACCOUNT_SYSTEM_FEES(10) (src/protocol/lxp_fee.c:241). - Program calls are priced differently: a call into the programs module carries an exact fee from the program runtime instead of the composed terms, and its metering schedule version must be non-zero. That schedule (
lx_programs_metering_schedule) holds 9 coefficients, an activation batch and a genesis or governance authority, in a 122-byte record; the v1 coefficients are1, 1, 1, 1, 1, 8, 8, 64, 8over base, entity, load, store, call, branches kept, function locals, memory bytes and table elements per fuel. - Not yet wired: no code under
src/callslxp_meter_init. The kernel takes the metered counts (canonical_encoded_bytes,execution_units,storage_units) from its execution input (include/layerx/lxp_kernel.h:352), so the ceiling-enforcing meter context is currently driven by callers, the network gateway and tests rather than by the kernel's own activity path. - The congestion multiplier described in
spec/layerx-protocol/docs/economics.mdis not implemented. The only multiplier in the code is the governedmultiplier_basis_pointson the schedule, and none of the metering dimension weights named in that document exist ininclude/orsrc/.
import { WalletRpc } from "layerx-sdk";
const wallet = new WalletRpc("/opt/layerx/bin/layerx-wallet", configuration);
const receipt = await wallet.wallet.send(payload, {
actor,
idempotencyKey,
feeLimit: 2000000n,
notBefore,
notAfter,
commitment: "finalised",
timeoutMs: 30000,
});More in LayerX agent domain
Build on Paxeer.
Give your agent a wallet, set its policy, and settle your first call on LayerX.