Объясняем смарт-контракты eosDAC

О чём идет речь?

На днях меня спросили о eosDAC, и что же особенного в нашей работе по созданию такой “странной” вещи, которую мы называем DAC инструменты. Чем отличается это решение от централизованных решений для управления организациями и их операциями? Насколько это безопасно? Как мы смогли разработать и построить коллекцию смарт-контрактов, гарантирующую, что ни одна другая организация не сможет навредить DAC через смарт-контракты?

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

Одна из главных идей во всех наших смарт-контрактах – это возможность их повторного использования другими DAC, чтобы можно было без проблем скопировать и использовать наш исходный код. С самого начала это стало для нас основным убеждением и оправданием того, почему некоторые решения стали более сложными, чем могли бы быть, если бы мы разрабатывали решение исключительно для нас. Будущая цель - сделать их еще более удобными, чтобы другие DAC могли использовать наши смарт-контракты и настраивать их параметры для своих собственных целей без необходимости переписывать исходный программный код. Таким образом, они получат все обновления одновременно вместе с командой eosDAC при добавлении новых функций и исправлении возможных ошибок.

Код контрактов состоит из контрактов для токенов (eosdactokens), для выборов и управления хранителями (dacustodian), для подачи и управлению рабочими предложениями, а также для оплаты и координации отдельного депозитного счета (dacescrow), чтобы надежно сохранить средства по рабочим предложениям. Это необходимо, как для защиты самого DAC, так и работника от возможной потери оплаты за выполненную работу.

EOSDACTOKENS

С этого контракта всё и началось. Токены EOSDAC хранятся в этом смарт-контракте. Все началось с копирования eosio.token - главного контракта для токенов, который используется и для токена EOS, а также является отправной точкой для всех токенов, работающих на блокчейне EOS. Мы добавили некоторые функциональные возможности к этому контракту, чтобы соответствовать нашим потребностям для запуска DAC и первоначального эирдропа. Он включает в себя следующее:

Возможность создания токенов в заблокированном состоянии

Основная цель заключалась в том, чтобы во время первоначального дропа держателям оригинальных токенов на базе Ethereum в июне 2018 года, мы бы смогли провести тщательную проверку балансов аккаунтов получателей прежде чем пользователи смогли бы начать торговать своими токенамии и убедились, что они соответствуют ожидаемым остаткам при снимке сети Ethereum. Мы очень серьезно отнеслись к тестированию :)

EOSDAC был одним из первых токенов, который сделал эирдроп в сети EOS, так что многое на тот момент было неизвестно. Как только дроп был завершен и протестирован, мы смогли разблокировать токены и разрешить их передачу. Важно отметить, что нет возможности повторно заблокировать токен после того, как его разблокировали, так как эта функция могла бы позволить создателям токенов манипулировать ценой посредством централизованного контроля ликвидности токенов.

Условия принятия участников

Согласие с условиями использования в рамках DAC рассматривалось нами как фундаментальная ключевая особенность смарт-контрактов DAC, и поэтому имело смысл включить эту функциональность в контракт токенов. Пользователь становится зарегистрированным участником сообщества после подтверждения и выполнения действия memberreg по контракту.

Для выполнения этого действия пользователь должен будет согласиться с условиями, и тем самым подтвердит контрольную сумму с известной контрольной суммой последних условий, прежде чем стать зарегистрированным участником. Эта логика контрольной суммы абстрагируется от конечного пользователя через графический интерфейс, и предоставляет криптографическое подтверждение того, что пользователь согласился с определенным набором терминов и добавляет своё согласие для взаимодействия с кодом контракта. Пока выполняются эти условия и совпадает контрольная сумма известных условий действие memberreg успешно выполняется. Хотя это может показаться слишком сложным способом подтверждения согласия с терминами и условиями, мы специально выбрали такой подход, потому что это как сказать «я согласен с этими условиями» вместо того, чтобы спрашивать пользователя «Согласны ли вы с последними положениями и условиями» с ответом пользователя «да» или «нет». Мы считаем, что последнее будет менее надежным, так как пользователь может случайно принять неправильные условия, которые уже устарели в контракте.

В интересах экономии использования RAM для всех конечных пользователей в контракте хранится только ссылка на хэш принятых условий, хранящийся в контракте, а не копия принятого хэша для каждого пользователя. Это означает, что каждому пользователю нужно хранить только версию принятых терминов (8 байт), а не весь хэш (32 байта) , и поскольку использование RAM в сети дорого, любая небольшая экономия нам помогает.

