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
| Function | Returns |
|---|---|
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
| Function | Description |
|---|---|
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
| Function | Caller | Description |
|---|---|---|
depositFees(_collection, _amount0, _amount1) | Listings (or admin) | Queues fees in the pool’s V4-sorted currency order; emits PoolFeesQueued |
Admin
| Function | Description |
|---|---|
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
| Error | Cause |
|---|---|
NotImplemented | A V4 hook callback that the protocol explicitly disables was invoked |
ZeroAddress | Invariant violation in admin setter |
LPRecipientIsZeroAddress | initializeCollection recipient is zero |
UnknownCollection | Hook lookup against an unregistered collection |
CannotBeInitializedDirectly | V4 PoolManager.initialize was called outside initializeCollection |
PoolNotInitialized | Hook callback before pool initialization completes |
CallerIsNotLocker | Privileged 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
| Event | Notes |
|---|---|
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
| Event | Notes |
|---|---|
PoolStateUpdated(_collection, _sqrtPriceX96, _tick, _protocolFee, _swapFee, _liquidity) | Emitted after every transaction that reads the slot |
Fee config
| Event | Notes |
|---|---|
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
| Event | Notes |
|---|---|
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 arebeforeInitialize,afterInitialize,beforeSwap,afterSwap,beforeAddLiquidity. Outside of these the hook reverts withNotImplemented.BaseOracle— TWAP oracle used bygetFeeand read paths. Public views:observe(_poolId, _secondsAgos)returning the standard V4 oracle cumulative arrays.TokenEscrow—withdraw(_recipient, _token, _amount)andbalances(_recipient, _token). Both AMM beneficiary claims and any refunded escrow live here.Ownable,ReentrancyGuard.