ContractsNFTXZap

NFTXZap

Contracts/src/contracts/zaps/NFTXZap.sol
Interface: Contracts/src/interfaces/INFTXZap.sol

Convenience wrapper that lets users buy/sell NFTs with raw ETH (no intermediate flETH / CollectionToken bookkeeping). Internally the Zap wraps/unwraps flETH and routes through the V4 PoolManager + Listings.

The frontend’s “Buy now” / “Sell” buttons almost always use these entry-points. Hand-rolled Listings.fillListings is reserved for the cases where the user already holds CollectionToken directly (e.g. arbitrage flows).

Public surface

NFT ↔ ETH

FunctionDescription
buyNFTWithETH(_collection, _tokenIdsOut, _minTokensReceived, _maxETHSpent)ETH → flETH → CT → fill listings → NFT to user. Returns ethSpent_.
sellNFTForETH(_collection, _tokenIds, _minETHReceived)NFT → Locker.deposit → swap CT→flETH → unwrap → ETH to user. Returns ethReceived_.
redeemFloorWithETH(_collection, _tokenIds, _maxETHSpent)ETH → swap → CT → Locker.redeem → NFT to user. Returns ethSpent_.

Token ↔ ETH

FunctionDescription
buyTokensWithETH(_collection, _minTokensReceived)ETH → flETH → swap → CT to user. Returns tokensReceived_.
sellTokensForETH(_collection, _tokenAmount, _minETHReceived)CT → swap → flETH → ETH to user. Returns ethReceived_.
sellTokensForETHWithPermit2(_collection, _tokenAmount, _minETHReceived, _deadline, _nonce, _signature)Same as sellTokensForETH but pulls the CT via Permit2 SignatureTransfer (no separate approval tx).

Sandwich + slippage protection

Every entry-point exposes either a min/max bound on the realised swap output, and the buy paths thread FillListingsParams.maxSpend through to Listings.fillListings:

  • _minTokensReceived / _minETHReceived — slippage on the V4 swap itself.
  • _maxETHSpent (on buyNFTWithETH / redeemFloorWithETH) — hard cap on total ETH spent. Reverts with ExcessiveInput if exceeded.
  • The combination defends against Listings.modifyListings front-runs that move listing prices upward between simulation and execution.

Errors

ErrorCause
CollectionNotInitializedPool not bootstrapped
InsufficientOutput(received, minimum)Swap output below _minTokensReceived / _minETHReceived
ExcessiveInput(spent, maximum)Realised spend above _maxETHSpent
NoTokenIdsEmpty array
ZeroTokenAmount_tokenAmount == 0
UnauthorizedETHSenderETH received from a contract that isn’t the Zap’s expected counterparty (flETH / V4 router)

Events

EventTrigger
NFTBoughtWithETH(_collection, _nftCount, _ethSpent, _buyer)buyNFTWithETH
NFTSoldForETH(_collection, _tokenIds, _ethReceived, _seller)sellNFTForETH
TokensBoughtWithETH(_collection, _tokensReceived, _ethSpent, _buyer)buyTokensWithETH
TokensSoldForETH(_collection, _tokensSold, _ethReceived, _seller)sellTokensForETH
FloorRedeemedWithETH(_collection, _tokenIds, _ethSpent, _redeemer)redeemFloorWithETH

Inherited surface

  • ReentrancyGuard.
  • A guarded receive() so only flETH / the V4 router can send ETH.