Состояние принятия последних условий каждым участником неоднократно упоминаются в смарт-контрактах eosDAC, чтобы гарантировать, что пользователь не сможет выполнять действия в DAC без согласия с последними условиями, в том числе и в будущем при обновлении таких условий.

DACCUSTODIAN

Этот контракт управляет всеми ставками, выдвижением, голосованием, подсчетом голосов и назначением хранителей по завершении каждого периода выборов. Конечным результатом действий этого контракта является управление разрешениями на управляющей учетной записи DAC (dacauthority), настраиваемыми с помощью конфигураций этого контракта. Управляющая учетная запись имеет заранее определенные разрешения на все действия в DAC, включая изменение кода и перевод средств. Эти разрешенные действия управляются различными транзакциями с мультиподписью, используя встроенные сложные инструменты управления разрешениями, доступные в программном обеспечении протокола EOSIO. Параметры избирательного процесса могут быть изменены с помощью конфигурации, установленной в контракте при помощи действия updateconfig. Функциональность этого контракта можно разбить на следующие разделы:

Cтекирование

Перед тем, как выдвинуть себя в качестве кандидата, участник должен сначала перенести определенную сумму EOSDAC, используя действие transfer по контракту токена на этот счет. Поле Memo должно быть одинаковым с именем учетной записи этого контракта (например “daccustodian”) для того, чтобы перенос был признан как транзакция по стекингу, а требуемая сумма настраивается полем lockupasset в объекте конфигурации. После установки ставки в контракте будет указана сумма ожидающей ставки для этого кандидата, готового к выдвижению.

Выдвижение кандидатов - nominatecand:

Чтобы стать избранным хранителем DAC, зарегистрированный участник должен сначала выдвинуть себя в качестве кандидата, используя действиеnominatecand. Для этого потребуется указать имя выдвигаемой учетной записи и запрашиваемую сумму оплаты в EOS. Это действие проверяет, что пользователь является зарегистрированным участником и стекировал достаточное количество токенов EOSDAC. Также контракт проверяет, что запрашиваемая сумма оплаты не превышает допустимое значение requested_pay_max из конфигурации, и если все эти условия будут выполнены, добавит пользователя в качестве кандидата для голосования.

Голосование - votecust:

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

  • Голосование требует действительного членства и согласия с текущими условиями участия.
  • Вес каждого голоса определяется балансом EOSDAC, который избиратель имеет на своем счете. (В настоящее время для голосования не требуется никаких ставок)
  • После того, как голоса избирателя будут размещены, это голосование остается активным до тех пор, пока избиратель не изменит свои голоса. Если баланс аккаунта упадёт до 0, а затем снова станет положительным или один из кандидатов уходит в отставку, а затем возвращается, голосование за него по-прежнему будет активным и применимым при подсчете голосов.
  • Все кандидаты, за которых проголосовал избиратель, получают одинаковый вес голоса на основе баланса EOSDAC.
  • Существует максимальное количество кандидатов, за которых избиратель может голосовать, определяемое настройкой конфигурации.
  • Чтобы удалить голосование, избирателю нужно будет проголосовать с пустым списком кандидатов.
  • Голосование и передача токенов для голосования будет иметь прямое и непосредственное влияние на вес каждого активного голосования, но единственный раз, когда вес голосов будет иметь значение - это блок, когда вызывается действие newperiod. (Объяснено ниже)

Новый период выборов - newperiod:

Для каждого действительного кандидата вес голоса будет непрерывно отслеживаться на основе изменений, вызванных действием votecust или действием transfer в контракте токена, если есть активное голосование за учетные записи from или to в действии передачи. При непрерывном отслеживании этих значений фактические выборы (во время newperiod) должны только сделать снимок кандидатов, выбранных большинством голосов в этот момент. Количество кандидатов настраивается с помощью поля numelected в конфигурации. Для успешного выполнения действия newperiod потребуются другие проверки, в том числе:

  • Убедитесь, что начальное число избирателей превышает initial_vote_quorum_percent в конфигурации.
  • Убедитесь, что на последующих выборах число избирателей превышает vote_quorum_percent в конфигурации.
  • Убедитесь, что период времени между вызовами newperiod превышает periodlength длину периода.

