FeeLimit & Energy cost

How fee_limit caps your TRX exposure for smart contract transactions, how it relates to the deployer-side origin_energy_limit, and three practical strategies for sizing it before every deploy or call.

📘

Prerequisites

When you deploy or call a smart contract on TRON, you set a parameter called fee_limit. Setting it wrong is one of the most common ways to lose TRX or have a transaction fail. This page explains what fee_limit actually does, how it differs from origin_energy_limit (a related but different parameter set by the contract deployer), and how to size fee_limit for your transaction before broadcasting.

What fee_limit actually does

fee_limit is a single number you attach to a smart contract transaction. The most useful way to think about it:

fee_limit caps the Energy budget that the caller can cover for this transaction, expressed in sun.

maxCallerEnergyFromFeeLimit = fee_limit / EnergyPrice

The network compares the Energy derived from fee_limit with the Energy the caller can actually provide through staking and their TRX balance, then uses the smaller value as the maximum the caller can cover for the transaction. If execution has not completed when the caller's required Energy reaches that limit, the transaction fails with OUT_OF_ENERGY. A low fee_limit can therefore cause failure even when the caller has ample staked Energy; conversely, insufficient staked Energy and TRX balance can cause failure even when fee_limit is high enough. In either case, the TRX burned for the call's Energy consumption will not exceed fee_limit. Thus, fee_limit plays two roles:

  • A safety cap against runaway Energy caused by buggy code or an attack
  • A per-transaction Energy budget, denominated in TRX so developers can control costs without working directly in chain-internal units

Three things to remember

  • It is set in sun — not TRX. 1 TRX = 1,000,000 sun.
  • The maximum allowed value is currently 15,000 TRX on Mainnet (15 × 10⁹ sun) — but this is a chain parameter (getMaxFeeLimit, parameter #47). Setting fee_limit higher than the current getMaxFeeLimit returns an error.
  • fee_limit always applies, regardless of how much Energy you have staked. The VM determines the caller's usable Energy by taking the minimum of two values:
    callerEnergyLimit = min(callerStakedEnergy + (balance − callValue) / sunPerEnergy, fee_limit / sunPerEnergy)
    The first term is what the caller can cover from staked Energy plus TRX burn; the second term is the fee_limit converted to an Energy ceiling. The min() means that even with ample staked Energy, a low fee_limit can still cap the total and trigger OUT_OF_ENERGY. This dual-bound protects against runaway-Energy consumption (a buggy loop or attack), not just TRX-burn exposure. See the full execution chain under "How fee_limit is enforced under the hood" below.
📘

EnergyPrice is also a chain parameter

EnergyPrice (the conversion rate from Energy to sun) is governed by the chain parameter getEnergyFee. The current value is 100 sun per Energy (0.0001 TRX). All examples on this page assume the default — query getEnergyFee for the current value when sizing fee_limit for production.

fee_limit (caller side) vs origin_energy_limit (deployer side)

TRON's contract Energy model has two independent ceilings on how much Energy a single call can consume. They look similar at first glance, but they live at completely different layers of the system — one is a property of the contract, the other is a property of each individual transaction. Understanding this scope difference is the fastest way to stop confusing them.

Dimensionfee_limitorigin_energy_limit
Belongs toTransactionContract
Set byCaller (per transaction)Deployer (at deploy or via update)
Unitsun (10⁻⁶ TRX)Energy (unitless)
Maximum valueCurrently 15,000 TRX on Mainnet (chain parameter, can change)No hard cap in the actuator — only > 0 is enforced (UpdateEnergyLimitContractActuator.java). 10,000,000 is the default, not a ceiling
Default if not set0 (the caller can cover 0 Energy; the transaction fails if the deployer cannot cover the full execution)10,000,000 Energy
How to updateJust set a new value on the next transactionSubmit an UpdateEnergyLimitContract system transaction; once mined, every subsequent call to that contract reads the new value
Update frequency in practiceHigh — every transaction, often re-estimated based on call complexityLow — only when the deployer adjusts operational policy
Risk it limitsPer-transaction Energy ceiling on the caller's sidePer-call Energy ceiling on the deployer's side
Mental model"How much energy I'm carrying for this transaction""My contract's reimbursement policy"

The two parameters are independent, but both participate in the Energy-limit calculation for every call. An insufficient origin_energy_limit only reduces the deployer's available subsidy; the caller may cover the remainder. The transaction fails with OUT_OF_ENERGY only when the combined Energy that the caller and deployer can cover is still insufficient.

Why scope matters

The single most common source of confusion is treating these as two flavors of the same parameter. They are not.

origin_energy_limit is contract metadata. It is set once when the deployer publishes the contract, sits in the on-chain SmartContract record, and is read by every node executing any call to that contract. When the deployer wants to change it, they broadcast an UpdateEnergyLimitContract system transaction; from the next block onward, every caller's transaction loads the new value automatically. Callers do not see this happening — the limit just changes underneath them.

fee_limit is a per-transaction instruction. It travels in the raw_data of each Transaction message and exists only while that specific transaction is being executed. The VM reads it once at the start of execution, converts it to an Energy ceiling (fee_limit / EnergyPrice), and uses that ceiling to cap how much Energy this call can consume. When the call completes, the value is discarded. The contract never records it; the next caller starts with their own fresh fee_limit.

This difference shapes how you think about each:

  • If you are building a DApp and want to make calls cheap for users, you tune origin_energy_limit and consume_user_resource_percent once at the contract level — these decisions affect everyone using your contract.
  • If you are calling a contract and want to bound your own spend, you tune fee_limit per call — your decision affects only your transaction.

consume_user_resource_percent — the bridge between them

A third field, consume_user_resource_percent, sits at the contract level and decides how the call's Energy gets split between caller and deployer. It is an integer between 0 and 100:

  • 100 → caller pays for all Energy. The deployer contributes nothing. This is what most popular contracts set, because subsidizing every call would drain the deployer's account.
  • 60 → caller pays 60%, deployer pays 40%.
  • 0 → deployer pays for everything. Useful for DApps that subsidize users, but exposes the deployer to drain attacks if origin_energy_limit is not set carefully.

Like origin_energy_limit, consume_user_resource_percent is also mutable post-deploy through wallet/updatesetting.

How a single call settles both ceilings

When a transaction needs X Energy total, the protocol splits the cost between deployer and caller:

Deployer's Actual Payment = min(
    X × (100 - consume_user_resource_percent) / 100   # theoretical share
    origin_energy_limit                               # deployer's per-call cap
    deployer_available_Energy                         # what's actually in deployer's account
)

