Pull to refresh

Учимся писать Waves смарт-контракты на RIDE и RIDE4DAPPS. Часть 1 (Многопользовательский кошелек)

Scala *Hackathon
Tutorial


Всем привет!


Совсем недавно Waves Labs анонсировал конкурс для разработчиков приуроченный к релизу в тестовую сеть расширения языка смарт-контрактов RIDE для децентрализованных приложений Ride4Dapps!


Мы выбрали кейс DAO, так как Ventuary планирует заниматься разработкой dApp с социальными функциями: голосованием, фандрейзингом, доверительным управлением и пр.


Мы начали работу с простого примера в Q&A-сессии и в RIDE IDE — примере с общим кошельком.


Давайте разберем данный пример, проверим гипотезы и рассмотрим некоторые странности:


Пусть у нас есть Alice — dApp Owner
Boob и Cooper — партнеры Alice, сооснователи Alice-BC DAO
Neli — владелец бизнеса, которой нужно финансирование
Bank — банк, раздающий токены


Этап 1. Инициализация балансов


Для того, что в тестовой сети waves получить токены, нужно обратиться к faucet и указать адрес на который отправить токены.


Адрес можно узнать в IDE, раскрыв данные аккаунта.


Выделяем Bank 10 WAVES. После проверяем, что они поступили через обозреватель блоков и транзакций: обозреватель


Теперь давайте раздадим токены из банка остальным участникам. (Notes: Все транзакции в сети waves не бесплатны, поэтому необходим минимальный положительный баланс у всех участников, чтобы совершать транзакции).


1 WAVES = 100000000 единиц (wavelets), так как amounts могут быть только integer
0.01 WAVES (Transaction Fee) = 1000000

Bank -> [3 WAVES] -> Alice, через TransferTransaction (Type: 4).


Проверяем, что env.SEED, от которого подписываются транзакции соответствует нашему Bank:




Если у вас нет соответствия seed фраз, просто переключитесь в него во вкладке Accounts и проверьте еще раз.


После этого создаем, анонсируем и подписываем транзакцию о передаче 3 WAVES Alice.
Узнать данные Алисы можно также через переменную env.accounts. Нумерация начинается с 0, соотвественно Алиса это env.accounts[1].



broadcast(transfer({recipient:address(env.accounts[1]), amount: 300000000, fee: 1000000}))

Результат можно также наблюдать в обозревателе, ссылка на него нам возвратится сразу после исполнения транзакции.


Убеждаемся, что баланс Alice пополнен на 3 WAVES, а на балансе банка осталось 10 — 3 — 0.01 = 0.699.




Отправляем Boob и Cooper по 3 WAVES, а Neli, Xena и Mark по 0.2 WAVES тем же способом.
(Notes: Мы допустили ошибку на один знак и отправили Neli 0.02 WAVES. Будьте внимательны!)


broadcast(transfer({recipient:address(env.accounts[4]), amount: 20000000, fee: 1000000}))

После пополнения балансов всех участников мы видим:



Этап 2. Создание dApp аккаунта


Мы договорились, что создателем и оунером децентрализованного приложения будет Alice.
В Accounts переходим устанавливаем ее, как SEED и проверяем env.SEED соответствует Alice.


Попробуем установить на аккаунт Alice самый простой скрипт (контракт) из возможных.
Смарт-контакты в Waves — это предикаты, которые запрещают или позволяют выполниться какому либо типу исходящей транзакции при определенных условиях. В данном случае это условие — ALWAYS. Код контракта — true. Вызываем deploy().



Fee за setScript транзакцию 1400000/100000000 = 0.014 WAVES. У Алисы на балансе осталось 2.986 WAVES.


Попробуем сейчас установить на аккаунт Alice более сложную логику смарт-контракта, описанную в примере


Ride4Dapps теперь включает 2 новых типа аннотаций:
  1. @Callable(i) — принимает в качестве параметра i, данные о том, какой аккаунт вызвал/подписал транзакцию. Именно результат этой функции определяет изменение состояния dApp аккаунта. Другие аккаунты могут создавать транзакции и исполнять функции с этой аннотацией и менять состояние dApp аккаунта.
  2. @Verifier(tx) — Верификатор транзакции с параметром tx транзакции. Соответствует логики предикатов из RIDE. Именно в этом выражении можно разрешить или запретить дальнейшие изменения логики смарт-контрактов на dApp аккаунте.
    Будьте внимательны! Важный момент заключается в том, что по-умолчанию скрипт на аккаунте не равен true, а использует сравнение подписи и позволяет только обладателю подписи совершать транзакции.
    sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPk)


    Без такой проверки, кто угодно может совершать транзакции с аккаунта!

Давайте сделаем dApp аккаунт как общий кошелек для всех участников.



Чтобы проверить то, какой сейчас контракт активен на аккаунте можно в обозревателе блоков скопировать base64 код смарт-контракта и распознать его через декомпилятор (например)





Убеждаемся, что логика смарт-контракта соответствует тому, что мы ожидаем.
У Алисы на балансе осталось 2.972 WAVES.


Данный dApp ведет учет того, сколько вносят каждый из участников в общий фонд через механизм data transaction — DataEntry(currentKey, newAmount), где currentKey — это аккаунт, который вызывает функцию deposit, а newAmount — это значение пополненного баланса.


Boob и Cooper вносят свои депозиты на dApp account по 1 WAVES.



Допускаем ошибку и транзакция не проходит. Так как мы несмотря на то, что убедились в том, что делаем транзакцию от имени Bob ошиблись в индексе и указали аккаунт Bank, на котором нет смарт-контракта. Тут стоит отметить важный момент — за неудачные попытки инициировать транзакции комиссия не снимается! У Алисы на балансе осталось 2.972 WAVES. У Bob 3 WAVES.


Bob отправил 1 WAVES на dApp Account.


broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"deposit",args:[]}, payment: [{amount: 100000000, asset:null }]}))


У Bob осталось 1.99 WAVES. То есть Bob заплатил 0.01 WAVES комиссии



У Алисы на балансе было 2.972 WAVES, стало 3.972. На аккаунте Alice также зарегистрирована транзакция, однако c dApp Account (Alice) никакой комиссии не было списано.
После того, как Cooper также пополнил счет у Алисы на балансе стало 4.972 WAVES.



О том, кому сколько WAVES в общем кошельке принадлежит можно узнать в обозревателе блоков во вкладке Data.


Cooper передумал оставлять сумму в 1 WAVES на общем кошельке и решил вывести половину сродств. Для этого он должен вызвать функцию withdraw.



Однако, мы снова ошиблись, так как у функции withdraw совсем другие параметры, другая сигнатура. Когда будете проектировать смарт-контракты на RIDE4DAPPS следует обратить внимание на этот момент



У Cooper на балансе стало 2.48 WAVES. Соответсвенно 3 WAVES — 1 — 0.01, а потом + 0.5 — 0.01. Соотвественно каждый вызов deposit и withdraw обходится в 0.01 WAVES. В итоге, в таблице собственников dApps записи поменялись следующим образом.



Bob также решил изъять некоторую сумму из общего кошелька, но ошибся и попытался извлечь 1.5 WAVES.



Однако в смарт-контракте была проверка на такую ситуацию.


Xena — мошенница, попробовала вывести 1 WAVES из общего счета.



У нее также ничего не вышло.


В следующей части рассмотрим более сложные моменты связанные с несовершенством Alice dApp Account.

Tags:
Hubs:
Total votes 12: ↑9 and ↓3 +6
Views 2.1K
Comments Comments 2