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

Владельцам малого бизнеса, от индивидуальных предпринимателей до индивидуальных предпринимателей, сложно получить внешнее финансирование: от ссуд на развитие своего бизнеса до ипотеки на покупку дома. Причиной этой потребности во внешнем финансировании является тот факт, что малому бизнесу требуется в среднем два-три года, чтобы получить прибыль. Опрос владельцев малого бизнеса, проведенный Национальной федерацией независимого бизнеса (NFIB) в сентябре 2020 года, показал, что 1% владельцев малого бизнеса сообщают, что внешнее финансирование является их основной бизнес-проблемой с 2% респондентами. что их последний заем получить труднее, чем раньше. Инвестиционная компания Biz2Credit подтверждает это сообщение о том, что крупные банки предоставили только 13,6% заявок на получение кредитов в августе 2020 года по сравнению с 13,8% в июле.

Во второй половине 2018 года в рамках Обзора кредитования малого бизнеса, проводимого в рамках национального сотрудничества 12 федеральных резервных банков, был проведен опрос 6614 владельцев малого бизнеса с целью сбора данных для лучшего понимания их финансовых потребностей; результаты были опубликованы в Отчете о компаниях-работодателях за 2019 год. Согласно этому отчету, в том году заявки на внешнее финансирование подавали 43% респондентов. Причина? Большинство респондентов искали внешнее финансирование для расширения своего бизнеса за счет использования новых возможностей или приобретения бизнес-активов и / или для покрытия операционных расходов. Большинство владельцев малого бизнеса регулярно используют ссуды и кредитные линии в качестве источника внешнего финансирования, поэтому неудивительно, что 85% респондентов, обратившихся за внешним финансированием, обратились за ссудой или кредитной линией.

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

При поиске ссуды или кредитной линии у владельцев малого бизнеса есть несколько вариантов как для типа финансирования, так и для кредитора, предоставляющего это финансирование. Самым популярным типом внешнего финансирования, которым пользовались владельцы малого бизнеса, были бизнес-ссуды, за которыми следовали бизнес-линии, за которыми следовали ссуды / кредитные линии SBA. Что касается кредиторов, согласно Отчету о фирмах-работодателях за 2019 год, 49% владельцев малого бизнеса подали заявки в крупный банк, 44% - в малый банк и 32% - к онлайн-кредитору. В среднем объем финансирования в денежном выражении, который ищут малые предприятия, относительно невелик. По данным Raddon, дочерней компании Fiserv, занимающейся финансовыми исследованиями и анализом, 95% малых предприятий ищут ссуды на сумму менее 250 000 долларов, а средняя запрашиваемая сумма ссуды составляет 75 000 долларов. Тем не менее, несмотря на высокий спрос на бизнес-ссуды и малый объем запрашиваемого финансирования, только 67% заявок были одобрены. Владельцам малого бизнеса больше повезло с бизнес-линиями, где было одобрено 73% заявок, и еще хуже - с ссудами / кредитными линиями SBA с показателем принятия только 52%. В целом, в отчете о фирмах работодателей за 2019 год обнаружено, что только 47% респондентов, подавших заявку на внешнее финансирование, получили всю запрашиваемую сумму.

Почему более половины владельцев малого бизнеса, ищущих финансирование, столкнулись с дефицитом, то есть получили меньше средств, чем искали. Можно сначала поискать ответы у кредиторов. Можно обнаружить, что в целом большинство банков, особенно крупные, сократили свою кредитную деятельность для малого бизнеса с 2006 года. Согласно отчету за 2018 год Каким образом банковское кредитование малого бизнеса в Соединенных Штатах прошло после финансового кризиса? , опубликованное Управлением по делам малого бизнеса США, кредитование малого бизнеса банками росло на 5% в год с 2009–2011 гг., прежде чем рост упал до менее 4% в год с 2012–2015 гг..

После тщательного изучения кредиторов можно было искать ответы в процессе получения ссуды. По мнению отраслевых экспертов из The Balance Small Business, Fundbox и Entrepreneur, общие причины отклонения кредитных заявок от владельцев малого бизнеса включают недостаточный залог или отсутствие нужного типа залога, низкий кредитный рейтинг или отсутствие кредитной истории, а также наличие большого количества кредитов. задолженность и недостаточный денежный поток. Согласно Отчету о фирмах работодателей за 2019 год, это также одни из тех же причин, по которым владельцы малого бизнеса не получили все необходимое финансирование.

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

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