Caller's Actual Payment = X − Deployer's Actual Payment

The caller then pays their share from their Energy first, and falls back to burning TRX (capped by fee_limit) for any shortfall.

The maximum Energy the caller can cover is the smaller of fee_limit / EnergyPrice and the sum of the caller's available staked Energy plus the Energy that can be purchased with the available TRX balance. If the caller's required share exceeds that limit, execution fails with OUT_OF_ENERGY.

📘

In one sentence

fee_limit protects the caller from runaway Energy consumption (and the resulting TRX burn) on this transaction. origin_energy_limit protects the deployer from drain attacks across all calls to the contract. They are not substitutes — both apply to every call.

A worked example

Suppose:

  • A contract call requires X = 80 Energy total
  • consume_user_resource_percent = 60 → caller's theoretical share is 60%, deployer's is 40%
  • Deployer set origin_energy_limit = 40 Energy at deploy time
  • Deployer's account currently has 10 Energy available
  • Caller has 0 staked Energy and sets fee_limit = 1,000,000 sun (1 TRX, equivalent to 10,000 Energy at the chain default of 100 sun/Energy)

Walking through the formula:

Deployer's Actual Payment = min(
    80 × 40% = 32 Energy        # theoretical share
    40 Energy                   # origin_energy_limit
    10 Energy                   # available
) = 10 Energy

The deployer covers only 10 Energy because their account is depleted. The caller covers the remaining 70 Energy.

Caller's Actual Payment = 80 − 10 = 70 Energy

The caller has 0 staked Energy, so all 70 Energy must come from burning TRX:

TRX burned from caller = 70 × 100 sun = 7,000 sun

Caller's fee_limit = 1,000,000 sun is well above 7,000 sun, so the transaction succeeds. The 7,000 sun are deducted from the caller's TRX balance; the remaining 993,000 sun of fee_limit are not charged — fee_limit is a cap, not a payment.

🚧

The TRX burn is unrefundable

Energy consumed (whether from stake or burn) is never refunded, even if the transaction reverts later or fails on a different check. Always estimate before broadcasting on Mainnet.

