---
title: "Fee Outcomes and Debugging"
description: "Applications should explain transaction outcomes in terms users or operators can act on. A submitted GenLayer transaction can be accepted by consensus,…"
source: https://docs.genlayer.com/developers/decentralized-applications/fee-outcomes-and-debugging
last_updated: 2026-06-16
---

# Fee Outcomes and Debugging

Applications should explain transaction outcomes in terms users or operators can act on. A submitted GenLayer transaction can be accepted by consensus, finalized later, rejected before execution or finish with a contract error.

## Success rule

A transaction is successful only when both are true:

- the transaction status is `ACCEPTED` or `FINALIZED`
- the execution result is `FINISHED_WITH_RETURN`

Use `isSuccessful(tx)` from `genlayer-js` or the transaction-kit outcome surfaces instead of checking status alone. A transaction can be accepted by validators and still finish with a contract error.

## User-facing outcomes

| Status and result | Meaning | Surface it as |
| --- | --- | --- |
| `ACCEPTED` / `FINALIZED` + `FINISHED_WITH_RETURN` | Execution succeeded. | Done. Unused fee budget refunds at finalization. |
| `UNDETERMINED` + any result | Validators could not reach a majority. | Treat as not executed, even if a leader result exists. |
| Rejected at submission, such as `MaxPriceExceeded` | A price cap or funding rule failed before execution. | Nothing charged. Re-estimate and retry. |
| `FINISHED_WITH_ERROR` | The contract reverted or errored. | Execution failed. Consensus fees may still be consumed. |

## Gasless networks

Some Studio deployments run gasless, with fee accounting disabled and all prices zero. The transaction kit detects this from the estimate:

```typescript
if (quote.gasless) {
  // Show "No fees on this network" and submit without fee params.
}
```

The same app code can work on gasless Studio and fee-charging networks. Do not hard-code a network name to decide whether fees are enabled; use the estimate result.

## Refunds

The initial deposit is a maximum budget, not the final cost. Unused budget is refunded when the transaction finalizes. Users should understand three numbers:

- total deposit: what must be available when signing
- spent fees: what the transaction actually consumed
- refund: the unused part returned after finalization

If an app tracks only until `decided`, it may not yet know the final refund. Use `finalized` tracking for screens or tools that need final fee settlement.

## Explorer debugging

Open the transaction in GenLayer Explorer and inspect the Fees section. It should show:

- allocation versus consumed values
- locked price caps versus current prices
- message fee budget and consumption
- refunds by category
- settlement status

If a quote looks too large, check whether the transaction used a developer profile or network defaults. `PolicyQuote.source` is `developer` when a matching `fee-profile.json` entry was used and `network-default` otherwise.

If a transaction failed even though the user accepted the quote, check:

- whether a price cap was exceeded before execution
- whether the method hit an unmeasured expensive branch
- whether `totalMessageFees` was too low for emitted child transactions
- whether the contract itself returned `FINISHED_WITH_ERROR`
- whether the app tracked only status and ignored execution result
