Architecture
NFTX’s on-chain surface is small but layered. Three contracts handle the hot path; everything else is auxiliary.
Contracts at a glance
| Contract | What it owns | Key public surface |
|---|---|---|
Locker | Collection registry, CollectionToken clones, NFT custody. | createCollection, initializeCollection, deposit, redeem, swap, swapBatch. |
Listings | Liquid + dutch + floor listings, tax accounting. | createListings, fillListings, relist, modifyListings, cancelListings, extendListings, transferOwnership. |
NFTXV4Hook | Uniswap V4 hook for every collection pool, AMM-fee escrow, fee config. | registerCollection, initializeCollection, depositFees, setDefaultFee, setFee, setAmmFee, setAmmBeneficiary, setFeeExemption, removeFeeExemption, withdraw (escrow). |
CollectionToken | One ERC-20 clone per collection. | Standard ERC-20 + permit; minted/burned by Locker only. |
LockerManager | Ops gate for privileged manager mints (Locker.unbackedDeposit). | setManager, isManager. |
TokenEscrow | Per-payee, per-token claimable balances. Inherited by Listings and NFTXV4Hook. | withdraw, balances. |
CollectionShutdown | Quorum-based shutdown lifecycle. | start, vote, reclaimVote, execute, claim, cancel, preventShutdown. |
AirdropRecipient | Merkle-distributed airdrops on top of CT supply. | requestAirdrop, distributeAirdrop, claim, setAirdropTarget. |
TaxCalculator | Pure tax math for listings. | calculateTax, getProtectedListingHealth. |
NFTXZap | Convenience wrapper to bootstrap a pool. | zap. |
Pool fee lifecycle
This is the part the FE most often needs to render correctly:
- Listings charges tax on liquid/dutch listings; relevant slices flow into
Listings.depositFees(collection, amount). NFTXV4Hook.depositFeesstores the deposit on the hook against the collection’s V4-sorted(currency0, currency1)and emitsPoolFeesQueued(collection, amount0, amount1).- On the next swap that touches the pool, the hook donates the queued amount
back to LPs via the V4
donatemechanic and emitsPoolFeesDonated(collection, amount0, amount1). - The subgraph mirrors this:
PoolFees.queuedAmount0/1increments onPoolFeesQueuedand clears onPoolFeesDonated, whiletotalDonated0/1accumulates lifetime amounts.
⚠️
The pre-rename “PoolFeesReceived / PoolFeesDistributed /
PoolFeesSwapped” pipeline has been retired. If any FE code is still
reading those events or PoolFees.ethAvailable / tokenAvailable /
totalEthOut / totalTokenIn fields, it must be migrated to the queued /
donated pair documented above.
AMM fee + beneficiary
The hook also takes a configurable AMM cut on top of the LP fee:
NFTXV4Hook.setAmmFee(uint24)— basis-points-style fee taken from the unspecified leg of every swap.NFTXV4Hook.setAmmBeneficiary(address)— recipient of the AMM cut. May beaddress(0), in which case the cut is burnt.- Per-beneficiary
FeeOverrideSet(beneficiary, flatFee)/FeeOverrideRemoved(beneficiary)— flat fee applied when a swap is routed through the beneficiary; replaces the previous “beneficiary royalty” model. - The cut is escrowed into the same
TokenEscrowthat backs listing refunds; the beneficiary callsNFTXV4Hook.withdraw(token)(inherited fromTokenEscrow) to claim.
Config.ammFee, Config.ammBeneficiary, and the per-beneficiary
FeeOverride rows in the subgraph reflect these states 1-for-1.