Если все эти проверки успешно пройдены будут выполнены следующие действия:

  • Оплата хранителей распределяется в соответствии со средней суммой текущих сумм requestedpay хранителей.
  • Новые хранители выбираются на основе рейтингового веса накопленных за них голосов за следующий период.
  • Разрешения на управление учетными записями DAC обновляются для включения вновь назначенных хранителей.
  • Текущее время сохраняется для использования в качестве временной ссылки для будущих вызовов newperiod, чтобы убедиться, что он не вызывается слишком рано для следующего периода.
  • Для каждого кандидата, избранного в качестве хранителя, будут заблокированы их токены, чтобы показать, что они достаточно благонадежны. Они смогут отменить блокировку токенов, как только они больше не будут хранителями в течении, определенного lockup_release_time_delay времени из конфигурации.

Другие операции:

В дополнение ко всему вышеперечисленному, есть и другие действия, поддерживаемые в этом контракте, включая:

  • Снять кандидата (withdrawcand): Эта функция вызывается существующим кандидатом, в том числе тем, который в настоящее время является избранным хранителем, если он захочет снять себя со следующего периода выборов. Его токены будут остануться заблокированными до истечения заданного промежутка времени. Хороший пример использования этой функции – это возможный отпуск хранителя, но вскоре он собирается вернуться (вот почему функция разблокировки токенов существует отдельно от этой). В противном случае это действие могло бы быть использовано по любой другой причине для добровольного отказа кандидата от участия в деятельности DAC.
  • Уволить кандидата (firecand): Это действие в настоящее время может быть вызвано только избранными хранителями с помощью мультиподписи, чтобы удалить кандидата с плохой репутацией или поведением. Это действие также имеет возможность заблокировать токены кандидата, если они еще не заблокированы.
  • Уволить хранителя (firecust): Аналогично с firecand это действие приведет к отстранению от должности в настоящее время избранного хранителя по решению других хранителей. Это приведет к удалению хранителя из избранной группы хранителей, а также удалит его в качестве потенциального кандидата на будущие выборы, заменит хранителя следующим в списке по количеству голосов кандидатом и, наконец, обновит разрешения учетной записи, чтобы отразить новый набор избранных хранителей.
  • Отправить хранителя в отставку (resigncust): Это действие выполняется активным хранителем, который хотел бы уйти с должности действующего хранителя. Это отменит его регистрацию в качестве кандидата и заменит хранителя следующим в списке по количеству голосов кандидатом.
  • Обновление запрашиваемой оплаты (updatereqpay): Кандидат может обновить свою запрошенную оплату за работу качестве хранителя. Но обновление не вступит в силу до следующего периода, чтобы предотвратить изменение средней дельты в текущем периоде.
  • Запросить оплату (claimpay): Это действие, вызывается активным хранителем, чтобы получить сумму оплаты, которая должна быть ему выплачена. Из-за особенностей правовой системы и другим юридическим причинам этот платеж проводится через сервисную компанию. С точки зрения контракта - это действие по оплате услуг хранителю DAC, и после этого данное обязательство считается выполненным.
  • Обновление конфигурации (updateconfig): Существует несколько настраиваемых параметров контракта, позволяющих его использование без необходимости перекомпиляции всего кода. Основная идея заключается в том, что это позволит другим DAC работать с одним и тем же развернутым кодом, но со своими собственными конфигурациями. Изменения вносятся путем установки нового объекта в конфигурации с помощью действия со следующими параметрами:

    • lockupasset: Сумма токенов EOSDAC, которые необходимо стекировать каждому кандидату, участвующему в выборах.
    • maxvotes : Максимальное количество кандидатов, за которых каждый участник может проголосовать. (По умолчанию 5)
    • numelected : Число хранителей, избираемых при каждом подсчете голосов.
    • periodlength : Продолжительность периода в секундах. Используется для предотвращения досрочных выборов от вызова функции newperiod. (По умолчанию 7 дней)
    • authaccount : Контрольная учетная запись должна иметь разрешения, установленные избранными хранителями.
    • tokenholder : Контракт, в котором хранятся средства DAC. Используется в качестве источника для оплаты хранителям.
    • serviceprovider : Контракт, который будет выступать в качестве учетной записи поставщика услуг для DAC. Используется в качестве источника для оплаты хранителям и участникам по рабочим предложениям.
    • should_pay_via_service_provider : Если установлено значение true, контракт будет направлять все платежи через поставщика услуг, а не напрямую.
    • initial_vote_quorum_percent : Необходимое количество проголосовавших токенов, необходимых для запуска совета хранителей.
    • vote_quorum_percent : Необходимое количество проголосовавших токенов, необходимых для запуска нового совета хранителей после достижения первоначального порога - 2ой период выборов и далее.

    Необходимое количество хранителей для утверждения различных уровней аутентифицированных действий в смарт-контрактах DAC:

    • auth_threshold_high
    • auth_threshold_mid
    • auth_threshold_low
    • lockup_release_time_delay : Время до того, как заблокированные токены будут возвращены кандидату с помощью действия unstack.
    • requested_pay_max : Максимальная сумма оплаты, которую может запросить хранитель.