Даже с учетом тех, кто не испытывал дефицита, большинство владельцев малого бизнеса, подавших заявки на финансирование в крупные банки и онлайн-кредиторы, сообщали о проблемах в процессе. Для крупных банков наибольшими проблемами, о которых сообщалось, были долгое ожидание решения и сложность процесса подачи заявки. Согласно опросу, проведенному в 2019 году среди 1000 владельцев малого бизнеса и опубликованному в Small Business Trends, 16,3% респондентов ответили, что ждали не менее месяца, чтобы получить ответ о заявке на кредит, а 7,5% ответили, что ожидали более шести месяцев. Для онлайн-кредиторов самой большой проблемой, о которой сообщалось, были высокие процентные ставки. Согласно Nav, для традиционной банковской ссуды годовая процентная ставка по традиционной банковской ссуде составляет от 2% до 13%, в то время как ставка по ссуде от онлайн-кредитора может варьироваться от 7% до 100%.

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

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

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

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

Блокчейн обеспечивает прозрачность. Основным фактором проблем с традиционным процессом кредитования является асимметрия информации. Банки не хотят одобрять ссуду от заявителя, с которым у них нет прежних отношений и в отношении которого они не могут быть уверены в том, что он выплатит ссуду. Блокчейн помогает установить это доверие или, с некоторых точек зрения, полностью устраняет эту потребность в доверии. Одним из основных компонентов блокчейна является «технология распределенного реестра», которая позволяет всем компьютерам в сети блокчейнов иметь одну и ту же копию всех транзакций, которые происходят в этой цепочке блоков, где они отдельно проверяются и защищены механизмом консенсуса. Это гарантирует, что все транзакции неизменны, и любое изменение данных в цепочке блоков документируется. Каждая транзакция имеет отметку времени и включает зашифрованную подпись исполнителя транзакции, которую могут видеть все участники цепочки блоков. Для кредитных рынков это обеспечивает симметрию информации между заемщиками и кредиторами. Заемщики могут быть уверены в том, что финансирование, которое они получают, не подвергнется риску аннулирования, поскольку средства уже были потрачены несколько раз. Кредиторы могут видеть историю транзакций заемщиков, чтобы оценить вероятность их погашения.

Блокчейн не имеет границ. Это значительно расширяет возможности блокчейна. Для кредитных рынков текущая фиатная система создает проблемы для получения кредита. Одна из проблем - временная сложность. Чтобы перевести деньги со счета кредитора на счет заемщика, требуется время. По оценкам многих источников, телеграмма может доставить от одного до пяти рабочих дней. Первый шаг - инициировать международный банковский перевод, после чего средства будут списаны со счета отправителя. Затем инструкции по переводу обычно передаются через сеть Общества всемирных межбанковских финансовых телекоммуникаций (SWIFT), сеть из более чем 10 000 банков и финансовых учреждений в более чем 200 странах, проходя через различные банки-посредники, прежде чем окончательно попасть в банк получателя, который затем имеет свои собственные задержки обработки. Часто эта обработка выполняется во избежание мошеннических транзакций; обратитесь к параграфу выше, чтобы узнать, как блокчейн может снизить риск мошенничества. Как только эти деньги поступят на счет получателя, скорее всего, потребуется дальнейшая обработка путем обмена на местную валюту получателя. Это также требует времени и обычно требует комиссии по текущему обменному курсу. Ситуация усугубляется тем, что разные страны предлагают разные процентные ставки по кредитам. По данным Всемирного банка, средняя процентная ставка по кредиту в 2019 году составила 19,82% в Украине, 67,26% в Аргентине, 9,56% в Бангладеш и 5,28% в США. Блокчейн открывает возможность любому человеку во всем мире получить ссуду в разумные сроки под глобальную процентную ставку, и любой желающий может внести свой вклад.

Теперь, когда мы выработали общее понимание некоторых способов, которыми блокчейн может улучшить процесс кредитования, давайте приступим к созданию чего-то на блокчейне! Мы создадим решения для блокчейна Ethereum, где сможем развертывать смарт-контракты. Смарт-контракты будут написаны на языке программирования Solidity. Мы не будем развертывать производственный блокчейн Ethereum. Вместо этого мы развернем Ganache, который создал экземпляр блока Ethereum на нашей локальной машине. Решение, которое мы создадим, позволит заемщику опубликовать запрос на ссуду, обеспеченную залогом в виде криптоактивов. Затем любой кредитор может просмотреть этот запрос и выбрать его финансирование. Тогда заемщик получит доступ к этому финансированию, и кредитору в конечном итоге будет выплачена сумма, обещанная заемщиком. Для этого мы создадим два смарт-контракта: один для представления запроса на ссуду, который будет получать финансирование и распределять доход, а второй - для представления обеспечения, поддерживающего запрос на ссуду.

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

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

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

$ mkdir smb-loan-platform-ethereum
$ cd smb-loan-platform-ethereum/
$ echo “{ \”name\”: \”smb-loan-platform-ethereum\”, \”version\”: \”1.0.0\”, \”description\”: \”A decentralized application (dapp) containing a smart contract deployed to the Ethereum blockchain via Alchemy.\” }” >> package.json
$ touch LoanPlatform.sol