How fee_limit is enforced under the hood

Most developers don't need to read this section — it is enough to know that fee_limit caps the maximum Energy cost the caller is willing to cover for this transaction. Understanding the enforcement chain also helps explain transaction timeouts and creator/caller settlements.

The full chain in java-tron's VMActuator:

  1. Range check. Before anything else, the node validates 0 ≤ fee_limit ≤ MaxFeeLimit (chain parameter getMaxFeeLimit). If your fee_limit exceeds the current chain limit, you get a ContractValidateException immediately — no Energy is consumed because the transaction never reaches the VM.

  2. Convert fee_limit to an Energy ceiling. energyFromFeeLimit = fee_limit / sunPerEnergy, where sunPerEnergy = DynamicPropertiesStore.getEnergyFee(). This is the maximum Energy cost the caller is willing to cover, and it participates in the budget calculation for both staked Energy and Energy paid for by burning TRX.

  3. Compute the caller's total Energy budget. callerEnergyLimit = min(callerStakedEnergy + (balance - callValue) / sunPerEnergy, energyFromFeeLimit). The caller can spend up to this much Energy on their share of the call.

  4. Add the deployer's contribution (if any). If consume_user_resource_percent < 100, the protocol then adds deployerEnergyLimit = min(theoretical share, origin_energy_limit, deployer's available Energy). The deployer's part is not bounded by the caller's fee_limit — that's a consume_user_resource_percent + origin_energy_limit decision, not a caller decision.

  5. Inject the total into the VM. The VM starts execution with totalEnergyLimit = callerEnergyLimit + deployerEnergyLimit. Each opcode deducts its Energy cost. When the counter hits zero, the VM throws OutOfEnergyException and execution halts.

  6. Settle in TRX. After execution, payEnergyBill deducts the actually-consumed Energy: from staked Energy first (no TRX burned), then from the TRX balance at sunPerEnergy per Energy unit (capped by what fee_limit allows).

The math always works out to actualTRXBurned ≤ fee_limit, because step 2 made it impossible to consume more Energy than fee_limit / sunPerEnergy in the first place.

Side effects worth knowing

  • Constant calls do not require a transaction-level fee_limit. triggerconstantcontract executes locally, creates no on-chain transaction, and consumes no actual account resources. The simulation is still subject to node configuration and protective TVM execution limits; inspect the returned result and error message when it fails.
  • OUT_OF_TIME exhausts the Energy budget for the execution. When a contract exceeds the per-transaction CPU time limit, the TVM accounts for Energy up to the limit calculated before execution: both the Energy actually used before the timeout and the unused remainder are recorded as consumed. OUT_OF_ENERGY also exhausts this Energy allowance after failure, but it has a different trigger: the remaining Energy is insufficient for the next operation, whereas OUT_OF_TIME means execution exceeded the CPU time limit. Expensive logic such as an unbounded loop over a large array increases the timeout risk. See VM exception handling.

The relevant source file is actuator/VMActuator.java, specifically getAccountEnergyLimitWithFixRatio (caller side) and getTotalEnergyLimitWithFixRatio (creator + caller combined).

How to size fee_limit: three strategies

There is no universal "right" fee_limit. The choice trades off precision against complexity. Below are the three strategies developers use in practice, ordered from simplest to most precise.

Strategy 1 — Use max_factor (recommended default)

max_factor is the upper bound of the Dynamic Energy Model (DEM) penalty factor and is controlled by chain parameter #75 getDynamicEnergyMaxFactor. The API returns the actual penalty factor multiplied by 10,000 as an integer. Mainnet currently returns 34,000; dividing it by 10,000 gives max_factor = 3.4. This means the dynamic penalty can add up to 3.4 times the base Energy, producing a maximum total Energy multiplier of 4.4. Estimate fee_limit from max_factor as follows:

fee_limit = floor(base_energy_estimate × (1 + max_factor)) × EnergyPrice

EnergyPrice is the price in sun per unit of Energy, so the resulting fee_limit is also denominated in sun.

Pros: simple and does not require querying each contract's current energy_factor; when the base estimate and chain parameters remain valid, it reduces failures caused by Dynamic Energy penalties.
Cons: typically over-budgets, and the account must be able to cover the higher cap. Normal execution and revert settle according to protocol-defined Energy consumption, but exceptional failures such as OUT_OF_TIME or illegal instructions may charge the maximum Energy allowed for the transaction.

