تخطي إلى المحتوى الرئيسي

كيفية كتابة ونشر رمز غير قابل للاستبدال (⁦NFT⁩) (الجزء ⁦1/3⁩ من سلسلة دروس ⁦NFT⁩)

ERC-721
Alchemy
Solidity
عقود ذكية
مبتدئ
سومي مودجيل
22 أبريل 2021
14 دقيقة للقراءة

مع لفت الرموز غير القابلة للاستبدال (NFTs) انتباه الجمهور إلى سلسلة الكتل، أصبحت الآن فرصة ممتازة لفهم هذه الضجة بنفسك من خلال نشر عقد NFT الخاص بك (رمز ERC-721) على سلسلة كتل إيثيريوم!

في هذا الدرس، سنستعرض إنشاء ونشر عقد ذكي ERC-721 على شبكة اختبار Sepolia باستخدام ميتاماسك (يفتح في علامة تبويب جديدة)، وSolidity (يفتح في علامة تبويب جديدة)، وHardhat (يفتح في علامة تبويب جديدة)، وPinata (يفتح في علامة تبويب جديدة)، وAlchemy (يفتح في علامة تبويب جديدة) (لا تقلق إذا كنت لا تفهم ما يعنيه أي من هذا بعد — سنشرح ذلك!).

في الجزء الثاني من هذا الدرس، سنستعرض كيف يمكننا استخدام عقدنا الذكي لسك رمز غير قابل للاستبدال (NFT)، وفي الجزء الثالث سنشرح كيفية عرض الرمز غير القابل للاستبدال (NFT) الخاص بك على ميتاماسك.

وبالطبع، إذا كانت لديك أسئلة في أي وقت، فلا تتردد في التواصل عبر ديسكورد Alchemy (يفتح في علامة تبويب جديدة) أو زيارة مستندات واجهة برمجة التطبيقات (API) لـ NFT الخاصة بـ Alchemy (يفتح في علامة تبويب جديدة)!

الخطوة 1: الاتصال بشبكة إيثيريوم

هناك العديد من الطرق لتقديم طلبات إلى سلسلة كتل إيثيريوم، ولكن لتسهيل الأمور، سنستخدم حسابًا مجانيًا على Alchemy (يفتح في علامة تبويب جديدة)، وهي منصة لمطوري سلسلة الكتل وواجهة برمجة التطبيقات (API) تتيح لنا التواصل مع سلسلة إيثيريوم دون الحاجة إلى تشغيل عقدنا الخاصة.

في هذا الدرس، سنستفيد أيضًا من أدوات مطوري Alchemy للمراقبة والتحليلات لفهم ما يحدث داخليًا في نشر عقدنا الذكي. إذا لم يكن لديك حساب Alchemy بالفعل، يمكنك التسجيل مجانًا هنا (يفتح في علامة تبويب جديدة).

الخطوة 2: إنشاء تطبيقك (ومفتاح واجهة برمجة التطبيقات)

بمجرد إنشاء حساب Alchemy، يمكنك إنشاء مفتاح واجهة برمجة التطبيقات (API) عن طريق إنشاء تطبيق. سيسمح لنا ذلك بتقديم طلبات إلى شبكة اختبار Sepolia. تحقق من هذا الدليل (يفتح في علامة تبويب جديدة) إذا كنت مهتمًا بمعرفة المزيد عن شبكات الاختبار.

  1. انتقل إلى صفحة "Create new app" (إنشاء تطبيق جديد) في لوحة تحكم Alchemy الخاصة بك عن طريق تحديد "Select an app" (تحديد تطبيق) في شريط التنقل والنقر على "Create new app"

Create your app

  1. قم بتسمية تطبيقك (اخترنا "My First NFT!")، وقدم وصفًا قصيرًا، واختر حالة استخدام. بعد ذلك، ابحث عن "Ethereum" وحدد الشبكة. سنستخدم Sepolia، وهي شبكة الاختبار الموصى بها لتطوير التطبيقات (انظر شبكات إيثيريوم).

  2. انقر على "Next" (التالي) للمتابعة، ثم "Create app" (إنشاء تطبيق) وهذا كل شيء! يجب أن يظهر تطبيقك في القائمة المنسدلة لشريط التنقل، مع توفر مفتاح واجهة برمجة التطبيقات (API) للنسخ.

