> For the complete documentation index, see [llms.txt](https://docs.t-rex.network/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.t-rex.network/guides/positions/09.-burn-a-position.md).

# 09. Burn a position

Burning destroys units of the asset held at an address. It is how a redemption, a buy-back or the cancellation of units issued in error lands on the register: once the Issuer has settled the redemption under its own process, an agent burns the corresponding position. A burn has no recipient, so neither gate applies. It is an agent operation that needs no signature from the holder.

## At a glance

|                   |                                                                                                                                                                                                                                                                               |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Triggered by**  | Token Agent                                                                                                                                                                                                                                                                   |
| **Actors**        | Issuer, Token Agent, Investor, Platform                                                                                                                                                                                                                                       |
| **Contracts**     | `Token`, `ModularCompliance`, compliance modules                                                                                                                                                                                                                              |
| **Preconditions** | The caller holds `AGENT_BURNER` in the asset's domain (see [25](/guides/issuer/25.-commission-a-suite-and-grant-roles.md)); the address holds at least `amount` on the reference chain; the redemption is settled, or the cancellation is decided, under the Issuer's process |
| **Result**        | The balance of the address, the position of its identity and the total supply have each decreased by `amount`                                                                                                                                                                 |

## Actors and roles

| Actor       | Role in this flow                                                                                                | What they hold                                            |
| ----------- | ---------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| Issuer      | Decides that the units are to be destroyed: the redemption is accepted and paid. Does not transact in this flow. | The roles it delegated to its agents                      |
| Token Agent | Submits the burn.                                                                                                | `AGENT_BURNER` on the `Token`                             |
| Investor    | Holds the position that is burned. Does not transact.                                                            | A balance at one of its addresses                         |
| Platform    | Runs the pre-checks and submits with the Token Agent's key.                                                      | The Token Agent's signing key, or a key authorized for it |

## Sequence

```mermaid
sequenceDiagram
    participant Platform
    participant Agent as Token Agent
    participant Token
    participant MC as ModularCompliance
    participant Module as Compliance modules

    Platform->>Token: balanceOf(address), getFrozenTokens(address) (read)
    Platform->>Agent: pre-checks passed, submit
    Agent->>Token: burn(address, amount)
    Token->>Token: caller holds AGENT_BURNER
    Token->>Token: balance sufficient, unfreeze what the burn needs
    Token->>Token: balance and total supply decrease
    Token-->>Platform: Transfer(address, 0x0, amount)
    Token->>MC: destroyed(address, amount)
    MC->>MC: position of the holder's identity decreases
    MC->>Module: afterTransfer(ctx), for each TRACKER module
```

## Step by step

### Step 1. Confirm what is to be burned

**Who:** Platform, on behalf of the Token Agent

**Call:** Off-chain, using read calls

**Before the call:** The redemption is settled under the Issuer's process, or the cancellation is decided. The Platform knows the address and the number of units.

**What happens:** The Platform reads `Token.balanceOf(address)`, which must cover the amount, and `Token.getFrozenTokens(address)`, to know whether the burn will release frozen tokens. If part of the investor's position is active on a satellite, that part is not in `balanceOf` and cannot be burned from here: it is recalled first.

**What changes:** Nothing on-chain.

### Step 2. Burn

**Who:** Token Agent (`AGENT_BURNER`)

**Call:** `Token.burn(userAddress, amount)`

**Before the call:** Step 1 passed.

**What the contract checks:**

1. The caller holds `AGENT_BURNER` in the asset's domain. Otherwise the call reverts with `AccessManagedUnauthorized`.
2. The amount is within the balance of the address, frozen tokens included. Otherwise `ERC20InsufficientBalance`.
3. The amount is not zero. The compliance does not record a movement of zero. Otherwise `ZeroValue`.

Nothing else is checked. The pause does not block a burn. A freeze on the address does not block it. The eligibility of the holder is not evaluated, and the compliance rules are not asked.

**What changes:** If the amount exceeds the free balance, the token releases the frozen tokens it needs and emits `TokensUnfrozen(address, releasedAmount)`. It debits the address, decreases `totalSupply` by `amount`, and emits `Transfer(address, 0x0, amount)`. It then calls `ModularCompliance.destroyed(address, amount)`. The compliance subtracts `amount` from the position of the holder's identity and calls `afterTransfer` on every `TRACKER` module.

## State after the flow

* `Token.balanceOf(address)` has decreased by `amount`.
* `Token.totalSupply()` has decreased by `amount`.
* `Token.getFrozenTokens(address)` has decreased by what the burn had to release, and is never above the balance.
* `ModularCompliance.positionOf(identity)` has decreased by `amount` for the holder's identity.
* One `Transfer` event with `to = 0x0` was emitted. An indexer treats it as a redemption or a cancellation.
* Room is freed under any cap that counts positions.

## Failure modes

| Symptom                                                           | Cause                                                                                | Fix                                                                                                                             |
| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| Reverts with `AccessManagedUnauthorized`                          | The calling key does not hold `AGENT_BURNER` in the asset's domain (step 2, check 1) | Grant the role: [25](/guides/issuer/25.-commission-a-suite-and-grant-roles.md). Holding `AGENT_MINTER` or `AGENT` is not enough |
| Reverts with `ERC20InsufficientBalance`                           | The address holds less than `amount` on the reference chain (step 2, check 2)        | Read `balanceOf`. Burn at most the balance                                                                                      |
| Reverts with `ZeroValue`                                          | The amount is zero (step 2, check 3)                                                 | Burn a positive amount. In a batch, remove the entries of zero                                                                  |
| The investor owns more than `balanceOf` shows                     | Part of its position is active on a satellite, or held at another of its addresses   | Burn at each address. For a satellite position, recall it first                                                                 |
| An unexpected `TokensUnfrozen` event appears                      | The burn exceeded the free balance and released frozen tokens                        | Intended. Read `getFrozenTokens` before burning to anticipate it                                                                |
| The burn succeeds while the token is paused                       | Burns are allowed during a pause                                                     | Intended. A redemption can be part of the response to an incident                                                               |
| The transaction succeeds and the Platform still shows the balance | The indexer ignores `Transfer` events whose `to` is the zero address                 | Index burns as `Transfer` to the zero address                                                                                   |

## Common misunderstandings

> **Wrong:** "The holder burns its own tokens."
>
> **Right:** There is no burn function for holders. `burn` is gated by `AGENT_BURNER`. A redemption is requested from the Issuer under the terms of the asset, and an agent executes it.

> **Wrong:** "A burn needs the holder's approval."
>
> **Right:** A burn takes no allowance and no signature from the holder. It is one of the servicing operations of the register. That is why it is a separate role, and why every burn is visible as a `Transfer` to the zero address.

> **Wrong:** "A burn is blocked if the holder is frozen or no longer eligible."
>
> **Right:** A burn passes no gate. It works on a frozen address, on a wallet whose link was revoked, and for a holder whose claims expired. A redemption can always be carried out.

> **Wrong:** "Burning reduces `balanceOf` but the compliance keeps counting the position."
>
> **Right:** The token tells the compliance after every burn. The position of the identity goes down by the same amount, so rules that count positions see the room that was freed.

## Integration notes

* Read `balanceOf` and `getFrozenTokens` before submitting. The first tells whether the burn can succeed, the second whether it will release a freeze.
* For a redemption across many investors, use `Token.batchBurn(userAddresses, amounts)`. It is gated by the same role and reverts as a whole if one entry fails.
* Index `Transfer(address, 0x0, amount)` as a burn. There is no separate burn event.
* Store the link between the redemption record and the transaction hash, as for a mint.
* A burn acts on one address. An investor that holds at its ONCHAINID and in linked wallets is burned address by address.
* The payment leg of a redemption is outside this flow. The Issuer settles it under its own process, or with an application built for it.

## Related flows

* [08 Mint a position to an investor](/guides/positions/08.-mint-a-position-to-an-investor.md) : the inverse operation
* [13 Freeze and unfreeze an address or a partial balance](/guides/agents/13.-freeze-and-unfreeze-an-address-or-a-partial-balance.md) : a burn releases what it needs
* [14 Execute a forced transfer](/guides/agents/14.-execute-a-forced-transfer.md) : moving a position without the holder, not destroying it
* [32 Recall a position to the reference chain](/guides/cross-chain/32.-recall-a-position-to-the-reference-chain.md) : before burning a position active on a satellite


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.t-rex.network/guides/positions/09.-burn-a-position.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
