> 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/agents/13.-freeze-and-unfreeze-an-address-or-a-partial-balance.md).

# 13. Freeze and unfreeze an address or a partial balance

A freeze immobilizes tokens without taking them away. An agent freezes an address entirely, so that it neither sends nor receives, or freezes an amount on an address, so that this amount cannot be sent. Issuers use freezes during an investigation, to enforce a lock-up or a pledge, to keep an address out of the asset, or to protect a holder whose wallet is compromised. The tokens stay owned by their holder throughout.

## At a glance

|                   |                                                                                                                                                                                                                                                             |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Triggered by**  | Token Agent                                                                                                                                                                                                                                                 |
| **Actors**        | Issuer, Token Agent, Investor, Platform                                                                                                                                                                                                                     |
| **Contracts**     | `Token`                                                                                                                                                                                                                                                     |
| **Preconditions** | The caller holds `AGENT_ADDRESS_FREEZER` to freeze an address, or `AGENT_PARTIAL_FREEZER` to freeze an amount, in the asset's domain (see [25](/guides/issuer/25.-commission-a-suite-and-grant-roles.md)); the freeze is decided under the Issuer's process |
| **Result**        | The address, or an amount on it, is immobilized, or released                                                                                                                                                                                                |

## Actors and roles

| Actor       | Role in this flow                                                   | What they hold                                            |
| ----------- | ------------------------------------------------------------------- | --------------------------------------------------------- |
| Issuer      | Decides the freeze and its release. Does not transact in this flow. | The roles it delegated to its agents                      |
| Token Agent | Submits the freeze or the release.                                  | `AGENT_ADDRESS_FREEZER`, `AGENT_PARTIAL_FREEZER`, or both |
| Investor    | Holds the tokens that are frozen. Does not transact.                | A balance at the address                                  |
| Platform    | Runs the reads 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

    Platform->>Token: isFrozen(address), getFrozenTokens(address), balanceOf(address) (read)
    Platform->>Agent: decision recorded, submit
    alt freeze or release the whole address
        Agent->>Token: setAddressFrozen(address, freeze)
        Token->>Token: caller holds AGENT_ADDRESS_FREEZER
        Token-->>Platform: AddressFrozen(address, freeze, agent)
    else freeze an amount
        Agent->>Token: freezePartialTokens(address, amount)
        Token->>Token: caller holds AGENT_PARTIAL_FREEZER
        Token->>Token: frozen amount stays within the balance
        Token-->>Platform: TokensFrozen(address, amount)
    else release an amount
        Agent->>Token: unfreezePartialTokens(address, amount)
        Token->>Token: caller holds AGENT_PARTIAL_FREEZER
        Token->>Token: amount within what is frozen
        Token-->>Platform: TokensUnfrozen(address, amount)
    end
