Skip to main content
Version: 0.1.0

Transfers and compliance

Every send on CenterChain — bank, NFT, and swap settlement alike — passes through one function. The first rule that matches decides.

The blacklist​

A blacklist is a per-denom list of addresses. Being blocked on one token has no effect on any other, and a denom with no authority metadata is never subject to it.

  • Only the denom admin can add or remove an entry, and an account cannot blacklist itself.
  • Adding is idempotent; removing decrements a global counter.
  • The cap is 100,000 blacklisted addresses across the whole chain.
  • The check is absolute. It applies under an open policy, to admins, to delegates, and to the module authority.

The restricted-denom rule​

is_restricted is set by the denom admin. When it is set, a denom can only be sent to an address that already holds a balance of it, unless the sender is the admin, one of the delegates, or the send is an internal leg of a swap.

This is the on-chain circulation control: an issuer can close a token to new addresses while leaving existing holders able to trade among themselves.

:::note This is not a KYC list The rule tests a balance, not an identity. The chain can prove that a recipient already holds the token; it cannot prove who that recipient is. Treating this as an identity check would be a mistake in both directions — it blocks nothing extra, and it claims an assurance the chain cannot make. :::

The ante checks​

Two decorators wrap the ante handler, both from tokenfactory:

DecoratorWhenWhat it does
NFTSendCheckDecoratorEvery transactionWalks nft.MsgSend, including ones nested inside an authz.MsgExec up to eight levels deep, and rejects locked, blacklisted, or unknown-counterparty transfers.
ZeroBalanceCheckDecoratorCheckTx and simulate onlyRe-applies CanSendTokens to every MsgSend after the rest of the ante chain, so a simulation shows the true result.

The zero-balance decorator does not run in DeliverTx. It exists so that a dry run and a real transaction agree, not to change consensus behaviour.

Reservations​

A fungible swap authorization reserves max_from against the holder's balance. The reservation is enforced at the store layer: a wrapper around the bank's KV store rejects any write that would drop a balance below the amount open authorizations have reserved.

This holds regardless of which code path moved the funds. A transfer through the AMM, a direct send, a staking unbonding — anything that decreases the balance below the reservation fails.

Ordering with income​

Income prepends its send restriction and tokenfactory appends its own, so the order on every bank send is:

1. income settle both sides against their pre-transfer balances
2. tokenfactory blacklist, then restriction

Income must run first: a holder's entitlement is a function of the balance they had before the transfer. Checking compliance first would mean settling a balance that no longer exists.

Blocklist versus freeze​

The chain has no separate account-level freeze. What exists is:

MechanismScopeEffect
Per-denom blacklistOne denom, one addressNo send in that denom, by anyone
is_restrictedThe whole denomNo transfer to a new address, by anyone except the admin and delegates
Income blocklist checkThe claimantA claim is rejected outright for a blocklisted holder

A transfer barrier is not immutability. An admin can still burn, force transfer, or change the admin of a restricted denom. Restriction controls circulation; it does not protect the token from its own administrator.