Мови смарт-контрактів
Чудова особливість Етеріуму полягає в тому, що смарт-контракти можна програмувати за допомогою відносно зручних для розробників мов. Якщо ви маєте досвід роботи з Python або будь-якою мовою з фігурними дужками (opens in a new tab), ви зможете знайти мову зі знайомим синтаксисом.
Дві найактивніші мови, що підтримуються:
- Solidity
- Vyper
Remix IDE надає комплексне середовище розробки для створення та тестування контрактів як на Solidity, так і на Vyper. Спробуйте браузерну Remix IDE (opens in a new tab), щоб почати писати код.
Більш досвідчені розробники також можуть використовувати Yul, проміжну мову для Віртуальної машини Етеріуму, або Yul+ — розширення для Yul.
Якщо вам цікаво і ви хочете допомогти в тестуванні нових мов, які все ще перебувають на стадії активної розробки, ви можете поекспериментувати з Fe — новою мовою смарт-контрактів, яка наразі перебуває на початковому етапі розвитку.
Передумови
Попередні знання мов програмування, особливо JavaScript або Python, можуть допомогти вам зрозуміти відмінності в мовах смарт-контрактів. Ми також рекомендуємо вам зрозуміти концепцію смарт-контрактів, перш ніж заглиблюватися в порівняння мов. Вступ до смарт-контрактів.
Solidity
- Об'єктно-орієнтована мова високого рівня для реалізації смарт-контрактів.
- Мова з фігурними дужками, на яку найбільше вплинув C++.
- Статично типізована (тип змінної відомий під час компіляції).
- Підтримує:
- Спадкування (ви можете розширювати інші контракти).
- Бібліотеки (ви можете створювати код для багаторазового використання, який можна викликати з різних контрактів — як статичні функції в статичному класі в інших об'єктно-орієнтованих мовах програмування).
- Складні типи, визначені користувачем.
Важливі посилання
- Документація (opens in a new tab)
- Портал мови Solidity (opens in a new tab)
- Solidity на прикладах (opens in a new tab)
- GitHub (opens in a new tab)
- Чат Solidity у Gitter (opens in a new tab), об'єднаний з чатом Solidity у Matrix (opens in a new tab)
- Шпаргалка (opens in a new tab)
- Блог Solidity (opens in a new tab)
- Twitter Solidity (opens in a new tab)
Приклад контракту
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.7.0;
contract Coin {
// Ключове слово "public" робить змінні
// доступними з інших контрактів
address public minter;
mapping (address => uint) public balances;
// Події дозволяють клієнтам реагувати на конкретні
// зміни контракту, які ви оголошуєте
event Sent(address from, address to, uint amount);
// Код конструктора виконується лише тоді, коли контракт
// створюється
constructor() {
minter = msg.sender;
}
// Надсилає певну кількість новостворених монет на адресу
// Може бути викликано лише творцем контракту
function mint(address receiver, uint amount) public {
require(msg.sender == minter);
require(amount < 1e60);
balances[receiver] += amount;
}
// Надсилає певну кількість існуючих монет
// від будь-якого ініціатора виклику на адресу
function send(address receiver, uint amount) public {
require(amount <= balances[msg.sender], "Insufficient balance.");
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
}
}
Цей приклад має дати вам уявлення про те, як виглядає синтаксис контракту на Solidity. Для більш детального опису функцій та змінних перегляньте документацію (opens in a new tab).
Vyper
- Мова програмування, подібна до Python
- Строга типізація
- Невеликий та зрозумілий код компілятора
- Ефективна генерація байт-коду
- Свідомо має менше функцій, ніж Solidity, з метою зробити контракти більш безпечними та простішими для аудиту. Vyper не підтримує:
- Модифікатори
- Спадкування
- Вбудований асемблер (inline assembly)
- Перевантаження функцій
- Перевантаження операторів
- Рекурсивні виклики
- Нескінченні цикли
- Двійкові числа з фіксованою комою
Для отримання додаткової інформації прочитайте обґрунтування Vyper (opens in a new tab).
Важливі посилання
- Документація (opens in a new tab)
- Vyper на прикладах (opens in a new tab)
- Більше про Vyper на прикладах (opens in a new tab)
- GitHub (opens in a new tab)
- Чат спільноти Vyper у Discord (opens in a new tab)
- Шпаргалка (opens in a new tab)
- Фреймворки та інструменти розробки смарт-контрактів для Vyper
- VyperPunk — навчіться захищати та зламувати смарт-контракти на Vyper (opens in a new tab)
- Vyper Hub для розробки (opens in a new tab)
- Найкращі приклади смарт-контрактів на Vyper (opens in a new tab)
- Добірка корисних ресурсів Awesome Vyper (opens in a new tab)
Приклад
# Відкритий аукціон
# Параметри аукціону
# Бенефіціар отримує гроші від учасника, який запропонував найвищу ціну
beneficiary: public(address)
auctionStart: public(uint256)
auctionEnd: public(uint256)
# Поточний стан аукціону
highestBidder: public(address)
highestBid: public(uint256)
# Встановлюється як true в кінці, забороняє будь-які зміни
ended: public(bool)
# Відстежуємо відшкодовані ставки, щоб ми могли дотримуватися патерну зняття коштів
pendingReturns: public(HashMap[address, uint256])
# Створює простий аукціон з `_bidding_time`
# секундами часу для торгів від імені
# адреси бенефіціара `_beneficiary`.
@external
def __init__(_beneficiary: address, _bidding_time: uint256):
self.beneficiary = _beneficiary
self.auctionStart = block.timestamp
self.auctionEnd = self.auctionStart + _bidding_time
# Зробити ставку на аукціоні з надісланою сумою
# разом із цією транзакцією.
# Сума буде відшкодована лише в тому випадку, якщо
# аукціон не виграно.
@external
@payable
def bid():
# Перевірити, чи закінчився період торгів.
assert block.timestamp < self.auctionEnd
# Перевірити, чи достатньо висока ставка
assert msg.value > self.highestBid
# Відстежувати відшкодування для попереднього учасника з найвищою ставкою
self.pendingReturns[self.highestBidder] += self.highestBid
# Відстежувати нову найвищу ставку
self.highestBidder = msg.sender
self.highestBid = msg.value
# Зняти попередньо відшкодовану ставку. Патерн зняття коштів
# використовується тут, щоб уникнути проблем з безпекою. Якби відшкодування надсилалися безпосередньо
# як частина bid(), зловмисний контракт для ставок міг би заблокувати
# ці відшкодування і таким чином заблокувати надходження нових вищих ставок.
@external
def withdraw():
pending_amount: uint256 = self.pendingReturns[msg.sender]
self.pendingReturns[msg.sender] = 0
send(msg.sender, pending_amount)
# Завершити аукціон і надіслати найвищу ставку
# бенефіціару.
@external
def endAuction():
# Хорошим правилом є структурування функцій, які взаємодіють
# з іншими контрактами (тобто вони викликають функції або надсилають етер)
# на три фази:
# 1. перевірка умов
# 2. виконання дій (потенційна зміна умов)
# 3. взаємодія з іншими контрактами
# Якщо ці фази переплутати, інший контракт може викликати
# назад поточний контракт і змінити стан або спричинити
# багаторазове виконання ефектів (виплата етеру).
# Якщо функції, що викликаються внутрішньо, включають взаємодію із зовнішніми
# контрактами, вони також повинні розглядатися як взаємодія із
# зовнішніми контрактами.
# 1. Умови
# Перевірити, чи настав час завершення аукціону
assert block.timestamp >= self.auctionEnd
# Перевірити, чи ця функція вже була викликана
assert not self.ended
# 2. Ефекти
self.ended = True
# 3. Взаємодія
send(self.beneficiary, self.highestBid)
Цей приклад має дати вам уявлення про те, як виглядає синтаксис контракту на Vyper. Для більш детального опису функцій та змінних перегляньте документацію (opens in a new tab).
Yul та Yul+
Якщо ви новачок в Етеріумі і ще не писали код мовами смарт-контрактів, ми рекомендуємо почати з Solidity або Vyper. Розглядайте Yul або Yul+ лише тоді, коли ви ознайомитеся з найкращими практиками безпеки смарт-контрактів та специфікою роботи з EVM.
Yul
- Проміжна мова для Етеріуму.
- Підтримує EVM та Ewasm (opens in a new tab) (WebAssembly, адаптований для Етеріуму) і розроблена як зручний спільний знаменник для обох платформ.
- Хороша ціль для етапів високорівневої оптимізації, яка може принести однакову користь як платформам EVM, так і Ewasm.
Yul+
- Низькорівневе, високоефективне розширення для Yul.
- Спочатку розроблено для контракту оптимістичного ролапу.
- Yul+ можна розглядати як експериментальну пропозицію щодо оновлення Yul, яка додає до неї нові функції.
Важливі посилання
- Документація Yul (opens in a new tab)
- Документація Yul+ (opens in a new tab)
- Вступна стаття про Yul+ (opens in a new tab)
Приклад контракту
Наступний простий приклад реалізує функцію піднесення до степеня. Його можна скомпілювати за допомогою solc --strict-assembly --bin input.yul. Приклад слід
зберегти у файлі input.yul.
{
function power(base, exponent) -> result
{
switch exponent
case 0 { result := 1 }
case 1 { result := base }
default
{
result := power(mul(base, base), div(exponent, 2))
if mod(exponent, 2) { result := mul(base, result) }
}
}
let res := power(calldataload(0), calldataload(32))
mstore(0, res)
return(0, 32)
}
Якщо ви вже маєте великий досвід роботи зі смарт-контрактами, повну реалізацію ERC-20 на Yul можна знайти тут (opens in a new tab).
Fe
- Статично типізована мова для Віртуальної машини Етеріуму (EVM).
- Натхненна Python та Rust.
- Має на меті бути простою у вивченні — навіть для розробників, які є новачками в екосистемі Етеріуму.
- Розробка Fe все ще перебуває на ранніх стадіях, альфа-реліз мови відбувся у січні 2021 року.
Важливі посилання
- GitHub (opens in a new tab)
- Анонс Fe (opens in a new tab)
- Дорожня карта Fe на 2021 рік (opens in a new tab)
- Чат Fe у Discord (opens in a new tab)
- Twitter Fe (opens in a new tab)
Приклад контракту
Нижче наведено простий контракт, реалізований на Fe.
type BookMsg = bytes[100]
contract GuestBook:
pub guest_book: map<address, BookMsg>
event Signed:
book_msg: BookMsg
pub def sign(book_msg: BookMsg):
self.guest_book[msg.sender] = book_msg
emit Signed(book_msg=book_msg)
pub def get_msg(addr: address) -> BookMsg:
return self.guest_book[addr].to_mem()
Як обрати
Як і з будь-якою іншою мовою програмування, здебільшого йдеться про вибір правильного інструменту для конкретного завдання, а також про особисті вподобання.
Ось кілька речей, які варто врахувати, якщо ви ще не пробували жодну з цих мов:
Чим чудова Solidity?
- Якщо ви новачок, існує багато посібників та інструментів для навчання. Дізнайтеся більше про це в розділі Навчання через програмування.
- Доступні хороші інструменти для розробників.
- Solidity має велику спільноту розробників, а це означає, що ви, швидше за все, досить швидко знайдете відповіді на свої запитання.
Чим чудова Vyper?
- Чудовий спосіб почати для розробників на Python, які хочуть писати смарт-контракти.
- Vyper має меншу кількість функцій, що робить її чудовою для швидкого прототипування ідей.
- Vyper прагне бути простою для аудиту та максимально зрозумілою для людини.
Чим чудові Yul та Yul+?
- Спрощена та функціональна низькорівнева мова.
- Дозволяє наблизитися до чистої EVM, що може допомогти оптимізувати використання газу у ваших контрактах.
Порівняння мов
Для порівняння базового синтаксису, життєвого циклу контракту, інтерфейсів, операторів, структур даних, функцій, потоку керування та іншого перегляньте цю шпаргалку від Auditless (opens in a new tab)