الخطوة 3: إنشاء حساب إيثيريوم (عنوان)

نحتاج إلى حساب إيثيريوم لإرسال واستقبال المعاملات. في هذا الدرس، سنستخدم ميتاماسك، وهي محفظة افتراضية في المتصفح تُستخدم لإدارة عنوان حساب إيثيريوم الخاص بك. إذا كنت ترغب في فهم المزيد حول كيفية عمل المعاملات على إيثيريوم، فتحقق من هذه الصفحة من مؤسسة إيثيريوم.

يمكنك تنزيل وإنشاء حساب ميتاماسك مجانًا هنا (يفتح في علامة تبويب جديدة). عند إنشاء حساب، أو إذا كان لديك حساب بالفعل، تأكد من التبديل إلى شبكة اختبار "Sepolia" باستخدام قائمة اختيار الشبكة (حتى لا نتعامل بأموال حقيقية). إذا لم ترَ Sepolia مدرجة، فافتح القائمة في الزاوية العلوية اليمنى، وحدد "Networks" (الشبكات)، وقم بتشغيل "Show test networks" (إظهار شبكات الاختبار) (انظر دليل ميتاماسك لعرض شبكات الاختبار (يفتح في علامة تبويب جديدة)).

Set Sepolia as your network

الخطوة 4: إضافة إيثر من صنبور

من أجل نشر عقدنا الذكي على شبكة الاختبار، سنحتاج إلى بعض ETH الوهمي. للحصول على ETH على Sepolia، اختر أحد الصنابير المدرجة في تفاصيل شبكة Sepolia وأدخل عنوان حسابك. إذا لم يعمل أحدها، فجرب آخر لأنها قد تنفد أحيانًا، وبعضها لديه قواعد أهلية: على سبيل المثال، يتطلب صنبور Alchemy Sepolia (يفتح في علامة تبويب جديدة) أن يحتفظ العنوان المستلم بما لا يقل عن 0.001 ETH على شبكة إيثيريوم الرئيسية. يجب أن ترى ETH في حساب ميتاماسك الخاص بك بعد فترة وجيزة!

الخطوة 5: التحقق من رصيدك

للتحقق مرة أخرى من وجود رصيدنا، دعنا نجري طلب eth_getBalance (يفتح في علامة تبويب جديدة) باستخدام أداة وضع الحماية (sandbox) الخاصة بـ Alchemy (يفتح في علامة تبويب جديدة). سيعيد هذا مقدار ETH في محفظتنا. بعد إدخال عنوان حساب ميتاماسك الخاص بك والنقر على "Send Request" (إرسال الطلب)، يجب أن ترى استجابة مثل هذه:

{ "jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000" }

ملاحظة هذه النتيجة بوحدة Wei، وليس ETH. تُستخدم Wei كأصغر فئة من الإيثر. التحويل من Wei إلى ETH هو 1 eth = 1018 wei. لذلك إذا قمنا بتحويل 0xde0b6b3a7640000 إلى النظام العشري نحصل على 1*1018 wei، وهو ما يعادل 1 ETH.

أخيرًا! أموالنا الوهمية كلها موجودة.

الخطوة 6: تهيئة مشروعنا

أولاً، سنحتاج إلى إنشاء مجلد لمشروعنا. انتقل إلى سطر الأوامر واكتب:

mkdir my-nft
cd my-nft

الآن بعد أن أصبحنا داخل مجلد مشروعنا، سنستخدم npm init لتهيئة المشروع. إذا لم يكن لديك npm مثبتًا بالفعل، فاتبع تعليمات تثبيت Node.js (يفتح في علامة تبويب جديدة) (سنحتاج إلى Node.js و npm في هذا الدرس).

npm init

لا يهم حقًا كيف تجيب على أسئلة التثبيت؛ إليك كيف فعلنا ذلك كمرجع:

وافق على package.json. يدعم Hardhat 3، الذي سنقوم بتثبيته تاليًا، مشاريع وحدات ES فقط، لذا قم بتمييز المشروع على هذا النحو:

npm pkg set type=module

ونحن جاهزون للبدء!

الخطوة 7: تثبيت Hardhat (يفتح في علامة تبويب جديدة)