Файл LoanPlatform.sol будет содержать два смарт-контракта, которые мы создаем в этом блоге.

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

contract SmartLoan {
  uint public loanAmount;
  uint public payableAmount;
  uint public timePeriod;
  address payable public borrower;
  uint public contractStart;
  
  constructor(uint _loanAmount, uint _payableAmount, uint _timePeriod) public {
    loanAmount = _loanAmount;
    payableAmount = _payableAmount;
    timePeriod = _timePeriod;
    contractStart = 0;
    borrower = msg.sender;
  }
...
}

contract - это особая концепция в Solidity, которая действует аналогично class в объектно-ориентированном языке программирования, таком как JavaScript. Как и class, конструкция является первым этапом жизненного цикла contract и также содержит функцию constructor. Мы используем эту функцию для инициализации переменных, которые мы определили ранее в контракте. После создания нового экземпляра SmartLoan смарт-контракт ожидает получить loanAmount, payableAmount и timePeriod, которые должны быть выражены в месяцах. Мы создаем переменную для представления начала контракта и инициализируем ее значением 0, поскольку мы не хотим, чтобы часы запускались, пока кредитор не отправит запрашиваемую сумму кредита в контракт. Наконец, мы получаем адрес человека, инициирующего смарт-контракт. Затем эти переменные сохраняются смарт-контрактом в public переменных, доступных через блокчейн Ethereum, чтобы их могли видеть все стороны.

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

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

contract BorrowerCollateral {
  uint public collateralAmount;
  SmartLoan public loan;
  fallback() payable external {
    collateralAmount = msg.value;
  }
  function withdrawCollateral(address payable loanAddress) external {
    loan = SmartLoan(loanAddress);
    if(loan.contractStart() == 0){
      require(
        msg.sender == loan.borrower(),
        ‘REVERT: Only the borrower can withdraw the collateral before the contract starts!’
      );
      collateralAmount = 0;
      msg.sender.transfer(address(this).balance);
    } else if(block.timestamp < loan.contractEnd()){
      require(
        loan.amountPaid() == true,
        ‘REVERT: Collateral can\’t be withdrawn until the payment is made!’
      );
      require(
        msg.sender == loan.borrower(),
        ‘REVERT: Only the borrower can withdraw the collateral before the contract ends!’
      );
      collateralAmount = 0;
      msg.sender.transfer(address(this).balance);
    } else {
      require(
        msg.sender == loan.lender(),
        ‘Payment is late; collateral forfeited to lender.’
      );
      collateralAmount = 0;
      msg.sender.transfer(address(this).balance);
    }
  }
}

В нашем BorrowerCollateral смарт-контракте мы используем fallback() payable механизм Solidity для сбора любых платежей, произведенных на адрес этого контракта. Затем мы определяем функцию withdrawCollateral для хранения довольно сложной логики того, как этот смарт-контракт будет обрабатывать снятие средств. Эта функция ожидает, что ей будет предоставлен адрес экземпляра смарт-контракта SmartLoan, который мы будем использовать для ссылки на этот contract. Первый пункт в нашем if заявлении предназначен для выполнения требования о том, что только заемщик может снять обеспечение до начала контракта. Для этого мы используем ссылку на переменную contractStart в нашем экземпляре SmartLoan, который, как следует из вышесказанного, инициализируется значением 0 при создании смарт-контракта, но до того, как он получит финансирование. В этом случае попытка отозвать залог кем-либо, кроме borrower, будет отменена виртуальной машиной Ethereum (EVM). Следующий пункт касается требования, согласно которому обеспечение может быть отозвано только borrower либо после завершения контракта, либо после выплаты обещанной суммы. Для этого мы сравниваем временную метку текущего блока с окончанием срока ссуды, который мы получаем от SmartLoan. Любые попытки снять залог в этом случае будут сначала отменены, если ссуда еще не выплачена, транзакция будет отменена, а во-вторых, если запрос будет сделан кем-либо, кроме borrower. Если платеж был произведен, borrower сможет снять всю сумму, хранящуюся в смарт-контракте, используя метод transfer, предоставленный Solidity, для отправки эфира в единицах wei на вызывающий адрес. Заявление else представляет собой наше последнее положение для обработки требования о том, что если заемщик не выполняет свои обязательства по ссуде, то есть не платит кредитору сумму, обещанную к концу контракта, то залог переходит к lender. Мы достигаем этого, возвращая все вызовы нашей withdrawCollateral функции, если они не сделаны кредитором, который мы получаем от SmartLoan. Затем заемщик проводит BorrowerCollateral и переводит сумму залога на вновь созданный адрес.

После внесения залога заемщик добавляет залог к ​​своей ссуде, чтобы вся информация содержалась в ссуде.

