ContractsNFTXV4Hook

NFTXV4Hook

Contracts/src/contracts/NFTXV4Hook.sol
Public interface: Contracts/src/interfaces/INFTXV4Hook.sol

The single Uniswap V4 hook implementation registered against the Locker. Owns:

  • Per-collection V4 pool config (PoolParams).
  • Pool-fee queue / donate lifecycle (replaces the legacy receive/distribute/swap pipeline).
  • AMM fee + beneficiary; per-beneficiary flat-fee overrides.
  • AMM-fee escrow (inherited from TokenEscrow).
⚠️

As of May 2026 this contract is the renamed UniswapV4Implementation and INFTXV4Hook is the renamed IBaseImplementation. All errors, events, and structs have moved into the interface so external integrators have a single source of truth.

State views

FunctionReturns
nativeToken()The ETH-equivalent ERC-20 paired against every CollectionToken (typically flETH)
getCollectionPoolKey(_collection)Encoded V4 PoolKey bytes
poolParams(_poolId)(collection, poolFee, initialized, currencyFlipped)
getFee(_poolId, _origin)Resolved swap fee (override → poolFee → defaultFee)
feeOverrides(_beneficiary)Encoded override ((flatFee \<\< 24) | 0xFFFFFF when active, 0 otherwise)
defaultFee()Global LP fee
ammFee()AMM cut taken from the unspecified swap leg
ammBeneficiary()AMM cut recipient (or address(0) to burn)

Public surface

Locker-only

FunctionDescription
registerCollection(_collection, _collectionToken)Called by Locker.createCollection
initializeCollection(_collection, _eth, _tokens, _amount1Slippage, _sqrtPriceX96, _recipient)Called by Locker.initializeCollection; mints the LP NFT to _recipient

Both revert with CallerIsNotLocker if any other address calls them.

Listings + admin

FunctionCallerDescription
depositFees(_collection, _amount0, _amount1)Listings (or admin)Queues fees in the pool’s V4-sorted currency order; emits PoolFeesQueued

Admin

FunctionDescription
setDefaultFee(_defaultFee)Update the global LP fee
setFee(_poolId, _fee)Per-pool LP override (0 = use default)
setAmmFee(_ammFee)Update AMM cut
setAmmBeneficiary(_ammBeneficiary)Update AMM beneficiary (address(0) = burn)
setFeeExemption(_beneficiary, _flatFee)Per-beneficiary flat fee override
removeFeeExemption(_beneficiary)Clear override

Structs

struct PoolParams {
  address collection;
  uint24 poolFee;
  bool initialized;
  bool currencyFlipped;  // nativeToken > collectionToken (collection sits on currency0)
}
 
struct PendingDonation {
  uint128 amount0;
  uint128 amount1;
}

Errors

ErrorCause
NotImplementedA V4 hook callback that the protocol explicitly disables was invoked
ZeroAddressInvariant violation in admin setter
LPRecipientIsZeroAddressinitializeCollection recipient is zero
UnknownCollectionHook lookup against an unregistered collection
CannotBeInitializedDirectlyV4 PoolManager.initialize was called outside initializeCollection
PoolNotInitializedHook callback before pool initialization completes
CallerIsNotLockerPrivileged entry-point invoked by anyone other than the registered Locker
FeeExemptionInvalid(_invalidFee, _maxFee)setFeeExemption over the V4 max LP fee
NoBeneficiaryExemption(_beneficiary)removeFeeExemption for a beneficiary with no override

Events

Pool fee lifecycle

EventNotes
PoolFeesQueued(_collection, _amount0, _amount1)Fees enqueued via depositFees; awaiting next swap
PoolFeesDonated(_collection, _amount0, _amount1)Fees donated to LPs in the next swap callback

Pool state

EventNotes
PoolStateUpdated(_collection, _sqrtPriceX96, _tick, _protocolFee, _swapFee, _liquidity)Emitted after every transaction that reads the slot

Fee config

EventNotes
DefaultFeeSet(_fee)Global LP fee updated
PoolFeeSet(_collection, _fee)Per-pool override
AMMFeeSet(_ammFee)AMM cut updated
AMMBeneficiarySet(_ammBeneficiary)AMM beneficiary updated
AMMFeesTaken(_recipient, _token, _amount)AMM cut realised on a swap; _recipient may be address(0) (burn)
FeeOverrideSet(_beneficiary, _flatFee)Per-beneficiary flat fee set/updated
FeeOverrideRemoved(_beneficiary)Per-beneficiary flat fee cleared

Inherited from TokenEscrow

EventNotes
Deposit(_payee, _token, _amount)Funds escrowed (e.g. AMM cut)
Withdrawal(_payee, _token, _amount)withdraw claim

Inherited surface

  • BaseHook — full V4 hook callback set; the public ones used here are beforeInitialize, afterInitialize, beforeSwap, afterSwap, beforeAddLiquidity. Outside of these the hook reverts with NotImplemented.
  • BaseOracle — TWAP oracle used by getFee and read paths. Public views: observe(_poolId, _secondsAgos) returning the standard V4 oracle cumulative arrays.
  • TokenEscrowwithdraw(_recipient, _token, _amount) and balances(_recipient, _token). Both AMM beneficiary claims and any refunded escrow live here.
  • Ownable, ReentrancyGuard.