Стейкинг NFT - способ заблокировать активы (NFTs) на смарт-контрактах с возможностью получения вознаграждения или других привилегий протокола без необходимости продажи или передачи NFT другому пользователю.

Множество проектов ищут способы принести пользу владельцам NFT и пытаются стимулировать долгосрочное владение или вовлечение в экосистему проекта. Для таких проектов стейкинг NFT может стать хорошим инструментом привлечения новых участников. А для держателей NFT способом получать пассивный доход.

Как работает стейкинг NFT?

Обычно стейкинг NFT требует реализации следующих смарт-контрактов:

  1. Смарт-контракт NFT. Предмет стейкинга. По сути актив для стейкинга.

  2. Смарт-контракт Staking. Хранилище смарт-контрактов NFT.

  3. Смарт-контракт для вознаграждений (rewards). Это может быть токен любого стандарта: ERC-20, ERC-721, ERC-1155.

Для того, чтобы застейкать NFT владелец должен передать ее во владение смарт-контракту Staking. После этого ему будет доступно вознаграждение согласно правилам, описанным на смарт-контракте Staking. Например, за одну "застейканную" NFT сроком на один год, пользователь получит ERC-20 токен эквивалентный 100$.

Вознаграждение или привилегии являются стимулом, который должен привлекать владельцев "стейкать" NFT за место обычного владения.

Реализация частных случаев может предоставлять off-chain привилегии за место вознаграждения в токене. Например, пропуск на блокчейн конференцию. Это означает, что смарт-контракт Rewards может отсутствовать в данной схеме. В этой схеме возможны различные вариации на любой вкус.

Как рассчитывается вознаграждение за стейкинг?

Когда вознаграждение может быть измерено, то есть имеет количественную характеристику, например, сумма в ERC-20 токене, необходимо иметь прозрачную систему начисления вознаграждения.

Подобная система может зависеть от нескольких факторов:

  • Продолжительность стейкинга. Чем дольше NFT "застейкана", тем больше потенциальное вознаграждение.

  • Процентная ставка. Различные платформы могут предлагать различные формы начисления процентов: фиксированную ставку, переменные ставки, ставки, зависящие от активности или выполнения специальных заданий и тому подобное.

  • Общая сумма стейкинга. Общее количество "застейканных" NFT может влиять на размер вознаграждения.

  • Редкость или свойство NFT. Различные показатели NFT могут влиять на размер вознаграждения. Например, редкая NFT может приносить вознаграждения больше, чем обычная.

  • Комиссия сети. Оплата за газ для того, чтобы забрать вознаграждение может свести на нет любой пассивный доход.

Например, формула может быть следующая:

reward= \frac{nftAmount * annualRewardAmountPerNft * stakingDuration}{secsPerYear}
  • nftAmount - количество застейканных NFT пользователем

  • annualRewardAmountPerNft - количество вознаграждения за одну NFT, которая будет застейкана в течение одного года

  • stakingDuration - реальное время, которое NFT была застейкана (в секундах)

  • secsPerYear - количество секунд в году. Является константой и равняется `31556952` секундам. Это значение определяет 365.2425 дней, что является средней продолжительностью календарного года, согласно [грегорианскому календарю](https://en.wikipedia.org/wiki/Gregorian_calendar).

Предположим, что пользователь застейкал одну NFT на 10 дней (864000 секунд). Годовое вознаграждение составляет 1000 ERC-20 токена. Тогда мы легко можем посчитать количество вознаграждения:

reward = 1 * 1000 * 864000 / 31556952 ≈ 27.379

Двадцать семь (с копейками) токенов пользователь получит за 10 дней стейкинга согласно нашей модели.

Плюсы и минусы

Как и все в этом мире, использование стейкинга NFT несет в себе плюсы и минусы. Подробности в сравнительной таблице ниже.

Плюсы

Минусы

Пассивный доход. За стейкинг NFT можно получать дополнительные активы.

Непостоянные потери (impermanent loss). Можно упустить немедленную прибыль. Продать NFT в моменте может оказаться более выгодно.

Диверсификация. Позволяет разнообразить портфель активов владельца.

Потенциальный риск потери. NFT, физически, на время стейкинга, меняет владельца. Вернуть обратно ее можно, только если это позволяет смарт-контракт Staking.

Повышение вовлечения. Предполагает активное участие в жизни проекта, что развивает чувство единства и способствует развитию проекта.

Снижение вовлечения. Непрозрачность системы вознаграждения или большой срок стейкинга с маленьким профитом может способствовать потери интереса владельца NFT к проекту.

Добавленная стоимость. Стейкинг может давать дополнительную полезность или функционал, повышая ценность NFT и ее владельца.

Недостаток ликвидности. Стейкинг на определенный период будет означать невозможность продать NFT в ближайшее время.

Чуть-чуть solidity кода

В этом разделе я опишу четыре примера смарт-контракта, которые решают различные задачи стейкинга NFT.

Самый простой стейкинг NFT

Для реализации самого простого стейкинга NFT потребуется один смарт-контракт, назовем его SimpleStaking.sol, который будет регламентировать три основных процесса:

  • передать NFT на контракт

  • забрать NFT с контракта

  • проверить, что контракт владеет NFT

В момент передачи NFT контракту нужно записать реального владельца NFT, чтобы потом, только он, смог вернуть ее себе обратно. Для этого я объявил две переменных:

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

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

Чтобы передать NFT контракту, владелец должен вызвать функцию stake().

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

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

Важно! Перед вызовом функции stake(), владельцу необходимо вызвать функцию approve() на контракте NFT и указать адрес контракта SimpleStaking.sol

Чтобы забрать NFT обратно, владелец должен вызвать функцию unstake().

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

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

Подобная логика может позволить реализовать некоторые привилегии пользователям, которые застейкали NFT. Для этого необходимо убедиться, что NFT действительно застейкана через вызов функции isStaked().

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

Полный код контракта SimpleStaking.sol можно найти тут.

Стейкинг с возможностью сменить владельца NFT

Задачи, которые решаются стейкингом NFT, могут быть гораздо сложнее. Например, неплохо было бы иметь возможность передать право владения застейканной NFT без необходимости забирать ее у смарт-контракта.

Решать подобную задачу можно несколькими способами. Можно реализовать дополнительную функцию transferOwnership(uint256 tokenId, address owner) или пойти по пути UniswapCompound и других протоколов выдавая lp токены для подтверждения права владения.

Мне больше нравится второй вариант, потому что подобная механика дает больше гибкости. Поэтому реализуем его в смарт-контракте под названием SimpleTransferableStaking.sol.

Для этого необходимо поменять реализации функций: stake() и 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);
}

Проверить, что NFT застейкана, можно вызвав функцию ownerOf(tokenId) на контракте lpNft (вернет адрес владельца) или ownerOf(tokenId) на контракте nft (вернет адрес контракта SimpleTransferableStaking.sol).

Полный код контракта SimpleTransferableStaking.sol можно найти тут.

Стейкинг за вознаграждение

Идем по нарастающей! Следующим примером стейкинга будет смарт-контракт, который позволит получать разовое вознаграждение за стейкинг NFT на определенный период в ERC-20 токене. Назовем такой смарт-контракт StakingWithOneTimeReward.sol.

Принципиальное различие заключается в том, что вводятся следующие понятия:

  • rewardToken - это токен, в котором будет выплачиваться вознаграждение

  • _stakeDuration - это время на которое необходим застейкать NFT

  • _rewardAmountPerNft - это сумма вознаграждение за одну NFT

Снова дорабатываем функцию stake() и unstake(). Теперь важно хранить информацию о стейке NFT (время начала и продолжительность).

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
    });
}

Функция unstake() вызывает функцию _claimReward() для отправки токена вознаграждения.

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);
}

Полный код контракта StakingWithOneTimeReward.sol можно найти тут.

Стейкинг за годовое вознаграждение

Последнее усложнение и последний пример смарт-контракта StakingWithReusableReward.sol. Позволим владельцу NFT получать за стейкинг NFT вознаграждение, но с возможностью забрать его в любой момент неограниченное количество раз.

Установим на контракте сумму вознаграждения, которую владелец получит, если одна NFT будет застейкана ровно на один год _annualRewardAmountPerNft. От этой суммы будем вычислять вознаграждение для любого периода времени.

Рассчитывать количество вознаграждения (актуализировать его сумму), которое ему причитается необходимо при любом взаимодеиствии владельца NFT со смарт-контрактом. За это будет отвечать модификатор updateReward() и приватная функция _updateReward().

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

      _;
  }

Вешаем модификатор на функции stake(), unstake() и тогда будет сначала рассчитываться заработанное вознаграждение, а потом выполняться действие владельца NFT.

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);
}

Расчет вознаграждения будет очень простым. Сумма вознаграждения рассчитывается за определенный период времени на базе суммы вознаграждения за один год "стейка" NFT.

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;
}

Полный код контракта StakingWithReusableReward.sol можно найти тут.

Примеры приложений

Несколько примеров проектов, которые сделали у себя стейкинг NFT в каком-то виде. Изучение опыта этих проектов может оказаться достаточно полезным для выбора и реализации собственной модели стейкинга NFT.

Zookeeper

Zookeeper - это геймефицированное децентрализованное приложение для обеспечения экосистемы ликвидностью. Для добычи ликвидности использует специальную ZooNFT. NFT можно заработать, купить или выиграть с помощью различных механизмов в приложении. Стейкинг этой NFT предоставляет уникальные возможности получения вознаграждения.

MOBOX (MBOX)

MOBOX - это метавселенная, которая сочетает в себе фарминг и NFT. Позволяет стейкать NFT и получать вознаграждение в собственной валюте. NFT в рамках вселенной называются MOMO. Управляется сообществом. Команда стремиться достичь максимальной прозрачности, поэтому публикует адреса своих смарт-контрактов.

Binance Fan Token Platform

Binance Fan Token Platform - уникальный сервис, который олицетворяет фанатскую базу популярных футбольных клубов, предоставляя пользователям возможность присоединится к своей любимой команде.

Платформа реализовала под-сервис NFT PowerStation для "подзарядки NFTs", который позволяет получать вознаграждения в виде токенов фанатов Binance. Вознаграждение распределяется из заранее определенного пула токенов. Оно будет распределяться в зависимости от различных факторов: тип NFT, количества участников и так далее. Чем дольше NFT "заряжается", тем выше будут награды. Вознаграждение рассчитываются почасово.

Вывод

Стейкинг и NFT - две важные концепции в мире web3. Зачастую эти две технологии используются отдельно, однако стейкинг NFT позволяет переосмыслить использование NFT и создать новые варианты использования.

Links

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

2. NFT Staking Explained: Earning Passive Income with NFTs 

3. Staking rewards. Это не про NFT, но про получение вознаграждения.

