July 4, 2022

Давайте понимать Solidity

Великолепная история про то, как работают смарт-контракты в общем (без тонкостей, поверхностно)

Автор: t.me/kibirpanks

Кратко про

Solidity

Это объектно-ориентированный язык, на котором работают все EVM-совместимые смарт-контракты.

Язык сделан похожим на JavaScript, который в свою очередь считается С-подобным. Подразумевалось, что этот язык будет быстро принят веб-разработчиками (JS и веб разработка очень тесно связаны).

Смарт-контракты

Давайте я вам буду постепенно приводить аналогии к смарт-контрактам, начиная от простых и далее усложняя их:

Давайте изначально воспринимать смарт-контракт как отдельный адрес (аккаунт) в блокчейне. По сути это действительно так: на него можно отправить деньги, а он может распоряжаться ими как хочет. Большой ньюанс в том, что к смарт-контракту не подобрать ключ или сид-фразу: у него должен быть владелец, а владельцем выступает другой адрес.

Владелец при помощи Solidity сам описывает, какими инструментами может обладать его личный смарт-контракт. Также владелец описывает уровень доступа к этим инструментом: он может предоставить доступ всем желающим к каким-нибудь функциям, а к другим функциям он оставит доступ только себе. К примеру, владелец может разрешить присылать деньги на свой смарт-контракт, но функцией вывода денег может пользоваться только он сам.

Из чего обычно состоит смарт-контракт (Solidity)

Вот так, собственно, выглядит простой контракт без ничего:

В первой строчке просят указывать лицензию (я просто ставлю как сказали), потом указываю версию Solidity, и потом в фигурные скобки заключаю код.

Я надеюсь здесь всё понятно, теперь разберёмся как писать код внутри контракта. Для начала уточню, что по сути, "contract" это типо функция main, и в нём уже можно писать какие-нибудь переменные и функции. Однако запомните: всё, что вы написали в contract (а не в функциях внутри контракта) записывается в блокчейн. И за каждую запись нужно платить. И соответственно, если мы запишем инфу в функцию и эту инфу никуда из функции не записывать, то за такую информацию платить не нужно - она работает только единоразово (в памяти).

Подробно про стоимость газа для разных вещей написано в Ethereum Yellow Paper на 27 странице. Очевидно, что за функции тоже нужно платить, но если в блокчейн записывается мало информации (а то что происходит внутри функции никуда не записывается, функция просто возвращает какое-нибудь значение), то и платить нужно меньше.

Давайте напишем контракт:
1) в который можно отправить деньги
2) который может отправлять деньги владельцу
3) может приветствовать всех мимо проходящих сообщением "hello world":

Ещё прикол Solidity в том, что можно по отдельности вызывать только по одной функции. А вот например в С++, если бы мы запустили программу, то она бы выполнила всё подряд. В этом основная особенность этого дурацкого Solidity.

Перед тем, как разобрать этот дурацкий код, я хочу выделить ТРИ основных типа функций:

1) Payable (красная) — это ТРАНЗАКЦИЯ, через которую можно отправить деньги

2) ТРАНЗАКЦИЯ — оно и есть, только через неё не отправить деньги. Как вы заметили, PAYABLE и TRANSACTION я заключил в один оранжевый квадратик - значит что это всё ТРАНЗАКЦИИ. А значит, за неё нужно заплатить газ, потому что мы вносим данные в блокчейн.

3) CALL — вызов, за него мы не платим деньги. В отличие от транзакции (где мы отправляем данные в блокчейн), CALL функции могут возвращать значения (могут и принимать ещё). А транзакции только принимают значения.

Можете ещё раз промотать вверх и посмотреть, какие у функций цвета (кроме конструктора, я ему дал белый цвет т.к. с ним нельзя взаимодействовать и давайте про него забудем)

Подробно разберу каждую функцию

address — это отдельный тип данных, наравне со всякими integer string etc. Можете заметить, что я записал переменную owner прямо в контракте - значит эта информация запишется в блокчейн и никуда не пропадёт. Ключевое слово public означает, что полем owner можно пользоваться как внутри контракта, так и извне. public объединяет в себе external (можно пользоваться только извне) и internal (только внутри).

Конструктор вызывается только единожды - при разворачивании контракта. В него я написал, что отправитель транзакции (в которой разворачивается контракт) это теперь owner.

В функцию pay() я ничего не записываю. По сути, она только принимает в себя деньги. Ключ public можно заменить на external, но от этого ничего не поменяется. Внутри функции, к примеру, можно реализовать список с учётом всех адресов-отправителей, используя mapping. А можно не делать.

public можно заменить на external :)

Строчка #1: внутри функции я создаю переменную thisOwner, она равна адресу owner с модификатором payable (поскольку owner внутри контракта не может быть payable по какой-то причине), и теперь у нас есть адрес, на который можно отправить деньги.

Строчка #2: создаю новую переменную, и она равна адресу этого контракта. this указывает на этот контракт (в других языках слово this реализовано по другому и кого-то это может удивить)

Строчка #3: делаю transfer адресу thisOwner, денег отправляю столько, сколько есть на контракте (насчёт комиссии я не разбирался на самом деле, наверное сначала берётся комиссия а потом считается баланс - я не разбирался в этом:) )

CALL функции — это функции, не требующие платы за газ. Вы просто отправляете вызов напрямую контракту, и он вам напрямую отвечает без всяких там блокчейнов.

external — вызывается только извне

view — гарантирует, что внутри функции не изменяются никакие значения в контракте (например мы не трогаем owner). А это значит — никаких плат за газ.

returns(address) — возвращает тип данных "адрес". Возможно только в call функциях.

pure — отличие от view представлено в том, что такое ключевое слово гарантирует, что внутри функции не только НЕ_изменяются данные контракта, но и НЕ_читаются. То есть нельзя даже обратиться к owner.

returns(string memory) — возвращает string, который хранится только в памяти (не в хранилище(блокчейне)). И в функции мы ещё раз обозначаем, что строка хранится только в памяти. Она вернёт строку "hello world".

Я заебался и хочу лечь спать, давайте завтра скину этот же контракт развёрнутый в Rinkeby и покажу как там взаимодействовать (если вам это надо вообще)

Если понравилось то подпишитесь t.me/kibirpanks