how it works?

NFT staking – a way to lock assets (NFTs) on smart contracts with the ability to receive rewards or other protocol privileges without having to sell or transfer the NFT to another user.

A variety of projects are looking for ways to benefit NFT holders and are trying to encourage long-term ownership or involvement in the project ecosystem. For such projects, NFT staking can be a good tool for attracting new participants. And for NFT holders a way to earn passive income.

How does NFT staking work?

Typically, NFT staking requires the implementation of the following smart contracts:

  1. NFT smart contract. Staking item. Essentially an asset for staking.

  2. Smart contract Staking. NFT smart contract storage.

  3. Smart contract for rewards (rewards). This can be a token of any standard: ERC-20, ERC-721, ERC-1155.

To stake NFT the owner must transfer it into the possession of a smart contract Staking. After this, a reward will be available to him according to the rules described on the smart contract Staking. For example, for one “steaked” NFT for a period of one year, the user will receive an ERC-20 token equivalent to $100.

Rewards or perks are an incentive that should entice holders to “stake” the NFT for the place of normal ownership.

Implementation of special cases can provide off-chain privileges for the place of reward in the token. For example, a pass to a blockchain conference. This means that the smart contract Rewards may not be included in this diagram. In this scheme, various variations are possible to suit every taste.

How are staking rewards calculated?

When the reward can be measured, that is, has a quantitative characteristic, for example, the amount in an ERC-20 token, it is necessary to have a transparent system accrual of remuneration.

Such a system may depend on several factors:

  • Staking Duration. The longer an NFT is staked, the greater the potential reward.

  • Interest rate. Different platforms may offer different forms of interest: fixed rate, variable rates, rates based on activity or completion of special tasks, and the like.

  • Total staking amount. The total number of NFTs staked may influence the reward amount.

  • Rarity or property of NFT. Various NFT metrics can affect the reward amount. For example, a rare NFT can generate rewards greater than a common one.

  • Network commission. Paying for gas in order to collect rewards can negate any passive income.

For example, the formula could be:

