Concept
Transfers & Compliance
A send is decided in one place. tokenfactory.CanSendTokens is consulted for bank sends, NFT sends, and swap settlement alike. It evaluates in a fixed order: blacklist first, then the restricted-denom rule. There is no second, weaker path.
The decision engine: CanSendTokens
Every token movement on CenterChain -- bank sends, NFT transfers, swap settlements -- passes through a single function:tokenfactory.CanSendTokens. This is the single most important thing to understand about behavior: there is no second, weaker path.
Step 1: Blacklist
If sender or recipient is on the denom's blacklist, the send is rejected immediately. No exceptions.
Step 2: Restriction
If the denom has a restriction rule, the recipient must satisfy it (or be the admin/delegate). Otherwise, rejected.
Step 3: Standard checks
Balance sufficiency, denom existence, send-enabled flag. Only after blacklist and restriction pass.
What goes through CanSendTokens
Bank sends
Standard MsgSend / MsgMultiSend. Every denom, every amount.
NFT transfers
The NFT module calls CanSendTokens for the underlying denom before transferring.
Swap settlement
When a swap settles, the movement of tokens also passes through the same function.
IBC sends
Tokens leaving via IBC also pass through the same compliance layer.
Blacklist mechanics
- Managed by denom admin (or delegate) via
MsgAddToBlacklist/MsgRemoveFromBlacklist. - Applies to both sender and recipient -- a blacklisted address cannot send or receive.
- Cap: 100,000 blacklisted addresses chain-wide.
- Blacklist check runs before any other logic -- immediate rejection, no state changes.
Restricted-denom rule
- Set by denom admin via
MsgSetDenomRestriction. Defines who may hold/receive the denom. - Can be an allowlist (only these addresses) or a denylist logic via module config.
- Admin and delegates are always exempt from restriction.
- Checked after blacklist, before standard balance checks.
Ante handler integration
The ante handler wraps CanSendTokens so that every transaction carrying token movements is validated before execution. This means:
- Failed compliance = transaction rejected before state changes
- Gas is consumed for the check, but no state is mutated on rejection
- Errors are descriptive:
ErrBlacklisted,ErrRestricted,ErrInsufficientBalance
Read the full specification
Full message flow diagrams, error code reference, and integration patterns.