Hardhat هي بيئة تطوير لتجميع برمجيات إيثيريوم الخاصة بك ونشرها واختبارها وتصحيح أخطائها. إنها تساعد المطورين عند بناء العقود الذكية والتطبيقات اللامركزية (dapps) محليًا قبل نشرها على السلسلة الحية.

يتطلب Hardhat 3 إصدار Node.js v22.13.0 أو أحدث. داخل مشروع my-nft الخاص بنا، قم بتشغيل:

npm install --save-dev hardhat

تحقق من هذه الصفحة لمزيد من التفاصيل حول تعليمات التثبيت (يفتح في علامة تبويب جديدة).

الخطوة 8: إنشاء مشروع Hardhat

سيؤدي تشغيل npx hardhat --init إلى إنشاء مشروع نموذج كامل، ولكن في هذا الدرس سنقوم بإعداد الأمور يدويًا حتى تتمكن من رؤية كل جزء. في الدليل الجذري لمجلد مشروعك، قم بإنشاء ملف يسمى hardhat.config.js بالمحتويات التالية:

import { defineConfig } from "hardhat/config"

export default defineConfig({
  solidity: "0.8.34",
})

هذا هو المكان الذي سنحدد فيه جميع إعدادات مشروعنا (في الخطوة 13). في الوقت الحالي، يخبر Hardhat فقط بإصدار مترجم Solidity الذي يجب استخدامه.

الخطوة 9: إضافة مجلدات المشروع

للحفاظ على تنظيم مشروعنا، سنقوم بإنشاء مجلدين جديدين. انتقل إلى الدليل الجذري لمشروعك في سطر الأوامر واكتب:

mkdir contracts
mkdir scripts
  • contracts/ هو المكان الذي سنحتفظ فيه بكود العقد الذكي لـ NFT الخاص بنا

  • scripts/ هو المكان الذي سنحتفظ فيه بالبرامج النصية لنشر العقد الذكي الخاص بنا والتفاعل معه

الخطوة 10: كتابة عقدنا

الآن بعد إعداد بيئتنا، ننتقل إلى أشياء أكثر إثارة: كتابة كود العقد الذكي الخاص بنا!

افتح مشروع my-nft في محرر النصوص المفضل لديك (نحن نفضل VSCode (يفتح في علامة تبويب جديدة)). تُكتب العقود الذكية بلغة تسمى Solidity وهي ما سنستخدمه لكتابة العقد الذكي MyNFT.sol الخاص بنا.‌

  1. انتقل إلى مجلد contracts وقم بإنشاء ملف جديد يسمى MyNFT.sol

  2. يوجد أدناه كود العقد الذكي لـ NFT الخاص بنا، والذي استندنا فيه إلى تنفيذ ERC-721 لمكتبة أوبن زبلن (يفتح في علامة تبويب جديدة). انسخ والصق المحتويات أدناه في ملف MyNFT.sol الخاص بك.

  3. نظرًا لأننا نرث فئات من مكتبة عقود أوبن زبلن، قم بتشغيل npm install @openzeppelin/contracts في سطر الأوامر لتثبيت المكتبة في مجلدنا. يستخدم هذا الدرس عقود أوبن زبلن إصدار 5.x، والذي يتطلب Solidity 0.8.24 أو أحدث.

إذن، ماذا يفعل هذا الكود بالضبط؟ دعنا نقسمه، سطرًا بسطر.

في الجزء العلوي من عقدنا الذكي، نقوم باستيراد ثلاث فئات عقود ذكية من أوبن زبلن (يفتح في علامة تبويب جديدة):

  • يحتوي @openzeppelin/contracts/token/ERC721/ERC721.sol على تنفيذ معيار ERC-721، والذي سيرثه العقد الذكي لـ NFT الخاص بنا. (لكي يكون رمزًا غير قابل للاستبدال (NFT) صالحًا، يجب أن ينفذ عقدك الذكي جميع طرق معيار ERC-721.) لمعرفة المزيد حول وظائف ERC-721 الموروثة، تحقق من تعريف الواجهة هنا (يفتح في علامة تبويب جديدة).

  • يقوم @openzeppelin/contracts/access/Ownable.sol بإعداد التحكم في الوصول (يفتح في علامة تبويب جديدة) على عقدنا الذكي، بحيث يمكن لمالك العقد الذكي (أنت) فقط سك الرموز غير القابلة للاستبدال (NFTs). المالك هو العنوان initialOwner الذي تم تمريره إلى المُنشئ. (ملاحظة، تضمين التحكم في الوصول هو تفضيل بالكامل. إذا كنت ترغب في أن يتمكن أي شخص من سك رمز غير قابل للاستبدال (NFT) باستخدام عقدك الذكي، فقم بإزالة Ownable و Ownable(initialOwner) من تعريف العقد والمُنشئ، و onlyOwner من الدالة mintNFT.)

  • يوسع @openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol معيار ERC-721 بحيث يمكن لكل رمز مميز تخزين معرّف الموارد المنتظم (URI) للبيانات الوصفية الخاص به، والذي نحدده عند السك.

