Freezing tokens

The Private Network operator can freeze a token for chosen participants in a Rayls Private Network. While a token is frozen for a participant, that participant's Rayls Sovereign chain (Privacy Node in the code) can't send the token to other chains or receive it from them. This covers Enygma transfers and delivery-versus-payment (DvP) swaps. Everything else on the network keeps working, including other tokens and the same token for other participants.

To stop a participant altogether, see Freezing participants.

How it works

The freeze list lives in the token registry on the Private Network Hub (TokenRegistryV1, which delegates to its TokenFreezeManagerV1 module). For each token, identified by its resource ID, it holds the chain IDs of the participants the token is frozen for.

  1. The operator calls freezeToken(resourceId, chainIds) on the Hub's TokenRegistry. The Hub adds the chain IDs to the token's freeze list and emits TokenFreezeStatusChanged.
  2. The Hub sends the token's freeze list to every chain in the network. Each chain stores it in its own token registry (PNTokenRegistryV1).
  3. On each listed chain, the token's Hub status becomes FROZEN. On every chain, the token's freeze list is checked before the token leaves for another chain.

unfreezeToken(resourceId, chainIds) removes chain IDs from the list, and each chain restores the token's previous Hub status.

A chain that joins the network later receives the current freeze lists when its contracts are deployed. A freeze applies only to the chain IDs listed: there is no network-wide switch, and a participant that joins after a freeze isn't covered by it.

An account with the ADMIN role in the Hub's access manager can freeze or unfreeze: the operator's deployment account by default. If the operator has activated the Hub's business roles, so can an account with the COMPLIANCE_OFFICER role. See Private Network roles.

What a frozen participant can and can't do

For a token frozen for participant B:

OperationEffect
Enygma transfers from BRefused on B's chain with RaylsApp__HubNotActive. Covers crossTransfer, crossTransferFrom, linearCrossTransfer and linearCrossTransferFrom.
Enygma transfers to BRefused on the sender's chain, with TokenFreezeManagerV1__TokenFrozenForParticipant
DvP with an Enygma token on BdepositToDvp, callWithdrawFromDvp, swapWithDvpForERC721 and swapWithDvpForERC1155 revert on B's chain
DvP with an ERC-721 or ERC-1155 token on BdepositIntoDvp, swapWithDvpForEnygma and withdrawFromDvp revert on B's chain
Transfers between clients on B's own chainContinue. The Hub freeze doesn't apply inside a chain.
Mint and burn by the token's owner on B's chainContinue
The same token on other participants' chainsContinue, except transfers to B

Each check runs on the chain that sends the token, against that chain's copy of the freeze list. A freeze takes effect on a chain once the Hub's update has reached it through that chain's relayer.

See Who sees what for how freezing fits with the other controls over Enygma tokens.

Freeze a token

You need the token's resource ID and the chain IDs of the participants to freeze it for. GET /audit/tokens on the governance API lists tokens with their resource IDs.

npx hardhat freeze-token --resource-id <resourceId> --participants 200002,200003

The task calls freezeToken on the Hub's TokenRegistry, using PNH_RPC_URL, PNH_DEPLOYMENT_PROXY_REGISTRY and PRIVATE_KEY_SYSTEM.

To freeze a token for every current participant, pass all their chain IDs. getAllParticipantsChainIds() on the Hub's ParticipantStorage returns them.

Unfreeze a token

npx hardhat unfreeze-token --resource-id <resourceId> --participants 200002

unfreezeToken reverts with Token not found if the token isn't frozen for anyone.

Check a token's freeze list

  • Governance API: GET /audit/tokens/{resourceId} returns the token with a frozenChainIds array.
  • Hub: isTokenFrozenForParticipant(resourceId, chainId) on TokenRegistry.
  • A participant's chain: getHubStatus(tokenAddress) on its PNTokenRegistryV1 returns FROZEN (4) while the token is frozen for that chain.

Freezes a participant controls itself

Each Rayls Sovereign chain's own administrator can also freeze a token on that chain, separately from the operator:

FreezeCall on the chain's PNTokenRegistryV1Effect
Chain freezefreezeOnPrivacyNode(tokenAddress) / unfreezeOnPrivacyNodeBlocks the token on that chain, including local transfers, approvals, minting and burning (RaylsApp__PrivacyNodeFrozen)

The operator can't set or lift these freezes from the Hub.


Did this page help you?