Учимся читать смарт контракты и обходить скам: Часть 1

Данная методичка предназначена, в первую очередь, для крипто энтузиастов, которые хотят научиться разбираться в том крипто мире, в котором они находятся, но при этом не обладают глубокими знаниями о протоколах, внутреннем устройстве блокчейнов и т.д.

Учимся читать смарт контракты и обходить скам: Часть 1

Поэтому в данной работе многие понятия сознательно сокращены (впрочем без потери их адекватности и применимости) для лучшего усвоения материала без излишних технических подробностей.

Основы мира DeFi

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

  • Смарт-контракт это программный код, который выполняется на нодах блокчейна, а результат выполнения (если это прописано в программе) сохраняется в блокчейне в специальном хранилище. Назовем данные, сохраняемые в блокчейне – персистент данными.
  • Код смарт-контракта после заливки в блокчейн дополнительно заливается сверху слоем эпоксидки, чтобы предотвратить любое случайное или намеренное изменение кода.
  • Функции смарт контракта могут быть вызваны извне (с кошелька пользователя или из другого контракта) и делятся на две большие группы:

– Не меняющие состояние персистент данных (только чтение из блокчейна)

– Меняющие состояние  персистент данных

Вызов функций первой группы не стоит газа и денег и не уходит дальше ближайшей ноды, к которой мы подцеплены (пример: Balance Of, TotalSupply, Allowance). В BSC scan эти функции перечислены во вкладке “READ”

Вызов функций второй группы превращается в полноценную транзакцию, которая майнится, включается в блок и результат которой записывается в блокчейн. (пример: Approve, Transfer, TransferFrom). В BSC scan эти функции перечислены во вкладке “WRITE”

Блокчейны состояния

  • Etherium и блокчейны, построенные на его основе (/Matic, BSC, и т.д.), относятся к блокчейнам состояния.
  • Каждый адрес хранит в блокчейне значение своего баланса в нативной монете блокчейна (ETH, BNB, MATIC)
  • Каждый смарт-контракт хранит в блокчейне значения своих персистент переменных
  • На текущий момент времени (Блок Х) состояние блокчейна описывается балансом всех существующих адресов в сети и текущими значениями персистент переменных всех смарт-контрактов в блокчейне.

Аккаунты

  • Сид-фраза (12 слов) которую вы записали при первом создании вашего кошелька, при помощи протокола BIP 39 превращается в приватный ключ, который при помощи алгоритма ECDSA (Elliptic Curve Digital Signature Algorithm) превращается в публичный ключ, который при помощи хеширования и обрезания превращается в ваш адрес в блокчейне. То есть:

Сид-Фраза -> Приватный ключ -> Публичный ключ -> Адрес

  • И это превращение совершенно однозначное. Из одной и той же сид фразы вы всегда получите один и тот же адрес со своим балансом.
  • Поэтому чтобы перенести свой аккаунт на другой кошелек (MetaMask, Trust Wallet, SafePal, Coin98. …) Вам всего лишь надо восстановить ваш аккаунт на новом кошельке используя сохраненную сид фразу.
  • Отсюда следует, что сид фразу надо хранить как зеницу ока, поскольку она дает полный доступ к вашему аккаунту.

А где же наши токены?

  • Для каждого аккаунта (адреса) в блокчейне хранится только баланс этого адреса в нативной монете блокчейна и все. А где же токены, которые мы купили?
  • Баланс вашего адреса в каждом купленном токене хранится в смарт-контракте этого токена в таблице (условно) balances, состоящей из двух столбцов – адрес и его баланс в токенах.

В BSC scan эта таблица отображается на вкладке “HOLDERS”

  • Именно поэтому чтобы баланс токена появился в вашем кошельке токен надо в него (кошелек) добавить. После добавления кошелек запрашивает смарт-контракт токена на предмет текущего баланса своего аккаунта и радостно отображает это в интерфейсе.

Один адрес – множество сетей

  • Ethereum был первым блокчейн (спасибо Виталий!) построенным вокруг идеологии смарт-контрактов. Первым и настолько успешным, что породил множество клонов, различающихся между собой порой только алгоритмом консенсуса и стоимостью транзакций.
  • Поэтому вы можете использовать (и используете) один и тот же адрес в сетях BSC, Polygon. Ethereum, и т.д. Когда вы находитесь внутри кошелька (хорошо что не чайника, да?) представьте что вы стоите на вокзале с билетом на поезд с номером 0хbc12….dd, вокруг вас множество дверей, на них написано Ethereum, BSC, Polygon,,, За дверями разные железные дороги и поезда, кто-то на угле, кто-то на ядерном реакторе, кого-то вообще еще лошади тянут. Но все они стоят на рельсах, везде есть локомотив и вагоны. И ваш билет всегда соответствует месту в одном из таких вагонов какую бы дверь вы ни открыли.