بعد عبارات الاستيراد الخاصة بنا، لدينا العقد الذكي المخصص لـ NFT، وهو قصير بشكل مدهش — فهو يحتوي فقط على عداد، ومُنشئ، ودالة واحدة! هذا بفضل عقود أوبن زبلن الموروثة، والتي تنفذ معظم الطرق التي نحتاجها لإنشاء رمز غير قابل للاستبدال (NFT)، مثل ownerOf التي تعيد مالك الرمز غير القابل للاستبدال (NFT)، و transferFrom، التي تنقل ملكية الرمز غير القابل للاستبدال (NFT) من حساب إلى آخر.

يتتبع العداد، _nextTokenId، العدد الإجمالي للرموز غير القابلة للاستبدال (NFTs) التي تم سكها ويحدد المعرف الفريد على الرمز غير القابل للاستبدال (NFT) الجديد الخاص بنا. (يجب تعيين معرف فريد لكل رمز غير قابل للاستبدال (NFT) يتم سكه باستخدام عقد ذكي — هنا يتم تحديد المعرف الفريد الخاص بنا فقط من خلال العدد الإجمالي للرموز غير القابلة للاستبدال (NFTs) الموجودة. يزيد ++_nextTokenId العداد قبل استخدامه، لذلك فإن أول رمز غير قابل للاستبدال (NFT) نسكه باستخدام عقدنا الذكي له معرف "1"، والرمز غير القابل للاستبدال (NFT) الثاني له معرف "2"، وما إلى ذلك.)

في مُنشئ ERC-721 الخاص بنا، ستلاحظ أننا نمرر سلسلتين نصيتين، "MyNFT" و "NFT". المتغير الأول هو اسم العقد الذكي، والثاني هو رمزه. يمكنك تسمية كل من هذه المتغيرات كما تشاء!

أخيرًا، لدينا الدالة mintNFT(address recipient, string memory tokenURI) التي تسمح لنا بسك رمز غير قابل للاستبدال (NFT)! ستلاحظ أن هذه الدالة تأخذ متغيرين:

  • يحدد address recipient العنوان الذي سيتلقى الرمز غير القابل للاستبدال (NFT) المسكوك حديثًا

  • string memory tokenURI عبارة عن سلسلة نصية يجب أن تشير إلى مستند JSON يصف البيانات الوصفية للرمز غير القابل للاستبدال (NFT). البيانات الوصفية للرمز غير القابل للاستبدال (NFT) هي حقًا ما يجعله ينبض بالحياة، مما يسمح له بامتلاك خصائص قابلة للتكوين، مثل الاسم والوصف والصورة والسمات الأخرى. في الجزء الثاني من هذا الدرس، سنصف كيفية تكوين هذه البيانات الوصفية.

تستدعي mintNFT بعض الطرق من مكتبة ERC-721 الموروثة، وتعيد في النهاية رقمًا يمثل معرف الرمز غير القابل للاستبدال (NFT) المسكوك حديثًا.

الخطوة 11: ربط ميتاماسك و Alchemy بمشروعك

الآن بعد أن أنشأنا محفظة ميتاماسك، وحساب Alchemy، وكتبنا عقدنا الذكي، حان الوقت لربط الثلاثة.

تتطلب كل معاملة يتم إرسالها من محفظتك الافتراضية توقيعًا باستخدام مفتاحك الخاص الفريد. لتزويد برنامجنا بهذا الإذن، يمكننا تخزين مفتاحنا الخاص (ومفتاح واجهة برمجة التطبيقات لـ Alchemy) بأمان في ملف بيئة.

