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); 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
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
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:
The caller holds
AGENT_BURNERin the asset's domain. Otherwise the call reverts withAccessManagedUnauthorized.The amount is within the balance of the address, frozen tokens included. Otherwise
ERC20InsufficientBalance.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 byamount.Token.totalSupply()has decreased byamount.Token.getFrozenTokens(address)has decreased by what the burn had to release, and is never above the balance.ModularCompliance.positionOf(identity)has decreased byamountfor the holder's identity.One
Transferevent withto = 0x0was emitted. An indexer treats it as a redemption or a cancellation.Room is freed under any cap that counts positions.
Failure modes
Reverts with AccessManagedUnauthorized
The calling key does not hold AGENT_BURNER in the asset's domain (step 2, check 1)
Grant the role: 25. 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.
burnis gated byAGENT_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
Transferto 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
balanceOfbut 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
balanceOfandgetFrozenTokensbefore 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 : the inverse operation
13 Freeze and unfreeze an address or a partial balance : a burn releases what it needs
14 Execute a forced transfer : moving a position without the holder, not destroying it
32 Recall a position to the reference chain : before burning a position active on a satellite
Last updated