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); the freeze is decided under the Issuer's process
Result
The address, or an amount on it, is immobilized, or released
Actors and roles
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
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.
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:
The caller holds
AGENT_ADDRESS_FREEZERin the asset's domain. Otherwise the call reverts withAccessManagedUnauthorized.
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:
The caller holds
AGENT_PARTIAL_FREEZERin the asset's domain. OtherwiseAccessManagedUnauthorized.The amount already frozen plus
amountdoes not exceed the balance of the address. OtherwiseERC20InsufficientBalance.
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:
The caller holds
AGENT_PARTIAL_FREEZER. OtherwiseAccessManagedUnauthorized.amountdoes not exceed the frozen amount of the address. OtherwiseAmountAboveFrozenTokens.
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 aboveToken.balanceOf(address).Token.freeBalanceOf(address)is the balance less the frozen amount.Token.balanceOf(address),Token.totalSupply()andModularCompliance.positionOf(identity)are unchanged. Frozen tokens are still owned and still counted by every rule.The eligibility of the holder is unchanged.
Failure modes
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
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. 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 withERC20InsufficientBalanceeven thoughbalanceOfis 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,TokensFrozenandTokensUnfrozen.AddressFrozennames 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 : moving a frozen position
15 Recover a position from a lost wallet : a recovery carries freezes over
16 Pause and unpause a token : halting the whole asset, not one address
09 Burn a position : a burn releases the freeze it needs
18 Remove an investor's registration : what does not keep an address out
23 Revoke a wallet : what the holder does for a compromised wallet
Last updated