چگونه یک توکن بسازیم؟ | آموزش زبان سالیدیتی (Solidity) | آموزش ساختن قرارداد هوشمند | آموزش برنامه نویسی بلاک چین | آموزش برنامه نویسی ارز های دیجیتال
قرارداد هوشمند (Smart Contract)
به زبان ساده، قرارداد هوشمند یک کد برنامه نویسی است که روی بلاک چین پیادهسازی میشود تا در صورت اتفاق افتادن دادن یک سری شرایط، دستورات خاصی را که برنامه نویس به آن داده است، اجرا کند. قراردادهای هوشمند ما را از اعتماد کردن به دیگران بی نیاز میکنند.
زبان برنامه نویسی Solidity
برای اینکه بتوانیم یک قرارداد هوشمند در بستر شبکه اتریوم یا شبکه هوشمند بایننس را ایجاد کنیم ، باید از زبان برنامه نویسی Solidity استفاده کنیم. زبان برنامه نویسی Solidity در سال 2014 توسط Gavin Wood ساخته شده است. §برای اینکه بتوانیم سورس کد خود را نوشته و بروی شبکه اتریوم قرار دهیم ، باید از ویرایشگر Remix استفاده کنیم. آدرس وب سایت:
پسوند فایل ها در Solidity
فایل های سورس کد زبان Solidity با پسوند .sol ساخته میشوند. مثلا اگر بخواهیم یک قرارداد هوشمند با عنوان Greeting ایجاد کنیم ، باید یک فایل با عنوان Greeting.sol ایجاد کنیم.
دستور pragma
کامپایلر: برنامهای است که کدهای نوشته شده به زبانی که برای انسان قابل درک است را به کدهایی تبدیل میکند که برای ماشین (سخت افزار) قابل درک باشد.
پیش از اینکه شروع به نوشتن کد با استفاده از زبان Solidity کنیم ، ابتدا باید ورژن زبان هدف را برای کامپایلر مشخص کنیم. این کار با استفاده از دستور زیر انجام میشود:
همچنین میتوانیم یک بازه برای ورژن هم تعیین کنیم. مثلا میخواهیم تعیین کنیم که تمامی کامپایلر ها از ورژن 0.5.0 تا ورژن 0.9.0 بتوانند کد ما را تبدیل کنند:
دستور contract
برای آنکه بخواهیم یک قرارداد هوشمند جدید ایجاد کنیم ، ابتدا باید دستور contract را نوشته و سپس اسم قرارداد هوشمند را به صورت Capital بنویسیم.
ویدیو قسمت دوم
متغیر در زبان برنامه نویسی Solidity
برای آنکه بهتر با مفهوم متغیر یا Variable در زبان برنامه نویسی Solidity آشنا شویم ، میخواهیم یک مینی پروژه را انجام دهیم. در این مینی پروژه قرار است یک قرارداد هوشمندی ایجاد کنیم که دو عدد 10 و 40 را جمع کرده و حاصل این جمع را به کاربر نشان دهد.
مینی پروژه اول
اما ابتدا میخواهیم بررسی کنیم که زمانی که کامپیوتر در حال جمع در مقدار 10 و 40 است ، چه اتفاقی در سخت افزار می افتد. به طور کلی میخواهیم این فرآیند را از لحاظ سخت افزاری بررسی کنیم.
فرض کنید ما کد قرارداد هوشمند خود را نوشته ایم و این کد را بروی هارد کامپیوتر ذخیره کرده ایم. اما زمانی که کد بروی هارد ذخیره میشود عملیات جمع را برای ما انجام نمیدهد و برای این کار باید ابتدا کد را اجرا کنیم. ما با ارسال یک درخواست به قرارداد هوشمند ، میتوانیم سورس کد آن را اجرا کنیم. پس از آنکه کد اجرا شد ، سورس ما از هارد کامپیوتر به رم کامپیوتر منتقل میشود.
پس از آنکه کد بروی رم قرار گرفت ، عملا دو مقدار 10 و 40 ایجاد شده و هر کدام در بخشی از رم ذخیره میشوند. در مرحله بعد با کمک حاصل جمع این اعداد محاسبه شده و نتیجه که عدد 50 است به کاربر نمایش داده میشود. سپس کد از روی رم خارج شده ، پس در نتیجه مقادیر 10 و 40 هم از بین خواهند رفت.
متغیر در Solidity
متغیر یک فضایی برای ذخیره سازی داده ها است. هر متغیر یک نام منحصر به فرد و مخصوص به خود دارد که باعث میشود از بقیه متغیر ها متمایز باشد. هر متغیر از سه بخش تشکیل شده است:
- نوع متغیر
- نام متغیر
- مقدار متغیر
تعریف یک متغیر در Solidity
برای تعریف یک متغیر در زبان Solidity باید چهار مرحله را طی کنیم:
- مرحله اول) اختصاص دادن یک نوع به متغیر. مثلا برای ذخیره یک مقدار عددی از uint استفاده میکنیم.
- مرحله دوم) اختصاص دادن یک نام به متغیر (میتوانید نام دلخواه را انتخاب کنید)
- مرحله سوم) قرار دادن علامت مساوی در سمت راست نام متغیر
- مرحله چهارم) اختصاص دادن یک مقدار به متغیر
استفاده از Semicolon در Solidity
در زبان برنامه نویسی Solidity باید در انتهای یک statement از علامت Semicolon یا ; استفاده کنیم. در غیر این صورت با خطای کامپایلر مواجه خواهیم شد.
سورس کد این جلسه:
pragma solidity 0.8.11;
contract Greeting {
uint number1 = 10;
uint number2 = 40;
uint public number3 = number1 + number2;
}
ویدیو قسمت سوم
لایسنس برای پروژه های متن باز
به طور کلی زمانی که سورس قرارداد های هوشمند به شکل Open Source در دسترس همه افراد باشد ، از لحاظ کارایی میتوان بیشتر به آن ها اعتماد کرد. به دلیل آنکه انتشار سورس کد به صورت متن باز ، میتواند مسائل قانونی و Copyright به همراه داشته باشد ، پس باید یک قوانینی برای انتشار سورس کد قرارداد های هوشمند تعریف شود.
چرا باید لایسنس تعریف کرد؟ به دلیل آنکه اگر شخص یا شرکتی بخواهد از سورس کدی که توسط ما منتشر شده است استفاده کند ، حقوق خود را در مورد ویرایش ، کپی ، انتشار و فروش آن بداند. به همین دلیل کامپایلر Solidity از شما انتظار دارد که یک لایسنس را در ابتدای سورس کد خود تعریف کنید.
لایسنس SPDX
در صنعت نرم افزار یک لیست ای لایسنس های موجود تعریف شده است. به این لیست SPDX یا Software Package Data Exchange گفته میشود. این لیست توسط بنیاد لینوکس تایید شده و معتبر است. آدرس وب سایت:
دو مورد از پر کاربرد ترین لایسنس ها در سورس کد قرارداد های هوشمند:
- MIT
- Apache-2.0
در این دو لایسنس ، حقوق زیر برای استفاده کننده آزاد است:
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software
تعریف لایسنس در Solidity
برای تعریف لایسنس در سورس کد Solidity از دستور زیر استفاده کنیم:
// SPDX-License-Identifier: License Type
به طور مثال میتوان نوشت:
// SPDX-License-Identifier: MIT OR Apache-2.0
در صورتی که سورس کد ما به صورت خصوصی و Private نوشته شده است و امکان انتشار ندارد باید به این صورت لایسنس آن تعریف شود:
// SPDX-License-Identifier: UNLICENSED
ویدیو – قسمت چهارم
تابع (Function) در زبان برنامه نویسی Solidity
زمانی که یک قرارداد هوشمند را ایجاد میکنیم ، میخواهیم یک وظیفه و کار خاص را در آن قرارداد هوشمند انجام دهیم. به طور مثال:
- در قرارداد هوشمند مربوط به یک صرافی غیر متمرکز ، میخواهیم توکن ها را به یکدیگر تبدیل کنیم.
- در قرارداد هوشمند یک فروشگاه محصولات NFT ، میخواهیم یک توکن NFT ایجاد کرده و آن را معامله کنیم.
- در قرارداد هوشمند یک پلتفرم وام دهی ، میخواهیم میزان وثیقه و قیمت لیکویید شدن را محاسبه کنیم.
تابع (Function): در زبان های برنامه نویسی تابع مانند یک کارمندی است که توسط برنامه نویس (کارفرما) استخدام میشود. کارفرما وظیفه یک کارمند را مشخص میکند. سپس به کارمند گفته میشود که کار خود را انجام داده و نتیجه را به کارفرما گزارش کند. پس زمانی که در یک قرارداد هوشمند 5 تابع تعریف میکنیم ، به این معناست که 5 کارمند را استخدام کرده ایم و هر کدام یک وظیفه خاصی دارند. سپس آن وظیفه را انجام داده و نتیجه کار را به کارفرما گزارش میکنند.
اعمال روی تابع
در مبحث تابع ، با دو مفهوم اساسی سر و کار داریم:
- اول) تعریف یک تابع
- دوم) فراخوانی یک تابع
برای تعریف یک تابع (Function) در زبان Solidity باید مراحل زیر را طی کنیم:
- 1- قرار دادن کلید رزرو شده function
- 2- قرار دادن نام تابع
- 3- قرار دادن علامت های پرانتز باز و بسته در سمت راست نام تابع
- 4- قرار دادن عبارت public : در ویدیو های بعدی در مورد این موضوع صحبت خواهد شد.
- 5- قرار دادن این علامت کروشه باز و بسته در سمت راست پرانتز
- 6- قرار دادن دستور مورد نظر جهت اجرا شدن
مینی پروژه
هدف: قرارداد هوشمندی بسازید که دو عدد 10 و 40 را جمع کرده و نتیجه را به کاربر نشان دهد. میخواهیم این عمل جمع را در تابعی با عنوان Add انجام دهیم.
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.11;
contract Greeting {
uint number1 = 10;
uint number2 = 40;
uint public sum;
function add() public {
sum = number1 + number2;
}
}
فراخوانی یک تابع
برای فراخوانی یک تابع از دو روش زیر استفاده میکنیم: در مرحله اول تابع را تعریف میکنیم.
- روش اول ) در مرحله دوم باید تابع را فراخوانی کنیم. با کلیک کردن بروی دکمه getMessage تابع فراخوانی میشود.
- روش دوم) استفاده از یک تابع در تابعی دیگر: در این روش ابتدا نام تابع را نوشته و سپس علامت پرانتز باز و بسته را قرار میدهیم.
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.11;
contract Greeting {
uint number1 = 10;
uint number2 = 40;
uint public sum;
function add() public {
sum = number1 + number2;
}
function testFunc() public {
add();
}
}
جمع بندی بحث توابع
مزیت های استفاده از تابع در برنامه نویسی:
- یک بخش از سورس کد است که یک وظیفه خاصی را انجام میدهد.
- یک تابع قابلیت اجرا شدن دارد. (اجرا شدن = فراخوانی)
- یک تابع میتواند بار ها و بار ها مورد استفاده قرار بگیرد.
- یک تابع تعداد خط سورس کد ما را کاهش داده و باعث خوانا تر شدن سورس کد میشود.
- توابع ، یک سورس کد بسیار بزرگ را به چند بخش کوچکتر تقسیم میکنند.
ویدیو – قسمت پنجم
سطح دسترسی
در مینی پروژه هایی که در ویدیو های قبلی آنها را انجام دادیم ، از واژه public استفاده کردیم. اما این واژه چه کاربردی دارد؟ برای درک بهتر موضوع Visibility با یک مثال شروع میکنیم.
فرض کنید ساختمان یک شرکت نرم افزاری دارای سه طبقه است. طبقه اول مخصوص کارمندان اداری ، طبقه دوم مخصوص برنامه نویسان و طبقه سوم مخصوص مدیر عامل است. در این ساختمان یک آسانسور وجود دارد که با استفاده از آن میتوان به طبقات مختلف دسترسی داشت. باید دقت کنید که برای استفاده از این آسانسور حتما باید از کارت شناسایی خود استفاده کنید.
اما برای این آسانسور قوانین مختلفی تعریف شده است:
- کارمندان اداری اجازه ورود به طبقه دوم و سوم را ندارند.
- برنامه نویسان اجازه ورود به طبقه سوم را ندارند.
- مدیر عامل اجازه دسترسی به تمامی طبقات را دارد.
در حقیقت برای استفاده از طبقات این ساختمان ، سطوح دسترسی تعریف شده و همه افراد به تمامی طبقات دسترسی ندارند.
Visibility در سالیدیتی
هر کدام از متغیر ها و توابعی که تعریف میکنیم ، میتوانند سطح دسترسی داشته باشند. به این معنا که آن متغیر یا تابع چگونه در دسترس قرار میگیرد.
در زبان Solidity ، 4 نوع Visibility وجود دارد:
- Public: متغیر یا تابع ، خارج از قرارداد هوشمند هم در دسترس است.
- Private: متغیر یا تابع ، فقط در داخل قرارداد در دسترس است.
- Internal: متغیر یا تابع فقط در داخل قرارداد و قرارداد های هوشمندی که ارث بری کنند ، در دسترس است.
- External: تابع ، فقط در خارج از قرارداد در دسترس است.
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.11;
contract Greeting {
uint number1 = 10;
uint number2 = 40;
uint public sum;
function add() public {
sum = number1 + number2;
}
}
contract Foo {
Greeting sample;
function getData() public {
sample.add();
}
}
ویدیو قسمت ششم
انواع داده ها (Data Types) در سالیدیتی
در زبان برنامه نویسی Solidity انواع داده ها به دو دسته کلی تقسیم میشوند:
- Value Types
- Reference Types
نوع int و uint
نوع int: برای ذخیره مقادیر عددی غیر اعشاری استفاده میشود. در این نوع داده ای میتوان اعداد مثبت و منفی را ذخیره کرد. (Integer)
نوع uint: برای ذخیره مقادیر عددی غیر اعشاری مثبت استفاده میشود. در این نوع داده ای فقط میتوان اعداد مثبت را ذخیره کرد. (Unsigned)
بدست آوردن مقادیر Max و Min
برای بدست آوردن مقدار Max و Min یک نوع داده ای ، میتوانیم از دستورات زیر استفاده کنیم:
نوع Boolean
نوع bool: برای ذخیره یک مقدار true یا false استفاده میشود. معمولا از متغیر های bool در شرط ها استفاده میشود.
bool public testBool = false;
function setTrue() public {
testBool = true;
}
نوع address
نوع address: برای ذخیره یک آدرس استفاده میشود. آدرس در قالب Hexadecimal ذخیره میشود و حتما باید 0x در ابتدای آن قرار داشته باشد. دقت کنید که برای ذخیره یک آدرس از Single Quote یا Double Quote استفاده نکنید.
address public ownerAddress;
function setNewAddress() public {
ownerAddress = 0xf62706350145ebaf32B6ff98ceF3941a81D896E0;
}
نوع string
Character: به هر تگ واج یک کاراکتر گفته میشود. مثل: A یک کاراکتر است – ? یک کاراکتر است.
String: به مجموعه ای از کاراکتر ها ، رشته یا string گفته میشود.
نوع string: برای ذخیره کردن یک کاراکتر یا یک رشته (string) استفاده میشود. برای ذخیره یک رشته ، باید از علامت های Single Quote یا Double Quote استفاده کنیم.
string public myChar = 'A';
//string public myChar = "A";
string public projectName = 'Bitcoin';
string public symbol = 'BTC';
function setString() public {
projectName = 'Ethereum';
}
نوع fixed و ufix
نوع fixed و ufixed: اعداد اعشاری میتوانند در Solidity تعریف شوند اما نمیتوان مقداری به آن ها اختصاص داد. به طور کلی زبان Solidity هنوز به طور کامل از اعداد اعشاری پشتیبانی نمیکند. مثلا مقادیری مثل 12.5 یا مثلا 150.56 را نمیتوان در Solidity تعریف کرد. برای مطالعه بیشتر به لینک زیر مراجعه کنید:
https://docs.soliditylang.org/en/v0.8.10/types.html#fixed-point-numbers
ویدیو قسمت هفتم
مقدار برگشتی از یک تابع
همانگونه که در ویدیو های قبلی گفته شد ، تعریف یک تابع مشابه با استخدام یک کارمند است. ما به عنوان یک برنامه نویس یک کارمند را برای انجام وظیفه خاص استخدام میکنیم. اما نکته مهم این است که از کارمند استخدام شده (تابع تعریف شده) انتظار داریم تا نتیجه کار را به ما برگرداند.
مراحل برگشت مقدار از تابع
برای اینکه بخواهیم یک مقدار را از یک تابع برگشت دهیم ، باید سه مرحله را طی کنیم:
- مرحله اول) در انتهای تعریف تابع ، باید واژه returns را قرار دهیم.
- مرحله دوم) باید نوع مقدار برگشتی را داخل پرانتز های جلوی returns بنویسیم. در حقیقت باید مشخص کنیم که مقدار برگشتی از تابع چه نوعی است.
- مرحله سوم) در قسمت تعریف تابع با استفاده واژه return مقدار مربوطه را برگشت میدهیم.
contract Test {
uint private myNumber;
function testG() public returns (uint) {
return myNumber;
}
}
برگشت چند مقدار از یک تابع
برای اینکه بتوانیم چندین مقدار را از یک تابع برگشت دهیم ، باید ابتدا مقادیر برگشتی را داخل پرانتز جلوی returns نوشته و با علامت , انگلیسی از یکدیگر جدا کنیم. سپس مقادیر مربوطه را جلوی return درون پرانتز قرار میدهیم.
contract Test {
uint private myNumber1;
uint private myNumber2;
uint private myNumber3;
function testG() public returns (uint, uint, uint) {
return (myNumber1, myNumber2, myNumber3);
}
}
پارامتر و آرگومان در Solidity
به متغیری که در زمان تعریف تابع بین پرانتز ها نوشته میشود ، پارامتر میگویند. به متغیری که در زمان فراخوانی تابع بین پرانتز ها نوشته میشود ، آرگومان میگویند.
در کد زیر ، متغیر های number1 و number2 به عنوان پارامتر های تابع و مقادیر 100 و 200 به عنوان آرگومان های تابع در نظر گرفته میشوند.
contract Test {
function calculate(uint number1, uint number2) private pure returns (uint) {
return number1 + number2;
}
function callCalculate() public pure returns (uint) {
return calculate(100, 200);
}
}
View و Pure در Solidity
برای آنکه با بحث View و Pure بهتر آشنا شویم ، ابتدا باید انواع متغیر ها در Solidity را بررسی کنیم:
- متغیر State: قبل از تعریف توابع تعریف میشود.
- متغیر Local: درون یک تابع تعریف میشود.
- متغیر Global: به صورت سراسری وجود دارد و نیازی به تعریف کردن آن نیست و فقط از آن استفاده میکنیم.
زمانی که یک تابع هیچ تغییری بروی یک متغیر انجام نمیدهد ، میتواند در دو دسته قرار بگیرد:
- View: تابعی که بروی هیچ متغیری از نوع State ، تغییری ایجاد نمیکند ولی میتواند به آن دسترسی داشته باشد. (میتواند Read کند.)
- Pure: تابعی که بروی هیچ متغیری از نوع State یا Global ، تغییری ایجاد نمیکند و نمیتواند به آن دسترسی داشته باشد. (نمیتواند Read کند.)
contract TestCodes {
uint private myNumber = 100;
function setValue() public {
myNumber = 10;
}
function getValue() public view returns(uint) {
return myNumber;
}
function calculate() public pure returns(uint) {
uint a = 100;
uint b = 200;
return a + b;
}
}
انواع فراخوانی تابع
زمانی که یک تابع را فراخوانی میکنیم ، ممکن است دو موضوع اتفاق بیفتد:
- یک تراکنش انجام شود و در نتیجه یک Transaction ID برگشت داده شود. مثلا زمانی که میخواهیم یک مقدار را بروی بلاک چین ذخیره کنیم. مثلا بروی یک متغیر State ذخیره کنیم. در این حالت رنگ تابع در بخش رابط کاربری نارنجی بوده و برای فراخوانی این تابع باید به شبکه هزینه پرداخت کنیم.
- یک Call یا فراخوانی انجام شود و بدون انجام تراکنش ، یک مقدار برگشت داده میشود. در این حالت رنگ تابع در بخش رابط کاربری آبی بوده و برای فراخوانی این تابع نیازی به پرداخت هزینه به شبکه نیست. (استفاده از view – pure)
سازنده (Constructor) در Solidity
سازنده یا Constructor چیست؟
سازنده یک نوع خاصی تابع (Function) است که در زمان Deploy شدن قرارداد هوشمند یک بار اجرا میشود. باید دقت کنید که تعریف سازنده در یک قرارداد هوشمند اختیاری است. معمولا از سازنده برای مقداردهی اولیه متغیر ها استفاده میشود. سازنده باید در خط های اول تعریف یک قرارداد هوشمند ، قرار داشته باشد.
برای تعریف تابع سازنده از دستور زیر استفاده میکنیم:
contract TehranToken is IERC20 {
constructor() {
}
}
همانگونه که مشاهده میکنید برای تعریف یک سازنده از واژه function استفاده نمیکنیم و فقط از واژه رزرو شده constructor استفاده میکنیم. همچنین هیچگونه سطح دسترسی مثل public و یا private هم برای آن تعریف نمیکنیم. همچنین باید بدانیم که تابع سازنده هیچ مقداری را برگشت نمیدهد و از نوع view یا pure هم نمیتواند باشد.
ذخیره دیپلوی کننده کانترکت با استفاده از تابع سازنده
فرض کنید میخواهیم آدرس کیف پول شخصی که قرارداد هوشمند را بروی شبکه Deploy میکند را به عنوان مالک یا Owner ذخیره کنیم. در این حالت باید از تابع سازنده استفاده کنیم:
contract TehranToken is IERC20 {
address public owner;
constructor() {
owner = msg.sender;
}
}
استفاده از Oracle های ChainLink
Oracle چیست؟
به طور تخصصی تر میتوان گفت که یک اوراکل عاملی است که نه تنها با منابع داده خارجی ارتباط برقرار می کند، بلکه به تایید و بررسی صحت داده های فراهم شده نیز می پردازد. بنابراین آنها مسئول فراهم کردن اطلاعات مهم و قابل اعتماد برای قراردادهای هوشمند هستند که این قراردادها هم به نوبه خود وظایف معینی را انجام می دهند. پس مفهوم اوراکل در فضای بلاک چین کمی با فناوری های دیگر متفاوت است.
استفاده از Oracle ها در Solidity
برای استفاده از داده های مختلف میتوانیم از Oracle هایی که توسط پروژه Chainlink آماده سازی شده است ، استفاده کنیم. استفاده از Oracle مربوط به داده های قیمتی (Data Feeds): پیاده سازی Interface با نام AggregatorV3Interface که شامل 5 تابع است. برای دریافت آخرین قیمت ها ، باید از تابع latestRoundData استفاده کنیم. برای درک بهتر موضوع با انجام یک پروژه آن را بررسی میکنیم.
تعریف پروژه: تبدیل قیمت اتریوم به یورو
برای استفاده از یک Oracle در قرارداد هوشمند باید 3 قدم را طی کنیم:
- 1- مشخص کردن آدرس کانترکت Oracle مربوط به Chainlink
- 2- تبدیل آدرس مربوط به کانترکت مرحله اول به یک interface
- 3- دریافت آخرین قیمت ها
استفاده از Data Feeds
قدم اول) مشخص کردن آدرس کانترکت Oracle مربوط به Chainlink: دریافت آدرس کانترکت از طریق لینک زیر:
https://docs.chain.link/docs/ethereum-addresses/
قدم دوم) تبدیل آدرس مربوط به کانترکت مرحله اول به یک interface
قدم سوم) دریافت آخرین قیمت ها
کد نوشته شده در ویدیو Oracle
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract ChainlinkPriceOracle {
AggregatorV3Interface internal EurUsdPriceFeed;
AggregatorV3Interface internal EthUsdPriceFeed;
constructor() {
// ETH / USD latest price
EthUsdPriceFeed = AggregatorV3Interface(0x8A753747A1Fa494EC906cE90E9f37563A8AF630e);
EurUsdPriceFeed = AggregatorV3Interface(0x78F9e60608bF48a1155b4B2A5e31F32318a1d85F);
}
function getEthUsd() public view returns(int) {
(,int price,,,) = EthUsdPriceFeed.latestRoundData();
return price;
}
function getEurUsd() public view returns(int) {
(,int price,,,) = EurUsdPriceFeed.latestRoundData();
return price;
}
function getEthEur() public view returns (int) {
int EthUsd = getEthUsd();
int EurUsd = getEurUsd();
return (EthUsd / EurUsd) ;
}
}
اعداد تصادفی در ارز های دیجیتال
در زمان ساخت یک قرارداد هوشمند ، استفاده از اعداد تصادفی یک امر اجتناب ناپذیر است. به طور مثال در پروژه های زیر نیاز به استفاده از اعداد تصادفی به میزان زیاد احساس میشود:
- ساخت بازی های بلاکچینی و NFT ها
- ساخت دپ های مرتبط با رای گیری
- ساخت دپ های مرتبط با قرعه کشی و انتخاب تصادفی
استفاده از اعداد تصادفی
برای اینکه بتوانیم با استفاده از Solidity اعداد تصادفی ایجاد کنیم ، باید از Oracle ها استفاده کنیم. مراحل استفاده از Oracle های ChainLink به این صورت است:
1- دریافت اتریوم تست بروی شبکه دلخواه (Rinkeby) و دریافت LINK تست بروی همان شبکه: برای دریافت اتریوم و لینک تست برای شبکه Rinkeby از آدرس های زیر استفاده میکنیم:
https://faucets.chain.link/rinkeby
2- پرداخت حق اشتراک به ChainLink: برای اینکه بتوانیم از خدمات ساخت اعداد تصادفی در اورکل های چین لینک استفاده کنیم ، باید حق اشتراک مربوط به آن را پرداخت کنیم. برای این منظور از سایت زیر استفاده میکنیم: (اطلاعات بیشتر در ویدیو وجود دارد)
https://vrf.chain.link/rinkeby
3- Deploy کردن قرارداد هوشمند و ساخت عدد تصادفی: برای دریافت سورس کد مربوط به ساخت اعداد تصادفی ، از وب سایت زیر استفاده میکنیم: (اطلاعات بیشتر در ویدیو وجود دارد)
https://docs.chain.link/docs/get-a-random-number/
تابع selfdestruct
یکی از مهمترین سوالاتی که در برنامه نویسی بلاک چین مطرح میشود این است که چگونه میتوانیم یک اسمارت کانترکت را که بروی شبکه Deploy شده است ، حذف کنیم؟ پاسخ این سوال تابع selfdestruct است.
تابع selfdestruct تمامی متغیر های state و bytecode (کد های کامپایل شده) های مربوط به یک اسمارت کانترکت را از روی شبکه حذف میکند. سپس کل موجودی اسمارت کانترکت را به آدرس موجود ارسال میکند. ساختار این تابع به صورت زیر است:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract HelloWorld {
function withdraw(address _to) public onlyOwner {
selfdestruct(payable(_to));
}
}
نکات مهم در مورد تابع selfdestrcut
نکته اول) پس از فراخوانی تابع selfdestruct امکان ارسال اتریوم وجود ندارد: پس از فراخوانی تابع selfdestruct در صورتی که مقداری اتریوم به آدرس این اسمارت کانترکت ارسال کنید ، این میزان اتریوم برای همیشه از بین خواهد رفت. چون تابع selfdestruct کلیه کد های کامپایل شده اسمارت کانترکت را حذف میکند و تابعی وجود ندارد که بتوان با استفاده از آن اتریوم را برداشت کرد.
نکته دوم) پس از فراخوانی تابع selfdestruct ، تاریخچه اسمارت کانترکت باقی می ماند: باید توجه داشته باشید که فرآیند حذف یک اسمارت کانترکت با فرآیند حذف یک فایل از روی هارد کامپیوتر متفاوت است. اگر فایل خود را از روی هارد کامپیوتر با نرم افزار های مناسب ، پاک کنید ، فایل شما واقعا برای همیشه پاک میشود. اما در بلاکچین ، در صورت حذف یک اسمارت کانترکت ، آدرس آن و تاریخچه تراکنش های انجام شده در آن برای همیشه در سایت های Explorer مثل EtherScan و یا BSCScan باقی خواهد ماند.
نکته سوم) هزینه گس فراخوانی تابع selfdestruct منفی است: همانگونه که گفته شد ، این تابع ، تمامی متغیر های State و Bytecode ها را از روی بلاک چین حذف میکند. عملا با این کار فضای بیشتری در اختیار بلاک چین قرار میگیرد و عملا کار Clean-Up به معنای پاک سازی انجام شده است. به همین دلیل هزینه گس این فرآیند منفی بوده و نه تنها نیاز به پرداخت هزینه نیست ، بلکه شبکه به شما پاداش هم میدهد!
البته دقت کنید که این تابع دو وظیفه دارد: یک) Clean-Up دو) ارسال اتریوم اسمارت کانترکت به آدرس خاص. وظیفه یک دارای گس منفی و وظیفه دو دارای گس مثبت است. پس این دو با یکدیگر محاسبه شده و در نهایت هزینه مربوطه باید توسط فراخوانی کننده تابع پرداخت شود.
مینی پروژه selfdestruct
اسمارت کانترکتی طراحی و پیاده سازی کنید که امکان دریافت اتریوم را به صورت مستقیم داشته باشد. سپس بتوان میزان موجودی اسمارت کانترکت را بررسی کرده و سپس با استفاده از تابع selfdestruct کل موجودی را به یک آدرس خاص ارسال کند. لازم به ذکر است که توابع withdraw و balance باید فقط توسط مالک اسمارت کانترکت قابل فراخوانی باشند.
کد مینی پروژه:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract HelloWorld {
address private owner;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner,
"Only owner of the contract can call this function");
_;
}
receive() external payable {}
function balance() public view onlyOwner returns(uint) {
return address(this).balance;
}
function withdraw(address _to) public onlyOwner {
selfdestruct(payable(_to));
}
}
فریم ورک Truffle
ترافل یک فریم ورک برای مدیریت اسمارت کانترکت ها است. اگر بخواهیم کاربرد های ترافل را بررسی کنیم ، میتوانیم موارد زیر را ذکر کنیم:
- مورد اول Smart Contract Lifecycle Management: مدیریت چرخه حیات اسمارت کانترکت ، در این فرآیند میتوانیم مواردی مانند: ساخت اسمارت کانترکت ، کامپایل کردن اسمارت کانترکت ، import کردن وابستگی ها (Dependencies) را انجام دهیم.
- مورد دوم Testing: با استفاده از این ویژگی میتوانیم تست کردن اسمارت کانترکت ها را انجام دهیم.
- مورد سوم Deployment and Migration: با استفاده از ترافل میتوانیم فرآیند دیپلوی کردن اسمارت کانترکت بروی شبکه را انجام دهیم.
- مورد چهارم Network Management: با استفاده از ترافل میتوانیم شبکه های ارز دیجیتال مختلف را مدیریت کنیم. به طور مثال میتوانیم بروی شبکه اتریوم یا لایه دوم های اتریوم مثل متیک یا شبکه بایننس یا شبکه ترون کد خود را دیپلوی کنیم.
- مورد پنجم Interactive Console: در ترافل یک سری دستوراتی وجود دارد که با وارد کردن آن ها میتوانیم کار های مختلفی را انجام دهیم. به طور مثال میتونیم با یک دستور یک اسمارت کانترکت جدید ایجاد کنیم ، یا مثلا با یک دستور اسمارت کانترکت رو کامپایل کنیم یا دیپلوی کنیم.
نصب و راه اندازی Truffle
برای نصب و راه اندازی ترافل باید مراحل زیر را طی کنیم:
1) نصب و راه اندازی نرم افزار Visual Studio Code:
2) نصب و راه اندازی NodeJS:
3) وارد کردن دستور زیر:
npm install truffle -g
4) وارد کردن دستور زیر به منظور ایجاد یک پروژه جدید:
mkdir NewProject
truffle init
اگر مراحل به درستی انجام شده باشد ، پوشه ها و فایل های زیر ایجاد شده اند:
- پوشه contracts
- پوشه migrations
- پوشه test
- فایل truffle.js
ساخت یک اسمارت کانترکت جدید با استفاده از Truffle
برای ایجاد کردن یک اسمارت کانترکت جدید با استفاده از ترافل ، از دستور زیر استفاده میکنیم:
truffle create contract ContractName
برای کامپایل کردن یک اسمارت کانترکت با استفاده از ترافل ، از دستور زیر استفاده میکنیم:
truffle compile
برای اطلاعات بیشتر در مورد این مبحث به ویدیو بالای این بخش مراجعه کنید.
Ganache چیست؟
Ganache یک بلاکچین شخصی است که برای افزایش سرعت فرآیند توسعه اپلیکیشن های غیر متمرکز ایجاد شده است. از جمله کاربرد های Ganache:
- توسعه قرارداد هوشمند
- دیپلوی کردن قرارداد هوشمند
- تست قرارداد هوشمند
برای نصب Ganache از وب سایت آن استفاده میکنیم:
https://trufflesuite.com/ganache/
فایل Migration
Migration: در توسعه قرارداد هوشمند با استفاده از Truffle ، به انتقال سورس کد نوشته شده با زبان Solidity به شبکه بلاکچین ، Migration گفته میشود.
نکات مهم در مورد فایل های Migrations
1- نام هر فایل باید با یک عدد شروع شود و به صورت مرتب شده نوشته شود.
2- نام استفاده شده برای Contract در این بخش مورد استفاده قرار میگیرد.
3- تغییر تنظیمات فایل truffle-config.js
4- میتوان پروژه را به Ganache متصل کرد.
5- دیپلوی کردن یک فایل کانترکت که حاوی چند Contract است.
6- پاس دادن یک پارامتر برای Constructor
تمامی موارد فوق به طور کامل در ویدیو توضیح داده شد.
دیپلوی کردن یک اسمارت کانترکت با استفاده از دستور Migration
برای دیپلوی کردن اسمارت کانترکت با استفاده از ترافل بروی شبکه Ganache ، از دستور زیر استفاده میکنیم:
truffle migrate –rest –network development
در صورتی که از Flag با عنوان reset استفاده نکنیم ، فقط فایل های Migration که اخیرا تغییر کرده اند ، اجرا خواهند شد.
ذخیره آدرس کانترکت دیپلوی شده بروی شبکه در یک فایل
برای آنکه بخواهیم یک Dapp بسازیم ، باید رابط کاربری که معمولا با ReactJS ساخته میشود را به بلاک چین متصل کنیم. در حال حاضر این اتصالات با استفاده از کتابخانه هایی مثل Web3.JS و یا Ether.JS انجام میشوند. این کتابخانه ها برای انجام اتصال به دو مورد نیاز دارند: یک) ABI دو) آدرس کانترکت دیپلوی شده بروی شبکه
برای آنکه بتوانیم به راحتی از آدرس کانترکت دیپلوی شده بروی شبکه استفاده کنیم ، میتوانیم آن را در ساختار یک متغیر در یک فایل ذخیره کرده و سپس در Dapp خود آن را import کنیم. برای اینکار باید سه مرحله را طی کنیم:
1- Consume کردن Promise برگشتی از تابع deploy:
const Inbox = artifacts.require('Inbox')
module.exports = function (deployer) {
deployer.deploy(Inbox, 'Hello From Truffle').then(() => {
})
}
2- ساختن یک متغیر از نوع String برای ذخیره سازی در فایل (Template Literal)
const Inbox = artifacts.require('Inbox')
module.exports = function (deployer) {
deployer.deploy(Inbox, 'Hello From Truffle').then((i) => {
const exportContent = `export const contractAddress = '${i.address}';`;
})
}
3- ایجاد یک فایل و ذخیره سازی متغیر در آن
const fs = require('fs');
const Inbox = artifacts.require('Inbox')
module.exports = function (deployer) {
deployer.deploy(Inbox, 'Hello From Truffle').then((i) => {
const exportContent = `export const contractAddress = '${i.address}';`;
fs.writeFileSync(`${__dirname}/../build/deployedContractAddr.js` , exportContent)
})
}
دیپلوی کردن کد بروی شبکه تست Rinkeby
برای آنکه بتوانیم کد خود را بروی شبکه تست نت Rinkeby دیپلوی کنیم ابتدا باید مقدار از کوین اتریوم بروی این شبکه را دریافت کنیم. برای دریافت اتریوم تست بروی شبکه تست Rinkeby ، میتوانیم از این وب سایت استفاده کنیم:
اتریوم تست را در کیف پولی واریز کنید که Recovery Phrase آن را در حال حاضر موجود داشته باشید.
سرویس Infura
سرویس Infura در نقش یک Full Node در شبکه اتریوم عمل میکند و عمل Deployment را برای ما انجام میدهد. این سرویس توسط شرکت ConsenSys ساخته شده است. برای استفاده از این سرویس ابتدا یک اکانت در وب سایت زیر ایجاد کنید و سپس لینک API مربوط به شبکه Rikneby را کپی کنید:
اعمال تغییرات در فایل truffle-config
در مرحله زیر ، کد های زیر را در فایل truffle-config قرار دهید:
const HDWalletProvider = require('@truffle/hdwallet-provider');
const fs = require('fs');
const mnemonic = fs.readFileSync(".secret").toString().trim();
const infuraAPI = fs.readFileSync(".api").toString();
module.exports = {
networks: {
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 7545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
rinkeby: {
provider: () => new HDWalletProvider(mnemonic, `https://rinkeby.infura.io/v3/${infuraAPI}`),
network_id: 4, // Rinkeby's id
gas: 5500000, // Rinkeby has a lower block limit than mainnet
confirmations: 2, // # of confs to wait between deployments. (default: 0)
timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
},
},
// Configure your compilers
compilers: {
solc: {
version: "0.8.10", // Fetch exact version from solc-bin (default: truffle's version)
}
},
};
دیپلوی کردن اسمارت کانترکت بروی شبکه تست Binance
نکته قابل توجه این است که سرویس Infura از شبکه بایننس پشتیبانی نمیکند و برای آنکه بتوانیم سورس کد خود را بروی شبکه Deploy کنیم ، میتوانیم از Remix استفاده کنیم. برای این منظور:
مرحله اول) برای اضافه کردن شبکه تست Binance به متامسک از وب سایت زیر استفاده میکنیم:
مرحله دوم) برای دریافت BNB تست بروی شبکه تست Binance ، میتوانیم از این وب سایت استفاده کنیم:
https://testnet.binance.org/faucet-smart
مرحله سوم) وارد Remix شده و در بخش DEPLOY & RUN TRANSACTIONS و بخش ENVIRONMENT گزینه Injected Web3 را انتخاب کرده و در کیف پول متامسک خود ، شبکه تست بایننس را انتخاب میکنیم. سپس بروی دکمه Deploy کلیک میکنیم.
سورس کد کانترکت استفاده شده در ویدیو
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Inbox {
string private message;
constructor(string memory newMessage) {
message = newMessage;
}
function setMessage(string memory newMessage) public {
message = newMessage;
}
function getMessage() public view returns(string memory) {
return message;
}
}
دیپلوی کردن اسمارت کانترکت بروی شبکه تست Moonbeam
ارز دیجیتال Polkadot با نماد DOT
ارز دیجیتال Polkadot با نماد DOT در سال 2020 معرفی شد. این پروژه و همچنین پروژه KSM توسط گوین وود ایجاد شده است. پروژه DOT از الگوریتم اثبات سهام استفاده میکند و از استخراج استفاده نمیکند. کوین DOT ، کوین اصلی این شبکه است و کارمزد ها باید با استفاده از این کوین پرداخت شود.
به طور شبکه پولکادات به عنوان یک تامین کننده امنیت و زیر ساخت به شبکه هایی که بروی آن ساخته میشوند خدمات ارائه میکند. به شبکه اصلی آن Relay Chain و به شبکه هایی که بروی آن ساخته میشوند ، Parachain گفته میشود. Moonbeam یکی از پاراچین های شبکه پولکادات محسوب میشود.
پروژه Moonbeam
شرکت Pure Stake ، یک شرکت آمریکایی است که در حوزه محصولات و خدمات بلاک چین فعالیت میکند. شرکت Pure Stake ، چندین محصول دارد که دو محصول مهم آن ها پروژه ارز دیجیتال Moonbeam و پروژه ارز دیجیتال Moonriver است. پروژه ارز دیجیتال Moonbeam یکی از Parachain های Polkadot و پروژه ارز دیجیتال Moonriver یکی از Parachain های Kusama است.
وظیفه اصلی پروژه Moonbeam این است که پروژه هایی که از EVM استفاده میکنند را به شبکه Polkadot انتقال دهد. اسم کوین این شبکه GLMR است. زمانی که یک پروژه ارز دیجیتال میخواهد بروی شبکه اتریوم یا Binance Chain عملیاتی شود ، باید سورس کد قرارداد هوشمند را با استفاده از زبان برنامه نویسی Solidity نوشته و آن را بروی شبکه ارز دیجیتال قرار دهد.
در صورتی که شبکه DOT از از زبان برنامه نویسی Rust و فریم ورک Substrate برای ساختن پروژه های ارز دیجیتال در بستر این دو شبکه استفاده میکنند. پروژه ارز دیجیتال Moonbeam به بقیه پروژه های ارز دیجیتال این امکان را میدهد که با کمترین میزان تغییرات در سورس کد ، پروژه خود را به شبکه Polkadot انتقال دهند و بتوانند از این شبکه استفاده کنند. در حقیقت Moonbeam در بلاک چین خود ، یک محیط شبیه به شبکه اتریوم را ایجاد کرده است که Dapp ها بتوانند در آن فعالیت کنند و در عین حال بتوانند با Relay Chain هم ارتباط داشته باشند.
شبکه Moonbase Alpha
به شبکه تست Moonbeam ، شبکه تست Moonbase Alpha گفته میشود. اطلاعات بیشتر:
https://docs.moonbeam.network/
برای اضافه کردن شبکه تست Moonbase Alpha به متامسک از وب سایت زیر استفاده میکنیم:
برای دریافت DEV تست بروی شبکه تست Moonbase Alpha:
https://discord.com/channels/745382242326413442/748921391646244864
وارد کردن عبارت زیر در ربات:
!faucet send 0xfc46be73A0D0045616A73B6d089d5F66b7B16371
بررسی قرارداد هوشمند در Explorer:
https://moonbase-blockscout.testnet.moonbeam.network/
Vesting Contract در ارز های دیجیتال
Vesting چیست؟
وستینگ یا اعطای سهام فرایندی است که طی آن کارمندان سود یا مالکیت بخشی از سهام را در شرکتشان به دست میآورند. معمولا این اتفاق زمانی رخ میدهد که کارمندان برای یک مدت زمان مشخص در آن شرکت کار کرده باشند.
به طور مثال یک کارمند به مدت 5 سال در یک شرکت فعالیت کرده است و به ازای این تلاش خود ، پس از 5 سال 1 درصد از کل سهام شرکت را دریافت میکند. به این فرآیند وستینگ یا اعطای سهام گفته میشود.
Vesting در پروژه های ارز دیجیتال
زمانی که یک پروژه ارز دیجیتال راه اندازی میشود ، گروه های مختلفی در راه اندازی آن سهیم هستند. در عکس زیر Tokenomics یا توزیع توکن پروژه ارز دیجیتال Polkastarter را مشاهده میکنید که در آن سه گروه شامل Team و Seed Sale و Private Sale با درصد های مشخصی در راه اندازی پروژه سهیم بوده اند.
اما سوال مهم این است که چه زمانی باید این توکن ها را به این گروه ها پرداخت کرد؟ در صورتی که کل توکن ها در ابتدای راه پروژه به گروه ها تحویل داده شود ممکن است با ایجاد فشار فروش در بازار ، باعث دامپ قیمت توکن شوند. پس میتوان با مشخص کردن یک بازه زمانی مشخص (مثلا یکسال) ، پس از گذشت این بازه زمانی ، توکن ها را به گروه های مختلف تحویل داد. این فرآیند با استفاده از یک اسمارت کانترکت از نوع Vesting Contract امکان پذیر است.
نحوه ساختن یک Vesting Contract در Solidity
برای ادامه بحث به ویدیویی که در بالای همین بخش قرار گرفته است ، مراجعه کنید.
کد های نوشته در این ویدیو
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
contract VestingContract {
IERC20 private token;
address private team;
uint256 private releaseTime;
constructor(
IERC20 token_,
address team_,
uint256 releaseTime_
) {
require(releaseTime_ > block.timestamp, "TokenTimelock: release time is before current time");
token = token_;
team = team_;
releaseTime = releaseTime_;
}
function release() public {
require(block.timestamp >= releaseTime, "TokenTimelock: current time is before release time");
uint256 amount = token.balanceOf(address(this));
require(amount > 0, "TokenTimelock: no tokens to release");
token.transfer(team, amount);
}
}
فراخوانی توابع یک کانترکت از کانترکت دیگر
فرض کنید شخصی که مالک یک پروژه ارز دیجیتال است و برای این پروژه ، توکن هم ایجاد کرده است ، میخواد توکن خود را در صرافی Uniswap لیست کند. این صرافی قبلا یک کانترکت بروی شبکه اتریوم دیپلوی کرده است که با استفاده از آن میتواند کانترکت های جدید را که برای انجام معاملات مورد استفاده قرار میگیرند ، ایجاد کرده و بروی شبکه دیپلوی کند.
در مرحله بعد مالک توکن باید یک جفت ارز شامل توکن خود و میزانی اتریوم را به صرافی ارسال کند. عملا با این کار قیمت گذاری هم انجام میدهد. مثلا 1000 توکن XYZ و 0.1 اتریوم واریز میکند.
در مرحله بعد کانترکت صرافی یک کانترکت جدید برای این جفت ارز ایجاد میکند و آن را بروی شبکه دیپلوی میکند. در حقیقت همه توکن ها و همه اتریوم ها در این کانترکت قرار میگیرند و یک واسطه بین خریدار و فروشنده محسوب میشود. این کانترکت جدید میتواند توابعی از کانترکت توکن را فراخوانی کند. توابعی مثل transfer و یا transferFrom و یا burn و یا decimals. این مثال یکی از بهترین مواردی است که میتوان با استفاده از آن ، فراخوانی توابع یک کانترکت از درون کانترکت های دیگر را بررسی کرد.
چگونه یک تابع را از کانترکت دیگر فراخوانی کنیم؟
این کار در سه مرحله انجام میشود:
مرحله اول: کانترکت اصلی باید بروی شبکه دیپلوی شود و یک آدرس مشخص داشته باشد.
مرحله دوم: با استفاده از Syntax زیر باید آدرس کانترکت را در قالب یک شی درون کانترکت دوم ذخیره کنیم: (برای توضیح بیشتر به ویدیو قرار گرفته در بالای این مطلب مراجعه کنید.)
MainContract mainContract = MainContract(contractAddress)
مرحله سوم: با استفاده از شی درون کانترکت دوم ، میتوان به توابع کانترکت اول دسترسی داشت.
کد های مورد استفاده در این جلسه
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Main {
string private message = “Default value";
function setMessage(string memory newMessage) public {
message = newMessage;
}
function getMessage() public view returns(string memory) {
return message;
}
}
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./Main.sol";
contract Branch {
Main mainContract;
constructor(address contractAddress) {
mainContract = Main(contractAddress);
}
function setMessage(string memory newMessage) public {
testCode.setMessage(newMessage);
}
function getMessage() public view returns(string memory) {
return testCode.getMessage();
}
}
دیدگاهتان را بنویسید