This formula covers only the Dynamic Energy factor upper bound. It does not account for execution branches, state changes, call parameters, account balances, or later chain-parameter changes, so it is a conservative budget rather than a success guarantee.

Strategy 2 — Track each contract's energy_factor per maintenance cycle

If you call the same contract repeatedly and want a tighter fee_limit, query the contract's current energy_factor once per maintenance cycle (every 6 hours). The API also returns this value as an integer scaled by 10,000; divide it by 10,000 to obtain contract_energy_factor before using the formula:

fee_limit = floor(base_energy_estimate × (1 + contract_energy_factor)) × EnergyPrice

The normalized contract_energy_factor is specific to each contract and reflects how heavily that contract is used. It is always between 0 and max_factor. Read the raw energy_factor from wallet/getcontractinfo:

BASE_URL=https://api.trongrid.io   # example — replace with any TRON node (TronGrid, third-party, or self-hosted)
curl -X POST ${BASE_URL}/wallet/getcontractinfo \
  -d '{"value":"TG3XXyExBkPp9nzdajDZsozEu4BkaSJozs","visible":true}'

Pros: usually tighter than Strategy 1 and reflects the contract's Dynamic Energy factor at query time.
Cons: requires periodic refreshes. Even within the same maintenance cycle, contract state, call parameters, and account resources can make an earlier estimate unsuitable.

Strategy 3 — Estimate Energy before every call

A more timely — and more complex — strategy is to call wallet/estimateenergy (or triggerconstantcontract as fallback) before broadcasting and set:

fee_limit = estimated_total_energy × EnergyPrice

Pros: reflects the contract state and Dynamic Energy factor observed by the estimation node at request time, and is usually closer to the eventual execution cost than a cached value.
Cons: adds a node round-trip before every transaction. State changes, maintenance-cycle transitions, node-state differences, or a different execution branch can still create estimation error, so keep a reasonable buffer and handle retries.

Picking a strategy

Your situationUse
Most use cases — wallets, occasional calls, deploysStrategy 1 (max_factor)
High-volume calls to a known, popular contractStrategy 2 (energy_factor)
Maximum precision required (cost-sensitive workloads, exchanges)Strategy 3 (estimate before every call)

Estimating Energy before broadcasting

Both Strategies 2 and 3 require a base Energy estimate. There are two APIs.

wallet/triggerconstantcontract — works everywhere

This is the universal estimation API. It simulates the transaction on the local node without touching the chain, and returns the Energy that would have been consumed in the energy_used field. It works for both contract calls and contract deployments.

For a contract call:

BASE_URL=https://api.trongrid.io   # example — replace with any TRON node (TronGrid, third-party, or self-hosted)
curl -X POST ${BASE_URL}/wallet/triggerconstantcontract \
  -d '{
    "owner_address": "TTGhREx2pDSxFX555NWz1YwGpiBVPvQA7e",
    "contract_address": "TVSvjZdyDSNocHm7dP3jvCmMNsCnMTPa5W",
    "function_selector": "transfer(address,uint256)",
    "parameter": "0000000000000000000000002ce5...0000038d7ea4c68000",
    "visible": true
  }'

For a contract deployment, pass the contract bytecode(the output of contract compiling) in the data field. See HTTP API — triggerconstantcontract.

BASE_URL=https://api.shasta.trongrid.io   # example — replace with any TRON node (TronGrid, third-party, or self-hosted)
curl --request POST \
 --url ${BASE_URL}/wallet/triggerconstantcontract \
 --header 'accept: application/json' \
 --header 'content-type: application/json' \
 --data '
{
  "owner_address": "TZ4UXDV5ZhNW7fb2AMSbgfAEZ7hWsnYS2g",
  "data":"608060405234801561000f575f80fd5b50d3801561001b575f80fd5b50d28015610027575f80fd5b5061015b806100355f395ff3fe608060405234801561000f575f80fd5b50d3801561001b575f80fd5b50d28015610027575f80fd5b506004361061004c575f3560e01c806360fe47b1146100505780636d4ce63c1461006c575b5f80fd5b61006a600480360381019061006591906100d2565b61008a565b005b610074610093565b604051610081919061010c565b60405180910390f35b805f8190555050565b5f8054905090565b5f80fd5b5f819050919050565b6100b18161009f565b81146100bb575f80fd5b50565b5f813590506100cc816100a8565b92915050565b5f602082840312156100e7576100e661009b565b5b5f6100f4848285016100be565b91505092915050565b6101068161009f565b82525050565b5f60208201905061011f5f8301846100fd565b9291505056fea26474726f6e58221220ca11b5749b47f126a08ed4dd6de453cf3e3e1d68c1105af0acdd8a38c18b37ac64736f6c63430008140033",
  "visible": true
}'