contract SmartLoan {
  BorrowerCollateral public collateral;
  uint public collateralAmount;
...
  function addCollateral(address payable collateralAddress) public returns(uint) {
    collateral = BorrowerCollateral(collateralAddress);
    collateralAmount = collateral.collateralAmount();
  }
...
}

Для этого мы добавляем новую addCollateral функцию к SmartLoan, которая принимает адрес в качестве параметра. Этот адрес должен быть адресом экземпляра BorrowerCollateral, который мы создали выше. Затем мы создаем новую переменную типа BorrowerCollateral, передавая ей собранный адрес, чтобы дать нам ссылку на этот конкретный экземпляр. Наконец, мы используем эту ссылку, чтобы получить значение залога и сохранить его в SmartLoan как новую переменную collateralAmount.

Получение финансирования для нашего кредита на блокчейне Ethereum

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

contract SmartLoan {
  uint public contractEnd;
...
  fallback() payable external {
    require(
      msg.value == loanAmount,
      ‘REVERT: Contribution should be the requested amount.’
    );
    lender = msg.sender;
    contractStart = block.timestamp;
    uint timePeriodUnix = timePeriod * 60 * 60 * 24 * 30;
    contractEnd = contractStart + timePeriodUnix;
  }
...
}

Снова мы используем механизм fallback() payable Solidity, чтобы получить платеж от кредитора. В первой строке этой функции мы вставляем require функцию, также известную как «вспомогательная функция», предоставляемая Solidity, чтобы утверждать, что платеж, произведенный кредитором, равен сумме, запрошенной ссудой. В противном случае транзакция будет отменена. Затем мы фиксируем адрес lender и сохраняем его в переменной кредитора для дальнейшего использования. Мы также запускаем часы по кредиту теперь, когда он получил финансирование. Поскольку платеж от lender добавит новый блок в цепочку блоков, мы можем получить доступ и сохранить метку времени этого блока, используя block.timestamp, который будет ссылаться на метку времени блока, в который эта транзакция была включена, в секундах с эпохи Unix, т. Е. Время истекло с 00:00:00 UTC 1 января 1970 г. Это будет означать начало контракта. Теперь нам нужно рассчитать срок окончания контракта. Вспомните в разделе Создание смарт-контракта на блокчейне Ethereum для представления запроса на ссуду, что мы определили timePeriod как часть построения этого смарт-контракта для хранения продолжительности ссуды в месяцах. Поскольку block.timestamp возвращается в секундах, мы выполняем простой расчет, чтобы определить contractEnd как функцию от timePeriod после этой временной метки. В этом простом примере мы предполагаем, что в месяц есть стандартные 30 дней. Теперь lender, contractStart и contractEnd сохраняются смарт-контрактом в public переменных, доступных через блокчейн Ethereum для всеобщего обозрения.

Управление жизненным циклом ссуды

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

contract SmartLoan {
  bool public loanAmountWithdrawn = false;
  bool public amountPaid = false;
...
  function withdrawLoanAmount() payable external {
    if(!loanAmountWithdrawn) {
      require(
        msg.sender == borrower,
        ‘REVERT: Only the borrower can withdraw the loan amount!’
    );
      msg.sender.transfer(loanAmount);
      loanAmountWithdrawn = true;
    } else {
      revert(‘REVERT: Loan amount already withdrawn!’);
    };
  }
  
  function makeBorrowerPayment() payable external {
    require(
      msg.value == payableAmount,
      ‘REVERT: The payment should be the total amount payable!’
    );
    borrowerPayment = msg.value;
    amountPaid = true;
  }
  function withdrawBorrowerPayment() external {
    require(
      lender != address(0),
      ‘REVERT: Contract has not started, lender does not exist!’
    );
    require(
      msg.sender == lender,
     ‘REVERT: Only the lender can withdraw the payment!’
    );
    msg.sender.transfer(borrowerPayment);
  }
...
}

Сначала мы даем возможность заемщику отозвать финансирование, добавив функцию withdrawLoanAmount. Это должно произойти только один раз, поэтому мы создаем переменную loanAmountWithdrawn типа bool, чтобы проверить это. Если финансирование еще не было отозвано, мы проверяем, поступает ли запрос на перевод от borrower. Вспомните из раздела Создание смарт-контракта на блокчейне Ethereum для представления запроса на ссуду выше, что мы сохранили ссылку на адрес заемщика при создании смарт-контракта, который мы используем для выполнения этой проверки. . После выполнения этих требований стоимость смарт-контракта затем перемещается на запрашивающий адрес с использованием метода transfer, предоставленного Solidity для отправки эфира, в единицах wei, а для withdrawLoanAmount устанавливается значение true, чтобы указать, что финансирование было отозвано.

