Доминирование BTC: 69.24%Рыночная капитализация: 266 097 189 879$Объем за 24 часа: 54 161 692 074$Индекс страха: 38
Индекс страха
страх
Подробнее
Что делают киты
  • 1 129 720$btc
    неизвестно
  • 3 058 416$btc
    неизвестно
  • 3 160 362$btc
    неизвестно
  • 4 077 888$btc
    перевод на coinbase
  • 1 794 270$btc
    неизвестно
Подробнее

Аудит смарт контракта SmartLotto от BitStat

14 дек 2018 11:07:42 Аудиты смартов

Исходный код смарт-контракта SmartLotto начинается подробным описанием своей работы и маркетинга на английском языке.

Тем, кому сложно даётся перевод, могут воспользоваться сайтом Smartlotto.in, либо обзором на нашем блоге.

В строке 30 осуществляется подключение библиотеки безопасной математики, код которой расположился в конце контракта. Следом идёт обширный список констант, на которых мы и остановимся.

TICKET_PRICE = 0.1 ether - цена одного билета;

MAX_TICKETS_PER_TX = 250 – максимальное количество билетов за 1 транзакцию;

JACKPOT_WINNER = 1 – количество победителей с самым большим призом;

FIRST_PRIZE_WINNERS = 5 – количество победителей с первым призом;

SECOND_PRIZE_WINNERS_PERC = 10 - процент победителей со вторым призом;

JACKPOT_PRIZE = 10 – процент от общей кассы, который будет составлять самый большой приз;

FIRST_PRIZE_POOL = 5 – процент от общей кассы, составляющий первый приз;

SECOND_PRIZE_POOL = 35 – процент от общей кассы, составляющий второй приз;

REFERRAL_COMMISSION = 5 – процент от суммы вклада, который будет начисляться рефереру;

MARKETING_COMMISSION = 10 – процент от суммы вклада, который будет направлен на маркетинг;

WINNINGS_COMMISSION = 20 – процент от выигрыша, который уйдёт на баланс администрации;

PERCENTS_DIVIDER = 100 – коэффициент для вычисления процентов;

CLOSE_TICKET_SALES = 1546297200 – дата прекращения продажи билетов (31 декабря 2018 в 23:00);

LOTTERY_DRAW_START = 1546300800 – дата начала розыгрыша и выплат (1 января 2019 в 0:00);

PAYMENTS_END_TIME = 1554076800 – дата прекращения выплат призов (1 апреля 2019 в 0:00);

Далее идёт список используемых переменных:

playersCount – общее количество игроков;

ticketsCount – общее количество купленных билетов;

jackpotPrize – размер самого большого приза;

firstPrize – размер первого приза;

secondPrize – размер второго приза;

secondPrizeWonTickets – количество билетов, получившие второй приз;

wonTicketsAmount – общее количество призовых билетов;

participantsMoneyPool – сумма, которая будет распределена между всеми билетами, которые ничего не выиграли;

participantsTicketPrize – размер компенсации с одного билета, который ничего не выиграл;

ticketsCalculated – количество обработанных билетов;

salt – коэффициент, который используется при расчёты случайных номеров;

calculationsDone – признак завершения обработки билетов (true/false);

Адрес маркетинга - 0xFD527958E10C546f8b484135CC51fa9f0d3A8C5f;

Адрес комиссии - 0x53434676E12A4eE34a4eC7CaBEBE9320e8b836e1;

Для хранения данных используются 3 структуры и 3 хранилища (таблицы):

Player – хранит информацию об игроке: количество билетов (ticketsCount), пачки билетов (ticketsPacksBuyed), сумма выигрыша(winnings), количество призовых билетов (wonTicketsCount), выплаченная сумма выигрыша (payed).

TicketsBuy – информация о пачке билетов: владелец (player), количество билетов (ticketsAmount).

TicketsWon – призовые билеты;

players – список всех игроков, доступ к которым осуществляется по адресу кошелька;

ticketsBuys – список купленных билетов;

ticketsWons – список призовых билетов;

Самая первая функция данного смарт-контракта является основополагающей и отвечает за обработку всех поступающих транзакций.

Логика функции следующая: если присланная сумма больше либо равна 0.1 Eth, то запустить функцию покупки билетов. Иначе идёт проверка завершения розыгрыша и, если он завершился, то произвести выплату выигрыша. Получается, что для получения выигрыша необходимо прислать сумму меньшую 0.1 Eth. Функция buyTickets() отвечает за продажу билетов.

Перед началом своей работы идёт проверка текущей даты и сравнение её с датой окончания продажи билетов. Если уже 31 декабря 23:01, то купить билет не получится. В строке 117 осуществляется загрузка данных игроков из базы контракта. Если игрок пришёл впервые, то идёт увеличение счётчика всех игроков на единицу (строка 121). Количество билетов определяется путём деления присланной суммы на 0.1 Eth (строка 125). Если получившееся количество превышает порог в 250 билетов, то оставшаяся сумма средств будет возращена на кошелёк обратно.

Сумма «сдачи» (overPayed) высчитывается в строке 134 и если она больше нуля, то она высылается в строке 142. Всё честно и красиво. В строках 146 – 159 идёт создание и сохранение записей о купленных билетах. Далее, с помощью функции bytesToAddress() определяется адрес реферера из параметра Data, который игрок заполняет при осуществлении транзакции. Если полученный адрес не равен адресу отправителя средств, то 5% от суммы высылается рефереру. Иначе, монеты останутся на балансе контракта. В строках 173 – 175 вычисляются 10% от присланной игроком суммы и направляются на развитие проекта (маркетинг).

Функция makeCalculations() осуществляет расчёт призовых билетов.

Так как расчёт должен производиться всего один раз, то существует проверка на запуск данной процедуры. Если расчёт уже был выполнен, то флаг calculationsDone будет равен true и ничего не запуститься (строка 180). Помимо этого, запуск расчёта призовых билетов возможен только после 1 января 2019 года 0:00 (строка 182).

В строке 185 осуществляется проверка на то, высчитывался ли коэффициент salt для генерации случайных чисел. Если salt равен нулю, то запускается блок кода, который находит итоговые призовые вознаграждения, в том числе, и сам коэффициент salt (строки 187 - 208).

Новые переменные, которые ещё не были упомянуты выше:

secondPrizeWonTickets – количество призовых билетов, получившие второй приз;

wonTicketsAmount – количество всех призовых билетов;

participantsMoneyPool – денежная сумма, которая будет возвращена всем тем, кто не победил;

participantsTicketPrize – размер вознаграждения за билет, который не победил;

После того, как будут определены размеры сумм за первый и второй приз, запускается функция calculateWonTickets(), которая занимается определением номеров призовых билетов (строки 211 - 213). Когда призовые номера будут определены, количество рассчитанных билетов увеличиться на 6 (1 jackpot + 5 firstprize).

Если коэффициент salt уже высчитывался, но не были обработаны все билеты, запускается вторая часть кода функции makeCalculations().

В связи с тем, что при переборе билетов данные записываются в блокчейн, тратиться много вычислительных ресурсов и газа. Поэтому, количество обрабатываемых билетов было уменьшено до 50 за транзакцию. Соответственно, строки 222 – 240 будут выполняться в том случае, когда идёт вычисление очередных 50 билетов. Строка 237 запускает очередной цикл определения обладателей второго приза. В строке 240 обновляется общее число обработанных билетов. Когда общее число обработанных билетов сравняется с числом выигрышных, переменной calculationsDone будет присвоено значение true и расчёт прекратит запускаться навсегда (строка 245).

Как уже было сказано выше, функция calculateWonTickets() занимается перебором и определением призовых билетов.

numbers – число билетов, которые будут участвовать в цикле перебора.

wonTicketNumber – номер призового билета, который генерируется случайным образом при помощи функции random().

В строках 257 – 259 определяется выпал призовой билет впервые или повторно. Если повторно, то число билетов numbers увеличивается на единицу и цикл запускается снова. В том случае, когда призовой билет выпал впервые, он помечается в списке ticketsWons (строка 263). Затем идёт перебор всех билетов и определение игрока, который обладает счастливым билетом. Все полученные данные записываются в базу контракта (строки 273 - 278).

Функция payPlayers() выплачивает средства, в соответствии с проведённым розыгрышем.

Первое, что проверяется – завершился ли расчёт призовых билетов (строка 293). Затем идёт проверка даты (строка 296). Как и было заявлено на сайте проекта, выплаты будут производиться до 1 апреля 2019 года. После этой даты все средства пойдут в адрес администрации (строки 333 - 339).

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

  • вычисление комиссии 20% в адрес администрации ( строка 303);
  • вычисление сумма выплаты от билетов, которые ничего не выиграли (строка 308);
  • сохранение данных в базе (строка 311);
  • выплата призовых билетов и билетов, которые не выиграли (строка 314);
  • выплата 20% комиссии администрации от выигрыша (строка 317);

В случае же, когда игрок не имеет призовых билетов и не имеет выплат (строка 321), осуществляется выплата компенсации (строки 321 - 329). Комиссия с «поощрительного приза» не взимается.

Функция random() в результате своей работы выдаёт случайное число, зависимое от коэффициента salt, который вычисляется из хэша предыдущего номера блока сети Ethereum.

Функция playerBuyedTicketsPacks() предоставляет информацию о купленных пачках билетов каждого игрока. Информацию можно увидеть на вкладке Read Contract в Etherscan.

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

В самом конце исходного кода расположилась библиотека безопасной математики SafeMath.

Библиотека содержит полный набор операций: умножение (mul), деление (div), вычитание (sub), сложение (add) и остаток от деления (mod). Ничего лишнего и зловредного не добавлено.

Итоги аудита смарт контракта SmartLotto от BitStat

К сожалению, из-за сложного алгоритма работы смарт-контракта не исключены логические ошибки. Мы долго общались с разработчиками и просили исправить все найденные проблемы. Были критические баги. Данная версия контракта далеко не первая. В целом, всё работает корректно, средства по завершению розыгрыша выплачиваются.

Аудит исходного кода контракта SmartLotto показал, что владелец контракта не имеет доступа ко всей «кассе».

Приходите на обсуждение проектов в наш чат: https://t.me/joinchat/C1ie2RK-ocDXAyuh2f00rA.

Предупреждение

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

Хотите зарабатывать на крипте? Подписывайтесь на наши Telegram каналы!

0 комментов4 769 просмотров
Читайте также
Комментарии
Только зарегистрированные пользователи могут писать комментарии.
Авторизуйтесь, пожалуйста, или зарегистрируйтесь.
Подписывайтесь