> ## Documentation Index
> Fetch the complete documentation index at: https://docs.li.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Gas costs and fee costs

> How to read gasCosts and feeCosts on a quote, which chain each cost belongs to, and when your users need native gas

Costs come back in two arrays, `gasCosts` and `feeCosts`. They answer different questions, they are denominated differently, and neither one maps cleanly onto "what the user pays on each chain". This guide explains how to read both so you can show your users an accurate cost breakdown.

***

## Where the cost arrays live

Both arrays hang off an `estimate` object, and `estimate` belongs to a **step**. Not every response hands you a step directly.

| Response                                                     | Where the costs are                                                   |
| :----------------------------------------------------------- | :-------------------------------------------------------------------- |
| `/v1/quote`, `/v1/quote/toAmount`, `/v1/quote/contractCalls` | `estimate.gasCosts` and `estimate.feeCosts` on the returned step      |
| `/v1/advanced/routes`                                        | `routes[].steps[].estimate` for each step in the route                |
| Any step with `includedSteps`                                | `estimate` on each included step, as a breakdown of the step above it |

A route is an envelope around its steps and has no `estimate` of its own. Reading `route.estimate` gives you `undefined`. The only cost figure a route carries at the top level is `gasCostUSD`, a single aggregate string.

<Note>
  Both arrays are optional. A step can come back with neither, or with an empty array, and that is a valid quote rather than a quoting failure. Guard every read before you index into one.
</Note>

***

## gasCosts or feeCosts?

The split is about **who submits a transaction**, not about what the money is for.

|                 | `gasCosts`                                                                         | `feeCosts`                                                                  |
| :-------------- | :--------------------------------------------------------------------------------- | :-------------------------------------------------------------------------- |
| What it is      | Estimated network gas for a transaction the sender submits                         | Anything charged as a fee rather than paid as network gas by the sender     |
| Denominated in  | The native gas token of the chain the transaction is sent on                       | Any token, usually the token the user is already sending                    |
| Paid by         | Whoever submits the transaction, from their native balance, on top of `fromAmount` | Deducted from the transfer, or added on top, depending on `included`        |
| Typical entries | Source-chain execution                                                             | Integrator fee, LI.FI fee, bridge or solver fee, destination execution cost |
| Field to check  | `type`                                                                             | `included`                                                                  |

A cost being *for* gas does not put it in `gasCosts`. A bridge that pays for destination-chain execution and bills the user for it reports that as a `feeCosts` entry, because the user never signs a destination transaction.

***

## Reading a gas cost

```json theme={"system"}
{
  "type": "SEND",
  "price": "128468782",        // wei per unit of gas
  "estimate": "459000",        // units of gas the transaction consumes
  "limit": "596700",           // estimate plus a safety buffer, use this when submitting
  "amount": "58967170938000",  // estimate * price, in wei
  "amountUSD": "0.1156",
  "token": {
    "symbol": "ETH",
    "decimals": 18,
    "chainId": 1               // the chain that consumes this gas
  }
}
```

`price` is in the smallest unit of the gas token per unit of gas, so wei per gas on EVM chains, not gwei. For EVM entries, `amount` is `estimate * price`, and `limit` is `estimate` plus a buffer. Other ecosystems may apply chain-specific units and rounding, so treat the returned `amount` as authoritative rather than reconstructing it. When constructing an EVM transaction from these fields, use `limit`, not `estimate`.

### Gas cost types

`GasCost.type` is typed as one of four values, but only one of them is in production use.

| Type      | Meaning                                                                                    | Returned today                                    |
| :-------- | :----------------------------------------------------------------------------------------- | :------------------------------------------------ |
| `SEND`    | Estimated network gas for the transaction the sender submits, normally on the source chain | Yes                                               |
| `APPROVE` | Estimated network gas for a separate ERC-20 approval transaction                           | No. Approval gas is not returned as its own entry |
| `FEE`     | An execution cost charged as a fee rather than as a transaction the user signs             | No. These costs appear in `feeCosts` instead      |
| `SUM`     | An aggregate of the other entries                                                          | No                                                |

<Note>
  Handle `APPROVE`, `FEE`, and `SUM` if they appear, so your integration stays forward-compatible, but don't build a flow that depends on them. If you need the gas cost of an approval today, estimate it yourself against `approvalAddress`.
</Note>

***

## Which chain does a cost belong to?

`token.chainId` tells you the chain of the token a cost is **denominated in**. It does not tell you where the underlying work happens.

For `gasCosts` the two coincide: gas is paid in the native token of the chain that consumes it, so `token.chainId` is the execution chain.

For `feeCosts` they often differ. In this quote, 50 USDC on Ethereum is sent to cbBTC on Base:

```json theme={"system"}
{
  "name": "Relayer Gas fee",
  "description": "Relay bridge gas fee",
  "token": { "symbol": "USDC", "chainId": 1, "decimals": 6 },  // denominated on Ethereum
  "amount": "1116",
  "amountUSD": "0.0011",
  "percentage": "0.0000",
  "included": true
}
```

The fee covers execution on Base, but it is charged in Ethereum USDC because that is the token the user is already sending. Reading `chainId: 1` as "this is a source-chain cost" is the mistake to avoid.

<Warning>
  Do not derive a per-chain cost breakdown from `token.chainId`. If your UI needs to say "you pay X on the source chain and Y on the destination chain", you cannot build that reliably from the quote alone.
</Warning>

***

## Where destination execution cost shows up

LI.FI does not guarantee a separate source-chain and destination-chain gas item. Depending on the tool, the cost of executing on the destination chain reaches you in one of three ways:

* **As a `feeCosts` entry**, typically named something like `Relayer Gas fee` or `Network fee`, denominated in the source-chain token. This is the most common case.
* **As tool-specific data**, for example a `destinationGasConsumption` value inside `estimate.data`. The shape varies by tool.
* **Priced into the output**, with no separate line item. The quoted `toAmount` is already net of it.

Fee names are tool-specific free text and are not a stable enum. `Relayer Gas fee`, `Relayer gas fee`, and `Network fee` all exist across different tools. Display `name` and `description` to users, but never branch on them.

***

## Does the user need native gas?

The answer depends on who broadcasts the source transaction, so start from the execution mode you integrated.

| Execution mode                                                                                                                                 | Source native gas | Who pays it                                                                 |
| :--------------------------------------------------------------------------------------------------------------------------------------------- | :---------------- | :-------------------------------------------------------------------------- |
| Self-submitted. The user signs a `transactionRequest` and broadcasts it                                                                        | Yes               | The user, from their native balance, on top of `fromAmount`                 |
| Gasless, for eligible EVM accounts. The user signs an EIP-712 payload from a `gasless=true` quote and LI.FI relays it via `/v1/advanced/relay` | No                | LI.FI. The relay cost is billed back through `feeCosts`, in the input token |
| Relayed (legacy). The user signs a Permit2 message and LI.FI's relayer broadcasts, via `/v1/relayer/relay`                                     | No                | The relayer. The cost is billed back through `feeCosts`                     |

Destination-chain native gas is normally not needed in either mode. LI.FI or the bridge executes on the destination side, and any cost reaches you through `feeCosts` or is priced into `toAmount`.

Gasless availability is determined at quote time. It currently requires an EVM source chain and an EIP-7702 delegated account that LI.FI supports; not every chain, delegate, or account type is eligible. See [Gasless Transactions](/guides/gasless-transactions) for the current requirements and execution flow.

If your integration self-submits, check the native balance on the source chain against `gasCosts[].amount` before letting a user sign. A user with enough USDC but no ETH will fail at submission, not at quoting. If you relay, that check does not apply to the user, and a `gasCosts` entry describes what the relayer spends rather than what the user must hold.

See [Permit and Permit2 Approval Flow](/introduction/user-flows-and-examples/permit2-approval-flow) for the signature the legacy relayed path expects.

The destination case has one exception worth planning for: your user lands on a new chain with the bridged token and no native balance, so they can't do anything next. That is a cold-start problem, not an execution problem, and LI.Fuel solves it.

### LI.Fuel is not execution gas

`fromAmountForGas` converts part of the sent amount into the destination chain's native token and delivers it to the user alongside the bridged asset. It exists so the user has gas for their *next* action.

Keep the two separate when you build a cost breakdown:

* **Execution gas** is what it costs to complete this transfer. It shows up in `gasCosts` and `feeCosts`.
* **LI.Fuel** is an extra amount the user asked to receive as native token. It reduces `toAmount`, and it is not a cost of the transfer.

See [Gas Fronting](/guides/gas-subsidy) for the request parameter and its limitations.

***

## The `included` flag

`included` decides whether a fee is already reflected in the quoted amounts.

* `included: true` means the fee is already accounted for. The quoted `toAmount` is net of it. Show it in a breakdown, but do not add it again as a separate user payment.
* `included: false` means the user pays it on top of `fromAmount`.

Adding an `included: true` fee back on top is the most common way integrations end up overstating cost to their users.

***

## Don't add the top-level and step-level arrays together

A `lifi` step carries its own `estimate.feeCosts` and `estimate.gasCosts`, and each entry in `includedSteps` carries its own. The top-level arrays are **derived from** the step-level ones, so summing both double counts.

They are derived differently, which matters:

* **`feeCosts`** at the top level is the concatenation of every included step's fee costs. Same entries, same amounts.
* **`gasCosts`** at the top level is a single estimate for the transaction that is actually submitted. It aggregates raw gas costs from included steps on the source chain and, for EVM transactions, adds estimated LI.FI contract overhead. It may therefore differ from—and often exceed—the sum of the source-chain per-step entries. Raw gas costs from destination-chain included steps are not added directly.

For the 50 USDC quote above:

| Source                              | Gas          | Fees         |
| :---------------------------------- | :----------- | :----------- |
| `includedSteps[0]` (fee collection) | \$0.0327     | \$0.1249     |
| `includedSteps[1]` (bridge)         | \$0.0217     | \$0.0549     |
| Sum of steps                        | \$0.0544     | \$0.1798     |
| Top-level `estimate`                | **\$0.1156** | **\$0.1798** |

In this example the fee columns match and the gas columns do not, because the top-level figure covers the single transaction the user actually submits, including LI.FI contract overhead.

<Warning>
  Use the top-level `estimate` arrays for anything you show the user or charge against. Treat `includedSteps` costs as a breakdown for debugging and display, never as additional amounts to sum.
</Warning>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Gas Fronting" icon="gas-pump" href="/guides/gas-subsidy">
    Deliver destination-chain native token to your users with `fromAmountForGas`.
  </Card>

  <Card title="Fees and monetization" icon="coins" href="/faqs/fees-monetization">
    How integrator fees are configured and collected.
  </Card>

  <Card title="Quote API reference" icon="code" href="/api-reference/get-a-quote-for-a-token-transfer">
    The full response shape, including `estimate`, `feeCosts`, and `gasCosts`.
  </Card>

  <Card title="Route and quote differences" icon="diagram-project" href="/introduction/user-flows-and-examples/difference-between-quote-and-route">
    When to call `/quote` and when to call `/advanced/routes`.
  </Card>
</CardGroup>
