Перейти до основного контенту

Посібник Waffle «Привіт, світе» з Hardhat та Ethers

waffle
Смарт-контракти
мова програмування
тестування
hardhat
ethers.js
Початківець
MiZiet
16 жовтня 2020 р.
4 читається за хвилину

У цьому посібнику з Waffleopens in a new tab ми дізнаємося, як налаштувати простий проєкт смарт-контракту «Привіт, світе», використовуючи hardhatopens in a new tab та ethers.jsopens in a new tab. Потім ми дізнаємося, як додати нову функціональність до нашого смарт-контракту та як протестувати його за допомогою Waffle.

Давайте розпочнемо зі створення нового проєкту:

yarn init

або

npm init

та встановлення необхідних пакетів:

yarn add -D hardhat @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai

або

npm install -D hardhat @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai

Наступний крок — створення зразка проєкту Hardhat за допомогою команди npx hardhat.

888 888 888 888 888
888 888 888 888 888
888 888 888 888 888
8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888
888 888 "88b 888P" d88" 888 888 "88b "88b 888
888 888 .d888888 888 888 888 888 888 .d888888 888
888 888 888 888 888 Y88b 888 888 888 888 888 Y88b.
888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888
👷 Ласкаво просимо до Hardhat v2.0.3 👷‍
? Що ви хочете зробити? …
❯ Створити зразок проєкту
Створити порожній hardhat.config.js
Вийти
Показати все

Виберіть Створити зразок проєкту

Структура нашого проєкту має виглядати так:

1MyWaffleProject
2├── contracts
3│ └── Greeter.sol
4├── node_modules
5├── scripts
6│ └── sample-script.js
7├── test
8│ └── sample-test.js
9├── .gitattributes
10├── .gitignore
11├── hardhat.config.js
12└── package.json
Показати все

Тепер поговоримо про деякі з цих файлів:

  • Greeter.sol — наш смарт-контракт, написаний мовою Solidity;
1contract Greeter {
2string greeting;
3
4constructor(string memory _greeting) public {
5console.log("Розгортання Greeter з привітанням:", _greeting);
6greeting = _greeting;
7}
8
9function greet() public view returns (string memory) {
10return greeting;
11}
12
13function setGreeting(string memory _greeting) public {
14console.log("Зміна привітання з '%s' на '%s'", greeting, _greeting);
15greeting = _greeting;
16}
17}
Показати все

Наш смарт-контракт можна розділити на три частини:

  1. конструктор — у ньому ми оголошуємо змінну типу string під назвою greeting,
  2. функція greet — функція, яка під час виклику повертає greeting,
  3. функція setGreeting — функція, яка дає змогу змінювати значення greeting.
  • sample-test.js — наш файл тестів
1describe("Greeter", function () {
2 it("Має повертати нове привітання після його зміни", async function () {
3 const Greeter = await ethers.getContractFactory("Greeter")
4 const greeter = await Greeter.deploy("Hello, world!")
5
6 await greeter.deployed()
7 expect(await greeter.greet()).to.equal("Hello, world!")
8
9 await greeter.setGreeting("Hola, mundo!")
10 expect(await greeter.greet()).to.equal("Hola, mundo!")
11 })
12})
Показати все

Наступний крок — компіляція нашого контракту та запуск тестів:

Тести Waffle використовують Mocha (фреймворк для тестування) з Chai (бібліотека тверджень). Все, що потрібно зробити, це виконати npx hardhat test і дочекатися появи наступного повідомлення.

✓ Має повертати нове привітання після його зміни

Поки що все чудово, додамо трохи складності до нашого проєкту

Уявіть ситуацію, коли хтось додає порожній рядок як привітання. Це було б не дуже тепле привітання, чи не так?
Переконаємося, що цього не станеться:

Ми хочемо використовувати revert з Solidity, коли хтось передає порожній рядок. Добре, що ми можемо легко протестувати цю функціональність за допомогою зіставлення to.be.revertedWith() з Chai від Waffle.

1it("Має скасовувати операцію в разі передавання порожнього рядка", async () => {
2 const Greeter = await ethers.getContractFactory("Greeter")
3 const greeter = await Greeter.deploy("Hello, world!")
4
5 await greeter.deployed()
6 await expect(greeter.setGreeting("")).to.be.revertedWith(
7 "Привітання не повинно бути порожнім"
8 )
9})
Показати все

Схоже, наш новий тест не пройшов:

Розгортання Greeter з привітанням: Hello, world!
Зміна привітання з 'Hello, world!' на 'Hola, mundo!'
✓ Має повертати нове привітання після його зміни (1514ms)
Розгортання Greeter з привітанням: Hello, world!
Зміна привітання з 'Hello, world!' на ''
1) Має скасовувати операцію в разі передавання порожнього рядка
1 пройдено (2с)
1 не пройдено
Показати все

Реалізуймо цю функціональність у нашому смарт-контракті:

1require(bytes(_greeting).length > 0, "Привітання не повинно бути порожнім");

Тепер наша функція setGreeting виглядає так:

1function setGreeting(string memory _greeting) public {
2require(bytes(_greeting).length > 0, "Привітання не повинно бути порожнім");
3console.log("Зміна привітання з '%s' на '%s'", greeting, _greeting);
4greeting = _greeting;
5}

Запустімо тести знову:

✓ Має повертати нове привітання після його зміни (1467ms)
✓ Має скасовувати операцію в разі передавання порожнього рядка (276ms)
2 пройдено (2с)

Вітаємо! Ви впоралися :)

Висновок

Ми створили простий проєкт за допомогою Waffle, Hardhat та ethers.js. Ми дізналися, як налаштовувати проєкт, додавати тест і реалізовувати нову функціональність.

Щоб знайти більше чудових зіставлень Chai для тестування ваших смарт-контрактів, перегляньте офіційну документацію Waffleopens in a new tab.

Останні оновлення сторінки: 8 грудня 2023 р.

Чи була ця інструкція корисною?