reward= \frac{nftAmount * annualRewardAmountPerNft * stakingDuration}{secsPerYear}

  • nftAmount – number of NFTs staked by the user

  • annualRewardAmountPerNft – the amount of reward for one NFT that will be staked within one year

  • stakingDuration – real time that the NFT was staked (in seconds)

  • secsPerYear – number of seconds in a year. Is a constant and equals `31556952` seconds. This value defines 365.2425 days, which is the average length of a calendar year, according to [грегорианскому календарю](https://en.wikipedia.org/wiki/Gregorian_calendar).

Let's assume that a user has staked one NFT for 10 days (864,000 seconds). The annual reward is 1000 ERC-20 tokens. Then we can easily calculate the amount of reward:

reward = 1 * 1000 * 864000 / 31556952 ≈ 27.379

The user will receive twenty-seven (with kopecks) tokens in 10 days of staking according to our model.

Advantages and disadvantages

Like everything in this world, there are pros and cons to staking NFTs. Details in the comparison table below.

pros

Minuses

Passive income. You can receive additional assets for staking NFTs.

Impermanent loss. You may miss out on immediate profits. It may be more profitable to sell NFTs at the moment.

Diversification. Allows you to diversify the owner's asset portfolio.

Potential risk of loss. NFT physically changes its owner during staking. You can return it back only if the smart contract allows it Staking.

Increased engagement. Involves active participation in the life of the project, which develops a sense of unity and contributes to the development of the project.

Decreased Engagement. The opacity of the reward system or a long staking period with a small profit can contribute to the loss of interest of the NFT owner in the project.

Added value. Staking can provide additional utility or functionality, increasing the value of the NFT and its owner.

Lack of liquidity. Staking for a certain period will mean that the NFT cannot be sold in the near future.

A little bit of code solidity

In this section, I will describe four smart contract examples that solve different NFT staking problems.

Easiest NFT staking

To implement the simplest NFT staking, you will need one smart contract, let’s call it SimpleStaking.solwhich will regulate three main processes:

  • transfer NFT to contract

  • pick up NFT from the contract

  • verify that the contract owns the NFT

At the time of transfer of the NFT, the contract needs to record the real owner of the NFT, so that later only he can return it to himself. To do this I declared two variables:

/// @notice Хранение адресов владельцев для застейканных NFT
mapping(uint256 tokenId => address stakeholder) private _stakes;

/// @notice Хранение количества застейканных NFT для каждого адреса
mapping(address stakeholder => uint256 counter) private _stakedNftBalance;

To transfer an NFT to a contract, the owner must call the function stake().

function stake(uint256 tokenId) external {
    /// Перевод NFT от владельца контракту
    _nft.safeTransferFrom(msg.sender, address(this), tokenId);

    /// Запись данных о владельце
    _stakes[tokenId] = msg.sender;
    _stakedNftBalance[msg.sender] += 1;
}

Important! Before calling the function stake()the owner needs to call the function approve() on the NFT contract and indicate the contract address SimpleStaking.sol

To take the NFT back, the owner must call the function unstake().

function unstake(uint256 tokenId) external checkUnstake(tokenId) {
    /// Перевод NFT от контракта владельцу
    _nft.safeTransferFrom(address(this), msg.sender, tokenId);

    /// Удаление данных о владельце
    delete _stakes[tokenId];
    _stakedNftBalance[msg.sender] -= 1;
}

This kind of logic could allow some privileges to be granted to users who have staked NFTs. To do this, you need to make sure that the NFT is actually staked through a function call isStaked().

function isStaked(uint256 tokenId) external view returns (address) {
    return _stakes[tokenId];
}

Full contract code SimpleStaking.sol can be found here.

Staking with the ability to change NFT owner

The problems that NFT staking solves can be much more complex. For example, it would be nice to be able transfer ownership of the staked NFT without having to take it from the smart contract.

There are several ways to solve such a problem. Additional function can be implemented transferOwnership(uint256 tokenId, address owner) or go the route Uniswap, Compound and other protocols issuing lp tokens to confirm ownership.

I like the second option better because this mechanic gives more flexibility. Therefore, we implement it in a smart contract called SimpleTransferableStaking.sol.

To do this, you need to change the function implementations: stake() And unstake().

function stake(uint256 tokenId) external {
    /// Перевод NFT от владельца контракту
    _nft.safeTransferFrom(msg.sender, address(this), tokenId);

    /// Выдается lp nft
    _lpNft.mint(msg.sender, tokenId);
}
function unstake(uint256 tokenId) external checkUnstake(tokenId) {
    /// Перевод lp NFT от владельца контракту
    _lpNft.safeTransferFrom(msg.sender, address(this), tokenId);

    /// Перевод NFT от контракта владельцу
    _nft.safeTransferFrom(address(this), msg.sender, tokenId);

    /// Сжигается lp nft
    _lpNft.burn(tokenId);
}

You can check that the NFT is staked by calling the function ownerOf(tokenId) on the lpNft contract (will return the owner's address) or ownerOf(tokenId) on the nft contract (will return the contract address SimpleTransferableStaking.sol).

Full contract code SimpleTransferableStaking.sol can be found here.

Staking for rewards

Let's go on and on! The next example of staking will be a smart contract that will allow you to receive a one-time reward for staking an NFT for a certain period in an ERC-20 token. Let's call this smart contract StakingWithOneTimeReward.sol.

The fundamental difference is that the following concepts are introduced:

  • rewardToken – this is the token in which the reward will be paid

  • _stakeDuration – this is the time for which you need to stake the NFT

  • _rewardAmountPerNft – this is the reward amount for one NFT

We are finalizing the function again stake() и unstake(). Now it is important to store the NFT stake information (start time and duration).

function stake(uint256 tokenId) external {
    /// Перевод NFT от владельца контракту
    _nft.safeTransferFrom(msg.sender, address(this), tokenId);

    /// Запись информации о стейке NFT
    _stakes[tokenId] = StakeInfo({
        owner: msg.sender,
        start: block.timestamp,
        duration: _stakeDuration
    });
}

Function unstake() calls a function _claimReward() to send a reward token.

function unstake(uint256 tokenId) external checkUnstake(tokenId) {
    /// Отправляет вознаграждение владельцу NFT
    _claimReward(msg.sender);

    /// Перевод NFT от контракта владельцу
    _nft.safeTransferFrom(address(this), msg.sender, tokenId);

    /// Удаление данных о стейке
    delete _stakes[tokenId];
}
function _claimReward(address account) private {
    uint256 value = _rewardAmountPerNft;

    _rewardToken.safeTransfer(account, value);
}

Full contract code StakingWithOneTimeReward.sol can be found here.

Staking for annual reward

The latest complication and the latest example of a smart contract StakingWithReusableReward.sol. We will allow the NFT owner to receive a reward for staking NFT, but with the ability to withdraw it at any time an unlimited number of times.

Let’s set on the contract the amount of reward that the owner will receive if one NFT is staked for exactly one year _annualRewardAmountPerNft. From this amount we will calculate the reward for any period of time.

It is necessary to calculate the amount of remuneration (update its amount) that is due to him for any interaction of the NFT owner with the smart contract. The modifier will be responsible for this updateReward() and private function _updateReward().

  modifier updateReward(address stakeholder) {
      _updateReward(stakeholder);

      _;
  }

We attach a modifier to the functions stake(), unstake() and then the earned reward will first be calculated, and then the action of the NFT owner will be performed.

function stake(uint256 tokenId) external updateReward(msg.sender) {
    /// Перевод NFT от владельца контракту
    _nft.safeTransferFrom(msg.sender, address(this), tokenId);

    /// Сохранение информации о стейке NFT
    _stakes[tokenId] = msg.sender;

    /// Сохранение информации о накопление вознаграждения
    _stakerRewardInfo[msg.sender].tokenBalance += 1;
    _stakerRewardInfo[msg.sender].lastTimeRewardUpdated = block.timestamp;
}
function unstake(uint256 tokenId) external updateReward(msg.sender) {
    _unstake(tokenId);
}

The calculation of remuneration will be very simple. The reward amount is calculated for a certain period of time based on the reward amount for one year of the NFT “stake”.

function _calculateReward(uint256 nftAmount, uint256 startTime, uint256 endTime)
    private
    view
    returns (uint256 rewardAmount)
{
    /// Количество NFT * годовую сумму вознаграждения
    uint256 rewardPerYear = (nftAmount * _annualRewardAmountPerNft) / MULTIPLIER;

    /// Сумма за определенный период времени
    rewardAmount = (rewardPerYear * (endTime - startTime)) / SECS_PER_YEAR;
}

Full contract code StakingWithReusableReward.sol can be found here.

Sample Applications

Here are a few examples of projects that have implemented NFT staking in some form. Studying the experience of these projects can be quite useful for choosing and implementing your own NFT staking model.

Zookeeper

Zookeeper is a gamified decentralized application to provide liquidity to the ecosystem. To extract liquidity, it uses a special ZooNFT. NFTs can be earned, purchased, or won through various mechanisms within the app. Staking this NFT provides unique reward opportunities.

MOBOX (MBOX)

MOBOX is a metaverse that combines farming and NFTs. Allows you to stake NFTs and receive rewards in your own currency. NFTs within the universe are called MOMOs. Community driven. The team strives to achieve maximum transparency, so it publishes addresses their smart contracts.

Binance Fan Token Platform

Binance Fan Token Platform – a unique service that personifies the fan base of popular football clubs, giving users the opportunity to join their favorite team.

The platform has implemented a sub-service NFT PowerStation for “recharging NFTs”, which allows you to receive rewards in the form of Binance fan tokens. Rewards are distributed from a predetermined pool of tokens. It will be distributed depending on various factors: the type of NFT, the number of participants, and so on. The longer the NFT “charges,” the higher the rewards will be. Remuneration is calculated hourly.

Conclusion

Staking and NFT are two important concepts in the web3 world. Often these two technologies are used separately, but NFT staking allows us to reimagine the use of NFTs and create new use cases.

Links

1. What Is NFT Staking and How Does It Work?

2. NFT Staking Explained: Earning Passive Income with NFTs

3. Staking rewards. This is not about NFTs, but about receiving rewards.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *