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

Пару лет назад я работал над интересным веб-приложением службы доставки пакетов p2p. По каким-то причинам разработку пришлось заморозить на стадии прототипа, поэтому я просто выложил исходники на GitHub и забыл об этом.

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

В какой-то момент я пришел к выводу, что только в такой среде у моего проекта есть шанс развиваться и процветать.

Смотрим на предстоящую работу

Первоначальная идея заключалась в том, чтобы люди, которые часто путешествуют, могли доставлять любые посылки в своих чемоданах или автомобилях за деньги или бесплатно. Этакий Uber для доставки. Пользователи делятся на путешественников и клиентов. Если вы собираетесь ехать, скажем, из Нью-Йорка в Монреаль на выходные, вы можете добавить в сервис новую поездку с описанием, что и когда можно доставить. Подписанные клиенты уведомляются о новой поездке в этом направлении и могут добавлять заявки на доставку, например, какого-нибудь лекарства или нового велосипеда для младшего брата. Стороны договариваются об оплате (эскроу на PayPal) и условиях поставки. После выполнения заказа стороны могут оставлять оценки и комментарии друг о друге. У каждого пользователя есть небольшая статистика в профиле.

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

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

Протокол такой службы будет следующим:

  • Клиент добавляет Заказ на доставку из пункта А в пункт Б
  • Перевозчик может добавить Предложение
  • Заказчик может добавить ответ на предложение
  • Перевозчик выставляет Счет на оплату Заказа с указанием суммы Предоплаты и Депозита.
  • Клиент оплачивает Инвойс и может установить Ключ к Депозиту
  • Перевозчик выполняет Заказ и получает Ключ к Депозиту (например, QR-код)
  • Перевозчик может в любой момент вернуть деньги Клиенту.
  • Перевозчик и Заказчик обмениваются оценками и комментариями.

Давайте начнем

Этот протокол будет реализован смарт-контрактом в Solidity, который мы назовем Osliki. Во-первых, мы создадим переменные для хранения заказов, предложений, счетов и статистики:

Order[] public orders;
Offer[] public offers; // here will also be stored responses from customers
Invoice[] public invoices;
mapping (address => Stat) internal stats; // mapping from user addresses to their stats

Описание всех структур:

struct Order {
    address customer;
    string from; // geo coordinate in 'lat,lon' format or Ethereum address '0x...' or empty 
    string to; // geo coordinate in 'lat,lon' format or Ethereum address '0x...' or empty 
    string params; // package params in 'weight(kg),length(m),width(m),height(m)' format
    uint expires; // expiration date in SECONDS since Unix Epoch
    string message;
uint[] offerIds; // array of carrier offers
address carrier; // chosen carrier
    uint invoiceId;
EnumOrderStatus status;
    uint createdAt;
    uint updatedAt;
}
struct Offer {
    address carrier;
    uint orderId;
    string message;
    string respond; // customer respond
    uint createdAt;
    uint updatedAt;
}
struct Invoice {
    address sender; // carrier
    uint orderId;
    uint prepayment; // amount for the prepayment
    uint deposit; // amount for the deposit
    EnumCurrency currency; // ETH or OSLIK (no fee)
    uint expires; // expiration date in SECONDS since Unix Epoch
    bytes32 depositHash; // Ethereum-SHA-3 (Keccak-256) hash of the deposit key string provided by the customer
    EnumInvoiceStatus status;
    uint createdAt;
    uint updatedAt;
}
struct Stat {
    uint[] orders;
    uint rateSum;
    uint rateCount; // averageRate = rateSum / rateCount
    mapping (uint => Review) reviews; // mapping orderId => Stat
}
struct Review {
    uint8 rate; // range between 1-5
    string text;
    uint createdAt;
}

Статусы:

enum EnumOrderStatus { New, Process, Fulfilled }
enum EnumInvoiceStatus { New, Settled, Closed, Refund }
enum EnumCurrency { ETH, OSLIK } // fee of 1% for ETH and no fee for OSLIK

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

Клиент добавляет Заказ на доставку:

function addOrder(
    string from,
    string to,
    string params,
    uint expires,
    string message
) public;

Перевозчик добавляет Предложение:

function addOffer(
    uint orderId,
    string message
) public;

Ответы Заказчика на Оферту:

function respond(
    uint offerId,
    string message
) public;

Перевозчик выставляет Счет:

function addInvoice(
    uint orderId,
    uint prepayment,
    uint deposit,
    EnumCurrency currency,
    uint expires
) public;

Клиент оплачивает Счет:

function pay(
    uint invoiceId,
    bytes32 depositHash // customer sets a keccak256 hash of the key for accessing to the deposit, it can be empty if there is no deposit and all funds are paid in advance
) public payable; // after payment, the invoice is attached to the order, and the sender of the invoice is considered to be chosen as a carrier.

Перевозчик выполняет Заказ и получает Ключ к Депозиту (например, сканирует QR-код):

function fulfill(
    uint orderId,
    string depositKey
) public;

Перевозчик может в любой момент вернуть деньги Клиенту:

function refund(
    uint invoiceId
) public payable;

Перевозчик и Заказчик обмениваются оценками и комментариями:

function addReview(
    uint orderId,
    uint8 rate,
    string text
) public; // here we update stats

Плюс еще несколько функций для получения данных.

В итоге имеем 2 контракта:

  • Контракт Ослики, реализующий наш протокол и являющийся ядром платформы для построения любого бизнеса, связанного с доставкой или зависящего от нее.
  • Токен OSLIK —внутренняя валюта, которую можно использовать для платежей без комиссии. Токены можно продавать через краудфандинговую кампанию для сбора средств на развитие и продвижение платформы и сервисов, построенных на этой платформе.

Примеры

По сути, контракт Ослики — это открытая база данных заказов на доставку, которую может использовать любое лицо, организация или какой-нибудь дрон вроде Amazon Prime Air.

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

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

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

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

Планы

Было бы неплохо иметь здесь децентрализованную торговую площадку (Osliki Marketplace) или объявления (Osliki Classifieds) как часть платформы. Или, возможно, использовать готовые решения.

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

На данный момент стоит задача реализовать фронтенд приложение osliki-js (как один из вариантов) и опубликовать его на GitHub Pages (или на любом другом статичном хостинге сайта), чтобы мы могли работать с контрактами обычным способом в браузере. Плюс набор виджетов для встраивания на сайты.

Если эта тема покажется вам интересной, вы можете присоединиться к разработке.

Ссылки

Ссылки на исходный код на GitHub:

  • "До"
  • "После"

В настоящее время контракты развернуты в тестовой сети Ethereum Ropsten. Тестовые эфиры раздаются здесь.

Адреса договоров: