# NFTXInventoryStakingV3Upgradeable

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>