DACPROPOSALS

Этот контракт отвечает за управление рабочими предложениями DAC. Он снова построен с учетом максимальной конфигурируемости, а не только для решения задач eosDAC.

Общая идея заключается в том, что у потенциального работника есть идея для реализации, которую он хотел бы предложить DAC в обмен на оплату в токенах EOS. Для утверждения предложения проголосуют текущие хранителями, а после выполнения работы будет произведена выплата автору предложения.

Создать предложение createprop

Потенциальный работник создаёт рабочее предложение и отправляет его в блокчейн для рассмотрения и голосования текущими хранителями DAC. Предложение должно включать следующее:

  • title (String): Определение предложения.
  • summary (String): Краткое изложение цели предложения работника.
  • arbitrator (имя аккаунта EOS): Имя аккаунта независимого арбитра, который может быть вызван для решения возможных споров при завершении предложения работника.
  • pay_amount (EOSAsset): Сумма токенов EOS, запрошенная в качестве суммы оплаты для предложения работника.
  • content_hash (ChecksumHash): Хэш содержимого для обеспечения детализации предложения, хранящийся вне блокчейна, остается неизменным после согласования предложения. Это позволяет сохранить более подробную информацию, которая не будет храниться в бокчейне при сохранении целостности данных.

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

Голосование за предложение voteprop

После того, как предложение было создано, оно будет находиться в состоянии, ожидающем, пока хранители проголосуют либо ‘proposal_approve’ (принято), либо ‘proposal_deny’ (отклонено) за предложение с требуемым количеством голосов и количеством голосов за ‘yes’, которые настраиваются в контракте. Также возможны уточнения к предложению с его отменой cancel и повторной подачей с изменениями на основе обратной связи от хранителей до тех пор, пока предложение не будет принято.

Начать работу над принятым предложением startwork

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

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

Сигнал завершения работы completework

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

Требование оплаты за выполненную работу claim

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

Конфигурация контракта updateconfig

Различные параметры настраиваются для этого контракта и включают:

  • service_account : Имя аккаунта EOS
  • proposal_threshold : Количество голосов, необходимых для участия в голосовании за предложение.
  • proposal_approval_threshold_percent : Требуемое количество голосов для утверждения предложения.
  • claim_threshold : Количество голосов, необходимых для принятия требования по предложению.
  • claim_approval_threshold_percent : Требуемое количество голосов для принятия требования по предложению.
  • escrow_expiry : время истечения, установленное для созданной транзакции (количество секунд). Значение по умолчанию - 30 дней.

DACESCROW

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

Инициализация сделки депонирования - init

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

Перевод средств на депозит - transfer

Средства для условного депонирования переводятся на контракт условного депонирования с использованием обычного действия transfer (перевод), он работает точно также для большинства других контрактов токенов EOS. Код этого контракта основан на встроенных уведомлениях, которые действие передачи направляет как отправителю, так и получателю счетов передачи. Когда уведомление о передаче получено контрактом депонирования, реализация функции transfer проверит, что отправитель имеет пустую запись депонирования и назначает сумму, переданную в эту запись для последующей обработки другими действиями в коде контракта. Инициализированная запись депонирования может быть отменена действием cancel (отмена) при условии, что она вызывается до того, как применили действие.

Одобрение или неодобрение сделки - approve и unapprove

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

Требование утвержденного депозитного платежа - claim

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

Заметка: Шаг сервисной компании не включен по техническим причинам, но является юридическим требованием при взаимодействии с традиционным правовым миром. Мы бы хотели выполнять все действия на блокчейне в криптографически защищенной среде смарт-контрактов, но пока мир к этому не готов :( .

Возврат после истечения срока действия - refund

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

Назад