> For the complete documentation index, see [llms.txt](https://docs.excoms.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.excoms.io/products/nft-staking.md).

# NFT Staking

Explanation how Excoms' NFT Staking Program works.

{% hint style="info" %}
If you'd like this program for your project or would like to integrate something similar, we'll be glad if you reach us through [Contact](/contact.md).
{% endhint %}

## What it does?

Staking allows you to lock your NFT for 30 days in exchange for GENZ tokens. GENZ reward is released gradually over staking period of 30 days and you can claim your GENZ any time and as frequently as you want. Once the staking period of 30 days has ended, you can either withdraw or re-stake your NFT. NFTs can be also upgraded to increase their GENZ reward, but the upgrade is covered in [NFT Upgrading](/products/nft-upgrading.md).

To understand our NFT Staking Program, we describe its PDAs first so you see what data the Program stores.&#x20;

Once you know all the data, you'll see easily how the program works.

## PDAs

There are 3 PDA types used in Staking Program

### Global PDA

This PDA stores global variables program needs, namely the reward to be paid for all the staked NFTs.

There is just one Global PDA.

```
to_be_paid_reward: u64
```

### Role PDA

There are 2 special roles (described further) in the program. In this PDA the program stores what is a `role` of a given `address`.

There are several Role PDAs (one for each `address` that has some special role).

```
address: Pubkey      
role:    u64        
```

### NFT PDA

There is one NFT PDA for each NFT that can be staked. The PDA stores NFT `mint` address and what `tier` the NFT has (note that `tier` is NFT attribute that's stored off-chain).

Remaining fields of NFT PDA are for storing information about staking itself - who stakes the NFT (`staker_address`, when the NFT has been staked (`staked_time`), time of last claim (`last_claim_time`) and `stake_reward`.

There are 6,666 NFT PDAs (one for each Excom NFT).

```
mint:            Pubkey
tier:            u64
    
staker_address:  Pubkey
    
staked_time:     i64
last_claim_time: i64
stake_reward:    u64
```

## Logic

Some operations cannot be done by everyone. That's why Staking Program defines roles

* Admin (manages Admins, Updaters),
* Updater (registers NFT for staking).

Information on what address has what role is stored in Role PDA, that's being updated by Admin.

Updater is the one who does all the dirty work for stakers - he has initialized PDA for every NFT that can be staked - that's 6,666 PDAs, each with a size of 104 bytes consuming 0.00161472 SOL as a rent-exempt - that's over 10.76 SOL that's been paid to create all PDAs.

Updater is still active - when the NFT is upgraded and its tier goes up, Updater has to update the corresponding NFT PDA to store new tier value on-chain.

Anyone who wants to stake needs an Excom NFT. There are 4 actions users can do with Staking program

### Stake

You send NFT to Staking Program and update corresponding NFT PDA and Global PDA

* `staker_address` is set to your address, so the program knows, the NFT is yours,
* `staked_time` is set to `now`,
* `last_claim_time` is set to `now`,
* `stake_reward`, that stores how many GENZ will be paid over 30 days for this stake, is calculated based on GENZ in Staking Program reward vault and `to_be_paid_reward` in Global PDA
* `to_be_paid_reward` is increased by `stake_reward`

### Claim

You claim your GENZ reward for period between `last_claim_time` and `now` and update corresponding NFT PDA and Global PDA

* `last_claim_time` is set to `now`,
* `to_be_paid_reward` is decreased by reward that's been paid

### Withdraw

When 30 days has passed since `staked_time`, this method claims your remaining GENZ reward, sends the NFT back to you and updates corresponding NFT PDA and Global PDA

* `staker_address` is set to `Pubkey::default()`
* `staked_time` is set to `0`,
* `last_claim_time` is set to `0`,
* `stake_reward`, is set to `0`
* `to_be_paid_reward` is decreased by reward that's been paid

### Re-Stake

This is just Withdraw and Stake in a single call.

## Conclusion

Isn't this beautiful? :)