Затем мы разрешаем заемщику произвести платеж по ссуде, добавив функцию makeBorrowerPayment. Для целей этого простого примера мы требуем, чтобы оплата была полной суммой, обещанной при создании смарт-контракта. Функция makeBorrowerPayment относится к типу payable, что делает ее доступной для приема транзакций. Я предоставляю больше информации о различных типах функций в Solidity в отдельном блоге, но, по сути, любые вызовы функции этого типа должны содержать значение, к которому мы можем получить доступ через msg.value и сохранить. После выполнения нашей makeBorrowerPayment функции SmartLoan теперь также будет содержать значение платежа, произведенного заемщиком. Мы сохраняем признание этого платежа во вновь добавленной переменной amountPaid. Обновление переменной amountPaid также разблокирует обеспечение в нашем BorrowerCollateral контракте, так что стоимость может быть востребована заемщиком.

contract BorrowerCollateral {
...
  require(
    loan.amountPaid() == true,
    ‘REVERT: Collateral can\’t be withdrawn until the payment is made!’
  );
...
}

Наконец, мы позволяем кредитору отозвать платеж по ссуде, добавив функцию withdrawBorrowerPayment. Поскольку наш смарт-контракт может существовать без получения какого-либо финансирования, мы сначала проверяем, действительно ли кредит начался. Мы делаем это, проверяя, что lender имеет фактический адрес, который указывает на то, что ссуда была профинансирована. Далее мы проверяем, что только lender может снять платеж. Как только они оба будут удовлетворены, мы инициируем перевод. Поскольку кредитор имеет право только на оплату, обещанную заемщиком, мы предоставляем borrowerPayment в качестве дополнения к функции transfer, так что будет переведена только эта сумма.

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

Развертывание нашего решения в блокчейне Ethereum

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

Начнем с установки зависимостей.

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

В окне терминала запустим Ganache CLI, чтобы посмотреть, что было установлено.

$ node_modules/.bin/ganache-cli
Ganache CLI v6.12.0 (ganache-core: 2.13.0)
Available Accounts
==================
(0) 0x19c22F9e151FAF0331cfc335DBc9d383EA6308F8 (100 ETH)
(1) 0x92cfe0156f08c1516aad3B38a0c03009E8e0166A (100 ETH)
(2) 0xeb5632df88440bE37bb07411ad1f31db837Aaf3d (100 ETH)(3) 0x386BeF8dfa26457077387Afb383e6765d1179779 (100 ETH)
(4) 0x719ff317a2796845F1202bf376e030E64cCA7464 (100 ETH)
(5) 0x1344990B4eE941e13224e2a3a806410EF5ec07Df (100 ETH)
(6) 0x5F4400D5967D2A24F46e9cd940085bA8f9e498E9 (100 ETH)
(7) 0xd9Bc118b5d7Cb8499ab05c74B4Ff58e53E86b419 (100 ETH)
(8) 0xC3d79097A32847e288497a767D19A247cEDb8277 (100 ETH)
(9) 0x8E72f2B921499e9A2d72Ba4CB007D62F50E24F78 (100 ETH)
Private Keys
==================
(0) 0x82ed56f35339d84a6c1f76dd84d4aa96fd9b5b729e8f13bf38a0288814c0d468
(1) 0x955e5adafe5a8132cb62206fec6414e4bb3ff0036e694afa30b4a9a50d04b128
(2) 0xb6b190249a26eea360006f2ba1b8e9523619d3ecc2bbac7217fa8bfe995bbff5
(3) 0xb4bbf216bd5981396d2cd10373aa4178fe1da66ec09f0ef06f746650951b2a93
(4) 0xb1257c40ef93fbfdaed6e51e061e1218630a58f7133259ba0b11329b6d1a2ce6
(5) 0x5435819e7797cbd7878026e04a883dca74630437e2a10b81c58315b79e3968ee
(6) 0xfabec80f35628de6fafb7e50700e319e1a020c92767a64e28f5fe65815917b6c
(7) 0x33da8361353f9b5624fffd8dfdd072c55708db7cb591f3448288dca9bae37fe8
(8) 0x683932c9b2576dd5ca9f685f4cf6f6f824044542955a5f11ca36956d5c55f06e
(9) 0x26ed5fc87d3de8f073c16abf2d99cfc06a963e7ac44a551d8f7acd40f509a7ab
HD Wallet
==================
Mnemonic: bamboo myself slender rally net cart firm crisp transfer organ impact spell
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 borrower = ‘0x19c22F9e151FAF0331cfc335DBc9d383EA6308F8’;
> const lender = ‘0x92cfe0156f08c1516aad3B38a0c03009E8e0166A’;

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

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

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

$ node_modules/.bin/solcjs — bin — abi ‘LoanPlatform.sol’