لمعرفة المزيد حول إرسال المعاملات، تحقق من وثائق المعاملات.

قم بإنشاء ملف .env في الدليل الجذري لمشروعنا، وأضف مفتاحك الخاص في ميتاماسك وعنوان URL لواجهة برمجة تطبيقات Alchemy عبر HTTP إليه.

يجب أن يبدو ملف .env الخاص بك الآن هكذا:

API_URL="https://eth-sepolia.g.alchemy.com/v2/your-api-key"
PRIVATE_KEY="your-metamask-private-key"

لربط هذه المتغيرات فعليًا بالكود الخاص بنا، سنشير إليها في ملف hardhat.config.js الخاص بنا في الخطوة 13. يمكن لـ Node.js قراءة ملفات .env بمفردها، لذلك لا توجد حزمة إضافية لتثبيتها.

لا تقم بإيداع ⁦.env⁩! يرجى التأكد من عدم مشاركة أو كشف ملف ⁦.env⁩ الخاص بك لأي شخص، لأنك بذلك تعرض أسرارك للخطر. إذا كنت تستخدم نظام التحكم في الإصدار، فأضف ⁦.env⁩ إلى ملف ⁦gitignore⁩ (يفتح في علامة تبويب جديدة).

الخطوة 12: تثبيت Ethers.js

Ethers.js هي مكتبة تسهل التفاعل وتقديم الطلبات إلى إيثيريوم عن طريق تغليف طرق JSON-RPC القياسية بطرق أكثر سهولة في الاستخدام.

يجعل Hardhat من السهل جدًا دمج المكونات الإضافية (يفتح في علامة تبويب جديدة) للحصول على أدوات إضافية ووظائف موسعة. سنستفيد من المكون الإضافي Ethers (يفتح في علامة تبويب جديدة) لنشر العقد (تحتوي Ethers.js (يفتح في علامة تبويب جديدة) على بعض طرق نشر العقود النظيفة جدًا).

في دليل مشروعك اكتب:

npm install --save-dev @nomicfoundation/hardhat-ethers ethers

سنضيف أيضًا المكون الإضافي إلى hardhat.config.js الخاص بنا في الخطوة التالية.

الخطوة 13: تحديث hardhat.config.js

لقد أضفنا العديد من التبعيات والمكونات الإضافية حتى الآن، والآن نحتاج إلى تحديث hardhat.config.js حتى يتعرف مشروعنا عليها جميعًا.

قم بتحديث hardhat.config.js الخاص بك ليبدو هكذا:

يخبر configVariable Hardhat بقراءة كل قيمة من متغير بيئة فقط عند الحاجة إليها، لذلك تعمل أوامر مثل compile حتى قبل تعيين القيم. إذا كنت تفضل عدم الاحتفاظ بمفتاحك الخاص في ملف نصي عادي، فيمكن لـ Hardhat أيضًا قراءة متغيرات التكوين من مخزن المفاتيح المشفر (يفتح في علامة تبويب جديدة).

الخطوة 14: تجميع عقدنا

للتأكد من أن كل شيء يعمل حتى الآن، دعنا نجمع عقدنا. مهمة التجميع هي إحدى مهام Hardhat المدمجة.

من سطر الأوامر قم بتشغيل:

npx hardhat compile

في المرة الأولى التي تقوم فيها بالتجميع، يقوم Hardhat بتنزيل مترجم Solidity. يجب أن ترى بعد ذلك شيئًا مثل Compiled 1 Solidity file with solc 0.8.34. إذا لم يكن الأمر كذلك، يمكنك دائمًا إرسال رسالة في ديسكورد Alchemy (يفتح في علامة تبويب جديدة).

الخطوة 15: كتابة برنامج النشر النصي الخاص بنا

الآن بعد أن تمت كتابة عقدنا وملف التكوين الخاص بنا جاهز للعمل، حان الوقت لكتابة البرنامج النصي لنشر العقد.

انتقل إلى مجلد scripts/ وقم بإنشاء ملف جديد يسمى deploy.js، مع إضافة المحتويات التالية إليه:

دعنا نستعرض ما يفعله كل سطر من أسطر الكود هذه.

const { ethers } = await network.create()

في Hardhat 3، يفتح البرنامج النصي اتصالاً بشبكة بشكل صريح. يتصل network.create() بالشبكة التي تختارها باستخدام خيار --network عند تشغيل البرنامج النصي، ويضيف المكون الإضافي hardhat-ethers كائن ethers إلى هذا الاتصال.

const [deployer] = await ethers.getSigners()

يعيد getSigners() الحسابات المكونة للشبكة. على Sepolia، هذا هو الحساب الذي وضعت مفتاحه الخاص في .env. نمرر عنوانه إلى المُنشئ حتى تصبح أنت مالك العقد.

const MyNFT = await ethers.getContractFactory("MyNFT")

يعد ContractFactory في ethers.js تجريدًا يُستخدم لنشر عقود ذكية جديدة، لذا فإن MyNFT هنا هو مصنع لمثيلات عقد NFT الخاص بنا. عند استخدام المكون الإضافي hardhat-ethers، يتم توصيل مثيلات ContractFactory و Contract بالموقّع الأول افتراضيًا.

const myNFT = await MyNFT.deploy(deployer.address)

سيؤدي استدعاء deploy() على ContractFactory إلى بدء النشر، وإرجاع وعد (Promise) يتم حله إلى عقد (Contract). هذا هو الكائن الذي يحتوي على طريقة لكل وظيفة من وظائف العقد الذكي الخاص بنا. تذهب الوسائط التي تمررها إلى deploy() إلى مُنشئ العقد، وهنا عنوان initialOwner.

ينتظر waitForDeployment() حتى يتم تضمين معاملة النشر في كتلة، ويعيد getAddress() عنوان العقد الجديد. راجع وثائق عقد ethers.js (يفتح في علامة تبويب جديدة) لمزيد من التفاصيل.

الخطوة 16: نشر عقدنا

نحن مستعدون أخيرًا لنشر عقدنا الذكي! ارجع إلى الدليل الجذري لمشروعك، وفي سطر الأوامر قم بتشغيل:

npx hardhat run scripts/deploy.js --network sepolia

يجب أن ترى بعد ذلك شيئًا مثل:

Contract deployed to address: 0x4C5266cCc4b3F426965d2f51b6D910325a0E7650

إذا ذهبنا إلى Etherscan لشبكة Sepolia (يفتح في علامة تبويب جديدة) وبحثنا عن عنوان عقدنا، فيجب أن نتمكن من رؤية أنه قد تم نشره بنجاح. إذا لم تتمكن من رؤيته على الفور، يرجى الانتظار لفترة حيث قد يستغرق الأمر بعض الوقت. ستبدو المعاملة كالتالي:

View your transaction address on Etherscan

يجب أن يتطابق عنوان "From" (من) مع عنوان حساب ميتاماسك الخاص بك وسيقول عنوان "To" (إلى) "Contract Creation" (إنشاء عقد). إذا نقرنا على المعاملة، فسنرى عنوان عقدنا في حقل "To":

View your contract address on Etherscan

رائع! لقد قمت للتو بنشر العقد الذكي لـ NFT الخاص بك على سلسلة إيثيريوم (شبكة الاختبار)!

لفهم ما يحدث داخليًا، يمكنك إلقاء نظرة على الطلبات التي تلقاها تطبيقك في لوحة تحكم Alchemy (يفتح في علامة تبويب جديدة) الخاصة بك.

هناك سترى مجموعة من استدعاءات JSON-RPC التي أجراها Hardhat/Ethers داخليًا لنا عندما استدعينا دالة .deploy(). هناك استدعاءان مهمان يجب الإشارة إليهما هنا وهما eth_sendRawTransaction، وهو طلب كتابة عقدنا الذكي فعليًا على سلسلة Sepolia، و eth_getTransactionByHash وهو طلب لقراءة معلومات حول معاملتنا بناءً على التجزئة (نمط نموذجي عند إرسال المعاملات). لمعرفة المزيد حول إرسال المعاملات، تحقق من وثائق المعاملات.

هذا كل شيء بالنسبة للجزء الأول من هذا الدرس. في الجزء الثاني، سنتفاعل فعليًا مع عقدنا الذكي عن طريق سك رمز غير قابل للاستبدال (NFT)، وفي الجزء الثالث سنوضح لك كيفية عرض الرمز غير القابل للاستبدال (NFT) الخاص بك في محفظة إيثيريوم الخاصة بك!