```

## Step by step

### Step 1. Choose the freeze and read the state

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

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

**Before the call:** The Issuer has decided what to immobilize and why.

**What happens:** The Platform reads `Token.isFrozen(address)`, `Token.getFrozenTokens(address)` and `Token.balanceOf(address)`, and chooses the kind of freeze.

|            | Freezing the address                                                                       | Freezing an amount                                                                 |
| ---------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
| **Blocks** | Every transfer from the address and every transfer to it                                   | Sending that amount. The rest of the balance moves, and the address still receives |
| **Suits**  | An investigation, a sanctioned or compromised address, keeping an address out of the asset | A lock-up, a pledge, a disputed part of a position                                 |
| **Role**   | `AGENT_ADDRESS_FREEZER`                                                                    | `AGENT_PARTIAL_FREEZER`                                                            |

A freeze applies to one address. An investor that holds at its ONCHAINID and in linked wallets is frozen address by address. The Platform lists the investor's addresses with `IdentityFactory.getAccounts(identity, start, end)` and reads the balance of each.

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

### Step 2. Freeze or release an address

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

**Call:** `Token.setAddressFrozen(userAddress, freeze)`, with `freeze` true to freeze and false to release

**Before the call:** Step 1 is done.

**What the contract checks:**

1. The caller holds `AGENT_ADDRESS_FREEZER` in the asset's domain. Otherwise the call reverts with `AccessManagedUnauthorized`.

**What changes:** The token records the address as frozen, or as not frozen, and emits `AddressFrozen(userAddress, freeze, agent)`. While frozen, every `transfer`, `transferFrom` and `identityTransfer` from or to the address reverts with `FrozenWallet`.

### Step 3. Freeze an amount

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

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

**Before the call:** Step 1 is done.

**What the contract checks:**

1. The caller holds `AGENT_PARTIAL_FREEZER` in the asset's domain. Otherwise `AccessManagedUnauthorized`.
2. The amount already frozen plus `amount` does not exceed the balance of the address. Otherwise `ERC20InsufficientBalance`.

**What changes:** The frozen amount of the address increases by `amount`. The token emits `TokensFrozen(userAddress, amount)`. The free balance, which is what the holder can send, decreases by the same amount. `balanceOf` does not change.

### Step 4. Release an amount

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

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

**Before the call:** The Issuer has decided to release all or part of what is frozen.

**What the contract checks:**

1. The caller holds `AGENT_PARTIAL_FREEZER`. Otherwise `AccessManagedUnauthorized`.
2. `amount` does not exceed the frozen amount of the address. Otherwise `AmountAboveFrozenTokens`.

**What changes:** The frozen amount decreases by `amount`. The token emits `TokensUnfrozen(userAddress, amount)`. The free balance increases by the same amount.

## State after the flow

* `Token.isFrozen(address)` reflects the address freeze.
* `Token.getFrozenTokens(address)` reflects the frozen amount, which is never above `Token.balanceOf(address)`.
* `Token.freeBalanceOf(address)` is the balance less the frozen amount.
* `Token.balanceOf(address)`, `Token.totalSupply()` and `ModularCompliance.positionOf(identity)` are unchanged. Frozen tokens are still owned and still counted by every rule.
* The eligibility of the holder is unchanged.

## Failure modes

| Symptom                                                        | Cause                                                                                                          | Fix                                                                                                                                                                                                         |
| -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Reverts with `AccessManagedUnauthorized`                       | The caller does not hold the role of this kind of freeze. The two are separate roles (check 1 of steps 2 to 4) | Grant the role: [25](/guides/issuer/25.-commission-a-suite-and-grant-roles.md)                                                                                                                              |
| `freezePartialTokens` reverts with `ERC20InsufficientBalance`  | The total frozen amount would exceed the balance of the address (step 3, check 2)                              | Freeze at most the balance less what is already frozen                                                                                                                                                      |
| `unfreezePartialTokens` reverts with `AmountAboveFrozenTokens` | More is released than is frozen (step 4, check 2)                                                              | Read `getFrozenTokens` and release at most that                                                                                                                                                             |
| The address is frozen and its tokens still moved               | An agent burned them, forced a transfer or ran a recovery. These operations go through a freeze                | Intended. A freeze stops holders and spenders, not the agents                                                                                                                                               |
| The address is frozen and it received tokens                   | An agent minted to it, or forced a transfer to it. A freeze blocks transfers by holders                        | Intended                                                                                                                                                                                                    |
| The investor is frozen and still moved tokens                  | Another of its addresses is not frozen                                                                         | Freeze each address that holds tokens                                                                                                                                                                       |
| The investor's tokens on a satellite still move                | A freeze applies to the reference chain                                                                        | Recall the position: [32](/guides/cross-chain/32.-recall-a-position-to-the-reference-chain.md). A recalled position arrives at the holder's address on the reference chain even when that address is frozen |
| A frozen amount disappeared                                    | A burn or a forced transfer needed it and released it, with a `TokensUnfrozen` event                           | Read the events of the address                                                                                                                                                                              |

## Common misunderstandings

> **Wrong:** "Frozen tokens are seized."
>
> **Right:** A freeze changes what can be done with tokens, not whose they are. They remain in `balanceOf`, in the position of the identity and in every rule about distribution. Taking them is a forced transfer or a burn, each with its own role.

> **Wrong:** "Freezing an investor freezes everything it owns."
>
> **Right:** A freeze is on an address. An investor's ONCHAINID and each of its linked wallets are separate addresses, and positions on satellites are not reached at all. Freezing an investor means freezing each of its addresses on the reference chain, and recalling what is on satellites.

> **Wrong:** "A frozen address has to be unfrozen before an agent can act on it."
>
> **Right:** A burn, a forced transfer and a recovery go through a freeze and release exactly the frozen amount they need. A recovery carries the frozen amount and the address freeze over to the new address.

> **Wrong:** "A freeze makes the investor ineligible."
>
> **Right:** Eligibility is about the identity's claims. A freeze is about an address on one asset. A frozen investor stays eligible, and keeps acting freely on its other assets.

## Integration notes

* Show holders their free balance, `freeBalanceOf`, as what they can send. A transfer above it reverts with `ERC20InsufficientBalance` even though `balanceOf` is higher.
* Use the batch variants for many addresses: `batchSetAddressFrozen`, `batchFreezePartialTokens`, `batchUnfreezePartialTokens`. Each is gated by the role of its single operation and reverts as a whole if one entry fails.
* Index `AddressFrozen`, `TokensFrozen` and `TokensUnfrozen`. `AddressFrozen` names the agent that acted. During a recovery it names the token itself.
* A freeze is the way to keep an address out of an asset. Removing its registration does not do it.
* Freezes are per asset. Freezing an address on one token has no effect on another.
* Record the reason and the authority for each freeze off-chain. The chain records who froze what and when, not why.

## Related flows

* [14 Execute a forced transfer](/guides/agents/14.-execute-a-forced-transfer.md) : moving a frozen position
* [15 Recover a position from a lost wallet](/guides/agents/15.-recover-a-position-from-a-lost-wallet.md) : a recovery carries freezes over
* [16 Pause and unpause a token](/guides/agents/16.-pause-and-unpause-a-token.md) : halting the whole asset, not one address
* [09 Burn a position](/guides/positions/09.-burn-a-position.md) : a burn releases the freeze it needs
* [18 Remove an investor's registration](/guides/agents/18.-remove-an-investors-registration.md) : what does not keep an address out
* [23 Revoke a wallet](/guides/identity/23.-revoke-a-wallet.md) : what the holder does for a compromised wallet


---

# 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/agents/13.-freeze-and-unfreeze-an-address-or-a-partial-balance.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.