The response includes energy_used (total Energy required) and energy_penalty (the DEM penalty portion). Subtract energy_penalty from energy_used if you want only the base Energy.

wallet/estimateenergy — more accurate but optional

wallet/estimateenergy was introduced in java-tron 4.7.0.1 to give better estimates for a small number of edge-case contracts. It has the same interface as triggerconstantcontract but the response field is energy_required instead of energy_used.

BASE_URL=https://api.trongrid.io   # example — replace with any TRON node (TronGrid, third-party, or self-hosted)
curl -X POST ${BASE_URL}/wallet/estimateenergy \
  -d '{
    "owner_address": "TTGhREx2pDSxFX555NWz1YwGpiBVPvQA7e",
    "contract_address": "TVSvjZdyDSNocHm7dP3jvCmMNsCnMTPa5W",
    "function_selector": "transfer(address,uint256)",
    "parameter": "0000000000000000000000002ce5...0000038d7ea4c68000",
    "visible": true
  }'

This API is optional on FullNodes — node operators must enable both vm.estimateEnergy and vm.supportConstant in node config. Support on a public RPC depends on the operator's current configuration. Clients should handle this node does not support estimate energy and fall back to triggerconstantcontract.

📘

Which to use

triggerconstantcontract is the commonly used local simulation endpoint and returns energy_used; the node must still enable vm.supportConstant.
estimateenergy may provide a closer estimate for a small set of unusual contracts, but it may be disabled on some nodes.
Use triggerconstantcontract by default; only switch when you have evidence the estimates differ for your specific contract.

The Dynamic Energy Model — why estimates can drift

If you tested a transaction on Shasta and saw 31,000 Energy, then deployed to Mainnet and saw 90,000 Energy charged for the same call — you encountered the Dynamic Energy Model (DEM).

DEM applies a per-contract penalty multiplier that grows when a contract is called frequently. It is recalculated every maintenance cycle (every 6 hours). The actual Energy charged for a call is:

actual_energy = floor(base_energy × (1 + contract_energy_factor))

Where:

  • base_energy is the deterministic Energy cost of executing the bytecode
  • contract_energy_factor is the contract penalty factor obtained by dividing the API's energy_factor by 10,000; it is between 0 and max_factor

For an infrequently called contract, contract_energy_factor is usually 0 and actual Energy equals base Energy. If the API returns energy_factor = 5,000, then contract_energy_factor = 0.5, adding 0.5 times the base Energy and producing a total of 1.5 times the base amount. Frequently called contracts can have a higher factor.

The estimation APIs use the contract state and energy_factor visible to the estimation node. The factor may change after a maintenance-cycle transition, so cross-cycle caches must be revalidated. Contract state or call-parameter changes can also make a cached estimate unsuitable before the cycle ends.

For full reference, see Resource model — Dynamic Energy Model.

Setting fee_limit and origin_energy_limit in different tools

The two parameters travel in different places. fee_limit goes on every transaction, while origin_energy_limit and consume_user_resource_percent only go on the deploy transaction — to change them later, the deployer broadcasts a separate update transaction (wallet/updateenergylimit for the limit, wallet/updatesetting for the percent). All values are in their natural units — sun for fee_limit, Energy (unitless) for origin_energy_limit, percent for consume_user_resource_percent.

HTTP API

For deployment, all three fields go in the wallet/deploycontract body:

BASE_URL=https://api.trongrid.io   # example — replace with any TRON node (TronGrid, third-party, or self-hosted)
curl -X POST ${BASE_URL}/wallet/deploycontract \
  -d '{
    "abi": "...",
    "bytecode": "...",
    "fee_limit": 1000000000,
    "consume_user_resource_percent": 100,
    "origin_energy_limit": 10000000,
    "owner_address": "TTGhREx2pDSxFX555NWz1YwGpiBVPvQA7e",
    "visible": true
  }'

For a regular call (wallet/triggersmartcontract), only fee_limit is needed — the other two are read from the contract's stored settings.

