Создание смарт-контракта на Ethereum с помощью web3.js, Node.js и Ganache

Владение и ведение малого бизнеса может быть одной из самых приятных и освобождающих профессий. К сожалению, во многих странах, включая США, владение малым бизнесом является проблемой. Согласно данным Бюро статистики труда Министерства труда США, 20% малых предприятий терпят неудачу в первый год, 50% терпят неудачу на пятом году и 70% терпят неудачу на десятом году. По данным Investopedia, одной из наиболее распространенных причин неудач малого бизнеса является неадекватное бизнес-планирование и, прежде всего, проблемы с денежным потоком. Фактически, опрос, проведенный в 2019 году, показал, что 61% малых предприятий во всем мире сообщили об этой проблеме. Одной из основных причин проблем с движением денежных средств является неспособность владельца малого бизнеса получить платеж в установленный срок.

В 2018 году Intuit QuickBooks провела опрос 500 самозанятых работников и 400 владельцев малого бизнеса. Респонденты этого опроса сообщили, что быстрый и точный сбор платежей - это проблема №1 для самозанятых работников и владельцев малого бизнеса. Несвоевременные платежи создают ряд проблем для владельцев малого бизнеса: оплата их поставщикам / поставщикам, возврат невыплаченных кредитов и оплата своим сотрудникам или даже самим себе. Анализ данных показал, что тот же опрос QuickBooks показал, что 30% респондентов заявили, что просроченные платежи помешали им оплачивать собственные счета, 22% заявили, что это не позволяет им расширять свой бизнес, а 5% были вынуждены продать свои дома. из-за просрочки платежа.

Насколько серьезна эта проблема? Согласно опросу QuickBooks, только 41% самозанятых работников и владельцев малого бизнеса никогда не получали просроченные платежи. Из оставшихся 59% респондентов 8% самозанятых и 4% владельцев бизнеса сообщают, что более половины платежей задерживаются. Насколько поздно эти выплаты? Опрос показывает, что 41% сообщают о получении платежа через одну-три недели после установленного срока, а 58% сообщают об ожидании до месяца или более. Что еще хуже, многие из этих предприятий предоставили услуги, за которые им никогда не заплатят. Согласно опросу, 53% самозанятых работников и 64% владельцев малого бизнеса сообщают, что, по крайней мере, один клиент в год категорически отказывается платить, а 14% самозанятых работников и 10% владельцев бизнеса сообщают, что, по крайней мере, один клиент каждую неделю, который отказывается платить.

Применение блокчейна к этой проблеме

Представьте себе мир, в котором не существует просроченных платежей, потому что платеж оформляется и выполняется по соглашению между малым предприятием и его клиентом! Это стало возможным благодаря основной технологии блокчейна Ethereum: смарт-контрактам. Смарт-контракт, как описано Агентством Национального института стандартов и технологий Министерства торговли США и Ethereum Foundation, представляет собой «набор кода и данных (иногда называемых функциями и состоянием), который развертывается с использованием криптографической подписи. транзакции в сети блокчейн ». Давайте распакуем это определение. Первый ключевой момент - это «сбор кода и данных» - это означает, что мы можем использовать смарт-контракты для написания бизнес-логики, хранения вывода этой логики и управления этим выводом, чтобы делать с ним то, что нам нужно. Следующим ключевым моментом является «развертывание с использованием криптографически подписанных транзакций» - это гарантирует, что все взаимодействия с этим смарт-контрактом безопасны благодаря применению технологий безопасности, таких как асимметричная криптография и шифрование, для всего, от информации о владельце учетной записи до взаимодействий и смарт-контракта. так что даже сеть, выполняющая обработку, не может получить доступ к базовым данным. Последний ключевой момент - «в сети блокчейн» - это означает, что все взаимодействия с этим смарт-контрактом сохраняются и неизменны, потому что выполнение контролируется и проверяется сетью независимых компьютеров, а не централизованными органами, которые могут контролировать и манипулировать действиями на сеть.

Давайте посмотрим, как мы могли бы создать решение, которое позволяет малому бизнесу вовремя собирать платежи, написав смарт-контракт на Solidity, объектно-ориентированном языке высокого уровня для реализации смарт-контрактов, предназначенном для виртуальной машины Ethereum ( EVM) и выполнение контракта с использованием библиотеки web3.js, популярной библиотеки JavaScript, которая предоставляет API для взаимодействия с блокчейном Ethereum.

Чтобы продолжить, вы можете найти исходный код на моем GitHub.

Создание решения с использованием смарт-контрактов и блокчейна Ethereum

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

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

Во-первых, мы создали проект для хранения нашего смарт-контракта.

$ mkdir smb-smart-contract-ethereum
$ cd smb-smart-contract-ethereum
$ echo “{ \”name\”: \”smb-smart-contract-ethereum\”, \”version\”: \”1.0.0\”, \”description\”: \”A decentralized application (dapp) containing a smart contract deployed to an in-memory blockchain.\” }” >> package.json
$ touch SmartInvoice.sol

В файле SmartInvoice.sol мы записываем содержимое нашего смарт-контракта.

contract SmartInvoice {
  uint public dueDate;
  uint public invoiceAmount;
  address serviceProvider;
  constructor(uint _invoiceAmount) public {
    dueDate = block.timestamp + 200;
    invoiceAmount = _invoiceAmount;
    serviceProvider = msg.sender;
  }
...
}

В исходном коде нашего смарт-контракта на Solidity мы сначала создаем экземпляр contract и называем его соответствующим образом SmartInvoice. Концептуально Solidity contract in аналогичен class в объектно-ориентированных языках, таких как JavaScript. Они сохраняют данные через переменные состояния и изменяют эти переменные через функции. В этом contract мы создаем все переменные состояния, которые составляют содержание соглашения между малым бизнесом и клиентом, а также функции, которые будут выполнять условия этого соглашения.

Давайте теперь определим эти переменные состояния и функции. При вызове функций язык Solidity описывает два вида вызовов: внутренние вызовы, известные как «вызовы сообщений», которые не создают вызов к EVM, и внешние вызовы, которые это делают. Из-за этого Solidity определяет четыре типа видимости, которые могут применяться к функциям и переменным состояния: external, public, internal или private. Переменная состояния с public видимостью является частью интерфейса contract и может вызываться либо изнутри, либо через вызовы сообщений. Кроме того, Solidity генерирует функцию автоматического получения public переменных состояния. Поскольку мы хотим, чтобы обе стороны могли видеть дату оплаты счета и сумму, которую необходимо оплатить, мы определяем две переменные состояния, dueDate и invoiceAmount, и даем им видимость public, чтобы интерфейс для этого смарт-контракта мог легко получить их. переменные. Мы определяем эти переменные, используя тип uint, указывающий, что ожидаемый ввод будет целым числом. В дополнение к dueDate и invoiceAmount мы также определяем третью переменную состояния, serviceProvider, которая будет содержать адрес малого бизнеса в цепочке блоков. Во-первых, обратите внимание, что мы не определяем явно видимость для этой переменной. Это связано с тем, что Solidity по умолчанию назначает переменным состояния видимость internal. Отсутствие назначения нашей переменной serviceProvider видимости означает, что к ней можно получить доступ только из текущего смарт-контракта или любых смарт-контрактов, производных от него, и не будет явно доступен для интерфейса для этого смарт-контракта. Во-вторых, обратите внимание, что мы определяем нашу переменную serviceProvider как тип address. Переменная адреса содержит 20-байтовое значение, которое как раз и является размером адреса в цепочке блоков Ethereum, и имеет специальные «члены», которые можно рассматривать как функции и свойства, специфичные для переменных этого типа. Например, мы можем использовать serviceProvider.balance в нашем contract для доступа к балансу счета по этому адресу, где balance - свойство участника.

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

Выполнение платежей в рамках смарт-контрактов

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

Давайте посмотрим, как производить платежи с помощью Solidity.

contract SmartInvoice {
...
  fallback () payable external {
    require(
      msg.value == invoiceAmount,
      'Payment should be the invoiced amount.'
    );
  }
  
  function getContractBalance() public view returns(uint) {
    return address(this).balance;
  }
...
}

Для этого в Solidity мы определяем функцию для сбора платежа от клиента и сохранения его в смарт-контракте. Мы достигаем этого с помощью первой функции в приведенном выше фрагменте кода. Мы рассмотрим значение ключевого слова fallback позже в этом блоге, потому что сначала я хочу обратить ваше внимание на ключевое слово payable. Это ключевое слово известно как «модификатор» в Solidity. Модификаторы можно использовать для легкого изменения поведения функций. В нашем примере мы используем модификатор payable, чтобы указать, что эта функция может получать эфир, форму оплаты, которую мы будем использовать для этого смарт-контракта. Кроме того, мы даем этой функции external видимость, чтобы ее можно было вызывать из других смарт-контрактов и через транзакции. Это означает, что когда мы отправляем транзакцию, содержащую эфир, в наш смарт-контракт, эта функция принимает ее. В рамках определения этой функции мы также можем выполнять операции. Операция, которую мы выполняем, представляет собой базовую проверку того, что платеж, произведенный клиентом малого бизнеса, совпадает с причитающейся суммой. Для этого мы используем функцию require, также известную как «вспомогательная функция», предоставляемая Solidity, которая проверяет наличие условий и генерирует исключение, если условие не выполняется. В нашем примере мы проверяем, что value, отправленное в транзакции, эквивалентно invoiceAmount, установленному при создании экземпляра контракта. Если это условие разрешается до true, тогда наша функция выполняется, но если оно разрешается до false, то транзакция отменяется, и ошибка вместе с пользовательским сообщением, которое мы определили, отправляется в ответ. В этом случае в смарт-контракт не отправляется эфир, а с исполняющей учетной записи взимается плата только за обработку транзакции, поскольку транзакция по-прежнему добавляет новый блок в цепочку блоков с пометкой о том, что транзакция была отменена.

Мы также определяем функцию getContractBalance, которая представляет собой настраиваемую функцию получения, позволяющую всем сторонам видеть текущий баланс, удерживаемый в контракте. Мы определяем эту функцию с помощью ключевого слова view, которое запрещает функции изменять состояние контракта, т.е. мы можем вызывать эту функцию, не платя за газ, необходимый сети Ethereum для обработки ее выполнения. Мы также определяем, что getContractBalance будет возвращать некоторые данные типа uint. В теле функции мы кодируем простой оператор возврата с использованием address(this), чтобы получить ссылку на address этого экземпляра контракта, который, как следует из раздела Создание решения с использованием смарт-контрактов и блокчейна Ethereum раздел выше, дает нам доступ к balance члену, который мы используем для возврата баланса контракта.

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

Получение платежей в рамках смарт-контрактов

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

Давайте посмотрим, как можно получать платежи с помощью Solidity.

contract SmartInvoice {
...
  function withdraw() public {
    require(
      msg.sender == serviceProvider,
      'Only the service provider can withdraw the payment.'
    );
  
  require(
    block.timestamp > dueDate,
    'Due date has not been reached.'
  );
  msg.sender.transfer(address(this).balance);
  }
...
}

Как мы уже делали в разделе Осуществление платежей в смарт-контрактах выше, мы определяем новую функцию, называем ее withdraw и даем public видимость, чтобы она могла получать сообщения, отправленные из API Ethereum, которые мы будем далее в этом блоге. В теле нашей withdraw функции мы используем знакомую require функцию, чтобы установить условия, необходимые для выполнения этой транзакции. Первое условие требует, чтобы сторона, пытающаяся отозвать платеж из контракта, была поставщиком услуги. Мы можем определить, кто пытается использовать переменную msg, предоставленную Solidity, которая представляет собой специальную глобальную переменную, которая содержит свойства, разрешающие доступ к блокчейну. Одно из этих свойств - sender, которое ссылается на адрес, с которого была вызвана функция. Напомним из раздела Создание решения с использованием смарт-контрактов и блокчейна Ethereum выше, что мы сохранили адрес учетной записи владельца малого бизнеса, поэтому для проверки того, что адрес исполнителя функции и адрес этой учетной записи совпадают. Если это не так, транзакция отменяется, и EVM выдаст наше настраиваемое сообщение об ошибке.

Если это первое условие выполнено, мы переходим к следующему условию. Это условие требует, чтобы сторона, пытающаяся отозвать платеж, могла сделать это только после согласованного срока платежа. При выполнении этой функции будет предпринята попытка изменить состояние контракта, то есть перевести средства из смарт-контракта в принимающую учетную запись, и, следовательно, будет создана транзакция, которая будет включена в новый блок в цепочке блоков. Этот блок имеет временную метку, к которой мы можем получить доступ через block.timestamp, которая будет ссылаться на временную метку блока, в который эта транзакция была включена, в секундах с эпохи Unix, то есть время, прошедшее с 00:00:00 UTC 1 января 1970 года. Мы можем затем сравните эту временную метку со сроком выполнения, который мы установили в разделе Создание решения с использованием смарт-контрактов и блокчейна Ethereum выше и сохраненным в переменной dueDate. Если временная метка блока, содержащего транзакцию, меньше установленного срока, транзакция отменяется, и EVM выдаст наше настраиваемое сообщение об ошибке.

Если все вышеперечисленные условия выполнены, мы, наконец, можем перейти к цели нашей withdraw функции. Мы снова используем msg.sender, чтобы получить адрес, с которого была вызвана функция. Затем мы используем метод transfer, предоставленный Solidity, для отправки эфира в единицах wei на этот адрес. Отправленная сумма в этом случае - это баланс смарт-контракта, доступного через address(this).balance, как мы делали в разделе Выполнение платежей в смарт-контрактах выше.

Потрясающие! Теперь наш вымышленный владелец малого бизнеса может установить сумму счета-фактуры и дату платежа в смарт-контракте, наш вымышленный клиент может безопасно оплатить выставленную в счет-фактуру сумму контракту, обе стороны могут наблюдать за балансом контракта, а владелец может отозвать платеж. сумма при наступлении срока. Теперь мы закодировали все компоненты смарт-контракта, которые нам нужны для нашего упрощенного примера. Далее мы посмотрим, как на самом деле выполнить наш смарт-контракт с помощью Ganache и библиотеки web3.js.

Выполнение нашего смарт-контракта

Хорошо, теперь, когда мы написали наш смарт-контракт, нам нужно сделать его исполняемым, поместив в блокчейн. Блокчейн, который мы используем, - это Ganache, персональный блокчейн Ethereum в памяти. Мы также хотим взаимодействовать с нашим смарт-контрактом. Мы сделаем это, запустив локальный сервер Node.js и загрузив библиотеку web3.js, популярный JavaScript API для Ethereum. Я рассмотрел как использовать Ganache и библиотеку web3.js в предыдущем блоге, поэтому не буду вдаваться в подробности здесь. Начнем с установки зависимостей.

$ nvm use 12 && npm install ganache-cli [email protected] web3

Теперь мы можем запустить Ganache и запустить блокчейн на нашем собственном компьютере.

$ node_modules/.bin/ganache-cli
Ganache CLI v6.10.2 (ganache-core: 2.11.3)
Available Accounts
==================
(0) 0x4B33Eb9c62cB022e47Ac3988B8Df17cA34F4E529 (100 ETH)
(1) 0x4af81D2a714C00ee57e251d6c313eC88Cd83057A (100 ETH)
(2) 0xa9f5f1Eb2F9d4229dE9EF04C44673D1CCF6a67a8 (100 ETH)
(3) 0x15220064f048274c48d583098D21D4443837cbE4 (100 ETH)
(4) 0xf5331350AD5dE1d78B7BA08cEA413d6Af488F3ec (100 ETH)
(5) 0x2e7B78f24b31d57aF746ddE4DCF733bCbb419909 (100 ETH)
(6) 0xC3ad48e45f07045EcB8a7E57858fa3bd6e37f05D (100 ETH)
(7) 0x8c76de15e16F59634e07B1eB4D096F75ca349F71 (100 ETH)
(8) 0xe23cd7d5dff67ACdc6b63473A60Bfb2C6d5C9d2c (100 ETH)
(9) 0x847dB651f6A08bc016c6CCb593ba6aE74Bb83D50 (100 ETH)
Private Keys
==================
(0) 0x369a03a1f5e794565f9924e19545094578ad169f4f4f061f91b3c530fc83dab8
(1) 0xc02a84d626a32564578a3826bc752b0e0c142010605390dae5429154bedc6179
(2) 0x502c98cd8d350ab0d369a72d1a658aced668a9f4ce00fde67b3b370187cd831c
(3) 0x0ad9810b20788125723917cd710eca2689fcd5feff7a6cfafe9709ac1a8f59d6
(4) 0x98761dd7911f69ef8aeebe4d5dc9b7fdd085b7987597ecd3dd94cd94f0fd17b8
(5) 0x469a8a89fbadc043db675398a8e63c3462b7a20b5d62343de7ae68c457975363
(6) 0xf45fae0de3462a4875a2fe6ff1892dd30f16ee408145833cc5d6ec75ffa301ee
(7) 0xe6ea6f817ce48f22f584bc0457def99dbc6e77ee571290e765c2f12c1ef23a02
(8) 0xcd6c3ddec9cca1f938efbf2133de07c326194b1d84c6c4c4aae2123fe112168c
(9) 0x2fbfe7d395fc7a4e58740b308ebeac874fe91e286ec861ef9f004e580ae549b4
HD Wallet
==================
Mnemonic: slight famous become exact route monkey bottom fancy time elbow middle candy
Base HD Path: m/44'/60'/0'/0/{account_index}
Gas Price
==================
20000000000
Gas Limit
==================
6721975
Call Gas Limit
==================
9007199254740991
Listening on 127.0.0.1:8545

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

$ node
> const serviceProvider = '0x4B33Eb9c62cB022e47Ac3988B8Df17cA34F4E529'
> const serviceConsumer = '0x4af81D2a714C00ee57e251d6c313eC88Cd83057A'

Мы можем просмотреть детали наших вновь созданных учетных записей, используя библиотеку web3.

> Web3 = require('web3');
> web3 = new Web3('http://127.0.0.1:8545');
> web3.eth.getBalance(serviceProvider).then(console.log);
100000000000000000000
> web3.eth.getBalance(serviceConsumer).then(console.log);
100000000000000000000

Мы видим, что на каждую учетную запись было предварительно загружено 10000000000000000000000 вэй (100 эфиров), поэтому мы готовы приступить к выполнению некоторых транзакций на Ethereum! Наша первая транзакция будет заключаться в развертывании нашего смарт-контракта в блокчейне. В отдельном окне мы используем компилятор solcjs Solidity, который мы установили ранее, для компиляции исходного кода SmartInvoice в файлы .bin и .abi.

node_modules/.bin/solcjs --bin --abi 'SmartInvoice.sol'

Вы заметите, что в вашем проекте появятся два новых файла: файл SmartInvoice_sol_SmartInvoice.abi и файл SmartInvoice_sol_SmartInvoice.bin. Нам нужны оба этих файла для развертывания нашего смарт-контракта в Ethereum.

> abi = JSON.parse(fs.readFileSync('SmartInvoice_sol_SmartInvoice.abi'));
> bytecode = fs.readFileSync('SmartInvoice_sol_SmartInvoice.bin').toString();
> contract = new web3.eth.Contract(abi);
> contract.deploy({data: bytecode, arguments: [50]}).send({ from: serviceProvider, gasPrice: web3.utils.toWei('0.000000098', 'ether'), gas: 1500000}).then((deployedContract) => { contract.options.address = deployedContract.options.address; console.log(deployedContract.options.address);});
0x07F063004f24AC5e0F8691b08Ca3D2f1001F5C5B

Мы выбрали 0,000000098 в качестве gasPrice, потому что, согласно Eth Gas Station, это рекомендованная цена на газ для обработки транзакции по стандартной ставке на момент написания этого блога. В Ganache CLI мы видим следующий вывод:

Transaction: 0xa3fcfebd436854cf851007b7aa881fe2f751ceaa3671c08c0f3f473b50b34771
Contract created: 0x07f063004f24ac5e0f8691b08ca3d2f1001f5c5b
Gas usage: 302988
Block Number: 1
Block Time: Fri Oct 02 2020 14:15:03 GMT-0400 (Eastern Daylight Time)

Сохраним адрес контракта в новой переменной. Нам он понадобится позже в этом блоге.

> const contractAddress = '0x07f063004f24ac5e0f8691b08ca3d2f1001f5c5b'

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

> web3.eth.getBalance(serviceProvider).then(console.log);
99970307176000000000

Эта транзакция стоила 29 692 824 000 000 000 вэй (0,029692824 эфира) для обработки. Мы можем это проверить, потому что 302 988 единиц газа * 0,000000098 Эфира на единицу газа = 0,029692824 Эфира. На момент написания этого блога 1 эфир стоил 344,45 доллара США, что означает, что эта транзакция стоила 10,22 доллара США. Благодаря этой единовременной стоимости наш смарт-контракт теперь существует в блокчейне навсегда, или, по крайней мере, до тех пор, пока мы не решим его изменить.

Наш смарт-контракт развернут на Ethereum, что означает, что мы, наконец, можем вызывать функции контракта, которые мы определили выше! Давайте начнем с проверки начального баланса контракта, вызвав метод getContractBalance, который мы написали, а также неявные функции получения для наших переменных dueDate и invoiceAmount.

> contract.methods.getContractBalance().call(console.log);
null 0
> contract.methods.dueDate().call(console.log);
null 1601662703
> contract.methods.invoiceAmount().call(console.log);
null 50

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

Затем попробуем перевести деньги на смарт-контракт со счета клиента, использующего услугу.

> web3.eth.sendTransaction({from: serviceConsumer, to: contractAddress, value: 10});
(node:57347) UnhandledPromiseRejectionWarning: Error: Returned error: VM Exception while processing transaction: revert Payment should be the invoiced amount.

Мы можем видеть тот же результат, отраженный в интерфейсе командной строки Ganache.

Transaction: 0xf7456725d99cf2a0e5aea5ce93a4647183aa446c1654ec36618db947bbe690d9
Gas usage: 22007
Block Number: 2
Block Time: Fri Oct 02 2020 14:28:59 GMT-0400 (Eastern Daylight Time)
Runtime Error: revert
Revert reason: Payment should be the invoiced amount.

Это иллюстрирует последствия обратного вызова функции.

> web3.eth.getBalance(serviceConsumer).then(console.log);
99999559860000000000

Для обработки этой транзакции со счета клиента было списано 440,140,000,000,000 вэй (0,00044014 эфира). Мы можем это проверить, потому что 22 007 единиц газа * 0,00000002 эфира на единицу газа = 0,00044014 эфира или, по сегодняшнему курсу конвертации, 0,15 доллара США. Для этой транзакции было использовано 0,00000002 эфира на единицу газа, а не 0,000000098 эфира, потому что это цена газа по умолчанию для нашего экземпляра Ganache.

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

> contract.methods.getContractBalance().call(console.log);
null 0

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

> web3.eth.sendTransaction({from: serviceConsumer, to: contractAddress, value: 50});

Мы видим в интерфейсе командной строки Ganache, что эта транзакция прошла успешно!

Transaction: 0xab7ce0222dd7d6398d2eb5de6e222591e6f4777c2683254167eb616903bf2ac3
Gas usage: 21876
Block Number: 3
Block Time: Fri Oct 02 2020 15:36:47 GMT-0400 (Eastern Daylight Time)

Мы можем проверить это, проверив баланс счета клиента.

> web3.eth.getBalance(serviceConsumer).then(console.log);
99999122339999999950

Раньше на счете клиента было 99 999 559 860 000 000 000 вэй (99,99955986 эфира), а теперь 99,999,122 339 999 999 950 вэй (99,99912233999999995 эфир): разница в 437 520 000 000 000 вэй (0,00043752 эфира). В записи транзакции в Ganache CLI мы видим, что для обработки транзакции было использовано 21 876 единиц газа. Таким образом, 21 876 единиц газа * 0,00000002 эфира на единицу газа = 0,00043752 эфира или 0,15 доллара США по сегодняшнему курсу конвертации были переведены со счета клиента в смарт-контракт.

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

> contract.methods.getContractBalance().call(console.log);
null 50

Также проверим, что платеж также не был переведен на счет малого бизнеса.

> web3.eth.getBalance(serviceProvider).then(console.log);
99970307176000000000

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

> const randomAccount = '0xa9f5f1Eb2F9d4229dE9EF04C44673D1CCF6a67a8'
> contract.methods.withdraw().send({from: randomAccount});
(node:57347) UnhandledPromiseRejectionWarning: Error: Returned error: VM Exception while processing transaction: revert Only the service provider can withdraw the payment.

Мы видим в интерфейсе командной строки Ganache, что эта транзакция не была успешной.

Transaction: 0x187ee6a3c2928c4428fe40095fb6bf9bca39f430e34ae274b256071c4ac9f4bb
Gas usage: 22185
Block Number: 4
Block Time: Fri Oct 02 2020 17:32:27 GMT-0400 (Eastern Daylight Time)
Runtime Error: revert
Revert reason: Only the service provider can withdraw the payment.

Мы можем проверить это, проверив, что предыдущий платеж остался на балансе контракта.

> contract.methods.getContractBalance().call(console.log);
null 50

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

> contract.methods.withdraw().send({from: serviceProvider});

Мы видим в интерфейсе командной строки Ganache, что эта транзакция прошла успешно!

Transaction: 0x50b0f6b683d711e9e033b71bae5c1f0789133c799249d3629a1e256d70f156ce
Gas usage: 30401
Block Number: 5
Block Time: Fri Oct 02 2020 17:37:04 GMT-0400 (Eastern Daylight Time)

Мы можем проверить это, проверив баланс счета малого бизнеса.

> web3.eth.getBalance(serviceProvider).then(console.log);
99969699156000000050

Вуаля! Мы видим, что 50 вэй были добавлены на баланс аккаунта. На счету по-прежнему было списано 30 401 единица газа * 0,00000002 эфира за единицу газа = 0,00060802 эфира для обработки транзакции перевода средств со смарт-контракта на их счет. В качестве дополнительной проверки мы можем проверить, что баланс смарт-контракта был снят.

> contract.methods.getContractBalance().call(console.log);
null 0

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

Как смарт-контракты и блокчейн помогают малому бизнесу?

Выставление счетов стало проще. Выставление счетов сегодня - это трудоемкий и обременительный процесс. По данным Business Wire, владельцы малого бизнеса тратят 3,5 часа в месяц на создание, отправку и проверку счетов, и иногда допускаются ошибки, которые способствуют просрочке платежей. Forbes приводит несколько распространенных ошибок при выставлении счетов, многие из которых можно исправить, если не устранить, с помощью смарт-контрактов и блокчейна. Первая ошибка - это забыть отправить счет или не следить за неоплаченными счетами. Одной из замечательных особенностей смарт-контрактов является то, что они могут взаимодействовать с другими смарт-контрактами. Владелец малого бизнеса может включить наш простой SmartInvoice контракт в качестве компонента родительского смарт-контракта, такого как контракт купли-продажи или контракт на оказание услуг. Таким образом, счет-фактура уже существует, как только начинается работа. Смарт-контракты также позволяют автоматизировать задачи, включая создание экземпляра контракта и последующие действия. Вторая распространенная ошибка при выставлении счетов - это неверные реквизиты или использование нечетких условий оплаты. Например, счет-фактура может быть отправлен не тому клиенту или в неправильный отдел, или в нем может использоваться «чистая 30», чтобы указать, что полная оплата должна быть произведена в течение 30 дней, что может быть незнакомой терминологии для клиента. Эти проблемы устраняются, поскольку условия и детали смарт-контракта, такие как сумма счета-фактуры и срок платежа, четко прописаны в контракте и доступны на неопределенный срок в блокчейне, так что ни одна из сторон не может их оспорить. Кроме того, смарт-контракт привязан как к счетам владельца, так и к счетам клиента, а перевод платежа осуществляется напрямую между ними, что делает использование физических адресов устаревшим. Наконец, даже если счет-фактура отправлен, получен правильным контактным лицом и активно отслеживается, платежи все равно могут задерживаться, если владельцы малого бизнеса забывают отслеживать свои счета и резервировать их. По своей сути блокчейн - это технология распределенного реестра, в которой данные реплицируются в сети независимых компьютеров. Смарт-контракты и блокчейн Ethereum используют это для записи всех транзакций с помощью смарт-контракта, предоставляя как поставщику услуг, так и потребителю услуг простой цифровой доступ к деталям их смарт-контрактов и делая потерю данных крайне маловероятной.

Транзакции в блокчейне обходятся владельцам малого бизнеса меньше, чем текущие формы оплаты, поскольку размер транзакции увеличивается. Согласно опросу Quickbooks из раздела Малые предприятия не могут своевременно собирать платежи, 38% клиентов малого бизнеса предпочитают платить дебетовой или кредитной картой, что делает их второй наиболее предпочтительной формой оплаты. ; денежные средства были первыми на 58%. По оценкам Square на момент написания этого блога, американские компании платят от 2,87% до 4,35% комиссии за обработку кредитной карты за транзакцию. По мере увеличения размера платежа эта комиссия существенно увеличивается, например Счет-фактура на сумму 1000,00 долларов США обойдется компании в сумму от 28,70 до 43,50 долларов США в качестве платы за обработку. Этот сбор фактически является кульминацией индивидуальных сборов, взимаемых центральными органами, то есть эмитентом карты, сетью карт и платежным оператором, для обработки транзакции и покрытия их рисков, таких как одобрение продажи и мошенничества. Таким образом, неудивительно, что по мере увеличения размера платежа и, следовательно, риска покрытия платежа увеличивается комиссия за обработку этой транзакции. В блокчейне вместо колеблющейся платы за обработку, определяемой некоторыми центральными органами и в зависимости от размера платежа, плата за обработку выплачивается сети узлов, которые обрабатывают транзакцию, где, поскольку сеть блокчейна проверяет каждую транзакцию как часть общая бухгалтерская книга, транзакции менее подвержены мошенничеству и менее рискованны. Хотя эта плата за обработку может варьироваться в зависимости от сетевого трафика, она часто меньше суммы, которую взимает обработчик кредитной карты, и зависит от объема работы, которую необходимо выполнить, а не от размера платежа. Например, как мы видели в разделе Выполнение нашего смарт-контракта выше, выполнение нашего смарт-контракта стоило 10,22 доллара США, что является той же ценой, которую владелец малого бизнеса заплатил бы, если бы размер платежа составлял 1000 долларов США. Долларов США или 10 000 долларов США. Помимо платы за обработку, существуют другие комиссии, которые взимаются за стандартные транзакции, то есть комиссии за зарубежные транзакции, которые становятся неактуальными, когда транзакция происходит в блокчейне, таком как Ethereum.

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

И снова о чем мы говорили?

Как мы узнали в начале этого блога, быстрый и точный сбор платежей является основной проблемой для самозанятых работников и владельцев малого бизнеса. Когда оплата не поступает вовремя, малые предприятия не могут оплачивать собственные расходы, не в последнюю очередь на оплату труда своих сотрудников и самих себя. Это делает просрочку платежей ведущим фактором, способствующим банкротству 50% малых предприятий в течение пяти лет. Владельцы этих предприятий - наши друзья и соседи; особенно те из нас, кому посчастливилось называть Нью-Йорк своим домом. Согласно статье в Small Business Trends, опубликованной в 2019 году, в Нью-Йорке проживает большинство владельцев малого бизнеса с общим количеством 411 тыс., Что даже больше, чем совокупное количество занявших второе место Лос-Анджелеса с 243 тыс., Сан-Франциско с 84 тыс. и Бостон - 81 тыс. владельцев малого бизнеса. Хотя владельцы малого бизнеса составляют меньшинство по сравнению с работающим населением, данные показывают, что большинство из нас действительно хочет того, на что эти люди были достаточно смелы. Фактически, согласно опросу, проведенному Организацией экономического сотрудничества и развития в 2015 году, 69% / 62% взрослых мужчин и 58% / 52% взрослых женщин в Соединенных Штатах и ​​Канаде соответственно хотят строить свои собственные дома. предприятия. Хотя это представляет собой очевидную экономическую возможность, можно также привести убедительный аргумент в пользу гуманитарных наук для поиска решений проблем, которые препятствуют достижению мечты, столь общей для наших собратьев.

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

И все начинается с предоставления владельцам малого бизнеса возможности собирать платежи в срок!

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

Об авторе

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

В свободное время Колина можно найти, проверяя комплект лагеря REI на выходные в лесу, тестируя новейшие HOKA, охотясь на свежую пороху на горе или просматривая раздел ужасов на Netflix.

Связаться с Колином - https://www.linkedin.com/in/colinkraczkowsky