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.
- The operator calls
freezeToken(resourceId, chainIds)on the Hub'sTokenRegistry. The Hub adds the chain IDs to the token's freeze list and emitsTokenFreezeStatusChanged. - The Hub sends the token's freeze list to every chain in the network. Each chain stores it in its own token registry (
PNTokenRegistryV1). - 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:
| Operation | Effect |
|---|---|
| Enygma transfers from B | Refused on B's chain with RaylsApp__HubNotActive. Covers crossTransfer, crossTransferFrom, linearCrossTransfer and linearCrossTransferFrom. |
| Enygma transfers to B | Refused on the sender's chain, with TokenFreezeManagerV1__TokenFrozenForParticipant |
| DvP with an Enygma token on B | depositToDvp, callWithdrawFromDvp, swapWithDvpForERC721 and swapWithDvpForERC1155 revert on B's chain |
| DvP with an ERC-721 or ERC-1155 token on B | depositIntoDvp, swapWithDvpForEnygma and withdrawFromDvp revert on B's chain |
| Transfers between clients on B's own chain | Continue. The Hub freeze doesn't apply inside a chain. |
| Mint and burn by the token's owner on B's chain | Continue |
| The same token on other participants' chains | Continue, 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,200003The 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 200002unfreezeToken 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 afrozenChainIdsarray. - Hub:
isTokenFrozenForParticipant(resourceId, chainId)onTokenRegistry. - A participant's chain:
getHubStatus(tokenAddress)on itsPNTokenRegistryV1returnsFROZEN(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:
| Freeze | Call on the chain's PNTokenRegistryV1 | Effect |
|---|---|---|
| Chain freeze | freezeOnPrivacyNode(tokenAddress) / unfreezeOnPrivacyNode | Blocks 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.
Updated 8 days ago