***

Итак:

  • Ключом к вашему аккаунту является сид-фраза или секретный ключ, однозначно определяющая ваш адрес в сети и дающая полный доступ к аккаунту
  • Ваш баланс какого-то токена лежит в смарт-контракте этого токена
  • Вы можете использовать один адрес для всех Ethernet-based блокчейнов
  • Смарт-Контракт это неизменяемая программа плюс изменяемые данные, которые хранятся в блокчейне
  • У смарт-контракта есть две группы функций, которые можно вызвать извне – не изменяющие состояние блокчейна (READ) и изменяющие (WRITE)

Интерфейс ERC 20/BEP 20 как основа контракта токена, разбор функций контракта

Что такое Интерфейс

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

Интерфейс ERC-20

  • На текущий момент уже создано и каждый день создается множество токенов. Но с любым токеном мы можем взаимодействовать единообразно – пересылать, свапать, апрувить и т.д. За счет чего же достигается подобная унификация?
  • Чтобы токен мог называться токеном, он должен “реализовывать” интерфейс ERC 20/BEP 20. Реализовывать означает, что смарт контракт токена должен содержать вполне определенный набор функций и параметров с однозначно прописанной реакцией (что смарт контракт должен сделать) на вызов каждой из этих функций.

Interface of the standard as defined in the EIP.

FUNCTIONS

EVENTS

  • Также не забываем, что при вызове каждой функции у нас незримо присутствуют еще два параметра (на самом деле их больше, но не будем усложнять):

msg.sender – адрес с которого прилетела транзакция (кто вызвал функцию)

msg.value – количество денег (нативных монет – ETH/BNB) пересланных с транзакцией

  • EVENT – способ передать информацию из смарт-контракта наружу, в web3 программу, вызвавшую контракт. Как флажок о том, что выполнена такая-то операция. Подробно рассматривать не будем, просто запомните.

Описание функций ERC-20

Разобьем наши 6 функций на две группы:

Группа READ (только читаем из блокчейна):

Группа WRITE (меняем состояние блокчейна):

***

  • Существует стандарт ERC-20 описывающий интерфейс (функции, их параметры и возвращаемые значения), который должен реализовывать смарт-контракт, чтобы называться токеном.
  • Если смарт-контракт реализует интерфейс ERC-20, то мы можем его использовать везде, где возможно использование токена – свапать его на DEX, пересылать друг другу, сжигать и т.д. И совершенно неважно что на самом деле представляет собой этот контракт.
  • Помните – если что-то выглядит как утка, ходит как утка и крякает как утка, то мы можем ее использовать как утку, КАКАЯ РАЗНИЦА ЧТО ЭТО ТАКОЕ НА САМОМ ДЕЛЕ )

Что происходит под капотом при работе с контрактом / Пример использования функций

Давайте рассмотрим на примере:

  • Вася решает создать свой токен. Он берет самую стандартную реализацию ERC20, меняет название, количество (1000), прописывает что при создании контракта ему должны быть намечены (переданы) все 1000 токенов и деплоит смарт-контракт в блокчейн.

Смарт контракт выполняет функцию конструктора (специальная функция выполняющаяся один раз при деплое контракта), которая инициализирует внутренние переменные, в частности создает две пустые таблицы – balances и allowances, затем вызывает функцию mint, которая создает первую строчку в таблице balances:

Вася – 1000

И завершает работу. Контракт готов.

  • Вася решает подарить своим друзьям Коле и Борису по 100 токенов

Кошелек Васи инициирует две транзакции к смарт-контракту токена: transfer(Коля, 100) и transfer(Борис, 100). В данном случае с кого надо списать монеты определяется тем, кто послал транзакцию, т.е. с баланса Васи (msg.sender, помните?).

Смарт-контракт просто меняет таблицу balances добавляя в нее две новые строчки и меняя сумму у Васи:

Вася – 800

Коля – 100

Борис – 100

  • Вася решает вывести токен на биржу, для этого он идет на панкейк и создает пару ликвидности Token-BNB. (800 токенов – 2 BNB)

Панкейк роутер создает пару ликвидности, Вася заливает в нее 800 токенов и 2 BNB, в результате где-то в другой вселенной в контракте BNB появляется строчка CAKE-LP-Token – 2, а в контракте токена таблица balances теперь выглядит так:

Вася – 0

Коля – 100

Борис – 100

CAKE-LP-Token/Pancake Router – 800   (В BSC scan мы можем увидеть ликвидность в таблице holders)

