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

# IX003 · Fees from the envelope

> The envelope says who bid. The ledger says who paid, and how much.

## What it flags

Two patterns:

1. **`TransactionEnvelope.Fee()` or `FeeBumpFee()`** in a function that never reads `FeeCharged`. The envelope fee is the bid, not the charge.
2. **`TransactionEnvelope.SourceAccount()` in fee logic** (the function's name or body mentions fees) that never checks for a fee-bump (`IsFeeBump`, `FeeBumpAccount`, `FeeAccount`…). On a fee-bump, `SourceAccount()` is the inner source, who didn't pay.

## Why it matters

On the [fee-bump fixture](https://docs.istravex.com/corpus/fixtures.md#fee-bump-fee-source), reading fees from the envelope gives the wrong account *and* the wrong amount: 46,341 stroops charged to `GDMV…COIW`, when the ledger charged 40,354 to `GA2J…HVAW`. The [naive replay indexer](https://docs.istravex.com/tools/replay.md) makes exactly this mistake.

## Fix

```go theme={null}
payer := env.SourceAccount()
if env.IsFeeBump() {
    payer = env.FeeBumpAccount()
}
charged := result.Result.FeeCharged
```

## Why it's limited to fee logic

`SourceAccount()` is often right. An operation without its own source runs as the inner transaction's source, fee-bump or not, so using it as the fallback is correct. The first version of this rule flagged every call and produced two false positives in wallet-backend, both correct fallbacks. Restricting it to fee logic removed them without losing the real pattern.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.