Locker
Contracts/src/contracts/Locker.sol
The Locker is the protocol’s central registry and NFT custodian. It owns
the CollectionToken clones (one per collection), holds the floor pool of
NFTs, and is the only contract authorised to call
NFTXV4Hook.registerCollection / initializeCollection.
Deployed addresses
| Chain | Address |
|---|---|
Base mainnet (8453) | see Frontend/packages/config/src/contracts.ts |
Base Sepolia (84532) | see Frontend/packages/config/src/contracts.ts |
State views
| Function | Returns |
|---|---|
tokenImplementation() | The shared CollectionToken master clone address |
implementation() | INFTXV4Hook — the Uniswap V4 hook |
lockerManager() | ILockerManager — manager allowlist |
listingsAt(uint _index) | The Nth registered IListings |
listingsLength() | Number of registered IListings |
collectionShutdown() | ICollectionShutdown — shutdown lifecycle |
collectionToken(address _collection) | The ICollectionToken clone for a registered collection |
collectionInitialized(address _collection) | True once the V4 pool is bootstrapped |
isCollectionToken(address _token) | Reverse lookup: is this address one of our clones |
collectionSunset(address _collection) | True for retired collections |
isListing(address _collection, uint _tokenId) | Whether (_collection, _tokenId) has an active liquid/dutch listing |
paused() | Pause flag |
permissionlessCreateCollection() | Whether non-owners can create collections |
collectionCreationFee() / collectionCreationFeeRecipient() | Fee for creating a new collection |
Public surface
Lifecycle
| Function | Caller | Description |
|---|---|---|
createCollection(_collection, _name, _symbol) | Anyone (or owner if permissionlessCreateCollection == false) | Registers an ERC-721 and deploys its CollectionToken clone. payable; msg.value == collectionCreationFee() enforced. Returns the clone address. |
initializeCollection(_collection, _eth, _tokenIds, _tokenSlippage, _sqrtPriceX96) | Approver of seed liquidity | Bootstraps the V4 pool. Forwards to NFTXV4Hook.initializeCollection. |
sunsetCollection(_collection) | Owner / CollectionShutdown | Permanently retires a collection (post-execute). |
withdrawToken(_collection, _tokenId, _recipient) | Owner | Emergency withdrawal of a stuck NFT. |
Errors: InvalidERC721, CollectionAlreadyExists, CollectionPreviouslySunset,
CollectionDoesNotExist, CollectionAlreadyInitialized,
CollectionCreationFeeDoesNotMatch(received, required),
CreateCollectionRestrictedToOwner, Paused.
Floor pool
| Function | Description |
|---|---|
deposit(_collection, _tokenIds) | Send NFTs in, receive tokenIds.length * 1e18 CollectionToken |
deposit(_collection, _tokenIds, _recipient) | Same, with custom recipient |
redeem(_collection, _tokenIds) | Burn 1e18 per token, receive the NFTs |
redeem(_collection, _tokenIds, _recipient) | Same, with custom recipient |
swap(_collection, _tokenIdIn, _tokenIdOut) | 1-for-1 NFT swap; CT-neutral |
swapBatch(_collection, _tokenIdsIn, _tokenIdsOut) | N-for-N variant |
Errors: NoTokenIds, TokenIdsLengthMismatch, CannotSwapSameToken,
TokenIsListing(_tokenId), InsufficientTokenIds, Paused.
Registry / governance
| Function | Caller | Description |
|---|---|---|
addListings(_listings) | Owner | Registers a new IListings contract |
removeListings(_listings) | Owner | De-registers an IListings contract |
setCollectionShutdownContract(_collectionShutdown) | Owner | Wires up the shutdown contract |
setCollectionCreationFee(_fee) | Owner | Updates createCollection fee |
setCollectionCreationFeeRecipient(_recipient) | Owner | Updates fee recipient |
setPermissionlessCreateCollection(_permissionless) | Owner | Toggles the open create-collection mode |
pause(_paused) | Owner | Pauses the protocol |
Errors: ListingsAlreadyRegistered, ListingsNotRegistered, ZeroAddress,
CannotChangeImplementation, UnapprovedCaller, CallerIsNotManager,
InvalidCaller.
Events
| Event | Notes |
|---|---|
CollectionCreated(_collection, _collectionToken, _name, _symbol, _creator) | New collection registered |
CollectionInitialized(_collection, _poolKey, _tokenIds, _sqrtPriceX96, _sender) | Pool bootstrapped |
CollectionSunset(_collection, _collectionToken, _sender) | Retired |
TokenDeposit(_collection, _tokenIds, _sender, _recipient) | Floor pool ↑ |
TokenRedeem(_collection, _tokenIds, _sender, _recipient) | Floor pool ↓ |
TokenSwap(_collection, _tokenIdIn, _tokenIdOut, _sender) | 1-for-1 swap |
TokenSwapBatch(_collection, _tokenIdsIn, _tokenIdsOut, _sender) | N-for-N swap |
ListingsContractAdded(_listings) / ListingsContractRemoved(_listings) | Registry mutations |
CollectionShutdownContractUpdated(_collectionShutdown) | Shutdown contract pointer |
CollectionCreationFeeUpdated(_collectionCreationFee) | Fee tweak |
CollectionCreationFeeRecipientUpdated(_collectionCreationFeeRecipient) | Recipient tweak |
PermissionlessCreateCollectionUpdated(_permissionless) | Toggle |
The Locker also forwards every floor mutation to the IListings
registry so each Listings contract can keep its derivative state in
sync. There is no separate Listings.deposit entry-point.
Inherited surface
Pausable—paused()/pause(bool).Ownable—owner()/transferOwnership(address).ReentrancyGuardon every state-changing entry-point.