Skip to main content
Version: 1.2.0

Application wiring

This page describes how the five modules are assembled into the application: registration order, what runs in each block, and the three mechanisms the chain uses to connect modules to each other.

:::note Naming x/nft is the Go package; nftrwa is the module name, the store key, and the query prefix. There is no centerchain.v1 core module: the five directories under proto/centerchain/ are income, liquidity, nft, nftmarket, and tokenfactory. :::

Registered modules​

Beyond the standard Cosmos SDK modules, the application registers:

ModuleOn-chain nameStore keyConsensus version
Token factorytokenfactorytokenfactory3
Liquidityliquidityliquidity5
NFTnftrwanftrwa1
NFT marketnftmarketnftmarket1
Incomeincomeincome1

IBC is registered outside the app-config composition path, together with the transfer application, interchain accounts, the 07-tendermint light client, and the 06-solomachine light client. There is no CosmWasm module.

Order matters​

InitGenesis runs tokenfactory before nftmarket, because the market's genesis import reads IsDenomRestricted to fail closed on a restricted denom in a listing price or an accepted-denom list.

The five CenterChain modules run last in all three lifecycle lists, after the standard modules, in the order nftrwa, nftmarket, tokenfactory, liquidity, income.

Block execution​

ModuleBeginBlockEndBlock
nftrwaNo-opNo-op
nftmarketPrunes up to 200 expired listingsNo-op
tokenfactoryPrunes expired authorizations and spent claim markersNo-op
liquidityLoads state, activates due fee updates, settles every emission scheduleIn-memory invariants every block; bank reconciliation every 10,000 blocks
incomeNo-opSolvency check every 10,000 blocks

Both invariant checks emit an alarm event and return no error. A violated invariant is therefore observable in the event stream without halting the chain.

How modules connect​

The chain does not use the SDK's SendHooks interface anywhere. It uses three other mechanisms instead.

1. Bank send restrictions​

Two modules append a function to the bank's restriction list:

ModuleCallPosition
incomePrependSendRestrictionRuns first.
tokenfactoryAppendSendRestrictionRuns last.

The order is deliberate: income must checkpoint a holder's accrual against the pre-transfer balance before tokenfactory decides whether the transfer is allowed at all.

2. The NFT transfer policy​

The vendored cosmossdk.io/x/nft fork exposes a package-level transfer policy. tokenfactory installs itself as that policy, so every NFT send is evaluated by the same blacklist and restriction logic as a bank send.

A second ante decorator, NFTSendCheckDecorator, re-checks NFT sends — including ones nested inside an authz.MsgExec, up to eight levels deep — and rejects locked, blacklisted, or unknown-counterparty transfers before they reach the handler.

3. Named burn hooks​

x/nft keeps a named hook registry that runs on every burn in sorted order. Two hooks are registered:

NameRegistered byEffect
incomex/incomeReleases the token's earmarked claimable.
nftmarketx/nftmarketRefunds the listing deposit and clears the listing.

The first hook to return an error aborts the burn and rolls the transaction back.

5. Keeper injection and the fee ante​

The remaining coupling is direct keeper wiring rather than hooks:

  • liquidity registers itself with tokenfactory as the module allowed to create and mint LP denoms, and injects the tokenfactory keeper as its denom eligibility and restriction source.
  • nftmarket injects the tokenfactory keeper to read the restricted-denom rule.
  • income injects the tokenfactory keeper to read authority metadata and the blacklist, and the NFT keeper for the burn hook.
  • liquidity is given an IBC asset-health checker that verifies the transfer module's denom trace, the channel, the connection, and the client state.

tokenfactory also installs a fee ante decorator. For a transaction carrying a MsgExecute*, it charges the authorization holder in ucen, enforces the signed max_fee, marks the authorization attempted, and rejects a nested or multi-message execution. There is no reservation store wrapper since v1.2: authorizations no longer reserve balances or lock NFTs.

Ante handler​

The existing ante chain is wrapped by three tokenfactory decorators:

FeePayerDecorator // outer
NFTSendCheckDecorator // inner
ZeroBalanceCheckDecorator
... the pre-existing ante chain ...

FeePayerDecorator implements the v1.2 settlement-fee rule. NFTSendCheckDecorator re-checks NFT sends, including ones nested inside an authz.MsgExec. ZeroBalanceCheckDecorator runs only in CheckTx and simulate, and re-applies CanSendTokens to every MsgSend in the transaction after the rest of the chain has run. Its purpose is to make the result visible in a simulation, not to change consensus behaviour.

Module accounts​

AccountPermissionsBlocked from receiving
tokenfactoryMinter, burnerNo
liquidityMinter, burnerYes
nftNoneYes
nftmarketNoneYes
incomeNoneNo — the yield pool must be able to receive

The liquidity module also creates per-pool accounts on demand: liquidity-reserve-{id}, liquidity-farm-{id}, and liquidity-fee-{id}.

Chain identity​

SettingValue
Bech32 account prefixcenter
Validator prefixescentervaloper, centervalcons
Bond and mint denomucen
Base and display denomucen / cen, symbol CEN, exponent 6

Upgrades​

The application registers the plan names v0.55 and v1.1. The handler runs RunMigrations with the version map the chain carried in. The registered migrations are:

ModuleFromToMigration
liquidity12MigrateLegacyState
liquidity23MigrateFarmLockDurationBound
liquidity34MigratePoolLifecycleParams
liquidity45MigratePoolFeeCounters
tokenfactory12MigratePoolPolicyGenesisV2
tokenfactory23MigrateSwapAuthorizationKindV3

The tokenfactory 1→2 migration seeds the three genesis counters — factory denoms, pool policies, and blacklisted addresses — that the state limits depend on. The 2→3 migration binds every pre-existing authorization to SWAP.

There is no v1.2 plan. v1.2 keeps tokenfactory at consensus version 3 and ships no migration, because a v1.2 network starts from a new genesis. See Upgrading a network.