Розробка токену ERC-2981 (Royalties)
До ERC-2981 кожен маркетплейс реалізовував роялті по-своєму. OpenSea використовував офчейн список у базі даних. Rarible мав свій контракт. LooksRare його власну схему. В результаті творці NFT отримували роялті тільки там, де їх колекція була зареєстрована вручну. EIP-2981 стандартизував це: єдиний ончейн-інтерфейс, який будь-який маркетплейс може прочитати.
Як працює ERC-2981
Стандарт додає одну функцію до контракту:
function royaltyInfo(
uint256 tokenId,
uint256 salePrice
) external view returns (address receiver, uint256 royaltyAmount);
Під час продажу NFT маркетплейс викликає royaltyInfo(tokenId, salePrice), отримує адресу одержувача та розмір роялті. Це все. Стандарт навмисно мінімалістичний — він не примушує до виплати (примус офчейн), тільки надає дані.
Базова реалізація через OpenZeppelin:
import "@openzeppelin/contracts/token/common/ERC2981.sol";
contract MyNFT is ERC721, ERC2981 {
constructor() ERC721("MyNFT", "MNFT") {
_setDefaultRoyalty(msg.sender, 500); // 500 basis points = 5%
}
// Перевизначення роялті для конкретного токену
function setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator)
external onlyOwner {
_setTokenRoyalty(tokenId, receiver, feeNumerator);
}
}
feeNumerator — чисельник від знаменника _feeDenominator() (за замовчуванням 10000). Отже, 500 = 5%, 250 = 2.5%, максимум 10000 = 100% (не використовувати).
Розширені паттерни роялті
Royalty splitter для кількох отримувачів
Стандарт підтримує тільки одного receiver. Для розподілу між творцем, командою та фондом — потрібний додатковий контракт. Два підходи:
PaymentSplitter: receiver в ERC-2981 вказує на контракт PaymentSplitter (OpenZeppelin). Маркетплейс переводить всю суму на splitter, а splitter розподіляє за shares. Простий, перевірений, але додатковий газ на release.
Push royalty splitter: механізм, вбудований в контракт NFT, який автоматично розподіляє при кожному надходженні платежу. Економить один виклик, але ускладнює контракт.
Динамічні роялті
ERC-2981 дозволяє royaltyInfo повертати різні значення для різних tokenId. Це відкриває можливості:
- Зниження роялті зі зростанням ціни продажу (прогресивна шкала)
- Різні ставки для різних категорій токенів (tier system)
- Нульові роялті для первинного продажу, 5% для вторинного
function royaltyInfo(uint256 tokenId, uint256 salePrice)
public view override returns (address, uint256) {
uint96 rate = tokenId < 1000 ? 500 : 250; // Genesis: 5%, Regular: 2.5%
return (_royaltyReceiver, (salePrice * rate) / _feeDenominator());
}
supportsInterface для маркетплейсів
Маркетплейси перевіряють підтримку ERC-2981 через ERC-165:
function supportsInterface(bytes4 interfaceId)
public view override(ERC721, ERC2981) returns (bool) {
return super.supportsInterface(interfaceId);
}
Без правильного supportsInterface маркетплейс не буде застосовувати роялті. OpenZeppelin автоматично реєструє 0x2a55205a (ID інтерфейсу ERC-2981) при спадкуванні від ERC2981.
Кошторис по часу
Базова реалізація ERC-2981 в існуючому контракті NFT — 1 день. Контракт з динамічними роялті та splitter — 2–3 дні.







