November 23, 2021

Деплой и тест 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
Проверка папки hardhat-dev/contarct

2. Создаем ERC20 смарт-контракт, здесь для примера используется импорт одной из стандартной библиотек ERC20.

устанавливаем бибилотеку openzeppelin :

npm install @openzeppelin/contracts
Вывод успешной установки openzeppelin

Создаем скрипт контракта 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]
    }
  }
};

3. Создаем ICO смарт-контракт :

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 контракта

2) Деплой ERC20 контракта

3) Ожидания пока ERC20 контракт задеплоится

4) Инициализация ICO смарт-контракта

5) Деплой ICO смарт-контракта

6) Ожидание когда ICO смарт-контракта будет задеплоен

5. Теперь создадим скрипт-файл для теста :

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) - мы вызываем функцию покупки токенов и проверяем что функция покупки отработала корректно.

6. Скомпилируем смарт-контракт :

npx hardhat compile
Вывод успешной компиляции

7. Запустим тест и деплой смарт-контрактов :

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 и созданные нами токены на второй кошелек

Отправляем токены DoubleTop

Проверяем со второго кошелька что токены пришли :

Токены пришли на другой кошелек

Отправляем оставшиеся созданные токены на адрес смарт-контракта

Отправили токены на адрес смарт-контракта

10. Напоследок проверяем функцию покупки токенов в ICO смарт-контракте. Для этого мы используем среду разработки Remix :

Подключаемся к метамаску на платформе remix

Подключили метамаск к платформе remix

Переходим во вкладку Workspace и создаем новую рабочую среду :

Создали рабочую среду Moonbeam ICO contract test

Создаем 2 файла "ICO.sol" и "MyTokenERC20.sol". Копируем в созданные файлы наши контракты соответсвенно :

файл ICO.sol
файл MyTokenERC20.sol

Переходим к компиляции файлов ICO.sol и MyTokenERC20.sol которые мы создали :

компилируем файл MyTokenERC20.sol
компилируем файл ICO.sol

Теперь пробуем купить наши токены с помощь смарт-контракта ICO развернутого в среде разработки remix :

Инициализируем покупку токенов
Смотрим в истории транзакцию покупки токенов
Наши токены куплены и на балансе

Полезные ссылки :

https://razumv.tech/smart-contract_Moonbeam

https://docs.moonbeam.network/builders/get-started/moonbeam-dev/

https://hardhat.org/tutorial/

https://remix.ethereum.org/

https://docs.moonbeam.network/tokens/connect/metamask/#connect-metamask-to-moonbeam

https://docs.moonbeam.network/ru/integrations/wallets/metamask/

https://docs.moonbeam.network/builders/interact/remix/