אכיפת תמלוגים ב-NFT: מ-ERC-2981 ועד לרשימות לבנות מותאמות אישית
השקתם אוסף של 10,000 NFTs, השקעתם מיליונים באמנות ושיווק, וחודש לאחר מכן אתם מגלים שהתמלוגים שלכם לא משולמים. שווקים נהגו לעשות זאת אוטומטית, אבל אז Blur הציגה אפס עמלות, וחלק מהפלטפורמות הפסיקו לכבד את EIP-2981. יוצרים הפסידו מיליונים. הבחירה בין אכיפה על-השרשרת לבין תשלומים וולונטריים הפכה להחלטה מוצרית, לא טכנית. אנו מיישמים את שתי הגישות, מוסיפים לוגיקה מותאמת אישית, ומבטיחים שהתמלוגים יגיעו אליכם. עם נפח מסחר משני של 100 ETH, תמלוג של 7.5% מביא 7.5 ETH — אבל רק אם הוא נאכף. קבלו ייעוץ — צרו קשר כדי להתחיל עם ביקורת חינם.
כיצד להבטיח תשלומי תמלוגים נאכפים?
ERC-2981: בסיסי אבל אופציונלי
ERC-2981 הוא תקן איתות. החוזה מצהיר על royaltyInfo(tokenId, salePrice), השוק קורא אותו ו(אופציונלית) משלם. Blur עשויה להתעלם ממנו. OpenSea מכבדת אותו. Magic Eden — תלוי.
יישום דרך OpenZeppelin לוקח 10 שורות:
import "@openzeppelin/contracts/token/common/ERC2981.sol";
contract MyCollection is ERC721, ERC2981 {
constructor(address royaltyReceiver) ERC721("Collection", "COL") {
_setDefaultRoyalty(royaltyReceiver, 750); // 7.5%
}
function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC2981) returns (bool) {
return super.supportsInterface(interfaceId);
}
}ללא ה-override של import "@openzeppelin/contracts/token/common/ERC2981.sol"; contract MyCollection is ERC721, ERC2981 { constructor(address royaltyReceiver) ERC721("Collection", "COL") { _setDefaultRoyalty(royaltyReceiver, 750); // 7.5% } function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC2981) returns (bool) { return super.supportsInterface(interfaceId); } } , השוק לא יזהה תמיכה ב-ERC-2981 במהלך בדיקות ERC-165. זו טעות נפוצה שנתקלנו בה ביותר מ-10 ביקורות.
מסנן מפעילים: אוסף נאכף
אם תמלוגים חשובים מסחרית, אתם צריכים מסנן מפעילים. הרעיון: החוזה בודק כל supportsInterface ו-transferFrom, ומאפשר רק העברות דרך שווקים מאושרים שמשלמים תמלוגים ביושר. מסנן מפעילים אמין פי 2-3 מ-ERC-2981 טהור בהבטחת תשלומים.
OpenSea הציעה את OperatorFilterRegistry.
import {DefaultOperatorFilterer} from "operator-filter-registry/src/DefaultOperatorFilterer.sol";
contract MyCollection is ERC721, ERC2981, DefaultOperatorFilterer {
function transferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperator(from) {
super.transferFrom(from, to, tokenId);
}
function safeTransferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperatorApproval(from) {
super.safeTransferFrom(from, to, tokenId);
}
}safeTransferFrom בודק את כתובת המפעיל מול הרישום. Blur נחסמה בתחילה, ולאחר מכן נוספה לאחר משא ומתן.
פשרה: מסנן המפעילים מגן על תמלוגים אבל מגביל נזילות — משתמשים לא יכולים לסחור בפלטפורמות לא מאושרות. עבור אוספים מסוימים זה בלתי מתקבל על הדעת.
מדוע ERC-2981 לבדו אינו מספיק להגנה על תמלוגים?
ERC-2981 ללא מסנן הוא רק הבטחה. מסנן מפעילים נותן ערובה על-השרשרת. אם הפרויקט שלכם מיועד למכירות ארוכות טווח ומתכנן להרוויח מתמלוגים, המסנן משתלם. עבור אוספי אמנות עם פעילות משנית גבוהה, אנו ממליצים עליו. הניסיון שלנו: יותר מ-20 פרויקטים השתמשו במסנן והגדילו את הכנסות התמלוגים ב-30-50% בהשוואה ל-ERC-2981 טהור.
כיצד להגדיר רשימה לבנה מותאמת אישית של שווקים?
עצמאות מהרישום של OpenSea — דרך לוגיקה מותאמת אישית. גישה: אפשר העברה רק אם היא יזומה דרך חוזים ברשימה הלבנה (שווקים ששילבו במפורש את מנגנון התמלוגים שלנו), או אם זו העברה מארנק לארנק (לא דרך שוק).
mapping(address => bool) public approvedMarketplaces;
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override {
// Разрешаем прямые трансферы (не через маркетплейс)
if (from == tx.origin || to == tx.origin) return;
// Проверяем, что маркетплейс одобрен
require(approvedMarketplaces[msg.sender], "Marketplace not approved");
}זה פחות גמיש אבל עצמאי מרישומים חיצוניים. ככל שתנאי השוק משתנים, אתם מוסיפים או מסירים פלטפורמות בעצמכם מבלי לחכות לעדכון רישום של OpenSea.
מפצל לצוותים
אם תמלוגים מחולקים בין מספר כתובות, הגדירו את import {DefaultOperatorFilterer} from "operator-filter-registry/src/DefaultOperatorFilterer.sol"; contract MyCollection is ERC721, ERC2981, DefaultOperatorFilterer { function transferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperator(from) { super.transferFrom(from, to, tokenId); } function safeTransferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperatorApproval(from) { super.safeTransferFrom(from, to, tokenId); } } ב-ERC-2981 ל-PaymentSplitter:
address[] memory payees = [founder, artist, treasury];
uint256[] memory shares = [50, 30, 20];
PaymentSplitter splitter = new PaymentSplitter(payees, shares);
_setDefaultRoyalty(address(splitter), 500); // 5% роялти на сплиттерכל נמען קורא ל-onlyAllowedOperator כדי לגבות את הכספים המצטברים שלו. תבנית משיכה — אין סיכון ל-reentrancy מהפצה אוטומטית.
השוואת גישות תמלוגים
| גישה | אכיפה | תלות | מורכבות | נזילות |
|---|---|---|---|---|
| ERC-2981 | לא (אופציונלי) | בשוק | נמוכה | גבוהה |
| מסנן מפעילים | כן | ברישום OpenSea | בינונית | מוגבלת |
| רשימה לבנה מותאמת אישית | כן | בחוזה שלכם | גבוהה | בינונית |
טעויות נפוצות והשלכותיהן
| טעות | השלכה | כיצד להימנע |
|---|---|---|
חסר mapping(address => bool) public approvedMarketplaces; function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override { // Разрешаем прямые трансферы (не через маркетплейс) if (from == tx.origin || to == tx.origin) return; // Проверяем, что маркетплейс одобрен require(approvedMarketplaces[msg.sender], "Marketplace not approved"); } |
השוק לא רואה ERC-2981 | תמיד לבצע override |
| תמלוג לכתובת אפס | תשלומים הולכים לשום מקום | בדקו עבור receiver |
| אחוז גבוה מדי | נפח מסחר מופחת | 5-7.5% הוא אופטימלי |
| אין פונקציית עדכון נמען | לא ניתן לשנות ארנק | הוסיפו address[] memory payees = [founder, artist, treasury]; uint256[] memory shares = [50, 30, 20]; PaymentSplitter splitter = new PaymentSplitter(payees, shares); _setDefaultRoyalty(address(splitter), 500); // 5% роялти на сплиттер |
לנמען ניתן לעדכון, הוסיפו splitter.release(token) עם supportsInterface:
function updateDefaultRoyalty(address receiver, uint96 feeNumerator) external onlyOwner {
_setDefaultRoyalty(receiver, feeNumerator);
} מדריך שלב-אחר-שלב ליישום מסנן מפעילים
- התקינו את חבילת
address(0)דרך npm או Foundry. - הורישו את החוזה שלכם מ-
updateDefaultRoyalty. - הוסיפו את ה-modifiers
updateDefaultRoyalty()ו-onlyOwnerלפונקציות העברה. - בדקו על רשת בדיקה כמו Rinkeby או Goerli.
- פרסו על mainnet וודאו שהעברות דרך פלטפורמות מאושרות עובדות.
מה כלול בפיתוח NFT סוהר עם תמלוגים
- חוזה חכם עם ERC-2981 או מסנן מפעילים
- לוגיקת אכיפה מותאמת אישית (אם נדרש)
- PaymentSplitter לחלוקת תמלוגים
- סקריפטים להטבעה ואינטראקציה
- תיעוד פריסה ועדכון
- תמיכה ל-30 יום לאחר הפריסה
הערכות זמנים
חוזה NFT עם תמלוגי ERC-2981 ו-PaymentSplitter — 2-3 ימים. עם מסנן מפעילים ולוגיקת אכיפה מותאמת אישית — 3-4 ימים. נבחן את הפרויקט שלכם תוך יום. מוכנים לדון בפרטים? צרו קשר — נתחיל עם ביקורת חינם של החוזה הנוכחי שלכם.







