אנו מתכננים ומפתחים חוזי ERC-721 שלא יישברו. סיפור טיפוסי: פרויקט מפרסם אוסף, רק כדי לגלות חודש לאחר מכן שתמלוגים לא משולמים ב-OpenSea (כי EIP-2981 לא יושם), המטא-דאטה נטען משרת מרכזי (שקורס), והטבעה באמצעות _safeMint במקום _mint מאפשרת כניסה חוזרת (reentrancy) דרך onERC721Received בחוזי מקבל מותאמים אישית. התוצאה: אובדן אמון הקהילה, תביעות משפטיות ושכתוב חוזים. מהניסיון שלנו: בפרויקט אחד, היעדר EIP-2981 הוביל לאובדן של 15% מהתמלוגים במכירות משניות—כ-120 ETH (~300 אלף דולר). ERC-721 תקין אינו רק עמידה בממשק; זה הבנה כיצד שווקים, ארנקים ואגרגטורים מתקשרים עם החוזה. אנו מציעים פיתוח מקצה לקצה עם ביקורת ותמיכה—צרו קשר להערכת פרויקט.
יישום בסיסי באמצעות OpenZeppelin
נקודת ההתחלה היא ERC721 מ-OpenZeppelin 5.x. איננו כותבים את התקן מאפס: OZ עבר עשרות ביקורות; כל יישום מותאם אישית מוסיף סיכון ללא תועלת ברורה. אנו מרחיבים באמצעות ירושה:
contract MyNFT is ERC721, ERC721Enumerable, ERC721URIStorage, ERC2981, Ownable {
uint256 private _nextTokenId;
uint256 public constant MAX_SUPPLY = 10000;
constructor(address initialOwner) ERC721("My Collection", "MYC") Ownable(initialOwner) {}
}contract MyNFT is ERC721, ERC721Enumerable, ERC721URIStorage, ERC2981, Ownable { uint256 private _nextTokenId; uint256 public constant MAX_SUPPLY = 10000; constructor(address initialOwner) ERC721("My Collection", "MYC") Ownable(initialOwner) {} } נדרש אם החוזה חייב להחזיר רשימת אסימונים שבבעלות כתובת (ERC721Enumerable). זה מוסיף כ-20K גז לכל העברה עקב פעולות אחסון נוספות. אם השוק אינו דורש זאת, עדיף להשמיט ולקרוא נתונים דרך The Graph.
tokenOfOwnerByIndex מאפשר אחסון URI נפרד לכל אסימון. חלופה היא תבנית ERC721URIStorage, שבה כל האסימונים משתמשים בנתיב בסיס יחיד. האפשרות השנייה זולה יותר בגז במהלך ההטבעה.
EIP-2981: תמלוגים ברמת החוזה
_setDefaultRoyalty(royaltyReceiver, royaltyBps); // bps: 500 = 5% OpenSea ורוב השווקים המודרניים קוראים baseURI + tokenId מ-EIP-2981. שווקים ישנים יותר השתמשו בתצורה מחוץ לשרשרת דרך Operator Filter Registry—גישה זו מיושנת. יישום EIP-2981 הוא התקן המינימלי לכל אוסף מודרני.
חשוב: _setDefaultRoyalty(royaltyReceiver, royaltyBps); // bps: 500 = 5% אינו נאכף על השרשרת; זה תקן אינפורמטיבי. שווקים עשויים להתעלם ממנו. לתמלוגים מחייבים, נדרשים hooks מותאמים להעברה (EIP-2981 + הגבלות העברה דרך רשימת מפעילים מורשים).
מטא-דאטה ואחסון
ה-URI של האסימון מחזיר JSON עם שדות royaltyInfo(), royaltyBps, name, description. היכן לאחסן—השוואת שיטות:
| שיטה | עלות | ביזור | עמידות | הכי מתאים ל |
|---|---|---|---|---|
| IPFS | נמוכה | כן (עם הצמדה) | דורש הצמדה | רוב האוספים |
| Arweave | בינונית (חד-פעמית) | כן | קבוע | פרויקטים ארוכי טווח |
| על השרשרת | גבוהה | מלא | קבוע | אמנות גנרטיבית (<1000 אסימונים) |
| שרת מרכזי | נמוכה | לא | תלוי במפעיל | שלב טרום-חשיפה |
שרת מרכזי מיועד רק לשלב טרום-החשיפה. לאחר החשיפה, ה-URI צריך לעבור ל-IPFS. אנו מיישמים זאת באמצעות דגל image ושני baseURIs.
כיצד לייעל הטבעה ולהפחית גז?
attributes הסטנדרטי יקר יותר מ-revealed עקב בדיקת _safeMint על כתובות חוזה. אם ההטבעה מיועדת רק ל-EOA, השתמשו ב-_mint. אם יש צורך בתמיכה בארנקי חוזה (מולטי-סיג), השתמשו ב-IERC721Receiver עם מגן כניסה חוזרת מפורש.
להטבעה בכמות, השתמשו ב-ERC-721A (Azuki) במקום ב-ERC-721 הסטנדרטי של OZ. ERC-721A מאחסן נתוני בעלות רק עבור ההטבעה הראשונה בקבוצה; אסימונים הבאים נגזרים—חוסך עד 70% בגז בעת הטבעת 10+ אסימונים. עבור אוסף של 10,000 אסימונים, זה חוסך כ-50 ETH (~100 אלף דולר) בעמלות. מחיר: העברת האסימון הראשון בקבוצה מעט יקרה יותר עקב אתחול עצל.
השוואת גז של שיטות הטבעה:
| שיטה | גז להטבעה אחת | גז ל-10 הטבעות | הגנה מכניסה חוזרת |
|---|---|---|---|
_mint |
~60k | ~600k | לא |
_safeMint |
~80k | ~800k | חלקית |
| ERC-721A | ~60k | ~150k | לא (נדרש מגן) |
אילו פגיעויות נוספות יש לסגור?
כניסה חוזרת דרך _mint
אם חוזה מקבל מיישם _safeMint, הוא יכול לקרוא חזרה לחוזה שלך במהלך ההטבעה. פתרון: השתמשו ב-ReentrancyGuard של OpenZeppelin או ב-onERC721Received ובדקו יתרה לאחר ההעברה.
קריאות ברמה נמוכה ללא בדיקה
הימנעו מ-IERC721Receiver ישיר ללא בדיקת ערך החזרה. ב-Solidity מודרני, המהדר דורש טיפול מפורש ב-_mint.
תהליך העבודה
- ניתוח (0.5-1 יום). קביעת היצע, מנגנוני הטבעה (ציבורי/רשימת היתרים/Merkle), תמלוגים, האם נדרשים Enumerable ו-URIStorage, שרשרת יעד.
- עיצוב ופיתוח (1-2 ימים). כתיבת החוזה ב-Solidity 0.8.x עם בדיקות ב-Foundry. הכנת סקריפטים לפריסה ואימות.
- ביקורת וייעול גז (0.5 יום). בדיקה עם המנתח הסטטי Slither, בדיקות fuzz עם Echidna. ייעול גז: הסרת משתני אחסון מיותרים, שימוש בבלוקים unchecked.
- פריסת Testnet (0.5 יום). Sepolia, אימות אינטראקציה עם שווקים.
- פריסת Mainnet ותמיכה (יום אחד). אימות ב-Etherscan, העברת בעלות, ניטור. תמיכה לאחר פריסה למשך 30 יום.
מה כלול בעבודה
- קוד מקור מלא של החוזה עם הערות.
- תיעוד על פונקציות, אירועים ומשנים.
- סקריפטים לפריסה ואימות עבור Etherscan.
- הוראות להגדרת מטא-דאטה (IPFS/Arweave).
- הדרכת צוות: בדיקת הטבעה, חשיפה.
- תמיכה טכנית למשך 30 יום לאחר הפריסה.
יתרונות העבודה איתנו
לצוות שלנו ניסיון של 7+ שנים בפיתוח בלוקצ'יין, עם למעלה מ-50 פרויקטי חוזים חכמים שהושלמו. איננו רק מעתיקים את התבנית של OpenZeppelin—אנו מתאימים כל אוסף לדרישות השוק הספציפיות, מגבלות הגז ומודלי ההפצה. קבלו ייעוץ—שלחו לנו תיאור של הפרויקט שלכם, ונעריך לוחות זמנים ועלויות.
// Пример контракта с whitelist и reveal contract AdvancedNFT is ERC721, ERC2981, Ownable {
using MerkleProof for bytes32[];
bytes32 public whitelistRoot;
string public baseURI;
string public placeholderURI;
bool public revealed;
uint256 public mintPrice = 0.08 ether;
function whitelistMint(bytes32[] calldata proof) external payable {
require(MerkleProof.verify(proof, whitelistRoot, keccak256(abi.encodePacked(msg.sender))));
_safeMint(msg.sender, _nextTokenId++);
}
function reveal(string memory _newBaseURI) external onlyOwner {
revealed = true;
baseURI = _newBaseURI;
}
}לוחות זמנים משוערים: ERC-721 בסיסי עם תמלוגים ומטא-דאטה ב-IPFS—2-3 ימים; עם רשימת היתרים, חשיפה ואתר הטבעה—5-7 ימים. העלות מחושבת באופן אישי. הזמינו פיתוח חוזה ERC-721 עם ביקורת ותמיכה.







