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
| Function | Description |
|---|---|
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
| Function | Description |
|---|---|
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(onbuyNFTWithETH/redeemFloorWithETH) — hard cap on total ETH spent. Reverts withExcessiveInputif exceeded.- The combination defends against
Listings.modifyListingsfront-runs that move listing prices upward between simulation and execution.
Errors
| Error | Cause |
|---|---|
CollectionNotInitialized | Pool not bootstrapped |
InsufficientOutput(received, minimum) | Swap output below _minTokensReceived / _minETHReceived |
ExcessiveInput(spent, maximum) | Realised spend above _maxETHSpent |
NoTokenIds | Empty array |
ZeroTokenAmount | _tokenAmount == 0 |
UnauthorizedETHSender | ETH received from a contract that isn’t the Zap’s expected counterparty (flETH / V4 router) |
Events
| Event | Trigger |
|---|---|
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.