# Introducing V3

The new and improved NFTX protocol.

NFTX V3 is our biggest release yet, including over 3,700 lines of audited solidity and a newly built web app. V3 aims to solve some of the biggest challenges with V2 while providing an improved foundation for us to continue building new releases.&#x20;

The most significant update with V3 is that NFTX now includes its own concentrated liquidity AMM, a forked version of Uniswap V3 with support for proportional vault fees to LPs. Other changes include vault fees in ETH (not vToken), inventory and liquidity provision represented using ERC721, and a new feature called premium fees that works like a Dutch auction for newly deposited NFTs. Much consideration went into designing V3, and we are confident that the user and developer experiences will benefit from the changes.&#x20;

Reputable security firms have audited V3, but it is essential to remember that no matter how well audited a protocol is, there is always the possibility of uncaught vulnerabilities. The NFTX DAO plans on migrating treasury assets over gradually out of caution, and we highly recommend that users are similarly cautious. The risks associated with a new protocol are highest when it first launches, so it's best to treat the early weeks as a beta period.&#x20;

We hope you enjoy learning more about V3 and experimenting with its new functionality. We are very excited about this release and are already working on plans for V3.1. So strap in, buckle up, and enjoy the ride.

P.S. L2 support coming soon.


# V2/V3 Comparison

Summary of V3, relative to V2.

## Main Points&#x20;

* **Separate deployments** — NFTX V2 will continue to run separately from NFTX V3. All vaults/vTokens on NFTX V3 use fresh deployment addresses. P*arts of this document refer to V2 in the past tense, but this is merely to aid comprehension. V2 will continue running in the future as it is now.*
* **NFTX AMM** — NFTX V3 uses its own AMM (a fork of Uniswap V3) instead of using Sushiswap. All pools on the NFTX AMM have pairs of the form vToken/WETH and have trading fees of 0.3% or 1%. All AMM fees go to LPs, but to receive vault fees (from mints, redeems, and NFT swaps), LPs must use the default 0.3% fee tier.&#x20;
* **Liquidity-based vault fees for LPs** — In V2, vault fees were distributed to all LPs at the same rate because all liquidity occupied an infinite range. In V3, vault fees are distributed to LPs at unique rates based on how much liquidity they provide around the current price—just like how AMM fees get distributed.&#x20;

*Now that NFTX V3 has its own AMM, the term "swap" can refer to both NFT-to-NFT vault swaps and vToken-WETH AMM swaps. When talking about mints, redeems, vaults, or vault fees, "swap" will usually refer to NFT-to-NFT swaps, but when discussing the AMM, the protocol as a whole, or the web UI, "swap" will usually refer to vToken-WETH swaps.*&#x20;

## Vaults

* **No more randomness** — NFTX V3 vaults offer minting, target-redeeming, and target-swapping, but not random-redeeming or random-swapping. In V3, a "redeem" implies a target-redeem, and "swap" implies a target-swap.&#x20;

## **Vault Fees**

* **Vault fees in ETH** — In V2, vault fees were paid and received in vToken. In V3, vault fees are paid and received in ETH and calculated using vToken TWAPs.&#x20;
* **Default 3/3/3 vault fees —** Like V2, V3 allows custom vault fee settings for mints, redeems, and swaps. In V2, the UI suggested default fee settings of 5/2/3/2/5 for mints, random-redeems, target-redeems, random-swaps, and target-swaps. In V3, the UI suggests default fee settings of 3/3/3 (mint/redeem/swap), represented as a flat 3%.&#x20;

*With V2, inventory stakers collected vault fees via xToken appreciation, and liquidity stakers collected yield by claiming vToken. In V3, both inventory stakers and LPs (in 0.3% pools) receive vault fees by claiming ETH.*

## Inventory & Liquidity

* **ERC721 positions** — NFTX V2 represented inventory and liquidity positions using ERC20 xTokens and xSLPs. Now, in V3, inventory and liquidity positions are represented using ERC721 NFTs. We refer to inventory staking positions in V3 as xNFTs, and instead of xSLPs, NFTX V3 uses UniV3-style liquidity positions from the NFTX AMM.&#x20;
* **Less restrictive timelocks** — NFTX V2 implemented timelocks as ERC20 transfer locks on stakers' wallets. NFTX V3 enforces timelocks on the NFT positions rather than their owners' addresses. This change means that accounts can move inventory and liquidity positions around while they are locked. Inventory staking timelocks are also 3 days in V3 instead of 7 days.
* **No more liquidity "staking"** — In V2, liquidity provision occurred on Sushiswap, and then SLP tokens were "liquidity staked" on NFTX. In V3, liquidity staking happens implicitly when an LP provides liquidity for a vToken's 0.3% fee pool.
* **Target NFT off-ramping** — In V2, only inventory stakers could receive NFTs (instead of vToken) when unstaking/off-ramping. In V3, inventory stakers *and* LPs can choose to receive NFTs when off-ramping. Another change is that, unlike V2, which used random redeeming when stakers off-ramp, in V3, inventory stakers and LPs can select which NFTs they wish to receive when off-ramping.&#x20;
* **One-hour timelocks for positions made with vToken** — Like V2, V3 allows users to onramp into an inventory or liquidity position using vToken or NFTs. In V3, inventory and liquidity positions are subject to only a 1-hour timelock (instead of 2-3 days) if the staker/LP accepts only being able to off-ramp back to vToken (not NFTs).&#x20;
* **Early withdrawal mechanism** — In V2, stakers had to wait until a timelock had ended before unstaking their position. In V3, it is possible to withdraw a position before its timelock ends by paying an early withdrawal fee. The early withdrawal fee is paid in vToken, begins at 10%, and goes down linearly to zero over the timelock's duration.

## New Features

* **Premium fees** — In V3, NFTs have an added "premium fee" if they have been transferred into the vault recently. The premium fee begins at 500% (of 1 vToken) and goes down to 0% over 10 hours. The premium fee is charged in ETH and determined by the vToken's TWAP. The fee distributor sends 90% of the proceeds to the address that sold the NFT into the vault (or that deposited the NFT as part of inventory staking or LPing). The remaining 10% is distributed as regular vault fees.&#x20;

*If an inventory staker or LP who is off-ramping in V3 wishes to receive an NFT that has a premium fee, they are required to pay the premium fee in ETH as part of the off-ramping process.*


# Protocol Overview

A non-technical V3 primer.

## Abstract

NFTX is a protocol for (A) wrapping similar-value NFTs into fungible ERC20 "vTokens" and (B) incentivizing liquid markets for those vTokens, which, in turn, creates liquid markets for the NFTs. Every vToken contract also acts as a vault for holding its respective NFTs, allowing the terms "vToken" and "vault" to be used interchangeably. vTokens are backed 1:1 by NFTs, so if there are 100 CryptoPunks in the PUNK vault, there is 100 PUNK in circulation.&#x20;

When a user buys an NFT on NFTX, the exchange goes ETH —> vToken -> NFT, meaning that the user sends ETH, it is wrapped and traded for vToken via the AMM, and then the vToken is burned for the NFT, which is sent back to the user after deducting a redeem fee in ETH. Alternatively, when a user sells an NFT on NFTX, the exchange goes NFT -> vToken -> ETH, meaning that the user sends their NFT to the vault in return for one newly minted vToken. Then, the vToken is sold for WETH, which is sent back to the user after deducting a mint fee. Vaults charge fees in ETH when a user buys, sells, or swaps an NFT, and AMM pools charge fees in vToken or WETH for each vToken-WETH trade. All fees generated go to inventory and liquidity providers. Inventory staking and liquidity provision are the two ways to earn yield with vTokens on NFTX. Inventory staking only requires staking vToken/NFTs and is designed to incentivize more NFT deposits and, therefore, greater diversity of NFTs for end-users. Inventory stakers receive 20% of ETH from vault fees. Alternatively, for liquidity providers (LPs), the experience is similar to LPing on Uniswap V3. However, LPs on NFTX can earn 80% of the ETH vault fees on top of their AMM trade fees.

NFT owners must remember that if they deposit an NFT into an NFTX vault, they may never get it back. When an NFT gets sent to a vault, the owner effectively gives up ownership in return for one vToken, which grants them ownership of *any* NFT in the vault, but not necessarily the NFT they deposited (if someone else took it first). Vaults are designed to attract the most affordable layer of "floor" NFTs to get deposited to create a fungible primitive, vTokens, that can power a range of DeFi/NFT use cases.

## Vault Creation & Management

Creating a vToken/vault can be done using the Vault Factory contract. Each vault gets linked to an ERC721 or ERC1155 collection. By default, vaults are set to "allow all items," meaning any NFT tokenID from their linked collection is eligible for minting. If "allow all items" is not turned on, the vault requires an eligibility module to declare which token IDs are valid. Some eligibility modules are a simple list or range of numbers. Others are more complicated and use custom logic or Merkle trees, such as the 4-digit ENS "NNNN" vault (on NFTX V2).&#x20;

Each vault, upon creation, has its "manager" set to its creator's address. Vault managers can modify vault settings and call permissioned functions. They can also remove themselves as manager by calling the finalizeVault function. Typically, vaults should only be considered ready for public use after the vault manager has given up their control by finalizing the vault.&#x20;

## Minting, Redeeming, Swapping

The three primary vault operations are minting, redeeming, and swapping. Minting is when a user sends one or more NFTs to a vault and receives newly minted vToken. Redeeming is when a user burns vToken and receives one or more NFTs. Swapping is when a user swaps NFTs in their wallet for NFTs from a vault. All three vault operations have percentage-based fees paid in ETH, determined using the vToken's TWAP. For example, if a user swaps a CryptoPunk from their wallet for a CryptoPunk in the PUNK vault, and the swap fee is 3%, then the user is required to pay 3% of the cost of 1 PUNK vToken in ETH, which the fee distributor passes on as vault fees for inventory stakers and LPs. The global/default vault fees are 3% mint, 3% redeem, and 3% swap, but it is also possible for vaults to have custom fee settings.

## Buying & Selling (and Swapping)

When a user buys an NFT from NFTX with ETH, behind the scenes, most of the ETH is used to purchase one vToken, and then that vToken is burned in return for one NFT from the vault. The remainder of the ETH is sent to the fee distributor as the vault's redeem fee. When a user sells an NFT on NFTX, behind the scenes, the NFT is used to mint one vToken, then that vToken is sold for WETH, a small portion of the WETH is sent as a mint fee, and the remaining amount is returned to the seller. As described above, it is also possible for a user to swap an NFT in their wallet for an NFT in a vault. During an NFT swap, no vTokens are bought, sold, minted, or burned—the NFT in the wallet is swapped with the NFT in the vault, and a swap fee is paid in ETH.

## Liquidity Provision

NFTX V3 has its own AMM that is a fork of Uniswap V3 and which pairs vTokens with WETH. There are two fee tiers for vToken AMM pools: 0.3% and 3%. Like UniV3, NFTX AMM fees are paid in the paired tokens (i.e., vTokens and WETH). LPs who provide liquidity on NFTX in the 0.3% fee pools also receive vault fees (i.e., fees from mints, redeems, and NFT swaps) as part of claiming AMM fees. Vault fees for LPs are distributed using the built-in fee distribution for AMM pools, meaning that LPs providing deeper liquidity earn a larger portion of vault fees—just like how AMM fees are distributed.&#x20;

## Inventory Staking

vTokens can also be used for inventory staking, which is when a user stakes vToken to earn a portion of vault fees. Vault fees are split 80/20 between liquidity providers (using the 0.3% fee pools) and inventory stakers. Unlike LPs, who claim ETH vault fees along with their vToken and ETH AMM fees, inventory stakers only claim ETH vault fees. Inventory staking aims to increase the number of NFTs in a vault from which buyers and swappers can choose. Inventory staking also allows stakers to earn yield from vTokens without taking on IL (impermanent loss) risk or actively managing an LP position.&#x20;

## On-ramping & Off-ramping

The process of creating or increasing an inventory or liquidity position on NFTX is referred to as on-ramping, and the reverse is called off-ramping. Inventory stakers can on-ramp by depositing NFTs or vToken, and LPs can on-ramp by depositing NFTs + ETH or vToken + ETH. When a user on-ramps using NFTs instead of vToken, behind the scenes, the NFTs are first used to mint vToken. Minting like this, as a means of on-ramping, does not charge a mint fee. Likewise, when an inventory staker off-ramps, they can choose NFTs or vToken, and when an LP off-ramps, they can choose NFTs + ETH or vToken + ETH. When an inventory provider or LP off-ramps to NFTs (or NFTs + ETH), the NFTs are redeemed behind the scenes using vToken, but no redeem fee is charged.

## Positions & Timelocks

Inventory staking positions are represented using ERC721 "xNFTs" implemented in the NFTX InventoryStaking contract. LP positions are implemented using a modified version of UniV3's NonfungiblePositionManager. Both inventory and liquidity positions incur "timelocks" when they are created that prohibit them from being unstaked/withdrawn. The liquidity timelock duration is two days, and the inventory timelock duration is three days—unless the staker/LP has opted for a 1-hour timelock on the condition that they cannot off-ramp or on-ramp using NFTs. The primary purpose of timelocks is to deter users from circumventing vault fees (for buys, sells, and swaps) by on-ramping with one asset type (or token ID) and immediately off-ramping with another.&#x20;

When on-ramping into an inventory or liquidity positions, users can receive a 1-hour timelock (as opposed to 2 or 3 days) if they on-ramp using vToken and if they are okay to off-ramp back to vToken when finished (instead of NFTs). If users prefer to have the option of off-ramping to vToken *or* NFTs, then they can choose to enforce a full (2 or 3-day) timelock when on-ramping with just vToken. \
\
Most positions allow the owner to override the timelock by paying an early withdrawal fee. The early withdrawal fee is paid in vToken, begins at 10%, and goes down linearly to zero over the duration of the timelock. Early withdrawal is supported for all positions except inventory positions during the first hour after they have been created or increased. Early withdrawal fees paid by inventory stakers are used to increase the vToken backing of all inventory positions (i.e., the vTokenShares for each inventory position end up being worth more vToken). Early withdrawal fees paid in vToken by liquidity providers get distributed to LPs (in the 0.3% pool) as AMM fees, which remaining LPs can then claim.

## Premium Fees

Users who wish to retrieve an NFT from a vault (by redeeming or swapping) must pay a "premium fee" if the NFT was recently minted into the vault. The premium fee is paid in ETH, begins at 500% (of 1 vToken), and decays to zero over 10 hours. Of the proceeds, 90% is given to the address that sold/swapped the NFT into the vault or deposited the NFT as part of inventory staking or LPing. The remaining 10% is distributed as regular vault fees.&#x20;

&#x20;


# Protocol Repo

Notes on V3 protocol contracts.

## Overview

NFTX is a protocol for incentivizing liquid markets for illiquid Non-Fungible Tokens (NFTs).\
Users deposit their NFTs into an NFTX vault to mint a fungible ERC20 token (vToken). This vToken can be burned to redeem any NFT from the vault by paying a redeem fee in ETH.\
\
vTokens can also be used to earn yield by:

1. Depositing into InventoryStaking to earn ETH (from vault fees) + vTokens (from early withdrawal fees)
2. Pairing the vTokens with ETH and providing concentrated (or infinite-range) liquidity into the NFTX AMM to earn trading fees and additional ETH (from vault fees).

***

Core contracts:

1. `NFTXVaultUpgradeableV3`
2. `NFTXVaultFactoryUpgradeableV3`
3. `NFTXFeeDistributorV3`
4. `NFTXInventoryStakingV3Upgradeable`
5. `UniswapV3FactoryUpgradeable`
6. `UniswapV3PoolUpgradeable`
7. `NonfungiblePositionManager`
8. `NFTXRouter`

Zaps:

1. `CreateVaultZap`
2. `MarketplaceUniversalRouterZap`
3. `MigratorZap`

## Core Contracts

### 1. NFTXVaultUpgradeableV3

Main operations:

i. `mint`: Deposits NFTs into the vault in exchange for minting vault tokens.\
ii. `redeem`: Burns vault tokens in exchange for redeeming NFTs from the vault.\
iii. `swap`: Swaps an array of NFTs into a desired array of NFTs from the vault.

All of the above operations require the user to pay vault fees in ETH, calculated as a % of the \~20 min TWAP of the vToken from the AMM pool (with fee tier = `FeeDistributor.rewardFeeTier()`). If the pool doesn't exist, no vault fees are charged.\
\
The vault fees collected are sent to the `NFTXFeeDistributorV3` in the same transaction to be distributed to inventory stakers and liquidity providers (LPs).

Users wishing to redeem (or swap out) a newly deposited NFT must pay an ETH "premium fee" in addition to ETH vault fees. The premium fee for an NFT is highest right after it is deposited and goes down exponentially until it reaches zero. The proceeds from a premium fee are shared between the original NFT depositor of the redeemed tokenId and the vault stakers/LPs. \
\
Additional features:

* Flash-minting. The fee for flash-minting is paid in ETH and is the highest of the vault's mint, redeem, and swap fees. The ETH proceeds from the fee are sent to inventory stakers for the vault.&#x20;
* Using Eligibility modules to only allow certain tokenIds into the vault.

### 2. NFTXVaultFactoryUpgradeableV3

Allows for the deployment of Vaults as Beacon Proxies.

### 3. NFTXFeeDistributorV3

Allows distribution of WETH vault fees to multiple receivers, including inventory stakers and NFTX AMM liquidity providers in `rewardFeeTier` pools.

### 4. NFTXInventoryStakingV3Upgradeable

Allows users to stake vTokens to create or increase xNFT positions. xNFTs earn fees in WETH and vToken, which are distributed proportionally based on vTokenShares.

* NFTs can also be directly staked via Inventory, which internally mints vToken without deducting any vault fees. Because users can use this to game and avoid the mint fees, a redeem timelock is placed on the xNFT.
* There is an option for stakers to "early withdraw" a position (while it is timelocked) by paying a % of the position's vToken as a penalty, which then gets distributed among the vault's stakers/LPs. This penalty begins at 100% and goes down linearly to zero over the duration of the timelock.
* Stakers can collect and withdraw the WETH accumulated by their position.
* During withdrawal/off-ramping, stakers can redeem NFTs from the vault with their underlying vToken balance. No vault fees are paid if (A) their xNFT position was initially created by depositing NFTs or (B) if it was made with vToken but a full timelock was enforced.
* Users can combine multiple xNFT "child positions" into one "parent position" after all the timelocks have ended.

### 5. UniswapV3FactoryUpgradeable

Forked from Uniswap V3, this contract was converted into an upgradeable contract and allows for the deployment of NFTX AMM pools as Create2 Beacon Proxies.

### 6. UniswapV3PoolUpgradeable

Forked from Uniswap V3, this contract includes an added function, `distributeRewards`, that enables the FeeDistributer to pass on WETH vault fees to the LPs in the current tick, proportional to their share of the liquidity. If the pool's fee tier matches the global `rewardFeeTier`, cardinality is set during the initialization of the pool so that it can provide a TWAP for the vault fee calculations. The costs of initializing the observation slots are forwarded to the first swappers.

### 7. NonfungiblePositionManager

Forked from Uniswap V3, this contract represents NFTX AMM positions as ERC721 NFTs, and allows the NFTXRouter to "timelock" positions from having liquidity withdrawn before the duration of the timelock is reached. While timelocked, a position can still have its liquidity increased, which further extends the timelock.&#x20;

* Vault fees accumulated as WETH are distributed the same way as normal LP fees.

### 8. NFTXRouter

This contract facilitates the addition and removal of liquidity on the NFTX AMM.  It handles any minting or burning of vToken while adding or removing concentrated liquidity in one transaction.

NFTs can be directly converted into vToken liquidity via the NFTXRouter, which internally mints vTokens without charging any vault fees. As a result of vault fees not being charged for LPs, there is a timelock placed on new LP positions to make it more difficult for users to game the system.&#x20;

* During withdrawal/off-ramping, LPs have the option to redeem NFTs from the vault with their underlying vToken balance. No vault fees are paid if the position was created by depositing NFTs.
* NFTs can be directly bought and sold from the pool in exchange for ETH via the AMM.

## Zaps

### 1. CreateVaultZap

An amalgamation of vault creation steps merged and optimized into a single contract call.\
Allows for the creation of a new Vault, minting vTokens in exchange for NFTs, deploying a new NFTX AMM pool, depositing the minted vToken and ETH into the AMM pool to mint a liquidity position NFT, and depositing the remaining vTokens into inventory staking to mint an xNFT.

### 2. MarketplaceUniversalRouterZap

A Marketplace Zap that utilizes Uniswap's Universal Router to facilitate token swaps via Sushiswap and the NFTX AMM. Enables deducting creator royalties via ERC2981.<br>

* `sell721`/`sell1155`: sell NFT tokenIds for ETH.\
  `idsIn --{--mint-> [vault] -> vTokens --sell-> [UniversalRouter] --}-> ETH`
* `swap721`/`swap1155`: Swap an array of NFTs from the sender's wallet into a desired array of NFTs from a vault by paying ETH for vault fees.
* `buyNFTsWithETH`: buy NFT tokenIds with ETH.\
  `ETH --{-sell-> [UniversalRouter] -> vTokens + ETH --redeem-> [vault] --}-> idsOut`
* `buyNFTsWithERC20`: buy NFT tokenIds with ERC20.\
  `ERC20 --{-sell-> [UniversalRouter] -> ETH -> [UniversalRouter] -> vTokens + ETH --redeem-> [vault] --}-> idsOut`

### 3. MigratorZap

Allows users to migrate their NFTX V2 positions to NFTX V3:

* from V2 vTokens in Sushiswap liquidity to V3 vTokens in the NFTX AMM.
* from V2 xTokens (vTokens in V2 inventory staking) to V3 vTokens inventory staked as xNFTs.
* from V2 vTokens to V3 vTokens inventory staked as xNFTs.

***

## Project Setup

We use [Foundry](https://book.getfoundry.sh/) for tests and [Hardhat](https://hardhat.org/docs) for contract deployments. Refer to installation instructions for Foundry [here](https://github.com/foundry-rs/foundry#installation).

```sh
git clone https://github.com/NFTX-project/nftx-protocol-v3.git
cd nftx-protocol-v3
forge install
yarn install
```

Copy `.env.sample` into `.env` and fill out the env variables.

### Tests

```sh
forge test
```

### Deployment

```sh
yarn deploy:goerli --maxfee <inWei> --priorityfee <inWei> --tags <tag>
```

Tags are defined in the deploy script at the end like: `func.tags = ["<tag>"]`

### Verify Contracts

`yarn verify:goerli`

**Note:** For some UniswapV3 contracts, there might be some errors while verifying, so run this for those contracts:

`yarn verify:goerli --license "GPL-2.0" --force-license --solc-input`


# Contact Addresses

Addresses of smart contracts.

<details>

<summary>Sepolia</summary>

#### NFTXVaultFactoryUpgradeableV3  [🔗](https://sepolia.etherscan.io/address/0x31C56CaF49125043e80B4d3C7f8734f949d8178C#readProxyContract)

```json
0x31C56CaF49125043e80B4d3C7f8734f949d8178C
```

#### NFTXFeeDistributorV3  [🔗](https://sepolia.etherscan.io/address/0x66EF5B4b6ee05639194844CE4867515665F14fED#readContract)

```json
0x66EF5B4b6ee05639194844CE4867515665F14fED
```

#### NFTXInventoryStakingV3Upgradeable  [🔗](https://sepolia.etherscan.io/address/0xfBFf0635f7c5327FD138E1EBa72BD9877A6a7C1C#readProxyContract)

```json
0xfBFf0635f7c5327FD138E1EBa72BD9877A6a7C1C
```

#### UniswapV3FactoryUpgradeable  [🔗](https://sepolia.etherscan.io/address/0xDD2dce9C403f93c10af1846543870D065419E70b#readProxyContract)

```json
0xDD2dce9C403f93c10af1846543870D065419E70b
```

#### NonfungiblePositionManager  [🔗](https://sepolia.etherscan.io/address/0x55BDc76262B1e6e791D0636A0bC61cee23CDFa87#readContract)

```json
0x55BDc76262B1e6e791D0636A0bC61cee23CDFa87
```

#### NFTXRouter  [🔗](https://sepolia.etherscan.io/address/0xD36ece08F76c50EC3F01db65BBc5Ef5Aa5fbE849#readContract)

```json
0xD36ece08F76c50EC3F01db65BBc5Ef5Aa5fbE849
```

#### CreateVaultZap  [🔗](https://sepolia.etherscan.io/address/0x50f69c6556338965bf77C16ADb462Fdb5bE01C09#readContract)

```json
0x50f69c6556338965bf77C16ADb462Fdb5bE01C09
```

#### MarketplaceUniversalRouterZap  [🔗](https://sepolia.etherscan.io/address/0x5Af324A8c90966Bef28386A67c6bE0A16aA03c19#readContract)

```json
0x5Af324A8c90966Bef28386A67c6bE0A16aA03c19
```

#### UniversalRouter  [🔗](https://sepolia.etherscan.io/address/0x12156cCA1958B6591CC49EaE03a5553458a4b424#readContract)

```json
0x12156cCA1958B6591CC49EaE03a5553458a4b424
```

#### SwapRouter  [🔗](https://sepolia.etherscan.io/address/0xa7069da6a7e600e0348620484fD2B1f24E075d5f#readContract)

```json
0xa7069da6a7e600e0348620484fD2B1f24E075d5f
```

#### QuoterV2  [🔗](https://sepolia.etherscan.io/address/0xb8EB27ca4715f7A04228c6F83935379D1f5AbABd#readContract)

```json
0xb8EB27ca4715f7A04228c6F83935379D1f5AbABd
```

#### TickLens  [🔗](https://sepolia.etherscan.io/address/0xA13E04fAEe08E784A44C27e9E77Ca7a02D45BFd7#readContract)

```json
0xA13E04fAEe08E784A44C27e9E77Ca7a02D45BFd7
```

#### Permit2  [🔗](https://sepolia.etherscan.io/address/0x000000000022d473030f116ddee9f6b43ac78ba3#readContract)

```json
0x000000000022d473030f116ddee9f6b43ac78ba3
```

#### WETH  [🔗](https://sepolia.etherscan.io/address/0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14#readContract)

```json
0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14
```

</details>


# Mainnet Addresses

NFTX V3 smart contract addresses on mainnet.

#### NFTXVaultFactoryUpgradeableV3

```json
0xC255335bc5aBd6928063F5788a5E420554858f01
```

#### NFTXFeeDistributorV3

```json
0x6845fF5f102bEF9D785468F0bEb535b4687406E7
```

#### NFTXInventoryStakingV3Upgradeable

```json
0x889f313e2a3FDC1c9a45bC6020A8a18749CD6152
```

#### UniswapV3FactoryUpgradeable

```json
0xa70e10beB02fF9a44007D9D3695d4b96003db101
```

#### NonfungiblePositionManager

```json
0x26387fcA3692FCac1C1e8E4E2B22A6CF0d4b71bF
```

#### NFTXRouter

```json
0x70A741A12262d4b5Ff45C0179c783a380EebE42a
```

#### CreateVaultZap

```json
0x56dab32697B4A313f353DA0CE42B5113eD8E6f74
```

#### MarketplaceUniversalRouterZap

```json
0x293A0c49c85F1D8851C665Ac3cE1f1DC2a79bE3d
```

#### nftxUniversalRouter

```json
0x250d62a67254A46c0De472d2c9215E1d890cC90f
```

#### SwapRouter

```json
0x1703f8111B0E7A10e1d14f9073F53680d64277A3
```

#### QuoterV2

```json
0x5493dF723c17B6A768aA61F79405bA56ffC5294a
```

#### TickLens

```json
0x1650115DDD287bE6F4972180d290D0FF89a42c40
```

#### permit2

```json
0x000000000022d473030f116ddee9f6b43ac78ba3
```

#### WETH

```json
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
```


# Arbitrum Addresses

NFTX V3 smart contract addresses on Arbitrum.

#### NFTXVaultFactoryUpgradeableV3

```json
0x4dEeb9D2Bff2e9C35ce1f013DcC4582F891cb711
```

#### NFTXFeeDistributorV3

```json
0x0d50970C7848ebbE52661e70057D7D063B7de886
```

#### NFTXInventoryStakingV3Upgradeable

```json
0xe39a7E67d3E3b6eAF58BC02C4E80C3688847d155
```

#### UniswapV3FactoryUpgradeable

```json
0xF4D0512FB47319B0CE9144EF582862e2921CaBF8
```

#### NonfungiblePositionManager

```json
0x8AD238377531547838370B9C4aC346b9Ed5466Ea
```

#### NFTXRouter

```json
0x52731751Dede22827ad47109f5e9697d75a3ef4d
```

#### CreateVaultZap

```json
0xF9E891AB1ECa89B7A4B3cBD45aEBFDF3Ec38946F
```

#### MarketplaceUniversalRouterZap

```json
0xf56296B3010a59Ef7F0915569DD44E1302b9Ca40
```

#### nftxUniversalRouter

```json
0x0DA69287B4C1B28181E5d155dDDda7Fa5C32E5Ad
```

#### SwapRouter

```json
0xeA60242d7183E3d13Dc17fb2A4D0230d34eef502
```

#### QuoterV2

```json
0xff3957CB28aB34186543281e0bbe0De05C9e7D6D
```

#### TickLens

```json
0x3f2797b0E19CBf2377B8DE2d1CEC2698AcA7b081
```

#### permit2

```json
0x000000000022d473030f116ddee9f6b43ac78ba3
```

#### WETH

```json
0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
```

#### UniswapV3Staker

```
0xd4E155135b7dFf66c9C3B34EcA4aE7d9555FE31F
```


# Sepolia Addresses

NFTX V3 smart contract addresses on Sepolia.

#### NFTXVaultFactoryUpgradeableV3

```json
0x31C56CaF49125043e80B4d3C7f8734f949d8178C
```

#### NFTXFeeDistributorV3

```json
0x53AE38742C78EE64fC077EF840B2Aa47A7E9c603
```

#### NFTXInventoryStakingV3Upgradeable

```json
0xfBFf0635f7c5327FD138E1EBa72BD9877A6a7C1C
```

#### UniswapV3FactoryUpgradeable

```json
0xDD2dce9C403f93c10af1846543870D065419E70b
```

#### NonfungiblePositionManager

```json
0xA9bCC1e29d3460177875f68fDCC0264D22c40BF0
```

#### NFTXRouter

```json
0x441b7DE4340AAa5aA86dB4DA43d9Badf7B2DAA66
```

#### CreateVaultZap

```json
0xD80b916470F8e79FD8d09874cb159CbB8D13d8da
```

#### MarketplaceUniversalRouterZap

```json
0xd88a3B9D0Fb2d39ec8394CfFD983aFBB2D4a6410
```

#### nftxUniversalRouter

```json
0x12156cCA1958B6591CC49EaE03a5553458a4b424
```

#### SwapRouter

```json
0xa7069da6a7e600e0348620484fD2B1f24E075d5f
```

#### QuoterV2

```json
0xb8EB27ca4715f7A04228c6F83935379D1f5AbABd
```

#### TickLens

```json
0xA13E04fAEe08E784A44C27e9E77Ca7a02D45BFd7
```

#### permit2&#x20;

```json
0x000000000022d473030f116ddee9f6b43ac78ba3
```

#### WETH&#x20;

```json
0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14
```


# Audit Reports

### Spearbit audit (for core contracts)

{% file src="/files/h2En7mVlMdyQCWO69NMr" %}

### Cantina audit (for zaps)

{% file src="/files/mOVSuACN8BcvYKR2mTwI" %}


# Bug Bounties

The NFTX Bounty program for V3 is now managed through Immunefi.

For all details and submissions please visit <https://immunefi.com/bounty/nftx/> .


# NFTXVaultUpgradeableV3

NFTXVaultUpgradeableV3.sol

The NFTX vault implementation used by the vault beacon proxy (and therefore all vaults).&#x20;

## Table of Contents

<details>

<summary>Constants</summary>

[#base](#base "mention")\
[#weth](#weth "mention")\
[#crypto\_punks](#crypto_punks "mention")\
[#crypto\_kitties](#crypto_kitties "mention")\
[#assetaddress](#assetaddress "mention")\
[#vaultfactory](#vaultfactory "mention")\
[#vaultid](#vaultid "mention")\
[#is1155](#is1155 "mention")

</details>

<details>

<summary>Variables</summary>

[#manager](#manager "mention")\
[#eligibilitystorage](#eligibilitystorage "mention")\
[#allowallitems](#allowallitems "mention")\
[#enablemint](#enablemint "mention")\
[#enableredeem](#enableredeem "mention")\
[#enableswap](#enableswap "mention")\
[#tokendepositinfo](#tokendepositinfo "mention")\
[#depositinfo1155](#depositinfo1155 "mention")\
[#pointerindex1155](#pointerindex1155 "mention")

</details>

<details>

<summary>Events</summary>

[#vaultinit](#vaultinit "mention")\
[#managerset](#managerset "mention")\
[#eligibilitydeployed](#eligibilitydeployed "mention")\
[#enablemintupdated](#enablemintupdated "mention")\
[#enableredeemupdated](#enableredeemupdated "mention")\
[#enableswapupdated](#enableswapupdated "mention")\
[#minted](#minted "mention")\
[#redeemed](#redeemed "mention")\
[#swapped](#swapped "mention")\
[#premiumshared](#premiumshared "mention")\
[#feesdistributed](#feesdistributed "mention")\
[#vaultshutdown](#vaultshutdown "mention")

</details>

<details>

<summary>Public Write Functions</summary>

[#mint](#mint "mention")\
[#redeem](#redeem "mention")\
[#swap](#swap "mention")\
[#flashloan](#flashloan "mention")

</details>

<details>

<summary>Privileged Write Functions</summary>

[#finalizevault](#finalizevault "mention")\
[#setvaultmetadata](#setvaultmetadata "mention")\
[#setvaultfeatures](#setvaultfeatures "mention")\
[#setfees](#setfees "mention")\
[#disablevaultfees](#disablevaultfees "mention")\
[#deployeligibilitystorage](#deployeligibilitystorage "mention")\
[#setmanager](#setmanager "mention")

</details>

<details>

<summary>Owner Write Functions</summary>

[#rescuetokens](#rescuetokens "mention")\
[#shutdown](#shutdown "mention")

</details>

<details>

<summary>Read Functions</summary>

[#nftidat](#nftidat "mention")\
[#allholdings](#allholdings "mention")\
[#totalholdings](#totalholdings "mention")\
[#holdingscontains](#holdingscontains "mention")\
[#vaultfees](#vaultfees "mention")\
[#allvalidnfts](#allvalidnfts "mention")\
[#vtokentoeth](#vtokentoeth "mention")\
[#depositinfo1155](#depositinfo1155 "mention")\
[#version](#version "mention")

</details>

## Constants

#### BASE

```solidity
uint256 constant BASE = 10 ** 18
```

10^18.

#### WETH

```solidity
function WETH() external view returns (address)
```

WETH contract address.

#### CRYPTO\_PUNKS

```solidity
address constant CRYPTO_PUNKS = 0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB
```

CryptoPunks contract address.

#### CRYPTO\_KITTIES

```solidity
address constant CRYPTO_KITTIES = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d
```

CryptoKitties contract address.

#### assetAddress

```solidity
function assetAddress() external view returns (address)
```

Contract address of NFT collection that can enter the vault.

#### vaultFactory

```solidity
function vaultFactory() external view returns (address)
```

Address of NFTX Vault Factory.

#### vaultId

```solidity
function vaultId() external view returns (uint256)
```

The vault's ID number.&#x20;

#### is1155

```solidity
function is1155() external view returns (bool)
```

Whether the vault is for an ERC1155 NFT.

## Variables

#### manager

```solidity
function manager() external view returns (address)
```

Address of vault manager.&#x20;

#### eligibilityStorage

```solidity
function eligibilityStorage() external view returns (address)
```

Address of Eligibility Storage.

#### allowAllItems

```solidity
function allowAllItems() external view returns (bool)
```

Whether all NFT tokenIDs are eligible to enter this vault.&#x20;

#### enableMint

```solidity
function enableMint() external view returns (bool)
```

Whether minting is enabled.&#x20;

#### enableRedeem

```solidity
function enableRedeem() external view returns (bool)
```

Whether redeeming is enabled.&#x20;

#### enableSwap

```solidity
function enableSwap() external view returns (bool)
```

Whether swapping is enabled.&#x20;

#### tokenDepositInfo

```solidity
function tokenDepositInfo(
    uint256 tokenId
) external view returns (uint48 timestamp, address depositor)
```

Timestamp and depositor address of each ERC721 deposit.

#### depositInfo1155

```solidity
function depositInfo1155(
    uint256 tokenId,
    uint256 index
) external view returns (uint256 qty, address depositor, uint48 timestamp)
```

Quantity, depositor address, and timestamp of each ERC1155 deposit.

#### pointerIndex1155

```solidity
function pointerIndex1155(uint256 tokenId) external view returns (uint256)
```

Pointer index of oldest DepositInfo1155 object, for each ERC1155 tokenID.

## Events

#### VaultInit

```solidity
event VaultInit(
    uint256 indexed vaultId,
    address assetAddress,
    bool is1155,
    bool allowAllItems
)
```

Emitted by `__NFTXVault_init` function.

<table><thead><tr><th width="199.33333333333331">Parameters</th><th width="138">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault initialized.</td></tr><tr><td>assetAddress</td><td><code>address</code></td><td>NFT collection address associated with vault.</td></tr><tr><td>is1155</td><td><code>bool</code></td><td>Whether the NFT collection uses ERC1155.</td></tr><tr><td>allowAllItems</td><td><code>bool</code></td><td>Whether all tokenIDs are allowed into vault. </td></tr></tbody></table>

#### ManagerSet

```solidity
event ManagerSet(address manager)
```

Emitted by `setManager` function.

<table><thead><tr><th width="199.33333333333331">Parameters</th><th width="138">Type</th><th>Description</th></tr></thead><tbody><tr><td>manager</td><td><code>address</code></td><td>New vault manager address.</td></tr></tbody></table>

#### EligibilityDeployed

```solidity
event EligibilityDeployed(uint256 moduleIndex, address eligibilityAddr)
```

Emitted by `deployEligibilityStorage` function.

<table><thead><tr><th width="199.33333333333331">Parameters</th><th width="138">Type</th><th>Description</th></tr></thead><tbody><tr><td>moduleIndex</td><td><code>uint256</code></td><td>Eligibility module number.</td></tr><tr><td>eligibilityAddr</td><td><code>address</code></td><td>Address of eligibility contract just added.</td></tr></tbody></table>

#### EnableMintUpdated

```solidity
event EnableMintUpdated(bool enabled)
```

Emitted by `setVaultFeatures` function.

<table><thead><tr><th width="199.33333333333331">Parameters</th><th width="138">Type</th><th>Description</th></tr></thead><tbody><tr><td>enabled</td><td><code>bool</code></td><td>True if minting has just been enabled, false if minting has been disabled. </td></tr></tbody></table>

#### EnableRedeemUpdated

```solidity
event EnableRedeemUpdated(bool enabled)
```

Emitted by `setVaultFeatures` function.

<table><thead><tr><th width="199.33333333333331">Parameters</th><th width="138">Type</th><th>Description</th></tr></thead><tbody><tr><td>enabled</td><td><code>bool</code></td><td>True if redeeming has just been enabled, false if redeeming has been disabled. </td></tr></tbody></table>

#### EnableSwapUpdated

```solidity
event EnableSwapUpdated(bool enabled)
```

Emitted by `setVaultFeatures` function.

<table><thead><tr><th width="199.33333333333331">Parameters</th><th width="138">Type</th><th>Description</th></tr></thead><tbody><tr><td>enabled</td><td><code>bool</code></td><td>True if NFT-to-NFT swapping has just been enabled, false if it has been disabled. </td></tr></tbody></table>

#### Minted

```solidity
event Minted(
    uint256[] nftIds,
    uint256[] amounts,
    address to,
    address depositor
)
```

Emitted by `mint` function.

<table><thead><tr><th width="199.33333333333331">Parameters</th><th width="138">Type</th><th>Description</th></tr></thead><tbody><tr><td>nftIds</td><td><code>uint256[]</code></td><td>TokenIDs of NFTs added to vault.</td></tr><tr><td>amounts</td><td><code>uint256[]</code></td><td>Amounts of each NFT tokenID (for ERC1155). </td></tr><tr><td>to</td><td><code>address</code></td><td>Recipient address that vTokens were sent to. </td></tr><tr><td>depositor</td><td><code>address</code></td><td>Depositor address that should receive premiums for the <code>nftIds</code> deposited.</td></tr></tbody></table>

#### Redeemed

```solidity
event Redeemed(uint256[] specificIds, address to)
```

Emitted by `redeem` function.

<table><thead><tr><th width="199.33333333333331">Parameters</th><th width="138">Type</th><th>Description</th></tr></thead><tbody><tr><td>specificIds</td><td><code>uint256[]</code></td><td>TokenIDs of redeemed NFTs.</td></tr><tr><td>to</td><td><code>address</code></td><td>Recipient address that NFTs were sent to. </td></tr></tbody></table>

#### Swapped

```solidity
event Swapped(
    uint256[] nftIds,
    uint256[] amounts,
    uint256[] specificIds,
    address to,
    address depositor
)
```

Emitted by `swap` function.

<table><thead><tr><th width="199.33333333333331">Parameters</th><th width="138">Type</th><th>Description</th></tr></thead><tbody><tr><td>nftIds</td><td><code>uint256[]</code></td><td>TokenIDs of NFTs sent to vault.</td></tr><tr><td>amounts</td><td><code>uint256[]</code></td><td>Amounts for NFT token IDs that entered the vault, and also for NFT tokenIDs that exited the vault. </td></tr><tr><td>specificIds</td><td><code>uint256[]</code></td><td>TokenIDs of NFTs sent to recipient.</td></tr><tr><td>to</td><td><code>address</code></td><td>Recipient address that NFTs were sent to. </td></tr><tr><td>depositor</td><td><code>address</code></td><td>Depositor address that should receive premiums for the <code>nftIds</code> deposited.</td></tr></tbody></table>

#### PremiumShared

```solidity
event PremiumShared(address depositor, uint256 wethPremium)
```

Emitted by `redeem` and `swap` functions.

<table><thead><tr><th width="199.33333333333331">Parameters</th><th width="138">Type</th><th>Description</th></tr></thead><tbody><tr><td>depositor</td><td><code>address</code></td><td>NFT depositor who receives bulk of premium fee.</td></tr><tr><td>wethPremium</td><td><code>uint256</code></td><td>WETH premium fee amount (total shared).</td></tr></tbody></table>

#### FeesDistributed

```solidity
event FeesDistributed(uint256 wethFees)
```

Emitted by `mint`, `redeem` and `swap` functions.

<table><thead><tr><th width="199.33333333333331">Parameters</th><th width="138">Type</th><th>Description</th></tr></thead><tbody><tr><td>wethFees</td><td><code>uint256</code></td><td>WETH fee amount distributed.</td></tr></tbody></table>

#### VaultShutdown

```solidity
event VaultShutdown(
    address assetAddress,
    uint256 numItems,
    address recipient
)
```

Emitted by `shutdown`.

<table><thead><tr><th width="199.33333333333331">Parameters</th><th width="138">Type</th><th>Description</th></tr></thead><tbody><tr><td>assetAddress</td><td><code>address</code></td><td>NFT collection address of shutdown vault.</td></tr><tr><td>numItems</td><td><code>uint256</code></td><td>Number of NFTs in vault at time of shutdown.</td></tr><tr><td>recipient</td><td><code>address</code></td><td>Recipient address where vault NFTs were sent.</td></tr></tbody></table>

## Write Functions

#### mint

```solidity
function mint(
    uint256[] calldata tokenIds,
    uint256[] calldata amounts,
    address depositor,
    address to
) external payable returns (uint256 vTokensMinted)
```

Mints vault tokens in exchange for depositing NFTs. Mint fee is paid in ETH.

<table><thead><tr><th width="170.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenIds</td><td><code>uint256[]</code></td><td>Token IDs of NFTs being sent to vault.</td></tr><tr><td>amounts</td><td><code>uint256[]</code></td><td>Quantity of each NFT. Ignored for ERC721 vaults.</td></tr><tr><td>depositor</td><td><code>address</code></td><td>Address that should receive premium fees for <code>tokenIds</code>.</td></tr><tr><td>to</td><td><code>address</code></td><td>Address to receive minted vToken.</td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send.</td></tr></tbody></table>

<table><thead><tr><th width="170.5">Return values</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>vTokensMinted</td><td><code>uint256</code></td><td>The amount of vTokens minted.</td></tr></tbody></table>

#### redeem

```solidity
function redeem(
    uint256[] calldata idsOut,
    address to,
    uint256 wethAmount,
    uint256 vTokenPremiumLimit,
    bool forceFees
) external payable returns (uint256 ethFees)
```

Redeems NFTs by burning vToken. Redeem fee is paid in ETH or WETH.

<table><thead><tr><th width="208.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>idsOut</td><td><code>uint256[]</code></td><td>Token IDs of NFTs to redeem.</td></tr><tr><td>to</td><td><code>address</code></td><td>Address to receive redeemed NFTs.</td></tr><tr><td>wethAmount</td><td><code>uint256</code></td><td>Amount of WETH to send for fees. If set to zero, then ETH is used instead.</td></tr><tr><td>vTokenPremiumLimit</td><td><code>uint256</code></td><td>Max total premium fees (denominated in vToken) that the user is willing to pay. </td></tr><tr><td>forceFees</td><td><code>bool</code></td><td>Whether to enforce fees even if caller is set as excludedFromFees.</td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send.</td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>ethFees</td><td><code>uint256</code></td><td>Total fees paid (in WETH or ETH). </td></tr></tbody></table>

#### swap

```solidity
function swap(
    uint256[] calldata idsIn,
    uint256[] calldata amounts,
    uint256[] calldata idsOut,
    address depositor,
    address to,
    uint256 vTokenPremiumLimit,
    bool forceFees
) external payable returns (uint256 ethFees)
```

Swap one or more NFTs (`idsIn`) for other NFTs from the vault (`idsOut`). Swap fee is paid in ETH.

<table><thead><tr><th width="204.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>idsIn</td><td><code>uint256[]</code></td><td>Token IDs of NFTs going to vault. </td></tr><tr><td>amounts</td><td><code>uint256[]</code></td><td>Quantity of each NFT going to vault. Ignored for ERC721.</td></tr><tr><td>idsOut</td><td><code>uint256[]</code></td><td>Token IDs of NFTs leaving vault.</td></tr><tr><td>depositor</td><td><code>address</code></td><td>Address that should receive premium fees for <code>idsIn</code>. </td></tr><tr><td>to</td><td><code>address</code></td><td>Address to receive NFTs from vault.</td></tr><tr><td>vTokenPremiumLimit</td><td><code>uint256</code></td><td>Max total premium fees (denominated in vToken) that the user is willing to pay. </td></tr><tr><td>forceFees</td><td><code>bool</code></td><td>Whether to enforce fees even if caller is set as excludedFromFees.</td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send.</td></tr></tbody></table>

<table><thead><tr><th width="206.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>ethFees</td><td><code>uint256</code></td><td>Total fees paid (in WETH or ETH).</td></tr></tbody></table>

#### flashLoan

```solidity
function flashLoan(
    IERC3156FlashBorrowerUpgradeable receiver,
    address token,
    uint256 amount,
    bytes calldata data
) public returns (bool)
```

Performs a flash loan. New tokens are minted and sent to `receiver`, who is required to implement the `IERC3156FlashBorrower` interface. By the end of the flash loan, the receiver is expected to own `amount` of tokens and have them approved back to the token contract itself so they can be burned and distributed.

The fee required to execute a flash loan is paid in ETH and is the highest of the vault's mint, redeem, and swap fees. All ETH proceeds are sent to the vault's inventory stakers.&#x20;

<table><thead><tr><th width="174.5">Parameters</th><th width="242">Type</th><th>Description</th></tr></thead><tbody><tr><td>receiver</td><td><code>IERC3156FlashBorrowerUpgradeable</code></td><td>The receiver address of the flash loan.</td></tr><tr><td>token</td><td><code>address</code></td><td>The token to be flash loaned. Only <code>address(this)</code> is supported.</td></tr><tr><td>amount</td><td><code>uint256</code></td><td>The amount of tokens to be loaned. </td></tr><tr><td>data</td><td><code>bytes</code></td><td>An arbitrary data field that is passed to the receiver.</td></tr></tbody></table>

<table><thead><tr><th width="182.5">Return values</th><th width="237">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>bool</code></td><td><code>true</code> if the flash loan was successful.</td></tr></tbody></table>

## Privileged Functions

These functions can only be called by the vault manager or (if there is no vault manager) the contract owner.

#### finalizeVault

```solidity
function finalizeVault() external
```

Removes the vault manager.

#### setVaultMetadata

```solidity
function setVaultMetadata(
    string calldata name_,
    string calldata symbol_
) external
```

Sets the name and symbol of the vault's ERC20 vToken.&#x20;

<table><thead><tr><th width="206.5">Parameters</th><th width="122">Type</th><th>Description</th></tr></thead><tbody><tr><td>name_</td><td><code>string</code></td><td>New name.</td></tr><tr><td>symbol_</td><td><code>string</code></td><td>New symbol.</td></tr></tbody></table>

#### setVaultFeatures

```solidity
function setVaultFeatures(
    bool enableMint_,
    bool enableRedeem_,
    bool enableSwap_
) external
```

Sets minting, redeeming, and swapping as either on or off.

<table><thead><tr><th width="222.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>enableMint_</td><td><code>bool</code></td><td>Whether minting is enabled.</td></tr><tr><td>enableRedeem_</td><td><code>bool</code></td><td>Whether redeeming is enabled.</td></tr><tr><td>enableSwap_</td><td><code>bool</code></td><td>Whether swapping is enabled.</td></tr></tbody></table>

#### setFees

```solidity
function setFees(
    uint256 mintFee_,
    uint256 redeemFee_,
    uint256 swapFee_
) external
```

Sets mint, redeem, and (NFT-to-NFT) swap fees. 1e16 = 1%.

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>mintFee_</td><td><code>uint256</code></td><td>New mint fee.</td></tr><tr><td>redeemFee_</td><td><code>uint256</code></td><td>New redeem fee.</td></tr><tr><td>swapFee_</td><td><code>uint256</code></td><td>New swap fee (for NFT swaps).</td></tr></tbody></table>

#### disableVaultFees

```solidity
function disableVaultFees() external
```

Removes custom vault fee settings, reverting to the global/default vault fee settings.&#x20;

#### deployEligibilityStorage

```solidity
function deployEligibilityStorage(
    uint256 moduleIndex,
    bytes calldata initData
) external returns (address)
```

Deploys and initializes an eligibility module contract from the EligibilityManager.

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>moduleIndex</td><td><code>uint256</code></td><td>Index of module to deploy.</td></tr><tr><td>initData</td><td><code>bytes</code></td><td>ABI encoded parameters for module.</td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>address</code></td><td>Address of deployed module. </td></tr></tbody></table>

#### setManager

```solidity
function setManager(address manager_) external
```

Sets the vault manager.&#x20;

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>manager_</td><td><code>address</code></td><td>Address of new vault manager.</td></tr></tbody></table>

## Owner Functions

#### rescueTokens

```solidity
function rescueTokens(
    TokenType tt,
    address token,
    uint256[] calldata ids,
    uint256[] calldata amounts
) external
```

Rescues ERC20, ERC721, or ERC1155 tokens.

<table><thead><tr><th width="161.5">Parameters</th><th width="219">Type</th><th>Description</th></tr></thead><tbody><tr><td>tt</td><td><code>TokenType</code></td><td>Enum: <code>ERC20</code>, <code>ERC721</code>, or <code>ERC1155.</code></td></tr><tr><td>token</td><td><code>IERC20Upgradeable</code></td><td>Contract address of token to retrieve.</td></tr><tr><td>ids</td><td><code>uint256[]</code></td><td>Token IDs for ERC721 or ERC1155 NFTs. Ignored for ERC20.</td></tr><tr><td>amounts</td><td><code>uint256[]</code></td><td>Quantities for ERC1155 token IDs. Ignored for ERC20 and ERC721.</td></tr></tbody></table>

#### shutdown

```solidity
function shutdown(
    address recipient,
    uint256[] calldata tokenIds
) external
```

Shuts the vault down and sends its NFTs to `recipient`. This function is meant to be used by the DAO when a vault has lost liquidity, and the vToken is too dispersed for any one user to redeem. When this happens, one or more users can request a shutdown, which is initiated by the DAO. The DAO then sells the assets for ETH and distributes the ETH to the vToken holders.&#x20;

This function works for both ERC721 and ERC1155 vaults. For ERC1155, the total amount of each tokenID will be sent to the recipient.&#x20;

<table><thead><tr><th width="210.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>recipient</td><td><code>address</code></td><td>Address to receives NFTs.</td></tr><tr><td>tokenIds</td><td><code>uint256[]</code></td><td>TokenIDs to send (should include all held by vault).</td></tr></tbody></table>

## Read Functions

#### nftIdAt

```solidity
function nftIdAt(
    uint256 holdingsIndex
) external view returns (uint256)
```

Retrieves the NFT token ID stored at a specified index in holdings.&#x20;

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>holdingsIndex</td><td><code>uint256</code></td><td>Index position of holdings data to retrieve.</td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>uint256</code></td><td>NFT Token ID, if found.</td></tr></tbody></table>

#### allHoldings

```solidity
function allHoldings() external view returns (uint256[] memory)
```

Returns an array of all NFT token IDs held by the vault.&#x20;

<table><thead><tr><th width="210.5">Return values</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>uint256[]</code></td><td>All token IDs in holdings.</td></tr></tbody></table>

#### totalHoldings

```solidity
function totalHoldings() external view returns (uint256)
```

Returns the number of distinct NFT token IDs in holdings.

<table><thead><tr><th width="210.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>uint256[]</code></td><td>Number of distinct token IDs in holdings.</td></tr></tbody></table>

#### holdingsContains

```solidity
function holdingsContains(uint256 tokenId) external view returns (bool)
```

Returns whether an NFT tokenId is in the vault.

<table><thead><tr><th width="210.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>tokenId</em></td><td><code>uint256</code></td><td>NFT tokenID to check for.</td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>bool</code></td><td>Whether the tokenID is in the vault.</td></tr></tbody></table>

#### vaultFees

```solidity
function vaultFees()
    external
    view
    returns (uint256 mintFee, uint256 redeemFee, uint256 swapFee)
```

The mint, redeem, and swap fees.

<table><thead><tr><th width="210.5">Return values</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>mintFee</td><td><code>uint256</code></td><td>Mint fee.</td></tr><tr><td>redeemFee</td><td><code>uint256</code></td><td>Redeem fee.</td></tr><tr><td>swapFee</td><td><code>uint256</code></td><td>Swap fee, for NFT-to-NFT swaps.</td></tr></tbody></table>

#### allValidNFTs

```solidity
function allValidNFTs(
    uint256[] memory tokenIds
) external view returns (bool)
```

Checks whether all NFT Token IDs inputed are valid for minting vToken.

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenIds</td><td><code>uint256</code></td><td>Token IDs of NFTs to check.</td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>bool</code></td><td>Whether all the NFT tokenIDs are valid to enter.</td></tr></tbody></table>

#### vTokenToETH

```solidity
function vTokenToETH(
    uint256 vTokenAmount
) external view returns (uint256 ethAmount)
```

Calculate ETH amount corresponding to a given vToken amount, calculated via the TWAP from the NFTX AMM.

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>vTokenAmount</td><td><code>uint256</code></td><td>Amount of vToken to calculate in ETH.</td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>ethAmount</td><td><code>uint256</code></td><td>ETH amount that is equal in value to the vToken amount, based on TWAP.</td></tr></tbody></table>

#### depositInfo1155Length

```solidity
function depositInfo1155Length(
    uint256 tokenId
) external view returns (uint256)
```

Returns length of the `depositInfo1155` list for a given tokenID.

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>NFT tokenID to check.</td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="123">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>uint256</code></td><td>Length of <code>depositInfo1155[tokenId]</code>.</td></tr></tbody></table>

#### version

```solidity
function version() external pure returns (string memory)
```

Returns the version of this contract.

<table><thead><tr><th width="210.5">Return values</th><th width="125">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>string</code></td><td>Contract version.</td></tr></tbody></table>


# NFTXVaultFactoryUpgradeableV3

NFTXVaultFactoryUpgradeableV3.sol

Factory contract for creating NFTX vaults, and also managing general protocol settings.

## Table of Contents

<details>

<summary>Constants</summary>

[#max\_depositor\_premium\_share](#max_depositor_premium_share "mention")\
[#beacon\_code](#beacon_code "mention")

</details>

<details>

<summary>Variables</summary>

[#feedistributor](#feedistributor "mention")\
[#eligibilitymanager](#eligibilitymanager "mention")\
[#excludedfromfees](#excludedfromfees "mention")\
[#factorymintfee](#factorymintfee "mention")\
[#factoryredeemfee](#factoryredeemfee "mention")\
[#factoryswapfee](#factoryswapfee "mention")\
[#twapinterval](#twapinterval "mention")\
[#premiumduration](#premiumduration "mention")\
[#premiummax](#premiummax "mention")\
[#depositorpremiumshare](#depositorpremiumshare "mention")

</details>

<details>

<summary>Events</summary>

[#newfeedistributor](#newfeedistributor "mention")\
[#feeexclusion](#feeexclusion "mention")\
[#neweligibilitymanager](#neweligibilitymanager "mention")\
[#newvault](#newvault "mention")\
[#updatevaultfees](#updatevaultfees "mention")\
[#disablevaultfees](#disablevaultfees "mention")\
[#updatefactoryfees](#updatefactoryfees "mention")\
[#newpremiummax](#newpremiummax "mention")\
[#newpremiumduration](#newpremiumduration "mention")\
[#newdepositorpremiumshare](#newdepositorpremiumshare "mention")\
[#newtwapinterval](#newtwapinterval "mention")

</details>

<details>

<summary>Public Write Functions</summary>

[#createvault](#createvault "mention")

</details>

<details>

<summary>Privileged Write Functions</summary>

[#setvaultfees](#setvaultfees "mention")\
[#disablevaultfees](#disablevaultfees "mention")

</details>

<details>

<summary>Owner Write Functions</summary>

[#setfactoryfees](#setfactoryfees "mention")\
[#setfeedistributor](#setfeedistributor "mention")\
[#setfeeexclusion](#setfeeexclusion "mention")\
[#seteligibilitymanager](#seteligibilitymanager "mention")\
[#settwapinterval](#settwapinterval "mention")\
[#setpremiumduration](#setpremiumduration "mention")\
[#setpremiummax](#setpremiummax "mention")\
[#setdepositorpremiumshare](#setdepositorpremiumshare "mention")

</details>

<details>

<summary>Read Functions</summary>

[#vaultfees](#vaultfees "mention")\
[#islocked](#islocked "mention")\
[#vaultsforasset](#vaultsforasset "mention")\
[#allvaults](#allvaults "mention")\
[#numvaults](#numvaults "mention")\
[#vault](#vault "mention")\
[#computevaultaddress](#computevaultaddress "mention")\
[#gettwapx96](#gettwapx96 "mention")\
[#getvtokenpremium721](#getvtokenpremium721 "mention")\
[#getvtokenpremium1155](#getvtokenpremium1155 "mention")

</details>

## Constants

#### MAX\_DEPOSITOR\_PREMIUM\_SHARE

```solidity
uint256 constant MAX_DEPOSITOR_PREMIUM_SHARE = 1 ether
```

Max depositor premium fee share allowed. Set to 100%.&#x20;

#### BEACON\_CODE

```solidity
bytes internal constant BEACON_CODE = type(Create2BeaconProxy).creationCode
```

Beacon proxy creation code.

## Variables

#### feeDistributor

```solidity
function feeDistributor() external view returns (address)
```

Address of NFTXFeeDistributorV3.

#### eligibilityManager

```solidity
function eligibilityManager() external view returns (address)
```

Address of NFTXEligibilityManager.

#### excludedFromFees

```solidity
function excludedFromFees(address addr) external view returns (bool)
```

Which addresses are excluded from fees.&#x20;

#### factoryMintFee

```solidity
function factoryMintFee() external view returns (uint64)
```

Global mint fee for vaults using default fee settings.

#### factoryRedeemFee

```solidity
function factoryRedeemFee() external view returns (uint64)
```

Global redeem fee for vaults using default fee settings.

#### factorySwapFee

```solidity
function factorySwapFee() external view returns (uint64)
```

Global (NFT-to-NFT) swap fee for vaults using default fee settings.

#### twapInterval

```solidity
function twapInterval() external view returns (uint32)
```

The time-weighted average price interval. For example, if the `twapInterval` is set to `3600` seconds (1 hour), it would mean that you are interested in computing or observing the average price of an asset over the past hour.

#### premiumDuration

```solidity
function premiumDuration() external view returns (uint256)
```

The time it takes for premium fees to decay from `premiumMax` to zero. In seconds.

#### premiumMax

```solidity
function premiumMax() external view returns (uint256)
```

The starting (max) premium fee. 1e16 = 1%.

#### depositorPremiumShare

```solidity
function depositorPremiumShare() external view returns (uint256)
```

Portion of premium fee that goes to depositor. 1e16 = 1%.

## Events

#### NewFeeDistributor

```solidity
event NewFeeDistributor(address oldDistributor, address newDistributor)
```

Emitted by `setFeeDistributor()`.

<table><thead><tr><th width="200.33333333333331">Parameters</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>oldDistributor</td><td><code>address</code></td><td>Previous address of NFTXFeeDistributorV3.</td></tr><tr><td>newDistributor</td><td><code>address</code></td><td>New address of NFTXFeeDistributorV3.</td></tr></tbody></table>

#### FeeExclusion

```solidity
event FeeExclusion(address feeExcluded, bool excluded)
```

Emitted by `setFeeExclusion()`.

<table><thead><tr><th width="200.33333333333331">Parameters</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>feeExcluded</td><td><code>address</code></td><td>Address being excluded (or un-excluded). </td></tr><tr><td>excluded</td><td><code>bool</code></td><td>Whether the address is excluded from fees.</td></tr></tbody></table>

#### NewEligibilityManager

```solidity
event NewEligibilityManager(address oldEligManager, address newEligManager)
```

Emitted by `setEligibilityManager()`.

<table><thead><tr><th width="200.33333333333331">Parameters</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>oldEligManager</td><td><code>address</code></td><td>Previous address of NFTXEligibilityManager.</td></tr><tr><td>newEligManager</td><td><code>address</code></td><td>New address of NFTXEligibilityManager.</td></tr></tbody></table>

#### NewVault

```solidity
event NewVault(
    uint256 indexed vaultId,
    address vaultAddress,
    address assetAddress,
    string name,
    string symbol
)
```

Emitted by `createVault()`.

<table><thead><tr><th width="200.33333333333331">Parameters</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr><tr><td>vaultAddress</td><td><code>address</code></td><td>Contract address of vault.</td></tr><tr><td>assetAddress</td><td><code>address</code></td><td>NFT collection address linked to vault.</td></tr><tr><td>name</td><td><code>string</code></td><td>ERC20 vToken name.</td></tr><tr><td>symbol</td><td><code>string</code></td><td>ERC20 vToken symbol. </td></tr></tbody></table>

#### UpdateVaultFees

```solidity
event UpdateVaultFees(
    uint256 vaultId,
    uint256 mintFee,
    uint256 redeemFee,
    uint256 swapFee
)
```

Emitted by `setVaultFees()`. Fees are calculated in vToken, but paid in ETH. 1e16 = 0.01 vToken = 1%.&#x20;

<table><thead><tr><th width="200.33333333333331">Parameters</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr><tr><td>mintFee</td><td><code>address</code></td><td>New vault mint fee. </td></tr><tr><td>redeemFee</td><td><code>address</code></td><td>New vault redeem fee. </td></tr><tr><td>swapFee</td><td><code>string</code></td><td>New vault swap fee. </td></tr></tbody></table>

#### DisableVaultFees

```solidity
event DisableVaultFees(uint256 vaultId)
```

Emitted by `disableVaultFees()`.

<table><thead><tr><th width="200.33333333333331">Parameters</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr></tbody></table>

#### UpdateFactoryFees

```solidity
event UpdateFactoryFees(
    uint256 mintFee,
    uint256 redeemFee,
    uint256 swapFee
)
```

Emitted by `setFactoryFees()`. Fees are calculated in vToken, but paid in ETH. 1e16 = 0.01 vToken = 1%.&#x20;

<table><thead><tr><th width="200.33333333333331">Parameters</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>mintFee</td><td><code>address</code></td><td>New factory mint fee. </td></tr><tr><td>redeemFee</td><td><code>address</code></td><td>New factory redeem fee. </td></tr><tr><td>swapFee</td><td><code>string</code></td><td>New factory swap fee. </td></tr></tbody></table>

#### NewPremiumMax

```solidity
event NewPremiumMax(uint256 premiumMax)
```

Emitted by `setPremiumMax()`. Fees are calculated in vToken, but paid in ETH. 1e16 = 0.01 vToken = 1%.&#x20;

<table><thead><tr><th width="200.33333333333331">Parameters</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>premiumMax</td><td><code>uint256</code></td><td>New max premium fee. </td></tr></tbody></table>

#### NewPremiumDuration

```solidity
event NewPremiumDuration(uint256 premiumDuration)
```

Emitted by `setPremiumDuration()`. In seconds.&#x20;

<table><thead><tr><th width="207.33333333333331">Parameters</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>premiumDuration</td><td><code>uint256</code></td><td>New premium duration. </td></tr></tbody></table>

#### NewDepositorPremiumShare

```solidity
event NewDepositorPremiumShare(uint256 depositorPremiumShare)
```

Emitted by `setDepositorPremiumShare()`. 1e16 = 1%.

<table><thead><tr><th width="215.33333333333331">Parameters</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>depositPremiumShare</td><td><code>uint256</code></td><td>New depositor share of premium fee. </td></tr></tbody></table>

#### NewTwapInterval

```solidity
event NewTwapInterval(uint32 twapInterval)
```

Emitted by `setTwapInterval()`.

<table><thead><tr><th width="215.33333333333331">Parameters</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>twapInterval</td><td><code>uint256</code></td><td>The time-weighted average price interval. For example, if the <code>twapInterval</code> is set to <code>3600</code> seconds (1 hour), it would mean that you are interested in computing or observing the average price of an asset over the past hour.</td></tr></tbody></table>

## Write Functions

#### createVault

```solidity
function createVault(
    string memory name,
    string memory symbol,
    address assetAddress,
    bool is1155,
    bool allowAllItems
) external returns (uint256 vaultId)
```

Creates a vault.&#x20;

<table><thead><tr><th width="170.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>name</td><td><code>string</code></td><td>ERC20 vToken name of vault. </td></tr><tr><td>symbol</td><td><code>string</code></td><td>ERC20 vToken symbol for vault.</td></tr><tr><td>assetAddress</td><td><code>address</code></td><td>Address of NFT contract.</td></tr><tr><td>is1155</td><td><code>bool</code></td><td>Whether the NFT uses ERC1155.</td></tr><tr><td>allowAllItems</td><td><code>bool</code></td><td>Whether all NFT token IDs are eligible to enter.</td></tr></tbody></table>

<table><thead><tr><th width="170.5">Return values</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr></tbody></table>

## Privileged Functions

These functions can be called by vault contracts (on themselves) or by this contract's owner.

#### setVaultFees

```solidity
function setVaultFees(
    uint256 vaultId,
    uint256 mintFee,
    uint256 redeemFee,
    uint256 swapFee
) external
```

Sets mint, redeem, and (NFT-to-NFT) swap fees for a vault. 1e16 = 1%.

<table><thead><tr><th width="206.5">Parameters</th><th width="122">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr><tr><td>mintFee</td><td><code>uint256</code></td><td>New mint fee.</td></tr><tr><td>redeemFee</td><td><code>uint256</code></td><td>New redeem fee. </td></tr><tr><td>swapFee</td><td><code>uint256</code></td><td>New (NFT-to-NFT) swap fee.</td></tr></tbody></table>

#### disableVaultFees

```solidity
function disableVaultFees(uint256 vaultId) external
```

Revert vault to global/default fee settings.

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr></tbody></table>

## Owner Functions

#### setFactoryFees

```solidity
function setFactoryFees(
    uint256 mintFee,
    uint256 redeemFee,
    uint256 swapFee
) external
```

Sets global/default mint, redeem, and (NFT-to-NFT) swap fees. 1e16 = 1%.

<table><thead><tr><th width="206.5">Parameters</th><th width="122">Type</th><th>Description</th></tr></thead><tbody><tr><td>mintFee</td><td><code>uint256</code></td><td>New mint fee.</td></tr><tr><td>redeemFee</td><td><code>uint256</code></td><td>New redeem fee.</td></tr><tr><td>swapFee</td><td><code>uint256</code></td><td>New swap fee (for NFT-to-NFT swaps).</td></tr></tbody></table>

#### setFeeDistributor

```solidity
function setFeeDistributor(
    address feeDistributor_
) external
```

Sets address of NFTXFeeDistributorV3.&#x20;

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>feeDistributor_</td><td><code>address</code></td><td>New address of NFTXFeeDistributorV3.</td></tr></tbody></table>

#### setFeeExclusion

```solidity
function setFeeExclusion(
    address excludedAddr,
    bool excluded
) external
```

Sets whether an address is excluded from vault fees.&#x20;

<table><thead><tr><th width="206.5">Parameters</th><th width="122">Type</th><th>Description</th></tr></thead><tbody><tr><td>excludedAddr</td><td><code>address</code></td><td>Address being set.</td></tr><tr><td>excluded</td><td><code>bool</code></td><td>Whether the address is excluded from vault fees.</td></tr></tbody></table>

#### setEligibilityManager

```solidity
function setEligibilityManager(
    address eligibilityManager_
) external
```

Sets address of NFTXEligibilityManager.

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>eligibilityManager_</td><td><code>address</code></td><td>New address of NFTXEligibilityManager.</td></tr></tbody></table>

#### setTwapInterval

```solidity
function setTwapInterval(uint32 twapInterval_) external
```

Sets the TWAP interval duration. In seconds.

<table><thead><tr><th width="210.5">Name</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>twapInterval_</td><td><code>uint32</code></td><td>New TWAP interval.</td></tr></tbody></table>

#### setPremiumDuration

```solidity
function setPremiumDuration(
    uint256 premiumDuration_
) external
```

Sets the time it takes, in seconds, for premium fees to decay from `premiumMax` to zero.

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>premiumDuration_</td><td><code>uint256</code></td><td>New duration.</td></tr></tbody></table>

#### setPremiumMax

```solidity
function setPremiumMax(uint256 premiumMax_) external
```

Sets the starting (max) premium fee.

<table><thead><tr><th width="206.5">Parameters</th><th width="122">Type</th><th>Description</th></tr></thead><tbody><tr><td>premiumMax_</td><td><code>uint256</code></td><td>New max premium. 1e16 = 1%.</td></tr></tbody></table>

#### setDepositorPremiumShare

```solidity
function setDepositorPremiumShare(
    uint256 depositorPremiumShare_
) external
```

Sets the portion of premium fee that goes to depositor.

<table><thead><tr><th width="237.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>depositorPremiumShare_</td><td><code>uint256</code></td><td>New depositor share. 1e16 = 1%.</td></tr></tbody></table>

## Read Functions

#### vaultFees

```solidity
function vaultFees(uint256 vaultId)
    external
    view
    returns (uint256 mintFee, uint256 redeemFee, uint256 swapFee)
```

Returns the mint, redeem, and (NFT-to-NFT) swap fees for a vault.

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>mintFee</td><td><code>uint256</code></td><td>Mint fee.</td></tr><tr><td>redeemFee</td><td><code>uint256</code></td><td>Redeem fee.</td></tr><tr><td>swapFee</td><td><code>uint256</code></td><td>(NFT-to-NFT) swap fee.</td></tr></tbody></table>

#### isLocked

```solidity
function isLocked(uint256 lockId) external view returns (bool)
```

Checks whether the NFTX protocol is locked (i.e., paused).&#x20;

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>lockId</td><td><code>uint256</code></td><td>The ID of the lock type.</td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>bool</code></td><td>Whether the lock type is active.</td></tr></tbody></table>

#### vaultsForAsset

```solidity
function vaultsForAsset(
    address assetAddress
) external view returns (address[] memory)
```

Returns addresses for all vaults that are linked to an NFT address.

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>assetAddress</td><td><code>address</code></td><td>Address of NFT contract.</td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>address[]</code></td><td>Array of vault addresses.</td></tr></tbody></table>

#### allVaults

```solidity
function allVaults() external view returns (address[] memory)
```

Returns addresses of all vaults.

<table><thead><tr><th width="210.5">Return values</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>address</code></td><td>Array of all vault addresses.</td></tr></tbody></table>

#### numVaults

```solidity
function numVaults() external view returns (uint256)
```

Returns total number of NFTX V3 vaults.&#x20;

<table><thead><tr><th width="210.5">Return values</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>bool</code></td><td>Number of vaults.</td></tr></tbody></table>

#### vault

```solidity
function vault(uint256 vaultId) external view returns (address)
```

Returns the address of a vault.

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>address</code></td><td>Vault address.</td></tr></tbody></table>

#### computeVaultAddress

```solidity
function computeVaultAddress(
    address assetAddress,
    string memory name,
    string memory symbol
) external view returns (address)
```

Returns a deterministic address based on an `assetAddress`, `name`, and `symbol`.&#x20;

#### getTwapX96

```solidity
function getTwapX96(
    address pool
) external view returns (uint256 priceX96)
```

Returns the TWAP of the given pool, across the recent `twapInterval`. The returned value is in UniswapV3's 96-bit fixed point representation.

<table><thead><tr><th width="210.5">Parameters</th><th width="132">Type</th><th>Description</th></tr></thead><tbody><tr><td>pool</td><td><code>address</code></td><td>Address of AMM pool to check. </td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="132">Type</th><th>Description</th></tr></thead><tbody><tr><td>priceX96</td><td><code>uint256</code></td><td>TWAP represented as 96-bit FixedPoint.</td></tr></tbody></table>

#### getVTokenPremium721

```solidity
function getVTokenPremium721(
    uint256 vaultId,
    uint256 tokenId
) external view returns (uint256 premium, address depositor)
```

Returns premium fee for redeeming or swapping an ERC721 NFT from a vault.

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault. </td></tr><tr><td>tokenId</td><td><code>uint256</code></td><td>ID of NFT.</td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>premium</td><td><code>uint256</code></td><td>Premium fee.</td></tr><tr><td>depositor</td><td><code>uint256</code></td><td>Address of NFT depositor. </td></tr></tbody></table>

#### getVTokenPremium1155

```solidity
function getVTokenPremium1155(
    uint256 vaultId,
    uint256 tokenId,
    uint256 amount
)
    external
    view
    returns (
        uint256 netPremium,
        uint256[] memory premiums,
        address[] memory depositors
    )
```

Returns premium fee for redeeming or swapping for ERC1155 NFTs from a vault.

<table><thead><tr><th width="210.5">Parameters</th><th width="130">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault. </td></tr><tr><td>tokenId</td><td><code>uint256</code></td><td>ID of NFT.</td></tr><tr><td>amount</td><td><code>uint256</code></td><td>Quantity of NFT.</td></tr></tbody></table>

<table><thead><tr><th width="210.5">Return values</th><th width="130">Type</th><th>Description</th></tr></thead><tbody><tr><td>netPremium</td><td><code>uint256</code></td><td>Total premium fee to purchase <code>amount</code>.</td></tr><tr><td>premiums</td><td><code>uint256[]</code></td><td>Premium fees.</td></tr><tr><td>depositors</td><td><code>uint256[]</code></td><td>Addresses of NFT depositors. </td></tr></tbody></table>


# NFTXFeeDistributorV3

NFTXFeeDistributorV3.sol

Fee distributor contract for distributing vault fees.&#x20;

## Table of Contents

<details>

<summary>Constants</summary>

[#nftxvaultfactory](#nftxvaultfactory "mention")\
[#ammfactory](#ammfactory "mention")\
[#inventorystaking](#inventorystaking "mention")\
[#weth](#weth "mention")\
[#pool\_default\_alloc](#pool_default_alloc "mention")\
[#inventory\_default\_alloc](#inventory_default_alloc "mention")

</details>

<details>

<summary>Variables</summary>

[#rewardfeetier](#rewardfeetier "mention")\
[#nftxrouter](#nftxrouter "mention")\
[#treasury](#treasury "mention")\
[#alloctotal](#alloctotal "mention")\
[#feereceivers](#feereceivers "mention")\
[#distributionpaused](#distributionpaused "mention")

</details>

<details>

<summary>Events</summary>

[#updatetreasuryaddress](#updatetreasuryaddress "mention")\
[#pausedistribution](#pausedistribution "mention")\
[#newrewardfeetier](#newrewardfeetier "mention")\
[#newnftxrouter](#newnftxrouter "mention")\
[#wethdistributedtoinventory](#wethdistributedtoinventory "mention")\
[#wethdistributedtopool](#wethdistributedtopool "mention")

</details>

<details>

<summary>Public Write Functions</summary>

[#distribute](#distribute "mention")\
[#distributevtokenstopool](#distributevtokenstopool "mention")

</details>

<details>

<summary>Owner Write Functions</summary>

[#setreceivers](#setreceivers "mention")\
[#changerewardfeetier](#changerewardfeetier "mention")\
[#settreasuryaddress](#settreasuryaddress "mention")\
[#setnftxrouter](#setnftxrouter "mention")\
[#pausefeedistribution](#pausefeedistribution "mention")\
[#rescuetokens](#rescuetokens "mention")

</details>

## Constants

#### nftxVaultFactory

```solidity
function nftxVaultFactory() external view returns (address)
```

Address of NFTX vault factory.

#### ammFactory

```solidity
function ammFactory() external view returns (address)
```

Address of NFTX AMM pool factory.&#x20;

#### inventoryStaking

```solidity
function inventoryStaking() external view returns (address)
```

Address of NFTX inventory staking contract.&#x20;

#### WETH

```solidity
function WETH() external view returns (address)
```

Address of WETH contract.&#x20;

#### POOL\_DEFAULT\_ALLOC

```solidity
uint256 constant POOL_DEFAULT_ALLOC = 0.8 ether
```

Global liquidity provider vault fee percentage, set to 80%.

#### INVENTORY\_DEFAULT\_ALLOC

```solidity
uint256 constant INVENTORY_DEFAULT_ALLOC = 0.2 ether
```

Global inventory staker vault fee percentage, set to 20%.

## Variables

#### rewardFeeTier

```solidity
function rewardFeeTier() external view returns (uint24)
```

AMM pool fee tier that receives vault fees for liquidity providers.

#### nftxRouter

```solidity
function nftxRouter() external view returns (address)
```

Contract address of NFTX router.

#### treasury

```solidity
function treasury() external view returns (address)
```

Treasury address.

#### allocTotal

```solidity
function allocTotal() external view returns (uint256)
```

Total allocation across all `feeReceivers`.

#### feeReceivers

```solidity
function feeReceivers(
    uint256
)
    external
    view
    returns (
        address receiver,
        uint256 allocPoint,
        ReceiverType receiverType
    )
    
enum ReceiverType {
    INVENTORY,
    POOL,
    ADDRESS
}
```

List of fee receivers.

#### distributionPaused

```solidity
function distributionPaused() external view returns (bool)
```

Whether fee distribution has been paused.

## Events

#### UpdateTreasuryAddress

```solidity
event UpdateTreasuryAddress(address oldTreasury, address newTreasury)
```

Emitted by `setTreasuryAddress()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="124">Type</th><th>Description</th></tr></thead><tbody><tr><td>oldTreasury</td><td><code>address</code></td><td>Previous treasury address.</td></tr><tr><td>newTreasury</td><td><code>address</code></td><td>New treasury address.</td></tr></tbody></table>

#### PauseDistribution

```solidity
event PauseDistribution(bool paused)
```

Emitted by `pauseFeeDistribution()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="124">Type</th><th>Description</th></tr></thead><tbody><tr><td>paused</td><td><code>bool</code></td><td>Whether the contract was paused or unpaused.</td></tr></tbody></table>

#### NewRewardFeeTier

```solidity
event NewRewardFeeTier(uint24 rewardFeeTier)
```

Emitted by `changeRewardFeeTier()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="124">Type</th><th>Description</th></tr></thead><tbody><tr><td>rewardFeeTier</td><td><code>address</code></td><td>The new reward fee tier that determins which AMM pools receive vault rewards .</td></tr></tbody></table>

#### NewNFTXRouter

```solidity
event NewNFTXRouter(address nftxRouter)
```

Emitted by `setNFTXRouter()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="124">Type</th><th>Description</th></tr></thead><tbody><tr><td>nftxRouter</td><td><code>address</code></td><td>New NFTXRouter address.</td></tr></tbody></table>

#### WethDistributedToInventory

```solidity
event WethDistributedToInventory(uint256 vaultId, uint256 amount)
```

Emitted by `distribute()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="124">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr><tr><td>amount</td><td><code>uin256</code></td><td>Amount of WETH.</td></tr></tbody></table>

#### WethDistributedToPool

```solidity
event WethDistributedToPool(uint256 vaultId, uint256 amount)
```

Emitted by `distribute()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="124">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID number of vault.</td></tr><tr><td>amount</td><td><code>uin256</code></td><td>Amount of WETH.</td></tr></tbody></table>

## Write Functions

#### distribute

```solidity
function distribute(uint256 vaultId) external
```

Distributes current WETH balance to `feeReceivers` for `vaultId.`

<table><thead><tr><th width="170.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr></tbody></table>

#### distributeVTokensToPool

```solidity
function distributeVTokensToPool(
    address pool,
    address vToken,
    uint256 vTokenAmount
) external
```

Distributes vTokens to NFTX AMM pool. Can only be called by NFTXRouter when vTokens have been paid as part of an early withdrawal penalty.

<table><thead><tr><th width="170.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>pool</td><td><code>address</code></td><td>Address of pool.</td></tr><tr><td>vToken</td><td><code>address</code></td><td>Address of vToken.</td></tr><tr><td>vTokenAmount</td><td><code>uint256</code></td><td>Amount of vToken.</td></tr></tbody></table>

## Owner Functions

#### setReceivers

```solidity
function setReceivers(
    FeeReceiver[] memory feeReceivers_
) external

struct FeeReceiver {
    address receiver;
    uint256 allocPoint;
    ReceiverType receiverType; // NOTE: receiver address is ignored for `POOL` type, as each vaultId has different pool address
}

enum ReceiverType {
    INVENTORY,
    POOL,
    ADDRESS
}
```

Sets fee receivers.

<table><thead><tr><th width="201.5">Parameters</th><th width="168">Type</th><th>Description</th></tr></thead><tbody><tr><td>feeReceivers_</td><td><code>FeeReceiver[]</code></td><td>New fee receivers array.</td></tr></tbody></table>

#### changeRewardFeeTier

```solidity
function changeRewardFeeTier(uint24 rewardFeeTier_) external
```

Sets new reward fee tier (determining which AMM pool receives vault fees).&#x20;

Updating the reward fee tier here won't change the cardinality of existing AMM pools already deployed with `rewardFeeTier_`. That has to be increased externally for each pool. If the new rewardFeeTier pool doesn't exist for a vToken, then the corresponding vault fees immediately become 0 until liquidity is provided in the new pool.

<table><thead><tr><th width="206.5">Parameters</th><th width="122">Type</th><th>Description</th></tr></thead><tbody><tr><td>rewardFeeTier_</td><td><code>uint24</code></td><td>New reward fee tier. </td></tr></tbody></table>

#### setTreasuryAddress

```solidity
function setTreasuryAddress(address treasury_) external
```

Sets new treasury address.&#x20;

<table><thead><tr><th width="210.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>treasury_</td><td><code>address</code></td><td>New treasury address.</td></tr></tbody></table>

#### setNFTXRouter

```solidity
function setNFTXRouter(INFTXRouter nftxRouter_) external
```

Sets NFTXRouter address.

<table><thead><tr><th width="210.5">Parameters</th><th width="148">Type</th><th>Description</th></tr></thead><tbody><tr><td>nftxRouter_</td><td><code>INFTXRouter</code></td><td>New NFTXRouter address.</td></tr></tbody></table>

#### pauseFeeDistribution

```solidity
function pauseFeeDistribution(bool pause) external
```

Pauses (or resumes) fee distribution.

<table><thead><tr><th width="210.5">Parameters</th><th width="148">Type</th><th>Description</th></tr></thead><tbody><tr><td>pause</td><td><code>bool</code></td><td>Whether the contract is being paused or un-paused.</td></tr></tbody></table>

#### rescueTokens

```solidity
function rescueTokens(IERC20 token) external
```

Rescues ERC20 token.

<table><thead><tr><th width="210.5">Name</th><th width="148">Type</th><th>Description</th></tr></thead><tbody><tr><td>token</td><td><code>IERC20</code></td><td>Address of token being rescued.</td></tr></tbody></table>


# NFTXInventoryStakingV3Upgradeable

NFTXInventoryStakingV3Upgradeable.sol

This contract allows users to stake vTokens to earn fees. Inventory staking positions are minted as xNFTs.&#x20;

## Table of Contents

<details>

<summary>Constants</summary>

[#minimum\_liquidity](#minimum_liquidity "mention")\
[#vtoken\_timelock](#vtoken_timelock "mention")\
[#weth](#weth "mention")\
[#permit2](#permit2 "mention")\
[#nftxvaultfactory](#nftxvaultfactory "mention")\
[#timelockexcludelist](#timelockexcludelist "mention")\
[#max\_timelock](#max_timelock "mention")\
[#max\_early\_withdraw\_penalty](#max_early_withdraw_penalty "mention")\
[#base](#base "mention")

</details>

<details>

<summary>Variables</summary>

[#timelock](#timelock "mention")\
[#earlywithdrawpenaltyinwei](#earlywithdrawpenaltyinwei "mention")\
[#positions](#positions "mention")\
[#vaultglobal](#vaultglobal "mention")\
[#descriptor](#descriptor "mention")

</details>

<details>

<summary>Events</summary>

[#deposit](#deposit "mention")\
[#depositwithnft](#depositwithnft "mention")\
[#combinepositions](#combinepositions "mention")\
[#collectwethfees](#collectwethfees "mention")\
[#withdraw](#withdraw "mention")\
[#updatetimelock](#updatetimelock "mention")\
[#updateearlywithdrawpenalty](#updateearlywithdrawpenalty "mention")

</details>

<details>

<summary>Public Write Functions</summary>

[#deposit-1](#deposit-1 "mention")\
[#depositwithnft-1](#depositwithnft-1 "mention")\
[#increaseposition](#increaseposition "mention")\
[#withdraw-1](#withdraw-1 "mention")\
[#combinepositions-1](#combinepositions-1 "mention")\
[#collectwethfees-1](#collectwethfees-1 "mention")\
[#receivewethrewards](#receivewethrewards "mention")

</details>

<details>

<summary>Owner Write Functions</summary>

[#settimelock](#settimelock "mention")\
[#setearlywithdrawpenalty](#setearlywithdrawpenalty "mention")

</details>

<details>

<summary>Read Functions</summary>

[#pricepersharevtoken](#pricepersharevtoken "mention")

</details>

## Constants

#### MINIMUM\_LIQUIDITY

```solidity
uint256 public constant override MINIMUM_LIQUIDITY = 1_000
```

The minimum amount of vToken required to be staked if the total vToken shares are 0 for that vault.

#### VTOKEN\_TIMELOCK

```solidity
uint256 private constant VTOKEN_TIMELOCK = 1 hours
```

The timelock applied to all xNFTs made by depositing vToken, even if `forceTimelock` is false.

#### WETH

```solidity
function WETH() external view returns (address)
```

Address of `WETH` contract.

#### PERMIT2

```solidity
function PERMIT2() external returns (address)
```

Address of PERMIT2 contract.&#x20;

#### nftxVaultFactory

```solidity
function nftxVaultFactory() external view returns (address)
```

Address of NFTX Vault Factory.

#### timelockExcludeListYeah&#x20;

```solidity
function timelockExcludeList() external view returns (address)
```

List of addresses excluded from having timelocks enforced.

#### MAX\_TIMELOCK

```solidity
uint256 constant MAX_TIMELOCK = 14 days
```

Max timelock duration possible to have set.

#### MAX\_EARLY\_WITHDRAW\_PENALTY

```solidity
uint256 constant MAX_EARLY_WITHDRAW_PENALTY = 1 ether
```

Max early withdrawal penalty, 10e16 = 1%.&#x20;

#### BASE

```solidity
uint256 constant BASE = 1 ether
```

Equal to 10e18.

## Variables

#### timelock

```solidity
function timelock() external view returns (uint256)
```

The timelock duration applied to a position (when minted with NFTs or with forceTimelock).

#### earlyWithdrawPenaltyInWei

```solidity
function earlyWithdrawPenaltyInWei() external view returns (uint256)
```

Early withdrawal penalty. 1e16 = 1%.

#### positions

```solidity
function positions(
    uint256 positionId
)
    external
    view
    returns (
        uint256 nonce,
        uint256 vaultId,
        uint256 timelockedUntil,
        uint256 timelock,
        uint256 vTokenTimelockedUntil,
        uint256 vTokenShareBalance,
        uint256 wethFeesPerVTokenShareSnapshotX128,
        uint256 wethOwed
    )
```

Inventory staking data related to each positionId.&#x20;

#### vaultGlobal

```solidity
function vaultGlobal(
    uint256 vaultId
)
    external
    view
    returns (
        uint256 totalVTokenShares,
        uint256 globalWethFeesPerVTokenShareX128
    )
```

Inventory staking data related to each vaultId. &#x20;

#### descriptor

```solidity
function descriptor() external view returns (address)
```

Contract responsible for generating tokenURI for xNFT positions.

## Events

#### Deposit

```solidity
event Deposit(
    uint256 indexed vaultId,
    uint256 indexed positionId,
    uint256 amount,
    bool forceTimelock
)
```

Emitted by `deposit()`.&#x20;

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="124">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr><tr><td>positionId</td><td><code>uint256</code></td><td>ID of staking position.</td></tr><tr><td>amount</td><td><code>uint256</code></td><td>Amount of vToken being deposited.</td></tr><tr><td>forceTimelock</td><td><code>bool</code></td><td>Whether to force a full timelock. Forcing a full timelock allows vToken inventory stakers to off-ramp to NFTs (without paying redeem fees) when they are done staking.</td></tr></tbody></table>

#### DepositWithNFT

```solidity
event DepositWithNFT(
    uint256 indexed vaultId,
    uint256 indexed positionId,
    uint256[] tokenIds,
    uint256[] amounts
)
```

Emitted by `depositWithNFF()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault. </td></tr><tr><td>positionId</td><td><code>uint256</code></td><td>ID of staking position.</td></tr><tr><td>tokenIds</td><td><code>uint256[]</code></td><td>Token IDs of NFTs being deposited.</td></tr><tr><td>amounts</td><td><code>uint256[]</code></td><td>Amounts of NFTs (for ERC1155).</td></tr></tbody></table>

#### CombinePositions

```solidity
event CombinePositions(
    uint256 parentPositionId,
    uint256[] childPositionIds
)
```

Emitted by `combinePosition()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td>parentPositionId</td><td><code>uint256</code></td><td>ID number of parent position.</td></tr><tr><td>childPositionIds</td><td><code>uint256[]</code></td><td>ID numbers of child positions being merged into parent.</td></tr></tbody></table>

#### CollectWethFees

```solidity
event CollectWethFees(uint256 indexed positionId, uint256 wethAmount)
```

Emitted by `collectWethFees()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID of staking position.</td></tr><tr><td>wethAmount</td><td><code>uint256</code></td><td>Amount of WETH.</td></tr></tbody></table>

#### Withdraw

```solidity
event Withdraw(
    uint256 indexed positionId,
    uint256 vTokenShares,
    uint256 vTokenAmount,
    uint256 wethAmount
)
```

Emitted by `withdraw()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID of staking position.</td></tr><tr><td>vTokenShares</td><td><code>uint256</code></td><td>Amount of vToken shares subtracted from the position as a result of removing vToken.</td></tr><tr><td>vTokenAmount</td><td><code>uint256</code></td><td>Amount of vToken returned to sender.</td></tr><tr><td>wethAmount</td><td><code>uint256</code></td><td>Amount of WETH (fees) returned to sender.</td></tr></tbody></table>

#### UpdateTimelock

```solidity
event UpdateTimelock(uint256 newTimelock)
```

Emitted by `setTimelock()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td>newTimelock</td><td><code>uint256</code></td><td>New timelock duration. In seconds. </td></tr></tbody></table>

#### UpdateEarlyWithdrawPenalty

```solidity
event UpdateEarlyWithdrawPenalty(uint256 newEarlyWithdrawPenaltyInWei)
```

Emitted by `setEarlyWithdrawPenalty()`.

<table><thead><tr><th width="287.3333333333333">Parameters</th><th width="118">Type</th><th>Description</th></tr></thead><tbody><tr><td>newEarlyWithdrawPenaltyInWei</td><td><code>uint256</code></td><td>New early withdrawal penalty. 1e16 = 1%.</td></tr></tbody></table>

## Write Functions

#### deposit

```solidity
function deposit(
    uint256 vaultId,
    uint256 amount,
    address recipient,
    bytes calldata encodedPermit2,
    bool viaPermit2,
    bool forceTimelock
) external returns (uint256 positionId)
```

Pulls vToken from the caller and returns an xNFT inventory staking position. Uses Uniswap's Permit2 contract for vToken approval and transfer, if specified. The xNFT position will have a 1-hour (hard) timelock, during which time the position cannot be withdrawn. &#x20;

If the deposit is the first deposit that the inventory staking pool has ever received, then `MINIMUM_LIQUIDITY` (i.e, 1000 wei) of the vTokenShares are locked up forever to prevent [front-running attacks](https://ethereum-magicians.org/t/address-eip-4626-inflation-attacks-with-virtual-shares-and-assets/12677).

If `forceTimelock` is set to false, then no regular timelock is applied and the position can be increased using `increasePosition()` but the owner of the position can only withdraw/off-ramp back to vToken (not NFTs).&#x20;

If `forceTimelock` is set to true, then a regular 3-day timelock is applied in addition to the hard 1-hour timelock. Unlike the hard 1-hour time-lock, the regular 3-day timelock allows early withdrawals by charging a fee that begins at 10% and goes down linearly to zero over the duration of the timelock. The benefit of setting `forceTimelock` to `true` is that the owner of the position can withdraw/off-ramp to either vToken or NFTs.&#x20;

<table><thead><tr><th width="174.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>The vault ID of the vToken being deposited.</td></tr><tr><td>amount</td><td><code>uint256</code></td><td>The amount of vToken to deposit.</td></tr><tr><td>recipient</td><td><code>address</code></td><td>The address which will receive the xNFT. </td></tr><tr><td>encodedPermit2</td><td><code>bytes</code></td><td><p>Encoded Permit2 data:</p><pre class="language-solidity"><code class="lang-solidity">address owner,
IPermitAllowanceTransfer.PermitSingle,
bytes memory signature
</code></pre></td></tr><tr><td>viaPermit2</td><td><code>bool</code></td><td>Whether to use Permit2.</td></tr><tr><td>forceTimelock</td><td><code>bool</code></td><td>Whether to force a full 3-day timelock. See paragraph above for more details.</td></tr></tbody></table>

<table><thead><tr><th width="172.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID of the new inventory position.</td></tr></tbody></table>

#### depositWithNFT

```solidity
function depositWithNFT(
    uint256 vaultId,
    uint256[] calldata tokenIds,
    uint256[] calldata amounts,
    address recipient
) external returns (uint256 positionId)
```

Pulls NFTs from sender, mints, and stakes vToken, and returns an xNFT inventory staking position. The xNFT position will have a 3-day timelock, during which time an early withdrawal penalty is charged in vToken if the owner of the position decides to withdraw. The early withdrawal penalty is 10% of the position and goes down linearly to zero over the duration of the timelock.&#x20;

If the deposit is the first deposit that the inventory staking pool has ever received, then `MINIMUM_LIQUIDITY` (i.e, 1000 wei) of the vTokenShares are locked up forever to prevent [front-running attacks](https://ethereum-magicians.org/t/address-eip-4626-inflation-attacks-with-virtual-shares-and-assets/12677).

<table><thead><tr><th width="174.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>Vault ID of the vToken to be minted and staked.</td></tr><tr><td>tokenIDs</td><td><code>uint256[]</code></td><td>Token IDs of NFTs being deposited.</td></tr><tr><td>amounts</td><td><code>uint256[]</code></td><td>Amounts of NFTs (for ERC1155).</td></tr><tr><td>recipient</td><td><code>address</code></td><td>Address which receives the xNFT. </td></tr></tbody></table>

<table><thead><tr><th width="172.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID of the newly minted xNFT inventory position.</td></tr></tbody></table>

#### increasePosition

```solidity
function increasePosition(
    uint256 positionId,
    uint256 amount,
    bytes calldata encodedPermit2,
    bool viaPermit2,
    bool forceTimelock
) external
```

Increases the size of an inventory staking position that was created using vToken and did not force a regular 3-day timelock. Positions can be increased more than once as long as `forceTimelock` is `false`. After a position is increased with `forceTimelock` as `true`, then it can no longer be increased. It can, however, still be combined with other positions.

<table><thead><tr><th width="174.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID number of staking position.</td></tr><tr><td>amount</td><td><code>uint256</code></td><td>Amount of vToken.</td></tr><tr><td>encodedPermit2</td><td><code>bytes</code></td><td><p>Encoded Permit2 data:</p><pre class="language-solidity"><code class="lang-solidity">address owner,
IPermitAllowanceTransfer.PermitSingle,
bytes memory signature
</code></pre></td></tr><tr><td>viaPermit2</td><td><code>bool</code></td><td>Whether to use Permit2.</td></tr><tr><td>forceTimelock</td><td><code>bool</code></td><td>Whether to force a regular timelock. If a full timelock is enforced, then the position can not be increased again; however, it can still be combined with other positions.</td></tr></tbody></table>

#### withdraw

```solidity
function withdraw(
    uint256 positionId,
    uint256 vTokenShares,
    uint256[] calldata nftIds,
    uint256 vTokenPremiumLimit
) external payable override nonReentrant
```

Reduces a position's `vTokenShares` and returns vToken/NFTs and ETH to the caller. Charges an early withdrawal penalty, paid in vToken, if the position has an active timelock. The penalty begins at 10% and goes down linearly to zero over the 3-day timelock duration. Early withdrawals are not possible for vToken -created positions unless they forced a full 3-day timelock,

<table><thead><tr><th width="205.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID of the position.</td></tr><tr><td>vTokenShares</td><td><code>uint256</code></td><td>Number of vTokenShares to withdraw.</td></tr><tr><td>nftIds</td><td><code>uint256[]</code></td><td>NFT IDs to redeem.</td></tr><tr><td>vTokenPremiumLimit</td><td><code>uint256</code></td><td>Max total premium fee (denominated in vToken) to be paid.</td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send. </td></tr></tbody></table>

#### combinePositions

```solidity
function combinePositions(
    uint256 parentPositionId,
    uint256[] calldata childPositionIds
) external
```

Merges one or more child positions into a parent position. Requires that there are no timelocks remaining on any of the child positions.&#x20;

<table><thead><tr><th width="174.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>parentPositionId</td><td><code>uint256</code></td><td>The position that child positions merge into. </td></tr><tr><td>childPositionIds</td><td><code>uint256[]</code></td><td>The positions being merged into a parent position.</td></tr></tbody></table>

#### collectWethFees&#x20;

```solidity
function collectWethFees(uint256[] calldata positionIds) external
```

Claims WETH fees from one or more positions.

<table><thead><tr><th width="201.5">Parameters</th><th width="130">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionIds</td><td><code>uint256[]</code></td><td>IDs of the positions.</td></tr></tbody></table>

#### receiveWethRewards&#x20;

```solidity
function receiveWethRewards(
    uint256 vaultId,
    uint256 wethAmount
) external returns (bool rewardsDistributed)
```

Retrieves WETH rewards. Only callable by fee distributor.&#x20;

<table><thead><tr><th width="201.5">Parameters</th><th width="130">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID number of vault. </td></tr><tr><td>wethAmount</td><td><code>uint256</code></td><td>Amount of WETH.</td></tr></tbody></table>

<table><thead><tr><th width="201.5">Return values</th><th width="130">Type</th><th>Description</th></tr></thead><tbody><tr><td>rewardsDistributed</td><td><code>bool</code></td><td>True if function completes successfully.</td></tr></tbody></table>

## Owner Functions

#### setTimelock

```solidity
function setTimelock(uint256 timelock_) external
```

Sets the timelock duration for future deposits.&#x20;

<table><thead><tr><th width="201.5">Parameters</th><th width="130">Type</th><th>Description</th></tr></thead><tbody><tr><td>timelock_</td><td><code>uint256</code></td><td>New timelock duration, in seconds.</td></tr></tbody></table>

#### setEarlyWithdrawPenalty

```solidity
function setEarlyWithdrawPenalty(
    uint256 earlyWithdrawPenaltyInWei_
) external
```

Sets the early withdraw penalty for current and future deposits.&#x20;

<table><thead><tr><th width="263.5">Parameters</th><th width="109">Type</th><th>Description</th></tr></thead><tbody><tr><td>earlyWithdrawPenaltyInWei_</td><td><code>uint256</code></td><td>New early withdraw penalty. 10e16 = 1%.</td></tr></tbody></table>

## Read Functions

#### pricePerShareVToken

```solidity
function pricePerShareVToken(uint256 vaultId) external view returns (uint256)
```

Returns the ratio of vTokens per share. &#x20;

<table><thead><tr><th width="201.5">Parameters</th><th width="130">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>Vault ID of the vToken.</td></tr></tbody></table>

<table><thead><tr><th width="201.5">Name</th><th width="130">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>uint256</code></td><td>vTokens per share. </td></tr></tbody></table>

#### wethBalance

```solidity
function wethBalance(uint256 positionId) external view returns (uint256)
```

Returns the amount of WETH that can be claimed by the xNFT with `positionId`.

<table><thead><tr><th width="201.5">Parameters</th><th width="130">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionID</td><td><code>uint256</code></td><td>ID of position.</td></tr></tbody></table>

<table><thead><tr><th width="201.5">Return values</th><th width="130">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>uint256</code></td><td>WETH balance of position.</td></tr></tbody></table>


# UniswapV3PoolUpgradeable

UniswapV3PoolUpgradeable.sol

NFTX AMM pool contract. Uses BeaconProxy for deployments.

## Table of Contents

<details>

<summary>Variables</summary>

[#factory](#factory "mention")\
[#token0](#token0 "mention")\
[#token1](#token1 "mention")\
[#fee](#fee "mention")\
[#tickspacing](#tickspacing "mention")\
[#maxliquiditypertick](#maxliquiditypertick "mention")\
[#slot0](#slot0 "mention")\
[#feegrowthglobal0x128](#feegrowthglobal0x128 "mention")\
[#feegrowthglobal1x128](#feegrowthglobal1x128 "mention")\
[#protocolfees](#protocolfees "mention")\
[#liquidity](#liquidity "mention")\
[#ticks](#ticks "mention")\
[#tickbitmap](#tickbitmap "mention")\
[#positions](#positions "mention")\
[#observations](#observations "mention")

</details>

<details>

<summary>Events</summary>

[#initialize](#initialize "mention")\
[#mint](#mint "mention")\
[#collect](#collect "mention")\
[#burn](#burn "mention")\
[#swap](#swap "mention")\
[#flash](#flash "mention")\
[#increaseobservationcardinalitynext](#increaseobservationcardinalitynext "mention")\
[#setfeeprotocol](#setfeeprotocol "mention")\
[#collectprotocol](#collectprotocol "mention")

</details>

<details>

<summary>Public Write Functions</summary>

[#increaseobservationcardinalitynext-1](#increaseobservationcardinalitynext-1 "mention")\
[#initialize](#initialize "mention")\
[#mint-1](#mint-1 "mention")\
[#collect-1](#collect-1 "mention")\
[#burn-1](#burn-1 "mention")\
[#swap-1](#swap-1 "mention")\
[#distributerewards](#distributerewards "mention")\
[#swap-1](#swap-1 "mention")\
[#distributerewards](#distributerewards "mention")

</details>

<details>

<summary>Owner Write Functions</summary>

[#setfeeprotocol-1](#setfeeprotocol-1 "mention")\
[#collectprotocol-1](#collectprotocol-1 "mention")

</details>

<details>

<summary>Read Functions</summary>

[#balance0](#balance0 "mention")\
[#balance1](#balance1 "mention")\
[#snapshotcumulativesinside](#snapshotcumulativesinside "mention")\
[#observe](#observe "mention")

</details>

## Variables

#### factory

```solidity
function factory() external view returns (address)
```

Address of the NFTX AMM's `UniswapV3FactoryUpgradeable` contract.

#### token0

```solidity
function token0() external view returns (address)
```

Address of "token0" (either WETH or vToken).

#### token1

```solidity
function token1() external view returns (address)
```

Address of "token1" (either WETH or vToken).

#### fee

```solidity
function fee() external view returns (uint24)
```

AMM swap fee tier.

#### tickSpacing

```solidity
function tickSpacing() external view returns (int24)
```

Tick spacing of the pool.&#x20;

#### maxLiquidityPerTick

```solidity
function maxLiquidityPerTick() external view returns (uint128)
```

Maximum liquidity amount per tick.&#x20;

#### slot0

```solidity
function slot0()
    external
    view
    returns (
        uint160 sqrtPriceX96,
        int24 tick,
        uint16 observationIndex,
        uint16 observationCardinality,
        uint16 observationCardinalityNext,
        uint8 feeProtocol,
        bool unlocked
    )
```

Pool data.&#x20;

#### feeGrowthGlobal0X128

```solidity
function feeGrowthGlobal0X128() external view returns (uint256)
```

Represents the accumulated fees of token0 that have been earned per unit of liquidity since the contract was deployed, stored as a fixed-point number.

#### feeGrowthGlobal1X128

```solidity
function feeGrowthGlobal1X128() external view returns (uint256)
```

Represents the accumulated fees of token1 that have been earned per unit of liquidity since the contract was deployed, stored as a fixed-point number.

#### protocolFees

```solidity
function protocolFees() external view returns (uint128 token0, uint128 token1)
```

Accumulated fees owed to the protocol (for example, to the governance treasury).&#x20;

#### liquidity

```solidity
function liquidity() external view returns (uint128)
```

The total liquidity that's currently active in the pool.

#### ticks

```solidity
function ticks(int24 tick)
    external
    view
    returns (
        uint128 liquidityGross,
        int128 liquidityNet,
        uint256 feeGrowthOutside0X128,
        uint256 feeGrowthOutside1X128,
        int56 tickCumulativeOutside,
        uint160 secondsPerLiquidityOutsideX128,
        uint32 secondsOutside,
        bool initialized
    )
```

Tick data.

#### tickBitmap

```solidity
function tickBitmap(int16 wordPosition) external view returns (uint256)
```

A mapping that represents a sub-interval of ticks to help with gas-efficient calculations related to liquidity.

#### positions

```solidity
function positions(bytes32 key)
    external
    view
    returns (
        uint128 liquidity,
        uint256 feeGrowthInside0LastX128,
        uint256 feeGrowthInside1LastX128,
        uint128 tokensOwed0,
        uint128 tokensOwed1
    )
```

A mapping that keeps track of individual liquidity provider positions. The key to this mapping is a bytes32 value derived from the liquidity provider's address and the tick range in which they've provided liquidity.

#### observations

```solidity
function observations(uint256 index)
    external
    view
    returns (
        uint32 blockTimestamp,
        int56 tickCumulative,
        uint160 secondsPerLiquidityCumulativeX128,
        bool initialized
    )
```

An array used for calculating the time-weighted average price (TWAP).

## Events

#### Initialize

```solidity
event Initialize(uint160 sqrtPriceX96, int24 tick)
```

Emitted by `initialize()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td>sqrtPriceX96</td><td><code>uint160</code></td><td>Starting price.</td></tr><tr><td>tick</td><td><code>int24</code></td><td>Closest tick representing price. </td></tr></tbody></table>

#### Mint

<pre class="language-solidity"><code class="lang-solidity"><strong>event Mint(
</strong>    address sender,
    address indexed owner,
    int24 indexed tickLower,
    int24 indexed tickUpper,
    uint128 amount,
    uint256 amount0,
    uint256 amount1
)
</code></pre>

Emitted by `mint()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td>sender</td><td><code>address</code></td><td>The address that called the mint function to add liquidity.</td></tr><tr><td>owner</td><td><code>address</code></td><td>The address that will own the liquidity position and can collect fees on it.</td></tr><tr><td>tickLower</td><td><code>int24</code></td><td>The lower price tick of the price range for which the liquidity is being provided.</td></tr><tr><td>tickUpper</td><td><code>int24</code></td><td>The upper price tick of the price range for which the liquidity is being provided.</td></tr><tr><td>amount</td><td><code>uint128</code></td><td>The amount of liquidity that was added.</td></tr><tr><td>amount0</td><td><code>uint256</code></td><td>The amount of token0 that was added as liquidity.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>The amount of token1 that was added as liquidity.</td></tr></tbody></table>

#### Collect

```solidity
event Collect(
    address indexed owner,
    address recipient,
    int24 indexed tickLower,
    int24 indexed tickUpper,
    uint128 amount0,
    uint128 amount1
)
```

Emitted by `collect()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td>owner</td><td><code>address</code></td><td>The address that called the mint function to add liquidity.</td></tr><tr><td>recipient</td><td><code>address</code></td><td>The address that will own the liquidity position and can collect fees on it.</td></tr><tr><td>tickLower</td><td><code>int24</code></td><td>The lower price tick of the price range for which the liquidity is being provided.</td></tr><tr><td>tickUpper</td><td><code>int24</code></td><td>The upper price tick of the price range for which the liquidity is being provided.</td></tr><tr><td>amount0</td><td><code>uint256</code></td><td>The amount of token0 that was added as liquidity.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>The amount of token1 that was added as liquidity.</td></tr></tbody></table>

#### Burn

```solidity
event Burn(
    address indexed owner,
    int24 indexed tickLower,
    int24 indexed tickUpper,
    uint128 amount,
    uint256 amount0,
    uint256 amount1
)
```

Emitted by `burn()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td>owner</td><td><code>address</code></td><td>The address that owned the liquidity position and called the function to remove liquidity.</td></tr><tr><td>tickLower</td><td><code>int24</code></td><td>The lower price tick of the price range for which the liquidity was provided.</td></tr><tr><td>tickUpper</td><td><code>int24</code></td><td>The lower price tick of the price range for which the liquidity was provided.</td></tr><tr><td>amount</td><td><code>uint128</code></td><td>The amount of liquidity that was removed.</td></tr><tr><td>amount0</td><td><code>uint256</code></td><td>The amount of token0 that was removed as liquidity.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>The amount of token1 that was removed as liquidity.</td></tr></tbody></table>

#### Swap

```solidity
event Swap(
    address indexed sender,
    address indexed recipient,
    int256 amount0,
    int256 amount1,
    uint160 sqrtPriceX96,
    uint128 liquidity,
    int24 tick
)
```

Emitted by `swap()`.&#x20;

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td>sender</td><td><code>address</code></td><td>The address that initiated the swap.</td></tr><tr><td>recipient</td><td><code>address</code></td><td>The address that received the output tokens from the swap.</td></tr><tr><td>amount0</td><td><code>uint256</code></td><td>The change in the token0 balance as a result of the swap. A negative value indicates token0 was sold, and a positive value indicates token0 was bought.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>The change in the token1 balance as a result of the swap. A negative value indicates token1 was sold, and a positive value indicates token1 was bought.</td></tr><tr><td>sqrtPriceX96</td><td><code>uint160</code></td><td>The price of the pool after the swap has occurred. Encoded as the square root of the ratio of token amounts, and stored as a fixed-point number with 96 bits to the right of the decimal point.</td></tr><tr><td>liquidity</td><td><code>uint128</code></td><td>The active liquidity at the time the swap occurred.</td></tr><tr><td>tick</td><td><code>int24</code></td><td>Represents the tick index of the pool after the swap has occurred.</td></tr></tbody></table>

#### Flash

```solidity
event Flash(
    address indexed sender,
    address indexed recipient,
    uint256 amount0,
    uint256 amount1,
    uint256 paid0,
    uint256 paid1
)
```

Emitted by `flash()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td>sender</td><td><code>address</code></td><td>The address that initiated the flash swap.</td></tr><tr><td>recipient</td><td><code>address</code></td><td>The address that received the tokens from the flash swap.</td></tr><tr><td>amount0</td><td><code>uint256</code></td><td>The amount of token0 that the recipient received in the flash swap.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>The amount of token1 that the recipient received in the flash swap.</td></tr><tr><td>paid0</td><td><code>uint160</code></td><td>The amount of token0 that was paid back to the pool by the sender by the end of the transaction.</td></tr><tr><td>paid1</td><td><code>uint128</code></td><td>The amount of token1 that was paid back to the pool by the sender by the end of the transaction.</td></tr></tbody></table>

#### IncreaseObservationCardinalityNext

```solidity
event IncreaseObservationCardinalityNext(
    uint16 observationCardinalityNextOld,
    uint16 observationCardinalityNextNew
)
```

Emitted by `increaseObservationCardinalityNext()`.

<table><thead><tr><th width="290.3333333333333">Parameters</th><th width="100">Type</th><th>Description</th></tr></thead><tbody><tr><td>observationCardinalityNextOld</td><td><code>uint16</code></td><td>The previous value of the next maximum number of observations that the pool can store.</td></tr><tr><td>observationCardinalityNextNew</td><td><code>uint16</code></td><td>The updated value of the next maximum number of observations that the pool will store.</td></tr></tbody></table>

#### SetFeeProtocol

```solidity
event SetFeeProtocol(
    uint8 feeProtocol0Old, 
    uint8 feeProtocol1Old, 
    uint8 feeProtocol0New, 
    uint8 feeProtocol1New
)
```

Emitted by `setProtocolFee()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="116">Type</th><th>Description</th></tr></thead><tbody><tr><td>feeProtocol0Old</td><td><code>uint8</code></td><td>The previous value of the fee protocol setting for token0.</td></tr><tr><td>feeProtocol1Old</td><td><code>uint8</code></td><td>The previous value of the fee protocol setting for token1.</td></tr><tr><td>feeProtocol0New</td><td><code>uint8</code></td><td>The updated value of the fee protocol setting for token0.</td></tr><tr><td>feeProtocol1New</td><td><code>uint8</code></td><td>The updated value of the fee protocol setting for token1.</td></tr></tbody></table>

#### CollectProtocol

```solidity
event CollectProtocol(
    address indexed sender, 
    address indexed recipient, 
    uint128 amount0, 
    uint128 amount1
)
```

Emitted by `collectProtocol()`.

<table><thead><tr><th width="182.33333333333331">Parameters</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td>sender</td><td><code>address</code></td><td>The address that initiated the collection of the protocol fees.</td></tr><tr><td>recipient</td><td><code>address</code></td><td>The address that received the collected protocol fees.</td></tr><tr><td>amount0</td><td><code>uint256</code></td><td>The amount of token0 that was collected as a protocol fee.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>The amount of token1 that was collected as a protocol fee.</td></tr></tbody></table>

## Write Functions

#### increaseObservationCardinalityNext

```solidity
function increaseObservationCardinalityNext(
    uint16 observationCardinalityNext
) external
```

Used to schedule an increase in the maximum number of observations that the pool can store. Observations are utilized in the AMM pool for computing TWAPs. By invoking this function, the caller is expressing the intent to expand the observation capacity in the future. The actual expansion of capacity takes effect the next time the pool undergoes significant interaction, like when liquidity is added or when a swap occurs that moves the price.

<table><thead><tr><th width="256.5">Parameters</th><th width="110">Type</th><th>Description</th></tr></thead><tbody><tr><td>observationCardinalityNext</td><td><code>uint26</code></td><td>Specifies the desired future maximum number of observations the pool should be able to store. It should be set to a value greater than the current <code>observationCardinalityNext</code>.</td></tr></tbody></table>

#### initialize

```solidity
function initialize(uint160 sqrtPriceX96) external
```

Used to set the initial price of the pool when it's first created. This function can only be called once for a pool, when it's transitioning from an uninitialized to an initialized state. Typically called by the AMM pool factory contract during the creation of a new pool.

<table><thead><tr><th width="174.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>sqrtPriceX96</td><td><code>uint160</code></td><td>The starting price for the pool. Represented as the square root of the ratio of token amounts, stored as a fixed-point number with 96 bits to the right of the decimal point. </td></tr></tbody></table>

#### mint

```solidity
function mint(
    address recipient,
    int24 tickLower,
    int24 tickUpper,
    uint128 amount,
    bytes calldata data
) external returns (uint256 amount0, uint256 amount1)
```

Adds liquidity to a specific price range within the AMM pool.

<table><thead><tr><th width="174.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>recipient</td><td><code>address</code></td><td>The address that will receive the liquidity position NFT.</td></tr><tr><td>tickLower</td><td><code>int24</code></td><td>The lower bound (in tick terms) of the price range for which liquidity is being provided.</td></tr><tr><td>tickUpper</td><td><code>int24</code></td><td>The upper bound (in tick terms) of the price range for which liquidity is being provided.</td></tr><tr><td>amount</td><td><code>uint128</code></td><td>The amount of liquidity being added to the pool within the specified tick range. </td></tr><tr><td>data</td><td><code>bytes</code></td><td>Arbitrary calldata that is forwarded to a callback function.</td></tr></tbody></table>

<table><thead><tr><th width="174.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>amount0</td><td><code>uint256</code></td><td>The amount of token0 that the liquidity provider added to the pool.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>The amount of token1 that the liquidity provider added to the pool.</td></tr></tbody></table>

#### collect

```solidity
function collect(
    address recipient,
    int24 tickLower,
    int24 tickUpper,
    uint128 amount0Requested,
    uint128 amount1Requested
) external returns (uint128 amount0, uint128 amount1)
```

Allows liquidity providers to retrieve tokens owed from one or both of the two following scenarios:

1. To remove accumulated fees from their specified liquidity range.
2. To retrieve tokens from liquidity that has previously been removed from the position.

The function can be used to collect either or both of the pool tokens, up to amounts specified by the caller.

<table><thead><tr><th width="198.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>recipient</td><td><code>address</code></td><td>The address that will receive the collected tokens (either fees or tokens from removed liquidity).</td></tr><tr><td>tickLower</td><td><code>int24</code></td><td>The lower tick bound of the price range.</td></tr><tr><td>tickUpper</td><td><code>int24</code></td><td>The upper tick bound of the price range.</td></tr><tr><td>amount0Requested</td><td><code>uint128</code></td><td>The maximum amount of token0 that the caller wishes to collect.</td></tr><tr><td>amount1Requested</td><td><code>uint128</code></td><td>The maximum amount of token1 that the caller wishes to collect.</td></tr></tbody></table>

<table><thead><tr><th width="174.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>amount0</td><td><code>uint256</code></td><td>The amount of token0 collected.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>The amount of token1 collected.</td></tr></tbody></table>

#### burn

```solidity
function burn(
    int24 tickLower,
    int24 tickUpper,
    uint128 amount
) external returns (uint256 amount0, uint256 amount1)
```

Allows liquidity providers to remove, or "burn," a specified amount of liquidity from a particular price range in the pool. After burning liquidity, the underlying tokens aren't immediately returned to the caller. Instead, the tokens can be later collected using the `collect` function

<table><thead><tr><th width="174.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>tickLower</td><td><code>int24</code></td><td>The lower tick bound of the price range of the specific liquidity position from which liquidity is being removed.</td></tr><tr><td>tickUpper</td><td><code>int24</code></td><td>The upper tick bound of the price range of the specific liquidity position from which liquidity is being removed.</td></tr><tr><td>amount</td><td><code>uint128</code></td><td>The amount of liquidity that the caller wishes to remove from the specified position within the tick range.</td></tr></tbody></table>

<table><thead><tr><th width="174.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>amount0</td><td><code>uint256</code></td><td>The amount of token0 that was removed and is available for collection.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>The amount of token1 that was removed and is available for collection.</td></tr></tbody></table>

#### swap

```solidity
function swap(
    address recipient,
    bool zeroForOne,
    int256 amountSpecified,
    uint160 sqrtPriceLimitX96,
    bytes calldata data
) external returns (int256 amount0, int256 amount1)
```

Swaps one token for another, taking slippage, price limits, and other factors into account.&#x20;

<table><thead><tr><th width="187.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>recipient</td><td><code>int24</code></td><td>The address that will receive the tokens resulting from the swap.</td></tr><tr><td>zeroForOne</td><td><code>int24</code></td><td>True to swap token0 for token1, false to swap token1 for token0.</td></tr><tr><td>amountSpecified</td><td><code>int128</code></td><td>The exact amount of the token being sold (if positive) or the maximum amount of token one is willing to buy (if negative).</td></tr><tr><td>sqrtPriceLimitX96</td><td><code>uint160</code></td><td>A price constraint for the trade. If <code>zeroForOne</code> is <code>true</code>, the trade will only execute if the pool's price doesn't go above this value (representing a price floor). If <code>zeroForOne</code> is <code>false</code>, the trade will only execute if the pool's price doesn't go below this value (representing a price ceiling). It's represented as the square root of the price ratio encoded in a 96-bit fixed-point format. If set to zero, it means no price constraint is enforced.</td></tr><tr><td>data</td><td><code>bytes</code></td><td>Arbitrary calldata sent along with the function call, allowing for more complex logic or interactions if required by the recipient. It can be used for custom callbacks, which the pool will call after the core swap logic runs.</td></tr></tbody></table>

<table><thead><tr><th width="189.5">Name</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>amount0</td><td><code>uint256</code></td><td>The amount of <code>token0</code> that was either paid (if negative) or received (if positive).</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>The amount of <code>token1</code> that was either paid (if negative) or received (if positive).</td></tr></tbody></table>

#### distributeRewards

```solidity
function distributeRewards(
    uint256 rewardsAmount,
    bool isToken0
) external
```

Distributes the received vault fees among the current LPs, proportional to their liquidity contribution. Can only be called by feeDistributor, after it sends the reward tokens to this pool.&#x20;

<table><thead><tr><th width="187.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>rewardsAmount</td><td><code>int24</code></td><td>The amount of reward tokens to distribute</td></tr><tr><td>isToken0</td><td><code>int24</code></td><td>True if reward token is token0, false if it is token1.</td></tr></tbody></table>

#### flash

```solidity
function flash(
    address recipient,
    uint256 amount0,
    uint256 amount1,
    bytes calldata data
) external
```

Executes a flash swap within the AMM pool. Allows a smart contract to borrow tokens from the pool, execute specific logic, and then either repay the borrowed amount with fees or provide equivalent value in the other token—all within a single transaction.

<table><thead><tr><th width="187.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>recipient</td><td><code>address</code></td><td>The address that receives the borrowed tokens and is responsible for ensuring their return within the same transaction. This should ideally be a smart contract that implements the necessary callback logic to repay the borrowed funds.</td></tr><tr><td>amount0</td><td><code>uint256</code></td><td>The amount of <code>token0</code> to be borrowed from the pool.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>The amount of <code>token1</code> to be borrowed from the pool.</td></tr><tr><td>data</td><td><code>bytes</code></td><td>Arbitrary calldata forwarded to the recipient's callback function. This allows the recipient smart contract to specify additional parameters or custom logic that should be executed after the tokens are borrowed and before they are returned.</td></tr></tbody></table>

## Owner Functions

#### setFeeProtocol

```solidity
function setFeeProtocol(
    uint8 feeProtocol0,
    uint8 feeProtocol1
) external
```

Allows the factory owner to set or update the fee protocol values for the pool. This function doesn't directly set the protocol fee rate (i.e., the fraction of LP fees that become protocol fees—which is set on the SwapRouter). Instead, it sets how these collected protocol fees are allocated. This function can be seen as a way to change the internal allocation mechanism or beneficiaries without affecting the global setting at the factory level.

<table><thead><tr><th width="187.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>feeProtocol0</td><td><code>uint8</code></td><td>The fee protocol value for <code>token0</code>.</td></tr><tr><td>feeProtocol1</td><td><code>uint8</code></td><td>The fee protocol value for <code>token1</code>.</td></tr></tbody></table>

#### collectProtocol

```solidity
function collectProtocol(
    address recipient,
    uint128 amount0Requested,
    uint128 amount1Requested
) external
```

Collects protocol fees that have accrued in the pool. Protocol fees are distinct from the fees accrued by individual liquidity providers; they're set at the protocol level and typically go to a treasury or another protocol-specific address.

<table><thead><tr><th width="199.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>recipient</td><td><code>address</code></td><td>The address that will receive the collected protocol fees. This is typically a treasury or another designated address decided upon by the protocol's governance.</td></tr><tr><td>amount0Requested</td><td><code>uint128</code></td><td>The maximum amount of <code>token0</code> fees that the caller wishes to collect from the protocol's accumulated fees.</td></tr><tr><td>amount1Requested</td><td><code>uint128</code></td><td>The maximum amount of <code>token1</code> fees that the caller wishes to collect from the protocol's accumulated fees.</td></tr></tbody></table>

## Read Functions

#### snapshotCumulativesInside

```solidity
function snapshotCumulativesInside(
    int24 tickLower,
    int24 tickUpper
)
    external
    view
    returns (
        int56 tickCumulativeInside,
        uint160 secondsPerLiquidityInsideX128,
        uint32 secondsInside
    )
```

Provides a snapshot of the cumulative tick and liquidity values inside a specific tick range. It's designed to give insights and facilitate calculations related to accrued fees and other operations for positions within that range.

<table><thead><tr><th width="250.5">Parameters</th><th width="113">Type</th><th>Description</th></tr></thead><tbody><tr><td>tickLower</td><td><code>int24</code></td><td>The lower tick bound of the specific tick range for which the cumulative values are to be fetched.</td></tr><tr><td>tickUpper</td><td><code>int24</code></td><td>The upper tick bound of the specific tick range for which the cumulative values are to be fetched.</td></tr></tbody></table>

<table><thead><tr><th width="252.5">Return values</th><th width="112">Type</th><th>Description</th></tr></thead><tbody><tr><td>tickCumulativeInside</td><td><code>int56</code></td><td>The cumulative tick value within the specified range. This value represents the sum of all tick values each time liquidity was added or removed in the given range, up to the current moment. It's useful for calculating price changes over time.</td></tr><tr><td>secondsPerLiquidityInsideX128</td><td><code>uint160</code></td><td>A cumulative value representing the seconds per liquidity within the specified tick range, encoded in a 128-bit fixed-point format. It's useful for determining how long, on average, liquidity has been available in the tick range, helping in calculations related to fee accrual.</td></tr><tr><td>secondsInside</td><td><code>uint32</code></td><td>The total time in seconds that the pool's current tick has been within the specified tick range. This is useful for determining how long the current price has been within a certain range.</td></tr></tbody></table>

#### observe

```solidity
function observe(
    uint32[] calldata secondsAgos
)
    external
    view
    returns (
        int56[] memory tickCumulatives,
        uint160[] memory secondsPerLiquidityCumulativeX128s
    )
```

Retrieves historical data on the pool's tick and liquidity based on a set of specified past timestamps. It's designed to facilitate off-chain computations, particularly for time-weighted averages and other time-dependent metrics.

<table><thead><tr><th width="206.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>secondsAgos</td><td><code>uint32[]</code></td><td>An array of time durations in seconds. Each duration represents how far in the past the data should be fetched. For instance, if one of the durations is <code>3600</code>, it means the function should return the cumulative values from 1 hour ago.</td></tr></tbody></table>

<table><thead><tr><th width="205.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>tickCumulatives</td><td><code>int56[]</code></td><td>An array of cumulative tick values corresponding to each of the durations in the <code>secondsAgos</code> array. Each value represents the sum of all tick values up to the respective historical point. Useful for assessing price movements over multiple historical points.</td></tr><tr><td>secondsPerLiquidityCumulativeX128s</td><td><code>uint160</code></td><td>An array of cumulative values representing the seconds per liquidity up to each of the durations in the <code>secondsAgos</code> array, encoded in a 128-bit fixed-point format. This metric provides insights into how liquidity has changed over each of the specified durations.</td></tr></tbody></table>


# UniswapV3FactoryUpgradeable

UniswapV3FactoryUpgradeable.sol

Factory contract for creating AMM pools.&#x20;

## Table of Contents

<details>

<summary>Variables</summary>

[#feedistributor](#feedistributor "mention")\
[#feeamounttickspacing](#feeamounttickspacing "mention")\
[#getpool](#getpool "mention")\
[#rewardtiercardinality](#rewardtiercardinality "mention")

</details>

<details>

<summary>Events</summary>

[#poolcreated](#poolcreated "mention")\
[#feeamountenabled](#feeamountenabled "mention")

</details>

<details>

<summary>Public Write Functions</summary>

[#createpool](#createpool "mention")

</details>

<details>

<summary>Owner Write Functions</summary>

[#setfeedistributor](#setfeedistributor "mention")\
[#setrewardtiercardinality](#setrewardtiercardinality "mention")\
[#enablefeeamount](#enablefeeamount "mention")

</details>

<details>

<summary>Read Functions</summary>

[#owner](#owner "mention")

</details>

## Variables

#### feeDistributor

```solidity
function feeDistributor() external view returns (address)
```

Address of `NFTXFeeDistributorV3`.

#### feeAmountTickSpacing

```solidity
function feeAmountTickSpacing(uint24 fee) external view returns (int24)
```

Tick spacing value for a given fee tier. Tick spacing is capped at 16384, which represents a >5x price change with ticks of 1 bip.

#### getPool

```solidity
function getPool(
    address tokenA,
    address tokenB,
    uint24 fee
) external view returns (address pool)
```

Pool address for a given pair and fee, or 0 if the pool does not exist.&#x20;

#### rewardTierCardinality

```solidity
function rewardTierCardinality() external view returns (uint16)
```

The CardinalityNext value for the RewardFeeTier pools.&#x20;

## Events

#### PoolCreated

```solidity
event PoolCreated(
    address indexed token0,
    address indexed token1,
    uint24 indexed fee,
    int24 tickSpacing,
    address pool
)
```

Emitted by `createPool()`.

<table><thead><tr><th width="174.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>token0</td><td><code>address</code></td><td>Address of token0.</td></tr><tr><td>token1</td><td><code>address</code></td><td>Address of token1.</td></tr><tr><td>fee</td><td><code>uint24</code></td><td>Fee tier of pool.</td></tr><tr><td>tickSpacing</td><td><code>int24</code></td><td>Tick spacing of pool.</td></tr><tr><td>pool</td><td><code>address</code></td><td>Address of pool. </td></tr></tbody></table>

#### FeeAmountEnabled

```solidity
event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing)
```

Emitted by `__UniswapV3FactoryUpgradeable_init()` and `enableFeeAmount()`.&#x20;

<table><thead><tr><th width="174.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>fee</td><td><code>uint24</code></td><td>New fee tier just added.</td></tr><tr><td>tickSpacing</td><td><code>int24</code></td><td>Tick spacing for the fee tier. </td></tr></tbody></table>

## Write Functions

#### createPool

```solidity
function createPool(
    address tokenA,
    address tokenB,
    uint24 fee
) external returns (address pool)
```

Deploys a new pool, using a BeaconProxy.&#x20;

<table><thead><tr><th width="174.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenA</td><td><code>address</code></td><td>First token for pair.</td></tr><tr><td>tokenB</td><td><code>address</code></td><td>Second token for pair.</td></tr><tr><td>fee</td><td><code>uint24</code></td><td>Fee tier of pool. Must be one of the enabled fee tiers.</td></tr></tbody></table>

<table><thead><tr><th width="172.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>pool</td><td><code>address</code></td><td>Address of new pool.</td></tr></tbody></table>

## Owner Functions

#### setFeeDistributor

```solidity
function setFeeDistributor(address feeDistributor_) external
```

Sets the `NFTXFeeDistributorV3` address.

<table><thead><tr><th width="174.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>feeDistributor_</td><td><code>address</code></td><td>Updated address for fee distributor.</td></tr></tbody></table>

#### setRewardTierCardinality

```solidity
function setRewardTierCardinality(
    uint16 rewardTierCardinality_
) external
```

Sets the CardinalityNext value for the RewardFeeTier pools.&#x20;

<table><thead><tr><th width="219.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>rewardTierCardinality_</td><td><code>uint16</code></td><td>New reward tier cardinality.</td></tr></tbody></table>

#### enableFeeAmount

```solidity
function enableFeeAmount(uint24 fee, int24 tickSpacing) external
```

Enables a new fee amount option for pools, with a given tick spacing. Once enabled, fee amounts cannot be removed.&#x20;

<table><thead><tr><th width="174.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>fee</td><td><code>uint24</code></td><td>New fee tier being added.</td></tr><tr><td>tickSpacing</td><td><code>int24</code></td><td>Tick spacing for the new fee tier.</td></tr></tbody></table>

## Read Functions

#### owner

```solidity
function owner()
    public
    view
    returns (address)
```

Returns the contract owner.&#x20;

<table><thead><tr><th width="157.5">Return values</th><th width="218">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>address</code></td><td>Address of contract owner</td></tr></tbody></table>


# NonfungiblePositionManager

NonfungiblePositionManager.sol

Wraps AMM positions in the ERC721 non-fungible token interface.

## Table of Contents

<details>

<summary>Variables</summary>

[#lockeduntil](#lockeduntil "mention")\
[#timelock](#timelock "mention")\
[#timelockexcluded](#timelockexcluded "mention")

</details>

<details>

<summary>Events</summary>

[#increaseliquidity](#increaseliquidity "mention")\
[#decreaseliquidity](#decreaseliquidity "mention")\
[#collect](#collect "mention")

</details>

<details>

<summary>Public Write Functions</summary>

[#increaseliquidity-1](#increaseliquidity-1 "mention")\
[#decreaseliquidity-1](#decreaseliquidity-1 "mention")\
[#collect-1](#collect-1 "mention")\
[#burn](#burn "mention")

</details>

<details>

<summary>Owner Write Functions</summary>

[#settimelockexcluded](#settimelockexcluded "mention")

</details>

<details>

<summary>Read Functions</summary>

[#positions](#positions "mention")\
[#tokenuri](#tokenuri "mention")\
[#getapproved](#getapproved "mention")

</details>

## Variables

#### lockedUntil

```solidity
function lockedUntil(uint256 tokenId) external view returns (uint256)
```

Unix timestamps, in seconds, for each position describing when they can be unlocked (without paying an early withdrawal fee).

#### timelock

```solidity
function timelock(uint256 tokenId) external view returns (uint256)
```

The full duration of the most recent timelock applied to a position.

#### timelockExcluded

```solidity
function timelockExcluded(address addr) external view returns (bool)
```

Whether an address is excluded from having timelocks applied. Useful for some integrations.

## Events

#### IncreaseLiquidity

```solidity
event IncreaseLiquidity(
    uint256 indexed tokenId,
    uint128 liquidity,
    uint256 amount0,
    uint256 amount1
)
```

Emitted by `mint()` and `increaseLiquidity()`.

<table><thead><tr><th width="192.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>ID of liquidity position being increased.</td></tr><tr><td>liquidity</td><td><code>uint128</code></td><td>Amount of liquidity added.</td></tr><tr><td>amount0</td><td><code>uint256</code></td><td>Amount of token0 deposited.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>Amount of token1 deposited.</td></tr></tbody></table>

#### DecreaseLiquidity

```solidity
event DecreaseLiquidity(
    uint256 indexed tokenId,
    uint128 liquidity,
    uint256 amount0,
    uint256 amount1
)
```

Emitted by `decreaseLiquidity()`.

<table><thead><tr><th width="192.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>ID of liquidity position being decreased.</td></tr><tr><td>liquidity</td><td><code>uint128</code></td><td>Amount of liquidity removed.</td></tr><tr><td>amount0</td><td><code>uint256</code></td><td>Amount of token0 removed.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>Amount of token1 removed.</td></tr></tbody></table>

#### Collect

```solidity
event Collect(
    uint256 indexed tokenId,
    address recipient,
    uint256 amount0,
    uint256 amount1
)
```

Emitted by `collect()`.

<table><thead><tr><th width="192.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>ID of liquidity position. </td></tr><tr><td>recipient</td><td><code>address</code></td><td>Address that collected tokens.</td></tr><tr><td>amount0</td><td><code>uint256</code></td><td>Amount of token0 sent.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>Amount of token1 sent.</td></tr></tbody></table>

## Write Functions

#### increaseLiquidity

```solidity
function increaseLiquidity(
    IncreaseLiquidityParams calldata params
)
    external
    payable
    returns (uint128 liquidity, uint256 amount0, uint256 amount1)
```

Increases liquidity of a position.&#x20;

<table><thead><tr><th width="160.5">Parameters</th><th width="266">Type</th><th>Description</th></tr></thead><tbody><tr><td>params</td><td><code>IncreaseLiquidityParams</code></td><td>See table below.</td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH sent.</td></tr></tbody></table>

<table><thead><tr><th width="248.5">IncreaseLiquidityParams</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>ID of liquidity position.</td></tr><tr><td>amount0Desired</td><td><code>uint256</code></td><td>Desired token0 deposit amount.</td></tr><tr><td>amount1Desired</td><td><code>uint256</code></td><td>Desired token1 deposit amount.</td></tr><tr><td>amount0Min</td><td><code>uint256</code></td><td>Minimum required token0 deposit amount.</td></tr><tr><td>amount1Min</td><td><code>uint256</code></td><td>Minimum required token0 deposit amount.</td></tr></tbody></table>

<table><thead><tr><th width="249.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>liquidity</td><td><code>uint128</code></td><td>Amount of liquidity added.</td></tr><tr><td>amount0</td><td><code>uint256</code></td><td>Amount of token0 added.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>Amount of token1 added. </td></tr></tbody></table>

#### decreaseLiquidity

```solidity
function decreaseLiquidity(
    DecreaseLiquidityParams calldata params
)
    external
    payable
    returns (uint256 amount0, uint256 amount1)
```

Decreases the liquidity of a position. Tokens removed from liquidity are not actually transferred; they are simply accounted for as tokens owed to the position's owner, should they decide to call `collect()`.&#x20;

<table><thead><tr><th width="249.5">DecreaseLiquidityParams</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>ID of liquidity position.</td></tr><tr><td>liquidity</td><td><code>uint256</code></td><td>Amount of liquidity to remove. </td></tr><tr><td>amount0Min</td><td><code>uint256</code></td><td>Minimum required token0 removal.</td></tr><tr><td>amount1Min</td><td><code>uint256</code></td><td>Minimum required token1 removal.</td></tr><tr><td>deadline</td><td><code>uint256</code></td><td>Unix timestamp in seconds after which the transaction will not succeed.</td></tr></tbody></table>

<table><thead><tr><th width="249.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>amount0</td><td><code>uint256</code></td><td>Amount of token0 removed.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>Amount of token1 removed.</td></tr></tbody></table>

#### collect

```solidity
function collect(
    CollectParams calldata params
)
    external
    payable
    returns (uint256 amount0, uint256 amount1)
```

Retrieves tokens from a liquidity position (from fees earned and any liquidity removed).&#x20;

<table><thead><tr><th width="196.5">CollectParams</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>ID of liquidity position.</td></tr><tr><td>recipient</td><td><code>address</code></td><td>Address to receive tokens.</td></tr><tr><td>amount0Max</td><td><code>uint256</code></td><td>Maximum token0 amount to withdraw.</td></tr><tr><td>amount1Max</td><td><code>uint256</code></td><td>Maximum token1 amount to withdraw.</td></tr></tbody></table>

<table><thead><tr><th width="197.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>amount0</td><td><code>uint256</code></td><td>Amount of token0 sent.</td></tr><tr><td>amount1</td><td><code>uint256</code></td><td>Amount of token1 sent.</td></tr></tbody></table>

#### burn

```solidity
function burn(
    uint256 tokenId
) external payable
```

Burns a liquidity position. The position must have zero liquidity and zero tokens owed.&#x20;

<table><thead><tr><th width="192.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>ID of liquidity position to burn.</td></tr></tbody></table>

## Owner Functions

#### setTimelockExcluded

```solidity
function setTimelockExcluded(
    address addr,
    bool isExcluded
) external
```

Sets whether an address is excluded from having timelocks imposed on new positions.&#x20;

<table><thead><tr><th width="192.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>addr</td><td><code>address</code></td><td>Address to be excluded (or un-excluded).</td></tr><tr><td>isExcluded</td><td><code>bool</code></td><td>True to exclude, false to un-exclude.</td></tr></tbody></table>

## Read Functions

#### positions

```solidity
function positions(
    uint256 tokenId
)
    external
    view
    returns (
        uint96 nonce,
        address operator,
        address token0,
        address token1,
        uint24 fee,
        int24 tickLower,
        int24 tickUpper,
        uint128 liquidity,
        uint256 feeGrowthInside0LastX128,
        uint256 feeGrowthInside1LastX128,
        uint128 tokensOwed0,
        uint128 tokensOwed1
    )
```

Returns the position data of a liquidity position ID.&#x20;

<table><thead><tr><th width="257.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>ID of liquidity position. </td></tr></tbody></table>

<table><thead><tr><th width="256.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>nonce</td><td><code>uint96</code></td><td>The nonce for permits.</td></tr><tr><td>operator</td><td><code>address</code></td><td>Address that is approved for spending. </td></tr><tr><td>token0</td><td><code>address</code></td><td>Address of token0.</td></tr><tr><td>token1</td><td><code>address</code></td><td>Address of token1.</td></tr><tr><td>fee</td><td><code>uint24</code></td><td>Swap fee tier of the pool.</td></tr><tr><td>tickLower</td><td><code>int24</code></td><td>Lower bound tick of price range.</td></tr><tr><td>tickUpper</td><td><code>int24</code></td><td>Upper bound tick of price range.</td></tr><tr><td>liquidity</td><td><code>uint128</code></td><td>Liquidity of position.</td></tr><tr><td>feeGrowthInside0LastX128</td><td><code>uint256</code></td><td>Fee growth of token0 since the last action on the position.</td></tr><tr><td>feeGrowthInside1LastX128</td><td><code>uint256</code></td><td>Fee growth of token1 since the last action on the position.</td></tr><tr><td>tokensOwed0</td><td><code>uint128</code></td><td>Uncollected amount of token0 owed to the position.</td></tr><tr><td>tokensOwed1</td><td><code>uint128</code></td><td>Uncollected amount of token1 owed to the position.</td></tr></tbody></table>

#### tokenURI

```solidity
function tokenURI(
    uint256 tokenId
) external view returns (string memory)
```

Returns a liquidity position's NFT tokenURI.

<table><thead><tr><th width="192.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>ID of liquidity position. </td></tr></tbody></table>

<table><thead><tr><th width="192.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>string</code></td><td>TokenURI string. </td></tr></tbody></table>

#### getApproved

```solidity
function getApproved(
    uint256 tokenId
) external view returns (address)
```

Returns the `operator` of a liquidity position.&#x20;

<table><thead><tr><th width="192.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>Liquidity position ID.</td></tr></tbody></table>

<table><thead><tr><th width="192.5">Return values</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>address</code></td><td>Operator of position.</td></tr></tbody></table>


# NFTXRouter

NFTXRouter.sol

This contract interacts with the NFTX AMM for adding & removing liquidity, and facilitating buys & sells. It also handles minting and burning vTokens when necessary.

## Table of Contents

<details>

<summary>Constants</summary>

[#weth](#weth "mention")\
[#permit2](#permit2 "mention")\
[#positionmanager](#positionmanager "mention")\
[#router](#router "mention")\
[#quoter](#quoter "mention")\
[#nftxvaultfactory](#nftxvaultfactory "mention")\
[#inventorystaking](#inventorystaking "mention")

</details>

<details>

<summary>Variables</summary>

[#lptimelock](#lptimelock "mention")\
[#earlywithdrawpenaltyinwei](#earlywithdrawpenaltyinwei "mention")\
[#vtokendustthreshold](#vtokendustthreshold "mention")

</details>

<details>

<summary>Events</summary>

[#addliquidity](#addliquidity "mention")\
[#removeliquidity](#removeliquidity "mention")\
[#increaseliquidity](#increaseliquidity "mention")\
[#sellnfts](#sellnfts "mention")\
[#buynfts](#buynfts "mention")

</details>

<details>

<summary>Public Write Functions</summary>

[#addliquidity-1](#addliquidity-1 "mention")\
[#addliquiditywithpermit2](#addliquiditywithpermit2 "mention")\
[#increaseliquidity-1](#increaseliquidity-1 "mention")\
[#increaseliquiditywithpermit2](#increaseliquiditywithpermit2 "mention")\
[#removeliquidity-1](#removeliquidity-1 "mention")\
[#sellnfts-1](#sellnfts-1 "mention")\
[#buynfts-1](#buynfts-1 "mention")

</details>

<details>

<summary>Owner Write Functions</summary>

[#rescuetokens](#rescuetokens "mention")\
[#setlptimelock](#setlptimelock "mention")\
[#setvtokendustthreshold](#setvtokendustthreshold "mention")\
[#setearlywithdrawpenalty](#setearlywithdrawpenalty "mention")

</details>

<details>

<summary>Read Functions</summary>

[#quotebuynfts](#quotebuynfts "mention")\
[#getpoolexists](#getpoolexists "mention")\
[#getpool](#getpool "mention")\
[#computepool](#computepool "mention")\
[#isvtoken0](#isvtoken0 "mention")

</details>

## Constants

#### WETH

```solidity
function WETH() external returns (address)
```

Contract address of `WETH`.

#### PERMIT2

```solidity
function PERMIT2() external returns (address)
```

Contract address of PERMIT2.&#x20;

#### positionManager

```solidity
function positionManager() external returns (address)
```

Contract address of the AMM's `NonfungiblePositionManager`.

#### router

```solidity
function router() external returns (address)
```

Contract address of the AMM's `SwapRouter`.

#### quoter

```solidity
function quoter() external returns (address)
```

Contract address of the AMM's `QuoterV2`.

#### nftxVaultFactory

```solidity
function nftxVaultFactory() external returns (address)
```

Contract address of the NFTX vault factory.

#### inventoryStaking

```solidity
function inventoryStaking() external returns (address)
```

Address of inventory staking contract.

## Variables

#### lpTimelock

```solidity
function lpTimelock() external returns (uint256)
```

The timelock duration to apply to new positions.

#### earlyWithdrawPenaltyInWei

```solidity
function earlyWithdrawPenaltyInWei() external returns (uint256)
```

Early withdrawal fee. 1e16 = 1%.

#### vTokenDustThreshold

```solidity
function vTokenDustThreshold() external returns (uint256)
```

Threshold amount for vToken dust to be returned.

## Events

#### AddLiquidity

```solidity
event AddLiquidity(
    uint256 indexed positionId,
    uint256 vaultId,
    uint256 vTokensAmount,
    uint256[] nftIds,
    address pool
)
```

Emitted by `addLiquidity()` and `addLiquidityWithPermit2()`.

<table><thead><tr><th width="204">Parameters</th><th width="130.33333333333331">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID of liquidity position.</td></tr><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault. </td></tr><tr><td>vTokensAmount</td><td><code>uint256</code></td><td>Amount of vToken deposited.</td></tr><tr><td>nftIds</td><td><code>uint256[]</code></td><td>IDs of NFTs deposited.</td></tr><tr><td>pool</td><td><code>address</code></td><td>Address of pool contract.</td></tr></tbody></table>

#### RemoveLiquidity

```solidity
event RemoveLiquidity(
    uint256 indexed positionId,
    uint256 vaultId,
    uint256 vTokenAmt,
    uint256 wethAmt
)
```

Emitted by `removeLiquidity()`.

<table><thead><tr><th width="204">Parameters</th><th width="130.33333333333331">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID number of liquidity position.</td></tr><tr><td>vaultId</td><td><code>uint256</code></td><td>ID number of vault.</td></tr><tr><td>vTokensAmount</td><td><code>uint256</code></td><td>Amount of vToken received.</td></tr><tr><td>nftIds</td><td><code>uint256[]</code></td><td>IDs of NFTs received.</td></tr><tr><td>pool</td><td><code>address</code></td><td>Address of pool contract.</td></tr></tbody></table>

#### IncreaseLiquidity

```solidity
event IncreaseLiquidity(
    uint256 indexed positionId,
    uint256 vaultId,
    uint256 vTokensAmount,
    uint256[] nftIds
)
```

Emitted by `increaseLiquidity()` and `increaseLiquidityWithPermit2()`.

<table><thead><tr><th width="204">Parameters</th><th width="130.33333333333331">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID of liquidity position.</td></tr><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr><tr><td>vTokensAmount</td><td><code>uint256</code></td><td>Amount of vToken deposited.</td></tr><tr><td>nftIds</td><td><code>uint256[]</code></td><td>IDs of NFTs deposited.</td></tr></tbody></table>

#### SellNFTs

```solidity
event SellNFTs(uint256 nftCount, uint256 ethReceived)
```

Emitted by `sellNFTs()`.

<table><thead><tr><th width="204">Parameters</th><th width="130.33333333333331">Type</th><th>Description</th></tr></thead><tbody><tr><td>nftCount</td><td><code>uint256</code></td><td>Number of NFTs sold.</td></tr><tr><td>ethReceived</td><td><code>uint256</code></td><td>Amount of ETH received.</td></tr></tbody></table>

#### BuyNFTs

```solidity
event BuyNFTs(uint256 nftCount, uint256 ethSpent)
```

Emitted by `buyNFTs()`.

<table><thead><tr><th width="204">Parameters</th><th width="130.33333333333331">Type</th><th>Description</th></tr></thead><tbody><tr><td>nftCount</td><td><code>uint256</code></td><td>Number of NFTs bought.</td></tr><tr><td>ethSpent</td><td><code>uint256</code></td><td>Amount of ETH spent.</td></tr></tbody></table>

## Write Functions

#### addLiquidity

```solidity
function addLiquidity(
    AddLiquidityParams calldata params
) external payable returns (uint256 positionId)
```

Adds liquidity to an AMM pool (specified by a vToken address and a trading fee). Returns the token ID of the newly minted liquidity NFT. There can be at most one pool for each vToken/WETH pair and fee. If a pool with the specified fee and vToken does not already exist then one is created.

<table><thead><tr><th width="179.5">Parameters</th><th width="214">Type</th><th>Description</th></tr></thead><tbody><tr><td>params</td><td><code>AddLiquidityParams</code></td><td>See table below.</td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send.</td></tr></tbody></table>

<table><thead><tr><th width="207.5">AddLiquidityParams</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID number of vault.</td></tr><tr><td>vTokensAmount</td><td><code>uint256</code></td><td>Amount of vToken to add as liquidity.</td></tr><tr><td>nftIds</td><td><code>uint256[]</code></td><td>NFT IDs to have converted to vToken, then used for liquidity.</td></tr><tr><td>nftAmounts</td><td><code>uint256[]</code></td><td>Amounts of NFTs.</td></tr><tr><td>tickLower</td><td><code>int24</code></td><td>Lower end of the price range for the liquidity. Minimum value is -887272.</td></tr><tr><td>tickUpper</td><td><code>int24</code></td><td>Upper end of the price range for the liquidity. Maximum value is 887272.</td></tr><tr><td>fee</td><td><code>uint24</code></td><td>The pool's trading fee, denominated in hundredths of a bip. </td></tr><tr><td>sqrtPriceX96</td><td><code>uint160</code></td><td>Fixed point Q64.96 number equalling the sqrt of the desired asset ratio (token1/token0). Only used if pool with fee does not already exist, in which case it determines the starting price. </td></tr><tr><td>vTokenMin</td><td><code>uint256</code></td><td>Minimum required vToken amount added.</td></tr><tr><td>wethMin</td><td><code>uint256</code></td><td>Minimum required WETH amount added.</td></tr><tr><td>deadline</td><td><code>uint256</code></td><td>Unix timestamp after which the transaction will revert. </td></tr><tr><td>forceTimelock</td><td><code>bool</code></td><td>Whether a timelock is forced, only applicable for vToken deposits. Forcing a timelock allows for off-ramping to NFTs when finished LPing, if desired.</td></tr></tbody></table>

<table><thead><tr><th width="211.5">Return values</th><th width="126">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID number of liquidity position NFT.</td></tr></tbody></table>

#### addLiquidityWithPermit2

```solidity
function addLiquidityWithPermit2(
    AddLiquidityParams calldata params,
    bytes calldata encodedPermit2
) external payable returns (uint256 positionId)
```

Adds liquidity using Permit2 contract.

<table><thead><tr><th width="179.5">Parameters</th><th width="214">Type</th><th>Description</th></tr></thead><tbody><tr><td>params</td><td><code>AddLiquidityParams</code></td><td>See <a data-mention href="#addliquidity-1">#addliquidity-1</a> function above.</td></tr><tr><td>encodedPermit2</td><td><code>bytes</code></td><td><p>Encoded Permit2 data:</p><pre class="language-solidity"><code class="lang-solidity">address owner,
IPermitAllowanceTransfer.PermitSingle,
bytes memory signature
</code></pre></td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send. </td></tr></tbody></table>

<table><thead><tr><th width="179.5">Return values</th><th width="216">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID number of liquidity position NFT.</td></tr></tbody></table>

#### increaseLiquidity

```solidity
function increaseLiquidity(
    IncreaseLiquidityParams calldata params
) external payable
```

Increase the size of a liquidity position.

<table><thead><tr><th width="179.5">Parameters</th><th width="262">Type</th><th>Description</th></tr></thead><tbody><tr><td>params</td><td><code>IncreaseLiquidityParams</code></td><td>See table below.</td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send.</td></tr></tbody></table>

<table><thead><tr><th width="239.5">IncreaseLiquidityParams</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID number of liquidity position</td></tr><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr><tr><td>vTokensAmount</td><td><code>uint256</code></td><td>Amount of vToken to add as liquidity.</td></tr><tr><td>nftIds</td><td><code>uint256[]</code></td><td>NFT IDs to have converted to vToken, then used for liquidity.</td></tr><tr><td>nftAmounts</td><td><code>uint256[]</code></td><td>Amount of NFTs (for ERC1155).</td></tr><tr><td>vTokenMin</td><td><code>uint256</code></td><td>Minimum required vToken amount added.</td></tr><tr><td>wethMin</td><td><code>uint256</code></td><td>Minimum required WETH amount added.</td></tr><tr><td>deadline</td><td><code>uint256</code></td><td>Unix timestamp after which the transaction will revert. </td></tr><tr><td>forceTimelock</td><td><code>bool</code></td><td>Whether to force a timelock.</td></tr></tbody></table>

#### increaseLiquidityWithPermit2

```solidity
function increaseLiquidityWithPermit2(
    IncreaseLiquidityParams calldata params,
    bytes calldata encodedPermit2
) external payable
```

Increase the size of a liquidity position, using permit2 for vTokens instead of regular approvals.

<table><thead><tr><th width="176.5">Parameters</th><th width="121">Type</th><th>Description</th></tr></thead><tbody><tr><td>params</td><td><code>IncreaseLiquidityParams</code></td><td>See table above.</td></tr><tr><td>encodedPermit2</td><td><code>bytes</code></td><td><p>Encoded Permit2 data:</p><pre class="language-solidity"><code class="lang-solidity">address owner,
IPermitAllowanceTransfer.PermitSingle,
bytes memory signature
</code></pre></td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send. </td></tr></tbody></table>

#### removeLiquidity

```solidity
function removeLiquidity(
    RemoveLiquidityParams calldata params
) external payable
```

Removes liquidity from an AMM pool and claims any available fees.

<table><thead><tr><th width="179.5">Parameters</th><th width="244">Type</th><th>Description</th></tr></thead><tbody><tr><td>params</td><td><code>RemoveLiquidityParams</code></td><td>See table below.</td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send.</td></tr></tbody></table>

<table><thead><tr><th width="233.5">RemoveLiquidityParams</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID number of the liquidity position.</td></tr><tr><td>vaultId</td><td><code>uint256</code></td><td>Vault ID of associated vToken.</td></tr><tr><td>nftIds</td><td><code>uint256[]</code></td><td>The requested NFT IDs.</td></tr><tr><td>liquidity</td><td><code>uint128</code></td><td>The amount of liquidity to remove.</td></tr><tr><td>amount0Min</td><td><code>uint256</code></td><td>The minimum amount of token0 that must result from removing liquidity.</td></tr><tr><td>amount1Min</td><td><code>uint256</code></td><td>The minimum amount of token1 that must result from removing liquidity for the transaction to not revert.</td></tr><tr><td>deadline</td><td><code>uint256</code></td><td>Unix timestamp after which the transaction will revert.</td></tr></tbody></table>

#### sellNFTs

```solidity
function sellNFTs(
    SellNFTsParams calldata params
) external payable returns (uint256 wethReceived)
```

Takes NFTs from caller and returns ETH. First, the NFTs are converted to vToken, and then the vToken is swapped for WETH through a single pool determined by the `fee` param.&#x20;

<table><thead><tr><th width="199.5">Parameters</th><th width="190">Type</th><th>Description</th></tr></thead><tbody><tr><td>params</td><td><code>SellNFTsParams</code></td><td>See table below.</td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send.</td></tr></tbody></table>

<table><thead><tr><th width="201.5">SellNFTsParams</th><th width="130">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>Vault ID of the associated vToken.</td></tr><tr><td>nftIds</td><td><code>uint256[]</code></td><td>The IDs of the NFTs to sell.</td></tr><tr><td>nftAmounts</td><td><code>uint256</code></td><td>Amounts of NFTs.</td></tr><tr><td>deadline</td><td><code>uint256</code></td><td>Unix timestamp after which the transaction will revert.</td></tr><tr><td>fee</td><td><code>uint24</code></td><td>The fee of the AMM pool which the trade will route through.</td></tr><tr><td>amountOutMinimum</td><td><code>uint256</code></td><td>The minimum amount of ETH required in return.</td></tr><tr><td>sqrtPriceLimitX96</td><td><code>uint160</code></td><td>The price limit that the swap can push the pool to. Can be left as 0, in which case it is ignored.</td></tr></tbody></table>

<table><thead><tr><th width="204">Return values</th><th width="130.33333333333331">Type</th><th>Description</th></tr></thead><tbody><tr><td>wethReceived</td><td><code>uint256</code></td><td>The amount of WETH received.</td></tr></tbody></table>

#### buyNFTs

```solidity
function buyNFTs(BuyNFTsParams calldata params) external payable
```

Takes ETH from caller in return for NFTs. First, the ETH is swapped for vToken, and then the vToken is used to redeem the NFTs. The swap is routed through a single pool, determined by the `fee` param.&#x20;

<table><thead><tr><th width="202.5">Parameters</th><th width="170">Type</th><th>Description</th></tr></thead><tbody><tr><td>params</td><td><code>BuyNFTsParams</code></td><td>See table below.</td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send.</td></tr></tbody></table>

<table><thead><tr><th width="205.5">BuyNFTsParams</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault that holds the requested NFTs. </td></tr><tr><td>nftIds</td><td><code>uint256[]</code></td><td>The IDs of the NFTs to be purchased.</td></tr><tr><td>vTokenPremiumLimit</td><td><code>uint256</code></td><td>Max total premium fee (in vToken) to be paid. </td></tr><tr><td>deadline</td><td><code>uint256</code></td><td>Unix timestamp after which the transaction will revert.</td></tr><tr><td>fee</td><td><code>uint24</code></td><td>Fee of the AMM pool which the trade will route through.</td></tr><tr><td>sqrtPriceLimitX96</td><td><code>uint160</code></td><td>The max spot price which cannot be exceeded. Can be left as 0, in which case it is ignored.</td></tr></tbody></table>

## Owner Functions

#### rescueTokens

```solidity
function rescueTokens(IERC20 token) external
```

Sends balance of an ERC20 token to caller. Also works for ETH.&#x20;

<table><thead><tr><th width="154.5">Parameters</th><th width="110">Type</th><th>Description</th></tr></thead><tbody><tr><td>token</td><td><code>IERC20</code></td><td>Address of the token contract being requested. Set to 0 to retrieve ETH.</td></tr></tbody></table>

#### setLpTimelock

```solidity
function setLpTimelock(uint256 lpTimelock_) external
```

Sets the LP timelock duration.

<table><thead><tr><th width="154.5">Parameters</th><th width="110">Type</th><th>Description</th></tr></thead><tbody><tr><td>lpTimelock_</td><td><code>uint256</code></td><td>New LP timelock duration. In seconds.</td></tr></tbody></table>

#### setVTokenDustThreshold

```solidity
function setVTokenDustThreshold(
    uint256 vTokenDustThreshold_
) external
```

Sets the vToken dust threshold (minimum amount required to be returned to sender).&#x20;

<table><thead><tr><th width="223.5">Parameters</th><th width="110">Type</th><th>Description</th></tr></thead><tbody><tr><td>vTokenDustThreshold_</td><td><code>uint256</code></td><td>New vToken dust threshold.</td></tr></tbody></table>

#### setEarlyWithdrawPenalty

```solidity
function setEarlyWithdrawPenalty(
    uint256 earlyWithdrawPenaltyInWei_
) external
```

Sets the early withdrawal penalty. 1e16 = 1%.

<table><thead><tr><th width="264.5">Parameters</th><th width="110">Type</th><th>Description</th></tr></thead><tbody><tr><td>earlyWithdrawPenaltyInWei_</td><td><code>uint256</code></td><td>New early withdrawal penalty.</td></tr></tbody></table>

## Read Functions

#### quoteBuyNFTs

```solidity
function quoteBuyNFTs(
    address vtoken,
    uint256 nftsCount,
    uint24 fee,
    uint160 sqrtPriceLimitX96
) external returns (uint256 ethRequired)
```

Computes the cost in ETH to purchase one or more NFTs.&#x20;

<table><thead><tr><th width="185.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>vtoken</td><td><code>address</code></td><td>Address of vToken/vault which holds the NFTs.</td></tr><tr><td>nftsCount</td><td><code>uint256[]</code></td><td>Total number of NFTs.</td></tr><tr><td>fee</td><td><code>uint24</code></td><td>The fee of the AMM pool used to facilitate the swap.</td></tr><tr><td>sqrtPriceLimitX96</td><td><code>uint160</code></td><td>The max spot price that can't be exceeded. Can be left as 0, in which case it is ignored.</td></tr></tbody></table>

<table><thead><tr><th width="185.5">Return values</th><th width="134">Type</th><th>Description</th></tr></thead><tbody><tr><td>ethRequired</td><td><code>uint256</code></td><td>The quoted ETH price to make the purchase.</td></tr></tbody></table>

#### getPoolExists

```solidity
function getPoolExists(
    uint256 vaultId,
    uint24 fee
) external view returns (address pool, bool exists)
```

Checks for the existence of a pool.&#x20;

<table><thead><tr><th width="185.5">Parameters</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>The vault ID of the vToken.</td></tr><tr><td>fee</td><td><code>uint24</code></td><td>The pool's trading fee, denominated in hundredths of a bip.</td></tr></tbody></table>

<table><thead><tr><th width="185.5">Return values</th><th width="136">Type</th><th>Description</th></tr></thead><tbody><tr><td>pool</td><td><code>address</code></td><td>Address of the pool contract. Returns <code>0</code> if the pool does not exist.</td></tr><tr><td>exists</td><td><code>bool</code></td><td>True if the pool already exists.</td></tr></tbody></table>

#### getPool

```solidity
function getPool(
    address vToken_,
    uint24 fee
) external view returns (address pool)
```

Retrieves the address of the pool (if it exists) for a vToken and fee setting.&#x20;

<table><thead><tr><th width="183.5">Parameters</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>vToken_</td><td><code>address</code></td><td>Address of vToken from the pool.</td></tr><tr><td>fee</td><td><code>uint24</code></td><td>The pool's trading fee, denominated in hundredths of a bip.</td></tr></tbody></table>

<table><thead><tr><th width="184.5">Return values</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td>pool</td><td><code>address</code></td><td>Address of the pool contract. Returns <code>0</code> if the pool does not exist.</td></tr></tbody></table>

#### computePool

```solidity
function computePool(
    address vToken_,
    uint24 fee
) external view returns (address)
```

Computes the deterministically generated pool address.&#x20;

<table><thead><tr><th width="154.5">Parameters</th><th width="141">Type</th><th>Description</th></tr></thead><tbody><tr><td>vToken_</td><td><code>address</code></td><td>Address of vToken from the pool.</td></tr><tr><td>fee</td><td><code>uint24</code></td><td>The pool's trading fee, denominated in hundredths of a bip.</td></tr></tbody></table>

<table><thead><tr><th width="156.5">Return values</th><th width="140">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>address</code></td><td>The deterministically generated address of the pool, given the vToken and fee.</td></tr></tbody></table>

#### isVToken0

```solidity
function isVToken0(address vtoken) external view returns (bool)
```

Checks if a vToken is token0 when paired with WETH.

<table><thead><tr><th width="159.5">Parameters</th><th width="158">Type</th><th>Description</th></tr></thead><tbody><tr><td>vtoken</td><td><code>address</code></td><td>Address of vToken which forms the vToken/ETH pair of a pool.</td></tr></tbody></table>

<table><thead><tr><th width="160.5">Return values</th><th width="155">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>bool</code></td><td>True if vToken address is "token0" of a vToken/WETH pair.</td></tr></tbody></table>


# CreateVaultZap

CreateVaultZap.sol

This contract is a zap for creating and setting up a vault.&#x20;

## Table of Contents

<details>

<summary>Constants</summary>

[#minimum\_inventory\_liquidity](#minimum_inventory_liquidity "mention")\
[#weth](#weth "mention")\
[#vaultfactory](#vaultfactory "mention")\
[#nftxrouter](#nftxrouter "mention")\
[#ammfactory](#ammfactory "mention")\
[#inventorystaking](#inventorystaking "mention")\
[#positionmanager](#positionmanager "mention")

</details>

<details>

<summary>Public Write Functions</summary>

[#createvault](#createvault "mention")

</details>

## Constants

#### MINIMUM\_INVENTORY\_LIQUIDITY

```solidity
uint256 internal immutable MINIMUM_INVENTORY_LIQUIDITY
```

Set to NFTX inventory staking contract's `MINIMUM_LIQUIDITY`.

#### WETH

```solidity
function WETH() external view returns (address)
```

Address of WETH contract.

#### vaultFactory

```solidity
function vaultFactory() external view returns (address)
```

Address of NFTXVaultFactoryUpgradeableV3.

#### nftxRouter

```solidity
function nftxRouter() external view returns (address)
```

Address of NFTXRouter contract.

#### ammFactory

```solidity
function ammFactory() external view returns (address)
```

Address of NFTX AMM's UniswapV3FactoryUpgradeable contract.

#### inventoryStaking

```solidity
function inventoryStaking() external view returns (address)
```

Address of NFTXInventoryStakingV3Upgradeable contract.

#### positionManager

```solidity
function positionManager() external view returns (address)
```

Address of the NFTX AMM's NonfungiblePositionManager contract.

## Write Functions

#### createVault

```solidity
function createVault(
    CreateVaultParams calldata params
) external payable returns (uint256 vaultId)
```

Sells one or more ERC721 NFTs for ETH.&#x20;

<table><thead><tr><th width="218">Parameters</th><th width="212">Type</th><th>Description</th></tr></thead><tbody><tr><td>params</td><td><code>CreateVaultParams</code></td><td>See table below.</td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send. </td></tr></tbody></table>

<table><thead><tr><th width="214.5">CreateVaultParams</th><th width="191">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultInfo</td><td><code>VaultInfo</code></td><td>See table below.</td></tr><tr><td>eligibilityStorage</td><td><code>VaultEligibilityStorage</code></td><td>See table below.</td></tr><tr><td>nftIds</td><td><code>uint256[]</code></td><td>TokenIDs of NFTs to deposit.</td></tr><tr><td>nftAmounts</td><td><code>uint256[]</code></td><td>Amounts of NFTs.</td></tr><tr><td>vaultFeaturesFlag</td><td><code>uint256</code></td><td>Packed booleans in the order: <code>enableMint</code>, <code>enableRedeem</code>, <code>enableSwap.</code></td></tr><tr><td>vaultFees</td><td><code>VaultFees</code></td><td>See table below.</td></tr><tr><td>liquidityParams</td><td>LiquidityParams</td><td>See table below.</td></tr></tbody></table>

<table><thead><tr><th width="216">VaultInfo</th><th width="192">Type</th><th>Description</th></tr></thead><tbody><tr><td>assetAddress</td><td><code>address</code></td><td>NFT collection address.</td></tr><tr><td>is1155</td><td><code>bool</code></td><td>Whether the collection uses ERC1155.</td></tr><tr><td>allowAllItems</td><td><code>bool</code></td><td>Whether all token IDs from the collection are allowed in vault.</td></tr><tr><td>name</td><td><code>string</code></td><td>ERC20 vToken name.</td></tr><tr><td>symbol</td><td><code>string</code></td><td>ERC20 vToken symbol.</td></tr></tbody></table>

<table><thead><tr><th width="218">VaultEligibilityStorage</th><th width="193">Type</th><th>Description</th></tr></thead><tbody><tr><td>moduleIndex</td><td><code>uint256</code></td><td>Module index number.</td></tr><tr><td>initData</td><td><code>bytes</code></td><td>Module initialization data.</td></tr></tbody></table>

<table><thead><tr><th width="218">VaultFees</th><th width="195">Type</th><th>Description</th></tr></thead><tbody><tr><td>mintFee</td><td><code>uint256</code></td><td>Vault mint fee. 1e16 = 1%.</td></tr><tr><td>redeemFee</td><td><code>uint256</code></td><td>Vault redeem fee. 1e16 = 1%.</td></tr><tr><td>swapFee</td><td><code>uint256</code></td><td>Vault swap fee. 1e16 = 1%.</td></tr></tbody></table>

<table><thead><tr><th width="218">LiquidityParams</th><th width="134">Type</th><th>Description</th></tr></thead><tbody><tr><td>lowerNFTPriceInETH</td><td><code>uint256</code></td><td>Lower vToken price bound of liquidity.</td></tr><tr><td>upperNFTPriceInETH</td><td><code>uint256</code></td><td>Upper vToken price bound of liquidity.</td></tr><tr><td>fee</td><td><code>uint24</code></td><td>Fee tier of AMM pool.</td></tr><tr><td>currentNFTPriceInETH</td><td><code>uint256</code></td><td>Current vToken price. Only used if the AMM pool is new and must be initialized.</td></tr><tr><td>vTokenMin</td><td><code>uint256</code></td><td>Minimum required vToken amount to be added.</td></tr><tr><td>wethMin</td><td><code>uint256</code></td><td>Minimum required WETH amount to be added.</td></tr><tr><td>deadline</td><td><code>uint256</code></td><td>Deadline for transaction to succeed, expressed as a Unix timestamp in seconds.</td></tr></tbody></table>

<table><thead><tr><th width="218">Return values</th><th width="191">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID number of newly deployed vault.</td></tr></tbody></table>


# MarketplaceUniversalRouterZap

MarketplaceUniversalRouterZap.sol

This contract is a marketplace zap that uses the NFTX Universal Router.&#x20;

## Table of Contents

<details>

<summary>Constants</summary>

[#weth](#weth "mention")\
[#permit2](#permit2 "mention")\
[#nftxvaultfactory](#nftxvaultfactory "mention")\
[#inventorystaking](#inventorystaking "mention")\
[#base](#base "mention")

</details>

<details>

<summary>Variables</summary>

[#universalrouter](#universalrouter "mention")\
[#paused](#paused "mention")\
[#dustthreshold](#dustthreshold "mention")

</details>

<details>

<summary>Events</summary>

[#sell](#sell "mention")\
[#swap-721](#swap-721 "mention")\
[#swap-1155](#swap-1155 "mention")\
[#buy](#buy "mention")\
[#dustreturned](#dustreturned "mention")\
[#paused-1](#paused-1 "mention")\
[#newuniversalrouter](#newuniversalrouter "mention")\
[#newdustthreshold](#newdustthreshold "mention")

</details>

<details>

<summary>Public Write Functions</summary>

[#sell721](#sell721 "mention")\
[#swap721](#swap721 "mention")\
[#buynftswitheth](#buynftswitheth "mention")\
[#buynftswitherc20](#buynftswitherc20 "mention")\
[#buynftswitherc20withpermit2](#buynftswitherc20withpermit2 "mention")\
[#sell1155](#sell1155 "mention")\
[#swap1155](#swap1155 "mention")

</details>

<details>

<summary>Owner Write Functions</summary>

[#pause](#pause "mention")\
[#setuniversalrouter](#setuniversalrouter "mention")\
[#setdustthreshold](#setdustthreshold "mention")

</details>

## Constants

#### WETH

```solidity
function WETH() external view returns (address)
```

Address of WETH contract.

#### PERMIT2

```solidity
function PERMIT2() external view returns (address)
```

Address of PERMIT2 contract.&#x20;

#### nftxVaultFactory

```solidity
function nftxVaultFactory() external view returns (address)
```

Address of NFTXVaultFactory contract.

#### inventoryStaking

```solidity
function inventoryStaking() external view returns (address)
```

Address of NFTXInventoryStakingV3 contract.

#### BASE

```solidity
uint256 constant BASE = 10 ** 18
```

## Variables

#### universalRouter

```solidity
function universalRouter() external view returns (address)
```

Address of NFTX's UniversalRouter contract.

#### paused

```solidity
function paused() external view returns (bool)
```

Is the contract paused.

#### dustThreshold

```solidity
function dustThreshold() external view returns (uint256)
```

The maximum vToken amount that constitutes "dust."

## Events

#### Sell

```solidity
event Sell(
    uint256 vaultId,
    uint256 count,
    uint256 ethReceived,
    address to,
    uint256 netRoyaltyAmount,
    uint256 wethFees
)
```

Emitted by `sell721()` and `sell1155()`.

<table><thead><tr><th width="190.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID number of vault. </td></tr><tr><td>count</td><td><code>uint256</code></td><td>Total number of NFTs sold. </td></tr><tr><td>ethReceived</td><td><code>uint256</code></td><td>Amount of ETH received.</td></tr><tr><td>to</td><td><code>address</code></td><td>ETH proceeds receipient.</td></tr><tr><td>netRoyaltyAmount</td><td><code>uint256</code></td><td>Total royalty paid. </td></tr><tr><td>wethFees</td><td><code>uint256</code></td><td>WETH vault fees paid.</td></tr></tbody></table>

#### Swap (721)

```solidity
event Swap(
    uint256 vaultId,
    uint256[] idsIn,
    uint256[] idsOut,
    uint256 ethSpent,
    address to
)
```

Emitted by `swap721()`.

<table><thead><tr><th width="190.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr><tr><td>idsIn</td><td><code>uint256[]</code></td><td>NFT tokenIDs sent.</td></tr><tr><td>idsOut</td><td><code>uint256[]</code></td><td>NFT tokenIDs received.</td></tr><tr><td>ethSpent</td><td><code>uint256</code></td><td>Total ETH paid for swap.</td></tr><tr><td>to</td><td><code>address</code></td><td>Recipient that received NFT <code>idsOut</code>.</td></tr></tbody></table>

#### Swap (1155)

```solidity
event Swap(
    uint256 vaultId,
    uint256[] idsIn,
    uint256[] amounts,
    uint256[] idsOut,
    uint256 ethSpent,
    address to
)
```

Emitted by `swap1155()`.

<table><thead><tr><th width="190.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID number of vault.</td></tr><tr><td>idsIn</td><td><code>uint256[]</code></td><td>NFT tokenIDs sent.</td></tr><tr><td>amounts</td><td><code>uint256[]</code></td><td>Amounts of tokenIDs (sent and received).</td></tr><tr><td>idsOut</td><td><code>uint256[]</code></td><td>NFT tokenIDs received.</td></tr><tr><td>ethSpent</td><td><code>uint256</code></td><td>Amount of ETH paid for swap.</td></tr><tr><td>to</td><td><code>address</code></td><td>Recipient that received NFT <code>idsOut</code>.</td></tr></tbody></table>

#### Buy

```solidity
event Buy(
    uint256 vaultId,
    uint256[] nftIds,
    uint256 ethSpent,
    address to,
    uint256 netRoyaltyAmount
)
```

Emitted by `buyNFTsWithETH()`, `buyNFTsWithERC20()` and `buyNFTsWithERC20WithPermit2()`.

<table><thead><tr><th width="190.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault.</td></tr><tr><td>nftIds</td><td><code>uint256[]</code></td><td>NFT token IDs.</td></tr><tr><td>ethSpent</td><td><code>uint256</code></td><td>Total ETH paid for purchase.</td></tr><tr><td>to</td><td><code>address</code></td><td>Recipient of NFTs.</td></tr><tr><td>netRoyaltyAmount</td><td><code>uint256</code></td><td>Total royalty paid, in ETH.</td></tr></tbody></table>

#### DustReturned

```solidity
event DustReturned(uint256 ethAmount, uint256 vTokenAmount, address to)
```

Emitted by `buyNFTsWithETH()`, `buyNFTsWithERC20()` and `buyNFTsWithERC20WithPermit2()`.

<table><thead><tr><th width="190.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>ethAmount</td><td><code>uint256</code></td><td>Amount of ETH dust returned.</td></tr><tr><td>vTokenAmount</td><td><code>uint256</code></td><td>Amount of vToken dust returned.</td></tr><tr><td>to</td><td><code>address</code></td><td>Recipient of dust.</td></tr></tbody></table>

#### Paused

```solidity
event Paused(bool status)
```

Emitted by `pause()`.

<table><thead><tr><th width="190.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>status</td><td><code>bool</code></td><td>True if paused, false if un-paused.</td></tr></tbody></table>

#### NewUniversalRouter

```solidity
event NewUniversalRouter(address universalRouter)
```

Emitted by `setUniversalRouter()`.

<table><thead><tr><th width="190.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>universalRouter</td><td><code>address</code></td><td>New NFTX UniversalRouter address.</td></tr></tbody></table>

#### NewDustThreshold

```solidity
event NewDustThreshold(uint256 dustThreshold)
```

Emitted by `setDustThreshold()`.

<table><thead><tr><th width="190.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>dustThreshold</td><td><code>uint256</code></td><td>New dust threshold amount.</td></tr></tbody></table>

## Write Functions

#### sell721

```solidity
function sell721(
    uint256 vaultId,
    uint256[] calldata idsIn,
    bytes calldata executeCallData,
    address payable to,
    bool deductRoyalty
) external
```

Sells one or more ERC721 NFTs for ETH.&#x20;

<table><thead><tr><th width="180.5">Parameters</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault that NFTs are being sold into. </td></tr><tr><td>idsIn</td><td><code>uint256[]</code></td><td>IDs of NFTs being sold. </td></tr><tr><td>executeCallData</td><td><code>address</code></td><td>Encoded swap data. </td></tr><tr><td>to</td><td><code>address</code></td><td>Recipient of ETH proceeds. </td></tr><tr><td>deductRoyalty</td><td><code>bool</code></td><td>Whether a royalty is deducted. </td></tr></tbody></table>

#### swap721

```solidity
function swap721(
    uint256 vaultId,
    uint256[] calldata idsIn,
    uint256[] calldata idsOut,
    uint256 vTokenPremiumLimit,
    address payable to
) external payable
```

Swaps one or more ERC721 NFTs for one or more other ERC721 NFTs.&#x20;

<table><thead><tr><th width="206.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault that NFTs are being swapped out of.</td></tr><tr><td>idsIn</td><td><code>uint256[]</code></td><td>IDs of NFTs being sent to vault.</td></tr><tr><td>idsOut</td><td><code>uint256[]</code></td><td>IDs of NFTs exiting vault. </td></tr><tr><td>vTokenPremiumLimit</td><td><code>uint256</code></td><td>Max premium fee to be paid (in vToken).</td></tr><tr><td>to</td><td><code>address</code></td><td>Address that NFTs from vault are sent to. </td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send.</td></tr></tbody></table>

#### buyNFTsWithETH

```solidity
function buyNFTsWithETH(
    uint256 vaultId,
    uint256[] calldata idsOut,
    bytes calldata executeCallData,
    address payable to,
    uint256 vTokenPremiumLimit,
    bool deductRoyalty
) external payable
```

Buys one or more NFTs with ETH.

<table><thead><tr><th width="205.5">Parameters</th><th width="128">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault holding desired NFTs.</td></tr><tr><td>idsOut</td><td><code>uint256[]</code></td><td>IDs of desired NFTs.</td></tr><tr><td>executeCallData</td><td><code>bytes</code></td><td>Encoded swap data.</td></tr><tr><td>to</td><td>address</td><td>Address that NFTs are sent to. </td></tr><tr><td>vTokenPremiumLimit</td><td><code>uint256</code></td><td>Max premium fee to be paid (measured in vToken despite payment being in ETH).</td></tr><tr><td>deductRoyalty</td><td>bool</td><td>Whether a royalty is deducted.</td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send.</td></tr></tbody></table>

#### buyNFTsWithERC20

```solidity
function buyNFTsWithERC20(
    BuyNFTsWithERC20Params calldata params
) external
```

Purchases NFTs via NFTX's UniversalRouter and pay with any ERC20 supported by the NFTX AMM.&#x20;

<table><thead><tr><th width="206.5">Parameters</th><th width="257">Type</th><th>Description</th></tr></thead><tbody><tr><td>params</td><td><code>BuyNFTsWithERC20Params</code></td><td><em>See table below.</em></td></tr></tbody></table>

<table><thead><tr><th width="262.5">BuyNFTsWithERC20Params</th><th width="109">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenIn</td><td><code>IERC20</code></td><td>Address of input token.</td></tr><tr><td>amountIn</td><td><code>uint256</code></td><td>Amount of input token.</td></tr><tr><td>vaultId</td><td><code>uint256</code></td><td>Vault ID of vToken holding desired NFTs.</td></tr><tr><td>idsOut</td><td><code>uint256</code></td><td>NFT token IDs to buy. </td></tr><tr><td>vTokenPremiumLimit</td><td><code>uint256</code></td><td>Max premium fee to be paid (measured in vToken).</td></tr><tr><td>executeToWETHCallData</td><td><code>bytes</code></td><td>Encoded call data for "ERC20 to WETH swap" for NFTX UniversalRouter's <code>execute</code> function.</td></tr><tr><td>executeToVTokenCallData</td><td><code>bytes</code></td><td>Encoded call data for "WETH to vToken swap" for NFTX Universal Router's <code>execute</code> function.</td></tr><tr><td>to</td><td><code>address</code></td><td>Recipient of purchased NFT IDs.</td></tr><tr><td>deductRoyalty</td><td>bool</td><td>Whether a royalty is deducted.</td></tr></tbody></table>

#### buyNFTsWithERC20WithPermit2

```solidity
function buyNFTsWithERC20WithPermit2(
    BuyNFTsWithERC20Params calldata params,
    bytes calldata encodedPermit2
) external
```

Buys one or more NFTs with ERC20, using Permit2 for token approval.

<table><thead><tr><th width="173.5">Parameters</th><th width="192">Type</th><th>Description</th></tr></thead><tbody><tr><td>params</td><td><code>BuyNFTsWithERC20Params</code></td><td><em>See table above.</em></td></tr><tr><td>encodedPermit2</td><td><code>bytes</code></td><td><p>Encoded Permit2 data:</p><pre class="language-solidity"><code class="lang-solidity">address owner,
IPermitAllowanceTransfer.PermitSingle,
bytes memory signature
</code></pre></td></tr></tbody></table>

#### sell1155

```solidity
function sell1155(
    uint256 vaultId,
    uint256[] calldata idsIn,
    uint256[] calldata amounts,
    bytes calldata executeCallData,
    address payable to,
    bool deductRoyalty
) external
```

Sells one or more ERC1155 NFTs.

<table><thead><tr><th width="174.5">Parameters</th><th width="150">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault to sell into. </td></tr><tr><td>idsIn</td><td><code>uint256[]</code></td><td>IDs of NFTs to sell.</td></tr><tr><td>amounts</td><td><code>uint256[]</code></td><td>Quantities of each NFT token ID to send.</td></tr><tr><td>executeCallData</td><td><code>bytes</code></td><td>Encoded swap data.</td></tr><tr><td>to</td><td><code>address</code></td><td>Address to receive ETH from sale.</td></tr><tr><td>deductRoyalty</td><td><code>bool</code></td><td>Whether a royalty is deducted.</td></tr></tbody></table>

#### swap1155

```solidity
function swap1155(
    uint256 vaultId,
    uint256[] calldata idsIn,
    uint256[] calldata amounts,
    uint256[] calldata idsOut,
    uint256 vTokenPremiumLimit,
    address payable to
) external payable
```

Swaps one or more ERC1155 NFTs for one or more other ERC1155 NFTs.&#x20;

<table><thead><tr><th width="205.5">Parameters</th><th width="134">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultId</td><td><code>uint256</code></td><td>ID of vault being swapped into.</td></tr><tr><td>idsIn</td><td><code>uint256[]</code></td><td>IDs of NFTs being sent to vault.</td></tr><tr><td>amounts</td><td><code>uint256[]</code></td><td>Quantities of each NFT being sent.</td></tr><tr><td>idsOut</td><td><code>uint256[]</code></td><td>IDs of NFTs exiting the vault.</td></tr><tr><td>vTokenPremiumLimit</td><td><code>uint256</code></td><td>Max premium fee to be paid (in vToken).</td></tr><tr><td>to</td><td><code>address</code></td><td>Address that receives NFTs leaving the vault.</td></tr><tr><td><code>msg.value</code></td><td><code>uint256</code></td><td>Amount of ETH to send.</td></tr></tbody></table>

## Owner Functions

#### pause

```solidity
function pause(bool paused_) external
```

Pauses this contract.&#x20;

<table><thead><tr><th width="201.5">Parameters</th><th width="130">Type</th><th>Description</th></tr></thead><tbody><tr><td>paused_</td><td><code>bool</code></td><td>True to pause, false to un-pause.</td></tr></tbody></table>

#### setUniversalRouter

```solidity
function setUniversalRouter(address universalRouter_) external
```

Sets address of NFTX Universal Router.

<table><thead><tr><th width="206.5">Parameters</th><th width="122">Type</th><th>Description</th></tr></thead><tbody><tr><td>universalRouter_</td><td><code>address</code></td><td>New NFTX universal router address.</td></tr></tbody></table>

#### setDustThreshold

```solidity
function setDustThreshold(uint256 dustThreshold_) external
```

Sets (max) threshold for what is considered token dust.&#x20;

<table><thead><tr><th width="210.5">Name</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td>dustThreshold_</td><td><code>uint256</code></td><td>Max threshold for dust.</td></tr></tbody></table>


# MigratorZap

MigratorZap.sol

Migrates positions from NFTX V2 to V3.

## Table of Contents

<details>

<summary>Constants</summary>

[#deadline](#deadline "mention")\
[#dust\_threshold](#dust_threshold "mention")\
[#weth](#weth "mention")\
[#v2nftxfactory](#v2nftxfactory "mention")\
[#v2inventory](#v2inventory "mention")\
[#sushirouter](#sushirouter "mention")\
[#positionmanager](#positionmanager "mention")\
[#v3nftxfactory](#v3nftxfactory "mention")\
[#v3inventory](#v3inventory "mention")

</details>

<details>

<summary>Public Write Functions</summary>

[#sushitonftxamm](#sushitonftxamm "mention")\
[#v2inventorytoxnft](#v2inventorytoxnft "mention")\
[#v2vaulttoxnft](#v2vaulttoxnft "mention")

</details>

## Constants

#### DEADLINE

```solidity
uint256 private constant DEADLINE =
    0xf000000000000000000000000000000000000000000000000000000000000000
```

A sufficiently large value used for Uniswap V2's deadline.

#### DUST\_THRESHOLD

```solidity
uint256 private constant DUST_THRESHOLD = 0.005 ether
```

Threshold for what amount of V2 vTokens (left after redeeming) constitutes "dust." Used to determine whether to swap dust to WETH or not.

#### WETH

```solidity
function WETH() external view returns (address)
```

Address of WETH contract.

#### v2NFTXFactory

```solidity
function v2NFTXFactory() external view returns (address)
```

NFTX V2 vault factory address.

#### v2Inventory

```solidity
function v2Inventory() external view returns (address)
```

NFTX V2 inventory staking address.

#### sushiRouter

```solidity
function sushiRouter() external view returns (address)
```

Sushi router address.

#### positionManager

```solidity
function positionManager() external view returns (address)
```

Address of NFTX V3's NonfungiblePositionManager contract.

#### v3NFTXFactory

```solidity
function v3NFTXFactory() external view returns (address)
```

Address of NFTXVaultFactoryUpgradeableV3 contract.

#### v3Inventory

```solidity
function v3Inventory() external view returns (address)
```

Address of NFTXInventoryStakingV3Upgradeable contract.

## Write Functions

#### sushiToNFTXAMM

```solidity
function sushiToNFTXAMM(
    SushiToNFTXAMMParams calldata params
) external returns (uint256 positionId)
```

Migrates Sushi vToken liquidity to NFTX v3 AMM.

<table><thead><tr><th width="249.5">SushiToNFTXAMMParams</th><th width="131">Type</th><th>Description</th></tr></thead><tbody><tr><td>sushiPair</td><td><code>address</code></td><td>SLP token address.</td></tr><tr><td>lpAmount</td><td><code>uint256</code></td><td>SLP amount.</td></tr><tr><td>vTokenV2</td><td><code>address</code></td><td>vToken amount.</td></tr><tr><td>idsToRedeem</td><td><code>uint256[]</code></td><td>NFT tokenIDs to redeem.</td></tr><tr><td>is1155</td><td><code>bool</code></td><td>Whether NFTs use ERC1155.</td></tr><tr><td>permitSig</td><td><code>bytes</code></td><td>Signed UniV2 Permit.</td></tr><tr><td>vaultIdV3</td><td><code>uint256</code></td><td>NFTX v3 vault ID.</td></tr><tr><td>tickLower</td><td><code>int24</code></td><td>Lower tick for v3 liquidity.</td></tr><tr><td>tickUpper</td><td><code>int24</code></td><td>Upper tick for v3 liquidity.</td></tr><tr><td>fee</td><td><code>uint24</code></td><td>Fee tier of V3 AMM pool to be used.</td></tr><tr><td>sqrtPriceX96</td><td><code>uint160</code></td><td>Starting price, if pool is not initialized.</td></tr><tr><td>amount0Min</td><td><code>uint256</code></td><td>Minimum token0 amount to succeed.</td></tr><tr><td>amount1Min</td><td><code>uint256</code></td><td>Minimum token1 amount to succeed.</td></tr><tr><td>deadline</td><td><code>uint256</code></td><td>Dealine for transaction to succeed. Unix timestamp, in seconds.</td></tr></tbody></table>

<table><thead><tr><th width="249.33333333333331">Return values</th><th width="132">Type</th><th>Description</th></tr></thead><tbody><tr><td>positionId</td><td><code>uint256</code></td><td>ID number of newly created position.</td></tr></tbody></table>

#### v2InventoryToXNFT

```solidity
function v2InventoryToXNFT(
    uint256 vaultIdV2,
    uint256 shares,
    uint256[] calldata idsToRedeem,
    bool is1155,
    uint256 vaultIdV3,
    uint256 minWethToReceive
) external returns (uint256 xNFTId)
```

Migrates V2 inventory position to V3 xNFT inventory staking position.

<table><thead><tr><th width="192.5">Parameters</th><th width="138">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultIdV2</td><td><code>uint256</code></td><td>V2 vault ID.</td></tr><tr><td>shares</td><td><code>uint256</code></td><td>V2 xToken shares.</td></tr><tr><td>idsToRedeem</td><td><code>uint256[]</code></td><td>NFT tokenIDs to redeem.</td></tr><tr><td>is1155</td><td><code>bool</code></td><td>Whether NFT collection uses ERC1155.</td></tr><tr><td>vaultIdV3</td><td><code>uint256</code></td><td>V3 vault ID.</td></tr><tr><td>minWethToReceive</td><td><code>uint256</code></td><td>Minimum WETH to be received.</td></tr></tbody></table>

<table><thead><tr><th width="192.5">Return values</th><th width="141">Type</th><th>Description</th></tr></thead><tbody><tr><td>xNFTId</td><td><code>uint256</code></td><td>ID of newly created xNFT. </td></tr></tbody></table>

#### v2VaultToXNFT

```solidity
function v2VaultToXNFT(
    address vTokenV2,
    uint256 vTokenV2Balance,
    uint256[] calldata idsToRedeem,
    bool is1155,
    uint256 vaultIdV3,
    uint256 minWethToReceive
) external returns (uint256 xNFTId)
```

Migrates V2 vault token to V3 xNFT inventory staking position.

<table><thead><tr><th width="192.5">Parameters</th><th width="137">Type</th><th>Description</th></tr></thead><tbody><tr><td>vaultIdV2</td><td><code>uint256</code></td><td>V2 vault ID.</td></tr><tr><td>vTokenV2</td><td><code>address</code></td><td>V2 vault address.</td></tr><tr><td>shares</td><td><code>uint256</code></td><td>The amount of v2 vToken shares to withdraw.</td></tr><tr><td>idsToRedeem</td><td><code>uint256[]</code></td><td>TokenIDs of NFTs to redeem.</td></tr><tr><td>is1155</td><td><code>bool</code></td><td>Whether the NFT collection uses ERC1155.</td></tr><tr><td>vaultIdV3</td><td><code>uint256</code></td><td>V3 vault ID.</td></tr><tr><td>minWethToReceive</td><td><code>uint256</code></td><td>Minimum required WETH to receive.</td></tr></tbody></table>

<table><thead><tr><th width="192.5">Return values</th><th width="140">Type</th><th>Description</th></tr></thead><tbody><tr><td>xNFTId</td><td><code>uint256</code></td><td>ID of newly created xNFT inventory position.</td></tr></tbody></table>


# UniswapV3Staker

UniswapV3Staker.sol

A forked version of the UniswapV3Staker contract for use with the NFTX AMM.

## Table of Contents

<details>

<summary>Constants</summary>

[#factory](#factory "mention")\
[#nonfungiblepositionmanager](#nonfungiblepositionmanager "mention")\
[#maxincentiveduration](#maxincentiveduration "mention")\
[#maxincentivestartleadtime](#maxincentivestartleadtime "mention")

</details>

<details>

<summary>Variables</summary>

[#incentives](#incentives "mention")\
[#deposits](#deposits "mention")\
[#rewards](#rewards "mention")

</details>

<details>

<summary>Events</summary>

[#incentivecreated](#incentivecreated "mention")\
[#incentiveended](#incentiveended "mention")\
[#deposittransferred](#deposittransferred "mention")\
[#tokenstaked](#tokenstaked "mention")\
[#tokenunstaked](#tokenunstaked "mention")\
[#rewardclaimed](#rewardclaimed "mention")

</details>

<details>

<summary>Public Write Functions</summary>

[#createincentive](#createincentive "mention")\
[#endincentive](#endincentive "mention")\
[#onerc721received](#onerc721received "mention")\
[#transferdeposit](#transferdeposit "mention")\
[#withdrawtoken](#withdrawtoken "mention")\
[#staketoken](#staketoken "mention")\
[#unstaketoken](#unstaketoken "mention")\
[#claimreward](#claimreward "mention")

</details>

<details>

<summary>Read Functions</summary>

[#stakes](#stakes "mention")\
[#getrewardinfo](#getrewardinfo "mention")

</details>

## Constants

#### factory

```solidity
function factory() external view returns (IUniswapV3Factory)
```

The address of the NFTX AMM's pool factory.

#### nonfungiblePositionManager

```solidity
function nonfungiblePositionManager() 
    external 
    view 
    returns (INonfungiblePositionManager)
```

The address of the NFTX AMM's NonfungiblePositionManager.

#### maxIncentiveDuration

```solidity
function maxIncentiveDuration() external view returns (uint256)
```

The maximum duration of an incentive, in seconds.

#### maxIncentiveStartLeadTime

```solidity
function maxIncentiveStartLeadTime() external view returns (uint256)
```

The maximum amount of seconds into the future the incentive startTime can be set.

### Variables

#### incentives

```solidity
function incentives(bytes32 incentiveId)
    external
    view
    returns (
        uint256 totalRewardUnclaimed,
        uint160 totalSecondsClaimedX128,
        uint96 numberOfStakes
    )
```

Represents a staking incentive.&#x20;

<table><thead><tr><th width="240.33333333333331">Parameters</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td>incentiveId</td><td><code>bytes32</code></td><td>The ID of the incentive computed from its parameters.</td></tr></tbody></table>

<table><thead><tr><th width="241.33333333333331">Return values</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td>totalRewardUnclaimed</td><td><code>bytes32</code></td><td>The amount of reward token not yet claimed by users</td></tr><tr><td>totalSecondsClaimedX128</td><td><code>uint160</code></td><td>Total liquidity-seconds claimed, represented as a <code>UQ32.128</code></td></tr><tr><td>numberOfStakes</td><td><code>uint96</code></td><td>The count of deposits that are currently staked for the incentive.</td></tr></tbody></table>

#### deposits

```solidity
function deposits(uint256 tokenId)
    external
    view
    returns (
        address owner,
        uint48 numberOfStakes,
        int24 tickLower,
        int24 tickUpper
    )
```

Returns information about a deposited liquidity NFT.

<table><thead><tr><th width="212.33333333333331">Parameters</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>The token ID of the liquidity NFT.</td></tr></tbody></table>

<table><thead><tr><th width="212.33333333333331">Return values</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td>owner</td><td><code>address</code></td><td>The owner of the deposited liquidity NFT.</td></tr><tr><td>numberOfStakes</td><td><code>uint48</code></td><td>Counter of how many incentives for which the liquidity is staked.</td></tr><tr><td>tickLower</td><td><code>int24</code></td><td>The lower tick of the range.</td></tr><tr><td>tickUpper</td><td><code>int24</code></td><td>The upper tick of the range.</td></tr></tbody></table>

#### rewards

```solidity
function rewards(IERC20Minimal rewardToken, address owner) 
    external 
    view 
    returns (uint256 rewardsOwed)
```

Returns amounts of reward tokens owed to a given address according to the last time all stakes were updated.

<table><thead><tr><th width="212.33333333333331">Parameters</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td>rewardToken</td><td><code>IERC20Minimal</code></td><td>The address of the token for which to check rewards.</td></tr><tr><td>owner</td><td><code>address</code></td><td>The owner for which the rewards owed are checked.</td></tr></tbody></table>

<table><thead><tr><th width="212.33333333333331">Return values</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>The amount of the reward token claimable by the owner.</td></tr></tbody></table>

## Events

#### IncentiveCreated

```solidity
event IncentiveCreated(
    IERC20Minimal indexed rewardToken,
    IUniswapV3Pool indexed pool,
    uint256 startTime,
    uint256 endTime,
    address refundee,
    uint256 reward
)
```

Event emitted when a liquidity mining incentive has been created.

<table><thead><tr><th width="224.33333333333331">Parameters</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td>rewardToken</td><td><code>IERC20Minimal</code></td><td>The token being distributed as a reward.</td></tr><tr><td>pool</td><td><code>IUniswapV3Pool</code></td><td>The NFTX AMM pool.</td></tr><tr><td>startTime</td><td><code>uint256</code></td><td>The time when the incentive program begins.</td></tr><tr><td>endTime</td><td><code>uint256</code></td><td>The time when rewards stop accruing.</td></tr><tr><td>refundee</td><td><code>uint256</code></td><td>The address that receives any remaining reward tokens after the end time.</td></tr><tr><td>reward</td><td><code>uint256</code></td><td>The amount of reward tokens to be distributed.</td></tr></tbody></table>

#### IncentiveEnded

```solidity
event IncentiveEnded(bytes32 indexed incentiveId, uint256 refund)
```

Event that can be emitted when a liquidity mining incentive has ended.

<table><thead><tr><th width="224.33333333333331">Parameters</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td>incentiveId</td><td><code>bytes32</code></td><td>ID of the incentive that is ending.</td></tr><tr><td>refund</td><td><code>uint256</code></td><td>The amount of reward tokens refunded.</td></tr></tbody></table>

#### DepositTransferred

```solidity
event DepositTransferred(
    uint256 indexed tokenId, 
    address indexed oldOwner, 
    address indexed newOwner
)
```

Emitted when ownership of a deposit changes

<table><thead><tr><th width="224.33333333333331">Parameters</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>The token ID of the deposited liquidity NFT that is being transferred.</td></tr><tr><td>oldOwner</td><td><code>address</code></td><td>The owner before the deposit was transferred.</td></tr><tr><td>newOwner</td><td><code>address</code></td><td>The owner after the deposit was transferred.</td></tr></tbody></table>

#### TokenStaked

```solidity
event TokenStaked(
    uint256 indexed tokenId, 
    bytes32 indexed incentiveId, 
    uint128 liquidity
)
```

Event emitted when an NFTX AMM LP token has been staked.

<table><thead><tr><th width="224.33333333333331">Parameters</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>The token ID of the staked liquidity NFT.</td></tr><tr><td>incentiveId</td><td><code>bytes32</code></td><td>ID of the incentive being staked on. </td></tr><tr><td>liquidity</td><td><code>uint128</code></td><td>The amount of liquidity staked.</td></tr></tbody></table>

#### TokenUnstaked

```solidity
event TokenUnstaked(uint256 indexed tokenId, bytes32 indexed incentiveId)
```

Event emitted when an NFTX AMM liquidity NFT has been unstaked.

<table><thead><tr><th width="224.33333333333331">Parameters</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>The token ID of the unstaked liquidity NFT.</td></tr><tr><td>incentiveId</td><td><code>bytes32</code></td><td>ID of the incentive being unstaked from.</td></tr></tbody></table>

#### RewardClaimed

```solidity
event RewardClaimed(address indexed to, uint256 reward)
```

Event emitted when a reward token has been claimed.

<table><thead><tr><th width="224.33333333333331">Parameters</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td>to</td><td><code>address</code></td><td>The address that claimed rewards were sent to.</td></tr><tr><td>reward</td><td><code>uint256</code></td><td>The amount of reward token claimed.</td></tr></tbody></table>

## Write Functions

#### constructor

```solidity
function constructor(
    contract IUniswapV3Factory _factory,
    contract INonfungiblePositionManager _nonfungiblePositionManager,
    uint256 _maxIncentiveStartLeadTime,
    uint256 _maxIncentiveDuration
) public
```

<table><thead><tr><th width="276.3333333333333">Parameters</th><th width="203">Type</th><th>Description</th></tr></thead><tbody><tr><td>_factory</td><td><code>contract IUniswapV3Factory</code></td><td>The Uniswap V3 factory.</td></tr><tr><td>_nonfungiblePositionManager</td><td><code>contract INonfungiblePositionManager</code></td><td>The NFT position manager contract address.</td></tr><tr><td>_maxIncentiveStartLeadTime</td><td><code>uint256</code></td><td>The max duration of an incentive in seconds.</td></tr><tr><td>_maxIncentiveDuration</td><td><code>uint256</code></td><td>The max amount of seconds into the future the incentive startTime can be set.</td></tr></tbody></table>

#### createIncentive

```solidity
function createIncentive(IncentiveKey memory key, uint256 reward) external 
```

Creates a new liquidity mining incentive program.

<table><thead><tr><th width="192.33333333333331">Parameters</th><th width="157">Type</th><th>Description</th></tr></thead><tbody><tr><td>key</td><td><code>IncentiveKey</code></td><td>Details of the incentive to create.</td></tr><tr><td>reward</td><td><code>uint256</code></td><td>The amount of reward tokens to be distributed.</td></tr></tbody></table>

#### endIncentive

```solidity
function endIncentive(IncentiveKey memory key) 
    external 
    returns (uint256 refund)
```

Ends an incentive after the incentive end time has passed and all stakes have been withdrawn.

<table><thead><tr><th width="192.5">Parameters</th><th width="157">Type</th><th>Description</th></tr></thead><tbody><tr><td>key</td><td><code>IncentiveKey</code></td><td>Details of the incentive to end.</td></tr></tbody></table>

<table><thead><tr><th width="192.5">Return values</th><th width="160">Type</th><th>Description</th></tr></thead><tbody><tr><td>refund</td><td><code>uint256</code></td><td>The remaining reward tokens when the incentive is ended.</td></tr></tbody></table>

#### onERC721Received

```solidity
function onERC721Received(
    address,
    address from,
    uint256 tokenId,
    bytes calldata data
) external returns (bytes4)
```

Upon receiving a NFTX  V3 LP ERC721, creates the token deposit setting owner to `from`. Also stakes token in one or more incentives if properly formatted `data` has a length > 0.

Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} by `operator` from `from`, this function is called. It must return its Solidity selector to confirm the token transfer. If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.

<table><thead><tr><th width="192.5">Parameters</th><th width="137">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>address</code></td><td>The address which called the transfer function.</td></tr><tr><td>from</td><td><code>address</code></td><td>The address which previously owned the token.</td></tr><tr><td>tokenId</td><td><code>uint256</code></td><td>ID of the NFT.</td></tr><tr><td>data</td><td><code>bytes</code></td><td>Additional data with no specified format.</td></tr></tbody></table>

<table><thead><tr><th width="192.5">Return values</th><th width="140">Type</th><th>Description</th></tr></thead><tbody><tr><td><em>unnamed</em></td><td><code>bytes4</code></td><td>A keccak256 hash of the function call and arguments.</td></tr></tbody></table>

#### transferDeposit

```solidity
function transferDeposit(uint256 tokenId, address to) external
```

Transfers ownership of a deposit from the sender to the given recipient.

<table><thead><tr><th width="192.5">Parameters</th><th width="157">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>The ID of the token (and the deposit) to transfer.</td></tr><tr><td>to</td><td><code>address</code></td><td>The new owner of the deposit.</td></tr></tbody></table>

#### withdrawToken

```solidity
function withdrawToken(uint256 tokenId, address to, bytes memory data) external
```

Withdraws an NFTX V3 LP token `tokenId` from this contract to the recipient `to`.

<table><thead><tr><th width="192.5">Parameters</th><th width="157">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>The unique identifier of an Uniswap V3 LP token.</td></tr><tr><td>to</td><td><code>address</code></td><td>The address where the LP token will be sent.</td></tr><tr><td>data</td><td><code>bytes</code></td><td>An optional data array that will be passed along to the <code>to</code> address via the NFT safeTransferFrom.</td></tr></tbody></table>

#### stakeToken

```solidity
function stakeToken(IncentiveKey memory key, uint256 tokenId) external override
```

Stakes an NFTX V3 LP token.

<table><thead><tr><th width="192.5">Parameters</th><th width="157">Type</th><th>Description</th></tr></thead><tbody><tr><td>key</td><td><code>IncentiveKey</code></td><td>The key of the incentive for which to stake the NFT.</td></tr><tr><td>tokenId</td><td><code>uint256</code></td><td>The ID of the token to stake.</td></tr></tbody></table>

#### unstakeToken

```solidity
function unstakeToken(IncentiveKey memory key, uint256 tokenId) external override
```

Unstakes an NFTX V3 LP token.

<table><thead><tr><th width="192.5">Parameters</th><th width="157">Type</th><th>Description</th></tr></thead><tbody><tr><td>key</td><td><code>IncentiveKey</code></td><td>The key of the incentive for which to unstake the NFT.</td></tr><tr><td>tokenId</td><td><code>uint256</code></td><td>The ID of the token to unstake.</td></tr></tbody></table>

#### claimReward

```solidity
function claimReward(
    IERC20Minimal rewardToken,
    address to,
    uint256 amountRequested
) external returns (uint256 reward)
```

Transfers `amountRequested` of accrued `rewardToken` rewards from the contract to the recipient `to`.

<table><thead><tr><th width="192.5">Parameters</th><th width="166">Type</th><th>Description</th></tr></thead><tbody><tr><td>rewardToken</td><td><code>IERC20Minimal</code></td><td>The token being distributed as a reward.</td></tr><tr><td>to</td><td><code>address</code></td><td>The address where claimed rewards will be sent.</td></tr><tr><td>amountRequested</td><td><code>uint256</code></td><td>The amount of reward token to claim. If set to 0, then the entire reward amount is claimed.</td></tr></tbody></table>

<table><thead><tr><th width="192.5">Return values</th><th width="160">Type</th><th>Description</th></tr></thead><tbody><tr><td>reward</td><td><code>uint256</code></td><td>The amount of reward token claimed.</td></tr></tbody></table>

## Read Functions

#### stakes

```solidity
function stakes(uint256 tokenId, bytes32 incentiveId)
    public
    view
    override
    returns (uint160 secondsPerLiquidityInsideInitialX128, uint128 liquidity)
```

Returns information about a staked liquidity NFT.

<table><thead><tr><th width="192.5">Parameters</th><th width="166">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td><code>uint256</code></td><td>The ID of the staked token.</td></tr><tr><td>incentiveId</td><td><code>bytes32</code></td><td>The ID of the incentive for which the token is staked.</td></tr></tbody></table>

<table><thead><tr><th width="198.5">Return values</th><th width="166">Type</th><th>Description</th></tr></thead><tbody><tr><td>secondsPerLiquidityInsideInitialX128</td><td><code>uint160</code></td><td>secondsPerLiquidity represented as a UQ32.128.</td></tr><tr><td>liquidity</td><td><code>bytes32</code></td><td>The amount of liquidity in the NFT as of the last time the rewards were computed.</td></tr></tbody></table>

#### getRewardInfo

```solidity
function getRewardInfo(IncentiveKey memory key, uint256 tokenId)
    external
    view
    override
    returns (uint256 reward, uint160 secondsInsideX128)
```

Calculates the reward amount that will be received for the given stake.

<table><thead><tr><th width="192.5">Parameters</th><th width="166">Type</th><th>Description</th></tr></thead><tbody><tr><td>key</td><td><code>IncentiveKey</code></td><td>The ID of the incentive.</td></tr><tr><td>tokenId</td><td><code>uint256</code></td><td>The token ID of the staked liquidity NFT.</td></tr></tbody></table>

<table><thead><tr><th width="194.5">Return values</th><th width="166">Type</th><th>Description</th></tr></thead><tbody><tr><td>reward</td><td><code>uint256</code></td><td>The reward accrued to the NFT for the given incentive thus far.</td></tr><tr><td>secondsInsideX128</td><td><code>uint160</code></td><td>The seconds inside the tick range.</td></tr></tbody></table>


# Introduction

The NFTX V3 protocol can be integrated into any marketplace.


# Marketplace Integration

These are the pseudo steps to integrate NFTX NFTs and liquidity into your application

1. Retrieve all NFTX vaults from the subgraph, including global fees, and holdings
2. Use the `asset > id` in the subgraph response to link the NFTX vault with the appropriate NFT collection in your application
3. Verify that the vault has `features > enableRedeems` set to `true` so specific NFTs can be bought from the vault.
4. Check if the vault uses default fees using `usesFactoryFees` , if `true` use the global fees to calculate the tokens required to buy an NFT, if `false` use the `fees > redeemFee` associated with the vault. To buy an NFT you need 1 token + `vTokenToEth` value of the fee.
5. Using the `NFTX Universal Router API`, check the ETH cost to buy the required tokens. As the number of tokens required increases (i.e. the user adds more items to their basket) the average price of the NFT will increase due to price impact on the token buy.
6. When the user buys, call the `MarketplaceUniversalRouterZap` to complete the purchase.

## Contract Addresses

### Sepolia Contract Addresses

```json
"sepolia": {
    "CreateVaultZap": "0x50f69c6556338965bf77C16ADb462Fdb5bE01C09",
    "MarketplaceUniversalRouterZap": "0x5Af324A8c90966Bef28386A67c6bE0A16aA03c19",
    "NFTXFeeDistributorV3": "0x66EF5B4b6ee05639194844CE4867515665F14fED",
    "NFTXInventoryStakingV3Upgradeable": "0xfBFf0635f7c5327FD138E1EBa72BD9877A6a7C1C",
    "NFTXRouter": "0xD36ece08F76c50EC3F01db65BBc5Ef5Aa5fbE849",
    "nftxUniversalRouter": "0x12156cCA1958B6591CC49EaE03a5553458a4b424",
    "NFTXVaultFactoryUpgradeableV3": "0x31C56CaF49125043e80B4d3C7f8734f949d8178C",
    "NonfungiblePositionManager": "0x55BDc76262B1e6e791D0636A0bC61cee23CDFa87",
    "permit2": "0x000000000022d473030f116ddee9f6b43ac78ba3",
    "QuoterV2": "0xb8EB27ca4715f7A04228c6F83935379D1f5AbABd",
    "SwapRouter": "0xa7069da6a7e600e0348620484fD2B1f24E075d5f",
    "TickLens": "0xA13E04fAEe08E784A44C27e9E77Ca7a02D45BFd7",
    "UniswapV3FactoryUpgradeable": "0xDD2dce9C403f93c10af1846543870D065419E70b",
    "WETH": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14"
  }
```

## New features of note in V3

There have been some updates to the way in which the NFTX V3 protocol works if you are used to NFTX v2. The two updates that are most relevant for&#x20;

### Vault Fees paid in ETH

In V2 the fees paid were done using the native vToken. This meant if there was a 5% fee for buying an NFT, you needed to swap 1.05 vTokens with 1 vToken being burned and the other 0.05 vTokens distributed to liquidity and inventory providers

In NFTX V3 the fees are now paid in ETH as part of the transaction. Using the same 5% fee example, users will now buy 1 vToken through the NFTX Universal AMM Router, and the additional fee amount can be worked out by passing the fee amount to the vault contract `vTokenToEth` function.

<figure><img src="/files/7QTmU9UUEeRem09rDmPe" alt=""><figcaption></figcaption></figure>

`redeemFee` = `5000000000000000`

`vTokenAmount` = `49995022529647` wei

The `vTokenToETH` function is based on the TWAP and does not flucuate based on the available liquidity in the pool. For example, if you were buying 5 items the fee amount would be\
&#x20;`5 * 5000000000000000 = 25000000000000000`&#x20;

which would equate to&#x20;

`5 * 49995022529647 = 249975112648235`

Buying more tokens doesn't impact the spread for the `vTokenToETH` calculation

### Premium NFT auctions

When an NFT is "minted" into the vault on Sepolia a premium fee of 500% placed on the item at an exponential reduction to 0% over `3600` seconds. The fee is reduced every second. `mainnet` duration will be 10 hours (36000 seconds)

To find the current fee required for the NFT pass the ID of the NFT into the `getVTokenPremium` function on the vault contract. The response includes the `premium` amount and the `depositor` address. The `depositor` will receieve the majority of the premium fee, with the liquidity and inventory providers also sharing in a portion, but this address is not required for the marketplace integration, only the `premium` amount.

<figure><img src="/files/MVK6gEvz3D29Ax4QtnVT" alt=""><figcaption><p>Checking the getVTokenPremium721 for tokenId 310</p></figcaption></figure>

{% hint style="info" %}
If you want to omit the premium NFTs from your integration you can add a filter to the subgraph call to require the `holdings.dateAdded` is less than `now - 3600`.
{% endhint %}

{% code title="Add this to your Get all NFT holdings query" overflow="wrap" %}

```graphql
holdings(first: 1000, orderBy: tokenId, orderDirection: asc, where: { dateAdded_lt: "$(now - 3600)"})
```

{% endcode %}

{% hint style="success" %}
Remember that the premium reduces every second even though the blocks are only every 12 seconds. This will mean that what ever calculation you make for the buyer, the actual buy price is going to be lower because more time has elapsed before the next block is mined. This additional ETH is returned to the user as part of the transaction.
{% endhint %}

## Get all NFT holdings

Send a request to the NFTX V3 subgraph for all vaults.

### Graph Endpoints

**Sepolia:** [**https://thegraph.com/hosted-service/subgraph/nftx-project/nftx-v3-vaults-sepolia**](https://thegraph.com/hosted-service/subgraph/nftx-project/nftx-v3-vaults-sepolia)

**Mainnet Graph Endpoint:** Not yet deployed.

**Arbitrum Graph Endpoint:** Not yet deployed.

**Graph request:**

```graphql
{
  globals {
    fees {
      mintFee
      randomRedeemFee
      targetRedeemFee
      randomSwapFee
      targetSwapFee
    }
  }
  vaults(
    first: 1000
    where: {vaultId_gte: 0, isFinalized: true, totalHoldings_gt: 0}
  ) {
    vaultId
    id
    is1155
    isFinalized
    totalHoldings
    totalMints
    totalRedeems
    totalFees
    totalSwaps
    createdAt
    holdings(first: 1000, orderBy: tokenId, orderDirection: asc) {
      id
      tokenId
      amount
      dateAdded
    }
   # holdings(
   #     first: 1000, 
   #     orderBy: tokenId, 
   #     orderDirection: asc,
   #     where: { dateAdded_lt: "$(now - 3600)"}
   #     ) {
   #   id
   #   tokenId
   #   amount
   #   dateAdded
   # }
    token {
      id
      name
      symbol
    }
    fees {
      mintFee
      redeemFee
      swapFee
    }
    usesFactoryFees
    asset {
      id
      name
      symbol
    }
    manager {
      id
    }
    createdBy {
      id
    }
    eligibilityModule {
      id
      eligibleIds
      eligibleRange
    }
    features {
      enableMint
      enableRedeem
      enableSwap
    }
  }
}
```

## Buying an NFT(s) from the vaults

When buying items from the vault you need

1. `redeemFee` amount to calculate the ETH fee required (subgraph).
2. `vTokenPremium` amount to calculate the ETH required for new items in the vault (onchain)
3. `quoteDecimals` amount to calculate the cost of the vTokens for redeeming the NFTs (this comes from the NFTX Router API request)
4. `nftIds` of the NFT you want to purchase
5. `to` address of the person buying

In this example we're buying 2 NFTs, `351, 346` from the following vault.\
\
`Vault Name: Fringoooor` \
`vaultId: 0`  \
`vTokenAddress: 0x6f4d645d1645e65db2E7f9Aa11Eb5Fc45a65592A`

### Calculate the NFT premium cost

When an NFT goes into the vault there is a `3600` second premium placed upon it which reduces each second exponentially from 500% - 0%.

To calculate the premium for an NFT being bought you can pass the `nftId` to the `getVTokenPremium721` function. The response will contain the amount of additional vToken that is set as the premium.

Below is an example of two tokens, one with almost the highest premium (token `351`) and the other no premium (token `346`).

<figure><img src="/files/dLURUgCHc4gm2JNRhnFI" alt=""><figcaption><p>This token has a premium of <code>4983601988461962229</code> vTokens.</p></figcaption></figure>

<figure><img src="/files/1NNAaI0OsRvxZf7i3POJ" alt=""><figcaption><p>This token has a premium of <code>0</code> vTokens.</p></figcaption></figure>

These values should be added to the ETH fee (see next step).

### Calculate ETH fee

Find the fee amount for `redeemFee`, either by using the subgraph response or by making an onchain call to the vault contract (see below).

<figure><img src="/files/Mah6TOljF1rPKiaf8JOI" alt=""><figcaption></figcaption></figure>

In this example we are buying two NFTs, we need to double the redeemFee from `50000000000000000` to `100000000000000000`

### Calculate Fee + Premium to ETH

Add the `redeemFee` and the `nftPremiumFee` together and pass that to the `vTokenToETH` function on the vault contract.

`100000000000000000 + 4983601988461962229 = 5083601988461962229` &#x20;

<figure><img src="/files/qp5jvfg3Cmh6x72z3RRO" alt=""><figcaption><p>We're passing the sum of the fee and NFT Premium amounts to find the ETH value</p></figcaption></figure>

`580380454730343582` wei is equivalent to `0.5080380454730343582` ETH.

This amount is then added to the cost of the token buy quote price.

### Calculate the token price

NFTX is running a Universal Router API to return the best price across all of the pools and positions.

When requesting

<https://api.nftx.xyz/v3/eth-sepolia/quote?tokenInAddress=ETH&tokenInChainId=11155111&tokenOutAddress=0xea0bb4de9f595439059af786614daf2ffada72d5&tokenOutChainId=11155111&amount=1000000000000000000&type=exactOut&recipient=0x4eAc46c2472b32dc7158110825A7443D35a90168&deadline=300&enableUniversalRouter=true&slippageTolerance=0.01&protocols=v3><br>

<table data-full-width="true"><thead><tr><th width="260.3333333333333">Query Parameters</th><th width="264">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>tokenInChainId</code></td><td><code>11155111</code></td><td>Sepolia: 11155111, Mainnet: 1, Arbitrum 42161</td></tr><tr><td><code>tokenOutChainId</code></td><td><code>11155111</code></td><td>Sepolia: 11155111, Mainnet: 1, Arbitrum 42161</td></tr><tr><td><code>protocols</code></td><td><code>v3</code></td><td>The Universal router is configured to also work with SushiSwap V2 router, however all V3 liquidity will be on the NFTX AMM which is <code>v3</code></td></tr><tr><td><code>slippageTolerance</code></td><td><code>10</code></td><td></td></tr><tr><td><code>deadline</code></td><td><code>3000</code></td><td>The quote is valid for 3000 seconds</td></tr><tr><td><code>recipient</code></td><td><code>0x50f69c6556338965bf77C16ADb462Fdb5bE01C09</code></td><td>The recipient is set to the <code>marketplaceZap</code> address, as that will be the recipient of the tokens to then redeem the NFT from the vault.</td></tr><tr><td><code>enableUniversalRouter</code></td><td><code>true</code></td><td>Required to return the quote <code>callData</code></td></tr><tr><td><code>tokenInAddress</code></td><td><code>0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6</code></td><td>The token you are paying with, this should be set to wETH even if paying with ETH. </td></tr><tr><td><code>amount</code></td><td><code>2000000000000000000</code></td><td>The number of tokens you are buying. Remember, this is 1:1 with the NFT, the fees are now paid as ETH. We are buying 2 tokens in this example.</td></tr><tr><td><code>type</code></td><td><code>exactOut</code></td><td>When buying we only want the exact number of tokens out.</td></tr><tr><td><code>tokenOutAddress</code></td><td><code>0x6f4d645d1645e65db2E7f9Aa11Eb5Fc45a65592A</code></td><td>The <code>vToken</code> for the NFT we want to buy.</td></tr></tbody></table>

Response

{% code fullWidth="true" %}

```json
{
    "methodParameters": {
        "calldata": "0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000064b944600000000000000000000000000000000000000000000000000000000000000001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010000000000000000000000000011f9ce2c92ed333115d1cb1078a1f7bbfa7de0d50000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000003a19200263a412600000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002b6f4d645d1645e65db2e7f9aa11eb5fc45a65592a002710b4fbf271143f4fbf7b91a5ded31805e42b2208d6000000000000000000000000000000000000000000",
        "value": "0x00",
        "to": "0x375e894364bEBed5388115A6BbEEfb9290C610de"
    },
    "blockNumber": "9376996",
    "amount": "2000000000000000000",
    "amountDecimals": "2",
    "quote": "237864347912006086",
    "quoteDecimals": "0.237864347912006086",
    "quoteGasAdjusted": "251903648500922086",
    "quoteGasAdjustedDecimals": "0.251903648500922086",
    "gasUseEstimateQuote": "14039300588916000",
    "gasUseEstimateQuoteDecimals": "0.014039300588916",
    "gasUseEstimate": "113000",
    "gasUseEstimateUSD": "28.078601",
    "simulationStatus": "UNATTEMPTED",
    "simulationError": false,
    "gasPriceWei": "124241598132",
    "route": [
        [
            {
                "type": "v3-pool",
                "address": "0x5E8A2433C047881D18B63AB239d02af4F4b33229",
                "tokenIn": {
                    "chainId": 5,
                    "decimals": "18",
                    "address": "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
                    "symbol": "WETH"
                },
                "tokenOut": {
                    "chainId": 5,
                    "decimals": "18",
                    "address": "0x6f4d645d1645e65db2E7f9Aa11Eb5Fc45a65592A",
                    "symbol": "FRINGOOOOOOOOR"
                },
                "fee": "10000",
                "liquidity": "22290182843350301072",
                "sqrtRatioX96": "26770813048747472398292166448",
                "tickCurrent": "-21702",
                "amountIn": "237864347912006086",
                "amountOut": "2000000000000000000"
            }
        ]
    ],
    "routeString": "[V3] 100.00% = WETH -- 1% [0x5E8A2433C047881D18B63AB239d02af4F4b33229] --> FRINGOOOOOOOOR",
    "quoteId": "1ec15"
}
```

{% endcode %}

Add the `quoteDecimals` to the `Fee + Premium ETH` amount calculated in the previous step.

`0.237864347912006086` + `0.574672096207709349` = `0.8125364441` ETH.

### Buy NFT with MarketplaceUniversalRouterZap

With all the data collected, call the `buyNFTsWithETH` function on the   `MarketplaceUniversalRouterZap`

* ETH amount calcuated earlier: premium + fee + token.
* The `vaultId` retrieved from the subgraph (or onchain against the vault contract)
* `idsOut` are the NFTs being bought
* `executeCallData` is the `calldata` in the response from the NFTX Universal Router API
* `to` address is who is buying the NFT (or who should receive the NFT)
* `deductRoyalty` is an optional inclusion, `false` for the sake of this implementation

<div data-full-width="true"><figure><img src="/files/1fLJzWaPnVbJGNwBwhSc" alt=""><figcaption></figcaption></figure></div>


# Project Background

Summary of V1, V2, and goals for V3.

### NFTX v1  (2020)

* NFTX v1 was a protocol for wrapping NFTs into fungible ERC20 "index" tokens. The index tokens could be minted by putting NFTs into a holding contract (1 NFT for 1 token), and random NFTs could be redeemed from the holding contract by burning index tokens. For example, you could mint 2 PUNK-BASIC tokens by putting 2 CryptoPunks into the holding contract, and redeem 2 CryptoPunks by burning 2 PUNK-BASIC.&#x20;
* Since each NFT equalled 1 index token, index tokens were built to attract the cheapest "floor" NFTs from a collection, and also to track the floor price of that collection.&#x20;
* Every index token on NFTX v1 was linked to one NFT contract which it accepted NFTs from. Index tokens on V1 could also have "eligibility modules" that contained custom rules for which NFT token IDs were allowed in the vault and which weren't. Later versions of NFTX have this feature as well.&#x20;
* NFTX v1 users tended to use Sushiswap for liquidity pools and to pair index tokens with WETH.
* We noticed that most NFTX v1 users were using index tokens (and Sushi liquidity) as an NFT liquidity endpoint, rather than out of interest in the actual index tokens. Essentially, when a user wanted to buy a random floor NFT from the holding contract they would buy 1 index token from Sushi and burn it for the NFT. And when a user wanted to sell a floor NFT they would mint 1 index token and then sell it on Sushi.&#x20;
* In NFTX v1, the focus was on turning non-fungible assets into fungible assets. In NFTX v2, the focus is on incentivizing liquidity (and inventory) for NFTs by capturing fees from buyers, sellers, and swappers. NFTX v2 still works like NFTX v1 by wrapping NFTs into ERC20s, however in V2 there are also fees paid by users that are then claimed as earnings by stakers.

### NFTX v2  (2021 - Present)

* In NFTX v2, index tokens are renamed to vTokens that also act as "vaults" to hold NFTs. Instead of a central holding contract like in V1, every vToken/vault contract holds its own NFTs in V2. And, like with index tokens in V1, vTokens in V2 are backed 1:1 by NFTs.&#x20;
* In V1, it was only possible to mint and to redeem randomly. In NFTX v2, it is possible to mint, random redeem, target redeem, random swap, and target swap. Target redeeming and target swapping means having the ability to pick which NFT(s) you receive. Swapping means exchanging one NFT that is eligible to enter a vault with another NFT from inside the vault. No vTokens are minted or burned during a swap.
* NFTX v2 includes vault fees, which are not possible in V1. Every vault in V2 can set fees for each of the five vault operations (minting, random redeeming, target redeeming, random swapping, and target swapping). Vault fees are paid in vToken, and there are default/global fee settings which apply if a vault has not customized its own fees.&#x20;
* Currently, at the time of this writing, the default V2 vault fees are 5% mint, 2% random redeem, 3% target redeem, 2% random swap, and 5% target swap. This fee structure is written as 5/2/3/2/5. Fees are paid in vToken, so a 5% fee means 0.05 vToken and implies that minting a vToken by sending an NFT to the vault will net the user 0.95 vToken in return.&#x20;
* When a user sells an NFT on NFTX v2, what actually happens is that the NFT is used to mint 1 vToken, of which 5% (i.e. 0.05 vToken) goes to stakers for that vault. The other 95% gets traded for WETH and returned to the seller. When a user buys an NFT on NFTX v2, what happens is that the user buys 1.03 vToken from the Sushi pool, then 0.03 vToken goes to vault stakers, 1 vToken gets burned, and the NFT is sent to the buyer.
* In V2, you can stake SLP tokens (Sushi Liquidity Provision tokens) to earn vault fees. Every time a vault is created in V2 there is also a Sushi liquidity pool deployed for the new vToken, paired with WETH. When a user liquidity stakes on NFTX, they send vToken & WETH which goes to the Sushi pool and returns an ERC20 SLP token, then that SLP gets deposited on NFTX and an ERC20 xSLP token is minted and sent to the staker. As vaults earn fees (in vToken), xSLP holders can claim their portion of those fees.&#x20;
* NFTX v2 also has inventory staking (rolled out as part of v2.1), which is when a user deposits vToken and receives xToken (e.g. deposits PUNK and receives xPUNK). Inventory stakers receive 20% of vault fees, and liquidity stakers receive the other 80%. The purpose of inventory staking is to increase the number of NFTs in the vault for buyers (and swappers) to choose from. Vault fees for inventory staking are sent to the xToken pools. This means that inventory stakers (i.e. xToken holders) don't have to claim their vToken earnings. Those earnings just get sent to the xToken pool so that the vToken backing increases.


# Security History

Audits, bugs, and exploits.

<figure><img src="/files/UqkpWZbTZ5X1b6UbQc9H" alt=""><figcaption></figcaption></figure>

## NFTX v1

* [Level K audit](https://github.com/NFTX-project/audit-level-k/blob/master/NFTX-final.pdf) (for v1) — November 2020
* NFTX v1 deployed — December 2020
* [<mark style="color:yellow;">Bug bounty: samczun</mark>](https://forum.nftx.org/t/retroactive-bug-bounty/161) — February 2021

## NFTX v2

* [Code Arena competition 1](https://code4rena.com/reports/2021-05-nftx) (for v2) — May 2021
* NFTX v2 deployed — June 2021
* [<mark style="color:red;">PUNK exploit</mark>](https://blog.nftx.io/nftx-v2-punk-incident-post-mortem/) (assets recovered w/ minor DAO loss) — June 2021
* [Code Arena competition 2](https://code4rena.com/reports/2021-12-nftx) (for v2.1)— December 2021
* NFTX v2.1 (Inventory Staking) deployed — January 2022
* [Trail of Bits audit](https://268710349-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MObsGdLeFkbdDe8_KiT-2910905616%2Fuploads%2FxxMQXacJ9gspSb09eUCz%2FToB_Audit.pdf?alt=media\&token=2c8a160a-8c5f-4f57-87a7-a5fdcf51eb4d) (for existing protocol) — April 2022
* Marketplace0xZap deployed (un-audited) — September 2022
* [<mark style="color:yellow;">Bug bounty: p</mark>](https://blog.nftx.io/postmortem-nftxmarketplace0xzap-vulnerability/)<mark style="color:yellow;">0n1</mark> — September 2022
* [SECBIT audit](https://268710349-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MObsGdLeFkbdDe8_KiT-2910905616%2Fuploads%2Ff5r6lXZIs4rTMBTrt0eH%2FNFTX_V2_Periphery_Report_v1.1_2022_12_23.pdf?alt=media\&token=c4902b12-53f7-4492-9555-1f1e46be7c56) (for Marketplace0xZap & CreateVaultZap)— November 2022

## NFTX v3

### Spearbit audit (for core contracts)

{% file src="/files/h2En7mVlMdyQCWO69NMr" %}

### Cantina audit (for zaps)

{% file src="/files/mOVSuACN8BcvYKR2mTwI" %}


# Notes for Auditors

from Alex (Gaus)

There is quite a lot going on within the NFTX protocol. At the root of it all are vaults that store NFTs in a 1:1 ratio to how many vTokens are minted. It is important that the 1:1 invariant always remains true and that any NFTs entering the vault are the expected type of NFTs (described by the vault's `assetAddress`, `allowAllItems`, and `eligibilityStorage` variables).

The inventory staking contract takes vTokens in exchange for minting xNFT positions. Each xNFT has a `vTokenShareBalance` that tracks its portion of the contract's total vToken holdings. It is important that the absolute amount of vTokens that a position can withdraw (determined by the contract's holdings and the position's vToken share) never goes down—unless as a result of paying an `earlyWithdraw` penalty.

Unlike V2, NFTX v3 has its own AMM, which is a Uniswap v3 fork with some (fairly minor) modifications. It is important that, outside of the modifications, the NFTX AMM functions how UniV3 functions and that it's not possible for the pools to be drained.&#x20;

In the past, we have suffered security issues with our V2 marketplace zap and with the V2 CryptoPunks vault. Given this, we like to be extra cautious about it not being possible to drain assets from the wallets of users who interact with the NFTX protocol (as was the case with the 2022 p0n1 bug bounty). Likewise, we like to be mindful that the CryptoPunks contract is a non-standard NFT contract deployed before ERC721 was released, so any contracts interacting with it may require added attention.

`NFTXVaultUpgradeable`, `NFTXVaultFactoryUpgradeableV3`, and `NFTXInventoryStakingV3Upgradeable` all implement `PausableUpgradeable` which allows certain functions to be paused by team "guardian" addresses. This may be used if there is a reason to think that the protocol is at risk, so it's important for it to function correctly. After the protocol is paused and the issue is addressed, the protocol can then be unpaused by the DAO (following a 7-day voting period).&#x20;

In NFTX v2, all fees were in vToken, so there was no need for TWAP feeds. With V3, vault fees are paid in ETH, and the amounts charged are determined using TWAPs. So, although no critical asset handling depends on TWAPs, they are still central to the protocol's usecase. Other aspects of the protocol that may require some added attention include merging inventory (xNFT) positions, adding to inventory and liquidity positions, and withdrawing from positions.

Lastly, a few final points... First, relating to TWAPs, low liquidity can make it difficult/impossible for users to buy or sell NFTs—this is a known issue that we may try to solve in the future. Second, vaults are built to work for ERC1155 collections as well, but we spend less time using such vaults, so it is important that they are reviewed too, and (3) NFTX makes extensive use of upgradeable proxies, which will be controlled by the NFTX DAO.&#x20;


# Introduction to NFTX

{% hint style="info" %}
[V1 documentation](https://docs.nftx.org/v/v1.0/) or [V2.0 documentation](https://docs.nftx.org/v/v2.0/) can be found using the drop down under the logo on the left sidebar.
{% endhint %}

NFTX is a platform for creating liquid markets for illiquid Non-Fungible Tokens (NFTs).

Users deposit their NFT into an NFTX vault and mint a fungible ERC20 token (vToken) that represents a claim on a random asset from within the vault. vTokens can also be used to redeem a specific NFT from a vault.

**Benefits include:**

* LP and stake minted vTokens to earn yield rewards
* Better distribution and price discovery for NFT projects
* Instantly sell any NFT by minting it as an ERC20 and swapping via Sushiswap
* Increased liquidity for NFT investors and speculators

## How does it work?

### Vault Creation

Vaults can be created by anyone for any NFT asset on Ethereum. Once a vault has been created, any user can then deposit eligible NFTs into the vault to mint a fungible NFT-backed token referred to as an "vToken".

[Learn more about vault creation](/main/tutorials/vault-creation)

### Minting vTokens

Anyone can deposit NFTs into an existing vault (or one they have created) in order to mint a fungible vToken that represents a 1:1 claim on a random NFT from within the vault.

[Learn more about minting](/main/tutorials/minting)

### Floor Prices

Users can then pool their minted vTokens in Automated Market Makers (AMMs) like Sushiswap to create a liquid market for other users to trade. With liquidity and trading volume established, the NFT-backed vToken enters into price discovery and a "floor price" is discovered.

The floor price denotes the lowest price for a particular NFT. Users establish a floor price by minting and selling vTokens in markets where they consider their NFT to be overvalued.

{% hint style="info" %}
NFTX is helping to establish reliable floor price feeds for NFTs, enabling their wider application in decentralized finance on Ethereum.
{% endhint %}

For example, a user has 5 Hashmasks and values 2 of them highly. However, they consider the other 3 Hashmasks to be lower value than the market price for the Mask vault on Sushiswap. The user deposits these 3 Hashmasks and sells their 3 minted MASK tokens on Sushiswap, lowering its price and aiding price discovery.

The above process will continue until a floor price is achieved.

### Eligibilities

The Mask vault allows any Hashmask to be deposited, however other vaults use an eligibility list that only allows a specific sub-category of NFTs to be deposited. For example, the Kitty Gen 0 vault has an eligibility list that includes only Kitties whose metadata is Generation 0. Other Kitties can not be deposited into this vault.

## Who Benefits From NFTX?

### Collectors

NFTs in their basic form do not earn yield. However, when they are used to mint vTokens they can tap into the world of decentralized finance. Put simply, collectors can use NFTX to unlock more value from their NFTs:

* Earn protocol fees
* Earn trading fees as a liquidity provider
* Farm with stablecoins using vTokens as loan collateral

### Content Creators

By launching on the NFTX protocol, content creators are able to earn protocol fees in perpetuity whilst also improving the reach and fairness of distribution:

* Earn protocol fees
* Distribute NFTs via an AMM in the form of vTokens
* Create instantly liquid markets for new content

### Investors

NFTs are typically highly illiquid and difficult to price. NFTX makes speculating and investing in the NFT market a far simpler process:

* Access the most liquid markets for NFTs
* Track the price of particular categories of NFT


# FAQ

## Basics

### What is NFTX?

NFTX is a platform for making ERC20 tokens that are backed by NFT collectibles. These tokens are called vault tokens, and (like all ERC20s) they are fungible and composable. With NFTX, it is possible to create and trade tokens based on your favorite collectibles such as [CryptoPunks](https://www.larvalabs.com/cryptopunks), [CryptoKitties](https://www.cryptokitties.co/), and [Avastars](https://avastars.io/), right from an exchange.

NFTX's mission is to become the primary issuer of NFT vault tokens, allowing anyone to trade & invest in NFT markets without needing the underlying knowledge and expertise required when investing in individual assets. By doing so, NFTX will function as a black hole for NFT assets.

### Is NFTX fully permissionless?

Yes, NFTX contracts are fully permissionless on-chain contracts.

The [NFTX.org](https://nftx.org) interface is built and maintained by the NFTX DAO and will be open-sourced as soon as possible, for anyone to run locally when needed.

### Who is working on NFTX?

NFTX is built by a decentralized autonomous organization (DAO) - a group of community members, contributors, and core members closely aligned to build the primary NFT liquidity hub. As NFTX is an open organization, anyone anywhere may join to provide expertise and/or additional resources with the goal to grow NFTXs' success.

If you'd like to contribute to what NFTX is building, feel free to join the community [on Discord.](https://discord.gg/xcJkxMXSR8)

### Does NFTX charge any fees?

[NFTX V1](https://v1.nftx.org) does not charge any fees.

[NFTX V2](https://app.nftx.org) allows vault creators to charge fees based on minting and redeeming NFTs in and out of the vaults. There are three fee options in V2 and are set to the following defaults for all DAO and new vault creations

1. 5% Minting Fee&#x20;
2. 0% Random Redemption Fee
3. 5% Targeted Redemption Fee

These fees are distributed as rewards to the liquidity providers for the vault.

Anyone providing liquidity to vaults can bypass minting fees by using a zap to automatically include liquidity. Learn more in the [minting tutorial](/main/tutorials/minting).

### Can you get rewards from using NFTX?

Yes. To encourage more liquidity for the vaults all fees that are generated from Buys and Sells (Minting and Redeeming) are passed to anyone that is staking their SLP against that vault. These rewards are paid out on a block-by-block basis, and are paid in the vault tokens you are using to stake.

You can see the APR for each of the different vaults on the [NFTX Staking](https://app.nftx.org/staking/) page.

### Is there an NFTX token?

Yes. The NFTX token is a governance token that can be used to vote on proposals and steer the direction of the organization. In total 650000 NFTX tokens will ever exist.

* 65K NFTX tokens are allocated to the founder of NFTX, Alex Gausman. These tokens are on a 5-year linear vesting schedule, without a cliff. Rewards on this vesting schedule are unlocked per block and added to the circulating supply until fully distributed.&#x20;
* 390K NFTX tokens were distributed during the origin [community raise](https://docs.nftx.io/v/v1.0/archive/community-raise), which has taken place from December 2020 to early January 2021. The tokens were granted to early community members through open bounties at various rates of ETH, as well as several NFTs. You can find a [full breakdown of this event here](https://docs.nftx.io/v/v1.0/archive/community-raise).
* 65K NFTX tokens were originally supplied as liquidity by the NFTX DAO on an AMM.
* 130K NFTX tokens are held in the NFTX DAO Treasury and used for additional market-making activities on vaults, such as the CryptoPunks vault.&#x20;

## Miscellaneous

### Who is the target audience of NFTX?

There are three main target audiences for NFTX: Investors, arbitrageurs, and NFT liquidity providers.

The main products are built for investors looking to buy and/or sell floor-priced NFTs without having to wait for a taker/maker on a secondary market.

The second audience we cater to are arbitrageurs, who can profit from ranging prices between NFT vault tokens and their underlying collaterals' floor prices on secondary markets. Arbitrageurs can use the products on nftx.org to interact directly with these pools.

A third audience we cater to are NFT liquidity providers, who can profit from providing additional liquidity and/or inventory to one or multiple NFT vaults. Liquidity providers may use the products on [nftx.org](https://app.nftx.org) to mint additional NFT vault tokens, which can then be supplied as liquidity.

### What is the NFTX token address?

The address of NFTX is: `0x87d73e916d7057945c9bcd8cdd94e42a6f47f776`

### How do I buy NFTX?

NFTX is available for trading on decentralized exchanges. To find the best rates across multiple exchanges, we recommend using an aggregator such as [Matcha](https://matcha.xyz/). A [detailed tutorial on how to do this can be found on our blog](https://blog.nftx.org/how-to-acquire-nftx-on-matcha/).

### Where do I find NFTX Vault Tokens?

V1 vaults can be viewed in the [Gallery](https://gallery.nftx.org/).

V2 NFTX Vaults can be found on the [App homepage.](https://app.nftx.org)

### What can I do with vTokens?

If you have recently received a small amount of vToken as part of the buying process there are somethings you can do with it.

1. Sell it on [Matcha for ETH](https://www.matcha.xyz/markets/1/ETH)
2. Stake it as inventory on the [Yield App](https://yield.nftx.io)
3. Stake it as liquidity (either on [Sushi](https://app.sushi.com/legacy/add) where you can then stake your SLP and earn fees) or as a [concentrated liquidity position on Uniswap](https://app.uniswap.org).


# Minting

NFTX v2 introduces a new minting interface that allows you to easily mint a liquid ERC20 token from your NFT!

![](/files/-McpuD8b3UMvcSz7epak)

## Why mint an NFT?

By adding your NFT to an NFTX vault you mint an ERC-20 token (vToken) that has a 1:1 claim on a random NFT inside the vault.

Unlike a non-fungible token (NFT), an ERC-20 is fungible (all tokens are the same) and this allows it to be:

* Instantly sold at an AMM (like Sushiswap)&#x20;
* Pooled in an AMM to earn trading fees
* Staking
* Used as collateral to borrow stablecoins

vTokens can be used to redeem a random vault NFT at any time.

## Minting Step-by-step

### Choose your vault

The initial mint view shows all the current NFTX Vaults that you are able to mint into based on the contents of your connected wallet. In this example we're going to select the [Avastr vault](https://v2.nftx.org/mint/0xdcdc1c1cc33aa817cbdbe8f5e2390bf7cc43dc4b/).

![](/files/-Mcpv0RcpHNAtgzg9a1c)

### Selecting NFTs

Choose the NFTs from your wallet that you would like to mint to the vault. Remember, the vaults are often floor vaults and minting a higher value NFT will provide the same result as a lower value NFT from the collection.

![](/files/-McpwtBH3Ryx3bz_nUJY)

Not seeing your NFT? [See our FAQ](https://docs.nftx.org/tutorials/get-started-v1.x/minting#faq).

### Mint Basket

The mint basket will show you the NFTs you have selected, their approval status, mint fee and the number of tokens you will recieve after minting.

{% hint style="info" %}
Although not shown in the screenshot below, you will sometimes need to "Approve" the NFTs to be minted into the Vault. Once Approved, the "Mint AVASTR" (or relevant NFT name) will appear and you can complete the minting process.
{% endhint %}

![](/files/-Mcpxbd_FcGs2q86b2mi)

#### Approval

Your NFTs will need to be approved for use by the NFTX contract before they can be minted into an ERC-20. To approve all your NFTs in this contract (i.e. the Wrapped Punks contract), click "Approve all".

**Mint fee & Tokens received**

The mint fee is new in v2 and will be distributed 100% to the liquidity providers.  The fee is set to a default of 5%, however during the vault creation process this can be changed to any value. Once the vault is published, only the DAO is able to update the mint fees via a governance vote.

With a 5% mint fee, each NFT minted will result in the distribution of 0.95 vTokens (in this case AVASTR tokens) with the remainder distributed to the liquidity providers.

### **Minting**

With your NFTs approved and your mint value confirmed, click the "Mint" button to generate your vTokens. Each NFT will return a single vToken, minus the mint fee.

For example, minting 2 Avastars to the Avastar vault will return 1.9 AVASTR ERC-20 tokens.

{% hint style="info" %}
It is important to mint your NFT to the appropriate vault. Do not mint high value NFTs (i.e. a Avastar Rank 70) to a lower value vault (i.e. AVASTR).
{% endhint %}

### Bypass Mint Fee's with Zaps

To encourage more liquidity for the vaults we allow users to avoid paying the mint fee if they choose to stake liquidity for a minimum of 48 hours.

Below shows the two options

1. 5% mint fee and get back 0.95 vTokens
2. 0% mint fee and get back 1 vToken

![With your NFT in the basket you can choose to pay the mint fee, or bypass the fee by Minting & Staking](/files/-MfcdOoSzS70SSvplLOB)

Choosing the Mint & Stake option requires an additional confirmation step, also shown below. This provides an overview of the number of tokens you are pairing, and the amount of ETH you need to pair for the pool.

* **Pool share** — the share of the fee's earned on this vault that you will get each block. In this case, it is 50% of the fee distribution.
* **Mint fee** — the mint fee is waived for staking your liquidity for 48 hours.
* **Lock time** — the length of time your position will be locked. After 48 hours you can unstake and withdraw your liquidity.

![](/files/-MfceHJ07J-vVV1Sz1zF)

{% hint style="danger" %}
Remember that if you already have a position on the vault your entire position will be locked for the 48 hours, not just the amount you are zapping on this process. This does not affect any other positions you might have in other vaults on NFTX.
{% endhint %}

Once you have confirmed the Mint & Stake you can view the Staking page to see your positions, and the time left on your locked positions.

![](/files/-MfcfWVMhzZKY923T6Hv)

### Mint Requests

In v2 there are no longer any mint requests.

## FAQ

### Why aren't my NFTs showing in the minter?

If you can't see an asset it will be for one of the following reasons:

#### Your NFT is not eligible for the vault

Some vaults use eligibilities to ensure that only certain sub-categories of an NFT can be included. For these vaults, it may be possible to send a [mint request](https://docs.nftx.org/tutorials/get-started-v1.x/minting#mint-requests).

#### Your NFT requires wrapping

NFTs that were developed several years ago did not follow the ERC721 or ERC1155 token standard. Unlike in V1, the V2 vaults now support unwrapped Mooncats and CryptoPunks.

#### You have just received your NFT

We use the OpenSea API to list the available NFTs that you may have in your wallet. The API can sometimes take a few minutes to update. Please wait 5 minutes and if it is still not showing, [reach out to us on Discord](https://discord.com/invite/fJg5burAKH).

#### Your wallet contains more than 1,000 NFTs

We currently limit the minter to scanning a wallet's first 1,000 NFTs that may be available for minting. If you have more than 1,000 NFTs in your wallet please [reach out to us on Discord](https://discord.com/invite/fJg5burAKH) for assistance.

### Can I get my NFT back once I've added it to a vault?

A vToken provides a claim on a single asset within a vault. In v2 we have introduced targeted redeems which allows you to choose any NFT from the vault for a 5% premium (this is the default settings, vault owners can change this value during the vault creation process).

You can buy additional vTokens from SushiSwap, and we will soon allow you to make up the additional costs with ETH directly from the App.

### My NFT can be deposited in multiple vaults, which one do I choose?

Some NFTs are eligible to be deposited to multiple vaults. While this is still possible in v2, the initial vaults created have moved away from multiple vaults for the same NFT and towards floor vaults.

Always check an NFT's available vaults before minting an vToken to ensure the most appropriate one is selected.

### I've minted my NFT but I haven't received my Token yet

You need to add the vault token as a custom token to your metamask wallet (see [an example of how to add custom tokens here](https://blog.nftx.org/how-do-i-view-my-nftx-tokens-in-metamask/#how-can-you-see-your-nftx-tokens-inside-of-metamask))


# Redeeming

![](/files/-MdRiaiaWOVeOpAOL67p)

NFTX v2 allows you to easily redeem your [minted](/main/tutorials/minting) ERC20 Vault Tokens (vTokens) for either a random or targeted NFT within the vault.

## Why redeem an NFT?

Redemptions allow users to take ownership of an underlying NFT from within a vault. This means that a user can go to an AMM like Sushiswap, purchase a single vToken like PUNK and use that token to claim a random CryptoPunk from the [PUNK Vault](https://app.nftx.org/redeem/0x269616d549d7e8eaa82dfb17028d0b212d11232a/).

For an additional fee, usually 5% (1.05 vTokens), users are able to select a specific NFT from the vault.

## Redeeming Step-by-Step

### vToken Balance

![This shows that I have 4 BUNNY tokens which will allow me to claim back 4 random Genbit Bunnies from the Vault](/files/-MdRj0z1_992guGYCRVg)

When you visit <https://app.nftx.org/redeem> and connect your wallet, your vToken and NFTX balances will be displayed on the right hand side. Each vToken represents a claim on a random NFT from within its vault.

You can also target redeem specific NFTs from the vault by paying the Targeted Redeem fee — often 5% or 1.05 vTokens.

{% hint style="info" %}
Don't have any vTokens? [Visit the App](http://app.nftx.org) to browse the available vaults. Once inside the vault you can click on "Buy {vToken}" and pick it up from SushiSwap.

{% endhint %}

![](/files/-MfchG2myTAElOd1cebP)

### Redeeming — Random

To redeem an NFT you must enter the quantity you would like to redeem (in whole numbers) next to the "Random" section in the redemption baskset and approve the NFTX contract. Once the approval transaction has been confirmed, you will then be able to redeem the desired number of NFTs from the vault.

![Here I am redeeming 2 random Genbit Bunnies using 2 BUNNY tokens](/files/-MdRkGD135czAQkiPPlE)

### Redeeming — Targeted

New in V2 is the option to choose the NFT you wish to redeem from the vault.

Select the NFT you wish to redeem from the vault and they will be added to the redeem basket. Note that each targeted redeem will require 1 vToken plus the fee set for targetted redeems on the vault. This fee defaults to 5% on vault creation, but can be changed by the vault creator prior to finalising the vault. Once finalised, the fee's can only be updated by the DAO via a governance vote.

If the vault is left at the default settings, each targeted redeem will cost 1.05 vTokens.

![Three Bunnies are being targetted redeem for 3.15 vTokens](/files/-MdRlUeoK_gITqXNChXi)

## FAQ

### Can I redeem from a vault without a vToken?

Users must have a vToken in their wallet balance to redeem from a vault. To browse the available vaults and vault NFTs, please visit the [home page of the App](https://app.nftx.org).


# Staking

## Why stake on NFTX?

Earn fees from the vault, currently 100% of protocol fees are paid out to those that stake. Liquidity providers earn a share of 80% and inventory providers earn a share of 20% of the fees.

Stakers also receive an ERC20 “xToken” like xPUNKWETH that is a claim on the underlying staked SLP, or xPUNK which is a claim on the underlying staked inventory. We expect other projects to build use cases for these xTokens.

You can learn more about the benefits of staking on <https://academy.nftx.io/staking>

{% hint style="info" %}
APRs are calculated by annualizing the last 30 days of the vault's fee earnings. The real rate of return will vary throughout the year.
{% endhint %}

## How to stake on NFTX?

To stake on NFTX you need an NFT from that collection. In this example we're going to look at the Space Poggers collection.

There are two ways to stake and earn fees

* Liquidity staking
* Inventory staking

Remember that in both situations your NFT ends up inside of the vault where *anyone* can buy or swap it back out. You are not gauranteed to get the same NFT back, so don't stake any rare NFTs or NFTs that you are attached to.

### Inventory Staking

Go to the Stake page on the vault.

![The stake page shows you the NFTs in your connected wallet that you can stake into the vault.](/files/ke4sp64bvIqdHxzJ77c6)

Select the NFT that you would like to stake as inventory into the vault. Note that in the image below we are staking Pogger #2877 which will give me a share of 3.26% of the inventory rewards (which is 20% of the fees), and the **position will be locked for 7 days**.

The lock period is there to avoid users from using staking as a way to bypass the mint/sell fees.

![](/files/fCvVSntGHeTdF5AS4ijt)

Once you have confirmed BOTH the **Approve** and **Stake** transactions you will receive the below message that your transaction was successful.

<img src="/files/1XBYyPwak4FEUsuuAZnl" alt="" data-size="original">

This will provide you with an xTOKEN (xPOGGER) which is a reference to your staked inventory position. The xTOKEN is usually *less* than the number of NFTs you have added, for example we received 0.9241 xPOGGER back from staking one Space Pogger.

When we decide to exit our position, that is equivalent to at least 1 POGGER token plus any fees that are accrued during the time we are staked. When exiting you are also able to claim a random NFT from the vault and bypass the redeem fee, so you're always gauranteed to get the same number of NFTs out of the vault that you put in when inventory staking.

![](/files/Bx3ZYOhEm9SF24hthMoI)

### Liquidity Staking

Go to the Stake page on the vault.

Select the NFT that you would like to stake as liquidity into the vault. Note that in the image below we are staking Pogger #5389 which will give me a share of 0.78% of the liquidity rewards (which is 80% of the fees), and the **position will be locked for 2 days**.

![](/files/5QT0mGH9ELz4BDyMo2Zx)

The lock period is there to avoid users from using staking as a way to bypass the mint/sell fees.

Once you have confirmed BOTH the **Approve** and **Stake** transactions you will receive the below message that your transaction was successful.

<img src="/files/1XBYyPwak4FEUsuuAZnl" alt="" data-size="original">

This will provide you with an xTOKENWETH (xPOGGERWETH) which is a reference to your staked liquidity position. The xTOKENWETH is usually *less* than the number of NFTs you have added, for example we received 0.0992 xPOGGERWETH back from staking one Space Pogger. This is your claim on the SLP on Sushi.

When we decide to exit our position, that **will not** be equivalent to the 1 POGGER or equivalent ETH your added into the pool when staking. If there were lots of sells you will get back more POGGER tokens and less ETH, if there were lots of buys then you will get back more ETH and less POGGER tokens, and unlike Inventory staking your rewards are not compounded into your position, and instead you can claim them at any time through the Dashboard.

![](/files/zE9Ex5WYaTQHUIbTxVJo)

## How to UNstake your position on NFTX?

You can unstake both your liquidity and inventory positions on the <https://nftx.io/rewards/dashboard/>

Find the position that you would like to exit and select the "Unstake" button.

### Inventory Unstaking

When unstaking your position you have the option to receive just the vault tokens which you can then sell on Sushi for ETH, or you can claim a random NFT (or multiple if you staked more) and bypass the random redeem fee.

There is also the option to "Withdraw remaining x.xxxx TOKEN" which you could then sell on Sushi. If you decide not to claim the additional tokens they will remain staked and earning fees.

![](/files/6xoDURbwdsvOHpQsMnVg)

### Liquidity Unstaking

Choose the "Unstake" button and select the amount of xTOKENWETH you would like to withdraw. This will return the SLP token which you can then unwind on Sushi directly.

{% hint style="info" %}
Before we unstaked there were 0.1499 BUNNY tokens that can be claimed. If you are unstaking your position those tokens will automatically be claimed as part of the process, saving you an additional transaction fee as part of the process.
{% endhint %}

When unstaking you will automatically claim all the reward tokens as well (so there is no need to claim your rewards before you unstake).

![](/files/qzi3Mf2YZzav5EF7VPbB)

Once the transaction is complete you can click through the link to "Remove Liquidity". This takes you to Sushi to unwind your SLP position and get back vTOKENS and ETH.

![](/files/9DpsHqPfNz7DntCXORpc)

In this example we will be receiving back almost 2 bunny tokens and 0.031ETH.

![Preconfirmation screen to approve the transaction (signed only, no gas)](/files/QegoXAXVntajEOeW8OxA)

![Confirm the burning on the BUNNY/ETH and receiving tokens back - this costs gas.](/files/JGTVHlndHsedOCOSSm6a)

## Removing Liquidity from V1 Vaults <a href="#docs-internal-guid-227675f5-7fff-e5b1-c52b-9d3c69bb7b2e" id="docs-internal-guid-227675f5-7fff-e5b1-c52b-9d3c69bb7b2e"></a>

### Overview

With the release of NFTX Version 2 there is more benefit from moving your position from the old vaults on V1 to the new vaults on V2.

For an overview on the release of NFTX V2 you can read the blog, however in this tutorial we’re going to focus on how you can remove your liquidity from existing vaults on V1.

### Steps to remove your liquidity

Head over to the pool which you are providing liquidating. An easy way to do this is to find the Vault on the [gallery](https://gallery.nftx.org) and select the “Swap on Sushi” button.

Choose the “Liquidity” tab from that pool and then select “Remove” from the options. In this case we’re going to remove all of our liquidity from the pool and we will get back 0.0811434 ETH and 2.09975 TWERKY tokens.

You will first need to “Approve” the transaction and then “Confirm Withdrawl”.

![](https://lh5.googleusercontent.com/UtVb7DxosPHqg3xGk-U8l7D5JHWBn4wJ_91sONewx6uR9ZdDLxBBifxM87JxfoWwpt2F4oNL4qFuy692uNzXDXQMVR9omEGkceWlbC6fcnz132BMAoKMxbeWJwr0qfMbiem0h6PH)

{% hint style="info" %}
Note: there is no rush for you to remove your liquidity from the pool, especially while GAS prices are high.
{% endhint %}

Once the transaction has been processed you will receive a confirmation along with details about the final Tokens and ETH returned.

![](https://lh5.googleusercontent.com/vbZxAEl2uujYEo17DPN-3ByK4pU-PSfT8XZyJAQmauL8ejnb9gQJFzGrCs-7fYsJ1nQbFSI83N6ZN_cmrp_2RPuWDnXJfIebHnBIW8wRVnWl7LMloC2HTdO15YwPsRm7tW1Dz8uv)

You will now be able to view your tokens in Metamask, and if you go to the NFTX App you can see your tokens in the header and sidebar.

![](https://lh6.googleusercontent.com/Il6GjVs7IuJRVuG-H7Eyz2ArG9iq5XSmfjyYMzuJd9p20TTDTZbhDYOoliyrFm0UP3_9yYmIz9VF_OkMfNJTA2JXmI7fye7FrhUh1xMK02DgvtabH9rV7q3bUM9D5bnhB37s1buv)

With you tokens you can now Redeem your NFTs from the Vault which will then allow you to

### FAQs

#### Why has my claimable balance not increased?

Rewards are earned when the vault generates fees. APRs are calculated based on the last 7 days of vault fees.

#### Do I have to remove my Liquidity?

No. You can keep your liquidity on the current vaults in V1 for as long as you would like and continue to earn fees on the trades on SushiSwap.

You will not be able to stake your liquidity and earn any of the 5% minting and 5% targeted fees on the new vaults unless you become a liquidity provider on V2.

#### I still have fractions of a token left after withdrawing my liquidity, what can I do?

These fractions of tokens are often referred to as dust. You have three options.

1. Sell the fractions of the token you have on a DEX like SushiSwap.  For low value NFTs there is a good chance that the GAS cost of this transaction will exceed the value of the dust.
2. Buy more of the token to take you up to one full token and use it to redeem an NFT from the pool.
3. Hold onto the dust until NFTX move towards a buyout. We expect there will be one NFT stuck in each of the vaults due to the dust and reduction of the liquidity. There are two options for resolving this which the DAO will vote on in the next few months
   1. The DAO will sell the final NFT and provide the fractionalised value of the sale to the dust holders.
   2. The DAO will propose to buy back the dust to retrieve the final NFT and keep it in the treasury

#### When will the NFTX DAO remove their liquidity from the V1 Vaults?

The DAO will remove their Liquidity in thirds across three weeks starting from the public release of V2. This is to ensure that holders of the NFT Tokens have time to sell their position without any major slippage/price impact.

{% hint style="info" %}
Lower liquidity does not impact the redeeming of NFTs from the V1 Vaults. 1 Token is always worth 1 NFT from the corresponding vault.
{% endhint %}


# Vault Creation

NFTX v2 introduces a new vault creation interface that allows you to easily create a public vault for any NFT or a specific subset of IDs for an NFT.

[Watch the video tutorial for creating vaults on NFTX V2](https://www.youtube.com/watch?v=Yt2aU7hxMmc)

## Why create a vault?

Vault creation is at the heart of the NFTX protocol and allows users and content creators to begin [minting](/main/tutorials/minting) fungible ERC20 tokens for any NFT.

By creating NFT-backed ERC20 tokens, users can create liquid markets for otherwise illiquid NFTs whilst also earning fees and rewards from liquidity provision.

Protocol fees have been introduced in V2 of the NFTX.

## Vault Creation Step-by-Step

### Create NFTX Vault

Three fields are required to create an NFTX vault as shown below.

![](/files/-MdO9gfUDg6kwXtFf3-z)

**NFT Asset Address**

The NFT asset address is immutable and points to the contract from which this vault will accept mints. By default, all NFT IDs from this contract will be eligible for minting in the vault.

{% hint style="info" %}
Eligibility lists or ranges can be added once the vault has been created. This will allow you to target specific NFT IDs for groups of NFTs like "Female Punks", or create NFT ID ranges for specific projects like "720 Minutes" from Art Blocks, from within a single NFT contract address.
{% endhint %}

Some assets are already used in other vaults. For example, Art Blocks are used in multiple vaults and separated using eligibility ranges. To avoid adding a duplicate vault and splitting liquidity, review the matching vaults list before proceeding.

![](/files/-MdOB46FGxvhJe2IK9b2)

**Vault Name**

This will be the *name* of the ERC20 token that is minted from this vault.

**Vault Symbol**

This will be the *symbol* of the ERC20 token that is minted from this vault.

Both the Vault Name and Vault symbol will appear anywhere that this token appears, from CoinGecko and Etherscan through to Sushi and Uniswap.

{% hint style="info" %}
A strong name and symbol play a critical part in a vault's long-term success. Try to keep the name singular (PUNK, not PUNKS), six characters or less (to enable ticker links in Twitter), and use a real word where possible (BUNNY, not GENBIT).
{% endhint %}

### Vault Created

![](/files/-MdOCAH12z-1ZdT2sLW8)

Once your create vault transaction has been confirmed onchain you will be notified and asked to proceed to managing your vault.

Your vault will not be visible in the NFTX app until it has been minted to and published. Click "Manage Vault" to complete the process.

### Manage Vault

Vault management allows vault creators to modify a number of important settings as well as publishing the vault so that it becomes visible on the NFTX app.

{% hint style="warning" %}
Published vaults cannot be edited by the creator, only the DAO can make updates to published vaults. Carefully review the vault's settings before publishing, including setting the Fees and Eligibility screens.
{% endhint %}

![](/files/-MdOCO-9cbmhlREYidbh)

#### **Enable Vault Features**

**Enable Minting —** The most important part of creating a vault is allowing users to mint their NFTs in. If you wanted to use the vault as a way to airdrop tokens for users to redeem NFTs from the vault you might disable the mint feature.

**Enable Random Redeems —** Allow users to randomly retrieve an NFT from your vault.

**Enable Target Redeems** — Users will be able to choose the NFTs they are redeem from the vault for an additional fee which you can set within the Fees section.

#### Fees

![](/files/-MdOE2DCGjhcrszywfeG)

Fees can now be set on the individual vaults which will then be distributed to the liqudity providers staking their LP. By default all new vaults are set with 10% Mint Fee (meaning you receive 0.95 tokens for each NFT minted), 4% Random Redeem Fee (so 1.06 tokens can redeem 1 random NFT from the vault), and a 6% Targeted Redeem Fee (1.06 tokens are needed to choose the NFT you want from the vault).

~~When you first create the vault, and ***before*** you finalise the vault, you can set the mint fees to 0% to encourage the initial seeding of the vault~~. When seeding the vault with liquidity and inventory staking you bypass the mint fees, so you no longer need to reduce the fees to get the vault seeded.

{% hint style="info" %}
Don't forget that you can use Zaps to bypass the 5% mint fee by providing ETH liquidity for the vault and staking it to earn yourself fees. Find out more on [Bypassing Mint Fee's with Zaps](/main/tutorials/minting#bypass-mint-fees-with-zaps).
{% endhint %}

#### **Eligibilities**

![](/files/-MdOFTQMpIaVJi-8D7Dm)

A vault's eligibility list is an allow list or range of NFT IDs that can be minted to this vault.

**List Module**

![](/files/-MdOFqbcqSuXlHsB_6F4)

Use this setting to specific individual IDs to add to the eligibility list.

**Eligibility Range**

![](/files/-MdOFv3LoJMgO4fBhsrJ)

For blocks of eligible IDs, use this setting to specify the "from" and "to" (inclusive) IDs that will be added to the eligibility list. **These work well for projects like Art Blocks Curtated which are all minted from the same contract but have distinct ranges for each project.**

### Publishing your Vault

Before your vault will be visible on the app you will need to mint at least one eligible NFT.

![](/files/-MdOHV28-BuzaihOiLff)

Once you've added one or more NFTs to your new vault you will have the option to publish your vault. Remember, once the vault has been published the ownership is passed to the DAO and you will no longer be able to update the Fees or Eligibilities.

![](/files/-MdONdkyk_-oqA8AE4cc)

![Last chance. You are asked to confirm your setting for Fees](/files/-MdONlaXpuD0QfeJJQP8)

Once confirmed you will be redirected to the vault detail page. On this page it will provide you with an overview of the vault details, including Vault ID, URL, Token Address, current Holdings, and Lifetime Fees.

![](/files/-MdOOAL6HkKVN3CogtOv)

### Verifying your vault & adding a vault icon

Once you have created and published your vault you will also need to provide an icon so that the vault can go through the final verification process.

To [add the icon and request verification complete this form](https://notionforms.io/forms/vault-verification), but make sure you have all the information required. Let's take a look at the requirements.

1. **Vault Name:** The name of your vault (not the token name).
2. **Vault ID:** You can find the Vault ID on the Info tab on your vault page in the right hand sidebar (or at the bottom if your are on mobile).
3. **Discord Username** *(i.e. javery#3313)*: You can get this by clicking on your discord user on the bottom left of the discord app. We need this so we can reach out to confirm the details are correct.

   ![](https://downloads.intercomcdn.com/i/o/437512436/12c9066f38f468ba71454c91/Screenshot+2021-12-21+at+12.16.04.png)
4. **Vault Icon**: upload a 512x512px transparent PNG icon that you want associated with the vault. See an example of the CryptoPunk vault icon below.

   ![PUNK](https://nftx-8e1220506660.intercom-attachments-1.com/i/o/437571507/89010aeffa2b0579949f63fa/256x256.png)
5. **Signed Message**: Visit <https://app.mycrypto.com/sign-message> and create a signed message with the wallet that you used to create the vault. This allows the NFTX DAO to confirm that the request is originating from the owner of vault.

   \
   When adding your signed message please **ensure that you are signing the message with the wallet that you used to create the vault**.

Once we recieve the request someone from the team will verifity the signed message, update the vault icon, and verify the vault.

Please note that the vault is usable even though it has not been verified.

[Verify Vault Now](https://notionforms.io/forms/vault-verification)

## FAQ

### I am being warned about the vault name or symbol, what does this mean?

Naming conventions provide structure for NFTX vaults that makes them instantly recognisable across platforms and help improve the network effects for all participants in the NFTX ecosystem.

**Naming conventions**

| Vault Name                 | Vault Symbol                                     |
| -------------------------- | ------------------------------------------------ |
| Alphanumeric only          | Less than 7 characters                           |
| Capitalized (i.e. Meebits) | Singular (i.e. PUNK for CryptoPunks floor vault) |
|                            | Uppercase                                        |
|                            | Real words where possible                        |

The tight recommendations on Vault Symbol are in place to conform to Twitter's cashtag standard.

### Why isn't my vault isn't showing in the NFTX app?

The most common reason for this is that your vault does not yet have holdings or has not been published. To add holdings, visit the vault management page and click "Add Holdings".


# Eligibility Modules

### NFTXEligibilityManager.sol

Handles our mappings and information for our `NFTXEligibility` contracts.

An eligibility contract allows NFTX vaults to apply one-to-one eligibility checks against tokens that are set to be stored. It offers the ability to extend upon a common eligibility contract interface to have access to calculate a boolean output for if the tokenId(s) is/are eligible for the vault.

This interface also gives us access to a number of hooks to allow additional processing to be called, required assertions to be made, or events to be triggered.

* `beforeMintHook(uint256[] calldata tokenIds)`
* `afterMintHook(uint256[] calldata tokenIds)`
* `beforeRedeemHook(uint256[] calldata tokenIds)`
* `afterRedeemHook(uint256[] calldata tokenIds)`

An eligibility module can only be deployed by the contract owner of the Eligibility Manager contract, though at a vault level it can be applied by any priviliged user. For more information on what defines a priviliged user, please refer to the `onlyPrivileged` modifier in the `NFTXVaultUpgradeable` contract.

If no eligibility module is set against a vault, then it will always assume that the NFT is eligible, resulting in the NFT transfer always being allowed.

Please note that the eligibility modules will only affect NFTs that are sent in the correct, expected journey; by calling `receiveNFTs` on the vault.

*Our eligibility contracts are stored under `./eligibility`.*

### Internal Structures

#### EligibilityModule

```solidity
struct EligibilityModule {
  address implementation;
  address targetAsset;
  string name;
}
```

#### modules

```solidity
struct NFTXEligibilityManager.EligibilityModule[] modules
```

Storage of all eligibility modules

### Events Emitted

#### ModuleAdded

```solidity
event ModuleAdded(address implementation, address targetAsset, string name, bool finalizedOnDeploy)
```

Emitted when a module has been added

| Name              | Type    | Description                                  |
| ----------------- | ------- | -------------------------------------------- |
| implementation    | address | The address of the eligibility module        |
| targetAsset       | address | The asset contract being interrogated        |
| name              | string  | The name given to the eligibility module     |
| finalizedOnDeploy | bool    | If the eligibility module has been finalized |

#### ModuleUpdated

```solidity
event ModuleUpdated(address implementation, string name, bool finalizedOnDeploy)
```

Emitted when a module has been updated

| Name              | Type    | Description                                  |
| ----------------- | ------- | -------------------------------------------- |
| implementation    | address | The address of the eligibility module        |
| name              | string  | The name given to the eligibility module     |
| finalizedOnDeploy | bool    | If the eligibility module has been finalized |

### Public Methods

#### \_\_NFTXEligibilityManager\_init

```solidity
function __NFTXEligibilityManager_init() public
```

Initialiser for the eligibility manager.

*Allows for upgradable deployment*

#### addModule

```solidity
function addModule(address implementation) external
```

Adds an address that supports `INFTXEligibility` to our array of `EligibilityModule`.

| Name           | Type    | Description                                                       |
| -------------- | ------- | ----------------------------------------------------------------- |
| implementation | address | The address of an implementation that supports `INFTXEligibility` |

#### updateModule

```solidity
function updateModule(uint256 moduleIndex, address implementation) external
```

Allows an existing implementation to be updated.

| Name           | Type    | Description                                                       |
| -------------- | ------- | ----------------------------------------------------------------- |
| moduleIndex    | uint256 | The array index of the implementation to be updated               |
| implementation | address | The address of an implementation that supports `INFTXEligibility` |

#### deployEligibility

```solidity
function deployEligibility(uint256 moduleIndex, bytes configData) external virtual returns (address)
```

Creates a cloned version of the specified implementation, using the provided `configData`. This allows multiple instances of the same eligibility module to be deployed, with varied constructor data.

*Our `configData` is an encoded abi that will be required to match against the expected, individual eligility module referenced. The specific encoding will be found in the respective `__NFTXEligibility_init_bytes` function.*

| Name        | Type    | Description                                          |
| ----------- | ------- | ---------------------------------------------------- |
| moduleIndex | uint256 | The array index of the implementation to be updated  |
| configData  | bytes   | Encoded abi bytes that represents keyword arguements |

#### allModules

```solidity
function allModules() external view returns (struct NFTXEligibilityManager.EligibilityModule[])
```

Returns our array of modules.

| Name | Type                                               | Description          |
| ---- | -------------------------------------------------- | -------------------- |
| \[0] | struct NFTXEligibilityManager.EligibilityModule\[] | EligibilityModule\[] |

#### allModuleNames

```solidity
function allModuleNames() external view returns (string[])
```

Returns a list of all module names from our stored array.

| Name | Type      | Description           |
| ---- | --------- | --------------------- |
| \[0] | string\[] | Array of module names |


# Example Module

### NFTXEligibility

This is a contract is intended to be inherited and overridden when creating an eligibility module. The functions outlined will be called throughout the NFTX vault journey and this abstract contract provides a number of helper functions.

<https://github.com/NFTX-project/nftx-protocol-v2/blob/master/contracts/solidity/eligibility/NFTXEligibility.sol>

### Public Methods

The following are a collection of understood functions that should be defined in your implementation.

#### name

```solidity
function name() public pure virtual returns (string)
```

Defines the constant name of the eligibility module.

*Try to keep the naming convention of the eligibility module short, but desciptive as this will be displayed to end users looking to implement it.*

| Name | Type   | Description                        |
| ---- | ------ | ---------------------------------- |
| \[0] | string | The name of the eligibility module |

#### finalized

```solidity
function finalized() public view virtual returns (bool)
```

If the eligibility has been finalized then it can no longer be updated, meaning the processing logic can no longer be modified and it is safe to use.

| Name | Type | Description                            |
| ---- | ---- | -------------------------------------- |
| \[0] | bool | If the eligibility module is finalized |

#### targetAsset

```solidity
function targetAsset() public pure virtual returns (address)
```

Allows the module to define an asset that is targetted. This can be subsequently used for internal calls to reference the token address being queried.

*This is not a required field, and can just return `address(0)` if no subsequent use is needed.*

| Name | Type    | Description                                             |
| ---- | ------- | ------------------------------------------------------- |
| \[0] | address | The address of the asset being referenced by the module |

#### \_\_NFTXEligibility\_init\_bytes

```solidity
function __NFTXEligibility_init_bytes(bytes initData) public virtual
```

Called when initialising the eligibility module, allowing configuring data to be passed and initial module contract setup to be performed.

*If no further configuration is required, then we can just omit providing the bytes with an attribute name and ignore any calculation.*

| Name     | Type  | Description                                                                                                                                     |
| -------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| initData | bytes | This allows for abi encoded bytes to be decoded when initialised and allow the module implementation to vary based on the vault's requirements. |

#### checkIsEligible

```solidity
function checkIsEligible(uint256 tokenId) external view virtual returns (bool)
```

Checks if a tokenId is eligible to be received by the vault.

| Name    | Type    | Description                           |
| ------- | ------- | ------------------------------------- |
| tokenId | uint256 | A tokenId to check the eligibility of |

| Name | Type | Description                                                                                                 |
| ---- | ---- | ----------------------------------------------------------------------------------------------------------- |
| \[0] | bool | True if the tokenId is eligible to be received by the module's logic for the vault, and False if it is not. |

#### checkEligible

```solidity
function checkEligible(uint256[] tokenIds) external view virtual returns (bool[])
```

Checks if an array of tokenIds are eligible to be received by the vault.

| Name     | Type       | Description                                      |
| -------- | ---------- | ------------------------------------------------ |
| tokenIds | uint256\[] | An array of tokenIds to check the eligibility of |

| Name | Type    | Description                                                                                                                                                                               |
| ---- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| \[0] | bool\[] | True if the tokenId is eligible to be received by the module's logic for the vault, and False if it is not. The array of booleans will follow the same order as the tokenIds were passed. |

#### checkAllEligible

```solidity
function checkAllEligible(uint256[] tokenIds) external view virtual returns (bool)
```

Checks if all tokenIds in an array are eligible to be received by the vault.

| Name     | Type       | Description                                      |
| -------- | ---------- | ------------------------------------------------ |
| tokenIds | uint256\[] | An array of tokenIds to check the eligibility of |

| Name | Type | Description                                                                                                       |
| ---- | ---- | ----------------------------------------------------------------------------------------------------------------- |
| \[0] | bool | True if *all* tokenIds are eligible to be received by the module's logic for the vault, and False if any are not. |

#### checkAllIneligible

```solidity
function checkAllIneligible(uint256[] tokenIds) external view virtual returns (bool)
```

Checks if all provided NFTs are NOT eligible. This is needed for mint requesting where all NFTs provided must be ineligible.

| Name     | Type       | Description                                      |
| -------- | ---------- | ------------------------------------------------ |
| tokenIds | uint256\[] | An array of tokenIds to check the eligibility of |

| Name | Type | Description                                                                                                    |
| ---- | ---- | -------------------------------------------------------------------------------------------------------------- |
| \[0] | bool | True if *none* tokenIds are eligible to be received by the module's logic for the vault, and False if any are. |

#### beforeMintHook

```solidity
function beforeMintHook(uint256[] tokenIds) external virtual
```

Called before tokenIds are minted into the NFTX vault.

*This function is not currently implemented in the NFTX Vault.*

| Name     | Type       | Description          |
| -------- | ---------- | -------------------- |
| tokenIds | uint256\[] | An array of tokenIds |

#### afterMintHook

```solidity
function afterMintHook(uint256[] tokenIds) external virtual
```

Called after tokenIds have been minted into the NFTX vault.

*This function is not currently implemented in the NFTX Vault.*

| Name     | Type       | Description          |
| -------- | ---------- | -------------------- |
| tokenIds | uint256\[] | An array of tokenIds |

#### beforeRedeemHook

```solidity
function beforeRedeemHook(uint256[] tokenIds) external virtual
```

Called before tokenIds are redeemed from the NFTX vault.

*This function is not currently implemented in the NFTX Vault.*

| Name     | Type       | Description          |
| -------- | ---------- | -------------------- |
| tokenIds | uint256\[] | An array of tokenIds |

#### afterRedeemHook

```solidity
function afterRedeemHook(uint256[] tokenIds) external virtual
```

Called after tokenIds are redeemed from the NFTX vault.

| Name     | Type       | Description          |
| -------- | ---------- | -------------------- |
| tokenIds | uint256\[] | An array of tokenIds |

#### \_checkIfEligible

```solidity
function _checkIfEligible(uint256 _tokenId) internal view virtual returns (bool)
```

Contains logic to determine if a tokenId is eligible to be handled by the NFTX vault.

*This is the minimum required logic to be processed in order to create a functioning eligibility module.*

| Name      | Type    | Description                           |
| --------- | ------- | ------------------------------------- |
| \_tokenId | uint256 | A tokenId to check the eligibility of |

| Name | Type | Description                                                |
| ---- | ---- | ---------------------------------------------------------- |
| \[0] | bool | A boolean representation of the eligibility of the tokenId |


# Merkle Eligibility

This page explains how to use our Merkle Eligibility module.

The Merkle eligibility module was set up to allow a predefined array of criteria to be defined that is then validated against in a precursory check, before the token can be deemed eligible.

This module was primarily developed to allow for ENS domains to be deemed eligible, or ineligible, though there are more use-cases available. For the purpose of this document I will be applying the logic to that of the ENS flow implemented.

The reason that a merkle approach is required for ENS is that the name of the token cannot be extracted from the token itself. This would mean that for handling a collection such as the #10KClub (in which only numeric domains from 0000 to 9999 are included) we would not be able to apply a simple conditional statement to check the range. We also would not be able to simply define a list of immutable token IDs inside the vault as the deployment gas costs would be extremely high.

To combat this we instead only require the application of a merkle root (`bytes32`) onto the contract and then require a precursory check that passes a merkle proof alongside the token ID to gauge eligibility and apply it to an internally eligibility mapping.

If you'd like to read more into the application of merkle trees on the blockchain, I'd recommend reading [Using Merkle Trees for NFT Whitelists](https://medium.com/@ItsCuzzo/using-merkle-trees-for-nft-whitelists-523b58ada3f9) by @ItsCuzzo.

### Encoding ENS domains

When working with ENS domains, we need to encode and decode them in a specific way to ensure they stay the same across the frontend website and on-chain.

In my document examples you will see regular reference to a helper function called `getTokenId` that is subsequently encoded with `keccak256`. This creates two vital steps for ENS domains. The `getTokenId` returns the `tokenId` that an ENS name has. You can test this by encoding a name and checking the listing on Opensea.

```
function getTokenId(domain) {
  return ethers.BigNumber.from(ethers.utils.id(domain.toLowerCase())).toString();
}
```

*Note: This method excludes the `.eth` suffix.*

When we then encode the return value with `keccak256` we get the ENS `tokenHash`. Both the `tokenId` and `tokenHash`, if calculated correctly, will correspond to the stored data on the [ENS Subgraph](https://thegraph.com/hosted-service/subgraph/ensdomains/ens).

### Generating your Merkle Tree

Generating our Merkle Tree uses 2 Node JS library:

* merkletreejs
* keccak256

The following code flow shows how to generate an ENS-compliant merkle tree, generate the root and generate a subsequent proof for later eligibility checks. Alternatively, an [online tool](https://lab.miguelmota.com/merkletreejs/example/) can be used for testing. Note, that `sortPairs` must be set to `True`.

We want to store our leaves in `bytes32` format, which is outputted from the `keccak256` encryption for consistent and gas-efficient storage.

```
  // Set up our Merkle tree leaves
  const leaves = [
    keccak256(getTokenId('a')),
    keccak256(getTokenId('b')),
    keccak256(getTokenId('c')),
  ];

  // Create a merkle tree containing the leaves defined above.
  const tree = new MerkleTree(leaves, keccak256, {sortPairs: true});
  
  // Generate our tree's merkle root
  const merkleRoot = tree.getHexRoot();
  
  // Generate a proof for b.eth
  const tokenHash = keccak256(getTokenId('b'));

  // Calculate our tree's proof from our tokenHash
  const proof = tree.getHexProof(tokenHash);
```

Once we have our proof for the `tokenHash`, we can call our precursory processing function. In most eligibility modules we can just directly call eligibility, but in order for our merkle tree approach to work, this function must be called at least once per token to ensure it's added to our `validTokenHashes` mapping.

```
/**
 * @notice This will run a precursory check by encoding the token ID, creating the
 * token hash, and then checking this against our merkle tree.
 *
 * @param tokenId The ENS token ID being validated
 * @param merkleProof Merkle proof to validate against the tokenId
 *
 * @return bool If the token is valid
 */

function processToken(uint tokenId, bytes32[] calldata merkleProof) public returns (bool) {
    // Get the hashed equivalent of our tokenId
    bytes32 tokenHash = keccak256(bytes(Strings.toString(tokenId)));

    // Determine if our domain is eligible by traversing our merkle tree
    bool isValid = MerkleProof.verify(merkleProof, merkleRoot, tokenHash);

    // Mark our hash as processed
    validTokenHashes[tokenHash] = isValid;
    _processedTokenHashes[tokenHash] = true;

    // Let our stalkers know that we are making the request
    emit PrecursoryCheckStarted(tokenId, tokenHash);
    emit PrecursoryCheckComplete(tokenId, tokenHash, isValid);

    return isValid;
}
```

Once our precursory check has been run for the token and we have deemed it valid and eligible, we are ready to mint it to the vault. Internally, the vault will just check that the encoded `tokenId` (creating the `tokenHash`) has been mapped as valid.

```
/**
 * @notice Checks if a supplied token is eligible, which is defined by our merkle
 * tree root assigned at initialisation.
 * 
 * @dev This check requires the token to have already been passed to `processToken`.
 *
 * @return bool If the tokenId is eligible
 */

function _checkIfEligible(uint tokenId) internal view override virtual returns (bool) {
    return validTokenHashes[keccak256(bytes(Strings.toString(tokenId)))];
}
```

To ensure that the `tokenId` is correctly mapped to the `tokenHash` we must convert our `tokenId` to a String and then into bytes before calling `keccak256`. Failure to do this results in an incorrect `tokenHash` being generated.

### Precursory Flow

![The happy path for validating an ENS domain against the module ](/files/M5m9UVRtUzk9SFyzHn1I)


# Fee Distribution

Contracts and wallets can be excluded from fees through the VaultFactoryUpgradable contract. The owner of the contract can add an address, along with a boolean representation of their exclusion from paying fees, to the `setFeeExclusion` function. This will emit a `FeeExclusion` event and update an internal mapping. This can then be queried by other contracts by performing a call along the lines of `nftxVaultFactory.excludedFromFees(msg.sender)`.

Fees are charged and distributed when an NFT is minted, redeemed or swapped in an NFTX vault. If a user is excluded from fees in this manner then no fees will be send to the `feeDistributor` and no tokens will be transferred via the NFTX Vault contract.

This is used for NFTX zaps to allow for additional transactions to take place before, or instead of, incurring fees.

If fees are not excluded then:

* The amount of fee owed is determined by checking the vault fees that are assigned by it’s creator
* The fee is then transferred to the fee distributor contract attached to the vault
  * This distributor is required during initialisation and its implementation is validated.
  * At this point the fee amount is also sense checked
* The distributor contract then calls the `distribute` function, along with the corresponding vaultId that is calling it
* Distribution logic will vary depending on the contract that is implemented. The different distribution contracts should have ample documentation and commenting to understand.

![](/files/6LOUdBIXNV0XtiRTz853)

### Internal Attributes

#### distributionPaused

```solidity
bool distributionPaused
```

Flags if distribution is currently paused

#### nftxVaultFactory

```solidity
address nftxVaultFactory
```

Contract address of the NFTX Vault Factory contract.

#### lpStaking

```solidity
address lpStaking
```

Contract address of the LP Staking contract.

#### treasury

```solidity
address treasury
```

Contract address of the NFTX Treasury contract.

#### allocTotal

```solidity
uint256 allocTotal
```

Total allocation points per vault.

#### feeReceivers

```solidity
struct INFTXSimpleFeeDistributor.FeeReceiver[] feeReceivers
```

Array storage of fee receivers, accessed by index.

#### inventoryStaking

```solidity
address inventoryStaking
```

Contract address of the NFTX Inventory Staking contract.

### Events Emitted

#### UpdateTreasuryAddress

```solidity
event UpdateTreasuryAddress(address newTreasury)
```

Emitted when the treasury address is updated.

| Name        | Type    | Description                               |
| ----------- | ------- | ----------------------------------------- |
| newTreasury | address | The new address for the treasury contract |

#### UpdateLPStakingAddress

```solidity
event UpdateLPStakingAddress(address newLPStaking)
```

Emitted when the LP Staking address is updated.

| Name         | Type    | Description                                 |
| ------------ | ------- | ------------------------------------------- |
| newLPStaking | address | The new address for the LP Staking contract |

#### UpdateInventoryStakingAddress

```solidity
event UpdateInventoryStakingAddress(address newInventoryStaking)
```

Emitted when the Inventory Staking address is updated.

| Name                | Type    | Description                                        |
| ------------------- | ------- | -------------------------------------------------- |
| newInventoryStaking | address | The new address for the Inventory Staking contract |

#### UpdateNFTXVaultFactory

```solidity
event UpdateNFTXVaultFactory(address factory)
```

Emitted when the NFTX Vault Factory address is updated.

| Name    | Type    | Description                                         |
| ------- | ------- | --------------------------------------------------- |
| factory | address | The new address for the NFTX Vault Factory contract |

#### PauseDistribution

```solidity
event PauseDistribution(bool paused)
```

Emitted when this contract is paused or unpaused.

| Name   | Type | Description                                                                     |
| ------ | ---- | ------------------------------------------------------------------------------- |
| paused | bool | Boolean value of if distribution has been paused (`true`) or unpaused (`false`) |

#### AddFeeReceiver

```solidity
event AddFeeReceiver(address receiver, uint256 allocPoint)
```

Emitted when a contract or non-contract receiver is added as a `FeeReceiver`.

| Name       | Type    | Description                                              |
| ---------- | ------- | -------------------------------------------------------- |
| receiver   | address | The address of the new fee recipient                     |
| allocPoint | uint256 | The number of allocation points assigned to the receiver |

#### UpdateFeeReceiverAlloc

```solidity
event UpdateFeeReceiverAlloc(address receiver, uint256 allocPoint)
```

Emitted when a receiver's allocation is updated.

| Name       | Type    | Description                                                  |
| ---------- | ------- | ------------------------------------------------------------ |
| receiver   | address | The address of the updated fee recipient                     |
| allocPoint | uint256 | The new number of allocation points assigned to the receiver |

#### UpdateFeeReceiverAddress

```solidity
event UpdateFeeReceiverAddress(address oldReceiver, address newReceiver)
```

Emitted when a receiver's address is updated.

| Name        | Type    | Description                     |
| ----------- | ------- | ------------------------------- |
| oldReceiver | address | The old address of the receiver |
| newReceiver | address | The new address of the receiver |

#### RemoveFeeReceiver

```solidity
event RemoveFeeReceiver(address receiver)
```

Emitted when a receiver's address is removed.

| Name     | Type    | Description                                  |
| -------- | ------- | -------------------------------------------- |
| receiver | address | The address of the receiver that was removed |

### **Public Methods**

#### **SimpleFeeDistributor\_\_init**

```solidity
function __SimpleFeeDistributor__init__(address _lpStaking, address _treasury) public
```

Initialiser for the fee distributor, setting relevant staking and treasury addresses.

*Allows for upgradable deployment*

| Name        | Type    | Description                        |
| ----------- | ------- | ---------------------------------- |
| \_lpStaking | address | Address of our LP Staking contract |
| \_treasury  | address | Address of our Treasury contract   |

#### distribute

```solidity
function distribute(uint256 vaultId) external virtual
```

Distributes fees to receivers. All receivers will be iterated over to distribute their relative allocation of the total number of tokens.

The total balance of the token on the contract will be distributed.

Any dust balance remaining on the contract is transferred to the treasury.

\_If distribution is paused or we have no receivers added (defined by allocTotal) then the entire token balance will be sent to the treasury.

When our receivers are set up by the contract owner they are assigned an `allocPoint` value that indicates the relative size of the allocation they will be eligible to receive. This is explained in greater depth on the `addReceiver` method.

The vault ID will determine the ERC20 token that will be transferred.\_

| Name    | Type    | Description                                       |
| ------- | ------- | ------------------------------------------------- |
| vaultId | uint256 | The vault ID that is to have its fees distributed |

#### addReceiver

```solidity
function addReceiver(uint256 _allocPoint, address _receiver, bool _isContract) external virtual
```

Adds a receiver to the fee distributor. If a contract receiver is added, then they must a call to `receiveRewards` as outlined in the `_sendForReceiver` function. The receiver is given an `allocPoint` value that defines their relative stake of the rewards.

\_For the point allocation, if receiver A has 1 `allocPoint` and receiver B has 3 `allocPoint` then when rewards are distributed they will each receive a percentage based on the relative value.

For example, in this case receiver B would receive 75% of the rewards and receiver A would receive the remaining 25%.\_

| Name         | Type    | Description                                                                   |
| ------------ | ------- | ----------------------------------------------------------------------------- |
| \_allocPoint | uint256 | The point allocation applied to the receiver                                  |
| \_receiver   | address | The address of the receiver                                                   |
| \_isContract | bool    | Flag to determine if the receiver is a contract, rather than a wallet address |

#### initializeVaultReceivers

```solidity
function initializeVaultReceivers(uint256 _vaultId) external
```

Allows the NFTX Vault Factory contract caller to add a pool vault for LP Staking and, if an inventory staking address is set, then deploys an xToken for the vault.

| Name      | Type    | Description       |
| --------- | ------- | ----------------- |
| \_vaultId | uint256 | The NFTX vault ID |

#### changeReceiverAlloc

```solidity
function changeReceiverAlloc(uint256 _receiverIdx, uint256 _allocPoint) public virtual
```

Allows receiver allocation to be updated.

*Safe math is not implemented, so calculations must not exceed uint256 boundaries for `allocTotal`.*

| Name          | Type    | Description                                                       |
| ------------- | ------- | ----------------------------------------------------------------- |
| \_receiverIdx | uint256 | The index value of the feeReceiver in our internally stored array |
| \_allocPoint  | uint256 | The new allocation for the receiver                               |

#### changeReceiverAddress

```solidity
function changeReceiverAddress(uint256 _receiverIdx, address _address, bool _isContract) public virtual
```

Allows receiver address and `isContract` state to be updated.

| Name          | Type    | Description                                                       |
| ------------- | ------- | ----------------------------------------------------------------- |
| \_receiverIdx | uint256 | The index value of the feeReceiver in our internally stored array |
| \_address     | address | The new address for the receiver                                  |
| \_isContract  | bool    | The new `isContract` boolean flag for the receiver                |

#### removeReceiver

```solidity
function removeReceiver(uint256 _receiverIdx) external virtual
```

Removes the receiver from our internal array so that they will no longer be included in our fee distribution.

*This removal changes the index order of the `feeReceivers` array by moving the last element to that of the removed value. External sources will need to reflect this change for future updates before making subsequent calls.*

| Name          | Type    | Description                                                       |
| ------------- | ------- | ----------------------------------------------------------------- |
| \_receiverIdx | uint256 | The index value of the feeReceiver in our internally stored array |

#### setTreasuryAddress

```solidity
function setTreasuryAddress(address _treasury) public
```

Allows our treasury address to be updated.

| Name       | Type    | Description                          |
| ---------- | ------- | ------------------------------------ |
| \_treasury | address | Address of our new Treasury contract |

#### setLPStakingAddress

```solidity
function setLPStakingAddress(address _lpStaking) public
```

Allows our LP Staking address to be updated.

| Name        | Type    | Description                            |
| ----------- | ------- | -------------------------------------- |
| \_lpStaking | address | Address of our new LP Staking contract |

#### setInventoryStakingAddress

```solidity
function setInventoryStakingAddress(address _inventoryStaking) public
```

Allows our Inventory Staking address to be updated.

| Name               | Type    | Description                                   |
| ------------------ | ------- | --------------------------------------------- |
| \_inventoryStaking | address | Address of our new Inventory Staking contract |

#### setNFTXVaultFactory

```solidity
function setNFTXVaultFactory(address _factory) external
```

Allows our NFTX Vault Factory address to be updated.

| Name      | Type    | Description                                    |
| --------- | ------- | ---------------------------------------------- |
| \_factory | address | Address of our new NFTX Vault Factory contract |

#### pauseFeeDistribution

```solidity
function pauseFeeDistribution(bool _pause) external
```

Allows our fee distribution system to be paused or unpaused.

| Name    | Type | Description                                                      |
| ------- | ---- | ---------------------------------------------------------------- |
| \_pause | bool | A boolean representation of if the distribution should be paused |

#### rescueTokens

```solidity
function rescueTokens(address _address) external
```

Allows tokens to be rescued from the contract to the sender. This will transfer the entire balance of the matching ERC20 token.

| Name      | Type    | Description                            |
| --------- | ------- | -------------------------------------- |
| \_address | address | The address of the token to be rescued |

#### \_addReceiver

```solidity
function _addReceiver(uint256 _allocPoint, address _receiver, bool _isContract) internal virtual
```

Adds a `FeeReceiver` to our internally stored fee receivers array.

*The new receiver will always be added to the end of the array.*

| Name         | Type    | Description                                                                   |
| ------------ | ------- | ----------------------------------------------------------------------------- |
| \_allocPoint | uint256 | The new allocation for the receiver                                           |
| \_receiver   | address | The address of the receiver                                                   |
| \_isContract | bool    | Flag to determine if the receiver is a contract, rather than a wallet address |

#### \_sendForReceiver

```solidity
function _sendForReceiver(struct INFTXSimpleFeeDistributor.FeeReceiver _receiver, uint256 _vaultId, address _vault, uint256 amountToSend) internal virtual returns (bool)
```

Sends the specified amount of tokens to a receiver from an NFTX vault.

*If the receiver is a contract then they must implement `receiveRewards` to handle the fee distribution.*

| Name         | Type                                         | Description                                                 |
| ------------ | -------------------------------------------- | ----------------------------------------------------------- |
| \_receiver   | struct INFTXSimpleFeeDistributor.FeeReceiver | Address of the receiver contract or wallet                  |
| \_vaultId    | uint256                                      | The ID of the NFTX vault, provided to the external contract |
| \_vault      | address                                      | The address of the NFTX vault                               |
| amountToSend | uint256                                      | The amount of tokens distributed to the receiver            |

| Name | Type | Description                                                                                    |
| ---- | ---- | ---------------------------------------------------------------------------------------------- |
| \[0] | bool | bool If the tokens were successfully transferred and there are no more tokens left to transfer |


# Bug Bounty

The NFTX Bounty program rewards users that discover and properly disclose found bugs with predefined bounties. We encourage anyone to help strengthen the protocol by actively searching for bugs in NFTX contracts.

The NFTX bounty program is derived from the Ethereum Bounty Program, an industry standard when it comes to rightfully rewarding bug bounty hunters.

Please send vulnerability submissions to <bounty@nftx.org>

{% hint style="info" %}
The NFTX V2 contracts have been through the Code Area bug bounty programme on two occassions. A number of vulnarabilities were flagged that were either fixed or acknowledge which you can review in these two reports

* <https://code423n4.com/reports/2021-05-nftx/>
* <https://code4rena.com/reports/2021-12-nftx/>

Please check these prior to submitting your bug bounties as anything already identified here is unlikely to qualify for this Bug Bounty programme outlined below.
{% endhint %}

## Rules and Rewards

Please have a look at the bullets below before starting your hunt!

* Issues that have already been submitted by another user or are already known to the NFTX team are not eligible for bounty rewards (this includes the [Code Area report](https://code423n4.com/reports/2021-05-nftx/)).
* Public disclosure of a vulnerability makes it ineligible for a bounty.
* You can start or fork a private chain for bug hunting. Please respect the NFTX main and test networks and refrain from attacking them.
* All NFTX members paid by the DAO are not eligible for rewards.
* NFTX websites or organizational infrastructure in general, are NOT part of the bounty program.
* NFTX bounty program considers a number of variables in determining rewards. Determinations of eligibility, score and all terms related to an award are at the sole and final discretion of the NFTX DAO.

The value of rewards paid out will vary depending on Severity. The severity is calculated according to the [OWASP](https://www.owasp.org/index.php/OWASP_Risk_Rating_Methodology) risk rating model based on Impact and Likelihood :

![Severity](https://lh3.googleusercontent.com/B-RaTD0aLBUht3y-NEPSja8vhSyncCHm28gWdE2uIjEfYjL4ceG9kEbcSR2n5IBAExH8uj57jamcoI6eY_ewLfRGBaIdZQD9dYGoQ56rDFA1WGYFEC9JIKRWHjGpog9yYL6OvvVt)

Reward sizes are guided by the rules below, but are in the end, determined at the sole discretion of the NFTX DAO.

* Critical: up to 25 000 USD
* High: up to 15 000 USD
* Medium: up to 10 000 USD
* Low: up to 2 000 USD
* Note: up to 500 USD

Bounties may be paid out in USD, ETH or NFTX tokens.

In addition to Severity, other variables are also considered when the NFTX DAO decides the score, including (but not limited to):

* Quality of description. Higher rewards are paid for clear, well-written submissions.
* Quality of reproducibility. Please include test code, scripts and detailed instructions. The easier it is for us to reproduce and verify the vulnerability, the higher the reward.
* Quality of fix, if included. Higher rewards are paid for submissions with clear descriptions of how to fix the issue.

**Important Legal Information**

The bug bounty program is an experimental and discretionary rewards program for our active NFTX community to encourage and reward those who are helping to improve the platform. It is not a competition. You should know that we can cancel the program at any time, and awards are at the sole discretion of the NFTX DAO. You are responsible for all taxes. All awards are subject to applicable law. Finally, your testing must not violate any law or compromise any data that is not yours.

### Bounty Scope

The above mentioned bug bounty rules and rewards are applicable to all smart contracts that are actively being used and/or promoted by NFTX.

When in doubt about whether the bug applies to the bounty program, please contact the DAO by sending an email to <bounty@nftx.org>.


# SECBIT Audit

Audit report from the SECBIT reviewing four new contract deployments on the NFTX protocol. The contents on this page is based upon the PDF report found at the bottom of the page.

NFTX is a platform for creating liquid markets for illiquid Non-Fungible Tokens (NFTs). Users deposit their NFT into an NFTX vault and mint a fungible ERC20 token (vToken) representing a claim on a random or specific asset from the vault. SECBIT Labs conducted an audit from November 14 to December 8, 2022, including an analysis of the smart contracts in 3 areas: code bugs, logic flaws, and risk assessment.&#x20;

The assessment shows that the peripheral smart contracts of NFTX V2 we audited have no critical security risks. The SECBIT team has some tips on logical implementation, potential risks, and code revising (see part 4 for details).

{% file src="/files/9cmelvYPGYnF3mj31k8K" %}


# Trail of Bits Audit

{% hint style="info" %}
Below is an excerpt from the Trail of Bits Audit, however due to the formatting of the PDF report not everything have been added to the page below.

You can access the full report as a PDF directly below.

{% endhint %}

{% file src="/files/UQZlrbMHn37wUtcyhSrL" %}
Click on the link above to download the full public report of the Trail of Bits audit.
{% endfile %}

## About Trail of Bits

Founded in 2012 and headquartered in New York, Trail of Bits provides technical security assessment and advisory services to some of the world’s most targeted organizations. We combine high-end security research with a real-world attacker mentality to reduce risk and fortify code. With 80+ employees around the globe, we’ve helped secure critical software elements that support billions of end users, including Kubernetes and the Linux kernel.

We maintain an exhaustive list of publications at <https://github.com/trailofbits/publications>, with links to papers, presentations, public audit reports, and podcast appearances.

In recent years, Trail of Bits consultants have showcased cutting-edge research through presentations at CanSecWest, HCSS, Devcon, Empire Hacking, GrrCon, LangSec, NorthSec, the O’Reilly Security Conference, PyCon, REcon, Security BSides, and SummerCon.

We specialize in software testing and code review projects, supporting client organizations in the technology, defense, and finance industries, as well as government entities. Notable clients include HashiCorp, Google, Microsoft, Western Digital, and Zoom.

Trail of Bits also operates a center of excellence with regard to blockchain security. Notable projects include audits of Algorand, Bitcoin SV, Chainlink, Compound, Ethereum 2.0, MakerDAO, Matic, Uniswap, Web3, and Zcash.

To keep up to date with our latest news and announcements, please follow @trailofbits on Twitter and explore our public repositories at <https://github.com/trailofbits>. To engage us directly, visit our “Contact” page at <https://www.trailofbits.com/contact>, or email us at <info@trailofbits.com>.

## Notices and Remarks

### Copyright and Distribution

All rights reserved. Trail of Bits hereby asserts its right to be identified as the creator of this report in the United Kingdom.

This report is considered by Trail of Bits to be public information; it is licensed to NFTX under the terms of the project statement of work and has been made public at NFTX’s request. Material within this report may not be reproduced or distributed in part or in whole without the express written permission of Trail of Bits.

### Test Coverage Disclaimer

All activities undertaken by Trail of Bits in association with this project were performed in accordance with a statement of work and mutually agreed upon project plan.

Security assessment projects are time-boxed and often reliant on information that may be provided by a client, its affiliates, or its partners. As a result, the findings documented in this report should not be considered a comprehensive list of security issues, flaws, or defects in the target system or codebase.

Trail of Bits uses automated testing techniques to rapidly test the controls and security properties of software. These techniques augment our manual security review work, but each has its limitations: for example, a tool may not generate a random edge case that violates a property or may not fully complete its analysis during the allotted time. Their use is also limited by the time and resource constraints of a project.

## Executive Summary

### Engagement Overview

NFTX engaged Trail of Bits to review the security of version 2 of its protocol. From April 4 to April 15, 2022, a team of two consultants conducted a security review of the client-provided source code, with four person-weeks of effort. Details of the project’s timeline, test targets, and coverage are provided in subsequent sections of this report.

### Project Scope

Our testing efforts were focused on the identification of flaws that could result in a compromise of confidentiality, integrity, or availability of the target system. We conducted this audit with full knowledge of the target system, including access to the source code and documentation for all of the on-chain components. Off-chain code was not included in the scope of this assessment. Also, we were instructed to ignore specific files in the codebase, enumerated in the Project Coverage section.

### Summary of Findings

The audit uncovered two flaws that could impact system confidentiality, integrity, or availability. Details on these notable findings are provided below. This report also contains technical appendices. Appendix C lists code quality findings that do not necessarily have security implications. Appendix D provides guidance on redesigning the fee distribution mechanism. Finally, appendix E provides security guidance on interacting with third-party token contracts

### Notable Findings

Significant flaws that impact system confidentiality, integrity, or availability are listed below.

#### TOB-NFTX-9

The process of creating vaults in the NFTX protocol is trustless. This means that anyone can create a new vault and use any asset as the underlying vault NFT. The user calls the NFTXVaultFactoryUpgradeable contract to create a new vault. After deploying the new vault, the contract sets the user as the vault manager.

Vault managers can change the vault fees and disable certain vault features. Therefore, users must verify that vaults that they interact with have reliable managers or have had their managers disabled through verification.

## Project Goals

The engagement was scoped to provide a security assessment of version 2 of the NFTX protocol. Specifically, we sought to answer the following non-exhaustive list of questions:

* Is there a way for users to circumvent fees?
* Can the fee distributor be abused?
* Can a buildup of fees introduce attack vectors?
* Is there a way for a malicious vault manager to grief the vault’s users?
* Is there a way for a malicious third-party token to compromise an NFTX vault?

## Project Targets

The engagement involved a review and testing of the following target.

### NFTX Protocol v2

<https://github.com/NFTX-project/nftx-protocol-v2/>

```
c8ddc72b4400ad1e12ed03f4369b765371564a00
```

Note: Some files in the repository were explicitly out of scope for this assessment. These are enumerated in the following section.

## Project Coverage

This section provides an overview of the analysis coverage of the review, as determined by our high-level engagement goals. Our approaches and their results include the following:

### NFTXVaultFactoryUpgradeable

This upgradeable contract is one of the centerpieces of the protocol. It is responsible for the deployment and management of vaults. As a vault factory, it is responsible for deploying new vault proxies. It also acts as a beacon proxy: vault proxies query the factory for the address of the vault reference implementation before executing delegatecall into it.

This beacon structure allows the NFTX team to upgrade all its vaults at the same time without much friction by simply updating the address of the reference implementation stored by the beacon.

### NFTXVaultUpgradeable

This contract is the reference vault implementation and is the core of the NFTX protocol. Users can deposit NFTs (ERC721 and ERC1155) into vaults and receive ERC20 tokens representing claims to the deposited NFTs. This allows users to gain exposure to the floor price of the collection and to provide liquidity on protocols such as automated market makers (AMMs), like Uniswap and Sushiswap. Vaults also allow users to redeem NFTs by burning the corresponding ERC20 tokens and swapping their NFTs for those deposited in a vault.

### NFTXInventoryStaking

This upgradeable contract acts as both a factory and a beacon proxy. As a factory, it enables the creation of xToken (also written “XToken” in the codebase) proxies; these ERC20 tokens are wrappers around vault tokens and enable depositors to earn rewards by staking their vault tokens in the inventory staking contract.

As a beacon proxy, similarly to the vault factory, it stores the reference to the xToken implementation contract, which xToken proxies can query before executing delegatecall into it.

The contract receives fees from the NFTXSimpleFeeDistributor contract. NFTXLPStaking

This upgradeable contract acts as both a factory and an intermediary. As a factory, it deploys minimal proxies using CREATE2, which allows it to compute the addresses of the newly deployed proxies without having to store them.

As an intermediary, it manages the staking functionality, which allows users to deposit liquidity provider (LP) tokens to receive rewards, and is responsible for directing calls to the right proxy contracts by computing their addresses; to do so, it relies on the StakingTokenProvider contract, which maps vaults to paired tokens.

The contract receives fees from the `NFTXSimpleFeeDistributor` contract.

### NFTXSimpleFeeDistributor

This upgradeable contract is responsible for managing the distribution of protocol fees. The owner (the NFTX DAO in this particular case) is responsible for adding and removing fee receivers. Anyone can perform fee distribution, although it is typically performed by users interacting with the vaults when they perform actions that charge them protocol fees.

### Coverage Limitations

Because of the time-boxed nature of testing work, it is common to encounter coverage limitations. This engagement was scoped to assess only on-chain code. The web-based front end and the protocols for deploying and upgrading contracts warrant a separate review. The following files in the reviewed repository were also explicitly out of scope:

* contracts/solidity/NFTXV1Buyout.sol
* contracts/solidity/tools/NFTXFlashSwipe.sol
* contracts/solidity/other/PalmNFTXStakingZap.sol
* /contracts/solidity/eligibility/\*
  * Except for the following file, which was in scope: contracts/solidity/eligibility/NFTXRangeEligibility.sol


# Contract Addresses

<table data-header-hidden><thead><tr><th>Contracts</th><th>Mainnet</th><th>Goerli</th><th>Arbitrum</th><th data-hidden>Code</th><th data-hidden>Rinkeby</th></tr></thead><tbody><tr><td><strong>Contracts</strong></td><td><strong>Mainnet</strong></td><td><strong>Goerli</strong></td><td><strong>Arbitrum</strong></td><td><strong>Code</strong></td><td><strong>Rinkeby</strong></td></tr><tr><td>StakingTokenProvider</td><td><code>0x5fAD0e4cc9925365b9B0bbEc9e0C3536c0B1a5C7</code></td><td><code>0x057862b3DB9fDe38d030479FEe43Deb38b04d211</code></td><td><code>0x92B80faa01389B753F41Faf90e1C46Dc975830d5</code></td><td>GitHub</td><td><code>0x262FEeCBac8Ee97200F060aeFd89BD41b961e526</code></td></tr><tr><td>LP Staking</td><td><code>0x688c3E4658B5367da06fd629E41879beaB538E37</code></td><td><code>0xAfC303423580239653aFB6fb06d37D666ea0f5cA</code></td><td><code>0x5326A720f76CFbDfE9e18fA618C3a3f7AbDF3934</code></td><td>GitHub</td><td><code>0xcd0dfb870A60C30D957b0DF1D180a236a55b5740</code></td></tr><tr><td>SimpleFeeDistributor</td><td><code>0xFD8a76dC204e461dB5da4f38687AdC9CC5ae4a86</code></td><td><code>0xEafB9D3cA7395Be8925A8c190e8361d1174D31D7</code></td><td><code>0x68A7F493F6C40556931559afD22D7eD868d3f78E</code></td><td>GitHub</td><td><code>0x29F52f4Df3Ae7bd736305c035d45EBa563CD7A2f</code></td></tr><tr><td>VaultFactory</td><td><code>0xBE86f647b167567525cCAAfcd6f881F1Ee558216</code></td><td><code>0x1478bEB5D18B23d2bA90FcEe91d66460AC585e6b</code></td><td><code>0xE77b89FEc41A7b7dC74eb33602e82F0672FbB33C</code></td><td>GitHub</td><td><code>0xbbc53022Af15Bb973AD906577c84784c47C14371</code></td></tr><tr><td>EligibilityManager</td><td><code>0x4086e98Cce041d286112d021612fD894cFed94D5</code></td><td><code>0x3b8aDf75653212622F57633e69dE29aedB554A00</code></td><td><code>0x1a0f3D0e40E9c211BD2D215E709b6FD2C17f35a2</code></td><td>GitHub</td><td><code>0x0256B5E9bE57D8e14BAdfF94fD79760cC44A33c2</code></td></tr><tr><td>Marketplace Zap</td><td><code>0x0fc584529a2AEfA997697FAfAcbA5831faC0c22d</code></td><td><code>0x528bDBe1DB8452bD4643F85695eE0628D900C195</code></td><td><code>0x66f26E38bD50FD52A50da8E87E435f04f98001B7</code></td><td>GitHub</td><td><code>0xF83d27657a6474cB2Ae09a5b39177BBB80E63d81</code></td></tr><tr><td>0x Marketplace Zap</td><td><code>0x941A6d105802CCCaa06DE58a13a6F49ebDCD481C</code></td><td><code>0x177246adb119ed83f982d1e3c4859f354578d5ef</code></td><td><code>0x3BD7512966CbC3406962f8877edbE80aea8A2904</code></td><td></td><td></td></tr><tr><td>MultiProxy Controller</td><td><code>0x35fb4026dcF19f8cA37dcca4D2D68A549548750C</code></td><td><code>0x70B139bFA4C91d9A13F6D7c7B949a62A6Fbd7488</code></td><td><code>0x732E5F7FE7c40333DfeFF57755666F85d1e164c1</code></td><td>GitHub</td><td><code>0xFc542C7fEA1da20E1195b2476ae35db50925515C</code></td></tr><tr><td>Inventory Staking</td><td><code>0x3E135c3E981fAe3383A5aE0d323860a34CfAB893</code></td><td><code>0x6e91A3f27cE6753f47C66B76B03E6A7bFdDB605B</code></td><td><code>0x1A2C03ABD4Af7C87d8b4d5aD39b56fa98E8C4Cc6</code></td><td>GitHub</td><td><code>0x05aD54B40e3be8252CB257f77d9301E9CB1A9470</code></td></tr><tr><td>NFTXStakingZap</td><td><code>0xdC774D5260ec66e5DD4627E1DD800Eff3911345C</code></td><td><code>0x775e23b64610dA2806dc5ed3b0862955e122DDc6</code></td><td><code>0xfb8664E4EB4d2F8B0220d358d0d9C4896DC84959</code></td><td>Github</td><td><code>0xeF5F5491EF04Df94638162Cb8f7CBAd64760e797</code></td></tr><tr><td><a href="https://etherscan.io/address/0x51d660ba5c218b2cf33fbaca5e3abb8aeff3543b#code">NFTXUnstakingInventoryZap</a></td><td><code>0x2374a32ab7b4f7BE058A69EA99cb214BFF4868d3</code></td><td><code>0x8B9D81fF1845375379865c0997bcFf538513Eae1</code></td><td><code>0xB25Ea886FcE4bfDC8750Cb2D4464FE3F7A67bc07</code></td><td>Github</td><td><code>0x608F0D84657BB876DDEDD8d8d5aB9D12639d5798</code></td></tr><tr><td>TimelockExcludeList</td><td></td><td><code>0xeF74238DF347BC5FfCd4EaA263F50eA693369cB6</code></td><td><code>0x96C394Cdd3B09B7B2971Aa6FB8c0435C914E1Df9</code></td><td>Github</td><td></td></tr><tr><td>Vault Creation Zap</td><td></td><td><code>0xD2066db5F318996D09a7cF3E7e5Cac5A4503cd4D</code></td><td></td><td></td><td></td></tr></tbody></table>


# Subgraph

The NFTX subgraph can be used to query protocol holdings, fees, users and more.

* **Subgraph:** [**https://gateway.thegraph.com/api/{api-key}/subgraphs/id/Epp6gJotEJKAsJYdk7bDEURtGWWeZVXwZds2Pgw8eG51**](https://gateway.thegraph.com/api/{api-key}/subgraphs/id/Epp6gJotEJKAsJYdk7bDEURtGWWeZVXwZds2Pgw8eG51)
* **GitHub repo:** <https://github.com/NFTX-project/nftx-v2-subgraph>

| Subgraph Name                   | Chain      | Graph Explorer URL                                                                                                   |
| ------------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------- |
| NFTX V2 Vaults                  | `mainnet`  | <https://thegraph.com/explorer/subgraphs/Epp6gJotEJKAsJYdk7bDEURtGWWeZVXwZds2Pgw8eG51?view=About&chain=arbitrum-one> |
| NFTX V2 Token Holdings          | `mainnet`  | <https://thegraph.com/explorer/subgraphs/3ngD6A27yUgGCEEaPHar9Z76ka23UcsqeAVbHEGfZezU?view=Query&chain=arbitrum-one> |
| NFTX V2 Fee Tracker             | `mainnet`  | <https://thegraph.com/explorer/subgraphs/CcvvFcDd3AgFx6bC8HM7DG856q8z7qDjkSPcMYtCo6vy?view=Query&chain=arbitrum-one> |
| NFTX V2 Vaults Arbitrum         | `arbitrum` | <https://thegraph.com/explorer/subgraphs/Es2MZLriyXL8WiQg4tzTUoQPzTdxYS6EkZYZmGQHT7D3?view=Query&chain=arbitrum-one> |
| NFTX V2 Token Holdings Arbitrum | `arbitrum` | <https://thegraph.com/explorer/subgraphs/AK6uZLwt3HYmwE93SvGLKQoWdnNuwp5JHE4xkRSu8ptx?view=Query&chain=arbitrum-one> |
| NFTX V2 Fee Tracker             | `arbitrum` | <https://thegraph.com/explorer/subgraphs/E3JVh9UhUbnHQCjgi4pPGyEJ8UXYyR7Us1Z1tNtSf1oH?view=Query&chain=arbitrum-one> |


# Subgraph Sample Request

Requesting data from the NFTX Subgraph.

The NFTX app is powered by a combination of Web3 calls for realtime data (token prices, connected wallet holdings etc) and calls to [The Graph](https://thegraph.com/en/) for the data that can't easily be requested from the blockchain.

Below are some common requests that you can make to the NFTX V2 subgraph to retrieve data about the vaults and their holdings.

### NFTX V2 Subgraph Endpoint

You can make `POST` requests to the following endpoint.

```
https://gateway.thegraph.com/api/{api-key}/subgraphs/id/Epp6gJotEJKAsJYdk7bDEURtGWWeZVXwZds2Pgw8eG51
```

### Global Fees

This request returns the global fees (default fees) that are applied to all vaults. The vaults have their own fees also applied to them so check what the `usesFactoryFees` is set to. If it is set to `true` then the global fees are used, if it is set to `false` then the fees defined on the vault are used.

{% tabs %}
{% tab title="Request" %}

```graphql
{
  globals {
    fees {
      mintFee
      randomRedeemFee
      targetRedeemFee
      randomSwapFee
      targetSwapFee
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
    "data": {
        "globals": [
            {
                "fees": {
                    "mintFee": "100000000000000000",
                    "randomRedeemFee": "40000000000000000",
                    "targetRedeemFee": "60000000000000000",
                    "randomSwapFee": "40000000000000000",
                    "targetSwapFee": "60000000000000000"
                }
            }
        ]
    }
}
```

{% endtab %}
{% endtabs %}

### Retrieve first 10 Published Vaults with Holdings

This request returns the first 10 vaults that have been finalised and have more than `0` NFTs in the holdings. To get all vaults change the `first: 10` to `first: 1000` .

{% tabs %}
{% tab title="Request" %}

```graphql
{
  vaults(
    first: 10
    where: { vaultId_gte: 0, isFinalized: true, totalHoldings_gt: 0 }
  ) {
    vaultId
    token {
      id
      name
      symbol
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
    "data": {
        "vaults": [
            {
                "vaultId": "297",
                "token": {
                    "id": "0x00c4a73f10b05228c64e971cf81ae84426a64780",
                    "name": "MineablePunks",
                    "symbol": "MPUNK"
                }
            },
            {
                "vaultId": "370",
                "token": {
                    "id": "0x00d0a61c5cb78f236a715fe08a6bb4a72514f460",
                    "name": "R0N1 World",
                    "symbol": "RONI"
                }
            },
            {
                "vaultId": "220",
                "token": {
                    "id": "0x0115bd305885999562d593c94328fe25190dbc90",
                    "name": "EtherGals",
                    "symbol": "ETHGAL"
                }
            },
            {
                "vaultId": "379",
                "token": {
                    "id": "0x011671956844f31620bb8b9709f32230186a307a",
                    "name": "Turtle Town",
                    "symbol": "TRTL"
                }
            },
            {
                "vaultId": "131",
                "token": {
                    "id": "0x01b0b287f784ccd19cf0a7c11127a70963fd9d30",
                    "name": "Party Penguins",
                    "symbol": "PPENG"
                }
            },
            {
                "vaultId": "411",
                "token": {
                    "id": "0x03b1a9e8bc6cbe4beaeeac277a042a584fe0af59",
                    "name": "Goopdoods Vault",
                    "symbol": "GOOP"
                }
            },
            {
                "vaultId": "286",
                "token": {
                    "id": "0x03f80ed11125f72537b8ad25855f907f5ef53c65",
                    "name": "HoneyBadger by Robness 734 ttl",
                    "symbol": "HONEYB"
                }
            },
            {
                "vaultId": "145",
                "token": {
                    "id": "0x04c5d215401411c4f28e167b3e9e3290d1178cd8",
                    "name": "JunkYard Dogs",
                    "symbol": "JYD"
                }
            },
            {
                "vaultId": "126",
                "token": {
                    "id": "0x051218de982d91c3af03187ed3d8a0dde8231333",
                    "name": "Nice Drips",
                    "symbol": "DRIP"
                }
            },
            {
                "vaultId": "427",
                "token": {
                    "id": "0x055c4497506ee438c6f7a73a8750561d4a334712",
                    "name": "Rebel's Haunted Mansion",
                    "symbol": "REBEL"
                }
            }
        ]
    }
}
```

{% endtab %}
{% endtabs %}

### Single Vault Details

If you want all the details for a single vault you can pass across the `vaultId` as an argument

{% tabs %}
{% tab title="Request" %}

```graphql
{
  vaults(
    first: 1000
    where: { vaultId: 0 }
  ) {
    vaultId
    id
    is1155
    isFinalized
    totalHoldings
    totalMints
    totalRedeems
    totalFees
    totalSwaps
    createdAt
    holdings(first: 1000, orderBy: tokenId, orderDirection: asc) {
      id
      tokenId
      amount
      dateAdded
    }
    token {
      id
      name
      symbol
    }
    fees {
      mintFee
      randomRedeemFee
      targetRedeemFee
      randomSwapFee
      targetSwapFee
    }
    usesFactoryFees
    asset {
      id
      name
      symbol
    }
    manager {
      id
    }
    createdBy {
      id
    }
    eligibilityModule {
      id
      eligibleIds
      eligibleRange
    }
    features {
      enableMint
      enableRandomRedeem
      enableTargetRedeem
      enableRandomSwap
      enableTargetSwap
    }
    inventoryStakingPool {
      id
      dividendToken {
        symbol
      }
    }
    lpStakingPool {
      id
      stakingToken {
        id
      }
    }
  }
}

```

{% endtab %}

{% tab title="Response" %}

```json
{
    "data": {
        "vaults": [
            {
                "vaultId": "0",
                "id": "0x269616d549d7e8eaa82dfb17028d0b212d11232a",
                "is1155": false,
                "isFinalized": true,
                "totalHoldings": "147",
                "totalMints": "341",
                "totalRedeems": "194",
                "totalFees": "6599999999999999000",
                "totalSwaps": "193",
                "createdAt": "1624265437",
                "token": {
                    "id": "0x269616d549d7e8eaa82dfb17028d0b212d11232a",
                    "name": "CryptoPunks",
                    "symbol": "PUNK"
                },
                "fees": {
                    "mintFee": "50000000000000000",
                    "randomRedeemFee": "20000000000000000",
                    "targetRedeemFee": "30000000000000000",
                    "randomSwapFee": "20000000000000000",
                    "targetSwapFee": "30000000000000000"
                },
                "usesFactoryFees": false,
                "asset": {
                    "id": "0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb",
                    "name": "CRYPTOPUNKS",
                    "symbol": "Ͼ"
                },
                "manager": {
                    "id": "0x0000000000000000000000000000000000000000"
                },
                "createdBy": {
                    "id": "0x3fce5449c7449983e263227c5aaeacb4a80b87c9"
                },
                "eligibilityModule": null,
                "features": {
                    "enableMint": true,
                    "enableRandomRedeem": true,
                    "enableTargetRedeem": true,
                    "enableRandomSwap": true,
                    "enableTargetSwap": true
                },
                "inventoryStakingPool": {
                    "id": "0x08765c76c758da951dc73d3a8863b34752dd76fb",
                    "dividendToken": {
                        "symbol": "xPUNK"
                    }
                },
                "lpStakingPool": {
                    "id": "0xfb2f1c0e0086bcef24757c3b9bfe91585b1a280f",
                    "stakingToken": {
                        "id": "0x0463a06fbc8bf28b3f120cd1bfc59483f099d332"
                    }
                },
                "holdings": [
                    {
                        "tokenId": "197"
                    },
                    {
                        "tokenId": "402"
                    },
                    {
                        "tokenId": "441"
                    },
                    {
                        "tokenId": "548"
                    },
                    {
                        "tokenId": "669"
                    },
                    {
                        "tokenId": "675"
                    },
                    {
                        "tokenId": "680"
                    },
                    {
                        "tokenId": "743"
                    },
                    {
                        "tokenId": "1011"
                    },
                    {
                        "tokenId": "1071"
                    },
                    {
                        "tokenId": "1109"
                    },
                    {
                        "tokenId": "1194"
                    },
                    {
                        "tokenId": "1254"
                    },
                    {
                        "tokenId": "1322"
                    },
                    {
                        "tokenId": "1345"
                    },
                    {
                        "tokenId": "1350"
                    },
                    {
                        "tokenId": "1436"
                    },
                    {
                        "tokenId": "1461"
                    },
                    {
                        "tokenId": "1482"
                    },
                    {
                        "tokenId": "1628"
                    },
                    {
                        "tokenId": "1713"
                    },
                    {
                        "tokenId": "1813"
                    },
                    {
                        "tokenId": "1893"
                    },
                    {
                        "tokenId": "1927"
                    },
                    {
                        "tokenId": "1940"
                    },
                    {
                        "tokenId": "2043"
                    },
                    {
                        "tokenId": "2170"
                    },
                    {
                        "tokenId": "2197"
                    },
                    {
                        "tokenId": "2233"
                    },
                    {
                        "tokenId": "2286"
                    },
                    {
                        "tokenId": "2339"
                    },
                    {
                        "tokenId": "2398"
                    },
                    {
                        "tokenId": "2447"
                    },
                    {
                        "tokenId": "2511"
                    },
                    {
                        "tokenId": "2522"
                    },
                    {
                        "tokenId": "2557"
                    },
                    {
                        "tokenId": "2575"
                    },
                    {
                        "tokenId": "2595"
                    },
                    {
                        "tokenId": "2629"
                    },
                    {
                        "tokenId": "2733"
                    },
                    {
                        "tokenId": "2791"
                    },
                    {
                        "tokenId": "2808"
                    },
                    {
                        "tokenId": "2837"
                    },
                    {
                        "tokenId": "2907"
                    },
                    {
                        "tokenId": "2941"
                    },
                    {
                        "tokenId": "3050"
                    },
                    {
                        "tokenId": "3067"
                    },
                    {
                        "tokenId": "3082"
                    },
                    {
                        "tokenId": "3118"
                    },
                    {
                        "tokenId": "3143"
                    },
                    {
                        "tokenId": "3235"
                    },
                    {
                        "tokenId": "3241"
                    },
                    {
                        "tokenId": "3257"
                    },
                    {
                        "tokenId": "3453"
                    },
                    {
                        "tokenId": "3527"
                    },
                    {
                        "tokenId": "3610"
                    },
                    {
                        "tokenId": "3627"
                    },
                    {
                        "tokenId": "3789"
                    },
                    {
                        "tokenId": "4011"
                    },
                    {
                        "tokenId": "4050"
                    },
                    {
                        "tokenId": "4064"
                    },
                    {
                        "tokenId": "4091"
                    },
                    {
                        "tokenId": "4195"
                    },
                    {
                        "tokenId": "4306"
                    },
                    {
                        "tokenId": "4348"
                    },
                    {
                        "tokenId": "4357"
                    },
                    {
                        "tokenId": "4406"
                    },
                    {
                        "tokenId": "4455"
                    },
                    {
                        "tokenId": "4486"
                    },
                    {
                        "tokenId": "4493"
                    },
                    {
                        "tokenId": "4496"
                    },
                    {
                        "tokenId": "4546"
                    },
                    {
                        "tokenId": "4563"
                    },
                    {
                        "tokenId": "4643"
                    },
                    {
                        "tokenId": "4875"
                    },
                    {
                        "tokenId": "4912"
                    },
                    {
                        "tokenId": "4930"
                    },
                    {
                        "tokenId": "4933"
                    },
                    {
                        "tokenId": "4951"
                    },
                    {
                        "tokenId": "5067"
                    },
                    {
                        "tokenId": "5254"
                    },
                    {
                        "tokenId": "5354"
                    },
                    {
                        "tokenId": "5462"
                    },
                    {
                        "tokenId": "5467"
                    },
                    {
                        "tokenId": "5516"
                    },
                    {
                        "tokenId": "5703"
                    },
                    {
                        "tokenId": "5766"
                    },
                    {
                        "tokenId": "5821"
                    },
                    {
                        "tokenId": "5881"
                    },
                    {
                        "tokenId": "5945"
                    },
                    {
                        "tokenId": "5962"
                    },
                    {
                        "tokenId": "5999"
                    },
                    {
                        "tokenId": "6028"
                    },
                    {
                        "tokenId": "6193"
                    },
                    {
                        "tokenId": "6276"
                    },
                    {
                        "tokenId": "6335"
                    },
                    {
                        "tokenId": "6341"
                    },
                    {
                        "tokenId": "6434"
                    },
                    {
                        "tokenId": "6561"
                    },
                    {
                        "tokenId": "6584"
                    },
                    {
                        "tokenId": "6603"
                    },
                    {
                        "tokenId": "6646"
                    },
                    {
                        "tokenId": "6772"
                    },
                    {
                        "tokenId": "6804"
                    },
                    {
                        "tokenId": "6997"
                    },
                    {
                        "tokenId": "7032"
                    },
                    {
                        "tokenId": "7054"
                    },
                    {
                        "tokenId": "7281"
                    },
                    {
                        "tokenId": "7304"
                    },
                    {
                        "tokenId": "7486"
                    },
                    {
                        "tokenId": "7608"
                    },
                    {
                        "tokenId": "7626"
                    },
                    {
                        "tokenId": "7628"
                    },
                    {
                        "tokenId": "7754"
                    },
                    {
                        "tokenId": "7957"
                    },
                    {
                        "tokenId": "8054"
                    },
                    {
                        "tokenId": "8089"
                    },
                    {
                        "tokenId": "8150"
                    },
                    {
                        "tokenId": "8208"
                    },
                    {
                        "tokenId": "8308"
                    },
                    {
                        "tokenId": "8331"
                    },
                    {
                        "tokenId": "8409"
                    },
                    {
                        "tokenId": "8444"
                    },
                    {
                        "tokenId": "8470"
                    },
                    {
                        "tokenId": "8538"
                    },
                    {
                        "tokenId": "8542"
                    },
                    {
                        "tokenId": "8730"
                    },
                    {
                        "tokenId": "8755"
                    },
                    {
                        "tokenId": "8858"
                    },
                    {
                        "tokenId": "8885"
                    },
                    {
                        "tokenId": "8922"
                    },
                    {
                        "tokenId": "9215"
                    },
                    {
                        "tokenId": "9228"
                    },
                    {
                        "tokenId": "9243"
                    },
                    {
                        "tokenId": "9364"
                    },
                    {
                        "tokenId": "9370"
                    },
                    {
                        "tokenId": "9386"
                    },
                    {
                        "tokenId": "9442"
                    },
                    {
                        "tokenId": "9490"
                    },
                    {
                        "tokenId": "9620"
                    },
                    {
                        "tokenId": "9747"
                    },
                    {
                        "tokenId": "9815"
                    },
                    {
                        "tokenId": "9846"
                    },
                    {
                        "tokenId": "9887"
                    },
                    {
                        "tokenId": "9903"
                    },
                    {
                        "tokenId": "9924"
                    },
                    {
                        "tokenId": "9956"
                    }
                ]
            }
        ]
    }
}
```

{% endtab %}
{% endtabs %}

### NFTX App Request

While there are a number of requests made to the subgraph to run the NFTX site the main request most integrations require is to retrieve all current vaults with the available NFTs available for purchase, and the facility to calculate the price.

This uses a combination of all the requests listed above.

{% tabs %}
{% tab title="Request" %}

```graphql
{
  globals {
    fees {
      mintFee
      randomRedeemFee
      targetRedeemFee
      randomSwapFee
      targetSwapFee
    }
  }
  vaults(
    first: 1000
    where: { vaultId_gte: 0, isFinalized: true, totalHoldings_gt: 0 }
  ) {
    vaultId
    id
    is1155
    isFinalized
    totalHoldings
    totalMints
    totalRedeems
    totalFees
    totalSwaps
    createdAt
    holdings(first: 1000, orderBy: tokenId, orderDirection: asc) {
      id
      tokenId
      amount
      dateAdded
    }
    token {
      id
      name
      symbol
    }
    fees {
      mintFee
      randomRedeemFee
      targetRedeemFee
      randomSwapFee
      targetSwapFee
    }
    usesFactoryFees
    asset {
      id
      name
      symbol
    }
    manager {
      id
    }
    createdBy {
      id
    }
    eligibilityModule {
      id
      eligibleIds
      eligibleRange
    }
    features {
      enableMint
      enableRandomRedeem
      enableTargetRedeem
      enableRandomSwap
      enableTargetSwap
    }
    inventoryStakingPool {
      id
      dividendToken {
        symbol
      }
    }
    lpStakingPool {
      id
      stakingToken {
        id
      }
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
// response truncated for brevity.
{
    "data": {
        "globals": [
            {
                "fees": {
                    "mintFee": "100000000000000000",
                    "randomRedeemFee": "40000000000000000",
                    "targetRedeemFee": "60000000000000000",
                    "randomSwapFee": "40000000000000000",
                    "targetSwapFee": "60000000000000000"
                }
            }
        ],
        "vaults": [
            {
                "vaultId": "297",
                "id": "0x00c4a73f10b05228c64e971cf81ae84426a64780",
                "is1155": false,
                "isFinalized": true,
                "totalHoldings": "38",
                "totalMints": "47",
                "totalRedeems": "9",
                "totalFees": "2440000000000000000",
                "totalSwaps": "0",
                "createdAt": "1639894659",
                "holdings": [
                    {
                        "id": "0x276c-0x00c4a73f10b05228c64e971cf81ae84426a64780",
                        "tokenId": "10092",
                        "amount": "1",
                        "dateAdded": "1646022345"
                    },
                    {
                    ...37 more nfts listed here....
                    }
                ],
                "token": {
                    "id": "0x00c4a73f10b05228c64e971cf81ae84426a64780",
                    "name": "MineablePunks",
                    "symbol": "MPUNK"
                },
                "fees": {
                    "mintFee": "100000000000000000",
                    "randomRedeemFee": "50000000000000000",
                    "targetRedeemFee": "100000000000000000",
                    "randomSwapFee": "50000000000000000",
                    "targetSwapFee": "100000000000000000"
                },
                "usesFactoryFees": true,
                "asset": {
                    "id": "0x595a8974c1473717c4b5d456350cd594d9bda687",
                    "name": "MineablePunks",
                    "symbol": "MPUNKS"
                },
                "manager": {
                    "id": "0x0000000000000000000000000000000000000000"
                },
                "createdBy": {
                    "id": "0x33569c101562e1faf5b24581057e5cee4c8288d7"
                },
                "eligibilityModule": null,
                "features": {
                    "enableMint": true,
                    "enableRandomRedeem": true,
                    "enableTargetRedeem": true,
                    "enableRandomSwap": true,
                    "enableTargetSwap": true
                },
                "inventoryStakingPool": {
                    "id": "0x013cf78239144abcf06bbd56d3d190c65d7f9635",
                    "dividendToken": {
                        "symbol": "xMPUNK"
                    }
                },
                "lpStakingPool": {
                    "id": "0xfda2d4ea96ae4c6c21b34ec4e607576163a55ec0",
                    "stakingToken": {
                        "id": "0xe7d5d6b7d3a3c70174d6b567697287a3322c4789"
                    }
                }
            },
            .... more vaults.....
            ] 
        }
    }
```

{% endtab %}
{% endtabs %}


# Dune Analytics

NFTX has a Dune Analytics dashboard for the protocol and each individual vault.

* **Protocol Dashboard**: <https://dune.xyz/nftx/NFTX-Dune-Dashboard-Protocol-View>
* **Vault Dashboard**: <https://dune.xyz/nftx/NFTX-Dune-Dashboard-Single-Vault-View>

To use the Vault Dashboard, enter the vault contract address into the `Vault_Address` input at the top of the page. Alternatively, go directly via this URL, replacing {vault\_address} with the vault's address:

<https://dune.xyz/nftx/NFTX-Dune-Dashboard-Single-Vault-View?Vault\\_Address=**{vault\\_address}>\*\*


# Deployment Flow

![](/files/mYkNYUu9FWVS6Ndl47zP)


# Vault Creation Zap

To assist in the creation of an NFTX vault, we created a zap that amalgamates a number of processes into a singular contract call. This call will allow you to perform the following steps:

1. Create a default vault
2. *(optional)* Add an eligibility storage module
3. *(optional)* Add 721 or 1155 tokens to the vault, returning tokens to the sender
4. *(optional)* Set vault features
5. Set vault fees
6. Finalise the vault

*Please note: Due to the evolution of ERC721 support, we have chosen to exclude support for the CryptoKitties contract to save gas for the majority of users.*

<table><thead><tr><th width="179.91384056105488">Network</th><th width="332.66666666666663">Contract Address</th></tr></thead><tbody><tr><td>Mainnet</td><td>Coming soon</td></tr></tbody></table>

Our vault creation function takes the following attributes, each of which will be explained in this document. Upon successful creation we receive the ID of the vault that was created. This can then be subsequently referenced in our NFTX Vault Factory to get address and implementation information.

```
  function createVault(
    vaultInfo calldata vaultData,
    uint vaultFeatures,
    vaultFeesConfig calldata vaultFees,
    vaultEligibilityStorage calldata eligibilityStorage,
    vaultTokens calldata assetTokens
  ) external nonReentrant returns (uint vaultId_);
```

### vaultData

Takes a formatted struct containing basic information regarding the vault.

```
  struct vaultInfo {
    address assetAddress;
    bool is1155;
    bool allowAllItems;
    string name;
    string symbol;
  }
```

### vaultFeatures

A integer value of a binary representation of booleans. This allows us to map five boolean values, one for each optional vault feature, inside of a single parameter. The order of these booleans aligns as:

1. Allow minting to the vault
2. Allow random redemptions
3. Allow targeted redemptions
4. Enable random swaps
5. Enable targeted swaps

For example, to allow only minting inside the vault, but no redemptions or swaps, this would give a binary value of `10000` as this would equate to `true, false, false, false, false`. Converted into an integer value, this would then come out as `16`, which would be passed to the contract.

We can use `parseInt` in JS to make this conversion into an integer value simple:

```
let x = '10000';
parseInt(x, 2) // 16
```

#### Examples

| Booleans | Binary | Integer |
| -------- | ------ | ------- |
| FFFFF    | 00101  | 5       |
| TFFFF    | 10000  | 16      |
| TFTFT    | 10101  | 21      |
| TTFTT    | 11011  | 27      |
| TTTTT    | 11111  | 31      |

### vaultFees

The fees for the vault, entered in 9-decimal format.

```
  struct vaultFeesConfig {
    uint32 mintFee;
    uint32 randomRedeemFee;
    uint32 targetRedeemFee;
    uint32 randomSwapFee;
    uint32 targetSwapFee;
  }
```

### eligibilityStorage

Allows for a vault eligibility storage implementation to be specified for the vault to use. The `moduleIndex` will represent the index ID of a valid eligibility module, and the `initData` bytes will be passed to the module when initialising. More information about eligibility modules can be found [here](/main/smart-contracts/eligibility-modules).

```
  struct vaultEligibilityStorage {
    int moduleIndex;
    bytes initData;
  }
```

If no module is required, then you can set a `moduleIndex` of `-1`.

### assetTokens

Tokens to be transferred to the vault to populate its initial supply. The vault tokens will be returned to the `msg.sender`.

***Note: Tokens must all be owned and approved for the zap to use by the sender as a precursor to calling.***

```
  struct vaultTokens {
    uint[] assetTokenIds;
    uint[] assetTokenAmounts;
  }
```

An array of token ID values that belong to the specified vault `assetAddress`, along with the amount of each token. If you're sending `ERC721` tokens, then the amount values will be ignored, though this will be required for `ERC1155` tokens to indicate how many of each token ID will be sent to the vault.

### Example Call

The below shows an example of an 1155 vault, deployed with 10 tokens across 3 different IDs. We don't have an eligibility module attached, but define features and fees.

```
  const vaultId = await vaultCreationZap.createVault(
    // Vault creation
    {
      name: 'Pace Spoggers',
      symbol: 'SPOGGERS',
      assetAddress: erc1155.address,
      is1155: true,
      allowAllItems: true
    },

    // Vault features
    26,  // 11010

    // Fee assignment
    {
      mintFee: 20000000,            // 0.2
      randomRedeemFee: 12500000,    // 0.125
      targetRedeemFee: 20000000,    // 0.2
      randomSwapFee: 15000000,      // 0.15
      targetSwapFee: 20000000       // 0.2
    },

    // Eligibility storage
    {
      moduleIndex: -1,
      initData: 0
    },

    // Mint and stake
    {
      assetTokenIds: [1, 2, 3],
      assetTokenAmounts: [2, 5, 3]
    }
  );
```


# Integrations

Use the NFTX protocol to access liquidity for NFT buys and sells within marketplaces and aggregators

NFTX is an NFT liquidity protocol that can be integrated into other NFT marketplace or NFT aggregator (both [Gem](https://gem.xyz) and [Uniswap](https://app.uniswap.org/#/nfts) have already integrated with NFTX).

The steps for displaying the items on your NFT marketplace include

1. Fetch NFTX vaults and their NFT holdings & fee settings
2. Check the price of buy/sell of those tokens on 0xProtocol for an ETH price
3. Call the 0xMarketplaceZap to perform the buy/sell (or the mint (sell) or redeem (buy) functions)

You can make a [single request to retrieve all vault data](#return-all-data-from-all-nft-vault-collections) from NFTX, or you can make [individual requests](#all-collection-details-from-a-single-vault) depending on your requirements.

{% hint style="info" %}
Vault tokens have a 1:1 relationship with the NFTs within the vault.&#x20;

* Adding an NFT to the vault, a vault token (vToken) is minted.
* Removing an NFT from the vault, a vToken is burned

Retrieving items from the vault, or buying NFTs, requires the 1 token to be burned plus the fees associated with the buy. Likewise, adding an item will return a vToken minus the fees associated with the sell.
{% endhint %}

## Example marketplace integration

These are the pseudo steps to integrate NFTX NFTs and liquidity into your application

1. Retrieve all NFTX vaults from the subgraph, including global fees, and holdings
2. Use the `asset > id` in the subgraph response to link the NFTX vault with the appropriate NFT collection in your application
3. Verify that the vault has `features > enableTargetRedeems` set to `true` so specific NFTs can be bought from the vault.
4. Check if the vault uses default fees using `usesFactoryFees` , if `true` use the global fees to calculate the tokens required to buy an NFT, if `false` use the `fees > targetRedeemFee` associated with the vault. To buy an NFT you need 1 token + target redeem fee.
5. Using the 0xAPI, check the ETH cost to buy the required tokens. As the number of tokens required increases (i.e. the user adds more items to their basket) the average price of the NFT will increase due to price impact on the token buy.
6. When the user buys, call the `0xMarketplaceZap` to complete the purchase, or alternatively call your own contracts to buy the token, redeem the NFTs using the `redeemTo` function on the vault contract.
7. For realtime updates on holdings, you can request individual vault holdings.

## Contract Calls

{% hint style="info" %}
We recommend using the `NFTXMarketplace0xZap` contract for interactions to ensure the best price is offered. This address can be found on our [Contract Addresses](/main/smart-contracts/contract-addresses) page.
{% endhint %}

There are 3 main logic approaches that we can undertake in this contract.

* BuyAndRedeem
* BuyAndSwap
* MintAndSell

Both `BuyAndSwap` and `MintAndSell` functions have 721 and 1155 function variants that can be called. `BuyAndRedeem` handles both of these standards in a single function. The 1155 variations will take an additional `uint256[] amounts` function parameter to allow multiples of each token to be interacted with.

### BuyAndRedeem

Purchases vault tokens from 0x with ETH (converted to WETH in the call) and then redeems the tokens for either random or specific token IDs from the vault. The specified recipient will receive the ERC721 tokens, as well as any WETH dust that is left over from the tx.

#### Parameters

* `vaultId` (uint256) : The ID of the NFTX vault
* `amount` (uint256) : The number of tokens to buy
* `specificIds` (uint256\[]) : An array of any specific token IDs to be minted
* `swapCallData` (bytes) : The \`data\` field from the 0x API response
* `to` (address payable) : The recipient of the token IDs from the tx

#### Events Emitted

* Emits NFTXMarketplace0xZap : Buy(amount, quoteAmount, to);
* Emits NFTXVaultUpgradable : Redeemed(redeemedIds, specificIds, to);
* Emits NFTXMarketplace0xZap : DustReturned(remaining, dustBalance, dustRecipient);

### BuyAndSwap721 / BuyAndSwap1155

Purchases vault tokens from 0x with ETH (converted to WETH in the call) and then swaps the tokens for either random or specific token IDs from the vault. The specified recipient will receive the ERC721 / ERC1155 tokens, as well as any WETH dust that is left over from the tx.

#### Parameters

* `vaultId` (uint256) : The ID of the NFTX vault
* `idsIn` (uint256\[]) : An array of random token IDs to be minted
* `specificIds` (uint256\[]) : An array of any specific token IDs to be minted
* `swapCallData` (bytes) : The \`data\` field from the 0x API response
* `to` (address payable) : The recipient of the token IDs from the tx

#### Events Emitted

* Emits NFTXMarketplace0xZap : Swap(idsIn.length, amount, to);
* Emits NFTXVaultUpgradable : Redeemed(redeemedIds, specificIds, to);
* Emits NFTXMarketplace0xZap : DustReturned(remaining, dustBalance, dustRecipient);

### MintAndSell721 / MintAndSell1155

Mints tokens on our NFTX vault and sells the generated tokens on 0x.

#### Parameters

* `vaultId` (uint256) : The ID of the NFTX vault
* `ids` (uint256\[]) : An array of token IDs to be minted
* `swapCallData` (bytes) : The \`data\` field from the 0x API response
* `to` (address payable) : The recipient of the token IDs from the tx

#### Events Emitted

* Emits NFTXMarketplace0xZap : emit Sell(ids.length, amount, to);
* Emits NFTXVaultUpgradable : Redeemed(redeemedIds, specificIds, to);
* Emits NFTXMarketplace0xZap : DustReturned(remaining, dustBalance, dustRecipient);

## API endpoints

The NFTX V2 subgraph is a GraphQL endpoint that is hosted on The Graph. It can be accessed for free through the existing hosted service, and also through The Graph Studio which is a decentralised endpoint supported by a number of indexers.

When making a request is will be a `POST` request and the endpoint URL will always remain the same, while the the body of the request will change depending on the data you require.

### NFTX Graph Endpoints

**Studio subgraph page**: <https://thegraph.com/explorer/subgraphs/Epp6gJotEJKAsJYdk7bDEURtGWWeZVXwZds2Pgw8eG51?view=Query&chain=arbitrum-one>

**Decentralised Studio endpoint**: <https://gateway.thegraph.com/api/{api-key}/subgraphs/id/Epp6gJotEJKAsJYdk7bDEURtGWWeZVXwZds2Pgw8eG51>

{% hint style="info" %}
An API key is required when making requests through the decentralised studio. Each request costs around 0.0005 GRT and you recieve free credits when you first sign up for a developer key.
{% endhint %}

{% hint style="warning" %}
The Graph Hosted service is being decomissioned in Q1 of 2023 and the only way to access the subgraphs will be through the new decentralised studio.
{% endhint %}

A few notes about making requests to the Subgraph

* Requests are always POST and the body of the request will define the response
* Reponses from GraphQL are always `200` success responses, even when the request fails. See below for the response from an incorrect query sent

{% code title="200 response from a misformed request body" %}

```json
{
    "errors": [
        {
            "locations": [
                {
                    "column": 1,
                    "line": 1
                }
            ],
            "message": "Unexpected `not[Name]`\nExpected `{`, `query`, `mutation`, `subscription` or `fragment`"
        }
    ]
}
```

{% endcode %}

### 0x Protocol Endpoints

The 0x endpoint is used to check the price for buying the tokens required to redeem NFTs from the NFTX vaults.

The price endpoint allows you to get the current price for displaying on the front end. Once someone adds an item to their basket to purchase you want to make another call to the `quote` endpoint to get the call data.

{% code title="GET request for pricing" overflow="wrap" %}

```url
https://api.0x.org/swap/v1/price?buyToken=0x269616D549D7e8Eaa82DFb17028d0B212D11232A&sellToken=WETH&buyAmount=1030000000000000000
```

{% endcode %}

{% code title="GET quote request for buying/selling" overflow="wrap" %}

```url
https://api.0x.org/swap/v1/quote?buyToken=0x269616D549D7e8Eaa82DFb17028d0B212D11232A&sellToken=WETH&buyAmount=1030000000000000000
```

{% endcode %}

## NFTX Graph requests

### Return all data from all NFT vault collections

The below request body returns all the data you need to include every collection within NFTX into your marketplace or aggregator. To increase response times and lower the response size you can remove any data points that are not required for your particular implementation.

Data requests for a specific vault can be found below.

#### Request

{% code title="Request URL" %}

```
https://gateway.thegraph.com/api/{api-key}/subgraphs/id/Epp6gJotEJKAsJYdk7bDEURtGWWeZVXwZds2Pgw8eG51
```

{% endcode %}

{% code title="GraphQL Query" %}

```graphql
{
  globals {
    fees {
      mintFee
      randomRedeemFee
      targetRedeemFee
      randomSwapFee
      targetSwapFee
    }
  }
  vaults(
    first: 1000
    where: { vaultId_gte: 0, isFinalized: true, totalHoldings_gt: 0, shutdownDate: "0"  }
  ) {
    vaultId
    id
    is1155
    isFinalized
    totalHoldings
    totalMints
    totalRedeems
    totalFees
    totalSwaps
    createdAt
    shutdownDate
    holdings(first: 1000, orderBy: tokenId, orderDirection: asc) {
      id
      tokenId
      amount
      dateAdded
    }
    token {
      id
      name
      symbol
    }
    fees {
      mintFee
      randomRedeemFee
      targetRedeemFee
      randomSwapFee
      targetSwapFee
    }
    usesFactoryFees
    asset {
      id
      name
      symbol
    }
    eligibilityModule {
      id
      name
      eligibleIds
      eligibleRange
    }
    features {
      enableMint
      enableRandomRedeem
      enableTargetRedeem
      enableRandomSwap
      enableTargetSwap
    }
  }
}

```

{% endcode %}

{% hint style="info" %}
The above request body is what the NFTX V2 frontend uses to retrieve all the required data to build out the homepage of the app. You should use a combination of requests to the subgraph to retrieve the data as needed for your own marketplace or aggregator setup. <br>

Additional [request examples](#example-requests) are found below.
{% endhint %}

#### Response

Below is a breakdown of the response from the request response.

#### globals -> fees

These are the default fee's that are set for the NFTX protocol. If a vault returns `usesFactoryFees: true` then the globals fees are used for items within that vault. This is true even if the vault returns alternative fees.

{% code title="Example response for global fees" lineNumbers="true" %}

```json
"globals": [
            {
                "fees": {
                    "mintFee": "100000000000000000",
                    "randomRedeemFee": "40000000000000000",
                    "targetRedeemFee": "60000000000000000",
                    "randomSwapFee": "40000000000000000",
                    "targetSwapFee": "100000000000000000"
                }
            }
        ],
```

{% endcode %}

The response is defined in wei and shows&#x20;

* `fees` : Contains the differnt global fee settings.
  * `mintFee`: Selling an item on NFTX. The current default is 10%, or 0.1 token
  * `randomRedeemFee`: Buying a random NFT from the vault. Default is 4% or 0.04 token
  * `targetRedeemFee`: Buying a specific NFT from the vault. Default is 6% of 0.06 token
  * `randomSwapFee`: Swapping an existing item in your wallet with a random item in the vault. Default is 4% or 0.04 token
  * `targetSwapFee`: Swapping an exisitng item in your wallet with a specific NFT in the vault. Default is 10% or 0.1 token

{% hint style="info" %}
Some vaults will not allow all vault features like targetRedeem, targetSwap even though there are fees set globally. See below the details defined in `features`
{% endhint %}

#### vaults

* `vaultId`: The squential number of the vault created on NFTX.
* `id`: the token contract address
* `is1155`: Defines if the collection is an ERC1155 collection. If `false` the collection will be ER721, if `true` is an 1155 collection.
* `isFinalized`: If set to `true` the vault details can not be updated unless going through a governance process and a vote through Aragon. There is a `where` clause on the request to set `isFinalized: true` so only finalised vaults are returned in this request.
* `totalHoldings`: The total number of NFTs inside the vault. For 1155's this counts the total number of NFTs, not the total individual NFT `tokenId` numbers.
* `totalMints`: total number of NFTs that have been added to the vault since the vault was created. This can be through selling or staking.
* `totalRedeems`: total number of NFTs taken from the vault since the vault was created. This can be done through target buys, random buys, unstaking.
* `totalFees`: total number of fees generated on the vault through buys/sells/swaps.
* `createdAt`: the unix timestamp when the vault was created
* `shutdownDate`: If this is set to `0` the vault is still functional. If there is a value other than `0` (a unix timestamp) then the vault has been shut down and should be ignored. This is why `shutdownDate: "0"` is included in the `where` filter during the initial request.
* `holdings`: provides the first `1000` tokens held in the vault
  * `id`: the ID of the NFT
  * `tokenId`: the NFT token ID.
  * `amount`: always 1 when dealing with `ERC721` , but if the vault has `is1155: true` then there can be multiple amounts for a single token id.
  * `dateAdded`: the unix timestamp the NFT was added to the vault
* `token`: details about the vault contract/token
  * `id`: the contract address of the vault on NFTX
  * `name`: the vault name defined by the vault creator
  * `symbol`: the cash tag given to the vault
* `fees`: these fees are only valid if the following is returned `usesFactoryFees: false`
  * see definitions in the global fee response above
* `usesFactoryFees`: if this is set to `true` then the fees from the global fees section should be used and these vault specific fees should be ignored. If this is set to `false` then the fees defined against the vault fees response should be used.
* `asset`: these are the details about the NFT collection that the vault is based on
  * `id`: the contract address for the collection. You would use this to match holdings in NFTX with NFT collections displayed in your marketplace or aggregator.
  * `name`: the name of the NFT Collection - this can sometimes be the same as the vault
  * `symbol`: the symbol for the NFT collections - this can somethimes be the same as the vault
* `eligibilityModule`: this is important where vaults are set to only allow certain items. Examples include the ArtBlocks collections which are all tied to the same contract, however are differentiated by the NFT id ranges. This is only important if you are looking to allow instant sells on your platform to ensure the NFT is able to go into the vault.
* `features`: when vaults are created they can have certain features disabled. By default, all items are enabled, however for some vaults users choose to remove the ability to choose a specific item to redeem, making the vault more like a lucky dip. For each, the relevant fee is added (or removed for mints) to the transaction.
  * `enableMint`: when set to `true` this will allow users to sell NFTs into the vault.
  * `enableRandomRedeem`: when set to `true` allows users to retrieve random items from the vault.
  * `enableTargetRedeem`: when set to `true` allows users to choose item to buy from teh vault. If this is disabled, you probably don't want to list them on your marketplace or aggregator.
  * `enableRandomSwap`: when set to `true` allows users to swap an existing NFT from their wallet that is suitable for the vault with a random one in the vault.
  * `enableTargetSwap`: when set to `true` allows users to choose an item to swap out of the vault.

### All collection details from a single vault

The below request body returns all the data for a specific vault. To increase response times and lower the response size you can remove any data points that are not required for your particular implementation.

The `{ globals { fees { ... } } }` has been left in, but this could be captured once and cached as the default global fees don't change.

```graphql
{
  globals {
    fees {
      mintFee
      randomRedeemFee
      targetRedeemFee
      randomSwapFee
      targetSwapFee
    }
  }
  vaults(
    where: { vaultId: "297" }
  ) {
    vaultId
    id
    is1155
    totalHoldings
    holdings(first: 1000, orderBy: tokenId, orderDirection: asc) {
      id
      tokenId
      amount
      dateAdded
    }
    token {
      id
      name
      symbol
    }
    fees {
      mintFee
      randomRedeemFee
      targetRedeemFee
      randomSwapFee
      targetSwapFee
    }
    usesFactoryFees
    asset {
      id
      name
      symbol
    }
    eligibilityModule {
      id
      name
      eligibleIds
      eligibleRange
    }
    features {
      enableMint
      enableRandomRedeem
      enableTargetRedeem
      enableRandomSwap
      enableTargetSwap
    }
  }
}

```

If the response shows that `totalHoldings` is more than 1000 then a follow up request containing can be made to get the next set of holdings.

```graphql
{
  vaults(
    where: { vaultId: "297" }
  ) {
    holdings(first: 1000, skip: 1000, orderBy: tokenId, orderDirection: asc) {
      id
      tokenId
      amount
      dateAdded
    }
  }
}

```

The use of `skip: 1000` will get the next set of holdings up to `2000`. You can either keep looping based on the original `totalHoldings` value, or check to see if the `holdings` array has 1000 items, and if you skip to retrieve the next set.&#x20;

Currently there are only a couple collections with more than 1000 items.

## 0x Protocol Requests

The final step is to price the buy/sell price for the NFTs. All NFTs within the vault are the same floor price. To calculate the price for each item you check the fee settings for the collection, and add that to the number of NFTs being bought. For example, on a vault with the default targetRedeem (the fee to choose an item to buy) of 6% the following tokens would be required...

| Number of NFTs | Fee | Total required |
| -------------- | --- | -------------- |
| 1              | 6%  | 1.06           |
| 2              | 6%  | 2.12           |
| 5              | 6%  | 5.30           |
| 10             | 6%  | 10.60          |

Next, you calculate the amount of ETH required to buy that number of tokens. NFTX recently switched using the 0x protocol when buying tokens through our 0xMarketplaceZap to take advantage of liquidty on any number of providers, including Uniswap V3 concentrated liquidity pools.

**Request**

{% code title="0x API Request" overflow="wrap" %}

```url
https://api.0x.org/swap/v1/price?buyToken=0x269616D549D7e8Eaa82DFb17028d0B212D11232A&sellToken=WETH&buyAmount=1030000000000000000
```

{% endcode %}

**Response**

{% code title="0x API Response" overflow="wrap" %}

```json
{
  "chainId": 1,
  "price": "66.139686266145680957",
  "estimatedPriceImpact": "2.4621",
  "value": "0",
  "gasPrice": "37000000000",
  "gas": "259700",
  "estimatedGas": "259700",
  "protocolFee": "0",
  "minimumProtocolFee": "0",
  "buyTokenAddress": "0x269616d549d7e8eaa82dfb17028d0b212d11232a",
  "buyAmount": "1030000000000000000",
  "sellTokenAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
  "sellAmount": "68123876854130051385",
  "sources": [
    {
      "name": "0x",
      "proportion": "0"
    },
    {
      "name": "Uniswap",
      "proportion": "0"
    },
    {
      "name": "Uniswap_V2",
      "proportion": "0"
    },
    {
      "name": "Curve",
      "proportion": "0"
    },
    {
      "name": "Balancer",
      "proportion": "0"
    },
    {
      "name": "Balancer_V2",
      "proportion": "0"
    },
    {
      "name": "Bancor",
      "proportion": "0"
    },
    {
      "name": "BancorV3",
      "proportion": "0"
    },
    {
      "name": "mStable",
      "proportion": "0"
    },
    {
      "name": "SushiSwap",
      "proportion": "0.9231"
    },
    {
      "name": "Shell",
      "proportion": "0"
    },
    {
      "name": "DODO",
      "proportion": "0"
    },
    {
      "name": "DODO_V2",
      "proportion": "0"
    },
    {
      "name": "CryptoCom",
      "proportion": "0"
    },
    {
      "name": "Lido",
      "proportion": "0"
    },
    {
      "name": "MakerPsm",
      "proportion": "0"
    },
    {
      "name": "KyberDMM",
      "proportion": "0"
    },
    {
      "name": "Component",
      "proportion": "0"
    },
    {
      "name": "Saddle",
      "proportion": "0"
    },
    {
      "name": "Uniswap_V3",
      "proportion": "0.07692"
    },
    {
      "name": "Curve_V2",
      "proportion": "0"
    },
    {
      "name": "ShibaSwap",
      "proportion": "0"
    },
    {
      "name": "Synapse",
      "proportion": "0"
    },
    {
      "name": "Synthetix",
      "proportion": "0"
    },
    {
      "name": "Aave_V2",
      "proportion": "0"
    },
    {
      "name": "Compound",
      "proportion": "0"
    }
  ],
  "allowanceTarget": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
  "sellTokenToEthRate": "1",
  "buyTokenToEthRate": "0.01550116240807967",
  "expectedSlippage": null
}
```

{% endcode %}

## Example requests

<details>

<summary>Fetch global fees</summary>

{% code title="GraphQL request" %}

```graphql
{
  globals {
    fees {
      mintFee
      randomRedeemFee
      targetRedeemFee
      randomSwapFee
      targetSwapFee
    }
  }
}
```

{% endcode %}

{% code title="cURL request" overflow="wrap" %}

```bash
curl --location --request POST 'https://gateway.thegraph.com/api/{api-key}/subgraphs/id/Epp6gJotEJKAsJYdk7bDEURtGWWeZVXwZds2Pgw8eG51' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"{\n  globals {\n    fees {\n      mintFee\n      randomRedeemFee\n      targetRedeemFee\n      randomSwapFee\n      targetSwapFee\n    }\n  }\n}\n","variables":{}}'
```

{% endcode %}

</details>

<details>

<summary>Fetch all active vault ids with more than one item</summary>

{% code title="GraphQL request" %}

```graphql
{
  vaults(
    first: 1000
    where: { isFinalized: true, totalHoldings_gt: 0, shutdownDate: "0" }
  ) {
    vaultId
  }
}

```

{% endcode %}

{% code title="cURL request" overflow="wrap" %}

```bash
curl --location --request POST 'https://gateway.thegraph.com/api/{api-key}/subgraphs/id/Epp6gJotEJKAsJYdk7bDEURtGWWeZVXwZds2Pgw8eG51' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"{\n  vaults(\n    first: 1000\n    where: { isFinalized: true, totalHoldings_gt: 0, shutdownDate: \"0\" }\n  ) {\n    vaultId\n  }\n}\n","variables":{}}'
```

{% endcode %}

</details>

<details>

<summary>Fetch single vault details</summary>

The `{vaultId}` can be pulled from response on the Fetch all active vault ids request above, i.e. "0" is the CryptoPunks vault, and "1" is the Avastar vault.&#x20;

{% code title="GraphQL request" %}

```graphql
{
  vaults(
    first: 1000
    where: { vaultId: "{vaultId}" }
  ) {
    vaultId
    id
    is1155
    totalHoldings
    holdings(first: 1000, orderBy: tokenId, orderDirection: asc) {
      id
      tokenId
      amount
      dateAdded
    }
    token {
      id
      name
      symbol
    }
    fees {
      mintFee
      randomRedeemFee
      targetRedeemFee
      randomSwapFee
      targetSwapFee
    }
    usesFactoryFees
    asset {
      id
      name
      symbol
    }
    eligibilityModule {
      id
      name
      eligibleIds
      eligibleRange
    }
    features {
      enableMint
      enableRandomRedeem
      enableTargetRedeem
      enableRandomSwap
      enableTargetSwap
    }
  }
}

```

{% endcode %}

{% code title="cURL request" overflow="wrap" %}

```bash
curl --location --request POST 'https://gateway.thegraph.com/api/{api-key}/subgraphs/id/Epp6gJotEJKAsJYdk7bDEURtGWWeZVXwZds2Pgw8eG51' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"{\n  globals {\n    fees {\n      mintFee\n      randomRedeemFee\n      targetRedeemFee\n      randomSwapFee\n      targetSwapFee\n    }\n  }\n  vaults(\n    first: 1000\n    where: { vaultId: \"0\" }\n  ) {\n    vaultId\n    id\n    is1155\n    totalHoldings\n    holdings(first: 1000, orderBy: tokenId, orderDirection: asc) {\n      id\n      tokenId\n      amount\n      dateAdded\n    }\n    token {\n      id\n      name\n      symbol\n    }\n    fees {\n      mintFee\n      randomRedeemFee\n      targetRedeemFee\n      randomSwapFee\n      targetSwapFee\n    }\n    usesFactoryFees\n    asset {\n      id\n      name\n      symbol\n    }\n    eligibilityModule {\n      id\n      name\n      eligibleIds\n      eligibleRange\n    }\n    features {\n      enableMint\n      enableRandomRedeem\n      enableTargetRedeem\n      enableRandomSwap\n      enableTargetSwap\n    }\n  }\n}\n","variables":{}}'


```

{% endcode %}

</details>

<details>

<summary>Fetch singe vault holdings</summary>

The `{vaultId}` can be pulled from response on the Fetch all active vault ids request above, i.e. "0" is the CryptoPunks vault, and "1" is the Avastar vault.&#x20;

{% code title="GraphQL request" %}

```graphql
{
  vaults(
    where: { vaultId: "{vaultId}" }
  ) {
    totalHoldings
    holdings(first: 1000, orderBy: tokenId, orderDirection: asc) {
      id
      tokenId
      amount
      dateAdded
    }
  }
}

```

{% endcode %}

{% code title="cURL request" overflow="wrap" %}

```bash
curl --location --request POST 'https://gateway.thegraph.com/api/{api-key}/subgraphs/id/Epp6gJotEJKAsJYdk7bDEURtGWWeZVXwZds2Pgw8eG51' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"{\n  vaults(\n    where: { vaultId: \"0\" }\n  ) {\n    totalHoldings\n    holdings(first: 1000, orderBy: tokenId, orderDirection: asc) {\n      id\n      tokenId\n      amount\n      dateAdded\n    }\n  }\n}","variables":{}}'
```

{% endcode %}

</details>


# Brand Kit

Below you will find the main brand kit for NFTX.

## Logo

![The primary logo of NFTX.](/files/-MT_k82c5GPqWPkjmR1h)

Above is the primary logomark for the NFTX DAO. Please use the correct version, based on the background it is placed on, found below.

When you have further questions on usage, contact any of the contributors on our Discord.

**On White Background**

{% file src="/files/-MT\_nr8Nv4s1NXejtJ8j" %}
Logo SVG on White BG
{% endfile %}

{% file src="/files/-MT\_o1ADUZN\_bIM0r5\_x" %}
Logo PNG on White BG
{% endfile %}

**On Black Background**

{% file src="/files/-MT\_o58UsvcuUf6TfjDh" %}
Logo PNG on Black BG
{% endfile %}

{% file src="/files/-MT\_o9tHmiJIDGV2lljO" %}
Logo SVG on Black BG
{% endfile %}

## Logo**type**

![The logotype of NFTX.](/files/-MT_nZ9-sBFKi9UGC66Q)

Above is the logotype for the NFTX DAO. Please use the correct version, based on the background it is placed on, found below.

When you have further questions on usage, contact any of the contributors on our Discord.

**On White Background**

{% file src="/files/-MT\_oJpwEvVpa-N1\_r1u" %}
Logotype PNG on White BG
{% endfile %}

{% file src="/files/-MT\_oRII5-j1Tqsv\_pLU" %}
Logotype SVG on White BG
{% endfile %}

**On Black Background**

{% file src="/files/-MT\_oaBPDtw7P4v0Yx60" %}
Logotype PNG on Black BG
{% endfile %}

{% file src="/files/-MT\_oaBPDtw7P4v0Yx60" %}
Logotype SVG on Black BG
{% endfile %}

**Download all logos at once**

{% file src="/files/-MT\_ovlC3\_V9dS58wJNg" %}
NFTX Logopack ZIP file
{% endfile %}

## **Color Palette**

### **Primary color 1: Outrageous Orange**

![](/files/-MT_qNCWSESlxZNYn8tq)

**Hex: #**&#x46;F6D41

### **Primary color 2: Rose**

![](/files/-MT_qbEAeUt_9vfMwTK_)

**Hex: #**&#x46;A297F

## Favicons

{% file src="/files/-MT\_vjfNf2eAuGlMKls8" %}
NFTX Favicon set
{% endfile %}


# Introduction to NFTX

{% hint style="info" %}
If you are looking for the[ v1 documentation you can find them here](https://docs.nftx.org/v/v1.0/), or toggle the drop down under the logo on the left sidebar.
{% endhint %}

NFTX is a platform for creating liquid markets for illiquid Non-Fungible Tokens (NFTs).

Users deposit their NFT into an NFTX vault and mint a fungible ERC20 token (vToken) that represents a claim on a random asset from within the vault. vTokens can also be used to redeem a specific NFT from a vault.

**Benefits include:**

* LP and stake minted vTokens to earn yield rewards
* Better distribution and price discovery for NFT projects
* Instantly sell any NFT by minting it as an ERC20 and swapping via Sushiswap
* Increased liquidity for NFT investors and speculators

## How does it work?

### Vault Creation

Vaults can be created by anyone for any NFT asset on Ethereum. Once a vault has been created, any user can then deposit eligible NFTs into the vault to mint a fungible NFT-backed token referred to as an "vToken".

[Learn more about vault creation](/v2.0/tutorials/vault-creation)

### Minting vTokens

Anyone can deposit NFTs into an existing vault (or one they have created) in order to mint a fungible vToken that represents a 1:1 claim on a random NFT from within the vault.

[Learn more about minting](/v2.0/tutorials/minting)

### Floor Prices

Users can then pool their minted vTokens in Automated Market Makers (AMMs) like Sushiswap to create a liquid market for other users to trade. With liquidity and trading volume established, the NFT-backed vToken enters into price discovery and a "floor price" is discovered.

The floor price denotes the lowest price for a particular NFT. Users establish a floor price by minting and selling vTokens in markets where they consider their NFT to be overvalued.

{% hint style="info" %}
NFTX is helping to establish reliable floor price feeds for NFTs, enabling their wider application in decentralized finance on Ethereum.
{% endhint %}

For example, a user has 5 Hashmasks and values 2 of them highly. However, they consider the other 3 Hashmasks to be lower value than the market price for the Mask vault on Sushiswap. The user deposits these 3 Hashmasks and sells their 3 minted MASK tokens on Sushiswap, lowering its price and aiding price discovery.

The above process will continue until a floor price is achieved.

### Eligibilities

The Mask vault allows any Hashmask to be deposited, however other vaults use an eligibility list that only allows a specific sub-category of NFTs to be deposited. For example, the Kitty Gen 0 vault has an eligibility list that includes only Kitties whose metadata is Generation 0. Other Kitties can not be deposited into this vault.

## Who Benefits From NFTX?

### Collectors

NFTs in their basic form do not earn yield. However, when they are used to mint vTokens they can tap into the world of decentralized finance. Put simply, collectors can use NFTX to unlock more value from their NFTs:

* Earn protocol fees
* Earn trading fees as a liquidity provider
* Farm with stablecoins using vTokens as loan collateral

### Content Creators

By launching on the NFTX protocol, content creators are able to earn protocol fees in perpetuity whilst also improving the reach and fairness of distribution:

* Earn protocol fees
* Distribute NFTs via an AMM in the form of vTokens
* Create instantly liquid markets for new content

### Investors

NFTs are typically highly illiquid and difficult to price. NFTX makes speculating and investing in the NFT market a far simpler process:

* Access the most liquid markets for NFTs
* Track the price of particular categories of NFT


# FAQ

## Basics

### What is NFTX?

NFTX is a platform for making ERC20 tokens that are backed by NFT collectibles. These tokens are called vault tokens, and (like all ERC20s) they are fungible and composable. With NFTX, it is possible to create and trade tokens based on your favorite collectibles such as [CryptoPunks](https://www.larvalabs.com/cryptopunks), [CryptoKitties](https://www.cryptokitties.co/), and [Avastars](https://avastars.io/), right from an exchange.

NFTX's mission is to become the primary issuer of NFT vault tokens, allowing anyone to trade & invest in NFT markets without needing the underlying knowledge and expertise required when investing in individual assets. By doing so, NFTX will function as a black hole for NFT assets.

### Is NFTX fully permissionless?

Yes, NFTX contracts are fully permissionless on-chain contracts.

The [NFTX.org](https://nftx.org) interface is built and maintained by the NFTX DAO and will be open-sourced as soon as possible, for anyone to run locally when needed.

### Who is working on NFTX?

NFTX is built by a decentralized autonomous organization (DAO) - a group of community members, contributors, and core members closely aligned to build the primary NFT liquidity hub. As NFTX is an open organization, anyone anywhere may join to provide expertise and/or additional resources with the goal to grow NFTXs' success.

If you'd like to contribute to what NFTX is building, feel free to join the community [on Discord.](https://discord.gg/xcJkxMXSR8)

### Does NFTX charge any fees?

[NFTX V1](https://v1.nftx.org) does not charge any fees.

[NFTX V2](https://app.nftx.org) allows vault creators to charge fees based on minting and redeeming NFTs in and out of the vaults. There are three fee options in V2 and are set to the following defaults for all DAO and new vault creations

1. 5% Minting Fee&#x20;
2. 0% Random Redemption Fee
3. 5% Targeted Redemption Fee

These fees are distributed as rewards to the liquidity providers for the vault.

Anyone providing liquidity to vaults can bypass minting fees by using a zap to automatically include liquidity. Learn more in the [minting tutorial](/v2.0/tutorials/minting).

### Can you get rewards from using NFTX?

Yes. To encourage more liquidity for the vaults all fees that are generated from Minting and Target Redeptions are passed to anyone that is staking their LP against that vault. These rewards are paid out on a block-by-block basis, are are paid in the vault tokens you are using to stake.

You can see the APR for each of the different vaults on the [NFTX Staking](https://app.nftx.org/staking/) page.

### Is there an NFTX token?

Yes. The NFTX token is a governance token that can be used to vote on proposals and steer the direction of the organization. In total 650000 NFTX tokens will ever exist.

* 65K NFTX tokens are allocated to the founder of NFTX, Alex Gausman. These tokens are on a 5-year linear vesting schedule, without a cliff. Rewards on this vesting schedule are unlocked per block and added to the circulating supply until fully distributed.&#x20;
* 390K NFTX tokens were distributed during the origin community raise, which has taken place from December 2020 to early January 2021. The tokens were granted to early community members through open bounties at various rates of ETH, as well as several NFTs. You can find a full breakdown of this event [here.](https://nftx.gitbook.io/nftx/community-raise)
* 65K NFTX tokens were originally supplied as liquidity by the NFTX DAO on an AMM.
* 130K NFTX tokens are held in the NFTX DAO Treasury and used for additional market-making activities on vaults, such as the CryptoPunks vault.&#x20;

## Miscellaneous

### Who is the target audience of NFTX?

There are three main target audiences for NFTX: Investors, arbitrageurs, and NFT liquidity providers.

The main products are built for investors looking to buy and/or sell floor-priced NFTs without having to wait for a taker/maker on a secondary market.

The second audience we cater to are arbitrageurs, who can profit from ranging prices between NFT vault tokens and their underlying collaterals' floor prices on secondary markets. Arbitrageurs can use the products on nftx.org to interact directly with these pools.

A third audience we cater to are NFT liquidity providers, who can profit from providing additional liquidity and/or inventory to one or multiple NFT vaults. Liquidity providers may use the products on [nftx.org](https://app.nftx.org) to mint additional NFT vault tokens, which can then be supplied as liquidity.

### What is the NFTX token address?

The address of NFTX is: `0x87d73e916d7057945c9bcd8cdd94e42a6f47f776`

### How do I buy NFTX?

NFTX is available for trading on decentralized exchanges. To find the best rates across multiple exchanges, we recommend using an aggregator such as [Matcha](https://matcha.xyz/). A [detailed tutorial on how to do this can be found on our blog](https://blog.nftx.org/how-to-acquire-nftx-on-matcha/).

### Where do I find NFTX Vault Tokens?

V1 vaults can be viewed in the [Gallery](https://gallery.nftx.org/).

V2 NFTX Vaults can be found on the [App homepage.](https://app.nftx.org)


# Minting

NFTX v2 introduces a new minting interface that allows you to easily mint a liquid ERC20 token from your NFT!

![](/files/-McpuD8b3UMvcSz7epak)

## Why mint an NFT?

By adding your NFT to an NFTX vault you mint an ERC-20 token (vToken) that has a 1:1 claim on a random NFT inside the vault.

Unlike a non-fungible token (NFT), an ERC-20 is fungible (all tokens are the same) and this allows it to be:

* Instantly sold at an AMM (like Sushiswap)&#x20;
* Pooled in an AMM to earn trading fees
* Staking
* Used as collateral to borrow stablecoins

vTokens can be used to redeem a random vault NFT at any time.

## Minting Step-by-step

### Choose your vault

The initial mint view shows all the current NFTX Vaults that you are able to mint into based on the contents of your connected wallet. In this example we're going to select the [Avastr vault](https://v2.nftx.org/mint/0xdcdc1c1cc33aa817cbdbe8f5e2390bf7cc43dc4b/).

![](/files/-Mcpv0RcpHNAtgzg9a1c)

### Selecting NFTs

Choose the NFTs from your wallet that you would like to mint to the vault. Remember, the vaults are often floor vaults and minting a higher value NFT will provide the same result as a lower value NFT from the collection.

![](/files/-McpwtBH3Ryx3bz_nUJY)

Not seeing your NFT? [See our FAQ](https://docs.nftx.org/tutorials/get-started-v1.x/minting#faq).

### Mint Basket

The mint basket will show you the NFTs you have selected, their approval status, mint fee and the number of tokens you will recieve after minting.

{% hint style="info" %}
Although not shown in the screenshot below, you will sometimes need to "Approve" the NFTs to be minted into the Vault. Once Approved, the "Mint AVASTR" (or relevant NFT name) will appear and you can complete the minting process.
{% endhint %}

![](/files/-Mcpxbd_FcGs2q86b2mi)

#### Approval

Your NFTs will need to be approved for use by the NFTX contract before they can be minted into an ERC-20. To approve all your NFTs in this contract (i.e. the Wrapped Punks contract), click "Approve all".

**Mint fee & Tokens received**

The mint fee is new in v2 and will be distributed 100% to the liquidity providers.  The fee is set to a default of 5%, however during the vault creation process this can be changed to any value. Once the vault is published, only the DAO is able to update the mint fees via a governance vote.

With a 5% mint fee, each NFT minted will result in the distribution of 0.95 vTokens (in this case AVASTR tokens) with the remainder distributed to the liquidity providers.

### **Minting**

With your NFTs approved and your mint value confirmed, click the "Mint" button to generate your vTokens. Each NFT will return a single vToken, minus the mint fee.

For example, minting 2 Avastars to the Avastar vault will return 1.9 AVASTR ERC-20 tokens.

{% hint style="info" %}
It is important to mint your NFT to the appropriate vault. Do not mint high value NFTs (i.e. a Avastar Rank 70) to a lower value vault (i.e. AVASTR).
{% endhint %}

### Bypass Mint Fee's with Zaps

To encourage more liquidity for the vaults we allow users to avoid paying the mint fee if they choose to stake liqudity for a minimum of 48 hours.

Below shows the two options

1. 5% mint fee and get back 0.95 vTokens
2. 0% mint fee and get back 1 vToken

![With your NFT in the basket you can choose to pay the mint fee, or bypass the fee by Minting & Staking](/files/-MfcdOoSzS70SSvplLOB)

Choosing the Mint & Stake option requires an additional confirmation step, also shown below. This provides an overview of the number of tokens you are pairing, and the amount of ETH you need to pair for the pool.

* **Pool share** — the share of the fee's earned on this vault that you will get each block. In this case, it is 50% of the fee distribution.
* **Mint fee** — you are being waived the mint fee for staking your liquidity for 48 hours.
* **Lock time** — the length of time your position will be locked. After 48 hours you can unstake and withdraw your liquidity.

![](/files/-MfceHJ07J-vVV1Sz1zF)

{% hint style="danger" %}
Remember that if you already have a position on the vault your entire position will be locked for the 48 hours, not just the amount you are zapping on this process. This does not affect any other positions you might have in other vaults on NFTX.
{% endhint %}

Once you have confirmed the Mint & Stake you can view the Staking page to see your positions, and the time left on your locked positions.

![](/files/-MfcfWVMhzZKY923T6Hv)

### Mint Requests

In v2 there are no longer any mint requests.

## FAQ

### Why aren't my NFTs showing in the minter?

If you can't see an asset it will be for one of the following reasons:

#### Your NFT is not eligible for the vault

Some vaults use eligibilities to ensure that only certain sub-categories of an NFT can be included. For these vaults, it may be possible to send a [mint request](https://docs.nftx.org/tutorials/get-started-v1.x/minting#mint-requests).

#### Your NFT requires wrapping

NFTs that were developed several years ago did not follow the ERC721 or ERC1155 token standard. Unlike in V1, the V2 vaults now support unwrapped Mooncats and CryptoPunks.

#### You have just received your NFT

We use the OpenSea API to list the available NFTs that you may have in your wallet. The API can sometimes take a few minutes to update. Please wait 5 minutes and if it is still not showing, reach out to us on Discord.

#### Your wallet contains more than 1,000 NFTs

We currently limit the minter to scanning a wallet's first 1,000 NFTs that may be available for minting. If you have more than 1,000 NFTs in your wallet please reach out to us on Discord for assistance.

### Can I get my NFT back once I've added it to a vault?

A vToken provides a claim on a single asset within a vault. In v2 we have introduced targeted redeems which allows you to choose any NFT from the vault for a 5% premium (this is the default settings, vault owners can change this value during the vault creation process).

You can buy additional vTokens from SushiSwap, and we will soon allow you to make up the additional costs with ETH directly from the App.

### My NFT can be deposited in multiple vaults, which one do I choose?

Some NFTs are eligible to be deposited to multiple vaults. While this is still possible in v2, the initial vaults created have moved away from multiple vaults for the same NFT and towards floor vaults.

Always check an NFT's available vaults before minting an vToken to ensure the most appropriate one is selected.

### I've minted my NFT but I haven't received my Token yet

You need to add the vault token as a custom token to your metamask wallet (see [an example of how to add custom tokens here](https://blog.nftx.org/how-do-i-view-my-nftx-tokens-in-metamask/#how-can-you-see-your-nftx-tokens-inside-of-metamask))


# Redeeming

![](/files/-MdRiaiaWOVeOpAOL67p)

NFTX v2 allows you to easily redeem your [minted](/v2.0/tutorials/minting) ERC20 Vault Tokens (vTokens) for either a random or targeted NFT within the vault.

## Why redeem an NFT?

Redemptions allow users to take ownership of an underlying NFT from within a vault. This means that a user can go to an AMM like Sushiswap, purchase a single vToken like PUNK and use that token to claim a random CryptoPunk from the [PUNK Vault](https://app.nftx.org/redeem/0x269616d549d7e8eaa82dfb17028d0b212d11232a/).

For an additional fee, usually 5% (1.05 vTokens), users are able to select a specific NFT from the vault.

## Redeeming Step-by-Step

### vToken Balance

![This shows that I have 4 BUNNY tokens which will allow me to claim back 4 random Genbit Bunnies from the Vault](/files/-MdRj0z1_992guGYCRVg)

When you visit <https://app.nftx.org/redeem> and connect your wallet, your vToken and NFTX balances will be displayed on the right hand side. Each vToken represents a claim on a random NFT from within its vault.

You can also target redeem specific NFTs from the vault by paying the Targeted Redeem fee — often 5% or 1.05 vTokens.

{% hint style="info" %}
Don't have any vTokens? [Visit the App](http://app.nftx.org) to browse the available vaults. Once inside the vault you can click on "Buy {vToken}" and pick it up from SushiSwap.

{% endhint %}

![](/files/-MfchG2myTAElOd1cebP)

### Redeeming — Random

To redeem an NFT you must enter the quantity you would like to redeem (in whole numbers) next to the "Random" section in the redemption baskset and approve the NFTX contract. Once the approval transaction has been confirmed, you will then be able to redeem the desired number of NFTs from the vault.

![Here I am redeeming 2 random Genbit Bunnies using 2 BUNNY tokens](/files/-MdRkGD135czAQkiPPlE)

### Redeeming — Targeted

New in V2 is the option to choose the NFT you wish to redeem from the vault.

Select the NFT you wish to redeem from the vault and they will be added to the redeem basket. Note that each targeted redeem will require 1 vToken plus the fee set for targetted redeems on the vault. This fee defaults to 5% on vault creation, but can be changed by the vault creator prior to finalising the vault. Once finalised, the fee's can only be updated by the DAO via a governance vote.

If the vault is left at the default settings, each targeted redeem will cost 1.05 vTokens.

![Three Bunnies are being targetted redeem for 3.15 vTokens](/files/-MdRlUeoK_gITqXNChXi)

## FAQ

### Can I redeem from a vault without a vToken?

Users must have a vToken in their wallet balance to redeem from a vault. To browse the available vaults and vault NFTs, please visit the [home page of the App](https://app.nftx.org).


# Staking

## Why stake on NFTX?

Earn fees from the vault, currently 100% of protocol fees are paid out to those that stake. Stakers also receive an ERC20 “xToken” like xPUNK that is a claim on the underlying staked SLP. We expect other projects to build use cases for these xTokens.

{% hint style="info" %}
APRs are calculated by annualizing the last 7 days of the vault's fee earnings. The real rate of return will vary throughout the year.
{% endhint %}

## How to stake on NFTX?

To stake on NFTX you first need to get a token for one of the NFTX vaults. In this example we're going to look at the AVASTR vault.

### Get a vToken

There are two ways that you can get a vToken (vault Token) from NFTX. Head to <https://app.nftx.org> and you will see a list of the current vaults you can mint into based on the NFTs in your wallet

![The NFTs in my wallet that match the Vaults already created in NFTX v2](/files/-MdORY54I2kSsXPNMWS_)

In this example I'm going to mint one of my Avastars into the AVASTR vault. I choose the Avastar that I would like to mint and select "Mint AVASTR". This provides me a single AVASTR token back.

![](/files/-MdORiUoGAu-aZ99TJF5)

Alternatively, you can go to the Redeem section of the app and look to redeem an Avastar from the vault. From here you will have a link to buy an AVASTR token directly from Sushi.

![](/files/-MdOUdt_XXugKfhPqbxb)

With a vToken, in this case an AVASTR token, you can head over to the [Staking](https://v2.nftx.org/staking/) page.

### Add Liquidity

From the Staking page you can find the pair that you want to provide liquidity for, in this case it is the AVASTR-ETH SLP, and we want to Add Liquidity to that pool

![](/files/-MdOVa-6T0hNqbUYCOyH)

From this page you can add the amount of AVASTR you want to add to the pool, and the relevant amount of ETH will be calculated below. If you are the first liquidity provider then you will need to set the initial price, which should be the floor price of the NFTs for the vault. One way to calculate this is to search for your NFT contract on OpenSea with the filter Buy Now and order from Lowest to Highest sale price.

![](/files/-MdOW-IClevHaiBad_uD)

Once you have confirmed adding liquidity you will be issued with pool tokens.

### Stake your LP

With your pool tokens you can return to the Staking screen, Approve the use of the SLP (this will be where the "Deposit SLP" button can be seen), and then "Deposit SLP".

![](/files/-MdOWjRyE1oApZcYcj7c)

Once completed, any pools that you are currently staking will be shown at the top of the staking page with details on your APY, Staked amount, Earnings, and Claimable AVASTAR tokens.

![](/files/-MdOXKcNxJMkFQWd6Fbg)

{% hint style="success" %}
Staking rewards are now active!
{% endhint %}

## Removing Liquidity from V1 Vaults <a href="#docs-internal-guid-227675f5-7fff-e5b1-c52b-9d3c69bb7b2e" id="docs-internal-guid-227675f5-7fff-e5b1-c52b-9d3c69bb7b2e"></a>

### Overview

With the release of NFTX Version 2 there is more benefit from moving your position from the old vaults on V1 to the new vaults on V2.

For an overview on the release of NFTX V2 you can read the blog, however in this tutorial we’re going to focus on how you can remove your liquidity from existing vaults on V1.

### Steps to remove your liquidity

Head over to the pool which you are providing liquidating. An easy way to do this is to find the Vault on the [gallery](https://gallery.nftx.org) and select the “Swap on Sushi” button.

Choose the “Liquidity” tab from that pool and then select “Remove” from the options. In this case we’re going to remove all of our liquidity from the pool and we will get back 0.0811434 ETH and 2.09975 TWERKY tokens.

You will first need to “Approve” the transaction and then “Confirm Withdrawl”.

![](https://lh5.googleusercontent.com/UtVb7DxosPHqg3xGk-U8l7D5JHWBn4wJ_91sONewx6uR9ZdDLxBBifxM87JxfoWwpt2F4oNL4qFuy692uNzXDXQMVR9omEGkceWlbC6fcnz132BMAoKMxbeWJwr0qfMbiem0h6PH)

{% hint style="info" %}
Note: there is no rush for you to remove your liquidity from the pool, especially while GAS prices are high.
{% endhint %}

Once the transaction has been processed you will receive a confirmation along with details about the final Tokens and ETH returned.

![](https://lh5.googleusercontent.com/vbZxAEl2uujYEo17DPN-3ByK4pU-PSfT8XZyJAQmauL8ejnb9gQJFzGrCs-7fYsJ1nQbFSI83N6ZN_cmrp_2RPuWDnXJfIebHnBIW8wRVnWl7LMloC2HTdO15YwPsRm7tW1Dz8uv)

You will now be able to view your tokens in Metamask, and if you go to the NFTX App you can see your tokens in the header and sidebar.

![](https://lh6.googleusercontent.com/Il6GjVs7IuJRVuG-H7Eyz2ArG9iq5XSmfjyYMzuJd9p20TTDTZbhDYOoliyrFm0UP3_9yYmIz9VF_OkMfNJTA2JXmI7fye7FrhUh1xMK02DgvtabH9rV7q3bUM9D5bnhB37s1buv)

With you tokens you can now Redeem your NFTs from the Vault which will then allow you to

### FAQs

#### Why has my claimable balance not increased?

Rewards are earned when the vault generates fees. APRs are calculated based on the last 7 days of vault fees.

#### Do I have to remove my Liquidity?

No. You can keep your liquidity on the current vaults in V1 for as long as you would like and continue to earn fees on the trades on SushiSwap.

You will not be able to stake your liquidity and earn any of the 5% minting and 5% targeted fees on the new vaults unless you become a liquidity provider on V2.

#### I still have fractions of a token left after withdrawing my liquidity, what can I do?

These fractions of tokens are often referred to as dust. You have three options.

1. Sell the fractions of the token you have on a DEX like SushiSwap.  For low value NFTs there is a good chance that the GAS cost of this transaction will exceed the value of the dust.
2. Buy more of the token to take you up to one full token and use it to redeem an NFT from the pool.
3. Hold onto the dust until NFTX move towards a buyout. We expect there will be one NFT stuck in each of the vaults due to the dust and reduction of the liquidity. There are two options for resolving this which the DAO will vote on in the next few months
   1. The DAO will sell the final NFT and provide the fractionalised value of the sale to the dust holders.
   2. The DAO will propose to buy back the dust to retrieve the final NFT and keep it in the treasury

#### When will the NFTX DAO remove their liquidity from the V1 Vaults?

The DAO will remove their Liquidity in thirds across three weeks starting from the public release of V2. This is to ensure that holders of the NFT Tokens have time to sell their position without any major slippage/price impact.

{% hint style="info" %}
Lower liquidity does not impact the redeeming of NFTs from the V1 Vaults. 1 Token is always worth 1 NFT from the corresponding vault.
{% endhint %}


# Vault Creation

NFTX v2 introduces a new vault creation interface that allows you to easily create a public vault for any NFT or a specific subset of IDs for an NFT.

[Watch the video tutorial for creating vaults on NFTX V2](https://www.youtube.com/watch?v=Yt2aU7hxMmc)

## Why create a vault?

Vault creation is at the heart of the NFTX protocol and allows users and content creators to begin [minting](/v2.0/tutorials/minting) fungible ERC20 tokens for any NFT.

By creating NFT-backed ERC20 tokens, users can create liquid markets for otherwise illiquid NFTs whilst also earning fees and rewards from liquidity provision.

Protocol fees have been introduced in V2 of the NFTX.

## Vault Creation Step-by-Step

### Create NFTX Vault

Three fields are required to create an NFTX vault as shown below.

![](/files/-MdO9gfUDg6kwXtFf3-z)

**NFT Asset Address**

The NFT asset address is immutable and points to the contract from which this vault will accept mints. By default, all NFT IDs from this contract will be eligible for minting in the vault.

{% hint style="info" %}
Eligibility lists or ranges can be added once the vault has been created. This will allow you to target specific NFT IDs for groups of NFTs like "Female Punks", or create NFT ID ranges for specific projects like "720 Minutes" from Art Blocks, from within a single NFT contract address.
{% endhint %}

Some assets are already used in other vaults. For example, Art Blocks are used in multiple vaults and separated using eligibility ranges. To avoid adding a duplicate vault and splitting liquidity, review the matching vaults list before proceeding.

![](/files/-MdOB46FGxvhJe2IK9b2)

**Vault Name**

This will be the *name* of the ERC20 token that is minted from this vault.

**Vault Symbol**

This will be the *symbol* of the ERC20 token that is minted from this vault.

Both the Vault Name and Vault symbol will appear anywhere that this token appears, from CoinGecko and Etherscan through to Sushi and Uniswap.

{% hint style="info" %}
A strong name and symbol play a critical part in a vault's long-term success. Try to keep the name singular (PUNK, not PUNKS), six characters or less (to enable ticker links in Twitter), and use a real word where possible (BUNNY, not GENBIT).
{% endhint %}

### Vault Created

![](/files/-MdOCAH12z-1ZdT2sLW8)

Once your create vault transaction has been confirmed onchain you will be notified and asked to proceed to managing your vault.

Your vault will not be visible in the NFTX app until it has been minted to and published. Click "Manage Vault" to complete the process.

### Manage Vault

Vault management allows vault creators to modify a number of important settings as well as publishing the vault so that it becomes visible on the NFTX app.

{% hint style="warning" %}
Published vaults cannot be edited by the creator, only the DAO can make updates to published vaults. Carefully review the vault's settings before publishing, including setting the Fees and Eligibility screens.
{% endhint %}

![](/files/-MdOCO-9cbmhlREYidbh)

#### **Enable Vault Features**

**Enable Minting —** The most important part of creating a vault is allowing users to mint their NFTs in. If you wanted to use the vault as a way to airdrop tokens for users to redeem NFTs from the vault you might disable the mint feature.

**Enable Random Redeems —** Allow users to randomly retrieve an NFT from your vault.

**Enable Target Redeems** — Users will be able to choose the NFTs they are redeem from the vault for an additional fee which you can set within the Fees section.

#### Fees

![](/files/-MdOE2DCGjhcrszywfeG)

Fees can now be set on the individual vaults which will then be distributed to the liqudity providers staking their LP. By default all new vaults are set with 5% Mint Fee (meaning you receive 0.95 tokens for each NFT minted), 0% Redeem Fee (so 1 token always can redeem 1 random NFT from the vault), and a 5% Targeted Redeem Fee (1.05 tokens are needed to choose the NFT you want from the vault).

When you first create the vault, and ***before*** you finalise the vault, you can set the mint fees to 0% to encourage the initial seeding of the vault. Once seeded, ensure that you change the fee back to 5% before finanlising the vault or no fees will be generated on minting NFTs.

{% hint style="info" %}
Don't forget that you can use Zaps to bypass the 5% mint fee by providing ETH liquidity for the vault and staking it to earn yourself fees. Find out more on [Bypassing Mint Fee's with Zaps](/v2.0/tutorials/minting#bypass-mint-fees-with-zaps).
{% endhint %}

#### **Eligibilities**

![](/files/-MdOFTQMpIaVJi-8D7Dm)

A vault's eligibility list is an allow list or range of NFT IDs that can be minted to this vault.

**List Module**

![](/files/-MdOFqbcqSuXlHsB_6F4)

Use this setting to specific individual IDs to add to the eligibility list.

**Eligibility Range**

![](/files/-MdOFv3LoJMgO4fBhsrJ)

For blocks of eligible IDs, use this setting to specify the "from" and "to" (inclusive) IDs that will be added to the eligibility list. **These work well for projects like Art Blocks Curtated which are all minted from the same contract but have distinct ranges for each project.**

### Publishing your Vault

Before your vault will be visible on the app you will need to mint at least one eligible NFT.

![](/files/-MdOHV28-BuzaihOiLff)

Once you've added one or more NFTs to your new vault you will have the option to publish your vault. Remember, once the vault has been published the ownership is passed to the DAO and you will no longer be able to update the Fees or Eligibilities.

![](/files/-MdONdkyk_-oqA8AE4cc)

![Last chance. You are asked to confirm your setting for Fees](/files/-MdONlaXpuD0QfeJJQP8)

Once confirmed you will be redirected to the vault detail page. On this page it will provide you with an overview of the vault details, including Vault ID, URL, Token Address, current Holdings, and Lifetime Fees.

![](/files/-MdOOAL6HkKVN3CogtOv)

## FAQ

### I am being warned about the vault name or symbol, what does this mean?

Naming conventions provide structure for NFTX vaults that makes them instantly recognisable across platforms and help improve the network effects for all participants in the NFTX ecosystem.

**Naming conventions**

| Vault Name                 | Vault Symbol                                     |
| -------------------------- | ------------------------------------------------ |
| Alphanumeric only          | Less than 7 characters                           |
| Capitalized (i.e. Meebits) | Singular (i.e. PUNK for CryptoPunks floor vault) |
|                            | Uppercase                                        |
|                            | Real words where possible                        |

The tight recommendations on Vault Symbol are in place to conform to Twitter's cashtag standard.

### Why isn't my vault isn't showing in the NFTX app?

The most common reason for this is that your vault does not yet have holdings or has not been published. To add holdings, visit the vault management page and click "Add Holdings".


# Bug Bounty

The NFTX Bounty program rewards users that discover and properly disclose found bugs with predefined bounties. We encourage anyone to help strengthen the protocol by actively searching for bugs in NFTX contracts.

The NFTX bounty program is derived from the Ethereum Bounty Program, an industry standard when it comes to rightfully rewarding bug bounty hunters.

Please send vulnerability submissions to <bounty@nftx.org>

{% hint style="info" %}
The NFTX V2 contracts have been through the Code Area bug bounty programme A number of vulnarabilities were flagged that were either fixed or acknowledge which you can review <https://code423n4.com/reports/2021-05-nftx/>.

Please check these prior to submitting your bug bounties as anything already identified here is unlikely to qualify for this Bug Bounty programme outlined below.
{% endhint %}

## Rules and Rewards

Please have a look at the bullets below before starting your hunt!

* Issues that have already been submitted by another user or are already known to the NFTX team are not eligible for bounty rewards (this includes the [Code Area report](https://code423n4.com/reports/2021-05-nftx/)).
* Public disclosure of a vulnerability makes it ineligible for a bounty.
* You can start or fork a private chain for bug hunting. Please respect the NFTX main and test networks and refrain from attacking them.
* All NFTX members paid by the DAO are not eligible for rewards.
* NFTX websites or organizational infrastructure in general, are NOT part of the bounty program.
* NFTX bounty program considers a number of variables in determining rewards. Determinations of eligibility, score and all terms related to an award are at the sole and final discretion of the NFTX DAO.

The value of rewards paid out will vary depending on Severity. The severity is calculated according to the [OWASP](https://www.owasp.org/index.php/OWASP_Risk_Rating_Methodology) risk rating model based on Impact and Likelihood :

![Severity](https://lh3.googleusercontent.com/B-RaTD0aLBUht3y-NEPSja8vhSyncCHm28gWdE2uIjEfYjL4ceG9kEbcSR2n5IBAExH8uj57jamcoI6eY_ewLfRGBaIdZQD9dYGoQ56rDFA1WGYFEC9JIKRWHjGpog9yYL6OvvVt)

Reward sizes are guided by the rules below, but are in the end, determined at the sole discretion of the NFTX DAO.

* Critical: up to 50 000 USD
* High: up to 30 000 USD
* Medium: up to 20 000 USD
* Low: up to 4 000 USD
* Note: up to 1000 USD

Bounties may be paid out in USD, ETH or NFTX tokens.

In addition to Severity, other variables are also considered when the NFTX DAO decides the score, including (but not limited to):

* Quality of description. Higher rewards are paid for clear, well-written submissions.
* Quality of reproducibility. Please include test code, scripts and detailed instructions. The easier it is for us to reproduce and verify the vulnerability, the higher the reward.
* Quality of fix, if included. Higher rewards are paid for submissions with clear descriptions of how to fix the issue.

**Important Legal Information**

The bug bounty program is an experimental and discretionary rewards program for our active NFTX community to encourage and reward those who are helping to improve the platform. It is not a competition. You should know that we can cancel the program at any time, and awards are at the sole discretion of the NFTX DAO. You are responsible for all taxes. All awards are subject to applicable law. Finally, your testing must not violate any law or compromise any data that is not yours.

### Bounty Scope

The above mentioned bug bounty rules and rewards are applicable to all smart contracts that are actively being used and/or promoted by NFTX.

When in doubt about whether the bug applies to the bounty program, please contact the DAO by sending an email to <bounty@nftx.org>.


# Contract Addresses

| **Contracts**           | **Code** | **Mainnet**                                  |
| ----------------------- | -------- | -------------------------------------------- |
| StakingTokenProvider    | GitHub   | `0x5fAD0e4cc9925365b9B0bbEc9e0C3536c0B1a5C7` |
| Staking                 | GitHub   | `0x688c3E4658B5367da06fd629E41879beaB538E37` |
| Vault template          | GitHub   | `0xe8B6820b74533c27786E4724a578Bfca28D97BD1` |
| FeeDistributor          | GitHub   | `0x7AE9D7Ee8489cAD7aFc84111b8b185EE594Ae090` |
| VaultFactory            | GitHub   | `0xBE86f647b167567525cCAAfcd6f881F1Ee558216` |
| EligibilityManager      | GitHub   | `0x4086e98Cce041d286112d021612fD894cFed94D5` |
| ProxyController address | GitHub   | `0x4333d66Ec59762D1626Ec102d7700E64610437Df` |
| NFTXStakingZap          | Github   | `0x0b8ee2ee7d6f3bfb73c9ae2127558d1172b65fb1` |


# Subgraph

The NFTX subgraph can be used to query protocol holdings, fees, users and more.

* **Subgraph:** <https://thegraph.com/legacy-explorer/subgraph/nftx-project/nftx-v2>
* **GitHub repo:** <https://github.com/NFTX-project/nftx-v2-subgraph>


# Dune Analytics

NFTX has a Dune Analytics dashboard for the protocol and each individual vault.

* **Protocol Dashboard**: <https://dune.xyz/nftx/NFTX-Dune-Dashboard-Protocol-View>
* **Vault Dashboard**: <https://dune.xyz/nftx/NFTX-Dune-Dashboard-Single-Vault-View>

To use the Vault Dashboard, enter the vault contract address into the `Vault_Address` input at the top of the page. Alternatively, go directly via this URL, replacing {vault\_address} with the vault's address:

<https://dune.xyz/nftx/NFTX-Dune-Dashboard-Single-Vault-View?Vault\\_Address=**{vault\\_address}>\*\*


# Brand Kit

Below you will find the main brand kit for NFTX.

## Logo

![The primary logo of NFTX.](/files/-MT_k82c5GPqWPkjmR1h)

Above is the primary logomark for the NFTX DAO. Please use the correct version, based on the background it is placed on, found below.

When you have further questions on usage, contact any of the contributors on our Discord.

**On White Background**

{% file src="/files/-MT\_nr8Nv4s1NXejtJ8j" %}
Logo SVG on White BG
{% endfile %}

{% file src="/files/-MT\_o1ADUZN\_bIM0r5\_x" %}
Logo PNG on White BG
{% endfile %}

**On Black Background**

{% file src="/files/-MT\_o58UsvcuUf6TfjDh" %}
Logo PNG on Black BG
{% endfile %}

{% file src="/files/-MT\_o9tHmiJIDGV2lljO" %}
Logo SVG on Black BG
{% endfile %}

## Logo**type**

![The logotype of NFTX.](/files/-MT_nZ9-sBFKi9UGC66Q)

Above is the logotype for the NFTX DAO. Please use the correct version, based on the background it is placed on, found below.

When you have further questions on usage, contact any of the contributors on our Discord.

**On White Background**

{% file src="/files/-MT\_oJpwEvVpa-N1\_r1u" %}
Logotype PNG on White BG
{% endfile %}

{% file src="/files/-MT\_oRII5-j1Tqsv\_pLU" %}
Logotype SVG on White BG
{% endfile %}

**On Black Background**

{% file src="/files/-MT\_oaBPDtw7P4v0Yx60" %}
Logotype PNG on Black BG
{% endfile %}

{% file src="/files/-MT\_oaBPDtw7P4v0Yx60" %}
Logotype SVG on Black BG
{% endfile %}

**Download all logos at once**

{% file src="/files/-MT\_ovlC3\_V9dS58wJNg" %}
NFTX Logopack ZIP file
{% endfile %}

## **Color Palette**

### **Primary color 1: Outrageous Orange**

![](/files/-MT_qNCWSESlxZNYn8tq)

**Hex: #**&#x46;F6D41

### **Primary color 2: Rose**

![](/files/-MT_qbEAeUt_9vfMwTK_)

**Hex: #**&#x46;A297F

## Favicons

{% file src="/files/-MT\_vjfNf2eAuGlMKls8" %}
NFTX Favicon set
{% endfile %}


# Introduction to NFTX

NFTX is a platform for creating liquid markets for illiquid Non-Fungible Tokens (NFTs).

Users deposit their NFT into an NFTX vault and mint a fungible ERC20 token (vToken) that represents a claim on a random asset from within the vault.

**Benefits include:**

* Use minted vTokens to earn yield
* Better distribution and price discovery for NFT projects
* Instantly sell any NFT by minting it as an ERC20 and swapping via Sushiswap
* Increased liquidity for NFT investors and speculators

### How does it work?

#### Vault Creation

Vaults can be created by anyone for any NFT asset on Ethereum. Once a vault has been created, any user can then deposit eligible NFTs into the vault to mint a fungible NFT-backed token referred to as an "vToken".

[Learn more about vault creation](/v1.0/tutorials/vault-creation)

#### Minting vTokens

Anyone can deposit NFTs into an existing vault (or one they have created) in order to mint a fungible vToken that represents a 1:1 claim on a random NFT from within the vault.

[Learn more about minting](/v1.0/tutorials/minting)

#### Floor Prices

Users can then pool their minted vTokens in Automated Market Makers (AMMs) like Sushiswap to create a liquid market for other users to trade. With liquidity and trading volume established, the NFT-backed vToken enters into price discovery and a "floor price" is discovered.

The floor price denotes the lowest price for a particular NFT. Users establish a floor price by minting and selling vTokens in markets where they consider their NFT to be overvalued.

{% hint style="info" %}
NFTX is helping to establish reliable floor price feeds for NFTs, enabling their wider application in decentralized finance on Ethereum.
{% endhint %}

For example, a user has 5 Hashmasks and values 2 of them highly. However, they consider the other 3 Hashmasks to be lower value than the market price for the Mask vault on Sushiswap. The user deposits these 3 Hashmasks and sells their 3 minted MASK tokens on Sushiswap, lowering its price and aiding price discovery.

The above process will continue until a floor price is achieved.

#### Eligibilities

The Mask vault allows any Hashmask to be deposited, however other vaults use an eligibility list that only allows a specific sub-category of NFTs to be deposited. For example, the Punk-Female vault has an eligibility list that includes only female CryptoPunk NFT IDs. Other CryptoPunks cannot be deposited.

### Who Benefits From NFTX?

#### Collectors

NFTs in their basic form do not earn yield. However, when they are used to mint vTokens they can tap into the world of decentralized finance. Put simply, collectors can use NFTX to unlock more value from their NFTs:

* Earn protocol fees (coming soon)
* Earn trading fees as a liquidity provider
* Farm with stablecoins using vTokens as loan collateral

#### Content Creators

By launching on the NFTX protocol, content creators are able to earn protocol fees in perpetuity (coming soon) whilst also improving the reach and fairness of distribution:

* Earn protocol fees (coming soon)
* Distribute NFTs via an AMM in the form of vTokens
* Create instantly liquid markets for new content

#### Investors

NFTs are typically highly illiquid and difficult to price. NFTX makes speculating and investing in the NFT market a far simpler process:

* Access the most liquid markets for NFTs
* Track the price of particular categories of NFT


# FAQ

## Basics

### What is NFTX?

NFTX is a platform for making ERC20 tokens that are backed by NFT collectibles. These tokens are called funds, and (like all ERC20s) they are fungible and composable. With NFTX, it is possible to create and trade funds based on your favorite collectibles such as [CryptoPunks](https://www.larvalabs.com/cryptopunks), [Axies](https://marketplace.axieinfinity.com), [CryptoKitties](https://www.cryptokitties.co/), and [Avastars](https://avastars.io/), right from an exchange.

NFTX's mission is to become the primary issuer of NFT index funds, allowing anyone to invest in NFT markets without needing the underlying knowledge and expertise required when investing in individual assets. By doing so, NFTX will function as a black hole for NFT assets.

### How are NFT index funds useful?

Investing in NFTs is booming. For example, Delphi Digital [invested for over 150k in *digital collectible pets* called Axies](https://www.delphidigital.io/reports/why-we-spent-159k-on-digital-battle-pets-2/), which are the main game collectibles for the highly successful game [Axie Infinity.](https://www.axieinfinity.com)

However, there are many people, organizations, and institutions that don’t have the time or knowledge to invest in individual NFTs but would like exposure to NFT markets. These are the NFTX target users—the people investing in NFT index funds on an exchange, rather than buying specific NFTs.

Most of the time the only people minting/redeeming fund tokens will be arbitrageurs. This is similar to the dynamic with WBTC. Most people that trade WBTC do not mint and burn it themselves.

### Is NFTX fully permissionless?

Yes, NFTX contracts are fully permissionless on-chain contracts.

The NFTX.org interface is built and maintained by the NFTX DAO and will be open-sourced as soon as possible, for anyone to run locally when needed.

### Who is working on NFTX?

NFTX is built by a decentralized autonomous organization (DAO) - a group of community members, contributors, and core members closely aligned to build the primary NFT index fund ecosystem. As NFTX is an open organization, anyone anywhere may join to provide expertise and/or additional resources with the goal to grow NFTXs' success.

If you'd like to contribute to what NFTX is building, feel free to join the community on Discord.

### Does NFTX charge any fees?

There are currently no fees charged on NFTX.

In the future, charging fees on managing index funds is one of the ways the NFTX token can accrue more value. The implementation of this will be decided by NFTX token holders.

### Is there an NFTX token?

Yes. The NFTX token is a governance token that can be used to vote on proposals and steer the direction of the organization. In total 650000 NFTX tokens will ever exist.

* 65K NFTX tokens are allocated to the founder of NFTX, Alex Gausman. These tokens are on a 5-year linear vesting schedule, without cliff. Rewards on this vesting schedule are unlocked per block and added to the circulating supply until fully distributed.&#x20;
* 390K NFTX tokens were distributed during the origin community raise, which has taken place from December 2020 to early January 2021. The tokens were granted to early community members through open bounties at various rates of ETH, as well as several NFTs. You can find a full breakdown of this event [here.](/v1.0/archive/community-raise)
* 65K NFTX tokens are supplied as liquidity by the NFTX DAO on an AMM.
* 130K NFTX tokens are held in the NFTX DAO Treasury, earmarked to use as liquidity farming rewards, which will start in Q1 or Q2 of 2021. No further details about this program are currently available.

![](/files/-MQ4J7W9K9DDB9e9GMW-)

## Miscellaneous

### Who is the target audience of NFTX?

There are three main target audiences for NFTX: Investors, arbitrageurs, and NFT liquidity providers.

The main products are built for investors looking to take a well-spread position in the NFT markets through buying into one or multiple NFT index funds. This audience most likely will not come into direct contact with the products offered on the NFTX.org website, as they will use a DEX such as Uniswap or an aggregator such as 1inch or DEX.AG to invest in the fund on the open markets. Investment products may be built for this audience later.

The second audience we cater to are arbitrageurs, who can profit from ranging prices between NFT index funds and their underlying collaterals' floor prices. Arbitrageurs can use the products on nftx.org to interact directly with the index fund pools.

A third audience we cater to are NFT liquidity providers, who can profit from providing additional liquidity to one or multiple NFT index funds. Liquidity providers may use the products on nftx.org to mint additional NFT fund tokens, which can then be supplied as liquidity on a Balancer pool or directly on a DEX.

Next to these three main audiences, a fourth target audience would be NFT collectors who want to trade their NFT with another NFT of the same category. These collectors can do so by minting a fund token on nftx.org & redeeming that token right after, giving back a random NFT from the fund.

### What is the NFTX token address?

The address of NFTX is: 0x87d73e916d7057945c9bcd8cdd94e42a6f47f776

### How do I buy NFTX?

NFTX is available for trading on decentralized exchanges. To find the best rates across multiple exchanges, we recommend using an aggregator such as [Matcha](https://matcha.xyz/).

### Where do I find NFTX Index Funds?

While the DAO contributors are working on creating better interfaces to invest in NFT Index Funds on NFTX.org, we've built a page that provides all current information below:

{% content-ref url="/pages/-MVv9Rfp-RarMac2zbPZ" %}
[Broken mention](broken://pages/-MVv9Rfp-RarMac2zbPZ)
{% endcontent-ref %}


# Minting

![](/files/-MXclqUPSLDvQyuS0CE_)

NFTX v1.x introduces a new minting interface that allows you to easily mint a liquid ERC20 token from your NFT!

## Why mint an NFT?

By adding your NFT to an NFTX vault you mint an ERC-20 token (vToken) that has a 1:1 claim on a random NFT inside the vault.

Unlike a non-fungible token (NFT), an ERC-20 is fungible (all tokens are the same) and this allows it to be:

* Instantly sold at an AMM (like Sushiswap)&#x20;
* Pooled in an AMM to earn trading fees
* Used as collateral to borrow stablecoins

vTokens can be used to redeem a random vault NFT at any time.

## Minting Step-by-step

### Selecting NFTs

When you arrive at [app.nftx.org](https://app.nftx.org) a list of your NFTs that are available for minting will be shown. Select the NFTs you would like to mint and they will be added to your "Mint Basket".

![](/files/-MXgFoG7nm33SQJ5sDd6)

Not seeing your NFT? [See our FAQ](https://docs.nftx.org/tutorials/get-started-v1.x/minting#faq).

### Mint Basket

The mint basket will show you the NFTs you have selected, their approval status and mint value.

![](/files/-MXdEI2NMK4pW6lZnnEY)

#### Approval

Your NFTs will need to be approved for use by the NFTX contract before they can be minted into an ERC-20. Click the NFT line item's "Approve" button to approve each NFT individually. To approve all your NFTs in this contract (i.e. the Wrapped Punks contract), click "Approve all".

**Mint Value**

Mint value is taken from the mid price of the token trading on Sushiswap. The mint value does not account for slippage and liquidity. If you are looking to mint an NFT in order to sell the vToken, it is recommended that you first check the exact value you would receive from selling on Sushiswap.

If the mint value shown is $0 this means that there have been no recorded trades for the vToken on Sushiswap. This might be a good opportunity to [bootstrap liquidity](https://help.sushidocs.com/guides/how-to-add-tokens-to-sushiswap-exchange-as-an-lp) and earn liquidity provider fees!

### **Minting**

With your NFTs approved and your mint value confirmed, click the "Mint" button to generate your vTokens. Each NFT will return a single vToken.

For example, minting 3 Hashmasks to the Mask vault will return 3 MASK ERC-20 tokens.

{% hint style="info" %}
It is important to mint your NFT to the appropriate vault. Do not mint high value NFTs (i.e. a Punk Zombie) to a lower value vault (i.e. Punk-Basic).
{% endhint %}

## Additional Info

### Eligibilities

Many vaults have an eligibility list. This ensures that the vault only accepts a certain sub-category of NFTs (i.e. Punk-Female).

### Mint Requests

Some vaults do not have an eligibility list as it can be cumbersome to maintain. Instead, the vault may accept "mint requests". Vaults that accept mint requests will show your ineligible NFTs and allow you to send them to the vault as a mint request.

![The minting request screens as you progress through the request to mint process](/files/-MXdFqcJcWi_jqE_AoZc)

When sending a mint request, your NFT will be held in escrow until the manager approves. If approved, your vTokens will be minted to your wallet. You can cancel your mint request at any time.

## FAQ

### Why aren't my NFTs showing in the minter?

If you can't see an asset it will be for one of the following reasons:

#### Your NFT is not eligible for the vault

Some vaults use eligibilities to ensure that only certain sub-categories of an NFT can be included. For these vaults, it may be possible to send a [mint request](https://docs.nftx.org/tutorials/get-started-v1.x/minting#mint-requests).

#### Your NFT requires wrapping

NFTs that were developed several years ago did not follow the ERC721 or ERC1155 token standard. Token standards are used as a secure interface for other smart contracts and web3 applications. In order to mint a Cryptopunk, Mooncat or any other non-standard NFT, visit their associated wrapping website.

#### You have just received your NFT

We use the OpenSea API to list the available NFTs that you may have in your wallet. The API can sometimes take a few minutes to update. Please wait 5 minutes and if it is still not showing, reach out to us on Discord.

#### Your wallet contains more than 1,000 NFTs

We currently limit the minter to scanning a wallet's first 1,000 NFTs that may be available for minting. If you have more than 1,000 NFTs in your wallet please reach out to us on Discord for assistance.

### Can I get my NFT back once I've added it to a vault?

An vToken provides a claim on a single asset within a vault, however it does not allow the user to choose which asset. When redeeming an vToken for an NFT, the NFT received is selected at random. For this reason, depositing an NFT into a vault is not advisable for anyone with a particular attachment to that NFT.

### My NFT can be deposited in multiple vaults, which one do I choose?

Some NFTs are eligible to be deposited to multiple vaults. For example, a female CryptoPunk can be deposited in either the Punk-Female or Punk-Basic vaults.

In this case, it would be essential that the female CryptoPunk is deposited in the Punk-Female vault as this vault trades at a higher value. If the female CryptoPunk was deposited in the Punk-Basic vault then it would be quickly redeemed by arbitrageurs as this asset trades higher than the PUNK-BASIC price on secondary markets like OpenSea.

Always check an NFT's available vaults before minting an vToken to ensure the most appropriate one is selected.

### I've minted my NFT but I haven't received my Token yet

There are two potential causes.

1. You need to add the vault token as a custom token to your metamask wallet (see [an example of how to add custom tokens here](https://blog.nftx.org/how-do-i-view-my-nftx-tokens-in-metamask/#how-can-you-see-your-nftx-tokens-inside-of-metamask))
2. The NFT you were minting required "Request Mint" and needs to be approved.

The second situation is the most common, so let's look at that in more detail.

The majority of the vaults on NFTX are floor vaults which will accept any NFT from the project contract. For example, it doesn't matter what type of Hashmask you own, you can always add it to the vault.

Other vaults are set up to only allow specific NFTs from the contract. These include vaults like Punk-Female which only accept Female Punks, or Punk-Zombie which only accept Zombie Punks. This eligibility is controlled through a list of permitted ID's assigned to vaults that require these limitations.

For NFT projects like CryptoKitties and Avastars it is not possible to get a full list of eligible IDs because there's either tens of thousands of ID's (Kitties) or there are still new NFTs being created (Avastars). When you mint into the following vaults and the ID hasn't already been approved it will need to be manually checked before being accepted:

* Kitty Gen 0
* Kitty Gen 0 Fast
* Avastar Rank 30
* Avastar Rank 60

The process usually takes a maximum of 24 hours, but can take longer. Here are the steps

1. You Request Mint the NFT into the vault
2. The NFTX contract holds that NFT is escrow while the check is made
3. The product team is alerted an NFT requires checking
4. The NFT is verified for the vault and a request to the dev team to approve the mint request
5. The NFT comes out of escrow and the Vault Token is sent to your wallet.

If the NFT is *not* eligible for the vault, for example if you try to mint a generation 5 Kitty into the vault, or you try to mint a rank 20 avastar into the Rank-30 vault, then the NFT will remain in escrow until you remove it through the `revokeMintRequests` Function detailed below.

{% hint style="info" %}
The request mint is not going to be required once the vaults move across to NFTX V2. In V2 we will be using the CryptoKitties and Avastars onchain metadata to check the validity of the NFTs and not allow the mint process if they do not below in the vault.
{% endhint %}

### How to cancel/revoke your mint requests

If you have request to mint an NFT into a vault that requires a review you can cancel that request at any time before it is accepted using the `revokeMintRequests` function.

* [ ] Visit <https://classic.nftx.org/#/backend>
* [ ] Select "Connect Accout" and connect using the wallet you used to mint the NFT

![](/files/-MbpOgUv3lTHwxmOd27Y)

* [ ] Choose the drop down on the right hand side of the NFTX Contract and choose `Write`

From there a side bar will open, and you can scroll down to `revokeMintRequests`

![](/files/-MbpPC6nisNM6EIUp5Ya)

To find the `vaultId` you can review the list of current vaults and holdings. The `nftIDs` are the IDs of the NFT you would like to get back from escrow. For example:

* **VaultId** `11` (Avastar-Rank-30)
* **VauldIds** `[1234, 9786, 19111]`


# Redeeming

![](/files/-MYKQ5ReuyFKbfWBe-ak)

NFTX v1.x allows you to easily redeem your [minted](/v1.0/tutorials/minting) ERC20 Vault Tokens (vTokens) for a random NFT within the vault.

## Why redeem an NFT?

Redemptions allow users to take ownership of an underlying NFT from within a vault. This means that a user can go to an AMM like Sushiswap, purchase a vToken like PUNK-BASIC and use that token to claim a random CryptoPunk from the [Punk-Basic vault](https://gallery.nftx.org/funds/punk-basic/).

## Redeeming Step-by-Step

### vToken Balance

![](/files/-MYKSuX24AUqtUaWqZyP)

When you visit <https://app.nftx.org/redeem> and connect your wallet, your vToken and NFTX balances will be displayed on the right hand side. Each vToken represents a claim on a random NFT from within its vault.

{% hint style="info" %}
Don't have any vTokens? [Visit our Gallery](https://gallery.nftx.org) to browse the available vaults and exchange trading pairs.
{% endhint %}

### Redeeming

To redeem an NFT you must enter the quantity you would like to redeem (in whole numbers) and approve the NFTX contract. Once the approval transaction has been confirmed, you will then be able to redeem the desired number of tokens.

![](/files/-MYKTiTZwHJeZRrK6chN)

Once the redeem transaction is confirmed, a receipt will be shown that includes an Etherscan link for viewing NFT ID that was redeemed.

![](/files/-MYKUqs-pXbQ7qr7Vrz6)

## FAQ

### Can I choose what NFTs I redeem?

The current version of the NFTX protocol does not allow for specific redemptions. This is a feature that will be made available in V2.

### Can I redeem from a vault without a vToken?

Users must have a vToken in their wallet balance to redeem from a vault. To browse the available vaults and vault NFTs, please visit the [NFTX Gallery](https://gallery.nftx.org).


# Vault Creation

NFTX v1.x introduces a new vault creation interface that allows you to easily create a public vault for any NFT or a specific subset of IDs for an NFT.

## Why create a vault?

Vault creation is at the heart of the NFTX protocol and allows users and content creators to begin [minting](/v1.0/tutorials/minting) fungible ERC20 tokens for any NFT.

By creating NFT-backed ERC20 tokens, users can create liquid markets for otherwise illiquid NFTs whilst also earning fees and rewards from liquidity provision.

Protocol fees will also be introduced in V2 of the NFTX.

## Vault Creation Step-by-Step

### Create NFTX Vault

Three fields are required to create an NFTX vault as shown below.

![](/files/-MZx7KyQnPQ9-1RO28xk)

**NFT Asset Address**

The NFT asset address is immutable and points to the contract from which this vault will accept mints. By default, all NFT IDs from this contract will be eligible for minting in the vault.

{% hint style="info" %}
Eligibility lists can be added once the vault has been created. This will allow you to target specific properties like "Female Punks" from within an asset.
{% endhint %}

Some assets are already used in other vaults. For example, Wrapped CryptoPunks are used in multiple vaults and separated using eligibility lists. To avoid adding a duplicate vault and splitting liquidity, review the matching vaults list before proceeding.

![](/files/-MZxCNBpv1pwGYukRo2m)

**Vault Name**

This will be the *name* of the ERC20 token that is minted from this vault.

**Vault Symbol**

This will be the *symbol* of the ERC20 token that is minted from this vault.

Both the Vault Name and Vault symbol will appear anywhere that this token appears, from CoinGecko and Etherscan through to Sushi and Uniswap.

{% hint style="info" %}
A strong name and symbol play a critical part in a vault's long-term success. Please review our recommended naming conventions to help maximize your vault's exposure.
{% endhint %}

### Vault Created

Once your create vault transaction has been confirmed onchain you will be notified and asked to proceed to managing your vault.

Your vault will not be visible in the NFTX app until it has been minted to and published. Click "Manage Vault" to complete the process.

{% hint style="warning" %}
The NFTX subgraph is currently under development. As a result, newly created vaults take up to 5 minutes to be visible on the front end.
{% endhint %}

![](/files/-MZxDG5718gFXLUBkBXl)

### Manage Vault

Vault management allows vault creators to modify a number of important settings as well as publishing the vault so that it becomes visible on the NFTX app.

{% hint style="warning" %}
Published vaults cannot be edited by the creator. Carefully review the vault's settings before publishing.
{% endhint %}

![](/files/-MZxEIk44V5WOX5z0Sx7)

**Allow Mint Requests**

By enabling this setting, users will have to make a request to mint their NFT to this vault. Once a vault is published, mint requests will be reviewed and approved by the DAO.

**Eligibilities**

A vault's eligibility list is an allow list of NFT IDs that can be minted to this vault. This can be flipped into a deny list by enabling the "Negate Eligibilities" setting (see "Negate Eligibility" below).

**Eligibility Range**

For blocks of eligible IDs, use this setting to specify the "from" and "to" (inclusive) IDs that will be added to the eligibility list.

![](/files/-MZxHL4cwpdMjyVkeFRI)

**Unique Eligibilities**

Use this setting to specific individual IDs to add to the eligibility list.

![](/files/-MZxHNZSNEeztszYF7M0)

**Negate Eligibility**

The negate eligibility setting flips the eligibility list into an allow (negate eligibility disabled) or deny list (negate eligibility enabled). For clarity, see the following examples.

| Setting                     | Eligibilities | Example Allowed | Example Denied |
| --------------------------- | ------------- | --------------- | -------------- |
| Negate Eligibility Enabled  | 1, 2, 3, 4, 5 | 2, 3, 5         | 2, 3, 5        |
| Negate Eligibility Disabled | 1, 2, 3, 4, 5 | 6, 8, 10        | 6, 8, 10       |

### Vaults Overview

To view your vaults at any time click the "Manage" link in the navigation. This link is only visible to connected wallets that are a manager of at least 1 vault.

![](/files/-MZxIc7hrxxBrxNfK6pE)

## FAQ

### I am being warned about the vault name or symbol, what does this mean?

Naming conventions provide structure for NFTX vaults that makes them instantly recognisable across platforms and help improve the network effects for all participants in the NFTX ecosystem.

**Naming conventions**

| Vault Name                          | Vault Symbol                                     |
| ----------------------------------- | ------------------------------------------------ |
| Alphanumeric only                   | Less than 7 characters                           |
| Capitalized (i.e. Punk Attribute 4) | Singular (i.e. PUNK for CryptoPunks floor vault) |
|                                     | Uppercase                                        |

The tight recommendations on Vault Symbol are in place to conform to Twitter's cashtag standard.

### Why isn't my vault isn't showing in the NFTX app?

The most common reason for this is that your vault does not yet have holdings or has not been published. To add holdings, visit the vault management page and click "Add Holdings".

If the vault is still not appearing, you may need to wait for a maximum of 5 minutes while the vault is indexed. This delay will become immediate once the NFTX subgraph is deployed in V2 of the protocol.


# Overview

### **NFTX Contracts**

#### **Structure Summary**

At the core of NFTX is the NFTX Fund contract which holds all NFTs stored by all various NFTX funds. The NFTX Fund contract maintains a vault per NFT address identified with a vault ID. Using the vault ID, the NFTX Fund contract accesses all fund/vault related storage through the xStore contract.

For every vault, there is a fund token (vToken) deployed for it, which is eligible for redeeming a pseudorandom NFT from the fund.

### [NFTXv7 Implementation](https://etherscan.io/address/0x87665c29ea77c4285ea7443f5f71c54ea90305b8)

#### **Vault Creation**

```javascript
function createVault(
    string memory name,
    string memory symbol,
    address _assetAddress,
    bool _isD2Vault
) public virtual nonReentrant returns (uint256 vaultId);
```

Anyone can create a vault by calling `createVault`. When a vault is made, a fund token (vToken) is deployed, and the vault ID is returned.

#### **Minting**

```javascript
function mint(uint256 vaultId, uint256[] memory nftIds, uint256 d2Amount) external;
```

The mint function allows you to mint an vToken for each NFT provided to the fund.

This function expects the contract to have approval of the NFTs or set as an operator from `msg.sender`.

#### **Redeeming**

```javascript
function redeem(uint256 vaultId, uint256 amount) external;
```

The redeem function allows users to use their NFTX Fund tokens to redeem NFTs pseudorandomly from the proper vault.

This function expects the contract to have approval of the NFTX Fund token by the `msg.sender`.

#### **vToken (Fund Tokens)**

For every fund on NFTX, an vToken proxy clone contract is deployed to serve as the means of minting/redeeming through that fund. Every vToken is a standard ERC20.

### [**xStore**](https://etherscan.io/address/0xBe54738723cea167a76ad5421b50cAa49692E7B7)

Using the vault ID, you can access vault information from xStore using the following view functions:

#### **Reading the vaults parameters**

```javascript
function xTokenAddress(uint256 vaultId) external view returns (address);
function assetAddress(uint256 vaultId) external view returns (address);
```

The vToken address represents the token that is minted/redeemed for the assets in that vault ID. This is also referred to as the fund token.

The asset address is the asset used to mint fund tokens, and what is given back to the user when they redeem their fund tokens.

#### **Reading the vaults contents and information**

```javascript
function reservesLength(uint256 vaultId) external view returns (uint256);
function reservesContains(uint256 vaultId, uint256 elem) external view returns (bool);
function reservesAt(uint256 vaultId, uint256 index) external view returns (uint256);
```

A reserve defines the vault's contents, which consists of ERC721s.

You can view the total amount of assets in a vault; if an asset is present in a vault; and which asset is located at a given index.

#### **Permissioning**

Currently there are 2 distinct roles which the permission checks are based on.

**Owner:** the address who initialized the NFTX contract, the owner of the NFTX Fund contract.\
**Manager:** the address who created the vault. (Note: every vault has its own manager.)

There is 1 modifier and 2 functions that are used as a permission check.

#### onlyOwner

```javascript
modifier onlyOwner()
```

Only the owner can execute the functions with this modifier.

#### **onlyOwnerIfPaused**

```javascript
function onlyOwnerIfPaused(uint256 pauserId) public view virtual;
```

It takes an ID as an argument which corresponds to an action and checks if the specific action is paused or not.

If the action is paused only the owner can call the function. If it isn’t paused, it is permissionless.

As of now the actions that can be “paused” are `createVault()`, `mint()`, `redeem()`.

**The functions that use this access control are:**

```javascript
function createVault(string memory name, string memory symbol, address _assetAddress, bool _isD2Vault) public virtual nonReentrant returns (uint256 vaultId);
function requestMint(uint256 vaultId, uint256[] memory nftIds) public payable virtual override nonReentrant;
function mint(uint256 vaultId, uint256[] memory nftIds, uint256 d2Amount) public payable virtual override nonReentrant;
function redeem(uint256 vaultId, uint256 amount) public payable virtual nonReentrant;
```

#### onlyPrivileged

```javascript
function onlyPrivileged(uint256 vaultId) internal view;
```

It takes as argument a vaultId and it checks if the vault is finalized or not, if it's finalized only the [owner](/v1.0/smart-contracts/overview#permissioning) can continue forward otherwise only the [manager](/v1.0/smart-contracts/overview#permissioning) can call it.

**The functions that use this access control are:**

```javascript
// Configuration
function setIs1155(uint256 vaultId, bool _boolean) public virtual;
function setNegateEligibility(uint256 vaultId, bool shouldNegate) public virtual override;
function setRange(uint256 vaultId, uint256 start, uint256 end) public virtual;
function setIsEligible(uint256 vaultId, uint256[] memory nftIds, bool _boolean) public virtual;
function setMintFees(uint256 vaultId, uint256 _ethBase, uint256 _ethStep) public virtual;
function setBurnFees(uint256 vaultId, uint256 _ethBase, uint256 _ethStep) public virtual;
function setSupplierBounty(uint256 vaultId, uint256 ethMax, uint256 length) public virtual;
function setAllowMintRequests(uint256 vaultId, bool isAllowed) public virtual;
function setFlipEligOnRedeem(uint256 vaultId, bool flipElig) public virtual;
function setNegateEligibility(uint256 vaultId, bool shouldNegate) public virtual;
function approveMintRequest(uint256 vaultId, uint256[] memory nftIds) public virtual;

// Management
function changeTokenName(uint256 vaultId, string memory newName) public virtual;
function changeTokenSymbol(uint256 vaultId, string memory newSymbol) public virtual;
function setManager(uint256 vaultId, address newManager) public virtual;
function finalizeVault(uint256 vaultId) public virtual;
function closeVault(uint256 vaultId) public virtual;)
```


# Contract Addresses

| **Contracts**         | **Code**                                                                                               | **Mainnet**                                                                                                                | Rinkeby                                                                                                                       |
| --------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| NFTXFundProxy         | [GitHub](https://docs.openzeppelin.com/contracts/3.x/api/proxy#UpgradeableProxy)                       | [0xAf93fCce0548D3124A5fC3045adAf1ddE4e8Bf7e](https://etherscan.io/address/0xAf93fCce0548D3124A5fC3045adAf1ddE4e8Bf7e)      | [0xFD07FDB485e4De4dCD7654E5EA25fd059CD7FDE2](https://rinkeby.etherscan.io/address/0xFD07FDB485e4De4dCD7654E5EA25fd059CD7FDE2) |
| NFTXv7 Implementation | [GitHub](https://github.com/NFTX-project/x-contracts-private/blob/master/contracts/NFTXv7.sol)         | [0x87665c29ea77c4285ea7443f5f71c54ea90305b8](https://etherscan.io/address/0x87665c29ea77c4285ea7443f5f71c54ea90305b8#code) | [0x8af4BdFC4CfBe5388bd194B7e86D4CcF502121A5](https://rinkeby.etherscan.io/address/0x8af4BdFC4CfBe5388bd194B7e86D4CcF502121A5) |
| xStore                | [GitHub](https://github.com/NFTX-project/x-contracts/blob/master/contracts/XStore.sol)                 | [0xBe54738723cea167a76ad5421b50cAa49692E7B7](https://etherscan.io/address/0xBe54738723cea167a76ad5421b50cAa49692E7B7)      | [0x899383a74b4A0dFc931912c8a4748B5b113B7d71](https://rinkeby.etherscan.io/address/0x899383a74b4A0dFc931912c8a4748B5b113B7d71) |
| $NFTX Token           | [GitHub](https://github.com/aragon/minime/blob/master/contracts/MiniMeToken.sol)                       | [0x87d73e916d7057945c9bcd8cdd94e42a6f47f776](https://etherscan.io/address/0x87d73e916d7057945c9bcd8cdd94e42a6f47f776)      |                                                                                                                               |
| Bounties              | [GitHub](https://github.com/NFTX-project/x-bounties/blob/master/contracts/XBouties.sol)                | [0x9C5a36AEf5A7b04b0123b2064BD20bc47183e1DC](https://etherscan.io/address/0x9C5a36AEf5A7b04b0123b2064BD20bc47183e1DC)      |                                                                                                                               |
| DAO                   | [GitHub](https://github.com/NFTX-project/x-contracts/blob/master/contracts/XController.sol)            | [0x40d73df4f99bae688ce3c23a01022224fe16c7b2](https://etherscan.io/address/0x40d73df4f99bae688ce3c23a01022224fe16c7b2)      |                                                                                                                               |
| TokenApp              | [GitHub](https://github.com/NFTX-project/x-bounties/blob/master/contracts/TokenAppController.sol)      | [0x5566b3e5fc300a1b28c214b49a5950c34d00eb33](https://etherscan.io/address/0x5566b3e5fc300a1b28c214b49a5950c34d00eb33)      |                                                                                                                               |
| xStoreMultiCall       | [GitHub](https://github.com/NFTX-project/x-backend/blob/master/contracts/XStoreMultiCall.json)         | [0x0ccA025C7b8C264F7a569afF1A74907CD43AeD62](https://etherscan.io/address/0x0ccA025C7b8C264F7a569afF1A74907CD43AeD62)      |                                                                                                                               |
| TokenMultiCall        | [GitHub](https://github.com/NFTX-project/x-backend/blob/master/contracts/TokenMultiCall.json)          | [0xd62b2DD08FCA73B82f014107bF1CC888C61b8dF3](https://etherscan.io/address/0xd62b2DD08FCA73B82f014107bF1CC888C61b8dF3)      |                                                                                                                               |
| ProxyController       | [GitHub](https://github.com/NFTX-project/x-contracts/blob/master/contracts/ProxyController.sol)        | [0x947c0bfA2bf3Ae009275f13F548Ba539d38741C2](https://etherscan.io/address/0x947c0bfA2bf3Ae009275f13F548Ba539d38741C2)      |                                                                                                                               |
| xTokenClonable        | [GitHub](https://github.com/NFTX-project/x-contracts-private/blob/master/contracts/XTokenClonable.sol) | [0x925297edcb4893d0d914e6d28f49381d47b864b0](https://etherscan.io/address/0x925297edcb4893d0d914e6d28f49381d47b864b0)      |                                                                                                                               |

## Contract User Interfaces

Mainnet: <https://nftx.org/#backend/>

Rinkeby: <https://rinkeby.nftx.org/#/backend/>

## **NFTX Interfaces**

Source code: <https://github.com/NFTX-project/x-frontend/blob/master/src/contracts/NFTXv7.json>


# Audit & Risks

Coming soon...


# Litepaper

NFTX is a platform for making ERC20 tokens that are backed by NFT collectibles. These tokens are called funds, and (like all ERC20s) they are fungible and composable. With NFTX, it is possible to create and trade funds based on your favorite collectibles such as CryptoPunks, Axies, CryptoKitties, and Avastars, right from a DEX like Uniswap.

There are two types of funds on NFTX:

* D1 funds (input) have a 1:1 backing between a single NFT contract and an ERC20 contract. For example, if Alice owns 2 PUNK-ZOMBIE, that means she can redeem exactly two random zombie CryptoPunks at any moment. Another example would be Alice owning 1 AXIE-MYSTIC-2, giving her the ability to redeem one random Axie with two [Mystic parts](http://axie.wiki/index.php?title=Parts#Mystic). &#x20;
* D2 funds (top-level) are Balancer pools which combine D1 funds. For example, AVASTR will be a D2 fund which combines three different D1 Avastar input funds (AVASTR-BASIC, AVASTR-RANK-30 & AVASTR-RANK-60). The point of this is to offer more diverse exposure without requiring users to hold multiple tokens.&#x20;

When a new fund is created, the account which sends the transaction is designated as the fund manager. This allows the creator to change fund parameters like fees, supplier incentives, and NFT eligibility. When the creator is done modifying the fund they can then “finalize” it which gives up their control to increase trustlessness.

## Target Users

A common misconception is that NFTX is a project for NFT collectors, but most NFT collectors enjoy browsing and trading individual NFTs, so there is no reason for them to wrap their collections into fungible tokens. There are, however, many people out there that don’t have the time or knowledge to trade individual NFTs but would like exposure to NFT markets. These are the NFTX target users—the people trading top-level funds of NFT blue-chips such as AXIE, PUNK & KITTY on Uniswap, not the people minting/redeeming their NFT on the NFTX website. Most of the time the only people minting/redeeming fund tokens will be arbitrageurs. This is similar to the dynamic with WBTC. Most people that trade WBTC do not mint and burn it themselves.

NFTX will start out with just D1 funds, so at first the homepage will have quite specific funds listed, however once the top-level D2 funds are created then the homepage can shift focus to those funds instead. The idea is for NFTX to be somewhat like a CoinMarketCap or DefiPulse style website but for the NFT space. Users will arrive at the homepage and be greeted with metrics for top-level funds backed by NFT blue-chips such as [CryptoPunks](https://www.larvalabs.com/cryptopunks), [Axies](https://marketplace.axieinfinity.com), [CryptoKitties](https://www.cryptokitties.co/), and [Avastars](https://avastars.io/).

Eventually, the hope is for NFTX to become home to over a hundred top-level NFT funds, each of which will feature real-time price, volume and TVL data.

## Platform Management

The process for creating a fund was inspired by Balancer’s process for creating a pool. Essentially, the pool creator gets “manager” privileges but can also call a “finalize” function which renounces their control. Like Balancer pools, NFTX funds also have a finalize function, but unlike Balancer, when the NFTX finalize function is called then control of the fund is handed over to the NFTX Dao. There are two reasons for this.

The first reason for the Dao receiving fund management privileges is that in some cases funds require ongoing governance (e.g. having new eligibilities added). The second, more controversial, reason for why the Dao receives management rights is so that we can guide the platform to evolve in a way that we see fit. If funds start cannibalizing each other (e.g. multiple funds targeting similar NFT subsets) then that can hurt our platform’s UX, so in such a situation we can decide to close all but one of the funds so that the remaining one may prosper.

The goal is for NFTX to offer one top-level fund which gets most of the liquidity for each major NFT contract. For example, if someone wants to create a AVASTR-V2 fund that differs from the main AVASTR fund, then that is fine (and actually encouraged), but if we get into a situation where AVASTR and AVASTR-V2 are splitting the liquidity down the middle and there is an easy fix (e.g. merging the differences) then that is something that the Dao can consider doing.

## Moat & Value Capture

Long-term, the goal for NFTX is to develop a moat as the primary issuer of wrapped NFT funds. This is potentially a huge use-case with the legitimate possibility of one day eclipsing the present market cap of all cryptocurrencies combined. Digital land, in-game items, lease-agreements, digital art, digital collectibles, digital lottery tickets and more can all be represented as NFTs. As the NFT ecosystem grows it will get increasingly difficult to keep track of, and tokenized funds will become a necessity for many investors and trading platforms.

In terms of value capture, it’s not inconceivable to consider a 2.5% fee in the future on all NFTX mint and burn operations. This added cost would mostly be absorbed by arbitrageurs and would essentially cause fund tokens to drift off-peg slightly more than usual. For a wrapped token like WBTC, a 2.5% price difference from regular BTC would be a major UX flaw, but for NFT funds (which represent an inherently illiquid category of assets) a 2.5% price difference would likely be unnoticeable.

## Avenues For Growth

1. **NFT→ ERC20 Loans —** Minting a D1 fund token requires handing over an NFT, and in many cases people will want the benefits of a fund token without having to give up ownership of their NFT. These people would prefer to lockup their NFT in return for a loan (similar to minting Dai with ETH). By having a surplus of D1 tokens in the NFTX treasury, our platform will be able to provide low-interest ERC20 loans to NFT collectors. Furthermore, these loans will have zero risk of unexpected liquidation because NFTs are always worth at least as much as the D1 funds which they are eligible for. &#x20;
2. **On-Chain Liquidity** — *\*\**&#x4F;ne of the biggest problems in the NFT space is price discovery. Unless market makers are in "the know" it can be challenging for them to determine the real price of an asset. One reason for this is wash-trading, another reason is illiquidity and gaps between sales. Having real-time price feeds from popular funds largely solves both of these issues. As a concrete example, if a trader can check that PUNK-ATTR-4 is 150% the price of PUNK-BASIC, and that PUNK-ZOMBIE is 60 ETH, then they are able to determine that a zombie CryptoPunk with four attributes should be about 150% of 60 ETH, or 90 ETH. With this problem ameliorated, it's not hard to imagine NFTX branching into the on-chain liquidity game, enabling NFT market makers to automate their strategies, and aiming to become somewhat of a "Kyber for the NFT space."
3. **Randomized Packs & Gift Cards** — Having a large reserve of NFTs opens up a number of possible usecases for NFTX. One such possibility is a service offering randomized packs with varying likelihoods of different NFTs. Another possibility is gift cards. Currently when a user redeems an NFT by burning a fund token, the NFT they receive is randomly selected, however it is possible for us to extend the NFTX smart contract so that (for a added charge) users can select the exact NFT which they want. This would be analogous to a gift-card and would enable recipients to enjoy the process of selecting their own unique items from the NFTX reserves.

## Near-Term Roadmap

The first item on our organizational to-do list is the NFTX community raise, which will be deployed in the coming week, and which will likely run for a number of months. More information about [this raise can be found here.](/v1.0/archive/community-raise)

Once the community raise is partially complete, and all of the D1 funds have at least one asset in them, then it will be possible for our Dao to launch the top-level D2 funds. This will be a top priority, and in many ways we will consider NFTX to be in a pre-launch state until the top level funds (PUNK, KITTY, AXIE, and AVASTR) are up and running, as these will be four of our six initial flagship tokens (along with GLYPH and JOY).

The current front-end site for the NFTX dapp is quite buggy and needs a number of improvements. This will be an ongoing process over the next couple months, which will become a greater priority as we approach the the start of our liquidity mining program, sometime in late Q1 or early Q2 of 2021, the details of which are still undecided.

Some project followers have already reached out with questions regarding the NFTX brand. In addition to improving the functionality of the front-end, we are also very open to a doing a full rebrand based on the preferences of our nascent community. If you have thoughts on this we encourage you to reach out or put together a community proposal. Like everything else about NFTX, the brand is not fixed in stone and may be altered subject to voter approval.

In terms of governance, we will begin by using only Discord and Aragon. Discord will be used for discussion and Aragon will be used to enact decisions we have reached consensus on. Of course, Aragon may also be used to decide internal conflicts, but we will do our best to avoid contentious issues early on. Once we have found our bearings as a community we will create a Discourse forum and begin outlining some more formal procedures for decision making.

There will be no employees to begin with, however it is very likely that our organization will employ people in the future, so it's worth noting that we will aim to offer competitive compensation that is similar to what could be expected in the tech industry.

## V2 & Gas

Although NFTX version 1 is only just taking off, there are already improvements in mind for version 2. Some of these improvements involve new features, like smart funds, which will have dynamic rule sets. Other improvements involve security concerns which were brought up during our audit but which were tabled on account of being considered low severity. Likely the most pressing issue for version 1 will be gas costs, which are quite high, and which will be considered a top priority improvement for NFTX v2.

Even though most end-users (top-level fund traders backed by blue-chip NFTs) are unaffected by platform costs, it can still be a high friction point for arbitrageurs and the occasional users who do mint or redeem. High fees also limit NFTX's ability to offer price-accurate funds for lower value items (e.g. NFTs < 0.1 ETH). In the mean time we will make do by subsidizing platform costs if necessary and recommending that users avoid minting and burning during high volume periods.

## Conclusion

If there is one important take-away for readers it should be that NFTX is entirely community-governed. This document describes a vision for the future, but that future depends entirely on what NFTX token holders decide to implement. All assets from the community raise will be considered as part of the NFTX treasury and will be under the control of token holders. The intention is to use the bulk of the treasury to supply liquidity for fund tokens and also for the NFTX token, however, make no mistake, those are treasury assets and may at any moment be used to cover expenses, should the Dao choose to do so.

The current NFTX mission is to become a DeFi black hole for NFT assets. We will aspire to remain objective about which NFTs we give preferential treatment, focusing above all else on what is best for the long-term appreciation of the NFTX token. That said, we will also place high value on principles of decentralization and endeavor to work with like-minded organizations.

The only potentially unpopular opinions the NFTX DAO will have which community members should be aware of is (A) a bias for ETH and Ethereum, and (B) a bias for PUNK and CryptoPunks as a store of value for the NFTX DAO treasury.

When in doubt, we will store our organization's wealth in these assets. And, unless met with no other option, we will always remain rooted on Ethereum. Treasury allocation may shift towards a more diversified basket of blue-chip NFTs such as Axies, Avastars, CryptoKitties, Autoglyphs & Joyworld Joys' as more community members get involved in DAO operations & a proposal to diversify gets voted in through DAO governance.

We invite anyone and everyone to join us in our mission. Over time, that mission will inevitably change but it's important that we begin our journey on the same footing, and with the same principles in mind, so that we may move forward, not only as a community, but as an anti-fragile digital warband 😈

Discord link: <https://discord.gg/nftx>


# Token Distribution

## Token Rights & Distribution

The NFTX smart contract uses an upgradeable proxy which is controlled by the NFTX Dao (on Aragon). This means that NFTX token holders have the power to change the NFTX smart contract if we reach consensus. Right now all changes require 80% of participating (i.e. voting) tokens to support a proposal in order for it to pass, with the voting period lasting for 24 hours. In the future we will propose decreasing the support threshold and increasing the duration (e.g. 65% support over 5 days), but for now the shorter duration allows our platform to make updates faster, and the 80% threshold helps protect against governance attacks.

The NFTX token supply is 650,000, and the distribution is as follows:

* 10% vested over 5 years for founder
* 30% distributed for NFT contributions (community raise)
* 30% distributed for ETH contributions (community raise)
* 10% earmarked for NFTX liquidity
* 20% earmarked for farming

![NFTX Token Distribution](/files/-MQ4J7W9K9DDB9e9GMW-)

Keeping popular funds liquid is important, so the community raise will be accepting ETH as well as NFTs (in the form of D1 fund tokens) in exchange for vested NFTX tokens. The idea is for the NFTX Dao to raise enough NFTs and ETH to bootstrap AMM pools with liquidity. Being an LP makes sense for our Dao because it improves the liquidity of funds (i.e. our product) while also earning yield for our treasury.


# Brand Kit

Below you will find the main brand kit for NFTX.

## Logo

![The primary logo of NFTX.](/files/-MT_k82c5GPqWPkjmR1h)

Above is the primary logomark for the NFTX DAO. Please use the correct version, based on the background it is placed on, found below.

When you have further questions on usage, contact any of the contributors on our Discord.

**On White Background**

{% file src="/files/-MT\_nr8Nv4s1NXejtJ8j" %}
Logo SVG on White BG
{% endfile %}

{% file src="/files/-MT\_o1ADUZN\_bIM0r5\_x" %}
Logo PNG on White BG
{% endfile %}

**On Black Background**

{% file src="/files/-MT\_o58UsvcuUf6TfjDh" %}
Logo PNG on Black BG
{% endfile %}

{% file src="/files/-MT\_o9tHmiJIDGV2lljO" %}
Logo SVG on Black BG
{% endfile %}

## Logo**type**

![The logotype of NFTX.](/files/-MT_nZ9-sBFKi9UGC66Q)

Above is the logotype for the NFTX DAO. Please use the correct version, based on the background it is placed on, found below.

When you have further questions on usage, contact any of the contributors on our Discord.

**On White Background**

{% file src="/files/-MT\_oJpwEvVpa-N1\_r1u" %}
Logotype PNG on White BG
{% endfile %}

{% file src="/files/-MT\_oRII5-j1Tqsv\_pLU" %}
Logotype SVG on White BG
{% endfile %}

**On Black Background**

{% file src="/files/-MT\_oaBPDtw7P4v0Yx60" %}
Logotype PNG on Black BG
{% endfile %}

{% file src="/files/-MT\_oaBPDtw7P4v0Yx60" %}
Logotype SVG on Black BG
{% endfile %}

**Download all logos at once**

{% file src="/files/-MT\_ovlC3\_V9dS58wJNg" %}
NFTX Logopack ZIP file
{% endfile %}

## **Color Palette**

### **Primary color 1: Outrageous Orange**

![](/files/-MT_qNCWSESlxZNYn8tq)

**Hex: #**&#x46;F6D41

### **Primary color 2: Rose**

![](/files/-MT_qbEAeUt_9vfMwTK_)

**Hex: #**&#x46;A297F

## Favicons

{% file src="/files/-MT\_vjfNf2eAuGlMKls8" %}
NFTX Favicon set
{% endfile %}


# Get Started

Below are the tutorials available for interacting with NFTX.

If you are missing information in any of the tutorials below, make sure to ask your question on our Discord channel!&#x20;

{% content-ref url="/pages/-MVv9RgAsYpkNReQNIGJ" %}
[How to create an NFT Index Fund](/v1.0/archive/old-tutorials/how-to-create-an-nft-index-fund)
{% endcontent-ref %}

{% content-ref url="/pages/-MVv9RgBm9r7k579ogyf" %}
[How to get my index fund listed on the NFTX Gallery?](/v1.0/archive/old-tutorials/how-to-get-my-index-fund-listed-on-the-nftx-gallery)
{% endcontent-ref %}

{% content-ref url="/pages/-MVv9RgCAI-ML6JLzyRj" %}
[How to mint an NFT Index token with your NFT?](/v1.0/archive/old-tutorials/minting-fund-tokens)
{% endcontent-ref %}

{% content-ref url="/pages/-MVv9RgDy7viaHqeUKfV" %}
[How to redeem an NFT from an index fund?](/v1.0/archive/old-tutorials/redeeming-nfts)
{% endcontent-ref %}


# How to create an NFT Index Fund

One of the advantages of using the NFTX platform is the permissionless way in which anyone can create a fund. Below are the steps you need to go through to create a fund yourself.

Note: SushiSwap is currently having issues listing the tokens on the frontend, which should be resolved shortly.

## **Choosing your NFT collection**

Funds created on NFTX are currently only for Ethereum-based NFTs, and the following contract types are supported for fund creation:

* ERC721
* ERC1155&#x20;

Once you have confirmed you are creating a fund for one of the supported NFT formats listed above, you can move to the next step.

You must have at least one NFT for the fund you plan to create. You will use this NFT to add your first asset to the fund/vault.

## **Step 1: Creating the NFT Vault**

The next thing to do is head over to[ **https://nftx.org/#/backend**](https://nftx.org/#/backend)\*\*\*\*

![](https://lh6.googleusercontent.com/icYa-bDC9Vd8Ph03KOdQiJVVaP2mJJzz851WzRYu4tDNjCCGGsyei-_8-2j3eUiJYht8yr9bRwLecX2RlckyeVdnYg0zWp1Cj3x83N-hm9ub5SI3I6F0BR-9TbImQ1o36twDAkVZ)

After connecting with your wallet, you will notice there are two (2) contracts, **NFTX** and **XStore**. We will be primarily using NFTX for this tutorial.

Choose the `Write` action from the `[...]` dropdown menu next to the NFTX Contact.

![](https://lh5.googleusercontent.com/o6NB72Tb8xBlMr0BPS8_kjIPQSnXt4qiUNDbdIPdDwNBI5OHVT77Uen04ppIwU3f0JqYnWcay5BfNBi6_wKiXIMBs63Yab553_0arlUuEvxB6grRXHvg0_LFr8QIrzwi7qvsA8SA)

Scroll through the list until you see the `CreateVault` function where you will need to fill in four (4) fields. We've used Twerky Pepes as an example in the tutorial:

1. **Name of fund:** Twerky Pepe *(This is the name your fund token will have)*
2. **Token Name:** TWERKY *(Try to keep the token name simple. One word, if possible. No dashes. Seven (7) characters or fewer, if possible.)*
3. **Contract Address:** 0xf4680c917A873E2dd6eAd72f9f433e74EB9c623C *(the NFT contract address)*
4. **D2 Vault:** false

![](https://lh6.googleusercontent.com/xOADj9mvPz2ulmcIUoAvQ8lcPKtKWx1aOA_u6n1ZO47TkPdvXNmLmLMOX8LSPaVT_SGQoLGRTytiZcK6U9o0WQvusC3DLC5sd441Wn0jB88F0frkCosCg1i2hTkiEhIaz3aK0b2A)

If you are unsure what the contract address is for your NFT, you can find it in the Chain Info dropdown menu on your NFT OpenSea page (you can also get an individual Token ID from here).

Clicking on the link will take you to Etherscan where you can copy the address. Keep that Etherscan page open; you'll need it soon.

![Screenshot from the Opensea page for Twerky Pepe](https://lh4.googleusercontent.com/2BoigsrWDsbB4FZsjbBVTqwJOQr9B7uJ1ku-w7We8ztD3Ah7Wwze9WSwSI1mtKcvYICwTsmkxWbhAaDB0TM1j8AWqZgqrqC0_ojpevQQhLuFiIAZQiRiG7pmu1D-Zqcq0Or6cR6q)

Once you've got those details, click on `CreateVault` to advance in creating your first NFT index fund. At this point, you will get a prompt from MetaMask to pay Gas for the transaction.

![Metamask asking for permission to create the vault.](https://lh6.googleusercontent.com/LpwxTOpATTs8xPJEnOx_LM3C5Kz9GaHyvQ-J6Zqcj6qcVcoOfNxPZHZ5w5nc-VZ9sjr8W0Wi2GytKNNakzFJdqg67BF2NieL_IB3RwONvv_Uz9NmP3zqfMX1BkMfPkf6-xuWbpbm)

Once you get confirmation that the process has been completed, you will need to find the `vaultID`.

## **Step 2: Finding the vaultID**

Every fund that is created gets its own vaultID. You will need to finish setting up the vault. In the future, these steps will be taken care of for you through a new frontend.

You should still be on [**https://nftx.org/#/backend**](https://nftx.org/#/backend), but this time we need to interact with the XStore contract.

![](https://lh3.googleusercontent.com/D9QILFVhZXYyGAf-xC5sDOYGUmAlbEsdsZu9eDPJNk-oTxVaD3-ETyyTzM8VhSwU7xiYh8pmEC36B9PfY9dQwf1gI9PufkYWxD9SlO5J1rn0o5rBd5CCUxQr_9OoXFxJ2kB0vEkn)

Copy the XStore contract address,[ 0xBe54738723cea167a76ad5421b50cAa49692E7B7](https://etherscan.io/address/0xBe54738723cea167a76ad5421b50cAa49692E7B7#readContract) and head over to Etherscan.

Paste in the contract address and go down to Contracts → Read Contract.

Alternatively, here's a link:[ https://etherscan.io/address/0xBe54738723cea167a76ad5421b50cAa49692E7B7#readContract](https://etherscan.io/address/0xBe54738723cea167a76ad5421b50cAa49692E7B7#readContract)

Scroll to the bottom of the page until you come across `vaultsLength` which will show how many funds have been created. The image below shows thirty-two (32) vaults, but because the vaultID's start at 0 the latest vault created will be number 31.

![Showing the number of Vaults](https://lh3.googleusercontent.com/5rHmK8MZTSWEl1XTOVW5YoPF9mQ5OE2uL2GbyTygXQkXsFBzOc9PEVN3A2Czy_yxaq8SwruTkVHK3r1ZIQ9PFAO5DMY0Zdm0GK3Dhtisqkr86CDIj6-vhjwz-TfHlGNqV-CLQWq3)

For our purposes, our `vaultID` was number 29 when we created the TWERKY fund.

Now that we have the `vaultID`, we need to confirm what type of fund this is and finalise, but before we do that, let's double check that we've got the right ID.

While still in the XStore Contract, move down to function number 33, xTokenAddress, and add the `vaultID` (in our example, 29).

![](https://lh6.googleusercontent.com/Gwt08_EmhWTzebtxkMUm6B6KxSPJrFU46kutqrJ_88ww45MJAnAmiESGa7AVrbOhd3DQlWIn4abrIX71jwC0WpFEM3KKmKetJKUv8LhU1TM0ZX6BYBlCHeCw9x9hjsIzmh6WI-G5)

This provides us with the address for the token as a link to that contract on Etherscan. Click the link and you will be able to see what the token contract address is.

![](https://lh3.googleusercontent.com/7eheI6mtYdPyO1DLqCoAQN61qUGgTCUDFsI2faRbPfWuiJf_A8DwiHoQESs3zYeY4eKVS3qgBNWgKeN-Kl23GG0ASSeYOLqq5mc9ItBlzMYJuUmwJDgVXro2DH-h3qJ2BXXgvaQ6)

As you can see, the Token Tracker contains the name and the token for the fund we just created. If this doesn't match your fund, someone might have created a new fund just after you, so try the preceding or following `vaultID`.

## **Step 2.5: Setting vault to ERC1155**

**This step is only required if you are creating an ERC1155 fund, otherwise skip to Step 3: Finalising the vault.**

Return to the[ https://nftx.org/#/backend](https://nftx.org/#/backend) and choose the NFTX `Write` function again, except this time instead of creating a vault we want to use `setIs1155`.

Include the vaultID as 29 (which is the vaultID for TWERKY) in the first field and the value "true" for the second field.

![](https://lh5.googleusercontent.com/5OBeefdEfX-fFg7CIotFM7eaP1AePfResppRZJnlP__lJXWIGBkkuZPV1akqTbv2jNkL4sRbvciERNPLpkSgm27FxUGkThP--yv3-vXbtXUIvIO1nw2ubXXF_YYlmteoTnOUJ50Q)

This will require a bit (but not much) more gas, as it involves another transaction. Confirm the transaction on the MetaMask prompt.

![](https://lh5.googleusercontent.com/UHuP-LtNo37J5gzphluMxOMlUd28gQhAKk-y3kkLw4ITlJ2ErrI_OB0xz2ubW_aiGsdlpO6EMyyR2_ZwcseVQVIc5uHXH1f-6RXM9KddMUUaI6B15XhaGD9nKrC19_WryUAxS46W)

Once that has been completed, it's time to finalise your vault.

## **Step 3: Finalising the Vault**

We've almost finished.

Head back to[ https://nftx.org/#/backend](https://nftx.org/#/backend) and into the NFTX → `Write` option again. This time find the `finalizeVault` function. Add the `vaultID` you confirmed a couple of steps back (in our example, 29).

![](https://lh5.googleusercontent.com/xy4ubUJHsay6d3cIZA4XrZtfdYRLiCN37YsCCgE0q1uXDr4ERFH4szyZmx54uIIivFT1eagT0eYlY3vf9c29SI4RLqDzp64OwuSdqxkANNo8DheWGz5jJart4ZLXIOvQEKySDu1Y)

This is the final transaction for creating the Vault.

![](https://lh4.googleusercontent.com/SpRCBaFIsDNQozjXo_CzKky5dxDKqgpufWBlsiUvaqAJiLzZxYLGz7FWlE45yhfWWZawEsOjmmFa6PJtulvpjIz8onknV_Xyruc-6EwnxomP2kUvzOa7sOCkCsiFM3JvOFodJLpr)

Congratulations, now you've created your first vault! 🦧🕳

### **Things to note**

1. Once you create your vault, you will not appear on the list of available funds on the NFTX.org site automatically. While it is permissionless to create funds, we want to manually approve them for display in order to prevent scams. You can still send people to your fund by providing them with a direct link,[ https://nftx.org/#/fund/](https://nftx.org/#/fund/29)**vaultID**, or in this case[ https://nftx.org/#/fund/29](https://nftx.org/#/fund/29)
2. Minting tokens isn't immediately possible until you have completed step 4. See the instructions below.
3. Your fund will not automatically be displayed on the [NFTX Gallery](/v1.0) site. This is done for two (2) reasons: to prevent scam funds from being promoted on the NFTX site AND because there are some image/content requirements for fund displays. If you would like to be added to the Gallery, please complete this form:[ https://docs.google.com/forms/d/e/1FAIpQLScnaUGFuz6-iyLTCeLhcLcFfxAdpPhGzGfxDtET7qgBIJO\_xg/viewform](https://docs.google.com/forms/d/e/1FAIpQLScnaUGFuz6-iyLTCeLhcLcFfxAdpPhGzGfxDtET7qgBIJO_xg/viewform). Once you complete and submit this form, we will review your fund.

## **Step 4: Allowing Minting**

Now that the fund has been created, we need to give permissions in order to mint NFTs into that fund.

We will need the Etherscan NFT Contract Address page for the next step(s).

As a reminder, the contract address for the NFT collection (*not your fund*) can be found listed in the Chain Info on an OpenSea page:

![](https://lh6.googleusercontent.com/RAbDlw01O2w4obiK2F8fcriDRx1FOG_V9jG5teOkUPJmpkgsoPwReASDyNPWSiE_7ayZmjqu5vGvhlIwk3ri2T18GafuJGUocofm-3j713EkE2Knn8bGYFWXE9zhlqb7tF_3AyA3)

Now that you've got that link (in our example <https://etherscan.io/address/0xf4680c917a873e2dd6ead72f9f433e74eb9c623c>), visit it and move to Contract -> `Write`.

In this step, we are specifying the NFTX Proxy contract to allow interacting with the NFT contract, with the intent to mint index fund tokens in step 5 of this tutorial.

Use the following information to fill in the `setApprovalforAll` fields on Etherscan.

* **\_operator:** 0xAf93fCce0548D3124A5fC3045adAf1ddE4e8Bf7e (NFTX proxy contract)
* **\_approved:** true

![](https://lh6.googleusercontent.com/-uX1kJJMnNwp-iNZlDBCPLjPSJCS3cEQlgrA-_2V87g2ipMlvDwGYMDaMHof1kxYBWkql_st9yDfuyWO5Gmlffe9L6quLW5lnQeIDYmOjhOeiK21mYIeKUB2DxCUncZmNDxgCT5k)

This will require another transaction and transaction fee.

![](https://lh5.googleusercontent.com/wvp90ovq73vL3vrlkOq0xCJoKUG6qaCnll2d6eEYRc0PQvHgimOgPMYayXOo3REPPZVm6FbbxtlOlNQ3bnMn9xyTP3xo-fyVmtVSufInxCWSL9HilNtduxpPNyRMQ3rh7F0xW5KC)

## **Step 5: Using your new fund**

Now that you have set up your new NFT Index Fund and allowed Minting, you can start using your fund to create Index Fund tokens (ERC20) using `Mint`.

This can be done from the frontend once the fund has been approved. If you don't want to wait, you can get started instantly on Etherscan by following the guide below.

[**Go to the NFTX contract address**](https://etherscan.io/address/0xAf93fCce0548D3124A5fC3045adAf1ddE4e8Bf7e#writeProxyContract) *\*\*0xAf93fCce0548D3124A5fC3045adAf1ddE4e8Bf7e* , click on Contracts → `Write as Proxy`, and then choose `Mint`.

**You want to include:**

* **payableAmount** — put a 0
* **vaultID** — the vault you want to mint into (likely the one you just created)
* **nftids** — you need to put these in \[48] square brackets. You can mint more than one, but separate them with commas and no spaces i.e. \[48,53,89]. These ID numbers are also listed on the OpenSea info.&#x20;
* **d2Amount** — put 0 into this field

![](https://lh5.googleusercontent.com/rD4LbjGPMO0lFIfxLqeiaHfvIO5FyDVwvbcRg3W2ikq9nZivafKvMyAVZUZ6lu4NRZnMfso0WzoeyzR4oGZrGDXGXlSSDqH5U16iqdDJV57KkhLOuGDiP8gON7p-GvefhQwmbe-D)

Once you're happy, you can click `Write` and it will ask you to confirm the transaction with your MetaMask.

![](https://lh4.googleusercontent.com/Vm-UOlYky029Fa895h53wUFRqdGZd2WNERf9MYEaNUI4HS2BDfaMMrYjyYittZXvlrAYZ4aObBzcoBh3BuOkx6BTDw_EUI5YDjbs-73l2ZCOBEmvkgAAiKI9cM2wSnxvJTNvxJbW)

Once completed, you can verify that the NFT has gone into the fund two ways.

**First way:** Check the OpenSea listing after a few minutes (takes a while to refresh) and you should see a transfer of ownership between you and NFTX.

![The minting was successful, moving the NFT into the NFTX fund.](https://lh5.googleusercontent.com/oYs-FPZoU9i3MQ8kX-6Wds7BYB6g059ISrlD0NZ1EJbfmFQ8NuHIxhVtRWcoTBX4q_5ORyqq3xh97HTza7-TUi_5j7Xd2FkqvD1mAU1mKB1GOyqSQD_0fzvb_9_cc4Mxnvlazov4)

**Second way:** Head to the[ XStore contract on Etherscan](https://etherscan.io/address/0xBe54738723cea167a76ad5421b50cAa49692E7B7#readContract) and run the Read Contract `holdingsLength` which should return the number of NFTs in your new fund.

![](https://lh4.googleusercontent.com/BtG39o4PsuiXrTF9oUGn6fCcVtFDSSAczXCXXo8_wrNFP9F8tPcQ80TBgDUe7_nF0bxVQ8LLfvoNFv1hlU16JHy2sUlhVFd4PWKtV_J8yu34o0d_Wq7v2XuSCUiFZyDchfzuI2Xa)

## **Wrapping up**

You're now a proud parent of an NFT Index Fund.

We weren't able to cover every scenario in this tutorial, but the instructors cover the process of creating your own fund. The current vault creation process is being refined by our team. Soon, the process will be simplified for our users.

Some things that weren't covered in this guide, but are possible, include:

* Adding Allow Deny lists for Funds. This is great if you want to create a fund like Punk Zombie and only allow certain NFTs (the ones with Zombie traits) from the same collection (CryptoPunks) to be minted.
* Allowing Allow ranges — This is great for funds like Art Blocks that are all on the same NFT Contract, but each project has its own distinctive range for their NFTs (based on the ID of the project).

If you have any suggestions or comments please drop by discord for a chat.


# How to get my index fund listed on the NFTX Gallery?

You've set up your NFT Index Fund and want it to be visible on the NFTX Gallery for your community? We got you.

To prevent scam funds from being promoted on the NFTX site and because there are some image/content requirements for fund displays, we've created a **listing request process** for all fund creators to follow.

Estimates of your listing request to be picked up is currently set to 24 hours, with extra time required when further due dilligence is applicable.

Below we will move past all fields you're requested to fill in. While not all fields are required, **please fill in as many as possible** to make it easier for our product team to process your request.

**Link to Listing Request:** <https://docs.google.com/forms/d/e/1FAIpQLScnaUGFuz6-iyLTCeLhcLcFfxAdpPhGzGfxDtET7qgBIJO_xg/viewform>

## Listing Details:

### **Fund Name**

This is the fully written name you'd like the fund to have when listed on the Gallery.

To be consistent between the fund as listed on the NFTX Homepage and the Gallery listing, we recommend using the same fund name that appears under the **Ticker** field on the fund page.

![](/files/-MX96Ed9hiDV2ltvXSaK)

### **Vault ID**

Please supply the fund's VaultID number. When you're unsure what your fund's VaultID is, please follow the [How to create an NFT Index Fund tutorial. ](/v1.0/archive/old-tutorials/how-to-create-an-nft-index-fund)

You can also find the VaultID by checking the fund page. It is listed at the end of the **URL** and the VaultID will match the **Fund #** on the fund's page.

![](/files/-MX966PFAj_iUl8SnzJv)

### **Description**

Please describe your fund and its underlying NFT collateral. The more clear you are describing your project, the easier it will be for users to understand and interact with your fund(s) once listed.

![](/files/-MX96HYzvE9U6DcCLW9X)

### **Buy Fund URL**

If your Index Fund is also listed on an AMM (Automated Market Maker), often referred to as Decentralized Exchange (DEX), please provide a link to the pair on i.e. SushiSwap, Uniswap or Balancer.

If you fund has liquidity spread over multiple different exchanges, please supply a link an aggregator such as Matcha or 1inch instead.

If there is no listing on an AMM available for your Index Fund, we will create an **Add Liquidity** button that will direct users to SushiSwap where anyone can add liquidity to create a liquidity pool for your fund.

![](/files/-MX96KctRCR5VmVAwuTO)

### **Name**

To make it easier interacting with you when the DAO has further questions, please provide your name. This is not required.

### **Discord Username**

Similar to having a name, having a Discord username is great for us to quickly reach out to you once we have additional questions.

### **Email address**

Please provide an email address so that we can reach out when your listing request requires additional information.


# How to mint an NFT Index token with your NFT?

In this tutorial, we will go through all the steps required to use your NFT collectible as collateral in an NFT index fund on NFTX.org.

{% embed url="<https://www.youtube.com/watch?v=63M2o2D6EjI>" %}

If you have an NFT that you want to use to mint an NFTX single-fund token, you can use the instructions below.

The guidelines below describe how to mint a PUNK-BASIC token, but this same process can be applied to any of the D1 Single-Fund tokens.

## Minting a PUNK-BASIC token

You will need to have a Wrapped Punk in order to mint a PUNK-BASIC token. If your CryptoPunk is not yet wrapped, you can use the [Wrapped Punks](https://wrappedpunks.com/) site to wrap your CryptoPunk.

With your Wrapped Punk (WPUNK), you can go to the [NFTX](https://nftx.org/#/) website.

Connect your wallet to use the NFTX minting function.

In the top right-hand corner, you will see the **Connect Account** button.

When you click this button, you will be prompted to connect using either a MetaMask or Frame wallet. Connect your wallet to proceed with the rest of the steps below.

Select the \[...] button from the homepage.

You will see three options: Mint, Redeem, or Inspect.

You can mint a token right from the index token right on the homepage, or you can select **Inspect** to review the information for that specific fund in more detail.

When you are ready to Mint your PUNK-BASIC token, select **Mint**.

A pop-out window will appear on the right-hand side of the page and there will be a prompt to insert the Token ID for your Wrapped Punk.

You can find the Token ID by reviewing your Wrapped Punk on the [Wrapped Punks](https://wrappedpunks.com/) site where you originally wrapped your CryptoPunk or you can go on [Etherscan](https://etherscan.io/) and check in your wallet for the Token ID that is listed under the ERC721 token txns list.

You will find the Token ID listed with the transaction where you wrapped your CryptoPunk.

In the Token ID field, enter the Token ID for your Wrapped Punk.

If you enter the wrong ID, you will get an error message. The Token ID needs to match the CryptoPunk you have in your wallet; otherwise, you won’t be able to mint a PUNK-BASIC token.

When you enter the Token ID in the field, you will be prompted to approve the transaction. If you are minting multiple PUNK-BASIC tokens, you can select the Approve All button at the bottom of the page. Doing this will approve all the tokens at once and save you on gas for the txn fee.

After the approval transaction is complete, you are ready to mint your token(s).

Click **Mint PUNK-BASIC token** to complete the final txn in the token creation process.

Once complete, you will see the **PUNK-BASIC minted successfully** message.The PUNK-BASIC token is now minted and in your wallet.

You have now successfully minted a single-fund index token and deposited your underlying asset.


# How to redeem an NFT from an index fund?

In this tutorial, we will go through the entire process of redeeming a random NFT (like a CryptoPunk) from one of the NFTX Index funds on NFTX.org.

{% embed url="<https://www.youtube.com/watch?v=J7VTrOJiaCY>" %}

If you have a single-fund index token that you want to use to redeem an NFT from the underlying fund, you can use the instructions below.

The guidelines below describe how to redeem a PUNK-BASIC token for the underlying CryptoPunk token, but this same process can be applied to any of the D1 single-fund tokens.

## Redeeming a PUNK-BASIC token for the underlying NFT

If you hold a PUNK-BASIC token and want to take out an NFT from the fund holdings to include the underlying CryptoPunks NFT in your collection or list the NFT on OpenSea, follow the process below.

Connect your wallet to use the NFTX redemption function.

In the top right-hand corner of the page, you will see the Connect Account button.

When you click this button, you will be prompted to connect using either a MetaMask or Frame wallet. Connect your wallet to proceed with the rest of the steps below.

Select the \[...] button next to the PUNK-BASIC fund from the homepage.

You will see three options: Mint, Redeem, or Inspect.

You can redeem an NFT from the index token right on the homepage, or you can select Inspect to review the information for that specific fund in more detail.

When you are ready to Redeem a random CryptoPunk from the Punk-Basic fund by burning your PUNK-BASIC token, select **Redeem**.

A pop-out window will appear on the right-hand side of the page and there will be a prompt to insert the number of PUNK-BASIC tokens that you want to use for redemption.

When you enter the number of tokens you want to redeem in the field, you will be prompted to approve the transaction. If you are using multiple PUNK-BASIC tokens to redeem NFTs, you can select the **Approve All** button at the bottom of the page. Doing this will approve all the tokens at once and save you on gas for the txn fee.

After the approval transaction is complete, you are ready to redeem your NFT(s).

Click **Redeem PUNK-BASIC** to complete the final txn in the redemption process.

Once complete, you will see the “Redemption was successful” message and the Token ID for your random CryptoPunk that was redeemed from the fund holdings.

You have now successfully redeemed an NFT from your single-fund index token and withdrawn the underlying asset.


# Community Raise

The NFTX token supply is 650,000 and 60% (i.e. 390k) is being distributed based on the community raise. The raise will accept both ETH and D1 NFT fund tokens to help the NFTX Dao bootstrap AMM pools. Half of the 390k tokens are for ETH contributions and the other half are for D1 NFT fund tokens. All NFTX sent to supporters in return for their contributions are vested (i.e. locked) until January 5th 2021.

The raise will begin on Dec 22, 2020 at 11am PST. There will be a per-transaction NFTX cap that starts at 0 NFTX and increases to 50,000 NFTX over the span of one hour. This is simply to avoid the possibility of whales eating up the entire supply before smaller contributors have had a chance to participate.

You can view the "XBounties" smart contract [at this link](https://etherscan.io/address/0x9C5a36AEf5A7b04b0123b2064BD20bc47183e1DC#code).

## ETH Contributions

The 195,000 NFTX tokens allocated for ETH contributions are tranched over three valuations. It is not expected that the second or third tranche will get reached anytime soon, but by pre-programming future rounds early contributors know exactly what to expect.

* Tranche 1: 65k NFTX @ 130 NFTX/ETH
* Tranche 2: 65k NFTX @ 65 NFTX/ETH
* Tranche 3: 65k NFTX @ 43.3 NFTX/ETH

## NFT Contributions

The 195,000 NFTX tokens allocated for NFT contributions are split across 16 different fund tokens which wrap 6 different NFT contracts. Here are the NFT contracts preceded by the total amount being allocated to each:

* 93,925 NFTX for CryptoPunks
* 23,400 NFTX for AxieInfinity
* 23,400 NFTX for Avastars
* 23,400 NFTX for Autoglyphs
* 19,175 NFTX for CryptoKitties
* 11,700 NFTX for JOYWORLD

Below is a list of D1 fund bounties. Each fund token has a certain reward rate which contributors are eligible for. For example, the reward rate for PUNK-BASIC is 390 NFTX, which means that if Alice mints and deposits 2 PUNK-BASIC then she will receive 2 x 390 NFTX (for a total of 780 NFTX tokens). However, each fund also has a reward cap, which is the maximum amount of NFTX tokens to be distributed. So, in our previous example, Alice's transaction would only get accepted if her transaction did not cause that category to go above its cap. The "expected" column is simply the reward cap divided by the reward rate.

| Fund           | Reward Rate | Reward Cap  | Expected |
| -------------- | ----------- | ----------- | -------- |
| PUNK-BASIC     | 390 NFTX    | 31,200 NFTX | 80       |
| PUNK-FEMALE    | 520 NFTX    | 15,600 NFTX | 30       |
| PUNK-ATTR-4    | 585 NFTX    | 14,625 NFTX | 25       |
| PUNK-ATTR-5    | 1,950 NFTX  | 15,600 NFTX | 8        |
| PUNK-ZOMBIE    | 8,450 NFTX  | 16,900 NFTX | 2        |
| GLYPH          | 1,300 NFTX  | 23,400 NFTX | 18       |
| AXIE-ORIGIN    | 130 NFTX    | 7,800 NFTX  | 60       |
| AXIE-MYSTIC-1  | 975 NFTX    | 7,800 NFTX  | 8        |
| AXIE-MYSTIC-2  | 3,900 NFTX  | 7,800 NFTX  | 2        |
| AVASTR-BASIC   | 19.5 NFTX   | 7,800 NFTX  | 400      |
| AVASTR-RANK-30 | 26 NFTX     | 7,800 NFTX  | 300      |
| AVASTR-RANK-60 | 195 NFTX    | 7,800 NFTX  | 40       |
| KITTY-GEN-0    | 32.5 NFTX   | 6,760 NFTX  | 208      |
| KITTY-GEN-0-F  | 39 NFTX     | 5,850 NFTX  | 160      |
| KITTY-FOUNDER  | 6,175 NFTX  | 6,175 NFTX  | 1        |
| JOY            | 650 NFTX    | 11,700 NFTX | 18       |

It is possible for our Dao to update this community raise smart contract and change the rate or cap for any particular fund. We will likely choose to do this in cases where the reward rate is too low to suck in any more assets, however we also encourage the community to be patient in this regard, since a rising NFTX token price translates into a higher reward rate, so with enough time it is possible that not many changes will have to be made. As a general standard, we will try to limit changes to at most once per week, and give followers at least a 24 hours notice before changes are enacted.

For those that are unsure about which fund to mint and deposit, consider comparing the prices for NFTs on OpenSea with their respective reward rates above. Also note that some NFTs have their own marketplaces which tend to be more liquid than OpenSea. CryptoPunks have the the [LarvaLabs website](https://www.larvalabs.com/cryptopunks/forsale), Axies have the [AxieInfinity marketplace](https://marketplace.axieinfinity.com/axie?title=Origin), and likewise CryptoKitties have [their own marketplace](https://www.cryptokitties.co/search/50?include=sale\&search=gen:0) as well. It may also be worth checking current supply of fund tokens on the NFTX site. It's safe to assume that anyone who has minted a fund token this early is likely planning to use it for the community raise, so if you see that one fund already has a supply which exceeds the "expected" quantity above, then that may not be a good choice since you will have to compete to not be last when the raise opens.

Some funds also require waiting 24-48 hours after minting to receive your fund tokens. This is referred to as a "mint request" and is necessary for funds which either have a very large number of potentially eligible tokens or that target an attribute which can change (e.g. the "fast" attribute on CryptoKitties). The reason for the delay is that the Dao must verify the mint requests manually, and voting takes 24 hours to complete. After the request has been verified then the requestee will receive their fund tokens (e.g. KITTY-GEN-0). If requestees change their mind or get impatient they can revoke their request and retrieve their NFTs at any time, assuming the request has not already been approved by the Dao.

Lastly, it's important for contributors to remain cognizant of gas costs, which can add up quickly both when purchasing NFTs and also when using those NFTs to mint tokens on NFTX. Gas usage for the NFTX contract is not particularly efficent, and this is something that will be improved in the future. However, in the mean time, we simply recommend that contributors wait for when gas prices are lower.

If you have any questions please visit our discord: <https://discord.gg/5ygF8rxdYR>


