diff --git a/.gitignore b/.gitignore index 86a3caf..0c55a8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ -.cache/*.json -.libs.json +build +node_modules +package-lock.json +*.swp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8a2d1a2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ens"] + path = ens + url = https://github.com/ensdomains/ens diff --git a/.travis.yml b/.travis.yml index 6c4e244..acd0880 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,15 @@ language: node_js -dist: trusty -sudo: false + +services: +- docker node_js: -- "6" +- "8" install: -- npm install -g aira-deploy ethereumjs-testrpc +- npm install script: -- aira-deploy --abi - -cache: - directories: - - .cache +- docker run --rm -d -p 8545:8545 foamspace/cliquebait:latest +- sleep 30 +- npm test diff --git a/LICENSE b/LICENSE index 2e9312d..0d15ea6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2017, Airalab +Copyright (c) 2015-2018, Airalab All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index 380ca70..e62002a 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,31 @@ -## Airalab smart contracts +Robonomics platform contracts +============================= -[![Build Status](https://travis-ci.org/airalab/core.svg?branch=master)](https://travis-ci.org/airalab/core) -[![GitHub release](https://img.shields.io/github/release/airalab/core.svg)]() +[![Build Status](https://travis-ci.org/airalab/robonomics_contracts.svg?branch=master)](https://travis-ci.org/airalab/robonomics_contracts) +[![GitHub release](https://img.shields.io/github/release/airalab/robonomics_contracts.svg)]() > Keep all significant smart-contracts in this repository. -- [API Reference](https://airalab.github.io/core/docs) -- [ABIs](https://github.com/airalab/core/tree/master/abi) -- [EthPM](https://www.ethpm.com/registry) +How to use +---------- + +Tested on Truffle@4.1.11 + +To build contracts run in it's directory: -## How to build -Tested on Truffle@3.4.11 -To build a single package run in it's directory: ``` truffle compile ``` -To install dependencies: + +To run testing framework: + ``` -truffle install airalab-token airalab-common +truffle test ``` -To publish a package to EthPM register run: +To deploy contracts in testnet run in it's directory: + ``` -truffle publish +truffle migrate ``` - -Configuration of RPC is located in truffle.js file. Here's links to our packages in EthPM: -- [airalab-common](https://www.ethpm.com/registry/packages/39) -- [airalab-token](https://www.ethpm.com/registry/packages/40) -- [airalab-liability](https://www.ethpm.com/registry/packages/41) diff --git a/SecurityRegulations.md b/SecurityRegulations.md deleted file mode 100644 index cd87fe9..0000000 --- a/SecurityRegulations.md +++ /dev/null @@ -1,148 +0,0 @@ -# Регламент проверки безопасности контрактов Airalab - -Каждый контракт, который мы создаем проверяется разработчиком по данному регламенту, в результате проверки формируется документ, который необходимо расположить по следующему пути: [/airalab/core/securityCheck](https://github.com/airalab/core/tree/master/securityCheck) - -**Результат проверки должен содержать 3 блока:** - -**Блок 1: «Проверка общих рекомендаций Airalab».** В данном блоке должен быть описан результат проверки по каждому из пунктов, содержащихся в разделе: "[Обобщенные рекомендации к проверке](#%D0%9E%D0%B1%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5-%D1%80%D0%B5%D0%BA%D0%BE%D0%BC%D0%B5%D0%BD%D0%B4%D0%B0%D1%86%D0%B8%D0%B8-%D0%BA-%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B5)". - -**Блок 2: «Проверка на известные атаки».** В данном блоке должен быть описан результат проверки по каждой из известных нам видов атак, содержащихся в разделе: "[Известные атаки](#%D0%98%D0%B7%D0%B2%D0%B5%D1%81%D1%82%D0%BD%D1%8B%D0%B5-%D0%B0%D1%82%D0%B0%D0%BA%D0%B8)". - -**Блок 3: «Комментарии по коду».** Данный блок позволяет разработчику обратить внимание на потенциально уязвимые места или же акцентировать внимание пользователя на каких либо фрагментах кода. - -Как пример результата проверки можно посмотреть следующий документ: [Smart contract «Token.sol» security check](https://github.com/airalab/core/blob/master/securityCheck/token.md). - -Рекомендации/замечания разработчиков пишите в формате [issue в репозиторий Aira core на GutHub](https://github.com/airalab/core/issues). - -Также любые вопросы в наш [канал друзей Airalab в Gitter](https://gitter.im/airalab/friends). - -## Обобщенные рекомендации к проверке кода контрактов на Ethereum платформе -1. Избегайте внешних вызовов когда это возможно, очень часто они являются причиной уязвимости -2. Отдавайте приоритет изменению состояния над внешним вызовом вызовом (включая `.send()`) -3. Изолируйте внешние вызовы в отдельной транзакции, например, метод `withdraw` для вывода средств -4. Будте внимательны при делении целых чисел (округление происходит к ближайшему целому) -5. При делении на ноль возвращается **ноль**, проверяйте аргументы самостоятельно -6. Будте внимательны к переполнению целых чисел (особенно в сравнениях) и приведению знаковых к беззнаковым в JS -7. Будьте осторожны при переборе динамических массивов, это может потребовать большое количество газа -8. Будте осторожны с привязкой логики контракта ко времени блока, оно устанавливается майнером -9. Подумайте о способе обновления контракта в будующем -10. Используйте метки остановки работы контракта в случае чрезвычайной ситуации, например обнаружении уязвимости -11. Разделяйте критически важные вызовы во времени, например, вывод большого количества средств не чаще раза в неделю -12. Используйте [формальную верификацию](https://gist.github.com/chriseth/c4a53f201cd17fc3dd5f8ddea2aa3ff9) контрактов - -## Известные атаки на контракты Ethereum платформы -### Атака по глубине стека -**Идея:** разрешенная глубина стека составляет 1024, вызовы глубже не быдут выполнены, однако транзакция не прервется; атакующий может вызвать код с глубиной стека 1023, в таком случае вызовы из уязвимого кода, например `send()` не будут исполнены. - -``` -// INSECURE -contract auction { - mapping(address => uint) refunds; - - // [...] - - function withdrawRefund(address recipient) { - uint refund = refunds[recipient]; - refunds[recipient] = 0; - recipient.send(refund); // эта строка исполнится не так, как ожидается - } -} -// ATTACKER -contract xxx { - function foo(address target, address recipient, uint iter) { - if (iter < 1023) foo(target, recipient, iter+1); - else auction(target).withdrawRefund(recipient); - } -} -``` - -**Противодействие:** минимизация вызовов внутри методов, приоритет записи и учета над вызовом другого метода; а также `.send()` возвращает `false` если не может быть исполнена, необходимо при каждой отправке средств проверять возвращаемое значение. - -### Условия гонки -**Идея:** внешний вызов может произвести неконтролируемые изменения в данных контракта. - -``` -// INSECURE -contract token { - mapping (address => uint) private userBalances; - - function withdrawBalance() public { - uint amountToWithdraw = userBalances[msg.sender]; - // в этом месте внешний контракт может вызвать метод withdrawBalance снова - if (!(msg.sender.call.value(amountToWithdraw)())) { throw; } - userBalances[msg.sender] = 0; - } -} -/// ATTACKER -contract xxx { - uint iter; - address target; - function foo(address _target) { - iter = 0; - target = _target; - token(_target).withdrawBalance(); - } - function () payable { - if (iter < 10) // Withrawal 10 times - token(_target).withdrawBalance(); - } -} -``` - -**Противодействие:** для недоверенного кода(`msg.sender`) приоритет в использовании `.send()` над `.call.value()`, так как количество газа для `.send()` очень ограничено и не может быть использовано для эксплуатации уязвимости. - -### DoS при вызове исключения -**Идея:** работа контракта может быть заблокирована брокском исключения во внешнем вызываемом коде. - -``` -// INSECURE -contract Auction { - address currentLeader; - uint highestBid; - - function bid() { - if (msg.value <= highestBid) { throw; } - - // если контракт в fallback вызовет исключение, новый лидер не сможет быть назначен - if (!currentLeader.send(highestBid)) { throw; } - - currentLeader = msg.sender; - highestBid = msg.value; - } -} -// ATTACKER -contract xxx { - function () payable { throw; } -} -``` - -**Противодействие:** приоритет логирования и записи во внутренние структуры над непосредственной отправкой, например, введение вызова `withdraw` для доступа к вознаграждению из текущего примера. - -### DoS при переполнении лимита газа -**Идея:** объем газа в блоке ограничен, если для транзакции требуется газа больше, чем помещается в блок - она никогда не будет исполнена. - -``` -struct Payee { - address addr; - uint256 value; -} -Payee payees[]; -uint256 nextPayeeIndex; - -function payOut() { - uint256 i = 0; - // при достаточно большом размере payees возможно превысить лимит газа - while (i < payees.length) { - payees[i].addr.send(payees[i].value); - i++; - } -} -``` -**Противодействие:** избегать итерации по большим массивам данных, либо переносить перебор на программную логику вне контракта; если невозможно избавиться от перебора, необходимо разбить его на несколько шагов, либо выполнять действия по запросу, например, добавить метод `withdraw` для вывода средств. - -## Ссылки -1. [Ethereum Contract Security Techniques and Tips](https://github.com/ConsenSys/smart-contract-best-practices) -2. [Публикация в блоге Ethereum Christian Reitwiessner: Smart contract security](https://blog.ethereum.org/2016/06/10/smart-contract-security/) -3. [Публикация в блоге Ethereum Виталика Бутерина: Thinking About Smart Contract Security](https://blog.ethereum.org/2016/06/19/thinking-smart-contract-security/) -4. [Запись лекции по безопасности умных контрактов на Youtube: Smart contract security in Ethereum](https://www.youtube.com/watch?v=pv032ppbakA) -5. [Smart Contract Security in Ethereum](https://docs.google.com/presentation/d/1kS9mVOQNieloYByGQw3P-Yyup2BYE5tg7jOItMNnR0A/edit#slide=id.g15d26d8dbd_0_0) diff --git a/abi/Ambix.json b/abi/Ambix.json deleted file mode 100644 index f696ce4..0000000 --- a/abi/Ambix.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_index","type":"uint256"},{"name":"_source","type":"address[]"},{"name":"_coef","type":"uint256[]"}],"name":"setSource","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"name":"rSource","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"hammer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sink","type":"address[]"},{"name":"_coef","type":"uint256[]"}],"name":"setSink","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"destroy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"rSink","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"run","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"name":"rSourceCoef","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_hammer","type":"address"}],"name":"setHammer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"rSinkCoef","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/abi/Destroyable.json b/abi/Destroyable.json deleted file mode 100644 index 6c4461d..0000000 --- a/abi/Destroyable.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":true,"inputs":[],"name":"hammer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"destroy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_hammer","type":"address"}],"name":"setHammer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/abi/ERC20.json b/abi/ERC20.json deleted file mode 100644 index f957271..0000000 --- a/abi/ERC20.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}] \ No newline at end of file diff --git a/abi/Factory.json b/abi/Factory.json deleted file mode 100644 index b3d6033..0000000 --- a/abi/Factory.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":true,"inputs":[],"name":"xrt","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"buildedLighthouse","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_minimalFreeze","type":"uint256"},{"name":"_timeoutBlocks","type":"uint256"}],"name":"createLighthouse","outputs":[{"name":"lighthouse","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"usedHash","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_model","type":"bytes32"},{"name":"_objective","type":"bytes32"},{"name":"_token","type":"address"},{"name":"_validator","type":"address"},{"name":"_expenses","type":"uint256[3]"},{"name":"_sign","type":"bytes32[8]"},{"name":"_deadline","type":"uint256[2]"}],"name":"createLiability","outputs":[{"name":"liability","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalGasUtilizing","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isBuilded","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"buildedLiability","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_xrt","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"robotLiability","type":"address"}],"name":"BuildedLiability","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"lighthouse","type":"address"}],"name":"BuildedLighthouse","type":"event"}] \ No newline at end of file diff --git a/abi/Lighthouse.json b/abi/Lighthouse.json deleted file mode 100644 index bf0922d..0000000 --- a/abi/Lighthouse.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"timeoutBlocks","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"marker","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"members","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minimalFreeze","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"keepaliveBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"factory","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"quota","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_minimalFreeze","type":"uint256"},{"name":"_timeoutBlocks","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":false,"stateMutability":"nonpayable","type":"fallback"}] \ No newline at end of file diff --git a/abi/LighthouseABI.json b/abi/LighthouseABI.json deleted file mode 100644 index 75bc819..0000000 --- a/abi/LighthouseABI.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_data","type":"bytes"}],"name":"to","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"refill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_member","type":"address"}],"name":"quotaOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/abi/LighthouseAPI.json b/abi/LighthouseAPI.json deleted file mode 100644 index b55bf71..0000000 --- a/abi/LighthouseAPI.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"timeoutBlocks","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"marker","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"members","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minimalFreeze","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"keepaliveBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"factory","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"quota","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/abi/LighthouseLib.json b/abi/LighthouseLib.json deleted file mode 100644 index 19163eb..0000000 --- a/abi/LighthouseLib.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"timeoutBlocks","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"marker","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"members","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minimalFreeze","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"keepaliveBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_data","type":"bytes"}],"name":"to","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"factory","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"refill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"quota","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_member","type":"address"}],"name":"quotaOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":false,"stateMutability":"nonpayable","type":"fallback"}] \ No newline at end of file diff --git a/abi/Object.json b/abi/Object.json deleted file mode 100644 index eda1422..0000000 --- a/abi/Object.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hammer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"destroy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_hammer","type":"address"}],"name":"setHammer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}] \ No newline at end of file diff --git a/abi/Owned.json b/abi/Owned.json deleted file mode 100644 index 8cde6b1..0000000 --- a/abi/Owned.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/abi/Recipient.json b/abi/Recipient.json deleted file mode 100644 index 7219635..0000000 --- a/abi/Recipient.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_value","type":"uint256"},{"name":"_token","type":"address"},{"name":"_extraData","type":"bytes"}],"name":"receiveApproval","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"amount","type":"uint256"}],"name":"ReceivedEther","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"value","type":"uint256"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"extraData","type":"bytes"}],"name":"ReceivedTokens","type":"event"}] \ No newline at end of file diff --git a/abi/RobotLiability.json b/abi/RobotLiability.json deleted file mode 100644 index e2ca5f9..0000000 --- a/abi/RobotLiability.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":true,"inputs":[],"name":"model","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cost","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"objective","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"xrt","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"validator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"validatorFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"promisee","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"result","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"finalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"promisor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"factory","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_model","type":"bytes32"},{"name":"_objective","type":"bytes32"},{"name":"_token","type":"address"},{"name":"_expenses","type":"uint256[3]"},{"name":"_parties","type":"address[3]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":false,"stateMutability":"nonpayable","type":"fallback"}] \ No newline at end of file diff --git a/abi/RobotLiabilityABI.json b/abi/RobotLiabilityABI.json deleted file mode 100644 index 29ec5e1..0000000 --- a/abi/RobotLiabilityABI.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":false,"inputs":[{"name":"_result","type":"bytes32"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"setResult","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_agree","type":"bool"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"setDecision","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/abi/RobotLiabilityAPI.json b/abi/RobotLiabilityAPI.json deleted file mode 100644 index 6d00720..0000000 --- a/abi/RobotLiabilityAPI.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":true,"inputs":[],"name":"model","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cost","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"objective","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"xrt","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"validator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"validatorFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"promisee","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"result","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"finalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"promisor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"factory","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/abi/RobotLiabilityEvents.json b/abi/RobotLiabilityEvents.json deleted file mode 100644 index c7fc00f..0000000 --- a/abi/RobotLiabilityEvents.json +++ /dev/null @@ -1 +0,0 @@ -[{"anonymous":false,"inputs":[],"name":"ValidationReady","type":"event"}] \ No newline at end of file diff --git a/abi/RobotLiabilityLib.json b/abi/RobotLiabilityLib.json deleted file mode 100644 index f1c1888..0000000 --- a/abi/RobotLiabilityLib.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":true,"inputs":[],"name":"model","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_result","type":"bytes32"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"setResult","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"cost","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"objective","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_agree","type":"bool"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"setDecision","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"xrt","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"validator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"validatorFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"promisee","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"result","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"hashPrefix","outputs":[{"name":"","type":"bytes2"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"finalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"promisor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"factory","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[],"name":"ValidationReady","type":"event"}] \ No newline at end of file diff --git a/abi/Token.json b/abi/Token.json deleted file mode 100644 index 20bb90f..0000000 --- a/abi/Token.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"hammer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"destroy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_hammer","type":"address"}],"name":"setHammer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"}],"name":"unapprove","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_decimals","type":"uint8"},{"name":"_count","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}] \ No newline at end of file diff --git a/abi/TokenEmission.json b/abi/TokenEmission.json deleted file mode 100644 index 663d0ca..0000000 --- a/abi/TokenEmission.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hammer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"emission","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"destroy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_hammer","type":"address"}],"name":"setHammer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"}],"name":"unapprove","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_decimals","type":"uint8"},{"name":"_start_count","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}] \ No newline at end of file diff --git a/abi/TokenEther.json b/abi/TokenEther.json deleted file mode 100644 index d0012df..0000000 --- a/abi/TokenEther.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"hammer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"refill","outputs":[{"name":"","type":"bool"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"destroy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_hammer","type":"address"}],"name":"setHammer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"}],"name":"unapprove","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}] \ No newline at end of file diff --git a/airalab-common/contracts/Destroyable.sol b/airalab-common/contracts/Destroyable.sol deleted file mode 100644 index dab1319..0000000 --- a/airalab-common/contracts/Destroyable.sol +++ /dev/null @@ -1,27 +0,0 @@ -pragma solidity ^0.4.18; - -/** - * @title Common pattern for destroyable contracts - */ -contract Destroyable { - address public hammer; - - /** - * @dev Hammer setter - * @param _hammer New hammer address - */ - function setHammer(address _hammer) public onlyHammer - { hammer = _hammer; } - - /** - * @dev Destroy contract and scrub a data - * @notice Only hammer can call it - */ - function destroy() public onlyHammer - { selfdestruct(msg.sender); } - - /** - * @dev Hammer check modifier - */ - modifier onlyHammer { require(msg.sender == hammer); _; } -} diff --git a/airalab-common/contracts/Object.sol b/airalab-common/contracts/Object.sol deleted file mode 100644 index f88922d..0000000 --- a/airalab-common/contracts/Object.sol +++ /dev/null @@ -1,14 +0,0 @@ -pragma solidity ^0.4.18; - -import './Owned.sol'; -import './Destroyable.sol'; - -/** - * @title Generic owned destroyable contract - */ -contract Object is Owned, Destroyable { - function Object() public { - owner = msg.sender; - hammer = msg.sender; - } -} diff --git a/airalab-common/contracts/Owned.sol b/airalab-common/contracts/Owned.sol deleted file mode 100644 index b6df05e..0000000 --- a/airalab-common/contracts/Owned.sol +++ /dev/null @@ -1,23 +0,0 @@ -pragma solidity ^0.4.18; - -/** - * @title Contract for object that have an owner - */ -contract Owned { - /** - * Contract owner address - */ - address public owner; - - /** - * @dev Delegate contract to another person - * @param _owner New owner address - */ - function setOwner(address _owner) public onlyOwner - { owner = _owner; } - - /** - * @dev Owner check modifier - */ - modifier onlyOwner { require(msg.sender == owner); _; } -} diff --git a/airalab-common/ethpm.json b/airalab-common/ethpm.json deleted file mode 100644 index 8206590..0000000 --- a/airalab-common/ethpm.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "package_name": "airalab-common", - "version": "0.7.0", - "description": "Airalab common smart-contracts", - "authors": [ - "Alexander Krupenkin " - ], - "keywords": [ - "airalab", - "core", - "robonomics" - ], - "license": "BSD-3" -} \ No newline at end of file diff --git a/airalab-common/truffle.js b/airalab-common/truffle.js deleted file mode 100644 index 51582a6..0000000 --- a/airalab-common/truffle.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - // See - // to customize your Truffle configuration! - networks: { - development: { - host: "127.0.0.1", - port: 8545, - network_id: "*" // Match any network id - }, - ropsten: { - host: "127.0.0.1", - port: 8545, - network_id: 3 // official id of the ropsten network - } - } -}; diff --git a/airalab-foundation/contracts/Congress.sol b/airalab-foundation/contracts/Congress.sol deleted file mode 100644 index 41fa3a7..0000000 --- a/airalab-foundation/contracts/Congress.sol +++ /dev/null @@ -1,326 +0,0 @@ -pragma solidity ^0.4.18; - -import 'airalab-common/contracts/Object.sol'; -import 'airalab-token/contracts/Recipient.sol'; - -/** - * @title Improved congress contract by Ethereum Foundation - * @dev https://www.ethereum.org/dao#the-blockchain-congress - */ -contract Congress is Object, Recipient { - /** - * @dev Minimal quorum value - */ - uint256 public minimumQuorum; - - /** - * @dev Duration of debates - */ - uint256 public debatingPeriodInMinutes; - - /** - * @dev Majority margin is used in voting procedure - */ - int256 public majorityMargin; - - /** - * @dev Archive of all member proposals - */ - Proposal[] public proposals; - - /** - * @dev Count of proposals in archive - */ - function numProposals() public view returns (uint256) - { return proposals.length; } - - /** - * @dev Congress members list - */ - Member[] public members; - - /** - * @dev Get member identifier by account address - */ - mapping(address => uint256) public memberId; - - /** - * @dev On proposal added - * @param proposal Proposal identifier - * @param recipient Ether recipient - * @param amount Amount of wei to transfer - */ - event ProposalAdded(uint256 indexed proposal, - address indexed recipient, - uint256 indexed amount, - string description); - - /** - * @dev On vote by member accepted - * @param proposal Proposal identifier - * @param position Is proposal accepted by memeber - * @param voter Congress memeber account address - * @param justification Member comment - */ - event Voted(uint256 indexed proposal, - bool indexed position, - address indexed voter, - string justification); - - /** - * @dev On Proposal closed - * @param proposal Proposal identifier - * @param quorum Number of votes - * @param active Is proposal passed - */ - event ProposalTallied(uint256 indexed proposal, - uint256 indexed quorum, - bool indexed active); - - /** - * @dev On changed membership - * @param member Account address - * @param isMember Is account member now - */ - event MembershipChanged(address indexed member, - bool indexed isMember); - - /** - * @dev On voting rules changed - * @param minimumQuorum New minimal count of votes - * @param debatingPeriodInMinutes New debating duration - * @param majorityMargin New majority margin value - */ - event ChangeOfRules(uint256 indexed minimumQuorum, - uint256 indexed debatingPeriodInMinutes, - int256 indexed majorityMargin); - - struct Proposal { - address recipient; - uint256 amount; - string description; - uint256 votingDeadline; - bool executed; - bool proposalPassed; - uint256 numberOfVotes; - int256 currentResult; - bytes32 proposalHash; - Vote[] votes; - mapping(address => bool) voted; - } - - struct Member { - address member; - string name; - uint256 memberSince; - } - - struct Vote { - bool inSupport; - address voter; - string justification; - } - - /** - * @dev Modifier that allows only shareholders to vote and create new proposals - */ - modifier onlyMembers { - require (memberId[msg.sender] != 0); - _; - } - - /** - * @dev First time setup - */ - function Congress( - uint256 minimumQuorumForProposals, - uint256 minutesForDebate, - int256 marginOfVotesForMajority, - address congressLeader - ) public { - changeVotingRules(minimumQuorumForProposals, minutesForDebate, marginOfVotesForMajority); - // It’s necessary to add an empty first member - addMember(0, ''); // and let's add the founder, to save a step later - if (congressLeader != 0) - addMember(congressLeader, 'The Founder'); - } - - /** - * @dev Append new congress member - * @param targetMember Member account address - * @param memberName Member full name - */ - function addMember(address targetMember, string memberName) public onlyOwner { - require (memberId[targetMember] == 0); - - memberId[targetMember] = members.length; - members.push(Member({member: targetMember, - memberSince: now, - name: memberName})); - - MembershipChanged(targetMember, true); - } - - /** - * @dev Remove congress member - * @param targetMember Member account address - */ - function removeMember(address targetMember) public onlyOwner { - require (memberId[targetMember] != 0); - - uint256 targetId = memberId[targetMember]; - uint256 lastId = members.length - 1; - - // Move last member to removed position - Member memory moved = members[lastId]; - members[targetId] = moved; - memberId[moved.member] = targetId; - - // Clean up - memberId[targetMember] = 0; - delete members[lastId]; - --members.length; - - MembershipChanged(targetMember, false); - } - - /** - * @dev Change rules of voting - * @param minimumQuorumForProposals Minimal count of votes - * @param minutesForDebate Debate deadline in minutes - * @param marginOfVotesForMajority Majority margin value - */ - function changeVotingRules( - uint256 minimumQuorumForProposals, - uint256 minutesForDebate, - int256 marginOfVotesForMajority - ) - public onlyOwner - { - minimumQuorum = minimumQuorumForProposals; - debatingPeriodInMinutes = minutesForDebate; - majorityMargin = marginOfVotesForMajority; - - ChangeOfRules(minimumQuorum, debatingPeriodInMinutes, majorityMargin); - } - - /** - * @dev Create a new proposal - * @param beneficiary Beneficiary account address - * @param amount Transaction value in Wei - * @param jobDescription Job description string - * @param transactionBytecode Bytecode of transaction - */ - function newProposal( - address beneficiary, - uint256 amount, - string jobDescription, - bytes transactionBytecode - ) - public - onlyMembers - returns (uint256 id) - { - id = proposals.length++; - Proposal storage p = proposals[id]; - p.recipient = beneficiary; - p.amount = amount; - p.description = jobDescription; - p.proposalHash = keccak256(beneficiary, amount, transactionBytecode); - p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes; - p.executed = false; - p.proposalPassed = false; - p.numberOfVotes = 0; - ProposalAdded(id, beneficiary, amount, jobDescription); - } - - /** - * @dev Check if a proposal code matches - * @param id Proposal identifier - * @param beneficiary Beneficiary account address - * @param amount Transaction value in Wei - * @param transactionBytecode Bytecode of transaction - */ - function checkProposalCode( - uint256 id, - address beneficiary, - uint256 amount, - bytes transactionBytecode - ) - public - view - returns (bool codeChecksOut) - { - return proposals[id].proposalHash - == keccak256(beneficiary, amount, transactionBytecode); - } - - /** - * @dev Proposal voting - * @param id Proposal identifier - * @param supportsProposal Is proposal supported - * @param justificationText Member comment - */ - function vote( - uint256 id, - bool supportsProposal, - string justificationText - ) - public - onlyMembers - { - Proposal storage p = proposals[id]; // Get the proposal - require (p.voted[msg.sender] != true); // If has already voted, cancel - p.voted[msg.sender] = true; // Set this voter as having voted - p.numberOfVotes++; // Increase the number of votes - if (supportsProposal) { // If they support the proposal - p.currentResult++; // Increase score - } else { // If they don't - p.currentResult--; // Decrease the score - } - // Create a log of this event - Voted(id, supportsProposal, msg.sender, justificationText); - } - - /** - * @dev Try to execute proposal - * @param id Proposal identifier - * @param transactionBytecode Transaction data - */ - function executeProposal( - uint256 id, - bytes transactionBytecode - ) - public - onlyMembers - { - Proposal storage p = proposals[id]; - /* Check if the proposal can be executed: - - Has the voting deadline arrived? - - Has it been already executed or is it being executed? - - Does the transaction code match the proposal? - - Has a minimum quorum? - */ - - if (now < p.votingDeadline - || p.executed - || p.proposalHash != keccak256(p.recipient, p.amount, transactionBytecode) - || p.numberOfVotes < minimumQuorum) - revert(); - - /* execute result */ - /* If difference between support and opposition is larger than margin */ - if (p.currentResult > majorityMargin) { - // Avoid recursive calling - - p.executed = true; - require (p.recipient.call.value(p.amount)(transactionBytecode)); - - p.proposalPassed = true; - } else { - p.proposalPassed = false; - } - // Fire Events - ProposalTallied(id, p.numberOfVotes, p.proposalPassed); - } -} diff --git a/airalab-foundation/contracts/Crowdfunding.sol b/airalab-foundation/contracts/Crowdfunding.sol deleted file mode 100644 index 1a6f56c..0000000 --- a/airalab-foundation/contracts/Crowdfunding.sol +++ /dev/null @@ -1,183 +0,0 @@ -pragma solidity ^0.4.18; - -import 'airalab-token/contracts/TokenEmission.sol'; - -/** - * @title Crowdfunding contract - */ -contract Crowdfunding is Object { - /** - * @dev Target fund account address - */ - address public fund; - - /** - * @dev Bounty token address - */ - TokenEmission public bounty; - - /** - * @dev Distribution of donations - */ - mapping(address => uint256) public donations; - - /** - * @dev Total funded value - */ - uint256 public totalFunded; - - /** - * @dev Documentation reference - */ - string public reference; - - /** - * @dev Crowdfunding configuration - */ - Params public config; - - struct Params { - /* start/stop block stamps */ - uint256 startBlock; - uint256 stopBlock; - - /* Minimal/maximal funded value */ - uint256 minValue; - uint256 maxValue; - - /** - * Bounty ratio equation: - * bountyValue = value * ratio / scale - * where - * ratio = R - (block - B) / S * V - * R - start bounty ratio - * B - start block number - * S - bounty reduction step in blocks - * V - bounty reduction value - */ - uint256 bountyScale; - uint256 startRatio; - uint256 reductionStep; - uint256 reductionValue; - } - - /** - * @dev Calculate bounty value by reduction equation - * @param _value Input donation value - * @param _block Input block number - * @return Bounty value - */ - function bountyValue(uint256 _value, uint256 _block) public view returns (uint256) { - if (_block < config.startBlock || _block > config.stopBlock) - return 0; - - var R = config.startRatio; - var B = config.startBlock; - var S = config.reductionStep; - var V = config.reductionValue; - uint256 ratio = R - (_block - B) / S * V; - return _value * ratio / config.bountyScale; - } - - /** - * @dev Crowdfunding running checks - */ - modifier onlyRunning { - bool isRunning = totalFunded + msg.value <= config.maxValue - && block.number >= config.startBlock - && block.number <= config.stopBlock; - require (isRunning); - _; - } - - /** - * @dev Crowdfundung failure checks - */ - modifier onlyFailure { - bool isFailure = totalFunded < config.minValue - && block.number > config.stopBlock; - require (isFailure); - _; - } - - /** - * @dev Crowdfunding success checks - */ - modifier onlySuccess { - bool isSuccess = totalFunded >= config.minValue - && block.number > config.stopBlock; - require (isSuccess); - _; - } - - /** - * @dev Crowdfunding contract initial - * @param _fund Destination account address - * @param _bounty Bounty token address - * @param _reference Reference documentation link - * @param _startBlock Funding start block number - * @param _stopBlock Funding stop block nubmer - * @param _minValue Minimal funded value in wei - * @param _maxValue Maximal funded value in wei - * @param _scale Bounty scaling factor by funded value - * @param _startRatio Initial bounty ratio - * @param _reductionStep Bounty reduction step in blocks - * @param _reductionValue Bounty reduction value - * @notice this contract should be owner of bounty token - */ - function Crowdfunding( - address _fund, - address _bounty, - string _reference, - uint256 _startBlock, - uint256 _stopBlock, - uint256 _minValue, - uint256 _maxValue, - uint256 _scale, - uint256 _startRatio, - uint256 _reductionStep, - uint256 _reductionValue - ) public { - fund = _fund; - bounty = TokenEmission(_bounty); - reference = _reference; - - config.startBlock = _startBlock; - config.stopBlock = _stopBlock; - config.minValue = _minValue; - config.maxValue = _maxValue; - config.bountyScale = _scale; - config.startRatio = _startRatio; - config.reductionStep = _reductionStep; - config.reductionValue = _reductionValue; - } - - /** - * @dev Receive Ether token and send bounty - */ - function () public payable onlyRunning { - totalFunded += msg.value; - donations[msg.sender] += msg.value; - - var bountyVal = bountyValue(msg.value, block.number); - require (bountyVal > 0); - - bounty.emission(bountyVal); - require(bounty.transfer(msg.sender, bountyVal)); - } - - /** - * @dev Withdrawal balance on successfull finish - */ - function withdraw() public onlySuccess - { require (fund.send(this.balance)); } - - /** - * @dev Refund donations when no minimal value achieved - */ - function refund() public onlyFailure { - var donation = donations[msg.sender]; - donations[msg.sender] = 0; - require (msg.sender.send(donation)); - } -} diff --git a/airalab-foundation/contracts/Presale.sol b/airalab-foundation/contracts/Presale.sol deleted file mode 100644 index eb88172..0000000 --- a/airalab-foundation/contracts/Presale.sol +++ /dev/null @@ -1,39 +0,0 @@ -pragma solidity ^0.4.18; - -import 'airalab-token/contracts/ERC20.sol'; -import 'airalab-common/contracts/Object.sol'; - -contract Presale is Object { - ERC20 public token; - uint256 public bounty; - uint256 public donation; - - /** - * @dev Presale contract constructor - * @param _token Bounty token address - * @param _bounty Bount value by donation - * @param _donation Donation value - */ - function Presale(address _token, uint256 _bounty, uint256 _donation) public { - token = ERC20(_token); - bounty = _bounty; - donation = _donation; - } - - /** - * @dev Cancel presale contract by owner, bounty refunded to owner - */ - function cancel() public onlyOwner { - require (token.transfer(owner, bounty)); - } - - /** - * @dev Accept presale contract, - * bounty transfered to sender - donation to owner - */ - function () public payable { - require (msg.value == donation); - require (token.transfer(msg.sender, bounty)); - require (owner.send(msg.value)); - } -} diff --git a/airalab-foundation/contracts/TokenHolder.sol b/airalab-foundation/contracts/TokenHolder.sol deleted file mode 100644 index 92e68a1..0000000 --- a/airalab-foundation/contracts/TokenHolder.sol +++ /dev/null @@ -1,46 +0,0 @@ -pragma solidity ^0.4.18; - -import 'airalab-common/contracts/Object.sol'; -import 'airalab-token/contracts/Recipient.sol'; - -contract TokenHolder is Object, Recipient { - /** - * @dev Recipient account address - */ - address public recipient; - - /** - * @dev Block number for holding before it'll not mined - */ - uint256 public holdBeforeBlock; - - /** - * @dev Construct TokenHolder contract - * @param _recipient Recipient account address - * @param _releaseBlock Block for releasing assets - */ - function TokenHolder(address _recipient, uint256 _releaseBlock) public { - recipient = _recipient; - holdBeforeBlock = _releaseBlock; - } - - /** - * @dev Check for current block is not release block - */ - modifier holding { if (block.number < holdBeforeBlock) revert(); _; } - - /** - * @dev Claim ERC20 token - * @param _token Token address - */ - function claimERC20(ERC20 _token) public holding { - require (_token.transfer(recipient, _token.balanceOf(this))); - } - - /** - * @dev Claim ether - */ - function claimEther() public holding { - require (recipient.send(this.balance)); - } -} diff --git a/airalab-foundation/ethpm.json b/airalab-foundation/ethpm.json deleted file mode 100644 index 13270a0..0000000 --- a/airalab-foundation/ethpm.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "package_name": "airalab-foundation", - "version": "0.7.0", - "description": "Airalab foundation smart-contracts", - "authors": [ - "Alexander Krupenkin " - ], - "keywords": [ - "airalab", - "core", - "foundation", - "robonomics" - ], - "build_dependencies": { - "airalab-common": "ipfs://Qmc8dothLPPNfqiRp9nBjM7vgEqzC5T9D8LN52T6ePAgDd", - "airalab-token": "ipfs://QmU5c7HaGjNKWzeBWHN29VGSvpXqj75TsG5Ta2prctRXMQ" - }, - "license": "BSD-3" -} \ No newline at end of file diff --git a/airalab-foundation/truffle.js b/airalab-foundation/truffle.js deleted file mode 100644 index 51582a6..0000000 --- a/airalab-foundation/truffle.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - // See - // to customize your Truffle configuration! - networks: { - development: { - host: "127.0.0.1", - port: 8545, - network_id: "*" // Match any network id - }, - ropsten: { - host: "127.0.0.1", - port: 8545, - network_id: 3 // official id of the ropsten network - } - } -}; diff --git a/airalab-lighthouse/.gitignore b/airalab-lighthouse/.gitignore deleted file mode 100644 index dd2868f..0000000 --- a/airalab-lighthouse/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build/ -installed_contracts/ diff --git a/airalab-lighthouse/contracts/Factory.sol b/airalab-lighthouse/contracts/Factory.sol deleted file mode 100644 index 290ecf8..0000000 --- a/airalab-lighthouse/contracts/Factory.sol +++ /dev/null @@ -1,166 +0,0 @@ -pragma solidity ^0.4.18; - -import {TokenEmission} from 'airalab-token/contracts/TokenEmission.sol'; -import './RobotLiability.sol'; -import './Lighthouse.sol'; - -contract Factory { - function Factory(TokenEmission _xrt) public - { xrt = _xrt; } - - /** - * @dev Robonomics network utility token - */ - TokenEmission public xrt; - - /* Constants */ - bytes constant MSGPREFIX = "\x19Ethereum Signed Message:\n32"; - - /** - * @dev Total GAS utilized by Robonomics network - */ - uint256 public totalGasUtilizing = 0; - - /** - * @dev Used market order hashes tracking. - */ - mapping(bytes32 => bool) public usedHash; - - RobotLiability[] public buildedLiability; - Lighthouse[] public buildedLighthouse; - - mapping(address => bool) public isBuilded; - - /* Events */ - event BuildedLiability(address indexed robotLiability); - event BuildedLighthouse(address indexed lighthouse); - - /** - * @dev Create robot liability contract - * @param _model Robot behaviour model - * @param _objective Task for the robot - * @param _token Operational token - * @param _expenses Liability creation expenses - * @param _sign Liability cyptographic params - * @param _deadline Messages deadline params - * - * '_sign' is a list of: - * - [0] => promisee nonce - * - [1-3] => promisee EC signature (v, r, s) - * - [4] => promisor nonce - * - [5-7] => promisor EC signature (v, r, s) - * - * '_expenses' is a list of: - * - execution cost (cost * count) - * - lighthouse fee (only for promisor) - * - validator fee (only for promisee) - * - * '_deadline' is a list of: - * - ASK deadline block number - * - BID deadline block number - */ - function createLiability( - bytes32 _model, - bytes32 _objective, - ERC20 _token, - address _validator, - uint256[3] _expenses, - bytes32[8] _sign, - uint256[2] _deadline - ) public returns (RobotLiability liability) { - uint256 gasinit = gasleft(); - require(gasinit >= 700000); - - require(isBuilded[msg.sender]); - - require(block.number < _deadline[0]); - require(block.number < _deadline[1]); - - bytes32 askHash = keccak256(_model, - _objective, - _token, - _validator, - _expenses[0], - _expenses[2], - _sign[0], - _deadline[0]); - bytes32 bidHash = keccak256(_model, - _token, - _expenses[0], - _expenses[1], - _sign[4], - _deadline[1]); - - require(!usedHash[askHash] && !usedHash[bidHash]); - usedHash[askHash] = true; - usedHash[bidHash] = true; - - address promisee = ecrecover(keccak256(MSGPREFIX, askHash), uint8(_sign[1]), _sign[2], _sign[3]); - address promisor = ecrecover(keccak256(MSGPREFIX, bidHash), uint8(_sign[5]), _sign[6], _sign[7]); - - // Instantiate liability contract - liability = new RobotLiability(_model, - _objective, - _token, - _expenses, - [promisee, promisor, _validator]); - buildedLiability.push(liability); - isBuilded[liability] = true; - emit BuildedLiability(liability); - - // Tnasfer robot fee for lighthouse - require(xrt.transferFrom(promisor, msg.sender, _expenses[1])); - - // Transfer token security - require(_token.transferFrom(promisee, liability, _expenses[0])); - - // Transfer promisee fee for validator - if (_validator != 0 && _expenses[2] > 0) - require(xrt.transferFrom(promisee, liability, _expenses[2])); - - // Transfer XRT emission for finalization - require(xrt.transfer(liability, xrt_emission(gasinit - gasleft()))); - } - - function xrt_emission(uint256 gas) internal returns (uint256) { - // Gas used = limit - left + uncounted expenses: emission, transfer, finalization - totalGasUtilizing += gas; - - uint256 wnEmission = gas; - /* Additional emission table */ - if (totalGasUtilizing < 856368000) { - wnEmission *= 37; - } else if (totalGasUtilizing < 856368000 * 2) { - wnEmission *= 25; - } else if (totalGasUtilizing < 856368000 * 3) { - wnEmission *= 17; - } else if (totalGasUtilizing < 856368000 * 4) { - wnEmission *= 11; - } else if (totalGasUtilizing < 856368000 * 5) { - wnEmission *= 7; - } else if (totalGasUtilizing < 856368000 * 6) { - wnEmission *= 5; - } else if (totalGasUtilizing < 856368000 * 7) { - wnEmission *= 3; - } else if (totalGasUtilizing < 856368000 * 8) { - wnEmission *= 2; - } - xrt.emission(wnEmission); - return wnEmission; - } - - /** - * @dev Create lighthouse - * @param _minimalFreeze Minimal freeze value of XRT token - */ - function createLighthouse( - uint256 _minimalFreeze - , uint256 _timeoutBlocks - ) public returns (Lighthouse lighthouse) { - lighthouse = new Lighthouse(_minimalFreeze, _timeoutBlocks); - - buildedLighthouse.push(lighthouse); - isBuilded[lighthouse] = true; - emit BuildedLighthouse(lighthouse); - } -} diff --git a/airalab-lighthouse/contracts/Lighthouse.sol b/airalab-lighthouse/contracts/Lighthouse.sol deleted file mode 100644 index 398833c..0000000 --- a/airalab-lighthouse/contracts/Lighthouse.sol +++ /dev/null @@ -1,17 +0,0 @@ -pragma solidity ^0.4.18; - -import './LighthouseAPI.sol'; - -contract Lighthouse is LighthouseAPI { - function Lighthouse(uint256 _minimalFreeze, uint256 _timeoutBlocks) public { - minimalFreeze = _minimalFreeze; - timeoutBlocks = _timeoutBlocks; - factory = msg.sender; - } - - function() public { - require(lib.delegatecall(msg.data)); - } - - address constant lib = 0x163CDd07a2b1b3DF797b563B79058f0DafbEfcBe; -} diff --git a/airalab-lighthouse/contracts/LighthouseABI.sol b/airalab-lighthouse/contracts/LighthouseABI.sol deleted file mode 100644 index 50560bc..0000000 --- a/airalab-lighthouse/contracts/LighthouseABI.sol +++ /dev/null @@ -1,8 +0,0 @@ -pragma solidity ^0.4.18; - -contract LighthouseABI { - function quotaOf(address _member) public view returns (uint256); - function refill(uint256 _value) public; - function withdraw(uint256 _value) public; - function to(address _to, bytes _data) public; -} diff --git a/airalab-lighthouse/contracts/RobotLiability.sol b/airalab-lighthouse/contracts/RobotLiability.sol deleted file mode 100644 index a2b434b..0000000 --- a/airalab-lighthouse/contracts/RobotLiability.sol +++ /dev/null @@ -1,31 +0,0 @@ -pragma solidity ^0.4.18; - -import './RobotLiabilityAPI.sol'; - -// Standard robot liability light contract -contract RobotLiability is RobotLiabilityAPI { - function RobotLiability( - bytes32 _model, - bytes32 _objective, - ERC20 _token, - uint256[3] _expenses, - address[3] _parties - ) public { - factory = Factory(msg.sender); - model = _model; - objective = _objective; - token = _token; - cost = _expenses[0]; - xrt = factory.xrt(); - promisee = _parties[0]; - promisor = _parties[1]; - validator = _parties[2]; - validatorFee = _expenses[2]; - } - - function() public { - require(lib.delegatecall(msg.data)); - } - - address constant lib = 0xd70D7001B6e93940A384B144997a3d95FcF5c3c8; -} diff --git a/airalab-lighthouse/contracts/RobotLiabilityABI.sol b/airalab-lighthouse/contracts/RobotLiabilityABI.sol deleted file mode 100644 index 963d7f4..0000000 --- a/airalab-lighthouse/contracts/RobotLiabilityABI.sol +++ /dev/null @@ -1,6 +0,0 @@ -pragma solidity ^0.4.18; - -contract RobotLiabilityABI { - function setDecision(bool _agree, uint8 _v, bytes32 _r, bytes32 _s) external; - function setResult(bytes32 _result, uint8 _v, bytes32 _r, bytes32 _s) external; -} diff --git a/airalab-lighthouse/contracts/RobotLiabilityAPI.sol b/airalab-lighthouse/contracts/RobotLiabilityAPI.sol deleted file mode 100644 index 827a5ef..0000000 --- a/airalab-lighthouse/contracts/RobotLiabilityAPI.sol +++ /dev/null @@ -1,28 +0,0 @@ -pragma solidity ^0.4.18; - -import {ERC20} from 'airalab-token/contracts/ERC20.sol'; -import './Factory.sol'; - -contract RobotLiabilityAPI { - /* Constants */ - bytes constant MSGPREFIX = "\x19Ethereum Signed Message:\n32"; - - /* State variables */ - Factory public factory; - - address public promisor; - address public promisee; - - ERC20 public xrt; - ERC20 public token; - uint256 public cost; - - bytes32 public model; - bytes32 public objective; - bytes32 public result; - - bool public finalized; - - address public validator; - uint256 public validatorFee; -} diff --git a/airalab-lighthouse/contracts/RobotLiabilityEvents.sol b/airalab-lighthouse/contracts/RobotLiabilityEvents.sol deleted file mode 100644 index 1af802a..0000000 --- a/airalab-lighthouse/contracts/RobotLiabilityEvents.sol +++ /dev/null @@ -1,5 +0,0 @@ -pragma solidity ^0.4.18; - -contract RobotLiabilityEvents { - event ValidationReady(); -} diff --git a/airalab-lighthouse/contracts/RobotLiabilityLib.sol b/airalab-lighthouse/contracts/RobotLiabilityLib.sol deleted file mode 100644 index 5a5f95a..0000000 --- a/airalab-lighthouse/contracts/RobotLiabilityLib.sol +++ /dev/null @@ -1,56 +0,0 @@ -pragma solidity ^0.4.18; - -import './RobotLiabilityABI.sol'; -import './RobotLiabilityAPI.sol'; -import './RobotLiabilityEvents.sol'; - -contract RobotLiabilityLib is RobotLiabilityABI - , RobotLiabilityAPI - , RobotLiabilityEvents { - /** - * @dev IPFS multihash prefix. - */ - bytes2 public constant hashPrefix = 0x1220; - - /** - * @dev Set result of this liability - * @param _result Result data hash - */ - function setResult(bytes32 _result, uint8 _v, bytes32 _r, bytes32 _s) external { - require(result == 0); - - require(factory.isBuilded(msg.sender)); - require(ecrecover(keccak256(MSGPREFIX, keccak256(this, _result)), _v, _r, _s) == promisor); - - result = _result; - - if (validator == 0) { - finalized = true; - require(token.transfer(promisor, cost)); - require(xrt.transfer(tx.origin, xrt.balanceOf(this))); - } else { - emit ValidationReady(); - } - } - - /** - * @dev Set result of this liability checking by observer - * @param _agree if true the observer confirm this execution of this liability - */ - function setDecision(bool _agree, uint8 _v, bytes32 _r, bytes32 _s) external { - require(result != 0); - require(!finalized); finalized = true; - - require(factory.isBuilded(msg.sender)); - require(ecrecover(keccak256(MSGPREFIX, keccak256(this, _agree)), _v, _r, _s) == validator); - - if (_agree) - require(token.transfer(promisor, cost)); - else - require(token.transfer(promisee, cost)); - - if (validatorFee > 0) - require(xrt.transfer(validator, validatorFee)); - require(xrt.transfer(tx.origin, xrt.balanceOf(this))); - } -} diff --git a/airalab-lighthouse/ethpm.json b/airalab-lighthouse/ethpm.json deleted file mode 100644 index f7e6694..0000000 --- a/airalab-lighthouse/ethpm.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "package_name": "airalab-lighthouse", - "version": "0.7.0", - "description": "Airalab lighthouse smart-contracts", - "authors": [ - "Alexander Krupenkin " - ], - "keywords": [ - "airalab", - "lighthouse", - "robonomics" - ], - "build_dependencies": { - "airalab-common": "ipfs://Qmc8dothLPPNfqiRp9nBjM7vgEqzC5T9D8LN52T6ePAgDd", - "airalab-token": "ipfs://QmU5c7HaGjNKWzeBWHN29VGSvpXqj75TsG5Ta2prctRXMQ" - }, - "license": "BSD-3" -} diff --git a/airalab-lighthouse/truffle.js b/airalab-lighthouse/truffle.js deleted file mode 100644 index 538e9d8..0000000 --- a/airalab-lighthouse/truffle.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - // See - // to customize your Truffle configuration! - networks: { - development: { - host: "127.0.0.1", - port: 8545, - network_id: "*" // Match any network id - }, - ropsten: { - host: "127.0.0.1", - port: 8545, - network_id: 3 // official id of the ropsten network - } - } -}; - diff --git a/airalab-token/contracts/Ambix.sol b/airalab-token/contracts/Ambix.sol deleted file mode 100644 index 54e9714..0000000 --- a/airalab-token/contracts/Ambix.sol +++ /dev/null @@ -1,108 +0,0 @@ -pragma solidity ^0.4.18; - -import './TokenEmission.sol'; -import {Object} from 'airalab-common/contracts/Object.sol'; - -/** - @dev Ambix contract is used for morph Token set to another - Token's by rule (recipe). In distillation process given - Token's are burned and result generated by emission. - - The recipe presented as equation in form: - (N1 * A1 | N'1 * A'1 | N''1 * A''1 ...) - & (N2 * A2 | N'2 * A'2 | N''2 * A''2 ...) ... - & (Nn * An | N'n * A'n | N''n * A''n ...) - = M1 * B1 & M2 * B2 ... & Mm * Bm - where A, B - input and output tokens - N, M - token value coeficients - n, m - input / output dimetion size - | - is alternative operator (logical OR) - & - is associative operator (logical AND) - This says that `Ambix` should receive (approve) left - part of equation and send (transfer) right part. -*/ -contract Ambix is Object { - /* Recipe fields */ - TokenEmission[][] public rSource; - uint[][] public rSourceCoef; - TokenEmission[] public rSink; - uint[] public rSinkCoef; - /* Recipe end */ - - /** - * @dev Set source by index - * @param _index is a source index - * @param _source is a list of source alternatives - * @param _coef is a list of source alternatives coeficients - */ - function setSource(uint _index, TokenEmission[] _source, uint[] _coef) public onlyOwner { - require (_source.length == _coef.length); - - // Lenght fix - if (rSource.length < _index + 1) { - rSource.length = _index + 1; - rSourceCoef.length = _index + 1; - } - - // Push values - delete rSource[_index]; - delete rSourceCoef[_index]; - for (uint i = 0; i < _source.length; ++i) { - rSource[_index].push(_source[i]); - rSourceCoef[_index].push(_coef[i]); - } - } - - /** - * @dev Set sink - * @param _sink is a list of sink tokens - * @param _coef is a list of sink coeficients - */ - function setSink(TokenEmission[] _sink, uint[] _coef) public onlyOwner { - require (_sink.length == _coef.length); - - delete rSink; - delete rSource; - for (uint i = 0; i < _sink.length; ++i) { - rSink.push(_sink[i]); - rSinkCoef.push(_coef[i]); - } - } - - /** - * @dev Run distillation process - * @notice Input tokens(any one of alternative) should be approved to this - */ - function run() public { - TokenEmission token; - uint value; - uint i; - uint j; - - // Take a source tokens - for (i = 0; i < rSource.length; ++i) { - bool tokenBurned = false; - - // Try to transfer alternatives and burn it - for (j = 0; j < rSource[i].length; ++j) { - token = rSource[i][j]; - value = rSourceCoef[i][j]; - if (token.transferFrom(msg.sender, this, value)) { - token.burn(value); - tokenBurned = true; - break; - } - } - - require (tokenBurned); - } - - // Generate sink tokens - for (i = 0; i < rSink.length; ++i) { - token = rSink[i]; - value = rSinkCoef[i]; - token.emission(value); - require (token.transfer(msg.sender, value)); - } - } -} diff --git a/airalab-token/contracts/ERC20.sol b/airalab-token/contracts/ERC20.sol deleted file mode 100644 index 99a607f..0000000 --- a/airalab-token/contracts/ERC20.sol +++ /dev/null @@ -1,42 +0,0 @@ -pragma solidity ^0.4.18; - -// Standard token interface (ERC 20) -// https://github.com/ethereum/EIPs/issues/20 -contract ERC20 -{ -// Functions: - /// @return total amount of tokens - uint256 public totalSupply; - - /// @param _owner The address from which the balance will be retrieved - /// @return The balance - function balanceOf(address _owner) public constant returns (uint256); - - /// @notice send `_value` token to `_to` from `msg.sender` - /// @param _to The address of the recipient - /// @param _value The amount of token to be transferred - /// @return Whether the transfer was successful or not - function transfer(address _to, uint256 _value) public returns (bool); - - /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` - /// @param _from The address of the sender - /// @param _to The address of the recipient - /// @param _value The amount of token to be transferred - /// @return Whether the transfer was successful or not - function transferFrom(address _from, address _to, uint256 _value) public returns (bool); - - /// @notice `msg.sender` approves `_addr` to spend `_value` tokens - /// @param _spender The address of the account able to transfer the tokens - /// @param _value The amount of wei to be approved for transfer - /// @return Whether the approval was successful or not - function approve(address _spender, uint256 _value) public returns (bool); - - /// @param _owner The address of the account owning tokens - /// @param _spender The address of the account able to transfer the tokens - /// @return Amount of remaining tokens allowed to spent - function allowance(address _owner, address _spender) public constant returns (uint256); - -// Events: - event Transfer(address indexed _from, address indexed _to, uint256 _value); - event Approval(address indexed _owner, address indexed _spender, uint256 _value); -} diff --git a/airalab-token/contracts/Recipient.sol b/airalab-token/contracts/Recipient.sol deleted file mode 100644 index aeff84c..0000000 --- a/airalab-token/contracts/Recipient.sol +++ /dev/null @@ -1,47 +0,0 @@ -pragma solidity ^0.4.18; - -import './ERC20.sol'; - -/** - * @title Asset recipient interface - */ -contract Recipient { - /** - * @dev On received ethers - * @param sender Ether sender - * @param amount Ether value - */ - event ReceivedEther(address indexed sender, - uint256 indexed amount); - - /** - * @dev On received custom ERC20 tokens - * @param from Token sender - * @param value Token value - * @param token Token contract address - * @param extraData Custom additional data - */ - event ReceivedTokens(address indexed from, - uint256 indexed value, - address indexed token, - bytes extraData); - - /** - * @dev Receive approved ERC20 tokens - * @param _from Spender address - * @param _value Transaction value - * @param _token ERC20 token contract address - * @param _extraData Custom additional data - */ - function receiveApproval(address _from, uint256 _value, - ERC20 _token, bytes _extraData) public { - require (_token.transferFrom(_from, this, _value)); - emit ReceivedTokens(_from, _value, _token, _extraData); - } - - /** - * @dev Catch sended to contract ethers - */ - function () public payable - { emit ReceivedEther(msg.sender, msg.value); } -} diff --git a/airalab-token/contracts/Token.sol b/airalab-token/contracts/Token.sol deleted file mode 100644 index f5be845..0000000 --- a/airalab-token/contracts/Token.sol +++ /dev/null @@ -1,119 +0,0 @@ -pragma solidity ^0.4.18; - -import {Object} from 'airalab-common/contracts/Object.sol'; -import './ERC20.sol'; - -/** - * @title Token contract represents any asset in digital economy. - */ -contract Token is Object, ERC20 { - - /** - * @dev Short description of token. - */ - string public name; - - /** - * @dev Token acronym (3-4 chars). - */ - string public symbol; - - /** - * @dev Fixed point position - */ - uint8 public decimals; - - /* Token approvement system */ - mapping(address => uint256) balances; - mapping(address => mapping(address => uint256)) allowances; - - /** - * @dev Token constructor - */ - function Token( - string _name, - string _symbol, - uint8 _decimals, - uint256 _count - ) public { - name = _name; - symbol = _symbol; - decimals = _decimals; - totalSupply = _count; - balances[msg.sender] = _count; - } - - /** - * @dev Get balance of plain address - * @param _owner is a target address - * @return amount of tokens on balance - */ - function balanceOf(address _owner) public view returns (uint256) - { return balances[_owner]; } - - /** - * @dev Take allowed tokens - * @param _owner The address of the account owning tokens - * @param _spender The address of the account able to transfer the tokens - * @return Amount of remaining tokens allowed to spent - */ - function allowance(address _owner, address _spender) public view returns (uint256) - { return allowances[_owner][_spender]; } - - /** - * @dev Transfer self tokens to given address - * @param _to destination address - * @param _value amount of token values to send - * @notice `_value` tokens will be sended to `_to` - * @return `true` when transfer done - */ - function transfer(address _to, uint256 _value) public returns (bool) { - if (balances[msg.sender] >= _value) { - balances[msg.sender] -= _value; - balances[_to] += _value; - emit Transfer(msg.sender, _to, _value); - return true; - } - return false; - } - - /** - * @dev Transfer with approvement mechainsm - * @param _from source address, `_value` tokens shold be approved for `sender` - * @param _to destination address - * @param _value amount of token values to send - * @notice from `_from` will be sended `_value` tokens to `_to` - * @return `true` when transfer is done - */ - function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { - uint256 avail = allowances[_from][msg.sender] - > balances[_from] ? balances[_from] - : allowances[_from][msg.sender]; - if (avail >= _value) { - allowances[_from][msg.sender] -= _value; - balances[_from] -= _value; - balances[_to] += _value; - emit Transfer(_from, _to, _value); - return true; - } - return false; - } - - /** - * @dev Give to target address ability for self token manipulation without sending - * @param _spender target address (future requester) - * @param _value amount of token values for approving - */ - function approve(address _spender, uint256 _value) public returns (bool) { - allowances[msg.sender][_spender] += _value; - emit Approval(msg.sender, _spender, _value); - return true; - } - - /** - * @dev Reset count of tokens approved for given address - * @param _spender target address (future requester) - */ - function unapprove(address _spender) public - { allowances[msg.sender][_spender] = 0; } -} diff --git a/airalab-token/contracts/TokenEmission.sol b/airalab-token/contracts/TokenEmission.sol deleted file mode 100644 index bfb51bf..0000000 --- a/airalab-token/contracts/TokenEmission.sol +++ /dev/null @@ -1,37 +0,0 @@ -pragma solidity ^0.4.18; - -import './Token.sol'; - -contract TokenEmission is Token { - function TokenEmission( - string _name, - string _symbol, - uint8 _decimals, - uint _start_count - ) public Token(_name, _symbol, _decimals, _start_count) {} - - /** - * @dev Token emission - * @param _value amount of token values to emit - * @notice owner balance will be increased by `_value` - */ - function emission(uint _value) public onlyOwner { - // Overflow check - require(_value + totalSupply > totalSupply); - - totalSupply += _value; - balances[owner] += _value; - } - - /** - * @dev Burn the token values from sender balance and from total - * @param _value amount of token values for burn - * @notice sender balance will be decreased by `_value` - */ - function burn(uint _value) public { - if (balances[msg.sender] >= _value) { - balances[msg.sender] -= _value; - totalSupply -= _value; - } - } -} diff --git a/airalab-token/contracts/TokenEther.sol b/airalab-token/contracts/TokenEther.sol deleted file mode 100644 index 2040f6a..0000000 --- a/airalab-token/contracts/TokenEther.sol +++ /dev/null @@ -1,43 +0,0 @@ -pragma solidity ^0.4.18; - -import './Token.sol'; - -/** - * @title Ethereum crypto currency extention for Token contract - */ -contract TokenEther is Token { - function TokenEther( - string _name, - string _symbol - ) public Token(_name, _symbol, 18, 0) {} - - /** - * @dev This is the way to withdraw money from token - * @param _value how many tokens withdraw from balance - */ - function withdraw(uint _value) public { - if (balances[msg.sender] >= _value) { - balances[msg.sender] -= _value; - totalSupply -= _value; - msg.sender.transfer(_value); - } - } - - /** - * @dev This is the way to refill your token balance by ethers - */ - function refill() public payable returns (bool) { - balances[msg.sender] += msg.value; - totalSupply += msg.value; - return true; - } - - /** - * @dev This method is called when money sended to contract address, - * a synonym for refill() - */ - function () public payable { - balances[msg.sender] += msg.value; - totalSupply += msg.value; - } -} diff --git a/airalab-token/ethpm.json b/airalab-token/ethpm.json deleted file mode 100644 index 464a882..0000000 --- a/airalab-token/ethpm.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "package_name": "airalab-token", - "version": "0.7.0", - "description": "Airalab token smart-contracts", - "authors": [ - "Alexander Krupenkin " - ], - "keywords": [ - "airalab", - "core", - "token", - "robonomics" - ], - "build_dependencies": { - "airalab-common": "ipfs://Qmc8dothLPPNfqiRp9nBjM7vgEqzC5T9D8LN52T6ePAgDd", - "airalab-token": "ipfs://QmU5c7HaGjNKWzeBWHN29VGSvpXqj75TsG5Ta2prctRXMQ" - }, - "license": "BSD-3" -} \ No newline at end of file diff --git a/airalab-token/truffle.js b/airalab-token/truffle.js deleted file mode 100644 index 51582a6..0000000 --- a/airalab-token/truffle.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - // See - // to customize your Truffle configuration! - networks: { - development: { - host: "127.0.0.1", - port: 8545, - network_id: "*" // Match any network id - }, - ropsten: { - host: "127.0.0.1", - port: 8545, - network_id: 3 // official id of the ropsten network - } - } -}; diff --git a/contracts/Migrations.sol b/contracts/Migrations.sol new file mode 100644 index 0000000..67e6ee9 --- /dev/null +++ b/contracts/Migrations.sol @@ -0,0 +1,23 @@ +pragma solidity ^0.4.24; + +contract Migrations { + address public owner; + uint public last_completed_migration; + + constructor() public { + owner = msg.sender; + } + + modifier restricted() { + if (msg.sender == owner) _; + } + + function setCompleted(uint completed) public restricted { + last_completed_migration = completed; + } + + function upgrade(address new_address) public restricted { + Migrations upgraded = Migrations(new_address); + upgraded.setCompleted(last_completed_migration); + } +} diff --git a/contracts/robonomics/LiabilityFactory.sol b/contracts/robonomics/LiabilityFactory.sol new file mode 100644 index 0000000..7abd5df --- /dev/null +++ b/contracts/robonomics/LiabilityFactory.sol @@ -0,0 +1,231 @@ +pragma solidity ^0.4.24; + +import './RobotLiability.sol'; +import './Lighthouse.sol'; +import './XRT.sol'; + +import 'ens/contracts/ENS.sol'; +import 'ens/contracts/ENSRegistry.sol'; +import 'ens/contracts/PublicResolver.sol'; + +contract LiabilityFactory { + constructor( + address _robot_liability_lib, + address _lighthouse_lib, + XRT _xrt + ) public { + robotLiabilityLib = _robot_liability_lib; + lighthouseLib = _lighthouse_lib; + xrt = _xrt; + } + + /** + * @dev New liability created + */ + event NewLiability(address indexed liability); + + /** + * @dev New lighthouse created + */ + event NewLighthouse(address indexed lighthouse, string name); + + /** + * @dev Robonomics network protocol token + */ + XRT public xrt; + + /** + * @dev Ethereum name system + */ + ENS public ens; + + /** + * @dev Robonomics ENS resolver + */ + PublicResolver public resolver; + + bytes32 constant lighthouseNode + // lighthouse.0.robonomics.eth + = 0x1e42a8e8e1e8cf36e83d096dcc74af801d0a194a14b897f9c8dfd403b4eebeda; + + /** + * @dev Set ENS registry contract address + */ + function setENS(ENS _ens) public { + require(address(ens) == 0); + ens = _ens; + resolver = PublicResolver(ens.resolver(lighthouseNode)); + } + + /** + * @dev Total GAS utilized by Robonomics network + */ + uint256 public totalGasUtilizing = 0; + + /** + * @dev GAS utilized by liability contracts + */ + mapping(address => uint256) public gasUtilizing; + + + /** + * @dev Used market orders accounting + */ + mapping(bytes32 => bool) public usedHash; + + /** + * @dev Lighthouse accounting + */ + mapping(address => bool) public isLighthouse; + + /** + * @dev Robot liability shared code smart contract + */ + address public robotLiabilityLib; + + /** + * @dev Lightouse shared code smart contract + */ + address public lighthouseLib; + + /** + * @dev XRT emission value for utilized gas + */ + function winnerFromGas(uint256 _gas) public view returns (uint256) { + // Basic equal formula + uint256 wn = _gas; + + /* Additional emission table */ + if (totalGasUtilizing < 347 * (10 ** 10)) { + wn *= 6; + } else if (totalGasUtilizing < 2 * 347 * (10 ** 10)) { + wn *= 4; + } else if (totalGasUtilizing < 3 * 347 * (10 ** 10)) { + wn = wn * 2667 / 1000; + } else if (totalGasUtilizing < 4 * 347 * (10 ** 10)) { + wn = wn * 1778 / 1000; + } else if (totalGasUtilizing < 5 * 347 * (10 ** 10)) { + wn = wn * 1185 / 1000; + } + + return wn ; + } + + /** + * @dev Only lighthouse guard + */ + modifier onlyLighthouse { + require(isLighthouse[msg.sender]); + _; + } + + /** + * @dev Parameter can be used only once + * @param _hash Single usage hash + */ + function usedHashGuard(bytes32 _hash) internal { + require(!usedHash[_hash]); + usedHash[_hash] = true; + } + + /** + * @dev Create robot liability smart contract + * @param _ask ABI-encoded ASK order message + * @param _bid ABI-encoded BID order message + */ + function createLiability( + bytes _ask, + bytes _bid + ) + external + onlyLighthouse + returns (RobotLiability liability) + { + // Store in memory available gas + uint256 gasinit = gasleft(); + + // Create liability + liability = new RobotLiability(robotLiabilityLib); + emit NewLiability(liability); + + // Parse messages + require(liability.call(abi.encodePacked(bytes4(0x82fbaa25), _ask))); // liability.ask(...) + usedHashGuard(liability.askHash()); + + require(liability.call(abi.encodePacked(bytes4(0x66193359), _bid))); // liability.bid(...) + usedHashGuard(liability.bidHash()); + + // Transfer lighthouse fee to lighthouse worker directly + require(xrt.transferFrom(liability.promisor(), + tx.origin, + liability.lighthouseFee())); + + // Transfer liability security and hold on contract + ERC20 token = liability.token(); + require(token.transferFrom(liability.promisee(), + liability, + liability.cost())); + + // Transfer validator fee and hold on contract + if (address(liability.validator()) != 0 && liability.validatorFee() > 0) + require(xrt.transferFrom(liability.promisee(), + liability, + liability.validatorFee())); + + // Accounting gas usage of transaction + uint256 gas = gasinit - gasleft() + 110525; // Including observation error + totalGasUtilizing += gas; + gasUtilizing[liability] += gas; + } + + /** + * @dev Create lighthouse smart contract + * @param _minimalFreeze Minimal freeze value of XRT token + * @param _timeoutBlocks Max time of lighthouse silence in blocks + * @param _name Lighthouse subdomain, + * example: for 'my-name' will created 'my-name.lighthouse.0.robonomics.eth' domain + */ + function createLighthouse( + uint256 _minimalFreeze, + uint256 _timeoutBlocks, + string _name + ) + external + returns (address lighthouse) + { + // Name reservation check + bytes32 subnode = keccak256(abi.encodePacked(lighthouseNode, keccak256(_name))); + require(ens.resolver(subnode) == 0); + + // Create lighthouse + lighthouse = new Lighthouse(lighthouseLib, _minimalFreeze, _timeoutBlocks); + emit NewLighthouse(lighthouse, _name); + isLighthouse[lighthouse] = true; + + // Register subnode + ens.setSubnodeOwner(lighthouseNode, keccak256(_name), this); + + // Register lighthouse address + ens.setResolver(subnode, resolver); + resolver.setAddr(subnode, lighthouse); + } + + /** + * @dev Is called whan after liability finalization + * @param _gas Liability finalization gas expenses + */ + function liabilityFinalized( + uint256 _gas + ) + external + returns (bool) + { + require(gasUtilizing[msg.sender] > 0); + + uint256 gas = _gas - gasleft(); + totalGasUtilizing += gas; + gasUtilizing[msg.sender] += gas; + require(xrt.mint(tx.origin, winnerFromGas(gasUtilizing[msg.sender]))); + return true; + } +} diff --git a/contracts/robonomics/LightContract.sol b/contracts/robonomics/LightContract.sol new file mode 100644 index 0000000..911e77c --- /dev/null +++ b/contracts/robonomics/LightContract.sol @@ -0,0 +1,16 @@ +pragma solidity ^0.4.24; + +contract LightContract { + /** + * @dev Shared code smart contract + */ + address lib; + + constructor(address _library) public { + lib = _library; + } + + function() public { + require(lib.delegatecall(msg.data)); + } +} diff --git a/contracts/robonomics/Lighthouse.sol b/contracts/robonomics/Lighthouse.sol new file mode 100644 index 0000000..50de674 --- /dev/null +++ b/contracts/robonomics/Lighthouse.sol @@ -0,0 +1,20 @@ +pragma solidity ^0.4.24; + +import './LighthouseAPI.sol'; +import './LightContract.sol'; + +contract Lighthouse is LighthouseAPI, LightContract { + constructor( + address _lib, + uint256 _minimalFreeze, + uint256 _timeoutBlocks + ) + public + LightContract(_lib) + { + minimalFreeze = _minimalFreeze; + timeoutBlocks = _timeoutBlocks; + factory = LiabilityFactory(msg.sender); + xrt = factory.xrt(); + } +} diff --git a/contracts/robonomics/LighthouseABI.sol b/contracts/robonomics/LighthouseABI.sol new file mode 100644 index 0000000..6c1505c --- /dev/null +++ b/contracts/robonomics/LighthouseABI.sol @@ -0,0 +1,8 @@ +pragma solidity ^0.4.24; + +contract LighthouseABI { + function refill(uint256 _value) external; + function withdraw(uint256 _value) external; + function to(address _to, bytes _data) external; + function () external; +} diff --git a/airalab-lighthouse/contracts/LighthouseAPI.sol b/contracts/robonomics/LighthouseAPI.sol similarity index 54% rename from airalab-lighthouse/contracts/LighthouseAPI.sol rename to contracts/robonomics/LighthouseAPI.sol index 8ac1451..704ff47 100644 --- a/airalab-lighthouse/contracts/LighthouseAPI.sol +++ b/contracts/robonomics/LighthouseAPI.sol @@ -1,4 +1,7 @@ -pragma solidity ^0.4.18; +pragma solidity ^0.4.24; + +import './LiabilityFactory.sol'; +import './XRT.sol'; contract LighthouseAPI { address[] public members; @@ -8,9 +11,14 @@ contract LighthouseAPI { uint256 public minimalFreeze; uint256 public timeoutBlocks; - address public factory; + + LiabilityFactory public factory; + XRT public xrt; uint256 public keepaliveBlock = 0; uint256 public marker = 0; uint256 public quota = 0; + + function quotaOf(address _member) public view returns (uint256) + { return balances[_member] / minimalFreeze; } } diff --git a/airalab-lighthouse/contracts/LighthouseLib.sol b/contracts/robonomics/LighthouseLib.sol similarity index 68% rename from airalab-lighthouse/contracts/LighthouseLib.sol rename to contracts/robonomics/LighthouseLib.sol index 53c7f11..846bb8a 100644 --- a/airalab-lighthouse/contracts/LighthouseLib.sol +++ b/contracts/robonomics/LighthouseLib.sol @@ -1,17 +1,12 @@ -pragma solidity ^0.4.18; +pragma solidity ^0.4.24; import './LighthouseAPI.sol'; import './LighthouseABI.sol'; -import './Factory.sol'; +import './LiabilityFactory.sol'; contract LighthouseLib is LighthouseAPI, LighthouseABI { - function quotaOf(address _member) public view returns (uint256) - { return balances[_member] / minimalFreeze; } - - function refill(uint256 _value) public { - ERC20 xrt = Factory(factory).xrt(); - + function refill(uint256 _value) external { require(xrt.transferFrom(msg.sender, this, _value)); require(_value >= minimalFreeze); @@ -22,9 +17,7 @@ contract LighthouseLib is LighthouseAPI, LighthouseABI { balances[msg.sender] += _value; } - function withdraw(uint256 _value) public { - ERC20 xrt = Factory(factory).xrt(); - + function withdraw(uint256 _value) external { require(balances[msg.sender] >= _value); require(xrt.transfer(msg.sender, _value)); @@ -45,8 +38,7 @@ contract LighthouseLib is LighthouseAPI, LighthouseABI { function nextMember() internal { marker = (marker + 1) % members.length; - quota = quotaOf(members[marker]); - keepaliveBlock = block.number; + quota = balances[members[marker]] / minimalFreeze; } modifier quoted { @@ -57,13 +49,9 @@ contract LighthouseLib is LighthouseAPI, LighthouseABI { } modifier keepalive { - if (timeoutBlocks < block.number - keepaliveBlock) { - nextMember(); - - // The main reason why here used 'while' is deadlock if two members is unavailable + if (timeoutBlocks < block.number - keepaliveBlock) while (msg.sender != members[marker]) nextMember(); - } _; } @@ -71,13 +59,14 @@ contract LighthouseLib is LighthouseAPI, LighthouseABI { modifier member { require(members.length > 0); require(msg.sender == members[marker]); + keepaliveBlock = block.number; _; } - function to(address _to, bytes _data) public quoted keepalive member + function to(address _to, bytes _data) external keepalive quoted member { require(_to.call(_data)); } - function () public quoted keepalive member + function () external keepalive quoted member { require(factory.call(msg.data)); } } diff --git a/contracts/robonomics/RobotLiability.sol b/contracts/robonomics/RobotLiability.sol new file mode 100644 index 0000000..5036e61 --- /dev/null +++ b/contracts/robonomics/RobotLiability.sol @@ -0,0 +1,10 @@ +pragma solidity ^0.4.24; + +import './RobotLiabilityAPI.sol'; +import './LightContract.sol'; + +// Standard robot liability light contract +contract RobotLiability is RobotLiabilityAPI, LightContract { + constructor(address _lib) public LightContract(_lib) + { factory = LiabilityFactory(msg.sender); } +} diff --git a/contracts/robonomics/RobotLiabilityABI.sol b/contracts/robonomics/RobotLiabilityABI.sol new file mode 100644 index 0000000..899209b --- /dev/null +++ b/contracts/robonomics/RobotLiabilityABI.sol @@ -0,0 +1,40 @@ +pragma solidity ^0.4.24; + +import "./XRT.sol"; + +contract RobotLiabilityABI { + function ask( + bytes _model, + bytes _objective, + + ERC20 _token, + uint256 _cost, + + address _validator, + uint256 _validator_fee, + + uint256 _deadline, + bytes32 _nonce, + bytes _signature + ) external returns (bool); + + function bid( + bytes _model, + bytes _objective, + + ERC20 _token, + uint256 _cost, + + uint256 _lighthouse_fee, + + uint256 _deadline, + bytes32 _nonce, + bytes _signature + ) external returns (bool); + + function finalize( + bytes _result, + bytes _signature, + bool _agree + ) external returns (bool); +} diff --git a/contracts/robonomics/RobotLiabilityAPI.sol b/contracts/robonomics/RobotLiabilityAPI.sol new file mode 100644 index 0000000..24582c5 --- /dev/null +++ b/contracts/robonomics/RobotLiabilityAPI.sol @@ -0,0 +1,29 @@ +pragma solidity ^0.4.24; + +import './LiabilityFactory.sol'; +import './XRT.sol'; + +contract RobotLiabilityAPI { + bytes public model; + bytes public objective; + bytes public result; + + XRT public xrt; + ERC20 public token; + + uint256 public cost; + uint256 public lighthouseFee; + uint256 public validatorFee; + + bytes32 public askHash; + bytes32 public bidHash; + + address public promisor; + address public promisee; + address public validator; + + bool public isConfirmed; + bool public isFinalized; + + LiabilityFactory public factory; +} diff --git a/contracts/robonomics/RobotLiabilityLib.sol b/contracts/robonomics/RobotLiabilityLib.sol new file mode 100644 index 0000000..28b6f5c --- /dev/null +++ b/contracts/robonomics/RobotLiabilityLib.sol @@ -0,0 +1,141 @@ +pragma solidity ^0.4.24; + +import 'openzeppelin-solidity/contracts/ECRecovery.sol'; +import './RobotLiabilityABI.sol'; +import './RobotLiabilityAPI.sol'; + +contract RobotLiabilityLib is RobotLiabilityABI + , RobotLiabilityAPI { + using ECRecovery for bytes32; + + function ask( + bytes _model, + bytes _objective, + + ERC20 _token, + uint256 _cost, + + address _validator, + uint256 _validator_fee, + + uint256 _deadline, + bytes32 _nonce, + bytes _signature + ) + external + returns (bool) + { + require(msg.sender == address(factory)); + require(block.number < _deadline); + + model = _model; + objective = _objective; + token = _token; + cost = _cost; + validator = _validator; + validatorFee = _validator_fee; + + askHash = keccak256(abi.encodePacked( + _model + , _objective + , _token + , _cost + , _validator + , _validator_fee + , _deadline + , _nonce + )); + + promisee = askHash + .toEthSignedMessageHash() + .recover(_signature); + return true; + } + + function bid( + bytes _model, + bytes _objective, + + ERC20 _token, + uint256 _cost, + + uint256 _lighthouse_fee, + + uint256 _deadline, + bytes32 _nonce, + bytes _signature + ) + external + returns (bool) + { + require(msg.sender == address(factory)); + require(block.number < _deadline); + require(keccak256(abi.encodePacked(model, objective)) + == keccak256(abi.encodePacked(_model, _objective))); + require(_token == token); + require(_cost == _cost); + + lighthouseFee = _lighthouse_fee; + + bidHash = keccak256(abi.encodePacked( + _model + , _objective + , _token + , _cost + , _lighthouse_fee + , _deadline + , _nonce + )); + + promisor = bidHash + .toEthSignedMessageHash() + .recover(_signature); + return true; + } + + /** + * @dev Finalize this liability + * @param _result Result data hash + * @param _agree Validation network confirmation + * @param _signature Result sender signature + */ + function finalize( + bytes _result, + bytes _signature, + bool _agree + ) + external + returns (bool) + { + uint256 gasinit = gasleft(); + + require(!isFinalized); + + address resultSender = keccak256(abi.encodePacked(this, _result)) + .toEthSignedMessageHash() + .recover(_signature); + require(resultSender == promisor); + + if (validator == 0) { + require(factory.isLighthouse(msg.sender)); + require(token.transfer(promisor, cost)); + } else { + require(msg.sender == validator); + + isConfirmed = _agree; + if (isConfirmed) + require(token.transfer(promisor, cost)); + else + require(token.transfer(promisee, cost)); + + if (validatorFee > 0) + require(xrt.transfer(validator, validatorFee)); + } + + result = _result; + isFinalized = true; + + require(factory.liabilityFinalized(gasinit)); + return true; + } +} diff --git a/contracts/robonomics/XRT.sol b/contracts/robonomics/XRT.sol new file mode 100644 index 0000000..47c271d --- /dev/null +++ b/contracts/robonomics/XRT.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.4.24; + +import 'openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol'; +import 'openzeppelin-solidity/contracts/token/ERC20/BurnableToken.sol'; + +contract XRT is MintableToken, BurnableToken { + string public constant name = "Robonomics Token :: Kovan"; + string public constant symbol = "XRT"; + uint public constant decimals = 9; + + uint256 public constant INITIAL_SUPPLY = 5 * (10 ** uint256(decimals)); + + constructor() public { + totalSupply_ = INITIAL_SUPPLY; + balances[msg.sender] = INITIAL_SUPPLY; + emit Transfer(0x0, msg.sender, INITIAL_SUPPLY); + } +} diff --git a/ens b/ens new file mode 160000 index 0000000..273797b --- /dev/null +++ b/ens @@ -0,0 +1 @@ +Subproject commit 273797bc0aab5037dd786c6d301d25f406ed8a95 diff --git a/ethpm.json b/ethpm.json new file mode 100644 index 0000000..8a19bbe --- /dev/null +++ b/ethpm.json @@ -0,0 +1,19 @@ +{ + "package-name": "robonomics_contracts", + "version": "0.9.0", + "description": "Robonomics platform contracts", + "authors": [ + "Alexander Krupenkin ", + "Sergey Lonshakov " + ], + "keywords": [ + "robonomics", + "contracts", + "ethereum", + "solidity", + "airalab" + ], + "dependencies": { + }, + "license": "BSD3" +} diff --git a/migrations/1_initial_migration.js b/migrations/1_initial_migration.js new file mode 100644 index 0000000..ee2135d --- /dev/null +++ b/migrations/1_initial_migration.js @@ -0,0 +1,5 @@ +const Migrations = artifacts.require("Migrations"); + +module.exports = function(deployer) { + deployer.deploy(Migrations); +}; diff --git a/migrations/2_factory_migration.js b/migrations/2_factory_migration.js new file mode 100644 index 0000000..a9da122 --- /dev/null +++ b/migrations/2_factory_migration.js @@ -0,0 +1,17 @@ +const RobotLiabilityLib = artifacts.require("RobotLiabilityLib"); +const LighthouseLib = artifacts.require("LighthouseLib"); + +const LiabilityFactory = artifacts.require("LiabilityFactory"); +const XRT = artifacts.require("XRT"); + +module.exports = (deployer, network, accounts) => { + deployer.deploy(RobotLiabilityLib).then(a => { + return deployer.deploy(LighthouseLib).then(b => { + return deployer.deploy(XRT).then(c => { + return deployer.deploy(LiabilityFactory, a.address, b.address, c.address).then(d => { + return c.transferOwnership(d.address); + }); + }); + }); + }); +}; diff --git a/migrations/3_ens_migration.js b/migrations/3_ens_migration.js new file mode 100644 index 0000000..ee0f33c --- /dev/null +++ b/migrations/3_ens_migration.js @@ -0,0 +1,56 @@ +const XRT = artifacts.require("XRT"); +const ENSRegistry = artifacts.require("ENSRegistry"); +const PublicResolver = artifacts.require("PublicResolver"); +const LiabilityFactory = artifacts.require("LiabilityFactory"); + +const namehash = require('eth-ens-namehash'); +const sha3 = require('web3-utils').sha3; + +const robonomicsGen = "0"; +const robonomicsRoot = robonomicsGen+".robonomics.eth"; + +function regNames(deployer, ens, accounts) { + let resolver + return deployer.deploy(PublicResolver, ens.address) + .then((r) => { + resolver = r + return ens.setSubnodeOwner(namehash("robonomics.eth"), sha3(robonomicsGen), accounts[0]) + }) + .then(() => { + return Promise.all([ + ens.setSubnodeOwner(namehash(robonomicsRoot), sha3("xrt"), accounts[0]), + ens.setSubnodeOwner(namehash(robonomicsRoot), sha3("factory"), accounts[0]), + ens.setSubnodeOwner(namehash(robonomicsRoot), sha3("lighthouse"), accounts[0]) + ]); + }).then(() => { return Promise.all([ + ens.setResolver(namehash(robonomicsRoot), resolver.address), + ens.setResolver(namehash("xrt."+robonomicsRoot), resolver.address), + ens.setResolver(namehash("factory."+robonomicsRoot), resolver.address), + ens.setResolver(namehash("lighthouse."+robonomicsRoot), resolver.address), + resolver.setAddr(namehash("xrt."+robonomicsRoot), XRT.address), + resolver.setAddr(namehash("factory."+robonomicsRoot), LiabilityFactory.address) + ]); + }).then(() => { + return ens.setSubnodeOwner(namehash(robonomicsRoot), sha3("lighthouse"), LiabilityFactory.address); + }).then(() => { + return LiabilityFactory.at(LiabilityFactory.address).setENS(ens.address); + }); +} + +module.exports = function(deployer, network, accounts) { + + if (network === 'development') { + deployer.deploy(ENSRegistry).then(ens => { + return ens.setSubnodeOwner('0x0', sha3("eth"), accounts[0]).then(() => { + return ens.setSubnodeOwner(namehash("eth"), sha3("robonomics"), accounts[0]).then(() => { + return regNames(deployer, ens, accounts); + }); + }); + }).catch(e => { + console.log("Error: "+e); + }); + } else { + regNames(deployer, ENSRegistry.at('0x314159265dD8dbb310642f98f50C066173C1259b'), accounts); + }; + +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..0e95b22 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "robonomics_contracts", + "version": "0.9.0", + "homepage": "https://github.com/airalab/robonomics_contracts#readme", + "description": "Robonomics platform smart contracts", + "main": "truffle.js", + "directories": { + "ens": "ens", + "test": "test" + }, + "scripts": { + "test": "truffle test" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/airalab/robonomics_contracts.git" + }, + "keywords": [ + "robonomics", + "contracts", + "ethereum", + "solidity", + "airalab" + ], + "dependencies": { + "truffle": "^4.0.0", + "openzeppelin-solidity": "1.9.0", + "eth-ens-namehash": "^1.0.2", + "ethereum-ens": "^0.7.4", + "web3-eth-abi": "^1.0.0-beta.34", + "web3-utils": "^1.0.0-beta.34" + }, + "author": "Airalab ", + "license": "BSD-3-Clause" +} diff --git a/securityCheck/runCheck.py b/securityCheck/runCheck.py deleted file mode 100755 index 94d005e..0000000 --- a/securityCheck/runCheck.py +++ /dev/null @@ -1,207 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf8 -*- - -import sys, os.path - -class cached_property: - """ - A property that is only computed once per instance and then replaces itself - with an ordinary attribute. Deleting the attribute resets the property. - Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76 - """ # noqa - - def __init__(self, func): - self.__doc__ = getattr(func, '__doc__') - self.func = func - - def __get__(self, obj, cls): - if obj is None: - return self - value = obj.__dict__[self.func.__name__] = self.func(obj) - return value - -def cli_input(text, variants): - while True: - print('\n'+text) - for v in variants: - print('> [{0}]: {1}'.format(v.key, v)) - - default = variants[0] - answer = input('Select [{0}]: '.format(default.key)) - - result = list(filter(lambda x: x.key == answer, variants)) - if len(result) > 0: - return result[0] - elif answer == '': - return default - else: - print('`{0}` is not in variants [0..{1}]'.format(answer, len(variants))) - -class Img: - class Good: - def __str__(self): - return '![good](https://cdn.rawgit.com/primer/octicons/master/build/svg/check.svg)' - - class Warning: - def __str__(self): - return '![warning](https://cdn.rawgit.com/primer/octicons/master/build/svg/issue-opened.svg)' - - class Danger: - def __str__(self): - return '![danger](https://cdn.rawgit.com/primer/octicons/master/build/svg/flame.svg)' - -class Opt: - def __init__(self, key, img, txt): - self.key = key - self.img = img - self.txt = txt - - def __str__(self): - return self.txt - -class Contract: - def __init__(self, fname): - pkgdir, self.name = os.path.split(fname) - _, self.package = os.path.split(pkgdir) - self.name = self.name[:-4] - -class Recomendations: - @cached_property - def external_calls(self): - return cli_input('Внешние вызовы:', \ - [ Opt('1', Img.Danger(), 'в большом количестве') \ - , Opt('2', Img.Warning(), 'немного') \ - , Opt('3', Img.Good(), 'отсутствуют') \ - ]) - - @cached_property - def state_over_call(self): - return cli_input('Состояние контракта:', \ - [ Opt('1', Img.Danger(), 'не меняется, внешний вызов управляет логикой контракта') \ - , Opt('2', Img.Warning(), 'меняется, логика зависит от внешних вызовов и состояния') \ - , Opt('3', Img.Good(), 'логика работы зависит только от состояния') \ - ]) - - @cached_property - def extcall_isolate(self): - return cli_input('Внешние вызовы:', \ - [ Opt('1', Img.Danger(), 'смешаны с логикой работы контракта') \ - , Opt('2', Img.Warning(), 'вызываются в конце метода') \ - , Opt('3', Img.Good(), 'вынесены в отдельные методы') \ - ]) - - @cached_property - def integer_div(self): - return cli_input('Целочисленное деление:', \ - [ Opt('y', Img.Warning(), 'присутствует') \ - , Opt('n', Img.Good(), 'отсутствует или используется множитель') \ - ]) - - @cached_property - def zero_div(self): - return cli_input('Проверка на ноль в качестве делителя:', \ - [ Opt('n', Img.Danger(), 'отсутствует') \ - , Opt('y', Img.Good(), 'присутствует') - ]) - - @cached_property - def var_overlflow(self): - return cli_input('Проверка на переполнение переменных при арифметических операциях:', \ - [ Opt('n', Img.Danger(), 'отсутствует') \ - , Opt('y', Img.Warning(),'только при присваивании') \ - , Opt('Y', Img.Good(), 'при любом использовании') - ]) - - @cached_property - def array_iteration(self): - return cli_input('Перебор динамических массивов:', \ - [ Opt('1', Img.Danger(), 'неконтролируемый перебор') - , Opt('2', Img.Warning(), 'присутсвует, расход газа контролируется') \ - , Opt('3', Img.Good(), 'отсутствует либо число итераций постоянно') \ - ]) - - - @cached_property - def timestamp_logic(self): - return cli_input('Логика работы контракта зависит от метки времени блока?', \ - [ Opt('y', Img.Warning(), 'да') \ - , Opt('n', Img.Good(), 'нет') - ]) - - @cached_property - def data_migration(self): - return cli_input('Предусмотрен ли перенос данных контракта?', \ - [ Opt('y', Img.Good(), 'да') \ - , Opt('n', Img.Warning(), 'нет') - ]) - - @cached_property - def emergency_breaks(self): - return cli_input('Присутствуют точки экстренного останова?', \ - [ Opt('y', Img.Good(), 'да') \ - , Opt('n', Img.Warning(), 'нет') - ]) - - @cached_property - def time_breaks(self): - return cli_input('Критически важные действия принудительно разнесены во времени?', \ - [ Opt('y', Img.Good(), 'да') \ - , Opt('n', Img.Warning(), 'нет') - ]) - - @cached_property - def formal_verify(self): - return cli_input('Проведена формальная верификация контракта?', \ - [ Opt('y', Img.Good(), 'да') \ - , Opt('n', Img.Warning(), 'нет') - ]) - -class Attacks: - def __init__(self, recs): - self.r = recs - - @property - def depth_stack(self): - result = 0 - result += int(self.r.external_calls.key) - result += int(self.r.state_over_call.key) - result += int(self.r.extcall_isolate.key) - result /= 3.0 - if result < 2: - return Img.Danger() - elif result < 3: - return Img.Warning() - else: - return Img.Good() - - @property - def race_condition(self): - return self.r.extcall_isolate.img - - @property - def dos_throw(self): - return self.r.extcall_isolate.img - - @property - def dos_gas_limit(self): - result = 0 - result += int(self.r.array_iteration.key) - result += int(self.r.extcall_isolate.key) - result /= 2.0 - if result < 2: - return Img.Danger() - elif result < 3: - return Img.Warning() - else: - return Img.Good() - -def main(): - template = open('template.md', 'r').read() - c = Contract(sys.argv[1]) - r = Recomendations() - a = Attacks(r) - md = template.format(contract=c, recs=r, att=a) - open('{0}_{1}.md'.format(c.package, c.name), 'w').write(md) - -if __name__ == '__main__': - main() diff --git a/securityCheck/template.md b/securityCheck/template.md deleted file mode 100644 index 7435ee9..0000000 --- a/securityCheck/template.md +++ /dev/null @@ -1,39 +0,0 @@ -# Smart contract {contract.name} security check - -- Семейство контрактов: [Aira DAO Core][1] -- Исходный код контракта: [{contract.name}.sol](https://github.com/airalab/core/master/sol/{contract.package}/{contract.name}.sol) - -## Проверка общих [рекомендаций Airalab][2] - -| № | Описание | | -|---|:-----------------------------------------------------|:--------------------------:| -| 1 | Внешние вызовы | {recs.external_calls.img} | -| 2 | Изоляция внешних вызовов в отдельной транзакции | {recs.extcall_isolate.img} | -| 3 | Деление целых чисел | {recs.integer_div.img} | -| 4 | Деление на ноль | {recs.zero_div.img} | -| 5 | Переполнение переменных | {recs.var_overlflow.img} | -| 6 | Приоритет изменения состояния над внешним вызовом | {recs.state_over_call.img} | -| 7 | Перебор динамических массивов | {recs.array_iteration.img} | -| 8 | Привязка логики работы к метке времени | {recs.timestamp_logic.img} | -| 9 | Миграция данных контракта | {recs.data_migration.img} | -|10 | Метки остановки работы | {recs.emergency_breaks.img}| -|11 | Метки задежки по времени | {recs.time_breaks.img} | -|12 | Формальная верификация | {recs.formal_verify.img} | - - -## Известные атаки на контракты Ethereum платформы - -| № | Описание | | -|---|:-----------------------------------------------------|:-------------------:| -| 1 | Атака по глубине стека | {att.depth_stack} | -| 2 | Условия гонки | {att.race_condition}| -| 3 | DoS при исключении в стороннем коде | {att.dos_throw} | -| 4 | DoS при выходе за лимит газа | {att.dos_gas_limit} | - -## Проверка на известные атаки - -## Комментарии по коду - - -[1]: https://github.com/airalab/core -[2]: https://github.com/airalab diff --git a/securityCheck/token_Token.md b/securityCheck/token_Token.md deleted file mode 100644 index 3d97b65..0000000 --- a/securityCheck/token_Token.md +++ /dev/null @@ -1,46 +0,0 @@ -# Smart contract Token security check - -- Семейство контрактов: [Aira DAO Core][1] -- Исходный код контракта: [Token.sol](https://github.com/airalab/core/62c672732695b6429678bcd321520c41af109475/sol/token/Token.sol) - -## Проверка общих [рекомендаций Airalab][2] - -| № | Описание | | -|---|:-----------------------------------------------------|:--------------------------:| -| 1 | Внешние вызовы | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 2 | Изоляция внешних вызовов в отдельной транзакции | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 3 | Деление целых чисел | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 4 | Деление на ноль | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 5 | Переполнение переменных | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 6 | Приоритет изменения состояния над внешним вызовом | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 7 | Перебор динамических массивов | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 8 | Привязка логики работы к метке времени | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 9 | Миграция данных контракта | ![warning](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/issue-opened.svg) | -|10 | Метки остановки работы | ![warning](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/issue-opened.svg)| -|11 | Метки задежки по времени | ![warning](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/issue-opened.svg) | -|12 | Формальная верификация | ![warning](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/issue-opened.svg) | - - -## Известные атаки на контракты Ethereum платформы - -| № | Описание | | -|---|:-----------------------------------------------------|:-------------------:| -| 1 | Атака по глубине стека | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 2 | Условия гонки | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg)| -| 3 | DoS при исключении в стороннем коде | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 4 | DoS при выходе за лимит газа | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | - -## Проверка на известные атаки - -## Комментарии по коду - - -``` -modifier onlyOwner { if (msg.sender != owner) throw; _ } -``` -*Бросать исключение предпочтительнее для кода, инициирующего вызов* - -Source: [common/Owned.sol#L27](https://github.com/airalab/core/blob/62c672732695b6429678bcd321520c41af109475/sol/common/Owned.sol#L27) - -[1]: https://github.com/airalab/core -[2]: https://github.com/airalab diff --git a/securityCheck/token_TokenEmission.md b/securityCheck/token_TokenEmission.md deleted file mode 100644 index fd1c1c7..0000000 --- a/securityCheck/token_TokenEmission.md +++ /dev/null @@ -1,39 +0,0 @@ -# Smart contract TokenEmission security check - -- Семейство контрактов: [Aira DAO Core][1] -- Исходный код контракта: [TokenEmission.sol](https://github.com/airalab/core/62c672732695b6429678bcd321520c41af109475/sol/token/TokenEmission.sol) - -## Проверка общих [рекомендаций Airalab][2] - -| № | Описание | | -|---|:-----------------------------------------------------|:--------------------------:| -| 1 | Внешние вызовы | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 2 | Изоляция внешних вызовов в отдельной транзакции | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 3 | Деление целых чисел | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 4 | Деление на ноль | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 5 | Переполнение переменных | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 6 | Приоритет изменения состояния над внешним вызовом | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 7 | Перебор динамических массивов | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 8 | Привязка логики работы к метке времени | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 9 | Миграция данных контракта | ![warning](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/issue-opened.svg) | -|10 | Метки остановки работы | ![warning](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/issue-opened.svg)| -|11 | Метки задежки по времени | ![warning](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/issue-opened.svg) | -|12 | Формальная верификация | ![warning](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/issue-opened.svg) | - - -## Известные атаки на контракты Ethereum платформы - -| № | Описание | | -|---|:-----------------------------------------------------|:-------------------:| -| 1 | Атака по глубине стека | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 2 | Условия гонки | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg)| -| 3 | DoS при исключении в стороннем коде | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 4 | DoS при выходе за лимит газа | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | - -## Проверка на известные атаки - -## Комментарии по коду - - -[1]: https://github.com/airalab/core -[2]: https://github.com/airalab diff --git a/securityCheck/token_TokenEther.md b/securityCheck/token_TokenEther.md deleted file mode 100644 index 01d2463..0000000 --- a/securityCheck/token_TokenEther.md +++ /dev/null @@ -1,39 +0,0 @@ -# Smart contract TokenEther security check - -- Семейство контрактов: [Aira DAO Core][1] -- Исходный код контракта: [TokenEther.sol](https://github.com/airalab/core/62c672732695b6429678bcd321520c41af109475/sol/token/TokenEther.sol) - -## Проверка общих [рекомендаций Airalab][2] - -| № | Описание | | -|---|:-----------------------------------------------------|:--------------------------:| -| 1 | Внешние вызовы | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 2 | Изоляция внешних вызовов в отдельной транзакции | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 3 | Деление целых чисел | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 4 | Деление на ноль | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 5 | Переполнение переменных | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 6 | Приоритет изменения состояния над внешним вызовом | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 7 | Перебор динамических массивов | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 8 | Привязка логики работы к метке времени | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 9 | Миграция данных контракта | ![warning](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/issue-opened.svg) | -|10 | Метки остановки работы | ![warning](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/issue-opened.svg)| -|11 | Метки задежки по времени | ![warning](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/issue-opened.svg) | -|12 | Формальная верификация | ![warning](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/issue-opened.svg) | - - -## Известные атаки на контракты Ethereum платформы - -| № | Описание | | -|---|:-----------------------------------------------------|:-------------------:| -| 1 | Атака по глубине стека | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 2 | Условия гонки | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg)| -| 3 | DoS при исключении в стороннем коде | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | -| 4 | DoS при выходе за лимит газа | ![good](https://cdn.rawgit.com/primer/octicons/62c672732695b6429678bcd321520c41af109475/build/svg/check.svg) | - -## Проверка на известные атаки - -## Комментарии по коду - - -[1]: https://github.com/airalab/core -[2]: https://github.com/airalab diff --git a/test/LiabilityFactory.test.js b/test/LiabilityFactory.test.js new file mode 100644 index 0000000..d2d246e --- /dev/null +++ b/test/LiabilityFactory.test.js @@ -0,0 +1,39 @@ +const LiabilityFactory = artifacts.require("LiabilityFactory"); +const ENSRegistry = artifacts.require("ENSRegistry"); +const RobotLiabilityLib = artifacts.require("RobotLiabilityLib"); +const LighthouseLib = artifacts.require("LighthouseLib"); +const XRT = artifacts.require("XRT"); + +const ethereum_ens = require("ethereum-ens"); +const ens = new ethereum_ens(web3, ENSRegistry.address); +const namehash = require('eth-ens-namehash'); + +contract("LiabilityFactory", () => { + const factory = LiabilityFactory.at(LiabilityFactory.address); + + it("shoudl be resolved via ENS", async () => { + const addr = await ens.resolver("factory.0.robonomics.eth").addr(); + assert.equal(addr, LiabilityFactory.address); + }); + + it("should point to XRT", async () => { + const xrt = await factory.xrt.call(); + assert.equal(xrt, XRT.address); + }); + + it("should point to ENS", async () => { + const ens = await factory.ens.call(); + assert.equal(ens, ENSRegistry.address); + }); + + it("should point to RobotLiability binary", async () => { + const rl = await factory.robotLiabilityLib.call(); + assert.equal(rl, RobotLiabilityLib.address); + }); + + it("should point to Lighthouse binary", async () => { + const ll = await factory.lighthouseLib.call(); + assert.equal(ll, LighthouseLib.address); + }); + +}); diff --git a/test/Lighthouse.test.js b/test/Lighthouse.test.js new file mode 100644 index 0000000..e1a3f3c --- /dev/null +++ b/test/Lighthouse.test.js @@ -0,0 +1,299 @@ +const LiabilityFactory = artifacts.require("LiabilityFactory"); +const ENSRegistry = artifacts.require("ENSRegistry"); +const Lighthouse = artifacts.require("LighthouseLib"); +const Liability = artifacts.require("RobotLiabilityLib"); +const XRT = artifacts.require("XRT"); + +const ethereum_ens = require("ethereum-ens"); +const ens = new ethereum_ens(web3, ENSRegistry.address); +const namehash = require("eth-ens-namehash"); +const utils = require("web3-utils"); +const abi = require("web3-eth-abi"); + +function randomAsk(account) { + let ask = { model: utils.randomHex(34) + , objective: utils.randomHex(34) + , token: XRT.address + , cost: 1 + , validator: "0x0000000000000000000000000000000000000000" + , validatorFee: 0 + , deadline: web3.eth.blockNumber + 1000 + , nonce: utils.randomHex(32) + }; + + const hash = utils.soliditySha3( + {t: "bytes", v: ask.model} + , {t: "bytes", v: ask.objective} + , {t: "address", v: ask.token} + , {t: "uint256", v: ask.cost} + , {t: "address", v: ask.validator} + , {t: "uint256", v: ask.validatorFee} + , {t: "uint256", v: ask.deadline} + , {t: "bytes32", v: ask.nonce} + ); + ask.signature = web3.eth.sign(account, hash); + + return ask; +} + +function pairBid(ask, account) { + let bid = Object.assign({}, ask); + bid.nonce = utils.randomHex(32); + bid.lighthouseFee = 1; + + const hash = utils.soliditySha3( + {t: "bytes", v: bid.model} + , {t: "bytes", v: bid.objective} + , {t: "address", v: bid.token} + , {t: "uint256", v: bid.cost} + , {t: "uint256", v: bid.lighthouseFee} + , {t: "uint256", v: bid.deadline} + , {t: "bytes32", v: bid.nonce} + ); + bid.signature = web3.eth.sign(account, hash); + + return bid; +} + +function encodeAsk(ask) { + return abi.encodeParameters( + [ "bytes" + , "bytes" + , "address" + , "uint256" + , "address" + , "uint256" + , "uint256" + , "bytes32" + , "bytes" + ], + [ ask.model + , ask.objective + , ask.token + , ask.cost + , ask.validator + , ask.validatorFee + , ask.deadline + , ask.nonce + , ask.signature + ] + ); +} + +function encodeBid(bid) { + return abi.encodeParameters( + [ "bytes" + , "bytes" + , "address" + , "uint256" + , "uint256" + , "uint256" + , "bytes32" + , "bytes" + ], + [ bid.model + , bid.objective + , bid.token + , bid.cost + , bid.lighthouseFee + , bid.deadline + , bid.nonce + , bid.signature + ] + ); +} + +function finalize(liability, account) { + const finalizeAbi = Liability.abi.find((e) => { return e.name == "finalize"; }); + + const result = utils.randomHex(34); + const hash = utils.soliditySha3( + {t: "address", v: liability} + , {t: "bytes", v: result} + ); + + return abi.encodeFunctionCall(finalizeAbi, [result, web3.eth.sign(account, hash)]); +} + +async function liabilityCreation(lighthouse, account, promisee, promisor) { + const factory = LiabilityFactory.at(LiabilityFactory.address); + const xrt = XRT.at(XRT.address); + + const builder = LiabilityFactory.at(lighthouse.address); + + const ask = randomAsk(promisee); + const bid = pairBid(ask, promisor); + + await xrt.increaseApproval(LiabilityFactory.address, ask.cost, {from: promisee}); + await xrt.increaseApproval(LiabilityFactory.address, bid.lighthouseFee, {from: promisor}); + + const result = await builder.createLiability(encodeAsk(ask), encodeBid(bid), {from: account}); + assert.equal(result.logs[0].event, "NewLiability"); + + const liability = Liability.at(result.logs[0].args.liability); + + const txgas = result.receipt.gasUsed; + const gas = await factory.gasUtilizing.call(liability.address); + const delta = txgas - gas.toNumber(); + console.log("gas:" + " tx = " + txgas + ", factory = " + gas.toNumber() + ", delta = " + delta); +// assert.equal(delta, 0); + + return liability; +} + +async function liabilityFinalization(liability, lighthouse, account, promisor) { + const factory = LiabilityFactory.at(LiabilityFactory.address); + const xrt = XRT.at(XRT.address); + let gas = await factory.gasUtilizing.call(liability.address); + + const result = await lighthouse.to(liability.address, finalize(liability.address, promisor), {from: account}); + + const txgas = result.receipt.gasUsed; + gas = (await factory.gasUtilizing.call(liability.address)).toNumber() - gas.toNumber(); + + const delta = txgas - gas; + console.log("gas:" + " tx = " + txgas + ", factory = " + gas + ", delta = " + delta); + + const totalgas = await factory.totalGasUtilizing.call(); + console.log("total gas: " + totalgas.toNumber()); + +// assert.equal(delta, 0); +} + +contract("Lighthouse", (accounts) => { + const factory = LiabilityFactory.at(LiabilityFactory.address); + const xrt = XRT.at(XRT.address); + + let lighthouse; + let liability; + + it("should be created via factory", async () => { + const result = await factory.createLighthouse(1000, 3, "test"); + assert.equal(result.logs[0].event, "NewLighthouse"); + + lighthouse = Lighthouse.at(result.logs[0].args.lighthouse); + + const registered = await factory.isLighthouse.call(lighthouse.address); + assert.equal(registered, true); + }); + + it("should be resolved via ENS", async () => { + const addr = await ens.resolver("test.lighthouse.0.robonomics.eth").addr(); + assert.equal(addr, lighthouse.address); + }); + + it("security placement", async () => { + await xrt.approve(lighthouse.address, 2000); + await lighthouse.refill(2000); + const balance = await lighthouse.balances.call(accounts[0]); + assert.equal(balance, 2000); + }); + + it("partial withdraw", async () => { + await lighthouse.withdraw(900); + const balance = await lighthouse.balances.call(accounts[0]); + assert.equal(balance, 1100); + }); + + it("full withdraw", async () => { + await lighthouse.withdraw(200); + const balance = await lighthouse.balances.call(accounts[0]); + assert.equal(balance, 0); + }); + + it("liability creation", async () => { + await xrt.approve(lighthouse.address, 1000); + await lighthouse.refill(1000); + + liability = await liabilityCreation(lighthouse, accounts[0], accounts[0], accounts[0]); + }); + + it("liability finalization", async () => { + const originBalance = (await xrt.balanceOf(accounts[0])).toNumber(); + + await liabilityFinalization(liability, lighthouse, accounts[0], accounts[0]); + + const currentBalance = (await xrt.balanceOf(accounts[0])).toNumber(); + const deltaB = currentBalance - originBalance; + console.log("emission: " + deltaB + " wn"); + + assert.equal(deltaB - 1, (await factory.gasUtilizing.call(liability.address)).toNumber() * 6); + }); + + it("marker marathon", async () => { + await xrt.transfer(accounts[1], 1000); + await xrt.approve(lighthouse.address, 1000, {from: accounts[1]}); + await lighthouse.refill(1000, {from: accounts[1]}); + + await xrt.transfer(accounts[2], 2000); + await xrt.approve(lighthouse.address, 2000, {from: accounts[2]}); + await lighthouse.refill(2000, {from: accounts[2]}); + + async function markerLog() { + const marker = await lighthouse.marker.call(); + const quota = await lighthouse.quota.call(); + const member = await lighthouse.members.call(marker); + console.log("m: " + marker + " q: " + quota + " a: " + member); + } + + liability = await liabilityCreation(lighthouse, accounts[1], accounts[0], accounts[0]); + await markerLog(); + + await liabilityFinalization(liability, lighthouse, accounts[2], accounts[0]); + await markerLog(); + + liability = await liabilityCreation(lighthouse, accounts[2], accounts[0], accounts[0]); + await markerLog(); + + await liabilityFinalization(liability, lighthouse, accounts[0], accounts[0]); + await markerLog(); + + liability = await liabilityCreation(lighthouse, accounts[1], accounts[0], accounts[0]); + await markerLog(); + + await liabilityFinalization(liability, lighthouse, accounts[2], accounts[0]); + await markerLog(); + + liability = await liabilityCreation(lighthouse, accounts[2], accounts[0], accounts[0]); + await markerLog(); + + await liabilityFinalization(liability, lighthouse, accounts[0], accounts[0]); + await markerLog(); + + }); + + it("keepalive marathon", async () => { + async function markerLog() { + const marker = await lighthouse.marker.call(); + const quota = await lighthouse.quota.call(); + const member = await lighthouse.members.call(marker); + console.log("m: " + marker + " q: " + quota + " a: " + member); + } + + function waitFor(blockNumber) { + console.log('waiting for block ' + blockNumber); + while (web3.eth.blockNumber < blockNumber) + console.log('.'); + } + + liability = await liabilityCreation(lighthouse, accounts[1], accounts[0], accounts[0]); + await markerLog(); + waitFor(web3.eth.blockNumber + 3); + await liabilityFinalization(liability, lighthouse, accounts[0], accounts[0]); + await markerLog(); + + liability = await liabilityCreation(lighthouse, accounts[1], accounts[0], accounts[0]); + await markerLog(); + waitFor(web3.eth.blockNumber + 3); + await liabilityFinalization(liability, lighthouse, accounts[0], accounts[0]); + await markerLog(); + + liability = await liabilityCreation(lighthouse, accounts[1], accounts[0], accounts[0]); + await markerLog(); + waitFor(web3.eth.blockNumber + 3); + await liabilityFinalization(liability, lighthouse, accounts[0], accounts[0]); + await markerLog(); + + }); + +}); diff --git a/test/XRT.test.js b/test/XRT.test.js new file mode 100644 index 0000000..d6d6bd4 --- /dev/null +++ b/test/XRT.test.js @@ -0,0 +1,21 @@ +const LiabilityFactory = artifacts.require("LiabilityFactory"); +const ENSRegistry = artifacts.require("ENSRegistry"); +const XRT = artifacts.require("XRT"); + +const ethereum_ens = require("ethereum-ens"); +const ens = new ethereum_ens(web3, ENSRegistry.address); + +contract("XRT", () => { + + it("should be resolved via ENS", async () => { + const addr = await ens.resolver("xrt.0.robonomics.eth").addr(); + assert.equal(addr, XRT.address); + }); + + it("should be owned by factory", async () => { + const xrt = await XRT.deployed(); + const owner = await xrt.owner.call(); + assert.equal(owner, LiabilityFactory.address); + }); + +}); diff --git a/truffle.js b/truffle.js new file mode 100644 index 0000000..2e5cb5b --- /dev/null +++ b/truffle.js @@ -0,0 +1,21 @@ +module.exports = { + networks: { + development: { + host: '127.0.0.1', + port: 9545, + network_id: '*' // Match any network id + }, + mainnet: { + host: '127.0.0.1', + port: 8545, + network_id: '*' // Match any network id + } + + }, + solc: { + optimizer: { + enabled: true, + runs: 200 + } + } +};