TronWeb

When deploying:

const tx = await tronWeb.transactionBuilder.createSmartContract(
  {
    abi: contractAbi,
    bytecode: contractBytecode,
    feeLimit: 1000e6,                      // 1,000 TRX, in sun
    userFeePercentage: 100,                // = consume_user_resource_percent
    originEnergyLimit: 10_000_000          // = origin_energy_limit
  },
  ownerAddress
);

When calling, only feeLimit is needed:

const result = await contract
  .transfer(toAddress, amount)
  .send({ feeLimit: 150e6 });

Trident (Java)

// Deploy
Response.TransactionExtention deployTx = wrapper.deployContract(
    "TokenContract",
    abiJson,
    bytecode,
    parameters,
    150_000_000L,      // feeLimit, in sun
    100,               // consumeUserResourcePercent
    10_000_000L,       // originEnergyLimit
    0L,                // callValue
    "",                // tokenName
    0L                 // tokenValue
);

// Call: callData is the 4-byte function selector followed by ABI-encoded arguments
String callData = "a9059cbb" + parameter;
Response.TransactionExtention callTx = wrapper.triggerContract(
    ownerAddress,
    contractAddress,
    callData,
    0L,                // callValue
    0L,                // tokenValue
    null,              // tokenId
    150_000_000L       // feeLimit, in sun
);

TronBox

Set globally in tronbox-config.js per network:

networks: {
  shasta: {
    privateKey: process.env.PRIVATE_KEY,
    feeLimit: 1000 * 1e6,                   // 1,000 TRX, in sun
    userFeePercentage: 100,                 // = consume_user_resource_percent
    originEnergyLimit: 10_000_000,          // = origin_energy_limit
    fullHost: 'https://api.shasta.trongrid.io',
    network_id: '2'
  }
}

The userFeePercentage and originEnergyLimit apply only to deployments. For calls, only feeLimit is consulted.

TronIDE

In the Deploy & Run panel, three fields are exposed: feeLimit (sun), userFeePercentage (0–100), and originEnergyLimit (Energy). Defaults are conservative — raise them for large contracts.

📘

Updating after deploy

Need to change consume_user_resource_percent or origin_energy_limit on a contract that's already deployed? Use wallet/updatesetting (the percent) or wallet/updateenergylimit (the limit). Only the deployer can call these.

Common pitfalls

  • Setting fee_limit in TRX instead of sun. A fee_limit = 100 (intending 100 TRX) actually authorizes 0.0001 TRX. The transaction fails immediately with OUT_OF_ENERGY.
  • Assuming fee_limit is always burned in full. It is a caller-side cost cap, not a fixed fee. Normal execution and REVERT settle the Energy actually used, while failures such as OUT_OF_TIME and illegal instructions exhaust the Energy allowance for the execution. Settlement consumes staked Energy first and burns TRX only for the remainder, so the final burn does not necessarily equal fee_limit.
  • Treating TRX burn as the first step. For an on-chain contract transaction, the VM first converts fee_limit into the maximum Energy the caller can cover, then executes and settles resources. This explains why staked Energy and Energy paid for by burning TRX share the same caller-side budget, and why some failed transactions still consume resources.
  • Hard-coding 15,000 TRX or 100 sun in your code. Both are chain parameters that can be changed by SR vote (getMaxFeeLimit for the upper bound, getEnergyFee for the conversion rate). Production code that sets the maximum or estimates costs should query wallet/getchainparameters rather than embedding the numeric values.
  • Reusing an estimate for too long. The Dynamic Energy factor may change at a maintenance-cycle transition, while contract state and call parameters can change sooner. Re-estimate before sending or use a conservative budget with a DEM upper-bound buffer.
  • Forgetting to estimate for deploys. Deployments are often the highest-Energy operation against a contract. A typical TRC-20 deploy consumes 200,000–500,000 Energy (20–50 TRX at the default EnergyPrice); a complex contract with libraries can exceed 1,000,000.
  • Confusing OUT_OF_TIME with OUT_OF_ENERGY. OUT_OF_ENERGY means the remaining Energy is insufficient for the next operation; check the Energy estimate, account resources, and fee_limit. OUT_OF_TIME means execution exceeded the per-transaction CPU time limit; check for unbounded loops, large-array traversal, and other expensive logic. See VM exception handling.

Related resources