* для простоты рассказа считаем, что Pancake Router и CAKE-LP-Token с точки зрения контракта токена это одно и то же. На самом деле нет, там все хитрее, но не будем усложнять, для наших целей такое упрощение вполне допустимо.

  • Коля решает прикупить еще 100 токенов, он идет на Панкейк, говорит “Хочу купить 100 токенов за BNN, почем нынче овес?”

Панкейк рутер запрашивает у пары ликвидности текущий курс токена к BNB (по алгоритму AMM) и говорит Коле – Это будет тебе стоить 0.25 BNB + комиссия.

  • Договорились, Коля отправляет Панкейку 0.25 BNB и ждет свои токены.

Панкейк рутер видит, что деньги пришли и создает транзакцию на смарт-контракт токена: transfer(Коля, 100) от имени LP пары.

Смарт контракт выполняет запрошенное, дебетуя счет пары и кредитуя счет Коли. В результате:

Вася – 0

Коля – 200

Борис – 100

CAKE-LP-Token – 700 

Панкейк роутер отправляет 0.25 BNB на другой конец вселенной и на другом плече LP пары в контракте BNB значение баланса пары CAKE-LP-Token увеличивается с 2 до 2.25

  • В это время Борис решает продать все токены и купить на все Binamon (БИНАМООН :). Он идет на панкейк и говорит: “Хочу продать 100 токенов, почем возьмешь?”

Панкейк рутер запрашивает у пары ликвидности текущий курс токена к BNB (по алгоритму AMM) и говорит Коле – Это будет тебе стоить 0.37 BNB + комиссия.

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

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

Борис до этого ничего не продавал, результат выполнения функции = 0. Панкейк видит это и в интерфейсе свопа рисует для Бориса кнопку “APPROVE”.

  • Борис нажимает на кнопку “APPROVE”

Кошелек Бориса инициирует транзакцию к смарт-контракту токена: approve(Панкейк-рутер, 99999999999999999), позволяя роутеру списывать со своего счета столько токенов, сколько ему (рутеру) надо.

* На самом деле правильнее было бы на каждую транзакцию давать разрешение только на сумму этой транзакции, но люди ленивые существа и поэтому обычно никто не заморачивается и в качестве количества разрешенных к списанию токенов ставит максимально возможное число. В нашем примере для простоты это много много 9-к.

Смарт-контракт токена выполняем операцию, добавляя в таблицу allowance строчку:

Борис – (Панкейк-рутер, 999999999) и генерирует событие Approval

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

Если смарт-контракт возвращает 9999999999 и это значение больше или равно сумме текущей транзакции, то рутер убирает кнопку “APPROVE” из интерфейса и включает кнопку “SWAP”. Если возвращается 0, то кнопка “APPROVE” не исчезает, кнопка “SWAP” все еще неактивна.

  • Борис нажимает на кнопку “SWAP”

Панкейк рутер дает команду BNB-шному плечу LP пары отправить 0.37 BNB Борису и создает транзакцию на смарт-контракт токена вызывая функцию transferFrom(Борис, Панкейк-рутер, 100)

Смарт-контракт проверяет наличие в таблице allowance строчки, разрешающей Панкейку списывать монеты с адреса Бориса, находит ее и выполняет операцию.

Таблица balances теперь имеет вид:

Вася – 0

Коля – 200

Борис – 0

CAKE-LP-Token – 800 

  • Все получилось, все довольны, все операции проведены, время пить кофе )

***

  • Токены пересылаются с баланса отправителя транзакции (обычно это кошелек пользователя) на любой другой адрес с помощью функции transfer.
  • Токены могут пересылаться с любого адреса на любой адрес, только если есть разрешение через функцию approve списывать деньги с адреса дебитора.
  • Функция approve вызывается владельцем адреса, который выдает разрешение другому адресу списать токены с его баланса.
  • Наличие разрешения можно посмотреть через функцию allowance.
  • При любых трансферах токены просто переезжают из одной строчки таблицы balances в другую, никогда не покидая пределов своего смарт-контракта.
  • Если вы хотите заранее апрувить продажу токена, вы заходите в смарт-контракт ТОКЕНА, вкладка WRITE, ищете там функцию APPROVE и вставляете адрес смарт-контракта РУТЕРА той свалки где хотите свапать. В нашем случае это адрес Панкейк-рутера: 0x10ED43C718714eb63d5aA57B78B54704E256024E

Разбор основных типов скама: рагпул, ханипот, свистоперделки. Где и как искать в контракте.

A) Рагпул – Ситуация, когда в токене на свалке внезапно (или очень быстро) исчезает вся ликвидность и вы остаетесь с кучей токенов, которые невозможно продать.

Заключение

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

Настоятельно советуем пройти базовые курсы по программированию, чтобы уметь на минимальном уровне читать код контракта и понимать хотя бы примерно что тот или иной кусок кода делает.

Удачи!