Вы заметите, что в вашем проекте появятся четыре новых файла: файл LoanPlatform_sol_BorrowerCollateral.abi, файл LoanPlatform_sol_BorrowerCollateral.bin, файл LoanPlatform_sol_SmartLoan.abi и файл LoanPlatform_sol_SmartLoan.bin. Все эти файлы нужны нам для развертывания наших смарт-контрактов в Ethereum. Сначала мы развертываем SmartLoan контракт со счета заемщика. В этом примере ссуды будет запрашиваться 2000 вэй и обещаться 2200 вэй взамен по прошествии 4 месяцев.

> abi1 = JSON.parse(fs.readFileSync(‘LoanPlatform_sol_SmartLoan.abi’));
> bytecode1 = fs.readFileSync(‘LoanPlatform_sol_SmartLoan.bin’).toString();
> contract1 = new web3.eth.Contract(abi1);
> contract1.deploy({data: bytecode1, arguments:[2000, 2200, 4]}).send({ from:borrower, gasPrice: web3.utils.toWei(‘0.000000098’, ‘ether’), gas: 1500000}).then((deployedContract) => { contract1.options.address = deployedContract.options.address; console.log(deployedContract.options.address);});
0x514F5F8b7c7e7B89c3313F287A2B659a2CDd227b

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

Transaction: 0xd164e1cab2e58a1f4e88c809b793de8c85f970e46707053be869c965e7399a6d
Contract created: 0x514f5f8b7c7e7b89c3313f287a2b659a2cdd227b
Gas usage: 797662
Block Number: 1
Block Time: Tue Dec 01 2020 10:51:51 GMT-0500 (Eastern Standard Time)

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

> const loanContractAddress = ‘0x514f5f8b7c7e7b89c3313f287a2b659a2cdd227b’;

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

> web3.eth.getBalance(borrower).then(console.log);
99921829124000000000

Эта транзакция стоила 78 170 876 000 000 000 вэй (0,078170876 эфира) для обработки. Мы можем это проверить, потому что 797 662 единицы газа * 0,000000098 Эфира на единицу газа = 0,078170876 Эфира. На момент написания этого блога 1 эфир стоил 590,67 долларов США, что означает, что эта транзакция стоила 46,17 долларов США. Благодаря этой единовременной стоимости наш смарт-контракт теперь существует в цепочке блоков навсегда или, по крайней мере, до тех пор, пока мы не решим его изменить.

Затем мы развертываем BorrowerCollateral контракт.

> abi2 = JSON.parse(fs.readFileSync(‘LoanPlatform_sol_BorrowerCollateral.abi’));
> bytecode2 = fs.readFileSync(‘LoanPlatform_sol_BorrowerCollateral.bin’).toString();
> contract2 = new web3.eth.Contract(abi2);
> contract2.deploy({data: bytecode2}).send({ from:borrower, gasPrice: web3.utils.toWei(‘0.000000098’, ‘ether’), gas: 1500000}).then((deployedContract) => { contract2.options.address = deployedContract.options.address; console.log(deployedContract.options.address);});
0x4d10a38B219CF4449Cc5d83C45caFF57Abb62c9D

Эта транзакция добавляет новый блок в нашу цепочку блоков Ethereuem.

Transaction: 0x22b53cbee238e141781b8efc3f7e5fdce356c87987c76d3d4a3cec47596dd1d1
Contract created: 0x4d10a38b219cf4449cc5d83c45caff57abb62c9d
Gas usage: 497049
Block Number: 2
Block Time: Tue Dec 01 2020 11:06:38 GMT-0500 (Eastern Standard Time)

Сохраним и адрес этого контракта.

> const collateralContractAddress = ‘0x100Ac3e452f756b20C112275d78EAB7eCf144636’;

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

Тестирование нашего решения с помощью Ganache

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

Тестовый пример. Наш BorrowerCollateral смарт-контракт может принимать переводы.

> web3.eth.sendTransaction({
  from: borrower,
  to: collateralContractAddress,
  value: 500
  });
> web3.eth.getBalance(collateralContractAddress).then(console.log);
500

Тестовый пример: если кредит еще не начался, только заемщик должен иметь возможность снять средства, хранящиеся в нашем BorrowerCollateral смарт-контракте.

> contract1.methods.contractStart().call(console.log);
null 0
> contract2.methods.withdrawCollateral(loanContractAddress).send({from:lender});
(node:38831) UnhandledPromiseRejectionWarning: Error: Returned error: VM Exception while processing transaction: revert REVERT: Only the borrower can withdraw the collateral before the contract starts!
> contract2.methods.withdrawCollateral(loanContractAddress).send({from:borrower});
> web3.eth.getBalance(collateralContractAddress).then(console.log);
0

Тестовый пример. Обеспечение может быть добавлено к нашему SmartLoan смарт-контракту.

> contract1.methods.addCollateral(collateralContractAddress).send({from:borrower});
> contract1.methods.collateralAmount().call(console.log);
null 500

Тестовый пример: Наш SmartLoan смарт-контракт может получать переводы только в сумме, определенной при развертывании контракта. При получении в контракте должны быть проставлены штампы времени начала и окончания.

> contract1.methods.loanAmount().call(console.log);
null 2000
> contract1.methods.payableAmount().call(console.log);
null 2200
> contract1.methods.contractStart().call(console.log);
null 0
> contract1.methods.contractEnd().call(console.log);
null 0
> web3.eth.sendTransaction({
  from:lender,
  to: loanContractAddress,
  value: 50
  });
(node:38992) UnhandledPromiseRejectionWarning: Error: Returned error: VM Exception while processing transaction: revert REVERT: Contribution should be the requested amount.
> web3.eth.sendTransaction({
  from:lender,
  to: loanContractAddress,
  value: 2000
  });
> contract1.methods.contractStart().call(console.log);
null 1606841253
> contract1.methods.contractEnd().call(console.log);
null 1617209253
> web3.eth.getBalance(loanContractAddress).then(console.log);
2000

Тестовый пример. Только заемщик может снять сумму кредита.

> contract1.methods.loanAmountWithdrawn().call(console.log);
null false
> contract1.methods.withdrawLoanAmount().send({from:lender});
(node:38992) UnhandledPromiseRejectionWarning: Error: Returned error: VM Exception while processing transaction: revert REVERT: Only the borrower can withdraw the loan amount!
> contract1.methods.withdrawLoanAmount().send({from:borrower});
> web3.eth.getBalance(loanContractAddress).then(console.log);
0
> contract1.methods.loanAmountWithdrawn().call(console.log);
null true

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

> contract1.methods.amountPaid().call(console.log);
null false
> contract2.methods.withdrawCollateral(loanContractAddress).send({from:borrower});
(node:38992) UnhandledPromiseRejectionWarning: Error: Returned error: VM Exception while processing transaction: revert REVERT: Collateral can’t be withdrawn until the payment is made!

Контрольный пример. Заемщику необходимо произвести возврат, равный обещанной сумме.

> contract1.methods.amountPaid().call(console.log);
null false
> contract1.methods.makeBorrowerPayment().send({from:borrower, value:2000});
(node:38992) UnhandledPromiseRejectionWarning: Error: Returned error: VM Exception while processing transaction: revert REVERT: The payment should be the total amount payable!
> contract1.methods.amountPaid().call(console.log);
null false
> contract1.methods.makeBorrowerPayment().send({from:borrower, value:2200});
> contract1.methods.amountPaid().call(console.log);
null true
> web3.eth.getBalance(loanContractAddress).then(console.log);
2200

Тестовый пример. После выплаты ссуды только кредитор сможет отозвать платеж.

> contract1.methods.withdrawBorrowerPayment().send({from:borrower});
(node:38992) UnhandledPromiseRejectionWarning: Error: Returned error: VM Exception while processing transaction: revert REVERT: Only the lender can withdraw the payment!
> contract1.methods.withdrawBorrowerPayment().send({from:lender});
> web3.eth.getBalance(loanContractAddress).then(console.log);
0

Тестовый пример. После выплаты кредита только заемщик сможет отозвать залог.

> web3.eth.getBalance(collateralContractAddress).then(console.log);
500
> contract1.methods.amountPaid().call(console.log);
null true
> contract2.methods.withdrawCollateral(loanContractAddress).send({from:lender});
(node:38992) UnhandledPromiseRejectionWarning: Error: Returned error: VM Exception while processing transaction: revert REVERT: Only the borrower can withdraw the collateral before the contract ends!
> contract2.methods.withdrawCollateral(loanContractAddress).send({from:borrower});
> web3.eth.getBalance(collateralContractAddress).then(console.log);
0

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

> contract1.methods.contractStart().call(console.log);
null 1606843164
> contract1.methods.contractEnd().call(console.log);
null 1606843164
> contract1.methods.amountPaid().call(console.log);
null false
> contract2.methods.withdrawCollateral(loanContractAddress).send({from:borrower});
(node:39096) UnhandledPromiseRejectionWarning: Error: Returned error: VM Exception while processing transaction: revert REVERT: Payment is late; collateral forfeited to lender.
> contract2.methods.withdrawCollateral(loanContractAddress).send({from:lender});
> web3.eth.getBalance(collateralContractAddress).then(console.log);
0

Отлично, все наши тесты пройдены!

Альтернативные варианты традиционному кредитованию

