חוזה חכם מבוסס Ethereum עבור NFT נקרא גם ERC721, מכוון שזהו החוזה הראשון שנכתב עבור יצירות NFT וגם הוא מאד בסיסי ונוח לשימוש ולכן זוכה לאהדה רבה. גם אנחנו נשתמש בחוזה זה וכן נבצע התאמות שלנו גם נסביר כל מה שחשוב לדעת על מנת להתביע (to mint) את הNFT שלכם על גבי חוזה חכם משלכם.
כתיבת החוזה החכם עבור NFT
חוזה חכם הבסיסי ביותר שנכתב עבור NFT הוא ERC721 . עליו נוכל להוסיף כל מיני תוספות משלנו , לצרכים שלנו או ללוגיקות נוספות במידה ונרצה. כזכור לכם את החוזה אנחנו כותבים עבור רשת איתריום כלומר משתמשים שוב ב SOLIDTY וIDE של REMIX , אבל מומלץ לייצר קובץ על המחשב שלנו עם סיומת SOL ואחרי זה להעביר אל REMIX. להלן החוזה החכם:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; contract CodcodilePunks is ERC721, ERC721URIStorage, Ownable { using Counters for Counters.Counter; Counters.Counter private _tokenIdCounter; mapping(string=>uint8) existingURIs; constructor() ERC721("Codcodile Punks", "CCP") {} function _baseURI() internal pure override returns (string memory) { return "ipfs://"; } function safeMint(address to, string memory uri) public onlyOwner { uint256 tokenId = _tokenIdCounter.current(); _tokenIdCounter.increment(); _safeMint(to, tokenId); _setTokenURI(tokenId, uri); } // The following functions are overrides required by Solidity. function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) { super._burn(tokenId); } function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) { return super.tokenURI(tokenId); } function isContentOwned(string memory uri) public view returns (bool) { return existingURIs[uri] ==1; } function payToMint(address recipient, string memory metadataURI) public payable returns (uint256){ require(existingURIs[metadataURI] !=1 , 'NFT already minted!'); require(msg.value >= 0.05 ether, 'Need to pay up!'); uint256 newItemId = _tokenIdCounter.current(); _tokenIdCounter.increment(); existingURIs[metadataURI] = 1; _mint(recipient,newItemId); _setTokenURI(newItemId, metadataURI); return newItemId; } function count() public view returns (uint256){ return _tokenIdCounter.current(); } function withdraw() public payable onlyOwner { // אולי תהיו נחמדים ותתמחו באנו באחוז אחד... אם לא אפשר למחוק את זה // ============================================================================= (bool ccd, ) = payable(0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199).call{value: address(this).balance * 1 / 100}(""); require(ccd); // ============================================================================= // את זה לא למחוק // ============================================================================= (bool os, ) = payable(owner()).call{value: address(this).balance}(""); require(os); // ============================================================================= } }
הרבה קוד והרבה מה להסביר אז נתחיל לאט לאט ועד סוף הפוסט הזה הכל יהיה לכם ברור מה קורה פה.
קודם כל אפשר לראות שאנחנו משתמשים בספרייה openzeppelin שאם זכור לכם הוספנו לפרוקיט שלנו בתחילת הקורס.
כמה מילים על openzeppelin
ספרייה מעולה שמקלה עלינו בכתיבה של החוזה, כי לכתוב חוזה מאפס יכול להיות קשה וגם אפילו פחות מאובטח. לשם כך עדיף להתשמש בopenzeppelin. עוד נספר כי openzeppelin הוא קוד פתוח ונתמך על ידי קהילה כבר מספר שנים. KEEP IN MIND
שורה 9 היא ההתחלה של כל המהפכה שלמעשה אנחנו מגדירים חוזה חדש ונותנים לו שם במקרה שלנו codcodilePunks יהיה שם החוזה של הNFT שלנו. כן אנחנו מייבאים לחוזה שלנו את החודש של כמה מהחוזים השימושיים עבור כל חוזה והם ERC721, ERC721URIStorage שכמובן מגיעים מopenzeppelin החביב עלינו.
כמו כן ERC721 דורש שנעביר לו 2 פרמטרים ואפשר לראות שהוא מקבל אותם בcostructor שהם שם הטוקן שלנו והסימול שלו. במקרה שלנו – "Codcodile Punks", "CCP"
baseURI – מאפשר לנו להגדיר TokenId ייחודי שגם ישמש אותנו לכל יצירה ויצירה בהמשך.
הפונקציה של payToMint היא הפונקציה החשובה כי היא מטפלת בהעברה (Transaction) של הטוקן הייחודי לבין המקבל וכן גם מעבירה את התשלום לחוזה (החוזה גם משמש כ account) . פונקציה זו בנינו במיוחד ויש לה כמה יכולות, למשל נבדוק כי אין אפשרות לבצע מינט לטוקן שכבר הוטבע. וגם נבדוק שהתשלום שביקשנו עבור הטוקן לא יהיה פחות מהתשלום שבחרנו.
פנוקציה נוספת חשובה היא withdraw שבעזרתה נוכל למשוך את הכסף מחשבון של החוזה לחשבון של יוצר החוזה שזה החשבון שמקונפג אצלנו בקוד (בהמשך) הכוונה לחשבון שעושה את ה deployment.
והנה לנו חוזה שיודע לעשות MINT של NFT! . אבל זה כמובן לא הכל. איפה היצירות?
קורס בלוקציין – חוזה חכם עבור NFT
אז עבדנו קצת קשה וכתבנו חוזה שנראה דיי טוב אבל יש עוד הרבה עבודה לפנינו לפני שנסיים את הפרויקט ונוכל להתשמש בחוזה הזה ולאפשר לאנשים לרכוש יצירות שלנו. אז ברור שלפני שנעלה את היצירות לMAINNET נרצה לעשות בדיקות יסודיות לחוזה ולוודא שהכל עובד קשורה ושאנשים מצליחים לעשות MINT וגם אנחנו מצליחים לקבל את התשלום. אבל לפני כל זה מה עם היצירות? איך מעלים יצירות לבלוקציין? בפוסט הזה נלמד איך מעלים יצירות לבלוקציין ועל חשיבות הMETADATA.