اگر بخواهی واقعا بلاکچین را بفهمی، باید یک بار همه چیز را بدون ابزارهای آماده بسازی. ساخت nft با سالیدیتی بدون فریم ورک دقیقا همین کار را می کند. این روش شاید در ابتدا سخت تر به نظر برسد، اما در عوض درک عمیقی از قرارداد هوشمند، ساختار NFT و نحوه تعامل مستقیم با بلاکچین به تو می دهد. در این آموزش قدم به قدم جلو می رویم و فقط روی خود سالیدیتی تمرکز می کنیم.

NFT چیست و چرا ساخت آن مهم است

NFT یا توکن غیرقابل تعویض، یک دارایی دیجیتال یکتا روی بلاکچین است. تفاوت NFT با توکن های معمولی در این است که هر NFT شناسه خاص خودش را دارد و قابل جایگزینی با NFT دیگر نیست. ساخت nft با سالیدیتی یعنی تو بتوانی مالکیت، انتقال و ویژگی های این دارایی دیجیتال را مستقیما در قالب کد تعریف کنی، بدون واسطه.

چرا بدون فریم ورک NFT بسازیم

فریم ورک هایی مثل Hardhat یا Truffle کار را سریع تر می کنند، اما خیلی از جزئیات را پنهان می کنند. وقتی بدون فریم ورک کار می کنی، دقیقا می فهمی قرارداد چطور کامپایل می شود، ABI چیست، گس چطور مصرف می شود و بلاکچین چطور با کدت تعامل دارد. برای یادگیری اصولی، این مسیر بسیار ارزشمند است.

پیش نیازهای ساخت NFT با سالیدیتی

برای شروع فقط به چند چیز نیاز داری. یک ادیتور کد ساده، دانش پایه سالیدیتی و دسترسی به یک کامپایلر سالیدیتی. نیازی به ابزارهای جانبی نیست. تمرکز ما فقط روی نوشتن قرارداد هوشمند استاندارد و قابل درک است.

استاندارد ERC721 چیست

اکثر NFT ها بر اساس استاندارد ERC721 ساخته می شوند. این استاندارد مشخص می کند NFT چه توابعی باید داشته باشد. مثلا ownerOf، transferFrom و balanceOf. وقتی از این استاندارد پیروی کنی، NFT تو با کیف پول ها و مارکت پلیس ها سازگار می شود. ساخت nft با سالیدیتی یعنی پیاده سازی همین استاندارد به شکل صحیح.

ساختار کلی قرارداد NFT

قرارداد NFT شامل چند بخش اصلی است. تعریف نام و نماد توکن، نگهداری مالک هر توکن، شمارنده شناسه توکن و توابع انتقال. هر بخش باید شفاف و ساده نوشته شود تا قرارداد قابل فهم و امن بماند.

تعریف قرارداد NFT پایه

در اولین قدم، قرارداد را تعریف می کنیم و اطلاعات اولیه را قرار می دهیم.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract SimpleNFT {
string public name = “Simple NFT”;
string public symbol = “SNFT”;
}

این قرارداد هنوز NFT کامل نیست، اما پایه کار را مشخص می کند. نام و نماد عمومی هستند و هر کسی می تواند آنها را بخواند.

نگهداری مالکیت توکن ها

برای هر NFT باید مشخص باشد مالک آن چه کسی است. این کار با یک mapping انجام می شود.

mapping(uint256 => address) private _owners;
mapping(address => uint256) private _balances;

در اینجا هر tokenId به یک آدرس مالک وصل می شود و تعداد توکن های هر آدرس هم ذخیره می گردد.

ایجاد شناسه یکتا برای NFT

هر NFT باید یک شناسه یکتا داشته باشد. ساده ترین راه استفاده از یک شمارنده است.

uint256 private _tokenIdCounter;

هر بار که NFT جدید ساخته می شود، این عدد افزایش پیدا می کند و به عنوان شناسه استفاده می شود.

تابع mint برای ساخت NFT

تابع mint مسئول ساخت NFT جدید است. این تابع مالکیت توکن را ثبت می کند و شمارنده را افزایش می دهد.

function mint(address to) public {
uint256 tokenId = _tokenIdCounter;
_tokenIdCounter += 1;
_owners[tokenId] = to;
_balances[to] += 1;
}

با این تابع، یک NFT جدید ساخته می شود و به آدرس مشخص شده اختصاص می یابد. این ساده ترین شکل ساخت nft با سالیدیتی است.

بررسی مالکیت NFT

برای اینکه قرارداد قابل استفاده باشد، باید بتوان مالک یک NFT را بررسی کرد.

function ownerOf(uint256 tokenId) public view returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "NFT does not exist");
return owner;
}

این تابع اگر توکن وجود نداشته باشد خطا می دهد و در غیر این صورت مالک را برمی گرداند.

انتقال NFT بین کاربران

یکی از ویژگی های اصلی NFT امکان انتقال است.

function transferFrom(address from, address to, uint256 tokenId) public {
require(ownerOf(tokenId) == from, "Not the owner");
require(to != address(0), "Invalid address");
_owners[tokenId] = to;
_balances[from] -= 1;
_balances[to] += 1;
}

در این نسخه ساده، فقط مالک مستقیم می تواند توکن را منتقل کند. برای آموزش، این کافی است.

موجودی NFT هر آدرس

برای تکمیل استاندارد، تابع balanceOf را اضافه می کنیم.

function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0), "Invalid address");
return _balances[owner];
}

این تابع تعداد NFT های یک آدرس را برمی گرداند.

افزودن رویدادها برای شفافیت

رویدادها کمک می کنند فرانت اند و ابزارها از تغییرات مطلع شوند.

event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

و داخل mint و transferFrom این رویداد را صدا می زنیم تا انتقال ثبت شود.

محدودیت های این پیاده سازی ساده

این قرارداد آموزشی است و همه قابلیت های ERC721 را ندارد. مثلا approve یا metadata پیاده سازی نشده اند. اما برای درک ساخت nft با سالیدیتی، این سطح کاملا کافی است و پایه محکمی می سازد.

چرا درک این ساختار مهم است

وقتی بدون فریم ورک NFT می سازی، می فهمی هر خط کد چه تاثیری روی امنیت، گس و رفتار قرارداد دارد. این درک باعث می شود وقتی سراغ ابزارهای حرفه ای رفتی، فقط مصرف کننده نباشی و بدانی زیرساخت چطور کار می کند.

گام بعدی بعد از این آموزش

بعد از این مرحله می توانی استاندارد ERC721 کامل را پیاده سازی کنی، metadata اضافه کنی و امنیت قرارداد را بالا ببری. همچنین می توانی این قرارداد را به یک فرانت ساده متصل کنی و NFT واقعی بسازی.

جمع بندی

ساخت nft با سالیدیتی بدون فریم ورک بهترین راه برای فهم عمیق قراردادهای هوشمند است. در این روش یاد می گیری NFT فقط یک مفهوم نیست، بلکه مجموعه ای از قوانین دقیق در بلاکچین است. اگر این پایه را درست یاد بگیری، در مراحل بعدی توسعه بلاکچین بسیار جلوتر از بقیه خواهی بود.