كيف تقوم بإنشاء ICO مبني على إيثريوم Ethereum ERC20 في 20 دقيقة
[highlight color=”yellow”]كيف تقوم بإنشاء ICO إيثريوم ERC20 في 20 دقيقة[/highlight]
كريبتو لايت – قمت في الآونة الأخيرة، بالتعمق في البحث فيما يتعلق بتطبيقات سلسلة الكتل “البلوكشين Blockchain” واللامركزية، وذلك لتثقيف نفسي وتحسين معرفتي، ولجعل عملية التعلم ممتعة. قررت أن أقوم بتأسيس برنامجي الخاص للعملات، الذي قمت بإنشائه على قاعدة إيثريوم Ethereum، والعمل على فهم عملية العرض الأولي للعملة ICO.
في هذه المقالة، أهدف لإعطائكم لمحة مبسطة وعامة عن كيفية عمل العقود الذكية في إيثريوم Ethereum من خلال إطلاق نسخة تجريبية بسيطة لعملية عرض أولي لعملة ICO.
المبادئ:
فيما يلي بعض المصطلحات الأساسية التي سنستخدمها في هذه لمقالة، في حال كان لديك معرفة سابقة بها، فيمكنك الانتقال إلى القسم التالي.
ERC20: هي رموز قائمة على أساس إيثريوم Ethereum أو مدعومة منها، ويمكن أن تمثل أي سلعة قابلة للتداول مثل العملات الرقمية المشفرة، السندات، وحتى أشياء من العالم الحقيقي مثل سيارة فرضاً يمكن ترميزها برمز معين يقيمها على إيثريوم Ethereum. بالإضافة لذلك، يمكن الاستفادة من اتباع معيار ERC20 في أن الرموز المميزة الخاصة بك ستكون متوافقة مع أي عميل آخر أو محفظة أخرى يستخدمان نفس المعايير.
العقود الذكية: هي كتل برمجية ذاتية التنفيذ منتشرة على سلسلة الكتل “البلوكشين Blockchain” التابعة للإيثريوم Ethereum. وهي تحتوي على البيانات والوظائف البرمجية. تقوم هذه العقود باتخاذ القرارات، والتعامل مع العقود الأخرى، وتخزين البيانات ونقل الإيثر (جزء من العملة الرقمية المشفرة داخل كتلة من إيثريوم Ethereum) بين المستخدمين.
Solidity: لغة برمجية لكتابة العقود الذكية والتطبيقات اللامركزية.
محافظ MEW\ Mist\ MetaMask: أداة رقمية تحوي الإيثر ورموز الإيثريوم Ethereum الأخرى الخاصة بك.
الآن، وبعد أن أصبحت على دراية بالمصطلحات الأساسية التي ستمر معنا في هذه المقالة، دعونا نبدأ.
الخطوة الأولى: الشيفرة Code
افتح محرر النصوص المفضل لديك ثم قم بنسخ التعليمة البرمجية التالية وألصقها فيه:
pragma solidity ^0.4.4;
contract Token {
/// @return total amount of tokens
function totalSupply() constant returns (uint256 supply) {}
/// @param _owner The address from which the balance will be retrieved
/// @return The balance
function balanceOf(address _owner) constant returns (uint256 balance) {}
/// @notice send `_value` token to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
function transfer(address _to, uint256 _value) returns (bool success) {}
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {}
/// @notice `msg.sender` approves `_addr` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of wei to be approved for transfer
/// @return Whether the approval was successful or not
function approve(address _spender, uint256 _value) returns (bool success) {}
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens allowed to spent
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {}
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
contract StandardToken is Token {
function transfer(address _to, uint256 _value) returns (bool success) {
//Default assumes totalSupply can't be over max (2^256 - 1).
//If your token leaves out totalSupply and can issue more tokens as time goes on, you need to check if it doesn't wrap.
//Replace the if with this one instead.
//if (balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
if (balances[msg.sender] >= _value && _value > 0) {
balances[msg.sender] -= _value;
balances[_to] += _value;
Transfer(msg.sender, _to, _value);
return true;
} else { return false; }
}
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
//same as above. Replace this line with the following if you want to protect against wrapping uints.
//if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
balances[_to] += _value;
balances[_from] -= _value;
allowed[_from][msg.sender] -= _value;
Transfer(_from, _to, _value);
return true;
} else { return false; }
}
function balanceOf(address _owner) constant returns (uint256 balance) {
return balances[_owner];
}
function approve(address _spender, uint256 _value) returns (bool success) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
uint256 public totalSupply;
}
contract HashnodeTestCoin is StandardToken { // CHANGE THIS. Update the contract name.
/* Public variables of the token */
/*
NOTE:
The following variables are OPTIONAL vanities. One does not have to include them.
They allow one to customise the token contract & in no way influences the core functionality.
Some wallets/interfaces might not even bother to look at this information.
*/
string public name; // Token Name
uint8 public decimals; // How many decimals to show. To be standard complicant keep it 18
string public symbol; // An identifier: eg SBX, XPR etc..
string public version = 'H1.0';
uint256 public unitsOneEthCanBuy; // How many units of your coin can be bought by 1 ETH?
uint256 public totalEthInWei; // WEI is the smallest unit of ETH (the equivalent of cent in USD or satoshi in BTC). We'll store the total ETH raised via our ICO here.
address public fundsWallet; // Where should the raised ETH go?
// This is a constructor function
// which means the following function name has to match the contract name declared above
function HashnodeTestCoin() {
balances[msg.sender] = 1000000000000000000000; // Give the creator all initial tokens. This is set to 1000 for example. If you want your initial tokens to be X and your decimal is 5, set this value to X * 100000. (CHANGE THIS)
totalSupply = 1000000000000000000000; // Update total supply (1000 for example) (CHANGE THIS)
name = "HashnodeTestCoin"; // Set the name for display purposes (CHANGE THIS)
decimals = 18; // Amount of decimals for display purposes (CHANGE THIS)
symbol = "HTCN"; // Set the symbol for display purposes (CHANGE THIS)
unitsOneEthCanBuy = 10; // Set the price of your token for the ICO (CHANGE THIS)
fundsWallet = msg.sender; // The owner of the contract gets ETH
}
function() payable{
totalEthInWei = totalEthInWei + msg.value;
uint256 amount = msg.value * unitsOneEthCanBuy;
require(balances[fundsWallet] >= amount);
balances[fundsWallet] = balances[fundsWallet] - amount;
balances[msg.sender] = balances[msg.sender] + amount;
Transfer(fundsWallet, msg.sender, amount); // Broadcast a message to the blockchain
//Transfer ether to fundsWallet
fundsWallet.transfer(msg.value);
}
/* Approves and then calls the receiving contract */
function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
//call the receiveApproval function on the contract you want to be notified. This crafts the function signature manually so one doesn't have to include a contract in here just for this.
//receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
//it is assumed that when does this that the call *should* succeed, otherwise one would use vanilla approve instead.
if(!_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData)) { throw; }
return true;
}
}
تعتمد الشيفرة المذكورة أعلاه لغة solidity لإنشاء رمز ERC20 بسيط. الشيفرة مكتوبة بشكل جيد ومن السهل فهمها. بعد لصق نص الشيفرة داخل محرر النصوص المفضل لديك، ابحث عن جملة CHANGE THIS. هذا هو ماتحتاج لتغييره بناءً على خصائص رمزك المميز Token الخاص بك. في المثال أعلاه، قمت بتسمية رمزي المميز HashnodeTestCoin (HTCN). يتم تعداد العرض الإجمالي عند 1000، لكن يمكن للأشخاص أن يتملكوا ابتداءً من 0.000000000000000001 بسبب وجود مكان لثمانية عشر رقماً عشرياً. بالإضافة لذلك، يحصل مالك العقد على جميع الرموز الأولية Tokens. لقد قمت بتحديد سعر عرض العملة الأولي كالتالي:
1 ETH = 10 HTCN
هذا يعني، إذا أرسل شخص ما 1ETH إلى هذا العقد الذكي، فسوف يحصل على 10 وحدات HTCN
الخطوة الثانية:
قم بتنصيب MetaMask chrome extension لإنشاء محفظة. لتكون صاحب العقد الذكي. كما يمكن استخدام محفظة Mist أو My Ether Wallet. لكن من أجا التبسيط دعونا نستخدم في هذا المشروع إضافة MetaMask.
حالما تنتهي من تنزيل الإضافة، قم بإنشاء حساب جديد محمي بكلمة مرور. ثم اختر Ropsten TestNet من الزاوية اليسرى في الأعلى. قبل نشر العقد على سلسلة الكتل “البلوكشين Blockchain” الرئيسية للإيثريوم Ethereum سنقوم باختباره للتأكد من أن كل شيء سيكون على ما يرام. وهذا يبدو شيئاً من هذا القبيل:
الآن، توجه إلى Remix IDE وهو محاكي ومصحح للأخطاء للغة البرمجة Solidity على النت. وقم بلصق الشيفرة التي قمت بتعديلها للتو، تجاهل أي تحذيرات تظهر لك. ثم انتقل للإعدادات وألغ خيار Enable Optimizations إذا كان مفعلا.
انتقل الآن إلى علامة التبويب Run وانقر على إنشاء create تحت اسم رمزك الخاص <your token name>.
بمجرد أن تنقر على إنشاء create، سيطلب منك MetaMask أن تقوم بشراء تجريبي لبعض الإيثر Ether وإرسال العملية Submit. العملية تبدو شيئاً من هذا القبيل:
فقط عليك التأكد من أنك على “شبكة روبستن التجريبية” Ropsten TestNet وليس على الشبكة الرئيسية MainNet ومن ثم اضغط إرسال Submit. الآن قم بفتح MetaMask مرة أخرى واضغط على أول عملية، حيث سيتم نقلك إلى قسم Etherscan حيث يمكنك مراقبة العملية الجارية. قد يستغرق الأمر حوالي 30 ثانية لتأكيد العملية. حالما يتم تأكيدها، فإنها تبدو كالتالي:
مرحى!! لقد قمت بنشر عقدك الخاص للتو. لاحظ العنوان في صفحة العملية الموجودة أعلاه. هذا هو عنوان عقدك الخاص.
والآن حان الوقت لنتحقق مما إذا كان يعمل بالفعل.
الخطوة 3:
في حال أنك قمت بإعداد كل شيء بشكل مثالي فيجب أن تتلقى جميع الرموز الأولية Tokens (والتي تبلغ في حالتنا هذه 1000 رمز Tokens) عندما تقوم بإضافته إلى محفظتك. قم بنسخ عنوان العقد، انتقل إلى MetaMask ثم Add Token وقم بلصق العنوان. الأمر يبدو كالتالي:
انقر فوق إضافة Add وقم بتحديث MetaMask Refresh. يجب أن يظهر لك الآن الإمداد الأولي (بلغ في حالتنا 1000HTCN كما ذكرنا سابقاً).
الخطوة 4:
بعد أن أصبح كل شيء يعمل بشكل ممتاز، علينا أن تأكيد عقدنا الذكي حتى يتمكن كل شخص على سلسلة الكتل “البلوكشين Blockchain” من قراءته وفهمه. من الأفضل دائماً تأكيد العقد بما أنه يساعد على تأسيس الثقة.
الآن انتقل إلى عنوان العقد الخاص بك وانقر على علامة تبويب Contract Code.
انقر الآن على رابط التأكيد والنشر Verify and publish. بمجرد أن يتم نقلك إلى الصفحة الجديدة، قم بملء التفاصيل مثل إصدار المحاكي Compiler version، تمكين التحسينات Enable Optimizations وغيرها، وقم بلصق الشيفرة التي اختبرناها في الخطوة الأولى.
تأكد من أن إصدار المحاكي الذي اخترته يتطابق مع ذلك الذي قمت بتطبيق شيفرتك عليه في الخطوة الأولى. والآن اضغط تأكيد ونشر Verify and publish. إذا نجحت، فسوف يتولد لك bytecode, ABI كالتالي:
مبروك! أصبح بإمكان أي شخص الآن زيارة عنوان عقدك الخاص وقراءة المصدر.
الخطوة 5:
لتحويل عقدك إلى الإنتاج، فكل ما عليك فعله هو تحويل من الشبكة التجريبية TestNet إلى الشبكة الرئيسية MainNet على MetaMask (الموجود أعلى الزاوية اليسرى) وتكرار الخطوات من 2 إلى 4. يرجى الانتباه إلى أنه سيتعين عليك هنا إنفاق إيثر Ether حقيقي لنشر العقد الخاص بك. لذا لا تقم بنشر العقد مالم تكن مستعداً تماماً فالعقود غير قابلة للتغيير ولا يمكن تحديثها بعد نشرها. في هذا المقال التعليمي سنستمر باستخدام الشبكة التجريبية TestNet.
شراء رموز Tokens بالإيثر Ether
كجزء من عملية العرض الأولي للعملة ICO، فإن المستخدمين سوف يشترون منك الرموز مقابل دفع ETH. تذكر أننا حددنا السعر 1ETH = 10HTCN أثناء نشر العقد. لذلك، إذا أراد المستخدم شراء 10HTCN خلال عملية العرض الأولي، فعليه أن يدفع 1ETH، دعونا نختبر ذلك.
انتقل إلى MetaMask، أنشئ حساباً جديداً وعبئه ببعض الإيثر التجريبي Test Ether. حالما يتم تحميل الحساب. انقر على إرسال Send وضع عنوان العقد الخاص بك . وفي حقل المبلغ أدخل 2ETH.
بعد ذلك، أرسل 2ETH إلى عنوان العقد وانتظر تأكيد العملية. قم بعمل تحديث Refresh للـ MetaMask بعد بضعة ثواني وتحقق من الرموز Tokens لديك. يجب أن يكون الحساب التجريبي الجديد قد تلقى 20HTCN (أو شيئاً مختلفاً بناءً على إعدادك الخاص لشيفرتك) ويجب أن يكون قد تبقى لدى صاحب العقد (أنت) 980 رمز Tokens أو ماشابه.
بالإضافة لحصولك على 2ETH.
تهانينا على النجاح!
إطلاق صفحة للعرض الأولي للعملة ICO:
لعرض كمية ETH المكتسبة من مشروعنا، فغننا سنستخدم مكتبة جافا سكريبت تدعى Web3.js على موقعنا.
توجه إلى شيفرة العرض الأولي ICO لعملة Hishnode Test Coin التجريبية وتحقق من الشيفرة في آخر علامة <script>. إنها بسيطة نوعاً ما، تستخدم فقط Web3.js و ABI مستمدة من العقد الخاص بك.
تهانينا! وبوصولك إلى هذا الحد فعليك أن تأخذ بالحسبان أن عقود الإنتاج الحقيقي وعمليات عروض العملة الأولية ICOs تتطلب جهداً كبيراً ويجب دعمها باختبارات دقيقة. في حين أن هذا المقال التعليمي يعطي فقط نظرة عامة على كتابة العقود للعرض الأولي للعملة ICOs وهي لا ترقى للنشر على مستوى عقود الإنتاج الحقيقية. لذا لا تقم بنشرها على الشبكة الرئيسية MainNet بدون إجراء الاختبارات المناسبة.
شكراً لقراءة هذا المقال، ونرجو أن يكون قد حقق الفائدة المرجوة.