Комментарии (9)


  1. NutsUnderline
    28.03.2024 06:18
    +2

    слово "физический" очень подходит для всего этого


  1. alexyr
    28.03.2024 06:18
    +2

    пытаемся состричь последние клочки шерсти с дохлой овцы?


    1. pnaydanovgoo Автор
      28.03.2024 06:18
      +4

      При чем тут шерсть?) И почему стричь?) Конечно у ERC-721 есть плохая репутация, но она связана больше с применением, в этом ключе не поспоришь. Но есть же и положительные моменты.

      Например:
      - Игровые проекты. Часто используют стандарт для токенизации персонажей и шмоток. Очень удобно хранить информации о предмете, а для обмена между пользователями можно использовать сторонние маркетплейсы или делать собственное решение.
      - RWA. Здесь только токенизация для покупки активов, обмена. Здесь блокчейн и ERC-721 позволяет ассоциировать пользователя с реальным активом. Есть тут проблемы с юридической стороной вопроса, не берусь прогнозировать найдется ли решение (хотя проекты есть). Есть проблемы и стехнической стороны, как в блокчейн доставлять данные об активах, чтобы им можно было доверять. Такое решают оракулами, ну либо не решают вовсе, что не очень хорошо.
      - Входной билет. Наличие токена позволяет предоставить доступ пользователя к ресурсам проекта, платформы. И здесь хорошо работает свойство - non fungible. Один токен - один пользователь. Некоторые проекты строят на этом процесс авторизации.
      - Право владения. Тут можно сразу вспомнить Uniswap V3, там ERC-721 доказывает право владения активами для поставщиков ликвидности. На мой взгляд, в свое время это было хорошее решение.

      Ну а теперь возвращаясь к статье. Зачем может понадобиться стейкать ERC-721? Возьму в пример игровой проект. Там часто делают, что токен (персонаж или предмет) должен быть застейкан, чтобы быть доступным для исопльзования в игре и анстекнут, чтобы была возможность обменивать токен. Отдать другу, продать на маркетплейсе. Этот механизм нужен для того, чтобы пользователь не могу передать токен и продолжать его использовать в игре какое-то время. Это возможно потому что технически между транзакцией и применением транзакции в игре проходит время. Чтобы избежать таких проблем использует подход со стейкингом токена.

      Именно поэтому статья нацелена на разбор механизма стейкинга NFT, который может пригодится для решения множества задач в разработке. Мне очень сложно судить "дохлая ли это овца?". Поэтому я не возьмусь утверждать. Но если посмотреть на defilama, то проекты в категории Nft Marketplace на 25 месте (с ними же отождествляется в первую очередь NFT) и Combined TVL равен $208,5m. Но есть же еще категории проектов, где стейкинг NFT может тоже применяться: Lending, Dexes, RWA, Launchpad, NFT Lending, Gaming и так далее. Во всех этих предметных областях можно успешно применять стейкинг NFT для решения своих задач.


      1. APXEOLOG
        28.03.2024 06:18

        Если честно, это надо было добавить в начало статьи. Потому что когда я ее читал, я вообще не понимал мотивацию отдавать свою вещь во владение кому-то, чтобы получить за это бесполезный токен.


        1. pnaydanovgoo Автор
          28.03.2024 06:18

          Тогда не осталось бы темы для дискуссии)
          Если серьезно, то я думал о том, чтобы добавить что-то подобное, но почему-то не стал, хотелось сразу перейти к части с кодом. Спасибо, что отметил, я соглашусь, что этого не хватает.


  1. APXEOLOG
    28.03.2024 06:18
    +1

    Например, за одну "застейканную" NFT сроком на один год, пользователь получит ERC-20 токен эквивалентный 100$.

    А как гарантируется стоимость этого токена?


    1. pnaydanovgoo Автор
      28.03.2024 06:18
      +4

      Это делается достаточно просто: на контракте Staking хранятся активы (вознаграждение), пользователь стейкает NFT, смарт-контракт должен отдать пользователю активы после выполнения условий. Например, время стейка NFT один месяц и по истечению только этого времени, пользователь получит NFT и активы.

      Что касается конкретно 100$ - это всего лишь пример. Количество получаемого вознаграждения должно быть соизмеримо экономике проекта. Но при этом по теории игр должно привлекать пользователя это делать и при этом быть полезным для проекта.

      Если говорить о чуть более реальном использовании. То это может работать следующим образом. Пользователь стейкает NFT, за это он получает токен протокола (это мало кому известный ERC-20 токен), через какое-то время протокол выходит на листинг и на биржах появляется ликвидность этого токена. Пользователь может обменять это актив или продолжить его хранить. Получается, что токен становится реальным активом. Проекту это дает своего рода способ распространения своего токена. А дальше этот токен ERC-20 может иметь какой-то свой вариант использования, например быть токеном для голосования.
      Если токен уже листится на бирже, то всегда можно использовать ораукулы внутри смарт-контрактов, чтобы сделать честное начисление вознаграждения. Это в случае, если количество вознаграждения зависит от стоимости токена вознаграждения.
      Пример я придумал из головы)


  1. kinguy
    28.03.2024 06:18
    +1

    Не всегда стейкинг подразумевает блокировку, что важно подметить, а то запугаете тех, кто решится на стейкинг)


    1. pnaydanovgoo Автор
      28.03.2024 06:18
      +1

      Да, да, ни в коем случае, стейкинг - это не всегда про блокировку актива. То есть стейкинг может быть реализован так, что пользователь всегда может воспользоваться своим токеном.

      Более того, не всегда токен меняет владельца для того, чтобы быть застейканным. То есть формально можно говорить, что токен стейкается, а фактически в коде смарт-контракта меняется флажок `isStaked = true;` Что позволяет по сути делать тоже самое: определять для токена два состояния: staked и unstaked. Но вот можно ли этот механизм с флажком назвать стейкингом? Я больше склоняюсь, к тому что нет. Потому что семантически stake подразумевает что-то куда-то поставить, отдать, а в этом случае этого не происходит.

      Для меня вот долгое время, когда я начинал, была неочевидна разница между стекать актив и блокировать (lock) активы. И там и там, применяется смарт-контракт, куда пользователь отдает свои активы. Но разница в том, что stake подразумевает, что пользователь будет получать что-то взамен: вознаграждение, привилегии и так далее. Блокировка в свою очередь, ничего этого не дает. Блокировка используется для того, чтобы публично показать, что ты гарантируешь полное отсутствие движения своих активов на какой-то период времени. И это все для чего нужна блокировка. Я часто встречал это в ланчпадах, когда новые проекты, которые не вышли на листинг, блокируют активы, чтобы показать своему сообществу, что они не заинтересованы сливать активы и проект сразу после листинга.

      Еще иногда можно встретить понятие заморозка (freezing) активов. На мой взгляд, этот термин нужно использовать, когда движение активов приостанавливается на какое-то время. То есть, технически, тоже самое, что блокировка, но означает это другое. Нельзя воспользоваться активами, потому что не выполнено условие при котором их можно использовать. Или например пользователь сам хочет приостановить действие активов на время. Предположим, токен имеет срок действия 1 год и это дает привилегии, по некоторой причине пользователь знает, что полгода он не сможет использовать эти привилегии, он замораживает токен и размораживает его, когда он ему снова нужен.

      В общем моя мысль такая, что все три термина: стейкинг, блокировка, заморозка очень похожи. И очень похожа их реализация. Но мне нравится стараться использовать терминологию правильно.

      P.S. Видел проекты, где во время заморозки тоже можно получать вознаграждение. Как-то так)