За последнее десятилетие мир стал свидетелем появления ряда новых вариантов кредитования в качестве альтернативы традиционному кредитованию через банки. Фактически, решение, которое мы создали на протяжении всего этого блога, - это то, что некоторые считают решением «однорангового кредитования». Примерно в 2005 году мы стали свидетелями развития однорангового кредитования, часто обозначаемого сокращенно «P2P», как еще одного варианта для малого бизнеса получить внешнее финансирование. Традиционно владельцы малого бизнеса обращались за внешним финансированием в банки. Владелец подает заявку в банк, и банк проверяет их кредитный рейтинг, историю и доход, чтобы определить, сколько денег им ссудить и какую процентную ставку они будут иметь. Вместо того, чтобы использовать кредитный рейтинг и историю, сервисы P2P-кредитования полагаются на свои собственные алгоритмы для оценки кредитоспособности, позволяя им принимать больше приложений, которые банки сочтут слишком рискованными. Проявления P2P-кредитования сегодня - это онлайн-сервисы, связывающие заемщиков с кредиторами. Заемщики подают заявку на получение кредита и свою информацию. На основе их информации служба определяет процентную ставку, которую заемщик будет платить сверх своей основной суммы. Такое присутствие в сети позволяет этим службам обрабатывать запросы намного быстрее, чем традиционные варианты внешнего финансирования. Затем служба публикует ссуду, после чего кредиторы могут обнаружить эту ссуду и внести сумму в общую сумму, запрошенную этим заемщиком. Затем кредиторы получают ежемесячную сумму основных платежей и выплат по процентам. Если заемщик не выполняет свои обязательства по ссуде, то кредиторы либо теряют остатки своих инвестиций, либо продают оставшиеся инвестиции с убытком другому инвестору, толерантному к риску, который считает, что некоторая стоимость все еще может быть возмещена. Популярные P2P-сервисы сегодня - это Funding Circle, Upstart, Prosper и LendingClub.

По данным MarketWatch, рынок P2P-кредитования в 2019 году оценивался примерно в 68 миллиардов долларов США, и ожидается, что он будет расти более чем на 30% в течение следующих семи лет. Они ссылаются на повышенную прозрачность и низкие эксплуатационные расходы как на важный фактор, способствующий этому росту. Как мы видели в этом блоге, появление блокчейна оказывает огромное влияние на те же факторы, и поэтому можно ожидать, что он изменит правила игры в P2P-ландшафте и возродит его как жизнеспособное средство для привлечения капитала для малого бизнеса. Поскольку это неизменяемый децентрализованный реестр, в блокчейне нет необходимости в посреднике. Кредиторы напрямую связаны с заемщиком из малого бизнеса с полной прозрачностью и возможностью наблюдать за процессом кредитования в режиме реального времени. Существует также экономия средств за счет устранения типичных накладных расходов, таких как авансовые платежи (например, услуги P2P сегодня приносят доход за счет сбора единовременной комиссии с заемщиков по финансируемым кредитам и комиссии за обслуживание кредита с инвесторов), комиссии за андеррайтинг и расходы на закрытие сделки. Кроме того, блокчейн может познакомить этих заемщиков с потенциалом безграничного финансирования и открыть двери для капитала, который ранее был для них недоступен.

Хотя на первый взгляд это кажется отличной ситуацией для малого бизнеса, как и в случае с любыми новыми технологиями и продуктами, существует неопределенность в отношении того, решат ли пользователи их использовать. Эту концепцию лучше всего охарактеризовал как «риск ценности» идейный лидер в области управления технологическими продуктами Марти Кейган в своей книге INSPIRED, которую необходимо прочитать специалистам по продуктам. Отчет о компаниях работодателей за 2019 год, представленный в начале этого блога, показывает благоприятную тенденцию к снижению риска стоимости. Согласно отчету, доверие к онлайн-кредитованию растет среди владельцев малого бизнеса: 32% респондентов искали финансирование у онлайн-кредиторов в 2018 году по сравнению с 19% в 2016 году. Применительно к онлайн-кредитованию респонденты в основном ценили скорость, с которой может быть принято решение по их заявке, а также вероятность того, что их заявка будет принята. И наоборот, малые предприятия, которые стремились получить внешнее финансирование от традиционного банка, указали, что существующие отношения являются наиболее важным фактором при принятии решения. Это хорошие новости для будущего онлайн-кредитования и блокчейна! Если существующие отношения являются основной причиной, по которой владелец малого бизнеса выбирает кредитора, и мы наблюдаем рост числа владельцев малого бизнеса, устанавливающих отношения с онлайн-кредиторами, то превращение онлайн-кредитования в основной источник финансирования - лишь вопрос времени. для малого бизнеса. И, как мы обсуждали ранее в этом разделе, улучшения, которые блокчейн обеспечит для онлайн-кредитования, только укрепят принятие вариантов кредитования, работающих на блокчейне.

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

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

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

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

Но для того, чтобы малый бизнес мог открываться и оставаться открытым, нам необходимо открыть новые каналы внешнего финансирования для владельцев малого бизнеса!

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

Об авторе

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

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

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