Деплой и тест ICO и ERC20 смарт-контракта Moonbeam используя hardhat
Данный документ является продолжением документации работы с мунбимом, ознакомьтесь с первой статьей для установки локальной ноды Moonbeam Development Node и комапонентов hardhat. В этой статье мы расскажем как задеплоить и протестировать ICO и ERC20 смарт-контракты Moonbeam используя локальную ноду, с помощью hardhat
1. Переходим в папку contacts (которая должна находится по пути hardhat-dev/contracts) и проверям что там находится:
cd contracts
Проверяем что лежит в папке | ll Если там находятся лишние файлы, удалите их чтоб они не мешали вам. В нашем случае там находится файл "Greeter.sol", давайте удалим его | rm -rf Greeter.sol И еще раз проверим что находится в папке contract: | ll
2. Создаем ERC20 смарт-контракт, здесь для примера используется импорт одной из стандартной библиотек ERC20.
npm install @openzeppelin/contracts
Создаем скрипт контракта ERC20
nano contracts/MyTokenERC20.sol
Пример скрипта, который мы использовали :
pragma solidity ^0.8.1; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MyTokenERC20 is ERC20 { /** * @dev Constructor that gives msg.sender all of exis> */ constructor( string memory name, string memory symbol, uint256 initialSupply ) ERC20(name, symbol) { _mint(msg.sender, initialSupply); } }
!help Проверяем чтоб версия солидити, которая используется в контракте совпадала с версией используемой в файле конфига:
nano hardhat.config.js
require("@nomiclabs/hardhat-waffle"); // This is a sample Hardhat task. To learn how to creat> // https://hardhat.org/guides/create-task.html task("accounts", "Prints the list of accounts", async (> const accounts = await hre.ethers.getSigners(); for (const account of accounts) { console.log(account.address); } }); // You need to export an object to set up your config // Go to https://hardhat.org/config/ to learn more /** * @type import('hardhat/config').HardhatUserConfig */ const { privateKey } = require('./secrets.json'); module.exports = { solidity: "0.8.1", networks: { dev: { url: "http://127.0.0.1:9933", chainId: 1281, accounts: [privateKey] } } };
nano contracts/ICO.sol
Пример скрипта, который мы использовали :
pragma solidity ^0.8.1; import "./MyTokenERC20.sol"; contract ICO { uint public buyPrice; MyTokenERC20 public token; constructor(MyTokenERC20 _token, uint _buyPrice) { token = _token; buyPrice = _buyPrice; } function buy() external payable returns (uint) { uint tokens = _buy(msg.sender , msg.value); return tokens; } function _buy(address _sender , uint256 _amount) inte> uint tokens = _amount / buyPrice; token.transfer(_sender , tokens); return tokens; } }
!help У этого контракта есть функция бай - функцию бай мы будем использовать для покупки токенов. Также у ICO смарт-контракта есть конструктор который принимает адресс ERC20 токена и цену токена, функция бай отправляет токены тому кто прислал эфир в соответсвии с указанной ценой.
4. Теперь нам нужно изменить деплой скрипт, который мы использовали в предидущей доке :
nano scripts/deploy.js
Вот так выглядит наш скрипт деплоя для текущего проекта :
async function main() { // Weget the contract to deploy const MyTokenERC20 = await ethers.getContractFactory('MyTokenERC20'); console.log('Deploying MyTokenERC20...'); const totalSupply = '1000000'; // Instantiating a new ERC20 smart contract const myTokenERC20 = await MyTokenERC20.deploy('DoubleTop', 'DoubleTop', totalSupply + '0000000000000000000'); // Waiting for the deployent to resolve await myTokenERC20.deployed(); console.log('MyTokenERC20 deployed to:', myTokenERC20.address); // We get the contract to deploy const ICO = await ethers.getContractFactory('ICO'); console.log('Deploying ICO...'); // Instantiating a new ICO smart contract const ico = await ICO.deploy(myTokenERC20.address, 1000); // Waiting for the deployment to resolve await ico.deployed(); console.log('ICO deployed to:', ico.address); } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); });
!Замените название "DoubleTop" в строке 8 на название вашего токена!
!help Обозначения скрипта. Для вашего удобства разберем что означает каждый абзац в скрипте (цифра это номер абзаца) :
1) Инициализация ERC20 контракта
3) Ожидания пока ERC20 контракт задеплоится
cd test
Проверяем что лежит в папке | ll Если там находятся лишние файлы, удалите их чтоб они не мешали вам. В нашем случае там находится файл "sample-test.js", давайте удалим его | rm -rf sample-test.js И еще раз проверим что находится в папке contract: | ll
создаем новый тестовый файл ICO.js
nano ICO.js
Вот так выглядит наш скрипт для теста :
const { expect } = require('chai'); describe('ICO contract', () => { let TokenContract, tokenContract, ICO, ico, owner, addr1, addr2, addr3 const totalSupply = '1000000'; const price = '10'; beforeEach(async () => { TokenContract = await ethers.getContractFactory('MyTokenERC20'); tokenContract = await TokenContract.deploy('MyTokenERC20', 'MTE', totalSupply + '00000000000000000'); await tokenContract.deployed(); ICO = await ethers.getContractFactory('ICO'); ico = await ICO.deploy(tokenContract.address, price); await ico.deployed(); [owner, addr1, addr2, addr3] = await ethers.getSigners(); await tokenContract.transfer(ico.address, '2000000' + '00000000000000000'); }); describe('Transfer token', () => { it('Owner balance', async () => { const ownerBalance = await tokenContract.balanceOf(owner.address); expect(ownerBalance.toString()).to.equal('800000' + '000000000000000000'); }); it('Buy token', async () => { await ico.connect(addr1).buy({ value: ethers.utills.parseEther('1') }); const adde1Balance = await tokenContract.balanceOf(addr1.address); expect(addr1Balance.toString()).to.equal(ethers.utils.parseEther('0.1').toString()); }); }); });
!help В первом тесте (строка 24-26) - мы берем адрес владельца и проверяем что баланс корректный. Во втором тесте (строка 30-34) - мы вызываем функцию покупки токенов и проверяем что функция покупки отработала корректно.
npx hardhat compile
npx hardhat test
npx hardhat run scripts/deploy.js --network dev
8. Теперь давайте подключимся к метамаску и протестируем и проверим работоспособность наших контрактов. Для этого нам понадобится расширение метамаска, аккаунт разработчика который мы использовали
(можете ознакомится с аккаунтами разработчиков здесь).
Мы для наших проектов использовали аккаунт Геральда :
Public Address: 0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b Private Key: 0x99b3c12287537e38c90a9219d4cb074a89a16e9cdb20bf85728ebd97c343e342
Импортируем закрытый ключ, подключаемся к сети Moonbeam Dev (как подключить метамаск к сетям moonbeam) и убеждаемся что у нас на балансе токены Dev и которые вы создали в смарт-контракте. В нашем случае "DoubleTop".
9. Сделаем пару тестовых переводов между кошельками метамаска для того чтоб убедится что все корректно работает :
Отправим токены Dev и созданные нами токены на второй кошелек
Проверяем со второго кошелька что токены пришли :
Отправляем оставшиеся созданные токены на адрес смарт-контракта
10. Напоследок проверяем функцию покупки токенов в ICO смарт-контракте. Для этого мы используем среду разработки Remix :
Переходим во вкладку Workspace и создаем новую рабочую среду :
Создаем 2 файла "ICO.sol" и "MyTokenERC20.sol". Копируем в созданные файлы наши контракты соответсвенно :
Переходим к компиляции файлов ICO.sol и MyTokenERC20.sol которые мы создали :
Теперь пробуем купить наши токены с помощь смарт-контракта ICO развернутого в среде разработки remix :
https://razumv.tech/smart-contract_Moonbeam
https://docs.moonbeam.network/builders/get-started/moonbeam-dev/
https://docs.moonbeam.network/tokens/connect/metamask/#connect-metamask-to-moonbeam
https://docs.moonbeam.network/ru/integrations/wallets/metamask/