diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..4b4280a4c --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +node_modules +deploy diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 000000000..8d19e2f80 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,27 @@ +{ + "extends": [ + "plugin:node/recommended", + "airbnb-base", + "plugin:prettier/recommended" + ], + "plugins": ["node"], + "env": { + "node" : true, + "mocha" : true + }, + "globals" : { + "artifacts": false, + "contract": false, + "assert": false, + "web3": false + }, + "rules": { + "no-plusplus": "off", + "no-await-in-loop": "off", + "no-shadow": "off", + "prefer-destructuring": "off", + "no-use-before-define": ["error", { "functions": false }], + "no-restricted-syntax": "off", + "node/no-unpublished-require": "off" + } +} diff --git a/.gitignore b/.gitignore index de8a6acc7..ef58a67d8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules build flats .node* +.idea diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..ec3053c8d --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +10.15 diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..31ba22d84 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "semi": false, + "singleQuote": true, + "printWidth": 120 +} diff --git a/.travis.yml b/.travis.yml index f26094479..a90db0b6c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ sudo: required group: beta language: node_js node_js: - - "9" + - "10" cache: yarn: true env: @@ -14,4 +14,5 @@ matrix: allow_failures: - env: SOLIDITY_COVERAGE=true script: + - yarn lint:js - yarn test diff --git a/Dockerfile b/Dockerfile index 476323109..992dc94c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:8 +FROM node:10 WORKDIR /contracts diff --git a/GAS_CONSUMPTION.md b/GAS_CONSUMPTION.md index 88cc9ae49..165d6d138 100644 --- a/GAS_CONSUMPTION.md +++ b/GAS_CONSUMPTION.md @@ -1,174 +1,7 @@ -## Gas Consumption +## Gas Consumption by Bridge Mode -### `NATIVE-TO-ERC` Bridge Mode - -#### Deployment -##### Home - Contract | Method | Min | Max | Avg ----- | ---- | ---- | ---- | ---- -EternalStorageProxy|deployment|378510|378510|378510 -BridgeValidators|deployment|1144207|1144207|1144207 -EternalStorageProxy|upgradeTo|35871|30924|30913 -BridgeValidators|initialize|187738|280847|253949 -EternalStorageProxy|transferProxyOwnership|30653|30653|30653 -EternalStorageProxy|deployment|378510|378510|378510 -HomeBridgeNativeToErc|deployment|3327263|3327263|3327263 -EternalStorageProxy|upgradeTo|35871|30924|30913 -HomeBridgeNativeToErc|initialize|190051|190947|190755 -EternalStorageProxy|transferProxyOwnership|30653|30653|30653 -Total| |5739327|5823438|5796326 - -##### Foreign - Contract | Method | Min | Max | Avg ----- | ---- | ---- | ---- | ---- -ERC677BridgeToken|deployment|1498202|1499226|1498829 -EternalStorageProxy|deployment|378510|378510|378510 -BridgeValidators|deployment|1144207|1144207|1144207 -EternalStorageProxy|upgradeTo|35871|30924|30913 -BridgeValidators|initialize|187738|280847|253949 -EternalStorageProxy|transferProxyOwnership|30653|30653|30653 -EternalStorageProxy|deployment|378510|378510|378510 -ForeignBridgeNativeToErc|deployment|2768705|2768705|2768705 -EternalStorageProxy|upgradeTo|35871|30924|30913 -ForeignBridgeNativeToErc|initialize|213493|213557|213549 -ERC677BridgeToken|setBridgeContract|29432|44432|39432 -ERC677BridgeToken|transferOwnership|30860|30924|30913 -EternalStorageProxy|transferProxyOwnership|30653|30653|30653 -Total| |6762705|6862072|6829736 - -#### Usage - -##### Validators - - Contract | Method | Min | Max | Avg ----- | ---- | ---- | ---- | ---- -To sign at the Home (each validator)| -HomeBridgeNativeToErc|submitSignature|159362|275135|220127 -To relay signatures from the Home to the Foreign (one validator)| -ForeignBridgeNativeToErc|executeSignatures|89201|146127|120917 -To sign and relay from the Foreign to the Home (each validator)| -HomeBridgeNativeToErc|executeAffirmation|64314|107669|83596 - -##### Users - - Contract | Method | Min | Max | Avg ----- | ---- | ---- | ---- | ---- -To request transfer from the Home to the Foreign| -HomeBridgeNativeToErc|fallback|46982|46982|46982 -To request transfer from the Foreign to the Home| -ERC677BridgeToken|transferAndCall|58370|166206|92399 - - -### `ERC-TO-ERC` Bridge Mode - -#### Deployment -##### Home - Contract | Method | Min | Max | Avg ----- | ---- | ---- | ---- | ---- -EternalStorageProxy|deployment|378510|378510|378510 -BridgeValidators|deployment|1144207|1144207|1144207 -EternalStorageProxy|upgradeTo|35871|30924|30913 -BridgeValidators|initialize|187738|280847|253949 -EternalStorageProxy|transferProxyOwnership|30653|30653|30653 -EternalStorageProxy|deployment|378510|378510|378510 -HomeBridgeErcToErc|deployment|3528509|3528509|3528509 -EternalStorageProxy|upgradeTo|35871|30924|30913 -ERC677BridgeToken|deployment|1498202|1499226|1498829 -ERC677BridgeToken|setBridgeContract|29432|44432|39432 -ERC677BridgeToken|transferOwnership|30860|30924|30913 -HomeBridgeErcToErc|initialize|212299|213195|213003 -EternalStorageProxy|transferProxyOwnership|30653|30653|30653 -Total| |7521315|7621514|7588994 - -##### Foreign - Contract | Method | Min | Max | Avg ----- | ---- | ---- | ---- | ---- -EternalStorageProxy|deployment|378510|378510|378510 -BridgeValidators|deployment|1144207|1144207|1144207 -EternalStorageProxy|upgradeTo|35871|30924|30913 -BridgeValidators|initialize|187738|280847|253949 -EternalStorageProxy|transferProxyOwnership|30653|30653|30653 -EternalStorageProxy|deployment|378510|378510|378510 -ForeignBridgeErcToErc|deployment|2449436|2449436|2449436 -EternalStorageProxy|upgradeTo|35871|30924|30913 -ForeignBridgeErcToErc|initialize|150614|150614|150614 -EternalStorageProxy|transferProxyOwnership|30653|30653|30653 -Total| |4822063|4905278|4878358 - -#### Usage - -##### Validators - - Contract | Method | Min | Max | Avg ----- | ---- | ---- | ---- | ---- -To sign at the Home (each validator)| -HomeBridgeErcToErc|submitSignature|159386|275159|220171 -To relay signatures from the Home to the Foreign (one validator)| -ForeignBridgeErcToErc|executeSignatures|73779|115769|93027 -To sign and relay from the Foreign to the Home (each validator)| -HomeBridgeErcToErc|executeAffirmation|79336|134607|108215 - -##### Users - - Contract | Method | Min | Max | Avg ----- | ---- | ---- | ---- | ---- -To request transfer from the Home to the Foreign| -ERC677BridgeToken|transferAndCall|58370|166206|92399 -To request transfer from the Foreign to the Home| -ERC677BridgeToken|transfer|37691|86589|55000 - - -### `ERC-TO-NATIVE` Bridge Mode - -#### Deployment -##### Home - Contract | Method | Min | Max | Avg ----- | ---- | ---- | ---- | ---- -EternalStorageProxy|deployment|378510|378510|378510 -BridgeValidators|deployment|1144207|1144207|1144207 -EternalStorageProxy|upgradeTo|35871|30924|30913 -BridgeValidators|initialize|187738|280847|253949 -EternalStorageProxy|transferProxyOwnership|30653|30653|30653 -EternalStorageProxy|deployment|378510|378510|378510 -HomeBridgeErcToNative|deployment|3757420|3757420|3757420 -EternalStorageProxy|upgradeTo|35871|30924|30913 -HomeBridgeErcToNative|initialize|196910|213930|210795 -EternalStorageProxy|transferProxyOwnership|30653|30653|30653 -Total| |6176343|6276578|6246523 - -##### Foreign - Contract | Method | Min | Max | Avg ----- | ---- | ---- | ---- | ---- -EternalStorageProxy|deployment|378510|378510|378510 -BridgeValidators|deployment|1144207|1144207|1144207 -EternalStorageProxy|upgradeTo|35871|30924|30913 -BridgeValidators|initialize|187738|280847|253949 -EternalStorageProxy|transferProxyOwnership|30653|30653|30653 -EternalStorageProxy|deployment|378510|378510|378510 -ForeignBridgeErcToNative|deployment|2449564|2449564|2449564 -EternalStorageProxy|upgradeTo|35871|30924|30913 -ForeignBridgeErcToNative|initialize|150614|150614|150614 -EternalStorageProxy|transferProxyOwnership|30653|30653|30653 -Total| | - -#### Usage - -##### Validators - - Contract | Method | Min | Max | Avg ----- | ---- | ---- | ---- | ---- -To sign at the Home (each validator)| -HomeBridgeErcToNative|submitSignature|159428|275201|220206 -To relay signatures from the Home to the Foreign (one validator)| -ForeignBridgeErcToNative|executeSignatures|73779|115769|92985 -To sign and relay from the Foreign to the Home (each validator)| -HomeBridgeErcToNative|executeAffirmation|64380|140744|97562 - -##### Users - - Contract | Method | Min | Max | Avg ----- | ---- | ---- | ---- | ---- -To request transfer from the Home to the Foreign| -HomeBridgeErcToNative|fallback|80174|80174|80174 -To request transfer from the Foreign to the Home| -ERC677BridgeToken|transfer|37691|86589|55000 +- [NATIVE-TO-ERC](docs/NATIVE-TO-ERC.md) +- [NATIVE-TO-ERC-WITH-REWARD](docs/NATIVE-TO-ERC-WITH-REWARD.md) +- [ERC-TO-ERC](docs/ERC-TO-ERC.md) +- [ERC-TO-NATIVE](docs/ERC-TO-NATIVE.md) +- [ERC-TO-NATIVE-WITH-REWARD](docs/ERC-TO-NATIVE-WITH-REWARD.md) diff --git a/README.md b/README.md index def139c3f..f0f6c3e1a 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,9 @@ docker-compose down ### Gas Consumption The [GAS_CONSUMPTION](GAS_CONSUMPTION.md) file includes Min, Max, and Avg gas consumption figures for contracts associated with each bridge mode. +### Reward Management +The [REWARD_MANAGEMENT](REWARD_MANAGEMENT.md) file includes information on how rewards are distributed among the validators on each bridge mode. + ### Testing environment To test the bridge scripts in ERC20-to-ERC20 mode on a testnet like Sokol or Kovan, you must deploy an ERC20 token to the foreign network. This can be done by running the following command: diff --git a/REWARD_MANAGEMENT.md b/REWARD_MANAGEMENT.md new file mode 100644 index 000000000..c862909ba --- /dev/null +++ b/REWARD_MANAGEMENT.md @@ -0,0 +1,53 @@ +# Reward Management + +## NATIVE-TO-ERC +Configuration: +``` +HOME_REWARDABLE=ONE_DIRECTION +FOREIGN_REWARDABLE=ONE_DIRECTION +``` +### Home to Foreign transfer +Fees are calculated and distributed on Foreign network. Validators will receive ERC20 tokens. +![native-erc-hometoforeign](https://user-images.githubusercontent.com/4614574/51607402-4bda6180-1ef3-11e9-91e3-50fe5d35d296.png) + +### Foreign to Home transfer +Fees are calculated and distributed on Home network. Validators will receive native coins. +![native-erc-foreigntohome](https://user-images.githubusercontent.com/4614574/51607428-5d236e00-1ef3-11e9-8083-3669899c7252.png) + +## NATIVE-TO-ERC - Fees collected on Home network only +Configuration: +``` +HOME_REWARDABLE=BOTH_DIRECTIONS +FOREIGN_REWARDABLE=false +``` +### Home to Foreign transfer +Fees are calculated and distributed on Home network. Validators will receive native coins. +![native-erc-homefee-hometoforeign](https://user-images.githubusercontent.com/4614574/53118155-43456d00-352b-11e9-80db-53e31494e09b.png) + +### Foreign to Home transfer +Fees are calculated and distributed on Home network. Validators will receive native coins. +![native-erc-homefee-foreigntohome](https://user-images.githubusercontent.com/4614574/53118176-4b9da800-352b-11e9-8118-123f30e37d61.png) + +## ERC-TO-NATIVE +Configuration: +``` +HOME_REWARDABLE=BOTH_DIRECTIONS +FOREIGN_REWARDABLE=false +``` +### Foreign to Home transfer +Fees are calculated and distributed on Home network. Validators will receive native coins. +![erc-native-foreigntohome](https://user-images.githubusercontent.com/4614574/51607498-9065fd00-1ef3-11e9-8212-fc1ba16ae91a.png) + +### Home to Foreign transfer +Fees are calculated and distributed on Home network. Validators will receive native coins. +![erc-native-hometoforeign](https://user-images.githubusercontent.com/4614574/51607508-96f47480-1ef3-11e9-93a1-0f1111793f2a.png) + +## ERC-TO-ERC + +### Foreign to Home transfer +Fees are calculated and distributed on Home network. Validators will receive ERC20 tokens. +![ERC-ERC-ForeignToHome (1)](https://user-images.githubusercontent.com/4614574/56502412-98c8d680-64e8-11e9-8eea-5bcd545d74d9.png) + +### Home to Foreign transfer +Fees are calculated and distributed on Home network. Validators will receive ERC20 tokens. +![ERC-ERC-HomeToForeign (1)](https://user-images.githubusercontent.com/4614574/56502454-b8f89580-64e8-11e9-84ae-d9a1c229e0c4.png) diff --git a/contracts/ERC677BridgeToken.sol b/contracts/ERC677BridgeToken.sol index 74cd52909..e335f2622 100644 --- a/contracts/ERC677BridgeToken.sol +++ b/contracts/ERC677BridgeToken.sol @@ -75,7 +75,7 @@ contract ERC677BridgeToken is } function isContract(address _addr) - private + internal view returns (bool) { diff --git a/contracts/ERC677BridgeTokenRewardable.sol b/contracts/ERC677BridgeTokenRewardable.sol new file mode 100644 index 000000000..39155fb38 --- /dev/null +++ b/contracts/ERC677BridgeTokenRewardable.sol @@ -0,0 +1,79 @@ +pragma solidity 0.4.24; + +import "./ERC677BridgeToken.sol"; + + +contract ERC677BridgeTokenRewardable is ERC677BridgeToken { + + address public blockRewardContract; + address public stakingContract; + + constructor( + string _name, + string _symbol, + uint8 _decimals + ) public ERC677BridgeToken(_name, _symbol, _decimals) {} + + function setBlockRewardContract(address _blockRewardContract) onlyOwner public { + require(_blockRewardContract != address(0) && isContract(_blockRewardContract)); + blockRewardContract = _blockRewardContract; + } + + function setStakingContract(address _stakingContract) onlyOwner public { + require(_stakingContract != address(0) && isContract(_stakingContract)); + stakingContract = _stakingContract; + } + + modifier onlyBlockRewardContract() { + require(msg.sender == blockRewardContract); + _; + } + + modifier onlyStakingContract() { + require(msg.sender == stakingContract); + _; + } + + function mintReward(address[] _receivers, uint256[] _rewards) external onlyBlockRewardContract { + for (uint256 i = 0; i < _receivers.length; i++) { + uint256 amount = _rewards[i]; + + if (amount == 0) continue; + + address to = _receivers[i]; + + // Mint `amount` for `to` + totalSupply_ = totalSupply_.add(amount); + balances[to] = balances[to].add(amount); + emit Mint(to, amount); + emit Transfer(address(0), to, amount); + } + } + + function stake(address _staker, uint256 _amount) external onlyStakingContract { + // Transfer `_amount` from `_staker` to `stakingContract` + require(_amount <= balances[_staker]); + balances[_staker] = balances[_staker].sub(_amount); + balances[stakingContract] = balances[stakingContract].add(_amount); + emit Transfer(_staker, stakingContract, _amount); + } + + function withdraw(address _staker, uint256 _amount) external onlyStakingContract { + // Transfer `_amount` from `stakingContract` to `_staker` + require(_amount <= balances[stakingContract]); + balances[stakingContract] = balances[stakingContract].sub(_amount); + balances[_staker] = balances[_staker].add(_amount); + emit Transfer(stakingContract, _staker, _amount); + } + + function transfer(address _to, uint256 _value) public returns(bool) { + require(_to != stakingContract); + return super.transfer(_to, _value); + } + + function transferFrom(address _from, address _to, uint256 _value) public returns(bool) { + require(_to != stakingContract); + return super.transferFrom(_from, _to, _value); + } + +} diff --git a/contracts/IBlockReward.sol b/contracts/IBlockReward.sol index 2d9e1b89a..ccf39f5a8 100644 --- a/contracts/IBlockReward.sol +++ b/contracts/IBlockReward.sol @@ -6,4 +6,6 @@ interface IBlockReward { function mintedTotally() public view returns (uint256); function mintedTotallyByBridge(address _bridge) public view returns(uint256); function bridgesAllowedLength() external view returns(uint256); + function addBridgeTokenFeeReceivers(uint256 _amount) external; + function addBridgeNativeFeeReceivers(uint256 _amount) external; } diff --git a/contracts/IRewardableValidators.sol b/contracts/IRewardableValidators.sol new file mode 100644 index 000000000..4c753f338 --- /dev/null +++ b/contracts/IRewardableValidators.sol @@ -0,0 +1,12 @@ +pragma solidity 0.4.24; + + +interface IRewardableValidators { + function isValidator(address _validator) public view returns(bool); + function requiredSignatures() public view returns(uint256); + function owner() public view returns(address); + function validatorList() public view returns (address[]); + function getValidatorRewardAddress(address _validator) public view returns(address); + function validatorCount() public view returns (uint256); + function getNextValidator(address _address) public view returns (address); +} diff --git a/contracts/test/BlockReward.sol b/contracts/test/BlockReward.sol index ea5c4cfa9..de8bada40 100644 --- a/contracts/test/BlockReward.sol +++ b/contracts/test/BlockReward.sol @@ -7,9 +7,12 @@ import "../libraries/SafeMath.sol"; contract BlockReward is IBlockReward { using SafeMath for uint256; + address[] public validatorList; uint256 public mintedCoins = 0; + uint256 public feeAmount = 0; mapping(bytes32 => uint256) internal uintStorage; bytes32 internal constant MINTED_TOTALLY_BY_BRIDGE = "mintedTotallyByBridge"; + address public token; function () external payable { } @@ -40,4 +43,59 @@ contract BlockReward is IBlockReward { bytes32 hash = keccak256(abi.encode(MINTED_TOTALLY_BY_BRIDGE, _bridge)); uintStorage[hash] = uintStorage[hash].add(_amount); } + + function setValidatorsRewards(address[] _initialValidators) external { + validatorList = _initialValidators; + } + + function setToken(address _token) external { + token = _token; + } + + function addBridgeNativeFeeReceivers(uint256 _amount) external { + feeAmount = _amount; + uint256 feePerValidator = _amount.div(validatorList.length); + + uint256 randomValidatorIndex; + uint256 diff = _amount.sub(feePerValidator.mul(validatorList.length)); + if (diff > 0) { + randomValidatorIndex = random(validatorList.length); + } + + for (uint256 i = 0; i < validatorList.length; i++) { + uint256 feeToDistribute = feePerValidator; + if (diff > 0 && randomValidatorIndex == i) { + feeToDistribute = feeToDistribute.add(diff); + } + this.addExtraReceiver(feeToDistribute, validatorList[i]); + } + } + + function addBridgeTokenFeeReceivers(uint256 _amount) external { + address[] memory receivers = new address[](validatorList.length); + uint256[] memory rewards = new uint256[](validatorList.length); + feeAmount = _amount; + uint256 feePerValidator = _amount.div(validatorList.length); + + uint256 randomValidatorIndex; + uint256 diff = _amount.sub(feePerValidator.mul(validatorList.length)); + if (diff > 0) { + randomValidatorIndex = random(validatorList.length); + } + + for (uint256 i = 0; i < validatorList.length; i++) { + uint256 feeToDistribute = feePerValidator; + if (diff > 0 && randomValidatorIndex == i) { + feeToDistribute = feeToDistribute.add(diff); + } + receivers[i] = validatorList[i]; + rewards[i] = feeToDistribute; + } + + require(token.call(abi.encodeWithSignature("mintReward(address[],uint256[])", receivers, rewards))); + } + + function random(uint256 _count) public view returns(uint256) { + return uint256(blockhash(block.number.sub(1))) % _count; + } } diff --git a/contracts/test/Staking.sol b/contracts/test/Staking.sol new file mode 100644 index 000000000..b9e39b7ef --- /dev/null +++ b/contracts/test/Staking.sol @@ -0,0 +1,6 @@ +pragma solidity 0.4.24; + + +contract Staking { + constructor() public {} +} diff --git a/contracts/upgradeability/ClassicEternalStorageProxy.sol b/contracts/upgradeability/ClassicEternalStorageProxy.sol new file mode 100644 index 000000000..d01770389 --- /dev/null +++ b/contracts/upgradeability/ClassicEternalStorageProxy.sol @@ -0,0 +1,31 @@ +pragma solidity 0.4.24; + +import "./EternalStorage.sol"; +import "./OwnedUpgradeabilityProxy.sol"; + + +contract ClassicEternalStorageProxy is EternalStorage, OwnedUpgradeabilityProxy { + + function () payable public { + address _impl = implementation(); + require(_impl != address(0)); + uint256 len = getSize(msg.sig); + assembly { + let ptr := mload(0x40) + calldatacopy(ptr, 0, calldatasize) + let result := delegatecall(gas, _impl, ptr, calldatasize, 0, len) + + switch result + case 0 { revert(0, len) } + default { return(0, len) } + } + } + + function getSize(bytes4 sig) public view returns(uint256) { + uint256 ret = uintStorage[keccak256(abi.encodePacked("dataSizes", sig))]; + if (ret == 0) { + ret = 32; + } + return ret; + } +} diff --git a/contracts/upgradeable_contracts/BaseBridgeValidators.sol b/contracts/upgradeable_contracts/BaseBridgeValidators.sol new file mode 100644 index 000000000..054d93478 --- /dev/null +++ b/contracts/upgradeable_contracts/BaseBridgeValidators.sol @@ -0,0 +1,126 @@ +pragma solidity 0.4.24; + +import "./Ownable.sol"; +import "../libraries/SafeMath.sol"; +import "../upgradeability/EternalStorage.sol"; + + +contract BaseBridgeValidators is EternalStorage, Ownable { + using SafeMath for uint256; + + address public constant F_ADDR = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF; + + event ValidatorAdded (address indexed validator); + event ValidatorRemoved (address indexed validator); + event RequiredSignaturesChanged (uint256 requiredSignatures); + + function setRequiredSignatures(uint256 _requiredSignatures) + external + onlyOwner + { + require(validatorCount() >= _requiredSignatures); + require(_requiredSignatures != 0); + uintStorage[keccak256(abi.encodePacked("requiredSignatures"))] = _requiredSignatures; + emit RequiredSignaturesChanged(_requiredSignatures); + } + + function getBridgeValidatorsInterfacesVersion() + public + pure + returns (uint64 major, uint64 minor, uint64 patch) + { + return (2, 2, 0); + } + + function validatorList() public view returns (address[]) { + address [] memory list = new address[](validatorCount()); + uint256 counter = 0; + address nextValidator = getNextValidator(F_ADDR); + require(nextValidator != address(0)); + + while (nextValidator != F_ADDR) { + list[counter] = nextValidator; + nextValidator = getNextValidator(nextValidator); + counter++; + + if (nextValidator == address(0) ) { + revert(); + } + } + + return list; + } + + function _addValidator(address _validator) internal { + require(_validator != address(0) && _validator != F_ADDR); + require(!isValidator(_validator)); + + address firstValidator = getNextValidator(F_ADDR); + require(firstValidator != address(0)); + setNextValidator(_validator, firstValidator); + setNextValidator(F_ADDR, _validator); + setValidatorCount(validatorCount().add(1)); + } + + function _removeValidator(address _validator) internal { + require(validatorCount() > requiredSignatures()); + require(isValidator(_validator)); + address validatorsNext = getNextValidator(_validator); + address index = F_ADDR; + address next = getNextValidator(index); + require(next != address(0)); + + while (next != _validator) { + index = next; + next = getNextValidator(index); + + if (next == F_ADDR || next == address(0) ) { + revert(); + } + } + + setNextValidator(index, validatorsNext); + deleteItemFromAddressStorage("validatorsList", _validator); + setValidatorCount(validatorCount().sub(1)); + } + + function requiredSignatures() public view returns (uint256) { + return uintStorage[keccak256(abi.encodePacked("requiredSignatures"))]; + } + + function validatorCount() public view returns (uint256) { + return uintStorage[keccak256(abi.encodePacked("validatorCount"))]; + } + + function isValidator(address _validator) public view returns (bool) { + return _validator != F_ADDR && getNextValidator(_validator) != address(0); + } + + function isInitialized() public view returns (bool) { + return boolStorage[keccak256(abi.encodePacked("isInitialized"))]; + } + + function deployedAtBlock() public view returns (uint256) { + return uintStorage[keccak256("deployedAtBlock")]; + } + + function getNextValidator(address _address) public view returns (address) { + return addressStorage[keccak256(abi.encodePacked("validatorsList", _address))]; + } + + function deleteItemFromAddressStorage(string _mapName, address _address) internal { + delete addressStorage[keccak256(abi.encodePacked(_mapName, _address))]; + } + + function setValidatorCount(uint256 _validatorCount) internal { + uintStorage[keccak256(abi.encodePacked("validatorCount"))] = _validatorCount; + } + + function setNextValidator(address _prevValidator, address _validator) internal { + addressStorage[keccak256(abi.encodePacked("validatorsList", _prevValidator))] = _validator; + } + + function setInitialize(bool _status) internal { + boolStorage[keccak256(abi.encodePacked("isInitialized"))] = _status; + } +} diff --git a/contracts/upgradeable_contracts/BaseFeeManager.sol b/contracts/upgradeable_contracts/BaseFeeManager.sol new file mode 100644 index 000000000..93437a501 --- /dev/null +++ b/contracts/upgradeable_contracts/BaseFeeManager.sol @@ -0,0 +1,51 @@ +pragma solidity 0.4.24; + +import "../upgradeability/EternalStorage.sol"; +import "../libraries/SafeMath.sol"; +import "../IRewardableValidators.sol"; +import "./FeeTypes.sol"; + + +contract BaseFeeManager is EternalStorage, FeeTypes { + using SafeMath for uint256; + + event HomeFeeUpdated(uint256 fee); + event ForeignFeeUpdated(uint256 fee); + + function calculateFee(uint256 _value, bool _recover, bytes32 _feeType) public view returns(uint256) { + uint256 fee = _feeType == HOME_FEE ? getHomeFee() : getForeignFee(); + uint256 eth = 1 ether; + if (!_recover) { + return _value.mul(fee).div(eth); + } + return _value.mul(fee).div(eth.sub(fee)); + } + + function setHomeFee(uint256 _fee) external { + uintStorage[keccak256(abi.encodePacked("homeFee"))] = _fee; + emit HomeFeeUpdated(_fee); + } + + function getHomeFee() public view returns(uint256) { + return uintStorage[keccak256(abi.encodePacked("homeFee"))]; + } + + function setForeignFee(uint256 _fee) external { + uintStorage[keccak256(abi.encodePacked("foreignFee"))] = _fee; + emit ForeignFeeUpdated(_fee); + } + + function getForeignFee() public view returns(uint256) { + return uintStorage[keccak256(abi.encodePacked("foreignFee"))]; + } + + function distributeFeeFromAffirmation(uint256 _fee) external; + + function distributeFeeFromSignatures(uint256 _fee) external; + + function getFeeManagerMode() public pure returns(bytes4); + + function random(uint256 _count) public view returns(uint256) { + return uint256(blockhash(block.number.sub(1))) % _count; + } +} diff --git a/contracts/upgradeable_contracts/BasicForeignBridge.sol b/contracts/upgradeable_contracts/BasicForeignBridge.sol index 5198a1a5f..365c4c169 100644 --- a/contracts/upgradeable_contracts/BasicForeignBridge.sol +++ b/contracts/upgradeable_contracts/BasicForeignBridge.sol @@ -21,14 +21,14 @@ contract BasicForeignBridge is EternalStorage, Validatable { require(contractAddress == address(this)); require(!relayedMessages(txHash)); setRelayedMessages(txHash, true); - require(onExecuteMessage(recipient, amount)); + require(onExecuteMessage(recipient, amount, txHash)); emit RelayedMessage(recipient, amount, txHash); } else { onFailedMessage(recipient, amount, txHash); } } - function onExecuteMessage(address, uint256) internal returns(bool); + function onExecuteMessage(address, uint256, bytes32) internal returns(bool); function setRelayedMessages(bytes32 _txHash, bool _status) internal { boolStorage[keccak256(abi.encodePacked("relayedMessages", _txHash))] = _status; diff --git a/contracts/upgradeable_contracts/BasicHomeBridge.sol b/contracts/upgradeable_contracts/BasicHomeBridge.sol index f1c27d03b..39b63b1b9 100644 --- a/contracts/upgradeable_contracts/BasicHomeBridge.sol +++ b/contracts/upgradeable_contracts/BasicHomeBridge.sol @@ -6,6 +6,7 @@ import "openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol"; import "./Validatable.sol"; import "../libraries/Message.sol"; + contract BasicHomeBridge is EternalStorage, Validatable { using SafeMath for uint256; @@ -36,7 +37,9 @@ contract BasicHomeBridge is EternalStorage, Validatable { // If the bridge contract does not own enough tokens to transfer // it will couse funds lock on the home side of the bridge setNumAffirmationsSigned(hashMsg, markAsProcessed(signed)); - require(onExecuteAffirmation(recipient, value)); + if (value > 0) { + require(onExecuteAffirmation(recipient, value, transactionHash)); + } emit AffirmationCompleted(recipient, value, transactionHash); } } else { @@ -74,6 +77,8 @@ contract BasicHomeBridge is EternalStorage, Validatable { if (signed >= reqSigs) { setNumMessagesSigned(hashMsg, markAsProcessed(signed)); emit CollectedSignatures(msg.sender, hashMsg, reqSigs); + + onSignaturesCollected(message); } } @@ -81,7 +86,10 @@ contract BasicHomeBridge is EternalStorage, Validatable { boolStorage[keccak256(abi.encodePacked("messagesSigned", _hash))] = _status; } - function onExecuteAffirmation(address, uint256) internal returns(bool) { + function onExecuteAffirmation(address, uint256, bytes32) internal returns(bool) { + } + + function onSignaturesCollected(bytes) internal { } function numAffirmationsSigned(bytes32 _withdrawal) public view returns(uint256) { diff --git a/contracts/upgradeable_contracts/BlockRewardFeeManager.sol b/contracts/upgradeable_contracts/BlockRewardFeeManager.sol new file mode 100644 index 000000000..a6414aabb --- /dev/null +++ b/contracts/upgradeable_contracts/BlockRewardFeeManager.sol @@ -0,0 +1,21 @@ +pragma solidity 0.4.24; + +import "./BaseFeeManager.sol"; +import "../IBlockReward.sol"; + +contract BlockRewardFeeManager is BaseFeeManager { + + function distributeFeeFromAffirmation(uint256 _fee) external { + distributeFeeFromBlockReward(_fee); + } + + function distributeFeeFromSignatures(uint256 _fee) external { + distributeFeeFromBlockReward(_fee); + } + + function _blockRewardContract() internal view returns(IBlockReward) { + return IBlockReward(addressStorage[keccak256(abi.encodePacked("blockRewardContract"))]); + } + + function distributeFeeFromBlockReward(uint256 _fee) internal; +} diff --git a/contracts/upgradeable_contracts/BridgeValidators.sol b/contracts/upgradeable_contracts/BridgeValidators.sol index d3ee1edba..58a7e4795 100644 --- a/contracts/upgradeable_contracts/BridgeValidators.sol +++ b/contracts/upgradeable_contracts/BridgeValidators.sol @@ -1,100 +1,59 @@ pragma solidity 0.4.24; -import "./Ownable.sol"; -import "../IBridgeValidators.sol"; -import "../libraries/SafeMath.sol"; -import "../upgradeability/EternalStorage.sol"; +import "./BaseBridgeValidators.sol"; -contract BridgeValidators is IBridgeValidators, EternalStorage, Ownable { - using SafeMath for uint256; +contract BridgeValidators is BaseBridgeValidators { - event ValidatorAdded (address indexed validator); - event ValidatorRemoved (address indexed validator); - event RequiredSignaturesChanged (uint256 requiredSignatures); - - function initialize(uint256 _requiredSignatures, address[] _initialValidators, address _owner) - public returns(bool) + function initialize( + uint256 _requiredSignatures, + address[] _initialValidators, + address _owner + ) + public + returns (bool) { require(!isInitialized()); require(_owner != address(0)); setOwner(_owner); require(_requiredSignatures != 0); require(_initialValidators.length >= _requiredSignatures); + for (uint256 i = 0; i < _initialValidators.length; i++) { - require(_initialValidators[i] != address(0)); - assert(validators(_initialValidators[i]) != true); + require(_initialValidators[i] != address(0) && _initialValidators[i] != F_ADDR); + require(!isValidator(_initialValidators[i])); + + if (i == 0) { + setNextValidator(F_ADDR, _initialValidators[i]); + if (_initialValidators.length == 1) { + setNextValidator(_initialValidators[i], F_ADDR); + } + } else if (i == _initialValidators.length - 1) { + setNextValidator(_initialValidators[i - 1], _initialValidators[i]); + setNextValidator(_initialValidators[i], F_ADDR); + } else { + setNextValidator(_initialValidators[i - 1], _initialValidators[i]); + } + setValidatorCount(validatorCount().add(1)); - setValidator(_initialValidators[i], true); emit ValidatorAdded(_initialValidators[i]); } + uintStorage[keccak256(abi.encodePacked("requiredSignatures"))] = _requiredSignatures; uintStorage[keccak256("deployedAtBlock")] = block.number; setInitialize(true); emit RequiredSignaturesChanged(_requiredSignatures); + return isInitialized(); } function addValidator(address _validator) external onlyOwner { - require(_validator != address(0)); - require(!isValidator(_validator)); - setValidatorCount(validatorCount().add(1)); - setValidator(_validator, true); + _addValidator(_validator); emit ValidatorAdded(_validator); } function removeValidator(address _validator) external onlyOwner { - require(validatorCount() > requiredSignatures()); - require(isValidator(_validator)); - setValidator(_validator, false); - setValidatorCount(validatorCount().sub(1)); + _removeValidator(_validator); emit ValidatorRemoved(_validator); } - - function setRequiredSignatures(uint256 _requiredSignatures) external onlyOwner { - require(validatorCount() >= _requiredSignatures); - require(_requiredSignatures != 0); - uintStorage[keccak256(abi.encodePacked("requiredSignatures"))] = _requiredSignatures; - emit RequiredSignaturesChanged(_requiredSignatures); - } - - function getBridgeValidatorsInterfacesVersion() public pure returns(uint64 major, uint64 minor, uint64 patch) { - return (2, 0, 0); - } - - function requiredSignatures() public view returns(uint256) { - return uintStorage[keccak256(abi.encodePacked("requiredSignatures"))]; - } - - function validatorCount() public view returns(uint256) { - return uintStorage[keccak256(abi.encodePacked("validatorCount"))]; - } - - function validators(address _validator) public view returns(bool) { - return boolStorage[keccak256(abi.encodePacked("validators", _validator))]; - } - - function isValidator(address _validator) public view returns(bool) { - return validators(_validator) == true; - } - - function isInitialized() public view returns(bool) { - return boolStorage[keccak256(abi.encodePacked("isInitialized"))]; - } - - function deployedAtBlock() public view returns(uint256) { - return uintStorage[keccak256("deployedAtBlock")]; - } - - function setValidatorCount(uint256 _validatorCount) private { - uintStorage[keccak256(abi.encodePacked("validatorCount"))] = _validatorCount; - } - - function setValidator(address _validator, bool _status) private { - boolStorage[keccak256(abi.encodePacked("validators", _validator))] = _status; - } - - function setInitialize(bool _status) private { - boolStorage[keccak256(abi.encodePacked("isInitialized"))] = _status; - } } diff --git a/contracts/upgradeable_contracts/ERC677Bridge.sol b/contracts/upgradeable_contracts/ERC677Bridge.sol index 8206e6669..37777b3b7 100644 --- a/contracts/upgradeable_contracts/ERC677Bridge.sol +++ b/contracts/upgradeable_contracts/ERC677Bridge.sol @@ -2,11 +2,11 @@ pragma solidity 0.4.24; import "./BasicBridge.sol"; -import "../IBurnableMintableERC677Token.sol"; +import "../ERC677.sol"; contract ERC677Bridge is BasicBridge { - function erc677token() public view returns(IBurnableMintableERC677Token) { - return IBurnableMintableERC677Token(addressStorage[keccak256(abi.encodePacked("erc677token"))]); + function erc677token() public view returns(ERC677) { + return ERC677(addressStorage[keccak256(abi.encodePacked("erc677token"))]); } function setErc677token(address _token) internal { @@ -15,16 +15,17 @@ contract ERC677Bridge is BasicBridge { } function onTokenTransfer(address _from, uint256 _value, bytes /*_data*/) external returns(bool) { - require(msg.sender == address(erc677token())); + ERC677 token = erc677token(); + require(msg.sender == address(token)); require(withinLimit(_value)); setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(_value)); - erc677token().burn(_value); - fireEventOnTokenTransfer(_from, _value); + bridgeSpecificActionsOnTokenTransfer(token, _from, _value); return true; } - function fireEventOnTokenTransfer(address /*_from */, uint256 /* _value */) internal { - // has to be defined + function bridgeSpecificActionsOnTokenTransfer(ERC677 _token, address _from, uint256 _value) internal { + fireEventOnTokenTransfer(_from, _value); } + function fireEventOnTokenTransfer(address _from, uint256 _value) internal; } diff --git a/contracts/upgradeable_contracts/ERC677BridgeForBurnableMintableToken.sol b/contracts/upgradeable_contracts/ERC677BridgeForBurnableMintableToken.sol new file mode 100644 index 000000000..3483626e9 --- /dev/null +++ b/contracts/upgradeable_contracts/ERC677BridgeForBurnableMintableToken.sol @@ -0,0 +1,13 @@ +pragma solidity 0.4.24; + + +import "./ERC677Bridge.sol"; +import "../IBurnableMintableERC677Token.sol"; + + +contract ERC677BridgeForBurnableMintableToken is ERC677Bridge { + function bridgeSpecificActionsOnTokenTransfer(ERC677 _token, address _from, uint256 _value) internal { + IBurnableMintableERC677Token(_token).burn(_value); + fireEventOnTokenTransfer(_from, _value); + } +} diff --git a/contracts/upgradeable_contracts/FeeTypes.sol b/contracts/upgradeable_contracts/FeeTypes.sol new file mode 100644 index 000000000..7cc977490 --- /dev/null +++ b/contracts/upgradeable_contracts/FeeTypes.sol @@ -0,0 +1,7 @@ +pragma solidity 0.4.24; + + +contract FeeTypes { + bytes32 internal constant HOME_FEE = keccak256(abi.encodePacked("home-fee")); + bytes32 internal constant FOREIGN_FEE = keccak256(abi.encodePacked("foreign-fee")); +} diff --git a/contracts/upgradeable_contracts/RewardableBridge.sol b/contracts/upgradeable_contracts/RewardableBridge.sol new file mode 100644 index 000000000..295ca025c --- /dev/null +++ b/contracts/upgradeable_contracts/RewardableBridge.sol @@ -0,0 +1,85 @@ +pragma solidity 0.4.24; + +import "./Ownable.sol"; +import "./FeeTypes.sol"; + + +contract RewardableBridge is Ownable, FeeTypes { + + event FeeDistributedFromAffirmation(uint256 feeAmount, bytes32 indexed transactionHash); + event FeeDistributedFromSignatures(uint256 feeAmount, bytes32 indexed transactionHash); + + function _getFee(bytes32 _feeType) internal view returns(uint256) { + uint256 fee; + address feeManager = feeManagerContract(); + string memory method = _feeType == HOME_FEE ? "getHomeFee()" : "getForeignFee()"; + bytes memory callData = abi.encodeWithSignature(method); + + assembly { + let result := callcode(gas, feeManager, 0x0, add(callData, 0x20), mload(callData), 0, 32) + fee := mload(0) + + switch result + case 0 { revert(0, 0) } + } + return fee; + } + + function getFeeManagerMode() public view returns(bytes4) { + bytes4 mode; + bytes memory callData = abi.encodeWithSignature("getFeeManagerMode()"); + address feeManager = feeManagerContract(); + assembly { + let result := callcode(gas, feeManager, 0x0, add(callData, 0x20), mload(callData), 0, 4) + mode := mload(0) + + switch result + case 0 { revert(0, 0) } + } + return mode; + } + + function feeManagerContract() public view returns(address) { + return addressStorage[keccak256(abi.encodePacked("feeManagerContract"))]; + } + + function setFeeManagerContract(address _feeManager) public onlyOwner { + require(_feeManager == address(0) || isContract(_feeManager)); + addressStorage[keccak256(abi.encodePacked("feeManagerContract"))] = _feeManager; + } + + function _setFee(address _feeManager, uint256 _fee, bytes32 _feeType) internal { + string memory method = _feeType == HOME_FEE ? "setHomeFee(uint256)" : "setForeignFee(uint256)"; + require(_feeManager.delegatecall(abi.encodeWithSignature(method, _fee))); + } + + function isContract(address _addr) internal view returns (bool) + { + uint length; + assembly { length := extcodesize(_addr) } + return length > 0; + } + + function calculateFee(uint256 _value, bool _recover, address _impl, bytes32 _feeType) internal view returns(uint256) { + uint256 fee; + bytes memory callData = abi.encodeWithSignature("calculateFee(uint256,bool,bytes32)", _value, _recover, _feeType); + assembly { + let result := callcode(gas, _impl, 0x0, add(callData, 0x20), mload(callData), 0, 32) + fee := mload(0) + + switch result + case 0 { revert(0, 0) } + } + return fee; + } + + function distributeFeeFromSignatures(uint256 _fee, address _feeManager, bytes32 _txHash) internal { + require(_feeManager.delegatecall(abi.encodeWithSignature("distributeFeeFromSignatures(uint256)", _fee))); + emit FeeDistributedFromSignatures(_fee, _txHash); + } + + function distributeFeeFromAffirmation(uint256 _fee, address _feeManager, bytes32 _txHash) internal { + require(_feeManager.delegatecall(abi.encodeWithSignature("distributeFeeFromAffirmation(uint256)", _fee))); + emit FeeDistributedFromAffirmation(_fee, _txHash); + } +} diff --git a/contracts/upgradeable_contracts/RewardableValidators.sol b/contracts/upgradeable_contracts/RewardableValidators.sol new file mode 100644 index 000000000..89e692069 --- /dev/null +++ b/contracts/upgradeable_contracts/RewardableValidators.sol @@ -0,0 +1,74 @@ +pragma solidity 0.4.24; + +import "./BaseBridgeValidators.sol"; + + +contract RewardableValidators is BaseBridgeValidators { + + function initialize( + uint256 _requiredSignatures, + address[] _initialValidators, + address[] _initialRewards, + address _owner + ) + public + returns (bool) + { + require(!isInitialized()); + require(_owner != address(0)); + setOwner(_owner); + require(_requiredSignatures != 0); + require(_initialValidators.length >= _requiredSignatures); + require(_initialValidators.length == _initialRewards.length); + + for (uint256 i = 0; i < _initialValidators.length; i++) { + require(_initialValidators[i] != address(0) && _initialValidators[i] != F_ADDR); + require(_initialRewards[i] != address(0)); + require(!isValidator(_initialValidators[i])); + + if (i == 0) { + setNextValidator(F_ADDR, _initialValidators[i]); + if (_initialValidators.length == 1) { + setNextValidator(_initialValidators[i], F_ADDR); + } + } else if (i == _initialValidators.length - 1) { + setNextValidator(_initialValidators[i - 1], _initialValidators[i]); + setNextValidator(_initialValidators[i], F_ADDR); + } else { + setNextValidator(_initialValidators[i - 1], _initialValidators[i]); + } + + setValidatorCount(validatorCount().add(1)); + setValidatorRewardAddress(_initialValidators[i], _initialRewards[i]); + emit ValidatorAdded(_initialValidators[i]); + } + + uintStorage[keccak256(abi.encodePacked("requiredSignatures"))] = _requiredSignatures; + uintStorage[keccak256("deployedAtBlock")] = block.number; + setInitialize(true); + emit RequiredSignaturesChanged(_requiredSignatures); + + return isInitialized(); + } + + function addRewardableValidator(address _validator, address _reward) external onlyOwner { + require(_reward != address(0)); + _addValidator(_validator); + setValidatorRewardAddress(_validator, _reward); + emit ValidatorAdded(_validator); + } + + function removeValidator(address _validator) external onlyOwner { + _removeValidator(_validator); + deleteItemFromAddressStorage("validatorsRewards", _validator); + emit ValidatorRemoved(_validator); + } + + function getValidatorRewardAddress(address _validator) public view returns (address) { + return addressStorage[keccak256(abi.encodePacked("validatorsRewards", _validator))]; + } + + function setValidatorRewardAddress(address _validator, address _reward) internal { + addressStorage[keccak256(abi.encodePacked("validatorsRewards", _validator))] = _reward; + } +} diff --git a/contracts/upgradeable_contracts/Sacrifice.sol b/contracts/upgradeable_contracts/Sacrifice.sol new file mode 100644 index 000000000..d82b35e91 --- /dev/null +++ b/contracts/upgradeable_contracts/Sacrifice.sol @@ -0,0 +1,8 @@ +pragma solidity 0.4.24; + + +contract Sacrifice { + constructor(address _recipient) public payable { + selfdestruct(_recipient); + } +} diff --git a/contracts/upgradeable_contracts/ValidatorsFeeManager.sol b/contracts/upgradeable_contracts/ValidatorsFeeManager.sol new file mode 100644 index 000000000..705d99b3c --- /dev/null +++ b/contracts/upgradeable_contracts/ValidatorsFeeManager.sol @@ -0,0 +1,67 @@ +pragma solidity 0.4.24; + +import "./BaseFeeManager.sol"; +import "../IRewardableValidators.sol"; + +contract ValidatorsFeeManager is BaseFeeManager { + + bytes32 public constant REWARD_FOR_TRANSFERRING_FROM_HOME = keccak256(abi.encodePacked("reward-transferring-from-home")); + + bytes32 public constant REWARD_FOR_TRANSFERRING_FROM_FOREIGN = keccak256(abi.encodePacked("reward-transferring-from-foreign")); + + function distributeFeeFromAffirmation(uint256 _fee) external { + distributeFeeProportionally(_fee, REWARD_FOR_TRANSFERRING_FROM_FOREIGN); + } + + function distributeFeeFromSignatures(uint256 _fee) external { + distributeFeeProportionally(_fee, REWARD_FOR_TRANSFERRING_FROM_HOME); + } + + function rewardableValidatorContract() internal view returns(IRewardableValidators) { + return IRewardableValidators(addressStorage[keccak256(abi.encodePacked("validatorContract"))]); + } + + function distributeFeeProportionally(uint256 _fee, bytes32 _direction) internal { + IRewardableValidators validators = rewardableValidatorContract(); + address F_ADDR = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF; + uint256 numOfValidators = validators.validatorCount(); + + uint256 feePerValidator = _fee.div(numOfValidators); + + uint256 randomValidatorIndex; + uint256 diff = _fee.sub(feePerValidator.mul(numOfValidators)); + if (diff > 0) { + randomValidatorIndex = random(numOfValidators); + } + + address nextValidator = validators.getNextValidator(F_ADDR); + require((nextValidator != F_ADDR) && (nextValidator != address(0))); + + uint256 i = 0; + while (nextValidator != F_ADDR) { + uint256 feeToDistribute = feePerValidator; + if (diff > 0 && randomValidatorIndex == i) { + feeToDistribute = feeToDistribute.add(diff); + } + + address rewardAddress = validators.getValidatorRewardAddress(nextValidator); + onFeeDistribution(rewardAddress, feeToDistribute, _direction); + + nextValidator = validators.getNextValidator(nextValidator); + require(nextValidator != address(0)); + i = i + 1; + } + } + + function onFeeDistribution(address _rewardAddress, uint256 _fee, bytes32 _direction) internal { + if (_direction == REWARD_FOR_TRANSFERRING_FROM_FOREIGN) { + onAffirmationFeeDistribution(_rewardAddress, _fee); + } else { + onSignatureFeeDistribution(_rewardAddress, _fee); + } + } + + function onAffirmationFeeDistribution(address _rewardAddress, uint256 _fee) internal; + + function onSignatureFeeDistribution(address _rewardAddress, uint256 _fee) internal; +} diff --git a/contracts/upgradeable_contracts/erc20_to_erc20/BasicForeignBridgeErcToErc.sol b/contracts/upgradeable_contracts/erc20_to_erc20/BasicForeignBridgeErcToErc.sol new file mode 100644 index 000000000..c59d85748 --- /dev/null +++ b/contracts/upgradeable_contracts/erc20_to_erc20/BasicForeignBridgeErcToErc.sol @@ -0,0 +1,63 @@ +pragma solidity 0.4.24; + + +import "../BasicBridge.sol"; +import "../BasicForeignBridge.sol"; +import "openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol"; + + +contract BasicForeignBridgeErcToErc is BasicBridge, BasicForeignBridge { + function _initialize( + address _validatorContract, + address _erc20token, + uint256 _requiredBlockConfirmations, + uint256 _gasPrice, + uint256 _maxPerTx, + uint256 _homeDailyLimit, + uint256 _homeMaxPerTx, + address _owner + ) internal { + require(!isInitialized()); + require(_validatorContract != address(0) && isContract(_validatorContract)); + require(_requiredBlockConfirmations != 0); + require(_gasPrice > 0); + require(_homeMaxPerTx < _homeDailyLimit); + require(_owner != address(0)); + addressStorage[keccak256(abi.encodePacked("validatorContract"))] = _validatorContract; + setErc20token(_erc20token); + uintStorage[keccak256(abi.encodePacked("deployedAtBlock"))] = block.number; + uintStorage[keccak256(abi.encodePacked("requiredBlockConfirmations"))] = _requiredBlockConfirmations; + uintStorage[keccak256(abi.encodePacked("gasPrice"))] = _gasPrice; + uintStorage[keccak256(abi.encodePacked("maxPerTx"))] = _maxPerTx; + uintStorage[keccak256(abi.encodePacked("executionDailyLimit"))] = _homeDailyLimit; + uintStorage[keccak256(abi.encodePacked("executionMaxPerTx"))] = _homeMaxPerTx; + setOwner(_owner); + setInitialize(true); + } + + function getBridgeMode() public pure returns(bytes4 _data) { + return bytes4(keccak256(abi.encodePacked("erc-to-erc-core"))); + } + + function claimTokens(address _token, address _to) public onlyIfOwnerOfProxy { + require(_token != address(erc20token())); + super.claimTokens(_token, _to); + } + + function onExecuteMessage(address _recipient, uint256 _amount, bytes32 _txHash) internal returns(bool){ + setTotalExecutedPerDay(getCurrentDay(), totalExecutedPerDay(getCurrentDay()).add(_amount)); + return erc20token().transfer(_recipient, _amount); + } + + function messageWithinLimits(uint256 _amount) internal view returns(bool) { + return withinExecutionLimit(_amount); + } + + function onFailedMessage(address, uint256, bytes32) internal { + revert(); + } + + function erc20token() public view returns(ERC20Basic); + + function setErc20token(address _token) internal; +} diff --git a/contracts/upgradeable_contracts/erc20_to_erc20/FeeManagerErcToErcPOSDAO.sol b/contracts/upgradeable_contracts/erc20_to_erc20/FeeManagerErcToErcPOSDAO.sol new file mode 100644 index 000000000..2867cbc93 --- /dev/null +++ b/contracts/upgradeable_contracts/erc20_to_erc20/FeeManagerErcToErcPOSDAO.sol @@ -0,0 +1,31 @@ +pragma solidity 0.4.24; + +import "../BlockRewardFeeManager.sol"; + +contract FeeManagerErcToErcPOSDAO is BlockRewardFeeManager { + + function getFeeManagerMode() public pure returns(bytes4) { + return bytes4(keccak256(abi.encodePacked("manages-both-directions"))); + } + + function blockRewardContract() public view returns(address) { + return _blockRewardContract(); + } + + function setBlockRewardContract(address _blockReward) external { + require(_blockReward != address(0) && isContract(_blockReward) && (IBlockReward(_blockReward).bridgesAllowedLength() != 0)); + addressStorage[keccak256(abi.encodePacked("blockRewardContract"))] = _blockReward; + } + + function distributeFeeFromBlockReward(uint256 _fee) internal { + IBlockReward blockReward = _blockRewardContract(); + blockReward.addBridgeTokenFeeReceivers(_fee); + } + + function isContract(address _addr) internal view returns (bool) + { + uint length; + assembly { length := extcodesize(_addr) } + return length > 0; + } +} diff --git a/contracts/upgradeable_contracts/erc20_to_erc20/ForeignBridgeErc677ToErc677.sol b/contracts/upgradeable_contracts/erc20_to_erc20/ForeignBridgeErc677ToErc677.sol new file mode 100644 index 000000000..6f5bfe34d --- /dev/null +++ b/contracts/upgradeable_contracts/erc20_to_erc20/ForeignBridgeErc677ToErc677.sol @@ -0,0 +1,54 @@ +pragma solidity 0.4.24; + + +import "./BasicForeignBridgeErcToErc.sol"; +import "../ERC677Bridge.sol"; + + +contract ForeignBridgeErc677ToErc677 is ERC677Bridge, BasicForeignBridgeErcToErc { + + event UserRequestForAffirmation(address recipient, uint256 value); + + function initialize( + address _validatorContract, + address _erc20token, + uint256 _requiredBlockConfirmations, + uint256 _gasPrice, + uint256 _dailyLimit, + uint256 _maxPerTx, + uint256 _minPerTx, + uint256 _homeDailyLimit, + uint256 _homeMaxPerTx, + address _owner + ) public returns(bool) { + require(_minPerTx > 0 && _maxPerTx > _minPerTx && _dailyLimit > _maxPerTx); + + _initialize( + _validatorContract, + _erc20token, + _requiredBlockConfirmations, + _gasPrice, + _maxPerTx, + _homeDailyLimit, + _homeMaxPerTx, + _owner + ); + + uintStorage[keccak256(abi.encodePacked("dailyLimit"))] = _dailyLimit; + uintStorage[keccak256(abi.encodePacked("minPerTx"))] = _minPerTx; + + return isInitialized(); + } + + function erc20token() public view returns(ERC20Basic) { + return erc677token(); + } + + function setErc20token(address _token) internal { + setErc677token(_token); + } + + function fireEventOnTokenTransfer(address _from, uint256 _value) internal { + emit UserRequestForAffirmation(_from, _value); + } +} diff --git a/contracts/upgradeable_contracts/erc20_to_erc20/ForeignBridgeErcToErc.sol b/contracts/upgradeable_contracts/erc20_to_erc20/ForeignBridgeErcToErc.sol index 73a2a34ab..57c8d1ea3 100644 --- a/contracts/upgradeable_contracts/erc20_to_erc20/ForeignBridgeErcToErc.sol +++ b/contracts/upgradeable_contracts/erc20_to_erc20/ForeignBridgeErcToErc.sol @@ -1,17 +1,10 @@ pragma solidity 0.4.24; -import "../../libraries/SafeMath.sol"; -import "../../libraries/Message.sol"; -import "../BasicBridge.sol"; -import "../BasicForeignBridge.sol"; -import "../../IBurnableMintableERC677Token.sol"; -import "../../ERC677Receiver.sol"; -import "openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol"; -contract ForeignBridgeErcToErc is BasicBridge, BasicForeignBridge { +import "./BasicForeignBridgeErcToErc.sol"; - event RelayedMessage(address recipient, uint value, bytes32 transactionHash); +contract ForeignBridgeErcToErc is BasicForeignBridgeErcToErc { function initialize( address _validatorContract, address _erc20token, @@ -22,53 +15,25 @@ contract ForeignBridgeErcToErc is BasicBridge, BasicForeignBridge { uint256 _homeMaxPerTx, address _owner ) public returns(bool) { - require(!isInitialized()); - require(_validatorContract != address(0) && isContract(_validatorContract)); - require(_requiredBlockConfirmations != 0); - require(_gasPrice > 0); - require(_homeMaxPerTx < _homeDailyLimit); - require(_owner != address(0)); - addressStorage[keccak256(abi.encodePacked("validatorContract"))] = _validatorContract; - setErc20token(_erc20token); - uintStorage[keccak256(abi.encodePacked("deployedAtBlock"))] = block.number; - uintStorage[keccak256(abi.encodePacked("requiredBlockConfirmations"))] = _requiredBlockConfirmations; - uintStorage[keccak256(abi.encodePacked("gasPrice"))] = _gasPrice; - uintStorage[keccak256(abi.encodePacked("maxPerTx"))] = _maxPerTx; - uintStorage[keccak256(abi.encodePacked("executionDailyLimit"))] = _homeDailyLimit; - uintStorage[keccak256(abi.encodePacked("executionMaxPerTx"))] = _homeMaxPerTx; - setOwner(_owner); - setInitialize(true); + _initialize( + _validatorContract, + _erc20token, + _requiredBlockConfirmations, + _gasPrice, + _maxPerTx, + _homeDailyLimit, + _homeMaxPerTx, + _owner + ); return isInitialized(); } - function getBridgeMode() public pure returns(bytes4 _data) { - return bytes4(keccak256(abi.encodePacked("erc-to-erc-core"))); - } - - function claimTokens(address _token, address _to) public onlyIfOwnerOfProxy { - require(_token != address(erc20token())); - super.claimTokens(_token, _to); - } - function erc20token() public view returns(ERC20Basic) { return ERC20Basic(addressStorage[keccak256(abi.encodePacked("erc20token"))]); } - function onExecuteMessage(address _recipient, uint256 _amount) internal returns(bool){ - setTotalExecutedPerDay(getCurrentDay(), totalExecutedPerDay(getCurrentDay()).add(_amount)); - return erc20token().transfer(_recipient, _amount); - } - - function setErc20token(address _token) private { + function setErc20token(address _token) internal { require(_token != address(0) && isContract(_token)); addressStorage[keccak256(abi.encodePacked("erc20token"))] = _token; } - - function messageWithinLimits(uint256 _amount) internal view returns(bool) { - return withinExecutionLimit(_amount); - } - - function onFailedMessage(address, uint256, bytes32) internal { - revert(); - } } diff --git a/contracts/upgradeable_contracts/erc20_to_erc20/HomeBridgeErcToErc.sol b/contracts/upgradeable_contracts/erc20_to_erc20/HomeBridgeErcToErc.sol index 51313be11..3273fe0cb 100644 --- a/contracts/upgradeable_contracts/erc20_to_erc20/HomeBridgeErcToErc.sol +++ b/contracts/upgradeable_contracts/erc20_to_erc20/HomeBridgeErcToErc.sol @@ -6,11 +6,12 @@ import "../../upgradeability/EternalStorage.sol"; import "../../IBurnableMintableERC677Token.sol"; import "../../ERC677Receiver.sol"; import "../BasicHomeBridge.sol"; -import "../ERC677Bridge.sol"; import "../OverdrawManagement.sol"; +import "./RewardableHomeBridgeErcToErc.sol"; +import "../ERC677BridgeForBurnableMintableToken.sol"; -contract HomeBridgeErcToErc is ERC677Receiver, EternalStorage, BasicBridge, BasicHomeBridge, ERC677Bridge, OverdrawManagement { +contract HomeBridgeErcToErc is ERC677Receiver, EternalStorage, BasicBridge, BasicHomeBridge, ERC677BridgeForBurnableMintableToken, OverdrawManagement, RewardableHomeBridgeErcToErc { event AmountLimitExceeded(address recipient, uint256 value, bytes32 transactionHash); @@ -27,6 +28,109 @@ contract HomeBridgeErcToErc is ERC677Receiver, EternalStorage, BasicBridge, Basi address _owner ) public returns(bool) + { + _initialize ( + _validatorContract, + _dailyLimit, + _maxPerTx, + _minPerTx, + _homeGasPrice, + _requiredBlockConfirmations, + _erc677token, + _foreignDailyLimit, + _foreignMaxPerTx, + _owner + ); + setInitialize(true); + + return isInitialized(); + } + + function rewardableInitialize ( + address _validatorContract, + uint256 _dailyLimit, + uint256 _maxPerTx, + uint256 _minPerTx, + uint256 _homeGasPrice, + uint256 _requiredBlockConfirmations, + address _erc677token, + uint256 _foreignDailyLimit, + uint256 _foreignMaxPerTx, + address _owner, + address _feeManager, + uint256 _homeFee, + uint256 _foreignFee + ) public + returns(bool) + { + _rewardableInitialize ( + _validatorContract, + _dailyLimit, + _maxPerTx, + _minPerTx, + _homeGasPrice, + _requiredBlockConfirmations, + _erc677token, + _foreignDailyLimit, + _foreignMaxPerTx, + _owner, + _feeManager, + _homeFee, + _foreignFee + ); + setInitialize(true); + + return isInitialized(); + } + + function _rewardableInitialize ( + address _validatorContract, + uint256 _dailyLimit, + uint256 _maxPerTx, + uint256 _minPerTx, + uint256 _homeGasPrice, + uint256 _requiredBlockConfirmations, + address _erc677token, + uint256 _foreignDailyLimit, + uint256 _foreignMaxPerTx, + address _owner, + address _feeManager, + uint256 _homeFee, + uint256 _foreignFee + ) internal + returns(bool) + { + _initialize ( + _validatorContract, + _dailyLimit, + _maxPerTx, + _minPerTx, + _homeGasPrice, + _requiredBlockConfirmations, + _erc677token, + _foreignDailyLimit, + _foreignMaxPerTx, + _owner + ); + require(isContract(_feeManager)); + addressStorage[keccak256(abi.encodePacked("feeManagerContract"))] = _feeManager; + _setFee(_feeManager, _homeFee, HOME_FEE); + _setFee(_feeManager, _foreignFee, FOREIGN_FEE); + } + + function _initialize ( + address _validatorContract, + uint256 _dailyLimit, + uint256 _maxPerTx, + uint256 _minPerTx, + uint256 _homeGasPrice, + uint256 _requiredBlockConfirmations, + address _erc677token, + uint256 _foreignDailyLimit, + uint256 _foreignMaxPerTx, + address _owner + ) internal + returns(bool) { require(!isInitialized()); require(_validatorContract != address(0) && isContract(_validatorContract)); @@ -45,10 +149,7 @@ contract HomeBridgeErcToErc is ERC677Receiver, EternalStorage, BasicBridge, Basi uintStorage[keccak256(abi.encodePacked("executionDailyLimit"))] = _foreignDailyLimit; uintStorage[keccak256(abi.encodePacked("executionMaxPerTx"))] = _foreignMaxPerTx; setOwner(_owner); - setInitialize(true); setErc677token(_erc677token); - - return isInitialized(); } function getBridgeMode() public pure returns(bytes4 _data) { @@ -59,13 +160,39 @@ contract HomeBridgeErcToErc is ERC677Receiver, EternalStorage, BasicBridge, Basi revert(); } - function onExecuteAffirmation(address _recipient, uint256 _value) internal returns(bool) { + function onExecuteAffirmation(address _recipient, uint256 _value, bytes32 txHash) internal returns(bool) { setTotalExecutedPerDay(getCurrentDay(), totalExecutedPerDay(getCurrentDay()).add(_value)); - return erc677token().mint(_recipient, _value); + uint256 valueToMint = _value; + address feeManager = feeManagerContract(); + if (feeManager != address(0)) { + uint256 fee = calculateFee(valueToMint, false, feeManager, FOREIGN_FEE); + distributeFeeFromAffirmation(fee, feeManager, txHash); + valueToMint = valueToMint.sub(fee); + } + return IBurnableMintableERC677Token(erc677token()).mint(_recipient, valueToMint); } function fireEventOnTokenTransfer(address _from, uint256 _value) internal { - emit UserRequestForSignature(_from, _value); + uint256 valueToTransfer = _value; + address feeManager = feeManagerContract(); + if (feeManager != address(0)) { + uint256 fee = calculateFee(valueToTransfer, false, feeManager, HOME_FEE); + valueToTransfer = valueToTransfer.sub(fee); + } + emit UserRequestForSignature(_from, valueToTransfer); + } + + function onSignaturesCollected(bytes _message) internal { + address feeManager = feeManagerContract(); + if (feeManager != address(0)) { + address recipient; + uint256 amount; + bytes32 txHash; + address contractAddress; + (recipient, amount, txHash, contractAddress) = Message.parseMessage(_message); + uint256 fee = calculateFee(amount, true, feeManager, HOME_FEE); + distributeFeeFromSignatures(fee, feeManager, txHash); + } } function affirmationWithinLimits(uint256 _amount) internal view returns(bool) { diff --git a/contracts/upgradeable_contracts/erc20_to_erc20/POSDAOHomeBridgeErcToErc.sol b/contracts/upgradeable_contracts/erc20_to_erc20/POSDAOHomeBridgeErcToErc.sol new file mode 100644 index 000000000..76b4bd409 --- /dev/null +++ b/contracts/upgradeable_contracts/erc20_to_erc20/POSDAOHomeBridgeErcToErc.sol @@ -0,0 +1,70 @@ +pragma solidity 0.4.24; + +import "./HomeBridgeErcToErc.sol"; + +contract POSDAOHomeBridgeErcToErc is HomeBridgeErcToErc { + + function rewardableInitialize ( + address _validatorContract, + uint256 _dailyLimit, + uint256 _maxPerTx, + uint256 _minPerTx, + uint256 _homeGasPrice, + uint256 _requiredBlockConfirmations, + address _erc677token, + uint256 _foreignDailyLimit, + uint256 _foreignMaxPerTx, + address _owner, + address _feeManager, + uint256 _homeFee, + uint256 _foreignFee, + address _blockReward + ) public + returns(bool) + { + _rewardableInitialize ( + _validatorContract, + _dailyLimit, + _maxPerTx, + _minPerTx, + _homeGasPrice, + _requiredBlockConfirmations, + _erc677token, + _foreignDailyLimit, + _foreignMaxPerTx, + _owner, + _feeManager, + _homeFee, + _foreignFee + ); + _setBlockRewardContract(_feeManager, _blockReward); + setInitialize(true); + + return isInitialized(); + } + + function blockRewardContract() public view returns(address) { + address blockReward; + address feeManager = feeManagerContract(); + bytes memory callData = abi.encodeWithSignature("blockRewardContract()"); + + assembly { + let result := callcode(gas, feeManager, 0x0, add(callData, 0x20), mload(callData), 0, 32) + blockReward := mload(0) + + switch result + case 0 { revert(0, 0) } + } + + return blockReward; + } + + function setBlockRewardContract(address _blockReward) public onlyOwner { + address feeManager = feeManagerContract(); + _setBlockRewardContract(feeManager, _blockReward); + } + + function _setBlockRewardContract(address _feeManager, address _blockReward) internal { + require(_feeManager.delegatecall(abi.encodeWithSignature("setBlockRewardContract(address)", _blockReward))); + } +} diff --git a/contracts/upgradeable_contracts/erc20_to_erc20/RewardableHomeBridgeErcToErc.sol b/contracts/upgradeable_contracts/erc20_to_erc20/RewardableHomeBridgeErcToErc.sol new file mode 100644 index 000000000..0b9282755 --- /dev/null +++ b/contracts/upgradeable_contracts/erc20_to_erc20/RewardableHomeBridgeErcToErc.sol @@ -0,0 +1,23 @@ +pragma solidity 0.4.24; + +import "../RewardableBridge.sol"; + + +contract RewardableHomeBridgeErcToErc is RewardableBridge { + + function setHomeFee(uint256 _fee) external onlyOwner { + _setFee(feeManagerContract(), _fee, HOME_FEE); + } + + function setForeignFee(uint256 _fee) external onlyOwner { + _setFee(feeManagerContract(), _fee, FOREIGN_FEE); + } + + function getHomeFee() public view returns(uint256) { + return _getFee(HOME_FEE); + } + + function getForeignFee() public view returns(uint256) { + return _getFee(FOREIGN_FEE); + } +} diff --git a/contracts/upgradeable_contracts/erc20_to_native/FeeManagerErcToNative.sol b/contracts/upgradeable_contracts/erc20_to_native/FeeManagerErcToNative.sol new file mode 100644 index 000000000..6da8aaa83 --- /dev/null +++ b/contracts/upgradeable_contracts/erc20_to_native/FeeManagerErcToNative.sol @@ -0,0 +1,33 @@ +pragma solidity 0.4.24; + +import "../../IBlockReward.sol"; +import "../Sacrifice.sol"; +import "../ValidatorsFeeManager.sol"; + + +contract FeeManagerErcToNative is ValidatorsFeeManager { + + function getFeeManagerMode() public pure returns(bytes4) { + return bytes4(keccak256(abi.encodePacked("manages-both-directions"))); + } + + function blockRewardContract() internal view returns(IBlockReward) { + return IBlockReward(addressStorage[keccak256(abi.encodePacked("blockRewardContract"))]); + } + + function onAffirmationFeeDistribution(address _rewardAddress, uint256 _fee) internal { + IBlockReward blockReward = blockRewardContract(); + blockReward.addExtraReceiver(_fee, _rewardAddress); + } + + function onSignatureFeeDistribution(address _rewardAddress, uint256 _fee) internal { + if (!_rewardAddress.send(_fee)) { + (new Sacrifice).value(_fee)(_rewardAddress); + } + } + + function getAmountToBurn(uint256 _value) public view returns(uint256) { + uint256 fee = calculateFee(_value, false, HOME_FEE); + return _value.sub(fee); + } +} diff --git a/contracts/upgradeable_contracts/erc20_to_native/FeeManagerErcToNativePOSDAO.sol b/contracts/upgradeable_contracts/erc20_to_native/FeeManagerErcToNativePOSDAO.sol new file mode 100644 index 000000000..cb8ea80e7 --- /dev/null +++ b/contracts/upgradeable_contracts/erc20_to_native/FeeManagerErcToNativePOSDAO.sol @@ -0,0 +1,20 @@ +pragma solidity 0.4.24; + +import "../../IBlockReward.sol"; +import "../BlockRewardFeeManager.sol"; + +contract FeeManagerErcToNativePOSDAO is BlockRewardFeeManager { + + function getFeeManagerMode() public pure returns(bytes4) { + return bytes4(keccak256(abi.encodePacked("manages-both-directions"))); + } + + function distributeFeeFromBlockReward(uint256 _fee) internal { + IBlockReward blockReward = _blockRewardContract(); + blockReward.addBridgeNativeFeeReceivers(_fee); + } + + function getAmountToBurn(uint256 _value) public view returns(uint256) { + return _value; + } +} diff --git a/contracts/upgradeable_contracts/erc20_to_native/ForeignBridgeErcToNative.sol b/contracts/upgradeable_contracts/erc20_to_native/ForeignBridgeErcToNative.sol index c64317685..aa9e292b8 100644 --- a/contracts/upgradeable_contracts/erc20_to_native/ForeignBridgeErcToNative.sol +++ b/contracts/upgradeable_contracts/erc20_to_native/ForeignBridgeErcToNative.sol @@ -53,7 +53,7 @@ contract ForeignBridgeErcToNative is BasicBridge, BasicForeignBridge { return ERC20Basic(addressStorage[keccak256(abi.encodePacked("erc20token"))]); } - function onExecuteMessage(address _recipient, uint256 _amount) internal returns(bool) { + function onExecuteMessage(address _recipient, uint256 _amount, bytes32 _txHash) internal returns(bool) { setTotalExecutedPerDay(getCurrentDay(), totalExecutedPerDay(getCurrentDay()).add(_amount)); return erc20token().transfer(_recipient, _amount); } diff --git a/contracts/upgradeable_contracts/erc20_to_native/HomeBridgeErcToNative.sol b/contracts/upgradeable_contracts/erc20_to_native/HomeBridgeErcToNative.sol index 8a42f4586..7b5b1323e 100644 --- a/contracts/upgradeable_contracts/erc20_to_native/HomeBridgeErcToNative.sol +++ b/contracts/upgradeable_contracts/erc20_to_native/HomeBridgeErcToNative.sol @@ -8,9 +8,10 @@ import "../../ERC677Receiver.sol"; import "../BasicHomeBridge.sol"; import "../ERC677Bridge.sol"; import "../OverdrawManagement.sol"; +import "./RewardableHomeBridgeErcToNative.sol"; -contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge, OverdrawManagement { +contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge, OverdrawManagement, RewardableHomeBridgeErcToNative { event AmountLimitExceeded(address recipient, uint256 value, bytes32 transactionHash); @@ -22,9 +23,17 @@ contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge, uint256 totalMinted = blockReward.mintedTotallyByBridge(address(this)); require(msg.value <= totalMinted.sub(totalBurntCoins())); setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(msg.value)); - setTotalBurntCoins(totalBurntCoins().add(msg.value)); - address(0).transfer(msg.value); - emit UserRequestForSignature(msg.sender, msg.value); + uint256 valueToTransfer = msg.value; + address feeManager = feeManagerContract(); + uint256 valueToBurn = msg.value; + if (feeManager != address(0)) { + uint256 fee = calculateFee(valueToTransfer, false, feeManager, HOME_FEE); + valueToTransfer = valueToTransfer.sub(fee); + valueToBurn = getAmountToBurn(valueToBurn); + } + setTotalBurntCoins(totalBurntCoins().add(valueToBurn)); + address(0).transfer(valueToBurn); + emit UserRequestForSignature(msg.sender, valueToTransfer); } function initialize ( @@ -40,24 +49,55 @@ contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge, address _owner ) public returns(bool) { - require(!isInitialized()); - require(_validatorContract != address(0) && isContract(_validatorContract)); - require(_requiredBlockConfirmations > 0); - require(_minPerTx > 0 && _maxPerTx > _minPerTx && _dailyLimit > _maxPerTx); - require(_blockReward == address(0) || isContract(_blockReward)); - require(_foreignMaxPerTx < _foreignDailyLimit); - require(_owner != address(0)); - addressStorage[keccak256(abi.encodePacked("validatorContract"))] = _validatorContract; - uintStorage[keccak256(abi.encodePacked("deployedAtBlock"))] = block.number; - uintStorage[keccak256(abi.encodePacked("dailyLimit"))] = _dailyLimit; - uintStorage[keccak256(abi.encodePacked("maxPerTx"))] = _maxPerTx; - uintStorage[keccak256(abi.encodePacked("minPerTx"))] = _minPerTx; - uintStorage[keccak256(abi.encodePacked("gasPrice"))] = _homeGasPrice; - uintStorage[keccak256(abi.encodePacked("requiredBlockConfirmations"))] = _requiredBlockConfirmations; - addressStorage[keccak256(abi.encodePacked("blockRewardContract"))] = _blockReward; - uintStorage[keccak256(abi.encodePacked("executionDailyLimit"))] = _foreignDailyLimit; - uintStorage[keccak256(abi.encodePacked("executionMaxPerTx"))] = _foreignMaxPerTx; - setOwner(_owner); + _initialize( + _validatorContract, + _dailyLimit, + _maxPerTx, + _minPerTx, + _homeGasPrice, + _requiredBlockConfirmations, + _blockReward, + _foreignDailyLimit, + _foreignMaxPerTx, + _owner + ); + setInitialize(true); + + return isInitialized(); + } + + function rewardableInitialize ( + address _validatorContract, + uint256 _dailyLimit, + uint256 _maxPerTx, + uint256 _minPerTx, + uint256 _homeGasPrice, + uint256 _requiredBlockConfirmations, + address _blockReward, + uint256 _foreignDailyLimit, + uint256 _foreignMaxPerTx, + address _owner, + address _feeManager, + uint256 _homeFee, + uint256 _foreignFee + ) public returns(bool) + { + _initialize( + _validatorContract, + _dailyLimit, + _maxPerTx, + _minPerTx, + _homeGasPrice, + _requiredBlockConfirmations, + _blockReward, + _foreignDailyLimit, + _foreignMaxPerTx, + _owner + ); + require(isContract(_feeManager)); + addressStorage[keccak256(abi.encodePacked("feeManagerContract"))] = _feeManager; + _setFee(_feeManager, _homeFee, HOME_FEE); + _setFee(_feeManager, _foreignFee, FOREIGN_FEE); setInitialize(true); return isInitialized(); @@ -80,14 +120,68 @@ contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge, addressStorage[keccak256(abi.encodePacked("blockRewardContract"))] = _blockReward; } - function onExecuteAffirmation(address _recipient, uint256 _value) internal returns(bool) { + function _initialize ( + address _validatorContract, + uint256 _dailyLimit, + uint256 _maxPerTx, + uint256 _minPerTx, + uint256 _homeGasPrice, + uint256 _requiredBlockConfirmations, + address _blockReward, + uint256 _foreignDailyLimit, + uint256 _foreignMaxPerTx, + address _owner + ) internal + { + require(!isInitialized()); + require(_validatorContract != address(0) && isContract(_validatorContract)); + require(_requiredBlockConfirmations > 0); + require(_minPerTx > 0 && _maxPerTx > _minPerTx && _dailyLimit > _maxPerTx); + require(_blockReward == address(0) || isContract(_blockReward)); + require(_foreignMaxPerTx < _foreignDailyLimit); + require(_owner != address(0)); + addressStorage[keccak256(abi.encodePacked("validatorContract"))] = _validatorContract; + uintStorage[keccak256(abi.encodePacked("deployedAtBlock"))] = block.number; + uintStorage[keccak256(abi.encodePacked("dailyLimit"))] = _dailyLimit; + uintStorage[keccak256(abi.encodePacked("maxPerTx"))] = _maxPerTx; + uintStorage[keccak256(abi.encodePacked("minPerTx"))] = _minPerTx; + uintStorage[keccak256(abi.encodePacked("gasPrice"))] = _homeGasPrice; + uintStorage[keccak256(abi.encodePacked("requiredBlockConfirmations"))] = _requiredBlockConfirmations; + addressStorage[keccak256(abi.encodePacked("blockRewardContract"))] = _blockReward; + uintStorage[keccak256(abi.encodePacked("executionDailyLimit"))] = _foreignDailyLimit; + uintStorage[keccak256(abi.encodePacked("executionMaxPerTx"))] = _foreignMaxPerTx; + setOwner(_owner); + } + + function onExecuteAffirmation(address _recipient, uint256 _value, bytes32 txHash) internal returns(bool) { setTotalExecutedPerDay(getCurrentDay(), totalExecutedPerDay(getCurrentDay()).add(_value)); IBlockReward blockReward = blockRewardContract(); require(blockReward != address(0)); - blockReward.addExtraReceiver(_value, _recipient); + uint256 valueToMint = _value; + + address feeManager = feeManagerContract(); + if (feeManager != address(0)) { + uint256 fee = calculateFee(valueToMint, false, feeManager, FOREIGN_FEE); + distributeFeeFromAffirmation(fee, feeManager, txHash); + valueToMint = valueToMint.sub(fee); + } + blockReward.addExtraReceiver(valueToMint, _recipient); return true; } + function onSignaturesCollected(bytes _message) internal { + address feeManager = feeManagerContract(); + if (feeManager != address(0)) { + address recipient; + uint256 amount; + bytes32 txHash; + address contractAddress; + (recipient, amount, txHash, contractAddress) = Message.parseMessage(_message); + uint256 fee = calculateFee(amount, true, feeManager, HOME_FEE); + distributeFeeFromSignatures(fee, feeManager, txHash); + } + } + function fireEventOnTokenTransfer(address _from, uint256 _value) internal { emit UserRequestForSignature(_from, _value); } diff --git a/contracts/upgradeable_contracts/erc20_to_native/RewardableHomeBridgeErcToNative.sol b/contracts/upgradeable_contracts/erc20_to_native/RewardableHomeBridgeErcToNative.sol new file mode 100644 index 000000000..fb47621de --- /dev/null +++ b/contracts/upgradeable_contracts/erc20_to_native/RewardableHomeBridgeErcToNative.sol @@ -0,0 +1,37 @@ +pragma solidity 0.4.24; + +import "../RewardableBridge.sol"; + + +contract RewardableHomeBridgeErcToNative is RewardableBridge { + + function setHomeFee(uint256 _fee) external onlyOwner { + _setFee(feeManagerContract(), _fee, HOME_FEE); + } + + function setForeignFee(uint256 _fee) external onlyOwner { + _setFee(feeManagerContract(), _fee, FOREIGN_FEE); + } + + function getHomeFee() public view returns(uint256) { + return _getFee(HOME_FEE); + } + + function getForeignFee() public view returns(uint256) { + return _getFee(FOREIGN_FEE); + } + + function getAmountToBurn(uint256 _value) public view returns(uint256) { + uint256 amount; + bytes memory callData = abi.encodeWithSignature("getAmountToBurn(uint256)", _value); + address feeManager = feeManagerContract(); + assembly { + let result := callcode(gas, feeManager, 0x0, add(callData, 0x20), mload(callData), 0, 32) + amount := mload(0) + + switch result + case 0 { revert(0, 0) } + } + return amount; + } +} diff --git a/contracts/upgradeable_contracts/native_to_erc20/ClassicHomeBridgeNativeToErc.sol b/contracts/upgradeable_contracts/native_to_erc20/ClassicHomeBridgeNativeToErc.sol new file mode 100644 index 000000000..cea6ba5c3 --- /dev/null +++ b/contracts/upgradeable_contracts/native_to_erc20/ClassicHomeBridgeNativeToErc.sol @@ -0,0 +1,34 @@ +pragma solidity 0.4.24; + +import "./HomeBridgeNativeToErc.sol"; + + +contract ClassicHomeBridgeNativeToErc is HomeBridgeNativeToErc { + + function _initialize ( + address _validatorContract, + uint256 _dailyLimit, + uint256 _maxPerTx, + uint256 _minPerTx, + uint256 _homeGasPrice, + uint256 _requiredBlockConfirmations, + uint256 _foreignDailyLimit, + uint256 _foreignMaxPerTx, + address _owner + ) internal + { + super._initialize( + _validatorContract, + _dailyLimit, + _maxPerTx, + _minPerTx, + _homeGasPrice, + _requiredBlockConfirmations, + _foreignDailyLimit, + _foreignMaxPerTx, + _owner + ); + uintStorage[keccak256(abi.encodePacked("dataSizes", bytes4(keccak256("signature(bytes32,uint256)"))))] = 132; + uintStorage[keccak256(abi.encodePacked("dataSizes", bytes4(keccak256("message(bytes32)"))))] = 210; + } +} diff --git a/contracts/upgradeable_contracts/native_to_erc20/FeeManagerNativeToErc.sol b/contracts/upgradeable_contracts/native_to_erc20/FeeManagerNativeToErc.sol new file mode 100644 index 000000000..521ff559a --- /dev/null +++ b/contracts/upgradeable_contracts/native_to_erc20/FeeManagerNativeToErc.sol @@ -0,0 +1,27 @@ +pragma solidity 0.4.24; + +import "../../IBurnableMintableERC677Token.sol"; +import "../Sacrifice.sol"; +import "../ValidatorsFeeManager.sol"; + + +contract FeeManagerNativeToErc is ValidatorsFeeManager { + + function getFeeManagerMode() public pure returns(bytes4) { + return bytes4(keccak256(abi.encodePacked("manages-one-direction"))); + } + + function erc677token() public view returns(IBurnableMintableERC677Token) { + return IBurnableMintableERC677Token(addressStorage[keccak256(abi.encodePacked("erc677token"))]); + } + + function onAffirmationFeeDistribution(address _rewardAddress, uint256 _fee) internal { + if (!_rewardAddress.send(_fee)) { + (new Sacrifice).value(_fee)(_rewardAddress); + } + } + + function onSignatureFeeDistribution(address _rewardAddress, uint256 _fee) internal { + erc677token().mint(_rewardAddress, _fee); + } +} diff --git a/contracts/upgradeable_contracts/native_to_erc20/FeeManagerNativeToErcBothDirections.sol b/contracts/upgradeable_contracts/native_to_erc20/FeeManagerNativeToErcBothDirections.sol new file mode 100644 index 000000000..049ff62c4 --- /dev/null +++ b/contracts/upgradeable_contracts/native_to_erc20/FeeManagerNativeToErcBothDirections.sol @@ -0,0 +1,26 @@ +pragma solidity 0.4.24; + +import "../Sacrifice.sol"; +import "../ValidatorsFeeManager.sol"; + + +contract FeeManagerNativeToErcBothDirections is ValidatorsFeeManager { + + function getFeeManagerMode() public pure returns(bytes4) { + return bytes4(keccak256(abi.encodePacked("manages-both-directions"))); + } + + function onAffirmationFeeDistribution(address _rewardAddress, uint256 _fee) internal { + _sendReward(_rewardAddress, _fee); + } + + function onSignatureFeeDistribution(address _rewardAddress, uint256 _fee) internal { + _sendReward(_rewardAddress, _fee); + } + + function _sendReward(address _rewardAddress, uint256 _fee) internal { + if (!_rewardAddress.send(_fee)) { + (new Sacrifice).value(_fee)(_rewardAddress); + } + } +} diff --git a/contracts/upgradeable_contracts/native_to_erc20/ForeignBridgeNativeToErc.sol b/contracts/upgradeable_contracts/native_to_erc20/ForeignBridgeNativeToErc.sol index 3b52049a2..1876a99b8 100644 --- a/contracts/upgradeable_contracts/native_to_erc20/ForeignBridgeNativeToErc.sol +++ b/contracts/upgradeable_contracts/native_to_erc20/ForeignBridgeNativeToErc.sol @@ -5,10 +5,11 @@ import "../../IBurnableMintableERC677Token.sol"; import "../../ERC677Receiver.sol"; import "../BasicForeignBridge.sol"; import "openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol"; -import "../ERC677Bridge.sol"; +import "../ERC677BridgeForBurnableMintableToken.sol"; +import "./RewardableForeignBridgeNativeToErc.sol"; -contract ForeignBridgeNativeToErc is ERC677Receiver, BasicBridge, BasicForeignBridge, ERC677Bridge { +contract ForeignBridgeNativeToErc is ERC677Receiver, BasicBridge, BasicForeignBridge, ERC677BridgeForBurnableMintableToken, RewardableForeignBridgeNativeToErc { /// Event created on money withdraw. event UserRequestForAffirmation(address recipient, uint256 value); @@ -25,6 +26,75 @@ contract ForeignBridgeNativeToErc is ERC677Receiver, BasicBridge, BasicForeignBr uint256 _homeMaxPerTx, address _owner ) public returns(bool) { + _initialize( + _validatorContract, + _erc677token, + _dailyLimit, + _maxPerTx, + _minPerTx, + _foreignGasPrice, + _requiredBlockConfirmations, + _homeDailyLimit, + _homeMaxPerTx, + _owner + ); + setInitialize(true); + return isInitialized(); + } + + function rewardableInitialize( + address _validatorContract, + address _erc677token, + uint256 _dailyLimit, + uint256 _maxPerTx, + uint256 _minPerTx, + uint256 _foreignGasPrice, + uint256 _requiredBlockConfirmations, + uint256 _homeDailyLimit, + uint256 _homeMaxPerTx, + address _owner, + address _feeManager, + uint256 _homeFee + ) public returns(bool) { + _initialize( + _validatorContract, + _erc677token, + _dailyLimit, + _maxPerTx, + _minPerTx, + _foreignGasPrice, + _requiredBlockConfirmations, + _homeDailyLimit, + _homeMaxPerTx, + _owner + ); + require(isContract(_feeManager)); + addressStorage[keccak256(abi.encodePacked("feeManagerContract"))] = _feeManager; + _setFee(_feeManager, _homeFee, HOME_FEE); + setInitialize(true); + return isInitialized(); + } + + function getBridgeMode() public pure returns(bytes4 _data) { + return bytes4(keccak256(abi.encodePacked("native-to-erc-core"))); + } + + function claimTokensFromErc677(address _token, address _to) external onlyIfOwnerOfProxy { + IBurnableMintableERC677Token(erc677token()).claimTokens(_token, _to); + } + + function _initialize( + address _validatorContract, + address _erc677token, + uint256 _dailyLimit, + uint256 _maxPerTx, + uint256 _minPerTx, + uint256 _foreignGasPrice, + uint256 _requiredBlockConfirmations, + uint256 _homeDailyLimit, + uint256 _homeMaxPerTx, + address _owner + ) internal { require(!isInitialized()); require(_validatorContract != address(0) && isContract(_validatorContract)); require(_minPerTx > 0 && _maxPerTx > _minPerTx && _dailyLimit > _maxPerTx); @@ -42,21 +112,20 @@ contract ForeignBridgeNativeToErc is ERC677Receiver, BasicBridge, BasicForeignBr uintStorage[keccak256(abi.encodePacked("executionDailyLimit"))] = _homeDailyLimit; uintStorage[keccak256(abi.encodePacked("executionMaxPerTx"))] = _homeMaxPerTx; setOwner(_owner); - setInitialize(true); - return isInitialized(); - } - - function getBridgeMode() public pure returns(bytes4 _data) { - return bytes4(keccak256(abi.encodePacked("native-to-erc-core"))); - } - - function claimTokensFromErc677(address _token, address _to) external onlyIfOwnerOfProxy { - erc677token().claimTokens(_token, _to); } - function onExecuteMessage(address _recipient, uint256 _amount) internal returns(bool){ + function onExecuteMessage(address _recipient, uint256 _amount, bytes32 _txHash) internal returns(bool) { setTotalExecutedPerDay(getCurrentDay(), totalExecutedPerDay(getCurrentDay()).add(_amount)); - return erc677token().mint(_recipient, _amount); + uint256 valueToMint = _amount; + address feeManager = feeManagerContract(); + if (feeManager != address(0)) { + uint256 fee = calculateFee(valueToMint, false, feeManager, HOME_FEE); + if (fee != 0) { + distributeFeeFromSignatures(fee, feeManager, _txHash); + valueToMint = valueToMint.sub(fee); + } + } + return IBurnableMintableERC677Token(erc677token()).mint(_recipient, valueToMint); } function fireEventOnTokenTransfer(address _from, uint256 _value) internal { diff --git a/contracts/upgradeable_contracts/native_to_erc20/HomeBridgeNativeToErc.sol b/contracts/upgradeable_contracts/native_to_erc20/HomeBridgeNativeToErc.sol index e561c4c4f..d77fb3b62 100644 --- a/contracts/upgradeable_contracts/native_to_erc20/HomeBridgeNativeToErc.sol +++ b/contracts/upgradeable_contracts/native_to_erc20/HomeBridgeNativeToErc.sol @@ -4,14 +4,25 @@ import "../../libraries/Message.sol"; import "../BasicBridge.sol"; import "../../upgradeability/EternalStorage.sol"; import "../BasicHomeBridge.sol"; +import "./RewardableHomeBridgeNativeToErc.sol"; +import "../Sacrifice.sol"; -contract Sacrifice { - constructor(address _recipient) public payable { - selfdestruct(_recipient); - } -} -contract HomeBridgeNativeToErc is EternalStorage, BasicBridge, BasicHomeBridge { +contract HomeBridgeNativeToErc is EternalStorage, BasicBridge, BasicHomeBridge, RewardableHomeBridgeNativeToErc { + + function () public payable { + require(msg.value > 0); + require(msg.data.length == 0); + require(withinLimit(msg.value)); + setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(msg.value)); + uint256 valueToTransfer = msg.value; + address feeManager = feeManagerContract(); + if (feeManager != address(0)) { + uint256 fee = calculateFee(valueToTransfer, false, feeManager, HOME_FEE); + valueToTransfer = valueToTransfer.sub(fee); + } + emit UserRequestForSignature(msg.sender, valueToTransfer); + } function initialize ( address _validatorContract, @@ -23,8 +34,72 @@ contract HomeBridgeNativeToErc is EternalStorage, BasicBridge, BasicHomeBridge { uint256 _foreignDailyLimit, uint256 _foreignMaxPerTx, address _owner - ) public - returns(bool) + ) public returns(bool) + { + _initialize( + _validatorContract, + _dailyLimit, + _maxPerTx, + _minPerTx, + _homeGasPrice, + _requiredBlockConfirmations, + _foreignDailyLimit, + _foreignMaxPerTx, + _owner + ); + setInitialize(true); + return isInitialized(); + } + + function rewardableInitialize ( + address _validatorContract, + uint256 _dailyLimit, + uint256 _maxPerTx, + uint256 _minPerTx, + uint256 _homeGasPrice, + uint256 _requiredBlockConfirmations, + uint256 _foreignDailyLimit, + uint256 _foreignMaxPerTx, + address _owner, + address _feeManager, + uint256 _homeFee, + uint256 _foreignFee + ) public returns(bool) + { + _initialize( + _validatorContract, + _dailyLimit, + _maxPerTx, + _minPerTx, + _homeGasPrice, + _requiredBlockConfirmations, + _foreignDailyLimit, + _foreignMaxPerTx, + _owner + ); + require(isContract(_feeManager)); + addressStorage[keccak256(abi.encodePacked("feeManagerContract"))] = _feeManager; + _setFee(_feeManager, _homeFee, HOME_FEE); + _setFee(_feeManager, _foreignFee, FOREIGN_FEE); + setInitialize(true); + return isInitialized(); + } + + function getBridgeMode() public pure returns(bytes4 _data) { + return bytes4(keccak256(abi.encodePacked("native-to-erc-core"))); + } + + function _initialize ( + address _validatorContract, + uint256 _dailyLimit, + uint256 _maxPerTx, + uint256 _minPerTx, + uint256 _homeGasPrice, + uint256 _requiredBlockConfirmations, + uint256 _foreignDailyLimit, + uint256 _foreignMaxPerTx, + address _owner + ) internal { require(!isInitialized()); require(_validatorContract != address(0) && isContract(_validatorContract)); @@ -43,26 +118,36 @@ contract HomeBridgeNativeToErc is EternalStorage, BasicBridge, BasicHomeBridge { uintStorage[keccak256(abi.encodePacked("executionDailyLimit"))] = _foreignDailyLimit; uintStorage[keccak256(abi.encodePacked("executionMaxPerTx"))] = _foreignMaxPerTx; setOwner(_owner); - setInitialize(true); - return isInitialized(); - } - - function () public payable { - require(msg.value > 0); - require(msg.data.length == 0); - require(withinLimit(msg.value)); - setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(msg.value)); - emit UserRequestForSignature(msg.sender, msg.value); } - function getBridgeMode() public pure returns(bytes4 _data) { - return bytes4(keccak256(abi.encodePacked("native-to-erc-core"))); + function onSignaturesCollected(bytes _message) internal { + address feeManager = feeManagerContract(); + if (feeManager != address(0)) { + address recipient; + uint256 amount; + bytes32 txHash; + address contractAddress; + (recipient, amount, txHash, contractAddress) = Message.parseMessage(_message); + uint256 fee = calculateFee(amount, true, feeManager, HOME_FEE); + if (fee != 0) { + distributeFeeFromSignatures(fee, feeManager, txHash); + } + } } - function onExecuteAffirmation(address _recipient, uint256 _value) internal returns(bool) { + function onExecuteAffirmation(address _recipient, uint256 _value, bytes32 txHash) internal returns(bool) { setTotalExecutedPerDay(getCurrentDay(), totalExecutedPerDay(getCurrentDay()).add(_value)); - if (!_recipient.send(_value)) { - (new Sacrifice).value(_value)(_recipient); + uint256 valueToTransfer = _value; + + address feeManager = feeManagerContract(); + if (feeManager != address(0)) { + uint256 fee = calculateFee(valueToTransfer, false, feeManager, FOREIGN_FEE); + distributeFeeFromAffirmation(fee, feeManager, txHash); + valueToTransfer = valueToTransfer.sub(fee); + } + + if (!_recipient.send(valueToTransfer)) { + (new Sacrifice).value(valueToTransfer)(_recipient); } return true; } diff --git a/contracts/upgradeable_contracts/native_to_erc20/RewardableForeignBridgeNativeToErc.sol b/contracts/upgradeable_contracts/native_to_erc20/RewardableForeignBridgeNativeToErc.sol new file mode 100644 index 000000000..f7c2dd996 --- /dev/null +++ b/contracts/upgradeable_contracts/native_to_erc20/RewardableForeignBridgeNativeToErc.sol @@ -0,0 +1,15 @@ +pragma solidity 0.4.24; + +import "../RewardableBridge.sol"; + + +contract RewardableForeignBridgeNativeToErc is RewardableBridge { + + function setHomeFee(uint256 _fee) external onlyOwner { + _setFee(feeManagerContract(), _fee, HOME_FEE); + } + + function getHomeFee() public view returns(uint256) { + return _getFee(HOME_FEE); + } +} diff --git a/contracts/upgradeable_contracts/native_to_erc20/RewardableHomeBridgeNativeToErc.sol b/contracts/upgradeable_contracts/native_to_erc20/RewardableHomeBridgeNativeToErc.sol new file mode 100644 index 000000000..71fb926ec --- /dev/null +++ b/contracts/upgradeable_contracts/native_to_erc20/RewardableHomeBridgeNativeToErc.sol @@ -0,0 +1,23 @@ +pragma solidity 0.4.24; + +import "../RewardableBridge.sol"; + + +contract RewardableHomeBridgeNativeToErc is RewardableBridge { + + function setForeignFee(uint256 _fee) external onlyOwner { + _setFee(feeManagerContract(), _fee, FOREIGN_FEE); + } + + function setHomeFee(uint256 _fee) external onlyOwner { + _setFee(feeManagerContract(), _fee, HOME_FEE); + } + + function getForeignFee() public view returns(uint256) { + return _getFee(FOREIGN_FEE); + } + + function getHomeFee() public view returns(uint256) { + return _getFee(HOME_FEE); + } +} diff --git a/deploy/.env.example b/deploy/.env.example index 06bd47ebe..dd9ea4773 100644 --- a/deploy/.env.example +++ b/deploy/.env.example @@ -1,7 +1,14 @@ #BRIDGE_MODE=ERC_TO_ERC BRIDGE_MODE=NATIVE_TO_ERC + +# If Home network does not support byzantium fork, should use contracts compiled for spuriousDragon +#HOME_EVM_VERSION=spuriousDragon + +# If Foreign network does not support byzantium fork, should use contracts compiled for spuriousDragon +#FOREIGN_EVM_VERSION=spuriousDragon + DEPLOYMENT_ACCOUNT_PRIVATE_KEY=67..14 -DEPLOYMENT_GAS_LIMIT=5000000 +DEPLOYMENT_GAS_LIMIT_EXTRA=0.2 HOME_DEPLOYMENT_GAS_PRICE=10000000000 FOREIGN_DEPLOYMENT_GAS_PRICE=10000000000 GET_RECEIPT_INTERVAL_IN_MILLISECONDS=3000 @@ -20,7 +27,6 @@ HOME_MIN_AMOUNT_PER_TX=500000000000000000 HOME_REQUIRED_BLOCK_CONFIRMATIONS=1 HOME_GAS_PRICE=1000000000 -#for bridge erc to native mode BLOCK_REWARD_ADDRESS= FOREIGN_RPC_URL=https://sokol.poa.network @@ -34,8 +40,28 @@ FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=8 FOREIGN_GAS_PRICE=10000000000 #for bridge erc_to_erc and erc_to_native mode ERC20_TOKEN_ADDRESS= +# Only for for erc_to_erc mode +ERC20_EXTENDED_BY_ERC677=false REQUIRED_NUMBER_OF_VALIDATORS=1 #If several validators are used, list them separated by space without quotes #E.g. VALIDATORS=0x 0x 0x VALIDATORS=0x +#Set to ONE_DIRECTION or BOTH_DIRECTIONS if fee will be charged on home side, set to false otherwise +HOME_REWARDABLE=false +# Valid only for rewards on erc_to_native mode. Supported values are BRIDGE_VALIDATORS_REWARD and POSDAO_REWARD +HOME_FEE_MANAGER_TYPE= +#Set to ONE_DIRECTION or BOTH_DIRECTIONS if fee will be charged on foreign side, set to false otherwise +FOREIGN_REWARDABLE=false +#If HOME_REWARDABLE or FOREIGN_REWARDABLE set to true, list validators accounts were rewards should be transferred separated by space without quotes +#E.g. VALIDATORS_REWARD_ACCOUNTS=0x 0x 0x +VALIDATORS_REWARD_ACCOUNTS=0x + +# Fee to be taken for every transaction directed from the Home network to the Foreign network +# E.g. 0.1% fee +HOME_TRANSACTIONS_FEE=0.001 +# Fee to be taken for every transaction directed from the Foreign network to the Home network +FOREIGN_TRANSACTIONS_FEE=0.001 +#for bridge native_to_erc, erc_to_erc mode +DEPLOY_REWARDABLE_TOKEN=false +DPOS_STAKING_ADDRESS= diff --git a/deploy/.nvmrc b/deploy/.nvmrc index fa97ecedc..ec3053c8d 100644 --- a/deploy/.nvmrc +++ b/deploy/.nvmrc @@ -1 +1 @@ -8.9 +10.15 diff --git a/deploy/README.md b/deploy/README.md index 50b38b473..895307237 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -18,7 +18,7 @@ cp .env.example .env 4. Adjust the parameters in the `.env` file depending on the desired bridge mode. See below for comments related to each parameter. -5. Add funds to the deployment accounts in both theHome and Foreign networks. +5. Add funds to the deployment accounts in both the Home and Foreign networks. 6. Run `node deploy.js`. @@ -32,12 +32,22 @@ This example of an `.env` file for the `native-to-erc` bridge mode includes comm # The type of bridge. Defines set of contracts to be deployed. BRIDGE_MODE=NATIVE_TO_ERC +# If Home network does not support byzantium fork, should use contracts compiled for spuriousDragon +# Default value is byzantium +#HOME_EVM_VERSION=spuriousDragon + +# If Foreign network does not support byzantium fork, should use contracts compiled for spuriousDragon +# Default value is byzantium +#FOREIGN_EVM_VERSION=spuriousDragon + # The private key hex value of the account responsible for contracts # deployments and initial configuration. The account's balance must contain # funds from both networks. DEPLOYMENT_ACCOUNT_PRIVATE_KEY=67..14 -# The "gas" parameter set in every deployment/configuration transaction. -DEPLOYMENT_GAS_LIMIT=4000000 +# Extra gas added to the estimated gas of a particular deployment/configuration transaction +# E.g. if estimated gas returns 100000 and the parameter is 0.2, +# the transaction gas limit will be (100000 + 100000 * 0.2) = 120000 +DEPLOYMENT_GAS_LIMIT_EXTRA=0.2 # The "gasPrice" parameter set in every deployment/configuration transaction on # Home network (in Wei). HOME_DEPLOYMENT_GAS_PRICE=10000000000 @@ -58,19 +68,21 @@ BRIDGEABLE_TOKEN_DECIMALS=18 # The RPC channel to a Home node able to handle deployment/configuration # transactions. -HOME_RPC_URL=https://poa.infura.io +HOME_RPC_URL=https://core.poa.network # Address on Home network with permissions to change parameters of the bridge contract. # For extra security we recommended using a multi-sig wallet contract address here. HOME_BRIDGE_OWNER=0x # Address on Home network with permissions to change parameters of bridge validator contract. HOME_VALIDATORS_OWNER=0x -# Address on Home network with permissions to upgrade the bridge contract and the bridge validator contract. +# Address on Home network with permissions to upgrade the bridge contract and the +# bridge validator contract. HOME_UPGRADEABLE_ADMIN=0x # The daily transaction limit in Wei. As soon as this limit is exceeded, any # transaction which requests to relay assets will fail. HOME_DAILY_LIMIT=30000000000000000000000000 # The maximum limit for one transaction in Wei. If a single transaction tries to -# relay funds exceeding this limit it will fail. +# relay funds exceeding this limit it will fail. HOME_MAX_AMOUNT_PER_TX must be +# less than HOME_DAILY_LIMIT. HOME_MAX_AMOUNT_PER_TX=1500000000000000000000000 # The minimum limit for one transaction in Wei. If a transaction tries to relay # funds below this limit it will fail. This is required to prevent dryout @@ -93,13 +105,15 @@ FOREIGN_RPC_URL=https://mainnet.infura.io FOREIGN_BRIDGE_OWNER=0x # Address on Foreign network with permissions to change parameters of bridge validator contract. FOREIGN_VALIDATORS_OWNER=0x -# Address on Foreign network with permissions to upgrade the bridge contract and the bridge validator contract. +# Address on Foreign network with permissions to upgrade the bridge contract and the +# bridge validator contract. FOREIGN_UPGRADEABLE_ADMIN=0x # The daily limit in Wei. As soon as this limit is exceeded, any transaction # requesting to relay assets will fail. FOREIGN_DAILY_LIMIT=15000000000000000000000000 # The maximum limit per one transaction in Wei. If a transaction tries to relay -# funds exceeding this limit it will fail. +# funds exceeding this limit it will fail. FOREIGN_MAX_AMOUNT_PER_TX must be less +# than FOREIGN_DAILY_LIMIT. FOREIGN_MAX_AMOUNT_PER_TX=750000000000000000000000 # The minimum limit for one transaction in Wei. If a transaction tries to relay # funds below this limit it will fail. This is required to prevent dryout @@ -123,6 +137,35 @@ REQUIRED_NUMBER_OF_VALIDATORS=1 # the Foreign network to confirm that the finalized agreement was transferred # correctly to the Foreign network. VALIDATORS=0x 0x 0x + +# Variable to define whether to use RewardableValidators contract and set a fee manager contract on Home network +# On this bridge mode ONE_DIRECTION and BOTH_DIRECTIONS are supported on Home network +HOME_REWARDABLE=false +# Variable to define whether to use RewardableValidators contract and set a fee manager contract on Foreign network +# On this bridge mode ONE_DIRECTION is supported on Foreign network +FOREIGN_REWARDABLE=false +# List validators accounts were rewards should be transferred separated by space without quotes +# Makes sense only when HOME_REWARDABLE!=false or FOREIGN_REWARDABLE!=false +VALIDATORS_REWARD_ACCOUNTS=0x 0x 0x + +# Fee to be taken for every transaction directed from the Home network to the Foreign network +# Makes sense only when FOREIGN_REWARDABLE=ONE_DIRECTION or HOME_REWARDABLE=BOTH_DIRECTIONS +# e.g. 0.1% fee +HOME_TRANSACTIONS_FEE=0.001 +# Fee to be taken for every transaction directed from the Foreign network to the Home network +# Makes sense only when HOME_REWARDABLE!=false +# e.g. 0.1% fee +FOREIGN_TRANSACTIONS_FEE=0.001 + +# The flag defining whether to use ERC677BridgeTokenRewardable contract instead of +# ERC677BridgeToken. +DEPLOY_REWARDABLE_TOKEN=false +# The address of Staking contract used by ERC677BridgeTokenRewardable contract. +# Makes sense only when DEPLOY_REWARDABLE_TOKEN=true +DPOS_STAKING_ADDRESS=0x +# The address of BlockReward contract used by ERC677BridgeTokenRewardable contract. +# Makes sense only when DEPLOY_REWARDABLE_TOKEN=true +BLOCK_REWARD_ADDRESS=0x ``` @@ -134,12 +177,22 @@ This example of an `.env` file for the `erc-to-erc` bridge mode includes comment # The type of bridge. Defines set of contracts to be deployed. BRIDGE_MODE=ERC_TO_ERC +# If Home network does not support byzantium fork, should use contracts compiled for spuriousDragon +# Default value is byzantium +#HOME_EVM_VERSION=spuriousDragon + +# If Foreign network does not support byzantium fork, should use contracts compiled for spuriousDragon +# Default value is byzantium +#FOREIGN_EVM_VERSION=spuriousDragon + # The private key hex value of the account responsible for contracts # deployments and initial configuration. The account's balance must contain # funds from both networks. DEPLOYMENT_ACCOUNT_PRIVATE_KEY=67..14 -# The "gas" parameter set in every deployment/configuration transaction. -DEPLOYMENT_GAS_LIMIT=4000000 +# Extra gas added to the estimated gas of a particular deployment/configuration transaction +# E.g. if estimated gas returns 100000 and the parameter is 0.2, +# the transaction gas limit will be (100000 + 100000 * 0.2) = 120000 +DEPLOYMENT_GAS_LIMIT_EXTRA=0.2 # The "gasPrice" parameter set in every deployment/configuration transaction on # Home network (in Wei). HOME_DEPLOYMENT_GAS_PRICE=10000000000 @@ -160,23 +213,25 @@ BRIDGEABLE_TOKEN_DECIMALS=18 # The RPC channel to a Home node able to handle deployment/configuration # transactions. -HOME_RPC_URL=https://poa.infura.io +HOME_RPC_URL=https://core.poa.network # Address on Home network with permissions to change parameters of the bridge contract. # For extra security we recommended using a multi-sig wallet contract address here. HOME_BRIDGE_OWNER=0x # Address on Home network with permissions to change parameters of bridge validator contract. HOME_VALIDATORS_OWNER=0x -# Address on Home network with permissions to upgrade the bridge contract and the bridge validator contract. +# Address on Home network with permissions to upgrade the bridge contract and +# the bridge validator contract. HOME_UPGRADEABLE_ADMIN=0x # The daily transaction limit in Wei. As soon as this limit is exceeded, any # transaction which requests to relay assets will fail. HOME_DAILY_LIMIT=30000000000000000000000000 # The maximum limit for one transaction in Wei. If a single transaction tries to -# relay funds exceeding this limit it will fail. +# relay funds exceeding this limit it will fail. HOME_MAX_AMOUNT_PER_TX must be +# less than HOME_DAILY_LIMIT. HOME_MAX_AMOUNT_PER_TX=1500000000000000000000000 # The minimum limit for one transaction in Wei. If a transaction tries to relay # funds below this limit it will fail. This is required to prevent dryout -# validator accounts. +# validator accounts. HOME_MIN_AMOUNT_PER_TX=500000000000000000 # The finalization threshold. The number of blocks issued after the block with # the corresponding deposit transaction to guarantee the transaction will not be @@ -195,13 +250,16 @@ FOREIGN_RPC_URL=https://mainnet.infura.io FOREIGN_BRIDGE_OWNER=0x # Address on Foreign network with permissions to change parameters of bridge validator contract. FOREIGN_VALIDATORS_OWNER=0x -# Address on Foreign network with permissions to upgrade the bridge contract and the bridge validator contract. +# Address on Foreign network with permissions to upgrade the bridge contract and the +# bridge validator contract. FOREIGN_UPGRADEABLE_ADMIN=0x -# These three parameters are not used in this mode, but the deployment script -# requires it to be set to some value. -FOREIGN_DAILY_LIMIT=0 -FOREIGN_MAX_AMOUNT_PER_TX=0 -FOREIGN_MIN_AMOUNT_PER_TX=0 +# The daily transaction limit in Wei. Used on the Home side to check the bridge validator’s actions. +FOREIGN_DAILY_LIMIT=15000000000000000000000000 +# The maximum limit for one transaction in Wei. FOREIGN_MAX_AMOUNT_PER_TX must be less +# than FOREIGN_DAILY_LIMIT. Used on the Home side to check the bridge validator’s actions. +FOREIGN_MAX_AMOUNT_PER_TX=750000000000000000000000 +# Not used in this mode, comment out or delete this variable. +# FOREIGN_MIN_AMOUNT_PER_TX= # The finalization threshold. The number of blocks issued after the block with # the corresponding deposit transaction to guarantee the transaction will not be # rolled back. @@ -213,6 +271,8 @@ FOREIGN_GAS_PRICE=10000000000 # The address of the existing ERC20 compatible token in the Foreign network to # be exchanged to the ERC20/ERC677 token deployed on Home. ERC20_TOKEN_ADDRESS=0x +# Flag to specify that the existing ERC20 is also ERC677 compatible and want the Foreign bridge to use it as ERC677 to increase security. +ERC20_EXTENDED_BY_ERC677=false # The minimum number of validators required to send their signatures confirming # the relay of assets. The same number of validators is expected on both sides @@ -223,6 +283,16 @@ REQUIRED_NUMBER_OF_VALIDATORS=1 # the Foreign network to confirm that the finalized agreement was transferred # correctly to the Foreign network. VALIDATORS=0x 0x 0x + +# The flag defining whether to use ERC677BridgeTokenRewardable contract instead of +# ERC677BridgeToken. +DEPLOY_REWARDABLE_TOKEN=false +# The address of Staking contract used by ERC677BridgeTokenRewardable contract. +# Makes sense only when DEPLOY_REWARDABLE_TOKEN=true +DPOS_STAKING_ADDRESS=0x +# The address of BlockReward contract used by ERC677BridgeTokenRewardable contract. +# Makes sense only when DEPLOY_REWARDABLE_TOKEN=true +BLOCK_REWARD_ADDRESS=0x ``` ## `ERC-TO-NATIVE` Bridge Mode Configuration Example. @@ -233,12 +303,22 @@ This example of an `.env` file for the `erc-to-native` bridge mode includes comm # The type of bridge. Defines set of contracts to be deployed. BRIDGE_MODE=ERC_TO_NATIVE +# If Home network does not support byzantium fork, should use contracts compiled for spuriousDragon +# Default value is byzantium +#HOME_EVM_VERSION=spuriousDragon + +# If Foreign network does not support byzantium fork, should use contracts compiled for spuriousDragon +# Default value is byzantium +#FOREIGN_EVM_VERSION=spuriousDragon + # The private key hex value of the account responsible for contracts # deployments and initial configuration. The account's balance must contain # funds from both networks. DEPLOYMENT_ACCOUNT_PRIVATE_KEY=67..14 -# The "gas" parameter set in every deployment/configuration transaction. -DEPLOYMENT_GAS_LIMIT=4000000 +# Extra gas added to the estimated gas of a particular deployment/configuration transaction +# E.g. if estimated gas returns 100000 and the parameter is 0.2, +# the transaction gas limit will be (100000 + 100000 * 0.2) = 120000 +DEPLOYMENT_GAS_LIMIT_EXTRA=0.2 # The "gasPrice" parameter set in every deployment/configuration transaction on # Home network (in Wei). HOME_DEPLOYMENT_GAS_PRICE=10000000000 @@ -251,19 +331,21 @@ GET_RECEIPT_INTERVAL_IN_MILLISECONDS=3000 # The RPC channel to a Home node able to handle deployment/configuration # transactions. -HOME_RPC_URL=https://poa.infura.io +HOME_RPC_URL=https://core.poa.network # Address on Home network with permissions to change parameters of the bridge contract. # For extra security we recommended using a multi-sig wallet contract address here. HOME_BRIDGE_OWNER=0x # Address on Home network with permissions to change parameters of bridge validator contract. HOME_VALIDATORS_OWNER=0x -# Address on Home network with permissions to upgrade the bridge contract and the bridge validator contract. +# Address on Home network with permissions to upgrade the bridge contract and the +# bridge validator contract. HOME_UPGRADEABLE_ADMIN=0x # The daily transaction limit in Wei. As soon as this limit is exceeded, any # transaction which requests to relay assets will fail. HOME_DAILY_LIMIT=30000000000000000000000000 # The maximum limit for one transaction in Wei. If a single transaction tries to -# relay funds exceeding this limit it will fail. +# relay funds exceeding this limit it will fail. HOME_MAX_AMOUNT_PER_TX must be +# less than HOME_DAILY_LIMIT. HOME_MAX_AMOUNT_PER_TX=1500000000000000000000000 # The minimum limit for one transaction in Wei. If a transaction tries to relay # funds below this limit it will fail. This is required to prevent dryout @@ -287,15 +369,20 @@ FOREIGN_RPC_URL=https://mainnet.infura.io # Address on Foreign network with permissions to change parameters of the bridge contract. # For extra security we recommended using a multi-sig wallet contract address here. FOREIGN_BRIDGE_OWNER=0x -# Address on Foreign network with permissions to change parameters of bridge validator contract. +# Address on the Foreign network with permissions to change parameters of +# the bridge validator contract. FOREIGN_VALIDATORS_OWNER=0x -# Address on Foreign network with permissions to upgrade the bridge contract and the bridge validator contract. +# Address on the Foreign network with permissions to upgrade the bridge contract +# and the bridge validator contract. FOREIGN_UPGRADEABLE_ADMIN=0x -# These three parameters are not used in this mode, but the deployment script -# requires it to be set to some value. -FOREIGN_DAILY_LIMIT=0 -FOREIGN_MAX_AMOUNT_PER_TX=0 -FOREIGN_MIN_AMOUNT_PER_TX=0 +# The daily transaction limit in Wei. Used on the Home side to check +# the bridge validator’s actions. +FOREIGN_DAILY_LIMIT=15000000000000000000000000 +# The maximum limit for one transaction in Wei. FOREIGN_MAX_AMOUNT_PER_TX must be +# less than FOREIGN_DAILY_LIMIT. Used on the Home side to check the bridge validator’s actions. +FOREIGN_MAX_AMOUNT_PER_TX=750000000000000000000000 +# Not used in this mode, comment out or delete this variable. +# FOREIGN_MIN_AMOUNT_PER_TX= # The finalization threshold. The number of blocks issued after the block with # the corresponding deposit transaction to guarantee the transaction will not be # rolled back. @@ -318,4 +405,27 @@ REQUIRED_NUMBER_OF_VALIDATORS=1 # the Foreign network to confirm that the finalized agreement was transferred # correctly to the Foreign network. VALIDATORS=0x 0x 0x + + +# Variable to define whether to use RewardableValidators contract and set a fee manager contract on Home network +# On this bridge mode only BOTH_DIRECTIONS is supported on Home network +HOME_REWARDABLE=false +# Variable to define whether to use RewardableValidators contract and set a fee manager contract on Foreign network +# Collecting fees on Foreign network is not supported on this bridge mode. +FOREIGN_REWARDABLE=false +# Variable to define if Home network is a POSDAO and rewards are distributed by blockReward contract to network validators or transferred directly to bridge validators. +# Supported values are BRIDGE_VALIDATORS_REWARD and POSDAO_REWARD +HOME_FEE_MANAGER_TYPE=BRIDGE_VALIDATORS_REWARD +# List validators accounts were rewards should be transferred separated by space without quotes +# Makes sense only when HOME_REWARDABLE=BOTH_DIRECTIONS +VALIDATORS_REWARD_ACCOUNTS=0x 0x 0x + +# Fee to be taken for every transaction directed from the Home network to the Foreign network +# Makes sense only when HOME_REWARDABLE=BOTH_DIRECTIONS +# e.g. 0.1% fee +HOME_TRANSACTIONS_FEE=0.001 +# Fee to be taken for every transaction directed from the Foreign network to the Home network +# Makes sense only when HOME_REWARDABLE=BOTH_DIRECTIONS +# e.g. 0.1% fee +FOREIGN_TRANSACTIONS_FEE=0.001 ``` diff --git a/deploy/deploy.js b/deploy/deploy.js index a727c5d49..9af9c126e 100644 --- a/deploy/deploy.js +++ b/deploy/deploy.js @@ -42,9 +42,10 @@ async function deployNativeToErc() { } async function deployErcToErc() { + const preDeploy = require('./src/erc_to_erc/preDeploy') const deployHome = require('./src/erc_to_erc/home') const deployForeign = require('./src/erc_to_erc/foreign') - + await preDeploy() const { homeBridge, erc677 } = await deployHome() const { foreignBridge } = await deployForeign() console.log('\nDeployment has been completed.\n\n') diff --git a/deploy/package-lock.json b/deploy/package-lock.json index a63423650..a2822c902 100644 --- a/deploy/package-lock.json +++ b/deploy/package-lock.json @@ -24,6 +24,25 @@ "js-tokens": "^4.0.0" } }, + "@babel/parser": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.2.3.tgz", + "integrity": "sha512-0LyEcVlfCoFmci8mXx8A5oIkpkOgyo8dRHtxBnK9RRBwxO2+JZPNsqtVEZQ7mJFPxnXF9lfmU24mHOPI0qnlkA==" + }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" + }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", @@ -34,54 +53,32 @@ } }, "acorn": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", - "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.0.tgz", + "integrity": "sha512-MW/FjM+IvU9CgBzjO3UIPCE2pyEwUsoFl+VGdczOPEdxfGFjuKny/gN54mOuX7Qxmb9Rg9MCn2oKiSUeW+pjrw==", + "dev": true }, "acorn-jsx": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-4.1.1.tgz", - "integrity": "sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw==", - "dev": true, - "requires": { - "acorn": "^5.0.3" - } - }, - "acorn-object-rest-spread": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/acorn-object-rest-spread/-/acorn-object-rest-spread-1.1.0.tgz", - "integrity": "sha1-eGma790Y7DGCyq2t9S4ml8BI9HY=", - "requires": { - "acorn": "^5.0.3" - } + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "dev": true }, "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz", + "integrity": "sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==", "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", + "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, - "ajv-keywords": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", - "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", - "dev": true - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "optional": true - }, "ansi-escapes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true }, "ansi-regex": { @@ -112,6 +109,21 @@ "sprintf-js": "~1.0.2" } }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -130,16 +142,23 @@ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" }, "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } }, "asn1.js": { "version": "4.10.1", @@ -156,6 +175,17 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", @@ -166,23 +196,28 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, "babel-runtime": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.25.0.tgz", - "integrity": "sha1-M7mOql1IK7AajRqmtDetKwGuxBw=", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { "core-js": "^2.4.0", - "regenerator-runtime": "^0.10.0" + "regenerator-runtime": "^0.11.0" } }, "balanced-match": { @@ -190,24 +225,76 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, "base64-js": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.3.tgz", - "integrity": "sha512-MsAhsUW1GxCdgYSO6tAfZrNapmUKk7mWx/k5mFY/A1gBtkaCaNapTg+FExCw1r9yeaZhqx/xPg43xgTFH6KL5w==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" }, "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "optional": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "requires": { "tweetnacl": "^0.14.3" } }, "bindings": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz", - "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.4.0.tgz", + "integrity": "sha512-7znEVX22Djn+nYjxCWKDne0RRloa9XfYa84yk3s+HkE3LpDYZmhArYr9O9huBoHY3/oXispx5LorIX7Sl2CgSQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } }, "bip66": { "version": "1.1.5", @@ -235,9 +322,9 @@ } }, "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" }, "bn.js": { "version": "4.11.8", @@ -245,28 +332,20 @@ "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, "body-parser": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", - "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", "requires": { "bytes": "3.0.0", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.1", - "http-errors": "~1.6.2", - "iconv-lite": "0.4.19", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", "on-finished": "~2.3.0", - "qs": "6.5.1", - "raw-body": "2.3.2", - "type-is": "~1.6.15" - } - }, - "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", - "requires": { - "hoek": "4.x.x" + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" } }, "brace-expansion": { @@ -278,15 +357,42 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, "browserify-aes": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz", - "integrity": "sha512-UGnTYAnB2a3YuYKIRy1/4FB2HdM866E0qC46JXvVTYKlBlZlnvfpSfY6OKfXZAkv70eJ2a1SqzpAo5CRhZGDFg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -297,9 +403,9 @@ } }, "browserify-cipher": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz", - "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "requires": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", @@ -307,13 +413,14 @@ } }, "browserify-des": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz", - "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "requires": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", - "inherits": "^2.0.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "browserify-rsa": { @@ -326,11 +433,12 @@ } }, "browserify-sha3": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/browserify-sha3/-/browserify-sha3-0.0.1.tgz", - "integrity": "sha1-P/NKMAbvFcD7NWflQbkaI0ASPRE=", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/browserify-sha3/-/browserify-sha3-0.0.4.tgz", + "integrity": "sha1-CGxHuMgjFsnUcCLCYYWVRXbdjiY=", "requires": { - "js-sha3": "^0.3.1" + "js-sha3": "^0.6.1", + "safe-buffer": "^5.1.1" } }, "browserify-sign": { @@ -348,19 +456,38 @@ } }, "buffer": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.1.0.tgz", - "integrity": "sha512-YkIRgwsZwJWTnyQrsBTWefizHh+8GYj3kbL1BTiAQ/9pwpino0G7B2gp5tx/FUBqUlvtxV85KNR3mwfAtv15Yw==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" } }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" + }, "buffer-to-arraybuffer": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", @@ -371,12 +498,6 @@ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, "byline": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", @@ -387,19 +508,31 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "requires": { - "callsites": "^0.2.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" } }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" + }, "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", + "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", "dev": true }, "caseless": { @@ -408,13 +541,13 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.1.0", + "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", - "supports-color": "^4.0.0" + "supports-color": "^5.3.0" } }, "chardet": { @@ -432,11 +565,26 @@ "safe-buffer": "^5.0.1" } }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } }, "cli-cursor": { "version": "2.1.0", @@ -453,17 +601,21 @@ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", "dev": true }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } }, "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "requires": { - "color-name": "^1.1.1" + "color-name": "1.1.3" } }, "color-name": { @@ -472,9 +624,9 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "requires": { "delayed-stream": "~1.0.0" } @@ -487,6 +639,11 @@ "graceful-readlink": ">= 1.0.0" } }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -518,10 +675,15 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, "core-js": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.4.tgz", - "integrity": "sha1-8si/GB8qgLkvNgEhQpzmOi8K6uA=" + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", + "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==" }, "core-util-is": { "version": "1.0.2", @@ -529,38 +691,39 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cors": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz", - "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=", + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "requires": { "object-assign": "^4", "vary": "^1" } }, "create-ecdh": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", - "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "requires": { "bn.js": "^4.1.0", "elliptic": "^6.0.0" } }, "create-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", - "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", - "ripemd160": "^2.0.0", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", "sha.js": "^2.4.0" } }, "create-hmac": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", - "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -581,32 +744,6 @@ "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", - "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", - "dev": true - } - } - }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "requires": { - "boom": "5.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - } } }, "crypto-browserify": { @@ -661,6 +798,13 @@ "make-dir": "^1.0.0", "pify": "^2.3.0", "strip-dirs": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } } }, "decompress-response": { @@ -734,6 +878,11 @@ "object-assign": "^4.0.1", "pinkie-promise": "^2.0.0" } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } }, @@ -751,33 +900,39 @@ "object-keys": "^1.0.12" } }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -807,19 +962,28 @@ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, "diffie-hellman": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", - "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "requires": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", "randombytes": "^2.0.0" } }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { "esutils": "^2.0.2" @@ -851,12 +1015,12 @@ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" }, "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "requires": { - "jsbn": "~0.1.0" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "ee-first": { @@ -865,9 +1029,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", + "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -878,6 +1042,12 @@ "minimalistic-crypto-utils": "^1.0.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -892,23 +1062,28 @@ } }, "envalid": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/envalid/-/envalid-4.1.4.tgz", - "integrity": "sha512-Xz1fNmcAFLQsUcYgoN2YmXkl9hGfLFXpvTHJKEBW/Nsqj+/4WoFnGf6wbdxJXIx5aKpdapf8XJCGrCRfrk2OZg==", - "requires": { - "chalk": "2.1.0", - "dotenv": "4.0.0", - "meant": "1.0.0", - "validator": "9.4.1" + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/envalid/-/envalid-4.2.2.tgz", + "integrity": "sha512-D6RV00pb4c/eKzslI8bwCeLhBrD9GzNrAa2QRoSto9LdwEQXhsHUKfI61areFi6LvLDVFmlHnrk/SD34UJiMpg==", + "requires": { + "chalk": "^2.4.1", + "dotenv": "^6.2.0", + "meant": "^1.0.1", + "validator": "^10.11.0" }, "dependencies": { "dotenv": { - "version": "4.0.0", - "resolved": "http://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz", - "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=" + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", + "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==" } } }, + "err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=" + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -919,27 +1094,28 @@ } }, "es-abstract": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", - "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", "dev": true, "requires": { - "es-to-primitive": "^1.1.1", + "es-to-primitive": "^1.2.0", "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" } }, "es-to-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", - "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "dev": true, "requires": { - "is-callable": "^1.1.1", + "is-callable": "^1.1.4", "is-date-object": "^1.0.1", - "is-symbol": "^1.0.1" + "is-symbol": "^1.0.2" } }, "escape-html": { @@ -953,94 +1129,74 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz", + "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", "requires": { - "esprima": "^2.7.1", - "estraverse": "^1.9.1", + "esprima": "^3.1.3", + "estraverse": "^4.2.0", "esutils": "^2.0.2", "optionator": "^0.8.1", - "source-map": "~0.2.0" + "source-map": "~0.6.1" } }, "eslint": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.6.0.tgz", - "integrity": "sha512-/eVYs9VVVboX286mBK7bbKnO1yamUy2UCRjiY6MryhQL2PaaXCExsCQ2aO83OeYRhU2eCU/FMFP+tVMoOrzNrA==", + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.14.1.tgz", + "integrity": "sha512-CyUMbmsjxedx8B0mr79mNOqetvkbij/zrXnFeK2zc3pGRn3/tibjiNAv/3UxFEyfMDjh+ZqTrJrEGBFiGfD5Og==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "ajv": "^6.5.3", + "ajv": "^6.9.1", "chalk": "^2.1.0", "cross-spawn": "^6.0.5", - "debug": "^3.1.0", - "doctrine": "^2.1.0", + "debug": "^4.0.1", + "doctrine": "^3.0.0", "eslint-scope": "^4.0.0", "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", - "espree": "^4.0.0", + "espree": "^5.0.1", "esquery": "^1.0.1", "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", + "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", "glob": "^7.1.2", "globals": "^11.7.0", "ignore": "^4.0.6", + "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.1.0", - "is-resolvable": "^1.1.0", + "inquirer": "^6.2.2", "js-yaml": "^3.12.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", - "lodash": "^4.17.5", + "lodash": "^4.17.11", "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", "progress": "^2.0.0", - "regexpp": "^2.0.0", - "require-uncached": "^1.0.3", + "regexpp": "^2.0.1", "semver": "^5.5.1", "strip-ansi": "^4.0.0", "strip-json-comments": "^2.0.1", - "table": "^4.0.3", + "table": "^5.2.3", "text-table": "^0.2.0" }, "dependencies": { - "ajv": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz", - "integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, "debug": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", - "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" } }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, "ms": { @@ -1048,12 +1204,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true - }, - "semver": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", - "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", - "dev": true } } }, @@ -1069,9 +1219,9 @@ } }, "eslint-config-prettier": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-3.0.1.tgz", - "integrity": "sha512-vA0TB8HCx/idHXfKHYcg9J98p0Q8nkfNwNAoP7e+ywUidn6ScaFS5iqncZAHPz+/a0A/tp657ulFHFx/2JDP4Q==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-3.6.0.tgz", + "integrity": "sha512-ixJ4U3uTLXwJts4rmSVW/lMXjlGwCijhBJHk8iVqKKSifeI0qgFEfWl8L63isfc8Od7EiBALF6BX3jKLluf/jQ==", "dev": true, "requires": { "get-stdin": "^6.0.0" @@ -1085,55 +1235,44 @@ "requires": { "debug": "^2.6.9", "resolve": "^1.5.0" - }, - "dependencies": { - "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } - } } }, "eslint-module-utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", - "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.3.0.tgz", + "integrity": "sha512-lmDJgeOOjk8hObTysjqH7wyMi+nsHwwvfBykwfhjR1LNdd7C2uFJBvx4OpWYpXOw4df1yE1cDEVd1yLHitk34w==", "dev": true, "requires": { "debug": "^2.6.8", - "pkg-dir": "^1.0.0" + "pkg-dir": "^2.0.0" } }, "eslint-plugin-es": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.3.1.tgz", - "integrity": "sha512-9XcVyZiQRVeFjqHw8qHNDAZcQLqaHlOGGpeYqzYh8S4JYCWTCO3yzyen8yVmA5PratfzTRWDwCOFphtDEG+w/w==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.4.0.tgz", + "integrity": "sha512-XfFmgFdIUDgvaRAlaXUkxrRg5JSADoRC8IkKLc/cISeR3yHVMefFHQZpcyXXEUUPHfy5DwviBcrfqlyqEwlQVw==", "dev": true, "requires": { "eslint-utils": "^1.3.0", - "regexpp": "^2.0.0" + "regexpp": "^2.0.1" } }, "eslint-plugin-import": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz", - "integrity": "sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.16.0.tgz", + "integrity": "sha512-z6oqWlf1x5GkHIFgrSvtmudnqM6Q60KM4KvpWi5ubonMjycLjndvd5+8VAZIsTlHC03djdgJuyKG6XO577px6A==", "dev": true, "requires": { "contains-path": "^0.1.0", - "debug": "^2.6.8", + "debug": "^2.6.9", "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.2.0", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.3.0", + "has": "^1.0.3", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", "read-pkg-up": "^2.0.0", - "resolve": "^1.6.0" + "resolve": "^1.9.0" }, "dependencies": { "doctrine": { @@ -1147,12 +1286,12 @@ } }, "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", "dev": true, "requires": { - "path-parse": "^1.0.5" + "path-parse": "^1.0.6" } } } @@ -1171,27 +1310,27 @@ "semver": "^5.5.0" }, "dependencies": { + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", "dev": true, "requires": { - "path-parse": "^1.0.5" + "path-parse": "^1.0.6" } - }, - "semver": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", - "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", - "dev": true } } }, "eslint-plugin-prettier": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.2.tgz", - "integrity": "sha512-tGek5clmW5swrAx1mdPYM8oThrBE83ePh7LeseZHBWfHVGrHPhKn7Y5zgRMbU/9D5Td9K4CEmUPjGxA7iw98Og==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.7.0.tgz", + "integrity": "sha512-CStQYJgALoQBw3FsBzH0VOVDRnJ/ZimUlpLm226U8qgqYJfPOY/CPK6wyRInMxh73HSKg5wyRwdS4BVYYHwokA==", "dev": true, "requires": { "fast-diff": "^1.1.1", @@ -1212,14 +1351,6 @@ "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" - }, - "dependencies": { - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true - } } }, "eslint-utils": { @@ -1235,27 +1366,20 @@ "dev": true }, "espree": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-4.0.0.tgz", - "integrity": "sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", + "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", "dev": true, "requires": { - "acorn": "^5.6.0", - "acorn-jsx": "^4.1.1" - }, - "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true - } + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" } }, "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" }, "esquery": { "version": "1.0.1", @@ -1264,14 +1388,6 @@ "dev": true, "requires": { "estraverse": "^4.0.0" - }, - "dependencies": { - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true - } } }, "esrecurse": { @@ -1281,20 +1397,12 @@ "dev": true, "requires": { "estraverse": "^4.1.0" - }, - "dependencies": { - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true - } } }, "estraverse": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" }, "esutils": { "version": "2.0.2", @@ -1326,18 +1434,18 @@ "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=" }, "ethereumjs-tx": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.4.tgz", - "integrity": "sha512-kOgUd5jC+0tgV7t52UDECMMz9Uf+Lro+6fSpCvzWemtXfMEcwI3EOxf5mVPMRbTFkMMhuERokNNVF3jItAjidg==", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz", + "integrity": "sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA==", "requires": { "ethereum-common": "^0.0.18", "ethereumjs-util": "^5.0.0" } }, "ethereumjs-util": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.5.tgz", - "integrity": "sha512-xPaSEATYJpMTCGowIt0oMZwFP4R1bxd6QsWgkcDvFL0JtXsr39p32WEcD14RscCjfP41YXZPCVWA4yAg0nrJmw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", "requires": { "bn.js": "^4.11.0", "create-hash": "^1.1.2", @@ -1365,9 +1473,9 @@ } }, "ethjs-util": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.4.tgz", - "integrity": "sha1-HItoeSV0RO9NPz+7rC3tEs2ZfZM=", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", "requires": { "is-hex-prefixed": "1.0.0", "strip-hex-prefix": "1.0.0" @@ -1387,19 +1495,51 @@ "safe-buffer": "^5.1.1" } }, - "expand-template": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.0.3.tgz", - "integrity": "sha1-bDAzIxd6YrGyLAcCefeGEoe2mxo=" - }, - "express": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", - "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "requires": { - "accepts": "~1.3.5", - "array-flatten": "1.1.1", - "body-parser": "1.18.2", + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-template": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.1.tgz", + "integrity": "sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg==" + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", "content-disposition": "0.5.2", "content-type": "~1.0.4", "cookie": "0.3.1", @@ -1416,10 +1556,10 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.3", - "qs": "6.5.1", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", "range-parser": "~1.2.0", - "safe-buffer": "5.1.1", + "safe-buffer": "5.1.2", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", @@ -1429,11 +1569,6 @@ "vary": "~1.1.2" }, "dependencies": { - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, "statuses": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", @@ -1442,9 +1577,28 @@ } }, "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } }, "external-editor": { "version": "3.0.3", @@ -1468,22 +1622,94 @@ } } }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "fast-diff": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz", - "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, + "fast-glob": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.6.tgz", + "integrity": "sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w==", + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -1495,9 +1721,9 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, "fd-slicer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", - "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "requires": { "pend": "~1.2.0" } @@ -1512,13 +1738,12 @@ } }, "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", "dev": true, "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "flat-cache": "^2.0.1" } }, "file-type": { @@ -1526,6 +1751,32 @@ "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "finalhandler": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", @@ -1548,47 +1799,56 @@ } }, "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "locate-path": "^2.0.0" } }, "flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, "requires": { - "circular-json": "^0.3.1", - "del": "^2.0.2", - "graceful-fs": "^4.1.2", - "write": "^0.2.1" + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" } }, + "flatted": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", + "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", + "dev": true + }, "for-each": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.2.tgz", - "integrity": "sha1-LEBFC5NI6X8oEyJZO6lnBLmr1NQ=", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "requires": { - "is-function": "~1.0.0" + "is-callable": "^1.1.3" } }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "requires": { "asynckit": "^0.4.0", - "combined-stream": "1.0.6", + "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } }, @@ -1597,18 +1857,41 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "fs-extra": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz", - "integrity": "sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "requires": { "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0" + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, "fs-promise": { @@ -1620,6 +1903,25 @@ "fs-extra": "^2.0.0", "mz": "^2.6.0", "thenify-all": "^1.6.0" + }, + "dependencies": { + "fs-extra": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz", + "integrity": "sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "requires": { + "graceful-fs": "^4.1.6" + } + } } }, "fs.realpath": { @@ -1661,6 +1963,11 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -1670,9 +1977,9 @@ } }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1682,6 +1989,30 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=" + }, "global": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", @@ -1692,21 +2023,23 @@ } }, "globals": { - "version": "11.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", - "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", "dev": true }, "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", "requires": { "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" } }, "got": { @@ -1731,9 +2064,9 @@ } }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, "graceful-readlink": { "version": "1.0.1", @@ -1746,11 +2079,11 @@ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "requires": { - "ajv": "^5.1.0", + "ajv": "^6.5.5", "har-schema": "^2.0.0" } }, @@ -1764,9 +2097,9 @@ } }, "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbol-support-x": { "version": "1.4.2", @@ -1787,32 +2120,51 @@ "has-symbol-support-x": "^1.4.1" } }, - "hash-base": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", - "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "requires": { - "inherits": "^2.0.1" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" } }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "requires": { - "boom": "4.x.x", - "cryptiles": "3.x.x", - "hoek": "4.x.x", - "sntp": "2.x.x" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" } }, "hmac-drbg": { @@ -1825,11 +2177,6 @@ "minimalistic-crypto-utils": "^1.0.1" } }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", @@ -1837,21 +2184,14 @@ "dev": true }, "http-errors": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", - "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { - "depd": "1.1.1", + "depd": "~1.1.2", "inherits": "2.0.3", - "setprototypeof": "1.0.3", - "statuses": ">= 1.3.1 < 2" - }, - "dependencies": { - "depd": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" - } + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" } }, "http-https": { @@ -1870,20 +2210,32 @@ } }, "iconv-lite": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } }, "ieee754": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz", - "integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg==" + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", + "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==" }, "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" + }, + "import-fresh": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", + "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } }, "imurmurhash": { "version": "0.1.4", @@ -1911,30 +2263,74 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "inquirer": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz", - "integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz", + "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==", "dev": true, "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", - "external-editor": "^3.0.0", + "external-editor": "^3.0.3", "figures": "^2.0.0", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "mute-stream": "0.0.7", "run-async": "^2.2.0", - "rxjs": "^6.1.0", + "rxjs": "^6.4.0", "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", + "strip-ansi": "^5.0.0", "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", + "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", + "dev": true + }, + "strip-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", + "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", + "dev": true, + "requires": { + "ansi-regex": "^4.0.0" + } + } + } + }, + "into-stream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-4.0.0.tgz", + "integrity": "sha512-i29KNyE5r0Y/UQzcQ0IbZO1MYJ53Jn0EcFRZPj5FzWKYH17kDFEOwuA+3jroymOI06SW1dEDnly9A1CAreC5dg==", + "requires": { + "from2": "^2.1.1", + "p-is-promise": "^2.0.0" } }, "ipaddr.js": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", - "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } }, "is-arrayish": { "version": "0.2.1", @@ -1942,20 +2338,33 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } }, "is-date-object": { "version": "1.0.1", @@ -1963,6 +2372,33 @@ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", "dev": true }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -1974,6 +2410,14 @@ "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz", "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=" }, + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "requires": { + "is-extglob": "^2.1.1" + } + }, "is-hex-prefixed": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", @@ -1984,40 +2428,42 @@ "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=" }, - "is-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", - "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" - }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", - "dev": true - }, - "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "is-path-inside": "^1.0.0" + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, - "is-path-inside": { + "is-object": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "requires": { - "path-is-inside": "^1.0.1" - } + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" }, "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -2033,12 +2479,6 @@ "has": "^1.0.1" } }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, "is-retry-allowed": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", @@ -2050,16 +2490,24 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-symbol": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", - "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", - "dev": true + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -2071,6 +2519,11 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -2092,9 +2545,9 @@ "dev": true }, "js-sha3": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.3.1.tgz", - "integrity": "sha1-hhIoAhQvCChQKg0d7h2V4lO7AkM=" + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.6.1.tgz", + "integrity": "sha1-W4n3enR3Z5h39YxKB1JAk0sflcA=" }, "js-tokens": { "version": "4.0.0", @@ -2103,9 +2556,9 @@ "dev": true }, "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", + "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -2123,8 +2576,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "json-schema": { "version": "0.2.3", @@ -2132,17 +2584,9 @@ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "requires": { - "jsonify": "~0.0.0" - } + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -2156,18 +2600,13 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "requires": { "graceful-fs": "^4.1.6" } }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -2191,14 +2630,19 @@ } }, "keccakjs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/keccakjs/-/keccakjs-0.2.1.tgz", - "integrity": "sha1-HWM6+QfvMFu/ny+mFtVsRFYd+k0=", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/keccakjs/-/keccakjs-0.2.3.tgz", + "integrity": "sha512-BjLkNDcfaZ6l8HBG9tH0tpmDv3sS2mA7FNQxFHpCdzP3Gb2MVruXBSuoM66SnVxKJpAr5dKGdkHD+bDokt8fTg==", "requires": { - "browserify-sha3": "^0.0.1", - "sha3": "^1.1.0" + "browserify-sha3": "^0.0.4", + "sha3": "^1.2.2" } }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -2210,7 +2654,7 @@ }, "load-json-file": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { @@ -2218,6 +2662,14 @@ "parse-json": "^2.2.0", "pify": "^2.0.0", "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } } }, "locate-path": { @@ -2228,14 +2680,6 @@ "requires": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } } }, "lodash": { @@ -2250,44 +2694,40 @@ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" }, "make-dir": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz", - "integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "requires": { "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - } + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" } }, "md5.js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", - "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "requires": { "hash-base": "^3.0.0", - "inherits": "^2.0.1" - }, - "dependencies": { - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - } + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "meant": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/meant/-/meant-1.0.0.tgz", - "integrity": "sha1-y2KG47evkxXxYRj9wiRybtOAdLs=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/meant/-/meant-1.0.1.tgz", + "integrity": "sha512-UakVLFjKkbbUwNWJ2frVLnnAtbb7D7DsloxRd3s/gDpI8rdv8W5Hp3NaDb+POBI1fQdeussER6NB8vpcRURvlg==" }, "media-typer": { "version": "0.3.0", @@ -2299,11 +2739,36 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "merge2": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", + "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==" + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, "miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", @@ -2319,16 +2784,16 @@ "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" }, "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" }, "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", "requires": { - "mime-db": "~1.33.0" + "mime-db": "~1.38.0" } }, "mimic-fn": { @@ -2338,9 +2803,9 @@ "dev": true }, "mimic-response": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz", - "integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" }, "min-document": { "version": "2.19.0", @@ -2351,9 +2816,9 @@ } }, "minimalistic-assert": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", - "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "minimalistic-crypto-utils": { "version": "1.0.1", @@ -2369,9 +2834,28 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } }, "mkdirp": { "version": "0.5.1", @@ -2379,6 +2863,13 @@ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } } }, "mkdirp-promise": { @@ -2390,9 +2881,9 @@ } }, "mock-fs": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.4.2.tgz", - "integrity": "sha512-dF+yxZSojSiI8AXGoxj5qdFWpucndc54Ug+TwlpHFaV7j22MGG+OML2+FVa6xAZtjb/OFFQhOC37Jegx2GbEwA==" + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.8.0.tgz", + "integrity": "sha512-Gwj4KnJOW15YeTJKO5frFd/WDO5Mc0zxXqL9oHx3+e9rBqW8EVARqQHSaIXznUdljrD6pvbNGW2ZGXKPEfYJfw==" }, "mout": { "version": "0.11.1", @@ -2405,9 +2896,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "multistream": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/multistream/-/multistream-2.1.0.tgz", - "integrity": "sha1-YlwmfVxEQkrWKUeItbtNo9yzLx0=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/multistream/-/multistream-2.1.1.tgz", + "integrity": "sha512-xasv76hl6nr1dEy3lPvy7Ej7K/Lx3O/FCvwge8PeVJpciPPoNCbaANcNiBug3IpdvTveZUcAV0DJzdnUDMesNQ==", "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.5" @@ -2430,15 +2921,33 @@ } }, "nan": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" }, "nano-json-stream-parser": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", "integrity": "sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=" }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -2457,20 +2966,31 @@ "dev": true }, "node-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", - "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", + "integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==" }, "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", + "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "resolve": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } } }, "number-to-bn": { @@ -2490,21 +3010,57 @@ } }, "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "object-keys": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", "dev": true }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", @@ -2518,15 +3074,23 @@ } }, "object.entries": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz", - "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", - "has": "^1.0.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" } }, "oboe": { @@ -2590,6 +3154,11 @@ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" }, + "p-is-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", + "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==" + }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", @@ -2622,16 +3191,26 @@ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, + "parent-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.0.tgz", + "integrity": "sha512-8Mf5juOMmiE4FcmzYc4IaiS9L3+9paz2KOiXzkRviCP6aDmN49Hz6EMWz0lGNp9pX80GvvAuLADtyGfW/Em3TA==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-asn1": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz", - "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", + "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", "requires": { "asn1.js": "^4.0.0", "browserify-aes": "^1.0.0", "create-hash": "^1.1.0", "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3" + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" } }, "parse-headers": { @@ -2657,14 +3236,21 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true }, "path-is-absolute": { "version": "1.0.1", @@ -2684,9 +3270,9 @@ "dev": true }, "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "path-to-regexp": { "version": "0.1.7", @@ -2694,18 +3280,17 @@ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "requires": { - "pify": "^2.0.0" + "pify": "^3.0.0" } }, "pbkdf2": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", - "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -2725,9 +3310,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, "pinkie": { "version": "2.0.4", @@ -2743,241 +3328,69 @@ } }, "pkg": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/pkg/-/pkg-4.3.1.tgz", - "integrity": "sha512-QaOXdF9doVkrXpeu0D5ODLDLjYE4LE2WAk7/wSgNiCsCajg4ExjApxwkVIanz61tR8oIe+8vkmW0WpAwfV1ExA==", - "requires": { - "acorn": "5.5.3", - "acorn-object-rest-spread": "1.1.0", - "babel-runtime": "6.25.0", - "chalk": "2.1.0", - "escodegen": "1.8.1", - "fs-extra": "4.0.1", - "globby": "6.1.0", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/pkg/-/pkg-4.3.7.tgz", + "integrity": "sha512-/BvtFft1nKKtnTuOm/0es0sk1cOs7ZtWgJpqdtszJ4348jYJ8owVyCB/iuGhI3YJFX/ZFIv4Rmra9ETUgpnnfA==", + "requires": { + "@babel/parser": "7.2.3", + "babel-runtime": "6.26.0", + "chalk": "2.4.2", + "escodegen": "1.11.0", + "fs-extra": "7.0.1", + "globby": "8.0.2", + "into-stream": "4.0.0", "minimist": "1.2.0", - "multistream": "2.1.0", - "pkg-fetch": "2.5.4", - "progress": "2.0.0", - "resolve": "1.4.0", - "simple-bufferstream": "1.0.0", + "multistream": "2.1.1", + "pkg-fetch": "2.5.7", + "progress": "2.0.3", + "resolve": "1.6.0", "stream-meter": "1.0.4" - }, - "dependencies": { - "fs-extra": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.1.tgz", - "integrity": "sha1-f8DGyJV/mD9X8waiTlud3Y0N2IA=", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^3.0.0", - "universalify": "^0.1.0" - } - }, - "jsonfile": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", - "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - } } }, "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { - "find-up": "^1.0.0" + "find-up": "^2.1.0" } }, "pkg-fetch": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-2.5.4.tgz", - "integrity": "sha512-KASiP5yytve4otDY242Zp3r+e11whyoSl79QmmBS3Qg4rvZsYOC5RE0szM0SZrVxg93sqYcINxHlXmzBTJDOeA==", - "requires": { - "babel-runtime": "6.25.0", - "byline": "5.0.0", - "chalk": "2.1.0", - "expand-template": "1.0.3", - "fs-extra": "4.0.1", - "in-publish": "2.0.0", - "minimist": "1.2.0", - "progress": "2.0.0", - "request": "2.81.0", - "request-progress": "3.0.0", - "semver": "5.4.1", - "unique-temp-dir": "1.0.0" + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-2.5.7.tgz", + "integrity": "sha512-fm9aVV3ZRdFYTyFYcSHuKMuxPCVQ0MD9tbVxbvQzFTg1gwvV0KqWrFoj5enVVha94yP83I50XEBa90X8L9fE8w==", + "requires": { + "babel-runtime": "~6.26.0", + "byline": "~5.0.0", + "chalk": "~2.4.1", + "expand-template": "~1.1.1", + "fs-extra": "~6.0.1", + "in-publish": "~2.0.0", + "minimist": "~1.2.0", + "progress": "~2.0.0", + "request": "~2.88.0", + "request-progress": "~3.0.0", + "semver": "~5.6.0", + "unique-temp-dir": "~1.0.0" }, "dependencies": { - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" - } - }, - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" - }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "requires": { - "hoek": "2.x.x" - } - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "requires": { - "boom": "2.x.x" - } - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" - } - }, "fs-extra": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.1.tgz", - "integrity": "sha1-f8DGyJV/mD9X8waiTlud3Y0N2IA=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", + "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", "requires": { "graceful-fs": "^4.1.2", - "jsonfile": "^3.0.0", + "jsonfile": "^4.0.0", "universalify": "^0.1.0" } - }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" - }, - "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "requires": { - "ajv": "^4.9.1", - "har-schema": "^1.0.5" - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "jsonfile": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", - "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - }, - "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" - }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" - }, - "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~4.2.1", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "performance-now": "^0.2.0", - "qs": "~6.4.0", - "safe-buffer": "^5.0.1", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.0.0" - } - }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "requires": { - "hoek": "2.x.x" - } } } }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, "prelude-ls": { "version": "1.1.2", @@ -2990,9 +3403,9 @@ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, "prettier": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz", - "integrity": "sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg==", + "version": "1.16.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz", + "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==", "dev": true }, "process": { @@ -3006,40 +3419,55 @@ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, "progress": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", - "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + }, + "promise-retry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", + "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + } }, "proxy-addr": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", - "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", "requires": { "forwarded": "~0.1.2", - "ipaddr.js": "1.6.0" + "ipaddr.js": "1.8.0" } }, + "psl": { + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" + }, "public-encrypt": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", - "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "requires": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", "create-hash": "^1.1.0", "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1" + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "query-string": { "version": "5.1.1", @@ -3079,13 +3507,13 @@ "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" }, "raw-body": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", - "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", "requires": { "bytes": "3.0.0", - "http-errors": "1.6.2", - "iconv-lite": "0.4.19", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", "unpipe": "1.0.0" } }, @@ -3098,6 +3526,23 @@ "load-json-file": "^2.0.0", "normalize-package-data": "^2.3.2", "path-type": "^2.0.0" + }, + "dependencies": { + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } } }, "read-pkg-up": { @@ -3108,71 +3553,77 @@ "requires": { "find-up": "^2.0.0", "read-pkg": "^2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - } } }, "readable-stream": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz", - "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", + "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "regenerator-runtime": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } }, "regexpp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.0.tgz", - "integrity": "sha512-g2FAVtR8Uh8GO1Nv5wpxW7VFVwHcCEr4wyA8/MHiRkO8uHoR5ntAA8Uq3P1vvMTX/BeQiRVSpDGLd+Wn5HNOTA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, "request": { - "version": "2.85.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", - "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "requires": { "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", + "aws4": "^1.8.0", "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "hawk": "~6.0.2", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "stringstream": "~0.0.5", - "tough-cookie": "~2.3.3", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" + "uuid": "^3.3.2" } }, "request-progress": { @@ -3183,30 +3634,25 @@ "throttleit": "^1.0.0" } }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - } - }, "resolve": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", - "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz", + "integrity": "sha512-mw7JQNu5ExIkcw4LPih0owX/TZXjD/ZUF/ZQ/pDnkw3ZKhDcZZw5klmBlj6gVMwjQ3Pz5Jgu7F3d0jcDVuEWdw==", "requires": { "path-parse": "^1.0.5" } }, "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -3217,27 +3663,41 @@ "signal-exit": "^3.0.2" } }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=" + }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "ripemd160": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", - "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "requires": { - "hash-base": "^2.0.0", + "hash-base": "^3.0.0", "inherits": "^2.0.1" } }, "rlp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.0.0.tgz", - "integrity": "sha1-nbOE/0uJqPYVY9kjldhiWxjzr7A=" + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.2.tgz", + "integrity": "sha512-Ng2kJEN731Sfv4ZAY2i0ytPMc0BbJKBsVNl0QZY8LxOWSwd+1xpg+fpSRfaMn0heHU447s6Kgy8qfHZR0XTyVw==", + "requires": { + "bn.js": "^4.11.1", + "safe-buffer": "^5.1.1" + } }, "run-async": { "version": "2.3.0", @@ -3249,24 +3709,31 @@ } }, "rxjs": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.2.tgz", - "integrity": "sha512-hV7criqbR0pe7EeL3O66UYVg92IR0XsA97+9y+BWTePK9SKmEI5Qd3Zj6uPnGkNzXsBywBQWTvujPl+1Kn9Zjw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", "dev": true, "requires": { "tslib": "^1.9.0" } }, "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "scrypt": { "version": "6.0.3", @@ -3294,9 +3761,9 @@ } }, "secp256k1": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.5.0.tgz", - "integrity": "sha512-e5QIJl8W7Y4tT6LHffVcZAxJjvpgE5Owawv6/XCYPQljE9aP2NFFddQ8OYMKhdLshNu88FfL3qCN3/xYkXGRsA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.6.2.tgz", + "integrity": "sha512-90nYt7yb0LmI4A2jJs1grglkTAXrBwxYAjP9bpeKjvJKOjG2fOeH/YI/lchDMIvjrOasd5QXwvV2jwN168xNng==", "requires": { "bindings": "^1.2.1", "bip66": "^1.1.3", @@ -3317,9 +3784,9 @@ } }, "semver": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" }, "send": { "version": "0.16.2", @@ -3371,15 +3838,36 @@ "xhr": "^2.3.3" } }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, "setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" }, "sha.js": { "version": "2.4.11", @@ -3391,11 +3879,18 @@ } }, "sha3": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/sha3/-/sha3-1.2.0.tgz", - "integrity": "sha1-aYnxtwpJhwWHajc+LGKs6WqpOZo=", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-1.2.2.tgz", + "integrity": "sha1-pmxQmN5MJbyIM27ItIF9AFvKe6k=", "requires": { - "nan": "^2.0.5" + "nan": "2.10.0" + }, + "dependencies": { + "nan": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" + } } }, "shebang-command": { @@ -3419,56 +3914,166 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, - "simple-bufferstream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/simple-bufferstream/-/simple-bufferstream-1.0.0.tgz", - "integrity": "sha1-XKsQ6FGqccZnt3th/hux2QpguqQ=" - }, "simple-concat": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" }, "simple-get": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.7.0.tgz", - "integrity": "sha512-RkE9rGPHcxYZ/baYmgJtOSM63vH0Vyq+ma5TijBcLla41SWlh8t6XYIGMR/oeZcmr+/G8k+zrClkkVrtnQ0esg==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", + "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", "requires": { "decompress-response": "^3.3.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, - "slice-ansi": { + "slash": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", "dev": true, "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" } }, - "sntp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", - "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "requires": { - "hoek": "4.x.x" + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "source-map": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", - "optional": true, + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "requires": { - "amdefine": ">=0.0.4" + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -3476,9 +4081,9 @@ } }, "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", "dev": true }, "spdx-expression-parse": { @@ -3492,11 +4097,19 @@ } }, "spdx-license-ids": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz", - "integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", "dev": true }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -3504,9 +4117,9 @@ "dev": true }, "sshpk": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", - "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -3515,9 +4128,29 @@ "ecc-jsbn": "~0.1.1", "getpass": "^0.1.1", "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" } }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -3547,18 +4180,13 @@ } }, "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" } }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" - }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -3597,11 +4225,11 @@ "dev": true }, "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^2.0.0" + "has-flag": "^3.0.0" } }, "swarm-js": { @@ -3622,45 +4250,64 @@ "setimmediate": "^1.0.5", "tar.gz": "^1.0.5", "xhr-request-promise": "^0.1.2" + }, + "dependencies": { + "fs-extra": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz", + "integrity": "sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "requires": { + "graceful-fs": "^4.1.6" + } + } } }, "table": { - "version": "4.0.3", - "resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz", - "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz", + "integrity": "sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==", "dev": true, "requires": { - "ajv": "^6.0.1", - "ajv-keywords": "^3.0.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" + "ajv": "^6.9.1", + "lodash": "^4.17.11", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" }, "dependencies": { - "ajv": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz", - "integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==", + "ansi-regex": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", + "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", + "dev": true + }, + "string-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.0.0.tgz", + "integrity": "sha512-rr8CUxBbvOZDUvc5lNIJ+OC1nPVpz+Siw9VBtUjB9b6jZehZLFt0JMCZzShFHIsI8cbhm0EsNIfWJMFV3cu3Ew==", "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.0.0" } }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "strip-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", + "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", + "dev": true, + "requires": { + "ansi-regex": "^4.0.0" + } } } }, @@ -3675,13 +4322,16 @@ } }, "tar-stream": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz", - "integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", "requires": { "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", "end-of-stream": "^1.0.0", - "readable-stream": "^2.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", "xtend": "^4.0.0" } }, @@ -3750,12 +4400,63 @@ "os-tmpdir": "~1.0.2" } }, + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { + "psl": "^1.1.24", "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } } }, "trim": { @@ -3780,8 +4481,7 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "type-check": { "version": "0.3.2", @@ -3819,36 +4519,51 @@ "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" }, "unbzip2-stream": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz", - "integrity": "sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", + "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", "requires": { - "buffer": "^3.0.1", - "through": "^2.3.6" + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" }, "dependencies": { - "base64-js": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", - "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg=" + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } }, - "buffer": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", - "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "requires": { - "base64-js": "0.0.8", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" } } } }, - "underscore": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", - "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" - }, "unique-temp-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unique-temp-dir/-/unique-temp-dir-1.0.0.tgz", @@ -3860,32 +4575,64 @@ } }, "universalify": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", - "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + } + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, "requires": { "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } } }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, "url-parse-lax": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", @@ -3904,6 +4651,11 @@ "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, "utf8": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.1.tgz", @@ -3920,9 +4672,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "validate-npm-package-license": { "version": "3.0.4", @@ -3935,9 +4687,9 @@ } }, "validator": { - "version": "9.4.1", - "resolved": "http://registry.npmjs.org/validator/-/validator-9.4.1.tgz", - "integrity": "sha512-YV5KjzvRmSyJ1ee/Dm5UED0G+1L4GZnLN3w6/T+zZm8scVua4sOhYKWTUrKa0H/tMiJyO9QLHMPN+9mB/aMunA==" + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", + "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" }, "vary": { "version": "1.1.2", @@ -4192,7 +4944,7 @@ "requires": { "underscore": "1.8.3", "web3-core-helpers": "1.0.0-beta.33", - "websocket": "git://github.com/frozeman/WebSocket-Node.git#7004c39c42ac98875ab61126e5b4a925430f592c" + "websocket": "websocket@git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" } }, "web3-shh": { @@ -4228,8 +4980,8 @@ } }, "websocket": { - "version": "git://github.com/frozeman/WebSocket-Node.git#7004c39c42ac98875ab61126e5b4a925430f592c", - "from": "websocket@git://github.com/frozeman/WebSocket-Node.git#7004c39c42ac98875ab61126e5b4a925430f592c", + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", "requires": { "debug": "^2.2.0", "nan": "^2.3.3", @@ -4257,9 +5009,9 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", "dev": true, "requires": { "mkdirp": "^0.5.1" @@ -4276,9 +5028,9 @@ } }, "xhr": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.4.1.tgz", - "integrity": "sha512-pAIU5vBr9Hiy5cpFIbPnwf0C18ZF86DBsZKrlsf87N5De/JbA6RJ83UP/cv+aljl4S40iRVMqP4pr4sF9Dnj0A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.5.0.tgz", + "integrity": "sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==", "requires": { "global": "~4.3.0", "is-function": "^1.0.1", @@ -4324,12 +5076,12 @@ "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" }, "yauzl": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.9.1.tgz", - "integrity": "sha1-qBmB6nCleUYTOIPwKcWCGok1mn8=", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "requires": { "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.0.1" + "fd-slicer": "~1.1.0" } } } diff --git a/deploy/package.json b/deploy/package.json index ecace1df5..cfbc85fba 100644 --- a/deploy/package.json +++ b/deploy/package.json @@ -10,12 +10,14 @@ "author": "", "license": "ISC", "dependencies": { + "bignumber.js": "^7.2.1", "dotenv": "^5.0.1", "envalid": "^4.1.4", "ethereumjs-tx": "^1.3.4", "node-fetch": "^2.1.2", "pkg": "^4.3.1", - "web3": "^1.0.0-beta.33" + "promise-retry": "^1.1.1", + "web3": "1.0.0-beta.33" }, "devDependencies": { "eslint": "^5.6.0", diff --git a/deploy/src/constants.js b/deploy/src/constants.js index 362c403bb..6f05af970 100644 --- a/deploy/src/constants.js +++ b/deploy/src/constants.js @@ -1,5 +1,10 @@ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' +const EVM_TYPES = { + BYZANTIUM: 'byzantium', + SPURIOUSDRAGON: 'spuriousDragon' +} module.exports = { - ZERO_ADDRESS + ZERO_ADDRESS, + EVM_TYPES } diff --git a/deploy/src/deploymentUtils.js b/deploy/src/deploymentUtils.js index 3d06a86fd..c08b48368 100644 --- a/deploy/src/deploymentUtils.js +++ b/deploy/src/deploymentUtils.js @@ -1,15 +1,17 @@ +const BigNumber = require('bignumber.js') const Web3 = require('web3') const Tx = require('ethereumjs-tx') const Web3Utils = require('web3-utils') const fetch = require('node-fetch') const assert = require('assert') +const promiseRetry = require('promise-retry') const { web3Home, web3Foreign, deploymentPrivateKey, FOREIGN_RPC_URL, HOME_RPC_URL, - GAS_LIMIT, + GAS_LIMIT_EXTRA, HOME_DEPLOYMENT_GAS_PRICE, FOREIGN_DEPLOYMENT_GAS_PRICE, GET_RECEIPT_INTERVAL_IN_MILLISECONDS @@ -46,7 +48,7 @@ async function deployContract(contractJson, args, { from, network, nonce }) { url, gasPrice }) - if (Web3Utils.hexToNumber(tx.status) !== 1) { + if (Web3Utils.hexToNumber(tx.status) !== 1 && !tx.contractAddress) { throw new Error('Tx failed') } instance.options.address = tx.contractAddress @@ -70,10 +72,32 @@ async function sendRawTxForeign(options) { async function sendRawTx({ data, nonce, to, privateKey, url, gasPrice, value }) { try { + const txToEstimateGas = { + from: privateKeyToAddress(Web3Utils.bytesToHex(privateKey)), + value, + to, + data + } + const estimatedGas = BigNumber(await sendNodeRequest(url, 'eth_estimateGas', txToEstimateGas)) + + const blockData = await sendNodeRequest(url, 'eth_getBlockByNumber', ['latest', false]) + const blockGasLimit = BigNumber(blockData.gasLimit) + if (estimatedGas.isGreaterThan(blockGasLimit)) { + throw new Error( + `estimated gas greater (${estimatedGas.toString()}) than the block gas limit (${blockGasLimit.toString()})` + ) + } + let gas = estimatedGas.multipliedBy(BigNumber(1 + GAS_LIMIT_EXTRA)) + if (gas.isGreaterThan(blockGasLimit)) { + gas = blockGasLimit + } else { + gas = gas.toFixed(0) + } + const rawTx = { nonce, gasPrice: Web3Utils.toHex(gasPrice), - gasLimit: Web3Utils.toHex(GAS_LIMIT), + gasLimit: Web3Utils.toHex(gas), to, data, value @@ -88,14 +112,16 @@ async function sendRawTx({ data, nonce, to, privateKey, url, gasPrice, value }) `0x${serializedTx.toString('hex')}` ) console.log('pending txHash', txHash) - const receipt = await getReceipt(txHash, url) - return receipt + return await getReceipt(txHash, url) } catch (e) { console.error(e) } } async function sendNodeRequest(url, method, signedData) { + if (!Array.isArray(signedData)) { + signedData = [signedData] + } const request = await fetch(url, { headers: { 'Content-type': 'application/json' @@ -104,15 +130,18 @@ async function sendNodeRequest(url, method, signedData) { body: JSON.stringify({ jsonrpc: '2.0', method, - params: [signedData], + params: signedData, id: 1 }) }) const json = await request.json() - if (method === 'eth_sendRawTransaction') { - assert.strictEqual(json.result.length, 66, `Tx wasn't sent ${json}`) + if (typeof json.error === 'undefined' || json.error === null) { + if (method === 'eth_sendRawTransaction') { + assert.strictEqual(json.result.length, 66, `Tx wasn't sent ${json}`) + } + return json.result } - return json.result + throw new Error(`web3 RPC failed: ${JSON.stringify(json.error)}`) } function timeout(ms) { @@ -140,12 +169,143 @@ function privateKeyToAddress(privateKey) { return new Web3().eth.accounts.privateKeyToAccount(add0xPrefix(privateKey)).address } +function logValidatorsAndRewardAccounts(validators, rewards) { + console.log(`VALIDATORS\n==========`) + validators.forEach((validator, index) => { + console.log(`${index + 1}: ${validator}, reward address ${rewards[index]}`) + }) +} + +async function upgradeProxy({ proxy, implementationAddress, version, nonce, url }) { + const data = await proxy.methods.upgradeTo(version, implementationAddress).encodeABI() + const sendTx = getSendTxMethod(url) + const result = await sendTx({ + data, + nonce, + to: proxy.options.address, + privateKey: deploymentPrivateKey, + url + }) + if (result.status) { + assert.strictEqual(Web3Utils.hexToNumber(result.status), 1, 'Transaction Failed') + } else { + await assertStateWithRetry(proxy.methods.implementation().call, implementationAddress) + } +} + +async function transferProxyOwnership({ proxy, newOwner, nonce, url }) { + const data = await proxy.methods.transferProxyOwnership(newOwner).encodeABI() + const sendTx = getSendTxMethod(url) + const result = await sendTx({ + data, + nonce, + to: proxy.options.address, + privateKey: deploymentPrivateKey, + url + }) + if (result.status) { + assert.strictEqual(Web3Utils.hexToNumber(result.status), 1, 'Transaction Failed') + } else { + await assertStateWithRetry(proxy.methods.proxyOwner().call, newOwner) + } +} + +async function transferOwnership({ contract, newOwner, nonce, url }) { + const data = await contract.methods.transferOwnership(newOwner).encodeABI() + const sendTx = getSendTxMethod(url) + const result = await sendTx({ + data, + nonce, + to: contract.options.address, + privateKey: deploymentPrivateKey, + url + }) + if (result.status) { + assert.strictEqual(Web3Utils.hexToNumber(result.status), 1, 'Transaction Failed') + } else { + await assertStateWithRetry(contract.methods.owner().call, newOwner) + } +} + +async function setBridgeContract({ contract, bridgeAddress, nonce, url }) { + const data = await contract.methods.setBridgeContract(bridgeAddress).encodeABI() + const sendTx = getSendTxMethod(url) + const result = await sendTx({ + data, + nonce, + to: contract.options.address, + privateKey: deploymentPrivateKey, + url + }) + if (result.status) { + assert.strictEqual(Web3Utils.hexToNumber(result.status), 1, 'Transaction Failed') + } else { + await assertStateWithRetry(contract.methods.bridgeContract().call, bridgeAddress) + } +} + +async function initializeValidators({ + contract, + isRewardableBridge, + requiredNumber, + validators, + rewardAccounts, + owner, + nonce, + url +}) { + let data + + if (isRewardableBridge) { + console.log(`REQUIRED_NUMBER_OF_VALIDATORS: ${requiredNumber}, VALIDATORS_OWNER: ${owner}`) + logValidatorsAndRewardAccounts(validators, rewardAccounts) + data = await contract.methods + .initialize(requiredNumber, validators, rewardAccounts, owner) + .encodeABI() + } else { + console.log( + `REQUIRED_NUMBER_OF_VALIDATORS: ${requiredNumber}, VALIDATORS: ${validators}, VALIDATORS_OWNER: ${owner}` + ) + data = await contract.methods.initialize(requiredNumber, validators, owner).encodeABI() + } + const sendTx = getSendTxMethod(url) + const result = await sendTx({ + data, + nonce, + to: contract.options.address, + privateKey: deploymentPrivateKey, + url + }) + if (result.status) { + assert.strictEqual(Web3Utils.hexToNumber(result.status), 1, 'Transaction Failed') + } else { + await assertStateWithRetry(contract.methods.isInitialized().call, true) + } +} + +async function assertStateWithRetry(fn, expected) { + return promiseRetry(async retry => { + const value = await fn() + if (value !== expected) { + retry(`Transaction Failed. Expected: ${expected} Actual: ${value}`) + } + }) +} + +function getSendTxMethod(url) { + return url === HOME_RPC_URL ? sendRawTxHome : sendRawTxForeign +} + module.exports = { deployContract, - sendNodeRequest, - getReceipt, - sendRawTx, sendRawTxHome, sendRawTxForeign, - privateKeyToAddress + privateKeyToAddress, + logValidatorsAndRewardAccounts, + upgradeProxy, + initializeValidators, + transferProxyOwnership, + transferOwnership, + setBridgeContract, + assertStateWithRetry } diff --git a/deploy/src/erc_to_erc/foreign.js b/deploy/src/erc_to_erc/foreign.js index 6dc7d81f9..1daa1b215 100644 --- a/deploy/src/erc_to_erc/foreign.js +++ b/deploy/src/erc_to_erc/foreign.js @@ -2,12 +2,24 @@ const assert = require('assert') const Web3Utils = require('web3-utils') const env = require('../loadEnv') -const { deployContract, privateKeyToAddress, sendRawTxForeign } = require('../deploymentUtils') +const { + deployContract, + privateKeyToAddress, + sendRawTxForeign, + upgradeProxy, + initializeValidators, + transferProxyOwnership, + assertStateWithRetry +} = require('../deploymentUtils') const { web3Foreign, deploymentPrivateKey, FOREIGN_RPC_URL } = require('../web3') - -const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json') -const BridgeValidators = require('../../../build/contracts/BridgeValidators.json') -const ForeignBridge = require('../../../build/contracts/ForeignBridgeErcToErc.json') +const { + foreignContracts: { + EternalStorageProxy, + BridgeValidators, + ForeignBridgeErcToErc: ForeignBridge, + ForeignBridgeErc677ToErc677 + } +} = require('../loadContracts') const VALIDATORS = env.VALIDATORS.split(' ') @@ -22,16 +34,77 @@ const { FOREIGN_GAS_PRICE, FOREIGN_MAX_AMOUNT_PER_TX, HOME_DAILY_LIMIT, - HOME_MAX_AMOUNT_PER_TX + HOME_MAX_AMOUNT_PER_TX, + FOREIGN_MIN_AMOUNT_PER_TX, + FOREIGN_DAILY_LIMIT, + ERC20_EXTENDED_BY_ERC677 } = env const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY) +async function initializeBridge({ validatorsBridge, bridge, nonce }) { + console.log(`Foreign Validators: ${validatorsBridge.options.address}, + ERC20_TOKEN_ADDRESS: ${ERC20_TOKEN_ADDRESS}, + FOREIGN_MAX_AMOUNT_PER_TX: ${FOREIGN_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + FOREIGN_MAX_AMOUNT_PER_TX + )} in eth, + FOREIGN_GAS_PRICE: ${FOREIGN_GAS_PRICE}, FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS : ${FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS}, + HOME_DAILY_LIMIT: ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth, + HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MAX_AMOUNT_PER_TX + )} in eth, + FOREIGN_BRIDGE_OWNER: ${FOREIGN_BRIDGE_OWNER} + `) + let initializeFBridgeData + + if (ERC20_EXTENDED_BY_ERC677) { + initializeFBridgeData = await bridge.methods + .initialize( + validatorsBridge.options.address, + ERC20_TOKEN_ADDRESS, + FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS, + FOREIGN_GAS_PRICE, + FOREIGN_DAILY_LIMIT, + FOREIGN_MAX_AMOUNT_PER_TX, + FOREIGN_MIN_AMOUNT_PER_TX, + HOME_DAILY_LIMIT, + HOME_MAX_AMOUNT_PER_TX, + FOREIGN_BRIDGE_OWNER + ) + .encodeABI() + } else { + initializeFBridgeData = await bridge.methods + .initialize( + validatorsBridge.options.address, + ERC20_TOKEN_ADDRESS, + FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS, + FOREIGN_GAS_PRICE, + FOREIGN_MAX_AMOUNT_PER_TX, + HOME_DAILY_LIMIT, + HOME_MAX_AMOUNT_PER_TX, + FOREIGN_BRIDGE_OWNER + ) + .encodeABI() + } + const txInitializeBridge = await sendRawTxForeign({ + data: initializeFBridgeData, + nonce, + to: bridge.options.address, + privateKey: deploymentPrivateKey, + url: FOREIGN_RPC_URL + }) + if (txInitializeBridge.status) { + assert.strictEqual(Web3Utils.hexToNumber(txInitializeBridge.status), 1, 'Transaction Failed') + } else { + await assertStateWithRetry(bridge.methods.isInitialized().call, true) + } +} + async function deployForeign() { if (!Web3Utils.isAddress(ERC20_TOKEN_ADDRESS)) { throw new Error('ERC20_TOKEN_ADDRESS env var is not defined') } - let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) + let nonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) console.log('========================================') console.log('deploying ForeignBridge') console.log('========================================\n') @@ -40,154 +113,103 @@ async function deployForeign() { const storageValidatorsForeign = await deployContract(EternalStorageProxy, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', - nonce: foreignNonce + nonce }) - foreignNonce++ + nonce++ console.log('[Foreign] BridgeValidators Storage: ', storageValidatorsForeign.options.address) console.log('\ndeploying implementation for foreign validators') const bridgeValidatorsForeign = await deployContract(BridgeValidators, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', - nonce: foreignNonce + nonce }) - foreignNonce++ + nonce++ console.log( '[Foreign] BridgeValidators Implementation: ', bridgeValidatorsForeign.options.address ) console.log('\nhooking up eternal storage to BridgeValidators') - const upgradeToBridgeVForeignData = await storageValidatorsForeign.methods - .upgradeTo('1', bridgeValidatorsForeign.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txUpgradeToBridgeVForeign = await sendRawTxForeign({ - data: upgradeToBridgeVForeignData, - nonce: foreignNonce, - to: storageValidatorsForeign.options.address, - privateKey: deploymentPrivateKey, + await upgradeProxy({ + proxy: storageValidatorsForeign, + implementationAddress: bridgeValidatorsForeign.options.address, + version: '1', + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual( - Web3Utils.hexToNumber(txUpgradeToBridgeVForeign.status), - 1, - 'Transaction Failed' - ) - foreignNonce++ + nonce++ console.log('\ninitializing Foreign Bridge Validators with following parameters:\n') - console.log( - `REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}` - ) - bridgeValidatorsForeign.options.address = storageValidatorsForeign.options.address - const initializeForeignData = await bridgeValidatorsForeign.methods - .initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, FOREIGN_VALIDATORS_OWNER) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txInitializeForeign = await sendRawTxForeign({ - data: initializeForeignData, - nonce: foreignNonce, - to: bridgeValidatorsForeign.options.address, - privateKey: deploymentPrivateKey, + await initializeValidators({ + contract: bridgeValidatorsForeign, + isRewardableBridge: false, + requiredNumber: REQUIRED_NUMBER_OF_VALIDATORS, + validators: VALIDATORS, + rewardAccounts: [], + owner: FOREIGN_VALIDATORS_OWNER, + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txInitializeForeign.status), 1, 'Transaction Failed') - foreignNonce++ + nonce++ console.log('\nTransferring ownership of ValidatorsProxy\n') - const validatorsForeignOwnershipData = await storageValidatorsForeign.methods - .transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txValidatorsForeignOwnershipData = await sendRawTxForeign({ - data: validatorsForeignOwnershipData, - nonce: foreignNonce, - to: storageValidatorsForeign.options.address, - privateKey: deploymentPrivateKey, + await transferProxyOwnership({ + proxy: storageValidatorsForeign, + newOwner: FOREIGN_UPGRADEABLE_ADMIN, + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual( - Web3Utils.hexToNumber(txValidatorsForeignOwnershipData.status), - 1, - 'Transaction Failed' - ) - foreignNonce++ + nonce++ console.log('\ndeploying foreignBridge storage\n') const foreignBridgeStorage = await deployContract(EternalStorageProxy, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', - nonce: foreignNonce + nonce }) - foreignNonce++ + nonce++ console.log('[Foreign] ForeignBridge Storage: ', foreignBridgeStorage.options.address) console.log('\ndeploying foreignBridge implementation\n') - const foreignBridgeImplementation = await deployContract(ForeignBridge, [], { + const bridgeContract = ERC20_EXTENDED_BY_ERC677 ? ForeignBridgeErc677ToErc677 : ForeignBridge + const foreignBridgeImplementation = await deployContract(bridgeContract, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', - nonce: foreignNonce + nonce }) - foreignNonce++ + nonce++ console.log( '[Foreign] ForeignBridge Implementation: ', foreignBridgeImplementation.options.address ) console.log('\nhooking up ForeignBridge storage to ForeignBridge implementation') - const upgradeToForeignBridgeData = await foreignBridgeStorage.methods - .upgradeTo('1', foreignBridgeImplementation.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txUpgradeToForeignBridge = await sendRawTxForeign({ - data: upgradeToForeignBridgeData, - nonce: foreignNonce, - to: foreignBridgeStorage.options.address, - privateKey: deploymentPrivateKey, + await upgradeProxy({ + proxy: foreignBridgeStorage, + implementationAddress: foreignBridgeImplementation.options.address, + version: '1', + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual( - Web3Utils.hexToNumber(txUpgradeToForeignBridge.status), - 1, - 'Transaction Failed' - ) - foreignNonce++ + nonce++ console.log('\ninitializing Foreign Bridge with following parameters:\n') - console.log(`Foreign Validators: ${storageValidatorsForeign.options.address}, - `) foreignBridgeImplementation.options.address = foreignBridgeStorage.options.address - const initializeFBridgeData = await foreignBridgeImplementation.methods - .initialize( - storageValidatorsForeign.options.address, - ERC20_TOKEN_ADDRESS, - FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS, - FOREIGN_GAS_PRICE, - FOREIGN_MAX_AMOUNT_PER_TX, - HOME_DAILY_LIMIT, - HOME_MAX_AMOUNT_PER_TX, - FOREIGN_BRIDGE_OWNER - ) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txInitializeBridge = await sendRawTxForeign({ - data: initializeFBridgeData, - nonce: foreignNonce, - to: foreignBridgeStorage.options.address, - privateKey: deploymentPrivateKey, - url: FOREIGN_RPC_URL + await initializeBridge({ + validatorsBridge: storageValidatorsForeign, + bridge: foreignBridgeImplementation, + nonce }) - assert.strictEqual(Web3Utils.hexToNumber(txInitializeBridge.status), 1, 'Transaction Failed') - foreignNonce++ - - const bridgeOwnershipData = await foreignBridgeStorage.methods - .transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txBridgeOwnershipData = await sendRawTxForeign({ - data: bridgeOwnershipData, - nonce: foreignNonce, - to: foreignBridgeStorage.options.address, - privateKey: deploymentPrivateKey, + nonce++ + + console.log('transferring proxy ownership to multisig for foreign bridge Proxy contract') + await transferProxyOwnership({ + proxy: foreignBridgeStorage, + newOwner: FOREIGN_UPGRADEABLE_ADMIN, + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txBridgeOwnershipData.status), 1, 'Transaction Failed') - foreignNonce++ console.log('\nForeign Deployment Bridge completed\n') return { diff --git a/deploy/src/erc_to_erc/home.js b/deploy/src/erc_to_erc/home.js index d8f238d21..d19bf6a38 100644 --- a/deploy/src/erc_to_erc/home.js +++ b/deploy/src/erc_to_erc/home.js @@ -1,16 +1,36 @@ const assert = require('assert') const Web3Utils = require('web3-utils') const env = require('../loadEnv') +const { ZERO_ADDRESS } = require('../constants') -const { deployContract, privateKeyToAddress, sendRawTxHome } = require('../deploymentUtils') +const { + deployContract, + privateKeyToAddress, + sendRawTxHome, + upgradeProxy, + initializeValidators, + transferProxyOwnership, + setBridgeContract, + transferOwnership, + assertStateWithRetry +} = require('../deploymentUtils') const { web3Home, deploymentPrivateKey, HOME_RPC_URL } = require('../web3') -const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json') -const BridgeValidators = require('../../../build/contracts/BridgeValidators.json') -const HomeBridge = require('../../../build/contracts/HomeBridgeErcToErc.json') -const ERC677BridgeToken = require('../../../build/contracts/ERC677BridgeToken.json') +const { + homeContracts: { + EternalStorageProxy, + BridgeValidators, + RewardableValidators, + FeeManagerErcToErcPOSDAO, + HomeBridgeErcToErc: HomeBridge, + POSDAOHomeBridgeErcToErc, + ERC677BridgeToken, + ERC677BridgeTokenRewardable + } +} = require('../loadContracts') const VALIDATORS = env.VALIDATORS.split(' ') +const VALIDATORS_REWARD_ACCOUNTS = env.VALIDATORS_REWARD_ACCOUNTS.split(' ') const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY, @@ -27,191 +47,282 @@ const { BRIDGEABLE_TOKEN_SYMBOL, BRIDGEABLE_TOKEN_DECIMALS, FOREIGN_DAILY_LIMIT, - FOREIGN_MAX_AMOUNT_PER_TX + FOREIGN_MAX_AMOUNT_PER_TX, + DEPLOY_REWARDABLE_TOKEN, + BLOCK_REWARD_ADDRESS, + DPOS_STAKING_ADDRESS, + HOME_REWARDABLE, + HOME_TRANSACTIONS_FEE, + FOREIGN_TRANSACTIONS_FEE } = env const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY) +const isRewardableBridge = HOME_REWARDABLE === 'BOTH_DIRECTIONS' + +async function initializeBridge({ validatorsBridge, bridge, erc677token, initialNonce }) { + let nonce = initialNonce + let initializeHomeBridgeData + + if (isRewardableBridge && BLOCK_REWARD_ADDRESS !== ZERO_ADDRESS) { + console.log('\ndeploying implementation for fee manager') + const feeManager = await deployContract(FeeManagerErcToErcPOSDAO, [], { + from: DEPLOYMENT_ACCOUNT_ADDRESS, + nonce + }) + console.log('[Home] feeManager Implementation: ', feeManager.options.address) + nonce++ + + const homeFeeInWei = Web3Utils.toWei(HOME_TRANSACTIONS_FEE.toString(), 'ether') + const foreignFeeInWei = Web3Utils.toWei(FOREIGN_TRANSACTIONS_FEE.toString(), 'ether') + console.log('\ninitializing Home Bridge with fee contract:\n') + console.log(`Home Validators: ${validatorsBridge.options.address}, + HOME_DAILY_LIMIT : ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth, + HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MAX_AMOUNT_PER_TX + )} in eth, + HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MIN_AMOUNT_PER_TX + )} in eth, + HOME_GAS_PRICE: ${HOME_GAS_PRICE}, HOME_REQUIRED_BLOCK_CONFIRMATIONS : ${HOME_REQUIRED_BLOCK_CONFIRMATIONS}, + Block Reward: ${BLOCK_REWARD_ADDRESS}, + Fee Manager: ${feeManager.options.address}, + Home Fee: ${homeFeeInWei} which is ${HOME_TRANSACTIONS_FEE * 100}% + Foreign Fee: ${foreignFeeInWei} which is ${FOREIGN_TRANSACTIONS_FEE * 100}%`) + initializeHomeBridgeData = await bridge.methods + .rewardableInitialize( + validatorsBridge.options.address, + HOME_DAILY_LIMIT, + HOME_MAX_AMOUNT_PER_TX, + HOME_MIN_AMOUNT_PER_TX, + HOME_GAS_PRICE, + HOME_REQUIRED_BLOCK_CONFIRMATIONS, + erc677token.options.address, + FOREIGN_DAILY_LIMIT, + FOREIGN_MAX_AMOUNT_PER_TX, + HOME_BRIDGE_OWNER, + feeManager.options.address, + homeFeeInWei, + foreignFeeInWei, + BLOCK_REWARD_ADDRESS + ) + .encodeABI() + } else { + console.log(`Home Validators: ${validatorsBridge.options.address}, + HOME_DAILY_LIMIT : ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth, + HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MAX_AMOUNT_PER_TX + )} in eth, + HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MIN_AMOUNT_PER_TX + )} in eth, + HOME_GAS_PRICE: ${HOME_GAS_PRICE}, HOME_REQUIRED_BLOCK_CONFIRMATIONS : ${HOME_REQUIRED_BLOCK_CONFIRMATIONS} + `) + initializeHomeBridgeData = await bridge.methods + .initialize( + validatorsBridge.options.address, + HOME_DAILY_LIMIT, + HOME_MAX_AMOUNT_PER_TX, + HOME_MIN_AMOUNT_PER_TX, + HOME_GAS_PRICE, + HOME_REQUIRED_BLOCK_CONFIRMATIONS, + erc677token.options.address, + FOREIGN_DAILY_LIMIT, + FOREIGN_MAX_AMOUNT_PER_TX, + HOME_BRIDGE_OWNER + ) + .encodeABI() + } + + const txInitializeHomeBridge = await sendRawTxHome({ + data: initializeHomeBridgeData, + nonce, + to: bridge.options.address, + privateKey: deploymentPrivateKey, + url: HOME_RPC_URL + }) + if (txInitializeHomeBridge.status) { + assert.strictEqual( + Web3Utils.hexToNumber(txInitializeHomeBridge.status), + 1, + 'Transaction Failed' + ) + } else { + await assertStateWithRetry(bridge.methods.isInitialized().call, true) + } + nonce++ + + return nonce +} + async function deployHome() { - let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) + let nonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) console.log('deploying storage for home validators') const storageValidatorsHome = await deployContract(EternalStorageProxy, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, - nonce: homeNonce + nonce }) console.log('[Home] BridgeValidators Storage: ', storageValidatorsHome.options.address) - homeNonce++ + nonce++ console.log('\ndeploying implementation for home validators') - const bridgeValidatorsHome = await deployContract(BridgeValidators, [], { + const bridgeValidatorsContract = + isRewardableBridge && BLOCK_REWARD_ADDRESS === ZERO_ADDRESS + ? RewardableValidators + : BridgeValidators + const bridgeValidatorsHome = await deployContract(bridgeValidatorsContract, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, - nonce: homeNonce + nonce }) console.log('[Home] BridgeValidators Implementation: ', bridgeValidatorsHome.options.address) - homeNonce++ + nonce++ console.log('\nhooking up eternal storage to BridgeValidators') - const upgradeToBridgeVHomeData = await storageValidatorsHome.methods - .upgradeTo('1', bridgeValidatorsHome.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txUpgradeToBridgeVHome = await sendRawTxHome({ - data: upgradeToBridgeVHomeData, - nonce: homeNonce, - to: storageValidatorsHome.options.address, - privateKey: deploymentPrivateKey, + await upgradeProxy({ + proxy: storageValidatorsHome, + implementationAddress: bridgeValidatorsHome.options.address, + version: '1', + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txUpgradeToBridgeVHome.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ console.log('\ninitializing Home Bridge Validators with following parameters:\n') - console.log( - `REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}` - ) - bridgeValidatorsHome.options.address = storageValidatorsHome.options.address - const initializeData = await bridgeValidatorsHome.methods - .initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, HOME_VALIDATORS_OWNER) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txInitialize = await sendRawTxHome({ - data: initializeData, - nonce: homeNonce, - to: bridgeValidatorsHome.options.address, - privateKey: deploymentPrivateKey, + await initializeValidators({ + contract: bridgeValidatorsHome, + isRewardableBridge: isRewardableBridge && BLOCK_REWARD_ADDRESS === ZERO_ADDRESS, + requiredNumber: REQUIRED_NUMBER_OF_VALIDATORS, + validators: VALIDATORS, + rewardAccounts: VALIDATORS_REWARD_ACCOUNTS, + owner: HOME_VALIDATORS_OWNER, + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txInitialize.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ console.log('transferring proxy ownership to multisig for Validators Proxy contract') - const proxyDataTransfer = await storageValidatorsHome.methods - .transferProxyOwnership(HOME_UPGRADEABLE_ADMIN) - .encodeABI() - const txProxyDataTransfer = await sendRawTxHome({ - data: proxyDataTransfer, - nonce: homeNonce, - to: storageValidatorsHome.options.address, - privateKey: deploymentPrivateKey, + await transferProxyOwnership({ + proxy: storageValidatorsHome, + newOwner: HOME_UPGRADEABLE_ADMIN, + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txProxyDataTransfer.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ console.log('\ndeploying homeBridge storage\n') const homeBridgeStorage = await deployContract(EternalStorageProxy, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, - nonce: homeNonce + nonce }) - homeNonce++ + nonce++ console.log('[Home] HomeBridge Storage: ', homeBridgeStorage.options.address) console.log('\ndeploying homeBridge implementation\n') - const homeBridgeImplementation = await deployContract(HomeBridge, [], { + const bridgeContract = + isRewardableBridge && BLOCK_REWARD_ADDRESS !== ZERO_ADDRESS + ? POSDAOHomeBridgeErcToErc + : HomeBridge + const homeBridgeImplementation = await deployContract(bridgeContract, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, - nonce: homeNonce + nonce }) - homeNonce++ + nonce++ console.log('[Home] HomeBridge Implementation: ', homeBridgeImplementation.options.address) console.log('\nhooking up HomeBridge storage to HomeBridge implementation') - const upgradeToHomeBridgeData = await homeBridgeStorage.methods - .upgradeTo('1', homeBridgeImplementation.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txUpgradeToHomeBridge = await sendRawTxHome({ - data: upgradeToHomeBridgeData, - nonce: homeNonce, - to: homeBridgeStorage.options.address, - privateKey: deploymentPrivateKey, + await upgradeProxy({ + proxy: homeBridgeStorage, + implementationAddress: homeBridgeImplementation.options.address, + version: '1', + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txUpgradeToHomeBridge.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ console.log('\n[Home] deploying Bridgeble token') + const erc677Contract = + (isRewardableBridge && BLOCK_REWARD_ADDRESS !== ZERO_ADDRESS) || DEPLOY_REWARDABLE_TOKEN + ? ERC677BridgeTokenRewardable + : ERC677BridgeToken const erc677token = await deployContract( - ERC677BridgeToken, + erc677Contract, [BRIDGEABLE_TOKEN_NAME, BRIDGEABLE_TOKEN_SYMBOL, BRIDGEABLE_TOKEN_DECIMALS], - { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'home', nonce: homeNonce } + { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'home', nonce } ) - homeNonce++ + nonce++ console.log('[Home] Bridgeble Token: ', erc677token.options.address) console.log('\nset bridge contract on ERC677BridgeToken') - const setBridgeContractData = await erc677token.methods - .setBridgeContract(homeBridgeStorage.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const setBridgeContract = await sendRawTxHome({ - data: setBridgeContractData, - nonce: homeNonce, - to: erc677token.options.address, - privateKey: deploymentPrivateKey, + await setBridgeContract({ + contract: erc677token, + bridgeAddress: homeBridgeStorage.options.address, + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(setBridgeContract.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ + + if ((isRewardableBridge && BLOCK_REWARD_ADDRESS !== ZERO_ADDRESS) || DEPLOY_REWARDABLE_TOKEN) { + console.log('\nset BlockReward contract on ERC677BridgeTokenRewardable') + const setBlockRewardContractData = await erc677token.methods + .setBlockRewardContract(BLOCK_REWARD_ADDRESS) + .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) + const setBlockRewardContract = await sendRawTxHome({ + data: setBlockRewardContractData, + nonce, + to: erc677token.options.address, + privateKey: deploymentPrivateKey, + url: HOME_RPC_URL + }) + assert.strictEqual( + Web3Utils.hexToNumber(setBlockRewardContract.status), + 1, + 'Transaction Failed' + ) + nonce++ + } + + if (DEPLOY_REWARDABLE_TOKEN) { + console.log('\nset Staking contract on ERC677BridgeTokenRewardable') + const setStakingContractData = await erc677token.methods + .setStakingContract(DPOS_STAKING_ADDRESS) + .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) + const setStakingContract = await sendRawTxHome({ + data: setStakingContractData, + nonce, + to: erc677token.options.address, + privateKey: deploymentPrivateKey, + url: HOME_RPC_URL + }) + assert.strictEqual(Web3Utils.hexToNumber(setStakingContract.status), 1, 'Transaction Failed') + nonce++ + } console.log('transferring ownership of Bridgeble token to homeBridge contract') - const txOwnershipData = await erc677token.methods - .transferOwnership(homeBridgeStorage.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txOwnership = await sendRawTxHome({ - data: txOwnershipData, - nonce: homeNonce, - to: erc677token.options.address, - privateKey: deploymentPrivateKey, + await transferOwnership({ + contract: erc677token, + newOwner: homeBridgeStorage.options.address, + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txOwnership.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ console.log('\ninitializing Home Bridge with following parameters:\n') - console.log(`Home Validators: ${storageValidatorsHome.options.address}, - HOME_DAILY_LIMIT : ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth, - HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( - HOME_MAX_AMOUNT_PER_TX - )} in eth, - HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( - HOME_MIN_AMOUNT_PER_TX - )} in eth, - HOME_GAS_PRICE: ${HOME_GAS_PRICE}, HOME_REQUIRED_BLOCK_CONFIRMATIONS : ${HOME_REQUIRED_BLOCK_CONFIRMATIONS} - `) homeBridgeImplementation.options.address = homeBridgeStorage.options.address - const initializeHomeBridgeData = await homeBridgeImplementation.methods - .initialize( - storageValidatorsHome.options.address, - HOME_DAILY_LIMIT, - HOME_MAX_AMOUNT_PER_TX, - HOME_MIN_AMOUNT_PER_TX, - HOME_GAS_PRICE, - HOME_REQUIRED_BLOCK_CONFIRMATIONS, - erc677token.options.address, - FOREIGN_DAILY_LIMIT, - FOREIGN_MAX_AMOUNT_PER_TX, - HOME_BRIDGE_OWNER - ) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txInitializeHomeBridge = await sendRawTxHome({ - data: initializeHomeBridgeData, - nonce: homeNonce, - to: homeBridgeStorage.options.address, - privateKey: deploymentPrivateKey, - url: HOME_RPC_URL + + nonce = await initializeBridge({ + validatorsBridge: storageValidatorsHome, + bridge: homeBridgeImplementation, + erc677token, + initialNonce: nonce }) - assert.strictEqual(Web3Utils.hexToNumber(txInitializeHomeBridge.status), 1, 'Transaction Failed') - homeNonce++ console.log('transferring proxy ownership to multisig for Home bridge Proxy contract') - const homeBridgeProxyData = await homeBridgeStorage.methods - .transferProxyOwnership(HOME_UPGRADEABLE_ADMIN) - .encodeABI() - const txhomeBridgeProxyData = await sendRawTxHome({ - data: homeBridgeProxyData, - nonce: homeNonce, - to: homeBridgeStorage.options.address, - privateKey: deploymentPrivateKey, + await transferProxyOwnership({ + proxy: homeBridgeStorage, + newOwner: HOME_UPGRADEABLE_ADMIN, + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txhomeBridgeProxyData.status), 1, 'Transaction Failed') - homeNonce++ console.log('\nHome Deployment Bridge completed\n') return { diff --git a/deploy/src/erc_to_erc/preDeploy.js b/deploy/src/erc_to_erc/preDeploy.js new file mode 100644 index 000000000..3df6f18b2 --- /dev/null +++ b/deploy/src/erc_to_erc/preDeploy.js @@ -0,0 +1,22 @@ +const { web3Foreign } = require('../web3') +const { ERC20_TOKEN_ADDRESS, ERC20_EXTENDED_BY_ERC677 } = require('../loadEnv') +const { + foreignContracts: { + ERC677BridgeToken: { abi } + } +} = require('../loadContracts') + +async function preDeploy() { + if (ERC20_EXTENDED_BY_ERC677) { + const tokenContract = new web3Foreign.eth.Contract(abi, ERC20_TOKEN_ADDRESS) + try { + await tokenContract.methods.bridgeContract().call() + } catch (e) { + throw new Error( + `ERC20_EXTENDED_BY_ERC677 is set to TRUE but bridgeContract method was not found on ERC677 token.` + ) + } + } +} + +module.exports = preDeploy diff --git a/deploy/src/erc_to_native/foreign.js b/deploy/src/erc_to_native/foreign.js index 7584fa7c5..87a2f1a6e 100644 --- a/deploy/src/erc_to_native/foreign.js +++ b/deploy/src/erc_to_native/foreign.js @@ -2,12 +2,23 @@ const assert = require('assert') const Web3Utils = require('web3-utils') const env = require('../loadEnv') -const { deployContract, privateKeyToAddress, sendRawTxForeign } = require('../deploymentUtils') +const { + deployContract, + privateKeyToAddress, + sendRawTxForeign, + upgradeProxy, + initializeValidators, + transferProxyOwnership, + assertStateWithRetry +} = require('../deploymentUtils') const { web3Foreign, deploymentPrivateKey, FOREIGN_RPC_URL } = require('../web3') - -const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json') -const BridgeValidators = require('../../../build/contracts/BridgeValidators.json') -const ForeignBridge = require('../../../build/contracts/ForeignBridgeErcToNative.json') +const { + foreignContracts: { + EternalStorageProxy, + BridgeValidators, + ForeignBridgeErcToNative: ForeignBridge + } +} = require('../loadContracts') const VALIDATORS = env.VALIDATORS.split(' ') @@ -27,11 +38,50 @@ const { const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY) +async function initializeBridge({ validatorsBridge, bridge, nonce }) { + console.log(`Foreign Validators: ${validatorsBridge.options.address}, + ERC20_TOKEN_ADDRESS: ${ERC20_TOKEN_ADDRESS}, + FOREIGN_MAX_AMOUNT_PER_TX: ${FOREIGN_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + FOREIGN_MAX_AMOUNT_PER_TX + )} in eth, + FOREIGN_GAS_PRICE: ${FOREIGN_GAS_PRICE}, FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS : ${FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS}, + HOME_DAILY_LIMIT: ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth, + HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MAX_AMOUNT_PER_TX + )} in eth, + FOREIGN_BRIDGE_OWNER: ${FOREIGN_BRIDGE_OWNER} + `) + const initializeFBridgeData = await bridge.methods + .initialize( + validatorsBridge.options.address, + ERC20_TOKEN_ADDRESS, + FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS, + FOREIGN_GAS_PRICE, + FOREIGN_MAX_AMOUNT_PER_TX, + HOME_DAILY_LIMIT, + HOME_MAX_AMOUNT_PER_TX, + FOREIGN_BRIDGE_OWNER + ) + .encodeABI() + const txInitializeBridge = await sendRawTxForeign({ + data: initializeFBridgeData, + nonce, + to: bridge.options.address, + privateKey: deploymentPrivateKey, + url: FOREIGN_RPC_URL + }) + if (txInitializeBridge.status) { + assert.strictEqual(Web3Utils.hexToNumber(txInitializeBridge.status), 1, 'Transaction Failed') + } else { + await assertStateWithRetry(bridge.methods.isInitialized().call, true) + } +} + async function deployForeign() { if (!Web3Utils.isAddress(ERC20_TOKEN_ADDRESS)) { throw new Error('ERC20_TOKEN_ADDRESS env var is not defined') } - let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) + let nonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) console.log('========================================') console.log('deploying ForeignBridge') console.log('========================================\n') @@ -40,154 +90,102 @@ async function deployForeign() { const storageValidatorsForeign = await deployContract(EternalStorageProxy, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', - nonce: foreignNonce + nonce }) - foreignNonce++ + nonce++ console.log('[Foreign] BridgeValidators Storage: ', storageValidatorsForeign.options.address) console.log('\ndeploying implementation for foreign validators') const bridgeValidatorsForeign = await deployContract(BridgeValidators, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', - nonce: foreignNonce + nonce }) - foreignNonce++ + nonce++ console.log( '[Foreign] BridgeValidators Implementation: ', bridgeValidatorsForeign.options.address ) console.log('\nhooking up eternal storage to BridgeValidators') - const upgradeToBridgeVForeignData = await storageValidatorsForeign.methods - .upgradeTo('1', bridgeValidatorsForeign.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txUpgradeToBridgeVForeign = await sendRawTxForeign({ - data: upgradeToBridgeVForeignData, - nonce: foreignNonce, - to: storageValidatorsForeign.options.address, - privateKey: deploymentPrivateKey, + await upgradeProxy({ + proxy: storageValidatorsForeign, + implementationAddress: bridgeValidatorsForeign.options.address, + version: '1', + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual( - Web3Utils.hexToNumber(txUpgradeToBridgeVForeign.status), - 1, - 'Transaction Failed' - ) - foreignNonce++ + nonce++ console.log('\ninitializing Foreign Bridge Validators with following parameters:\n') - console.log( - `REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}` - ) - bridgeValidatorsForeign.options.address = storageValidatorsForeign.options.address - const initializeForeignData = await bridgeValidatorsForeign.methods - .initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, FOREIGN_VALIDATORS_OWNER) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txInitializeForeign = await sendRawTxForeign({ - data: initializeForeignData, - nonce: foreignNonce, - to: bridgeValidatorsForeign.options.address, - privateKey: deploymentPrivateKey, + await initializeValidators({ + contract: bridgeValidatorsForeign, + isRewardableBridge: false, + requiredNumber: REQUIRED_NUMBER_OF_VALIDATORS, + validators: VALIDATORS, + rewardAccounts: [], + owner: FOREIGN_VALIDATORS_OWNER, + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txInitializeForeign.status), 1, 'Transaction Failed') - foreignNonce++ + nonce++ console.log('\nTransferring ownership of ValidatorsProxy\n') - const validatorsForeignOwnershipData = await storageValidatorsForeign.methods - .transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txValidatorsForeignOwnershipData = await sendRawTxForeign({ - data: validatorsForeignOwnershipData, - nonce: foreignNonce, - to: storageValidatorsForeign.options.address, - privateKey: deploymentPrivateKey, + await transferProxyOwnership({ + proxy: storageValidatorsForeign, + newOwner: FOREIGN_UPGRADEABLE_ADMIN, + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual( - Web3Utils.hexToNumber(txValidatorsForeignOwnershipData.status), - 1, - 'Transaction Failed' - ) - foreignNonce++ + nonce++ console.log('\ndeploying foreignBridge storage\n') const foreignBridgeStorage = await deployContract(EternalStorageProxy, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', - nonce: foreignNonce + nonce }) - foreignNonce++ + nonce++ console.log('[Foreign] ForeignBridge Storage: ', foreignBridgeStorage.options.address) console.log('\ndeploying foreignBridge implementation\n') const foreignBridgeImplementation = await deployContract(ForeignBridge, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', - nonce: foreignNonce + nonce }) - foreignNonce++ + nonce++ console.log( '[Foreign] ForeignBridge Implementation: ', foreignBridgeImplementation.options.address ) console.log('\nhooking up ForeignBridge storage to ForeignBridge implementation') - const upgradeToForeignBridgeData = await foreignBridgeStorage.methods - .upgradeTo('1', foreignBridgeImplementation.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txUpgradeToForeignBridge = await sendRawTxForeign({ - data: upgradeToForeignBridgeData, - nonce: foreignNonce, - to: foreignBridgeStorage.options.address, - privateKey: deploymentPrivateKey, + await upgradeProxy({ + proxy: foreignBridgeStorage, + implementationAddress: foreignBridgeImplementation.options.address, + version: '1', + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual( - Web3Utils.hexToNumber(txUpgradeToForeignBridge.status), - 1, - 'Transaction Failed' - ) - foreignNonce++ + nonce++ console.log('\ninitializing Foreign Bridge with following parameters:\n') - console.log(`Foreign Validators: ${storageValidatorsForeign.options.address}, - `) foreignBridgeImplementation.options.address = foreignBridgeStorage.options.address - const initializeFBridgeData = await foreignBridgeImplementation.methods - .initialize( - storageValidatorsForeign.options.address, - ERC20_TOKEN_ADDRESS, - FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS, - FOREIGN_GAS_PRICE, - FOREIGN_MAX_AMOUNT_PER_TX, - HOME_DAILY_LIMIT, - HOME_MAX_AMOUNT_PER_TX, - FOREIGN_BRIDGE_OWNER - ) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txInitializeBridge = await sendRawTxForeign({ - data: initializeFBridgeData, - nonce: foreignNonce, - to: foreignBridgeStorage.options.address, - privateKey: deploymentPrivateKey, - url: FOREIGN_RPC_URL + await initializeBridge({ + validatorsBridge: storageValidatorsForeign, + bridge: foreignBridgeImplementation, + nonce }) - assert.strictEqual(Web3Utils.hexToNumber(txInitializeBridge.status), 1, 'Transaction Failed') - foreignNonce++ - - const bridgeOwnershipData = await foreignBridgeStorage.methods - .transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txBridgeOwnershipData = await sendRawTxForeign({ - data: bridgeOwnershipData, - nonce: foreignNonce, - to: foreignBridgeStorage.options.address, - privateKey: deploymentPrivateKey, + nonce++ + + console.log('transferring proxy ownership to multisig for foreign bridge Proxy contract') + await transferProxyOwnership({ + proxy: foreignBridgeStorage, + newOwner: FOREIGN_UPGRADEABLE_ADMIN, + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txBridgeOwnershipData.status), 1, 'Transaction Failed') - foreignNonce++ console.log('\nForeign Deployment Bridge completed\n') return { diff --git a/deploy/src/erc_to_native/home.js b/deploy/src/erc_to_native/home.js index 2040b953a..963fe8f6e 100644 --- a/deploy/src/erc_to_native/home.js +++ b/deploy/src/erc_to_native/home.js @@ -2,14 +2,29 @@ const assert = require('assert') const Web3Utils = require('web3-utils') const env = require('../loadEnv') -const { deployContract, privateKeyToAddress, sendRawTxHome } = require('../deploymentUtils') +const { + deployContract, + privateKeyToAddress, + sendRawTxHome, + upgradeProxy, + initializeValidators, + transferProxyOwnership, + assertStateWithRetry +} = require('../deploymentUtils') const { web3Home, deploymentPrivateKey, HOME_RPC_URL } = require('../web3') - -const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json') -const BridgeValidators = require('../../../build/contracts/BridgeValidators.json') -const HomeBridge = require('../../../build/contracts/HomeBridgeErcToNative.json') +const { + homeContracts: { + EternalStorageProxy, + BridgeValidators, + RewardableValidators, + FeeManagerErcToNative, + HomeBridgeErcToNative: HomeBridge, + FeeManagerErcToNativePOSDAO + } +} = require('../loadContracts') const VALIDATORS = env.VALIDATORS.split(' ') +const VALIDATORS_REWARD_ACCOUNTS = env.VALIDATORS_REWARD_ACCOUNTS.split(' ') const { BLOCK_REWARD_ADDRESS, @@ -24,153 +39,223 @@ const { HOME_MIN_AMOUNT_PER_TX, HOME_REQUIRED_BLOCK_CONFIRMATIONS, FOREIGN_DAILY_LIMIT, - FOREIGN_MAX_AMOUNT_PER_TX + FOREIGN_MAX_AMOUNT_PER_TX, + HOME_REWARDABLE, + HOME_TRANSACTIONS_FEE, + FOREIGN_TRANSACTIONS_FEE, + HOME_FEE_MANAGER_TYPE } = env const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY) +const isRewardableBridge = HOME_REWARDABLE === 'BOTH_DIRECTIONS' +const isFeeManagerPOSDAO = HOME_FEE_MANAGER_TYPE === 'POSDAO_REWARD' + +async function initializeBridge({ validatorsBridge, bridge, initialNonce }) { + let nonce = initialNonce + let initializeHomeBridgeData + + if (isRewardableBridge) { + console.log('\ndeploying implementation for fee manager') + const feeManagerContract = isFeeManagerPOSDAO + ? FeeManagerErcToNativePOSDAO + : FeeManagerErcToNative + const feeManager = await deployContract(feeManagerContract, [], { + from: DEPLOYMENT_ACCOUNT_ADDRESS, + nonce + }) + console.log('[Home] feeManager Implementation: ', feeManager.options.address) + nonce++ + + const homeFeeInWei = Web3Utils.toWei(HOME_TRANSACTIONS_FEE.toString(), 'ether') + const foreignFeeInWei = Web3Utils.toWei(FOREIGN_TRANSACTIONS_FEE.toString(), 'ether') + console.log('\ninitializing Home Bridge with fee contract:\n') + console.log(`Home Validators: ${validatorsBridge.options.address}, + HOME_DAILY_LIMIT : ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth, + HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MAX_AMOUNT_PER_TX + )} in eth, + HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MIN_AMOUNT_PER_TX + )} in eth, + HOME_GAS_PRICE: ${HOME_GAS_PRICE}, HOME_REQUIRED_BLOCK_CONFIRMATIONS : ${HOME_REQUIRED_BLOCK_CONFIRMATIONS}, + BLOCK_REWARD_ADDRESS: ${BLOCK_REWARD_ADDRESS}, + FOREIGN_DAILY_LIMIT: ${FOREIGN_DAILY_LIMIT} which is ${Web3Utils.fromWei( + FOREIGN_DAILY_LIMIT + )} in eth, + FOREIGN_MAX_AMOUNT_PER_TX: ${FOREIGN_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + FOREIGN_MAX_AMOUNT_PER_TX + )} in eth, + HOME_BRIDGE_OWNER: ${HOME_BRIDGE_OWNER}, + Fee Manager: ${feeManager.options.address}, + Home Fee: ${homeFeeInWei} which is ${HOME_TRANSACTIONS_FEE * 100}% + Foreign Fee: ${foreignFeeInWei} which is ${FOREIGN_TRANSACTIONS_FEE * 100}%`) + initializeHomeBridgeData = await bridge.methods + .rewardableInitialize( + validatorsBridge.options.address, + HOME_DAILY_LIMIT, + HOME_MAX_AMOUNT_PER_TX, + HOME_MIN_AMOUNT_PER_TX, + HOME_GAS_PRICE, + HOME_REQUIRED_BLOCK_CONFIRMATIONS, + BLOCK_REWARD_ADDRESS, + FOREIGN_DAILY_LIMIT, + FOREIGN_MAX_AMOUNT_PER_TX, + HOME_BRIDGE_OWNER, + feeManager.options.address, + homeFeeInWei, + foreignFeeInWei + ) + .encodeABI() + } else { + console.log('\ninitializing Home Bridge with following parameters:\n') + console.log(`Home Validators: ${validatorsBridge.options.address}, + HOME_DAILY_LIMIT : ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth, + HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MAX_AMOUNT_PER_TX + )} in eth, + HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MIN_AMOUNT_PER_TX + )} in eth, + HOME_GAS_PRICE: ${HOME_GAS_PRICE}, HOME_REQUIRED_BLOCK_CONFIRMATIONS : ${HOME_REQUIRED_BLOCK_CONFIRMATIONS}, + BLOCK_REWARD_ADDRESS: ${BLOCK_REWARD_ADDRESS}, + FOREIGN_DAILY_LIMIT: ${FOREIGN_DAILY_LIMIT} which is ${Web3Utils.fromWei( + FOREIGN_DAILY_LIMIT + )} in eth, + FOREIGN_MAX_AMOUNT_PER_TX: ${FOREIGN_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + FOREIGN_MAX_AMOUNT_PER_TX + )} in eth, + HOME_BRIDGE_OWNER: ${HOME_BRIDGE_OWNER} + `) + initializeHomeBridgeData = await bridge.methods + .initialize( + validatorsBridge.options.address, + HOME_DAILY_LIMIT, + HOME_MAX_AMOUNT_PER_TX, + HOME_MIN_AMOUNT_PER_TX, + HOME_GAS_PRICE, + HOME_REQUIRED_BLOCK_CONFIRMATIONS, + BLOCK_REWARD_ADDRESS, + FOREIGN_DAILY_LIMIT, + FOREIGN_MAX_AMOUNT_PER_TX, + HOME_BRIDGE_OWNER + ) + .encodeABI() + } + + const txInitializeHomeBridge = await sendRawTxHome({ + data: initializeHomeBridgeData, + nonce, + to: bridge.options.address, + privateKey: deploymentPrivateKey, + url: HOME_RPC_URL + }) + if (txInitializeHomeBridge.status) { + assert.strictEqual( + Web3Utils.hexToNumber(txInitializeHomeBridge.status), + 1, + 'Transaction Failed' + ) + } else { + await assertStateWithRetry(bridge.methods.isInitialized().call, true) + } + nonce++ + + return nonce +} + async function deployHome() { - let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) + let nonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) console.log('deploying storage for home validators') const storageValidatorsHome = await deployContract(EternalStorageProxy, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, - nonce: homeNonce + nonce }) console.log('[Home] BridgeValidators Storage: ', storageValidatorsHome.options.address) - homeNonce++ + nonce++ console.log('\ndeploying implementation for home validators') - const bridgeValidatorsHome = await deployContract(BridgeValidators, [], { + const bridgeValidatorsContract = isRewardableBridge ? RewardableValidators : BridgeValidators + const bridgeValidatorsHome = await deployContract(bridgeValidatorsContract, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, - nonce: homeNonce + nonce }) console.log('[Home] BridgeValidators Implementation: ', bridgeValidatorsHome.options.address) - homeNonce++ + nonce++ console.log('\nhooking up eternal storage to BridgeValidators') - const upgradeToBridgeVHomeData = await storageValidatorsHome.methods - .upgradeTo('1', bridgeValidatorsHome.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txUpgradeToBridgeVHome = await sendRawTxHome({ - data: upgradeToBridgeVHomeData, - nonce: homeNonce, - to: storageValidatorsHome.options.address, - privateKey: deploymentPrivateKey, + await upgradeProxy({ + proxy: storageValidatorsHome, + implementationAddress: bridgeValidatorsHome.options.address, + version: '1', + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txUpgradeToBridgeVHome.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ console.log('\ninitializing Home Bridge Validators with following parameters:\n') - console.log( - `REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}` - ) bridgeValidatorsHome.options.address = storageValidatorsHome.options.address - const initializeData = await bridgeValidatorsHome.methods - .initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, HOME_VALIDATORS_OWNER) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txInitialize = await sendRawTxHome({ - data: initializeData, - nonce: homeNonce, - to: bridgeValidatorsHome.options.address, - privateKey: deploymentPrivateKey, + await initializeValidators({ + contract: bridgeValidatorsHome, + isRewardableBridge, + requiredNumber: REQUIRED_NUMBER_OF_VALIDATORS, + validators: VALIDATORS, + rewardAccounts: VALIDATORS_REWARD_ACCOUNTS, + owner: HOME_VALIDATORS_OWNER, + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txInitialize.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ console.log('transferring proxy ownership to multisig for Validators Proxy contract') - const proxyDataTransfer = await storageValidatorsHome.methods - .transferProxyOwnership(HOME_UPGRADEABLE_ADMIN) - .encodeABI() - const txProxyDataTransfer = await sendRawTxHome({ - data: proxyDataTransfer, - nonce: homeNonce, - to: storageValidatorsHome.options.address, - privateKey: deploymentPrivateKey, + await transferProxyOwnership({ + proxy: storageValidatorsHome, + newOwner: HOME_UPGRADEABLE_ADMIN, + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txProxyDataTransfer.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ console.log('\ndeploying homeBridge storage\n') const homeBridgeStorage = await deployContract(EternalStorageProxy, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, - nonce: homeNonce + nonce }) - homeNonce++ + nonce++ console.log('[Home] HomeBridge Storage: ', homeBridgeStorage.options.address) console.log('\ndeploying homeBridge implementation\n') const homeBridgeImplementation = await deployContract(HomeBridge, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, - nonce: homeNonce + nonce }) - homeNonce++ + nonce++ console.log('[Home] HomeBridge Implementation: ', homeBridgeImplementation.options.address) console.log('\nhooking up HomeBridge storage to HomeBridge implementation') - const upgradeToHomeBridgeData = await homeBridgeStorage.methods - .upgradeTo('1', homeBridgeImplementation.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txUpgradeToHomeBridge = await sendRawTxHome({ - data: upgradeToHomeBridgeData, - nonce: homeNonce, - to: homeBridgeStorage.options.address, - privateKey: deploymentPrivateKey, + await upgradeProxy({ + proxy: homeBridgeStorage, + implementationAddress: homeBridgeImplementation.options.address, + version: '1', + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txUpgradeToHomeBridge.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ - console.log('\ninitializing Home Bridge with following parameters:\n') - console.log(`Home Validators: ${storageValidatorsHome.options.address}, - HOME_DAILY_LIMIT : ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth, - HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( - HOME_MAX_AMOUNT_PER_TX - )} in eth, - HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( - HOME_MIN_AMOUNT_PER_TX - )} in eth, - HOME_GAS_PRICE: ${HOME_GAS_PRICE}, HOME_REQUIRED_BLOCK_CONFIRMATIONS : ${HOME_REQUIRED_BLOCK_CONFIRMATIONS}`) homeBridgeImplementation.options.address = homeBridgeStorage.options.address - const initializeHomeBridgeData = await homeBridgeImplementation.methods - .initialize( - storageValidatorsHome.options.address, - HOME_DAILY_LIMIT, - HOME_MAX_AMOUNT_PER_TX, - HOME_MIN_AMOUNT_PER_TX, - HOME_GAS_PRICE, - HOME_REQUIRED_BLOCK_CONFIRMATIONS, - BLOCK_REWARD_ADDRESS, - FOREIGN_DAILY_LIMIT, - FOREIGN_MAX_AMOUNT_PER_TX, - HOME_BRIDGE_OWNER - ) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txInitializeHomeBridge = await sendRawTxHome({ - data: initializeHomeBridgeData, - nonce: homeNonce, - to: homeBridgeStorage.options.address, - privateKey: deploymentPrivateKey, - url: HOME_RPC_URL + nonce = await initializeBridge({ + validatorsBridge: storageValidatorsHome, + bridge: homeBridgeImplementation, + initialNonce: nonce }) - assert.strictEqual(Web3Utils.hexToNumber(txInitializeHomeBridge.status), 1, 'Transaction Failed') - homeNonce++ console.log('transferring proxy ownership to multisig for Home bridge Proxy contract') - const homeBridgeProxyData = await homeBridgeStorage.methods - .transferProxyOwnership(HOME_UPGRADEABLE_ADMIN) - .encodeABI() - const txhomeBridgeProxyData = await sendRawTxHome({ - data: homeBridgeProxyData, - nonce: homeNonce, - to: homeBridgeStorage.options.address, - privateKey: deploymentPrivateKey, + await transferProxyOwnership({ + proxy: homeBridgeStorage, + newOwner: HOME_UPGRADEABLE_ADMIN, + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txhomeBridgeProxyData.status), 1, 'Transaction Failed') - homeNonce++ console.log('\nHome Deployment Bridge completed\n') return { diff --git a/deploy/src/loadContracts.js b/deploy/src/loadContracts.js new file mode 100644 index 000000000..c44c55095 --- /dev/null +++ b/deploy/src/loadContracts.js @@ -0,0 +1,41 @@ +/* eslint import/no-dynamic-require: 0 */ +const { HOME_EVM_VERSION, FOREIGN_EVM_VERSION } = require('./loadEnv') +const { EVM_TYPES } = require('./constants') + +const homeContracts = getContracts(HOME_EVM_VERSION) +const foreignContracts = getContracts(FOREIGN_EVM_VERSION) + +function getContracts(evmVersion) { + const buildPath = evmVersion === EVM_TYPES.SPURIOUSDRAGON ? 'spuriousDragon' : 'contracts' + const useClassicProxy = evmVersion === EVM_TYPES.SPURIOUSDRAGON + return { + EternalStorageProxy: useClassicProxy + ? require(`../../build/${buildPath}/ClassicEternalStorageProxy.json`) + : require(`../../build/${buildPath}/EternalStorageProxy.json`), + BridgeValidators: require(`../../build/${buildPath}/BridgeValidators.json`), + RewardableValidators: require(`../../build/${buildPath}/RewardableValidators.json`), + FeeManagerErcToErcPOSDAO: require(`../../build/${buildPath}/FeeManagerErcToErcPOSDAO.json`), + HomeBridgeErcToErc: require(`../../build/${buildPath}/HomeBridgeErcToErc.json`), + ForeignBridgeErcToErc: require(`../../build/${buildPath}/ForeignBridgeErcToErc.json`), + ForeignBridgeErc677ToErc677: require(`../../build/${buildPath}/ForeignBridgeErc677ToErc677.json`), + POSDAOHomeBridgeErcToErc: require(`../../build/${buildPath}/POSDAOHomeBridgeErcToErc.json`), + ERC677BridgeToken: require(`../../build/${buildPath}/ERC677BridgeToken.json`), + ERC677BridgeTokenRewardable: require(`../../build/${buildPath}/ERC677BridgeTokenRewardable.json`), + ForeignBridgeErcToNative: require(`../../build/${buildPath}/ForeignBridgeErcToNative.json`), + FeeManagerErcToNative: require(`../../build/${buildPath}/FeeManagerErcToNative.json`), + FeeManagerErcToNativePOSDAO: require(`../../build/${buildPath}/FeeManagerErcToNativePOSDAO.json`), + HomeBridgeErcToNative: require(`../../build/${buildPath}/HomeBridgeErcToNative.json`), + FeeManagerNativeToErc: require(`../../build/${buildPath}/FeeManagerNativeToErc.json`), + ForeignBridgeNativeToErc: require(`../../build/${buildPath}/ForeignBridgeNativeToErc.json`), + FeeManagerNativeToErcBothDirections: require(`../../build/${buildPath}/FeeManagerNativeToErcBothDirections.json`), + HomeBridgeNativeToErc: useClassicProxy + ? require(`../../build/${buildPath}/ClassicHomeBridgeNativeToErc.json`) + : require(`../../build/${buildPath}/HomeBridgeNativeToErc.json`), + BlockReward: require(`../../build/${buildPath}/BlockReward.json`) + } +} + +module.exports = { + homeContracts, + foreignContracts +} diff --git a/deploy/src/loadEnv.js b/deploy/src/loadEnv.js index 21d5f9fe8..3d08d9775 100644 --- a/deploy/src/loadEnv.js +++ b/deploy/src/loadEnv.js @@ -4,10 +4,13 @@ require('dotenv').config({ }) const { isAddress, toBN } = require('web3').utils const envalid = require('envalid') -const { ZERO_ADDRESS } = require('./constants') +const { ZERO_ADDRESS, EVM_TYPES } = require('./constants') // Validations and constants +const evmVersions = [EVM_TYPES.BYZANTIUM, EVM_TYPES.SPURIOUSDRAGON] const validBridgeModes = ['NATIVE_TO_ERC', 'ERC_TO_ERC', 'ERC_TO_NATIVE'] +const validRewardModes = ['false', 'ONE_DIRECTION', 'BOTH_DIRECTIONS'] +const validFeeManagerTypes = ['BRIDGE_VALIDATORS_REWARD', 'POSDAO_REWARD'] const bigNumValidator = envalid.makeValidator(x => toBN(x)) const validateAddress = address => { if (isAddress(address)) { @@ -21,16 +24,64 @@ const addressesValidator = envalid.makeValidator(addresses => { addresses.split(' ').forEach(validateAddress) return addresses }) +const validateRewardableAddresses = (validators, rewards) => { + const validatorsLength = validators ? validators.split(' ').length : 0 + const validatorsRewardLength = rewards ? rewards.split(' ').length : 0 + if (validatorsLength !== validatorsRewardLength) { + throw new Error( + `List of rewards accounts (${validatorsRewardLength} accounts) should be the same length as list of validators (${validatorsLength} accounts)` + ) + } +} + +const { + BRIDGE_MODE, + HOME_REWARDABLE, + FOREIGN_REWARDABLE, + VALIDATORS, + VALIDATORS_REWARD_ACCOUNTS, + DEPLOY_REWARDABLE_TOKEN, + HOME_FEE_MANAGER_TYPE, + ERC20_EXTENDED_BY_ERC677, + HOME_EVM_VERSION, + FOREIGN_EVM_VERSION +} = process.env -const { BRIDGE_MODE } = process.env +if (HOME_EVM_VERSION) { + if (!evmVersions.includes(HOME_EVM_VERSION)) { + throw new Error( + `Invalid Home EVM Version: ${HOME_EVM_VERSION}. Supported values are ${evmVersions}` + ) + } +} + +if (FOREIGN_EVM_VERSION) { + if (!evmVersions.includes(FOREIGN_EVM_VERSION)) { + throw new Error( + `Invalid Foreign EVM Version: ${FOREIGN_EVM_VERSION}. Supported values are ${evmVersions}` + ) + } +} if (!validBridgeModes.includes(BRIDGE_MODE)) { throw new Error(`Invalid bridge mode: ${BRIDGE_MODE}`) } +if (!validRewardModes.includes(HOME_REWARDABLE)) { + throw new Error( + `Invalid HOME_REWARDABLE: ${HOME_REWARDABLE}. Supported values are ${validRewardModes}` + ) +} + +if (!validRewardModes.includes(FOREIGN_REWARDABLE)) { + throw new Error( + `Invalid FOREIGN_REWARDABLE: ${FOREIGN_REWARDABLE}. Supported values are ${validRewardModes}` + ) +} + let validations = { DEPLOYMENT_ACCOUNT_PRIVATE_KEY: envalid.str(), - DEPLOYMENT_GAS_LIMIT: bigNumValidator(), + DEPLOYMENT_GAS_LIMIT_EXTRA: envalid.num(), HOME_DEPLOYMENT_GAS_PRICE: bigNumValidator(), FOREIGN_DEPLOYMENT_GAS_PRICE: bigNumValidator(), GET_RECEIPT_INTERVAL_IN_MILLISECONDS: bigNumValidator(), @@ -49,6 +100,7 @@ let validations = { FOREIGN_UPGRADEABLE_ADMIN: addressValidator(), FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS: envalid.num(), FOREIGN_GAS_PRICE: bigNumValidator(), + FOREIGN_MAX_AMOUNT_PER_TX: bigNumValidator(), REQUIRED_NUMBER_OF_VALIDATORS: envalid.num(), VALIDATORS: addressesValidator() } @@ -60,8 +112,28 @@ if (BRIDGE_MODE === 'NATIVE_TO_ERC') { BRIDGEABLE_TOKEN_SYMBOL: envalid.str(), BRIDGEABLE_TOKEN_DECIMALS: envalid.num(), FOREIGN_DAILY_LIMIT: bigNumValidator(), - FOREIGN_MAX_AMOUNT_PER_TX: bigNumValidator(), - FOREIGN_MIN_AMOUNT_PER_TX: bigNumValidator() + FOREIGN_MIN_AMOUNT_PER_TX: bigNumValidator(), + DEPLOY_REWARDABLE_TOKEN: envalid.bool(), + BLOCK_REWARD_ADDRESS: addressValidator() + } + + if (DEPLOY_REWARDABLE_TOKEN === 'true') { + validations = { + ...validations, + DPOS_STAKING_ADDRESS: addressValidator() + } + } + + if (FOREIGN_REWARDABLE === 'BOTH_DIRECTIONS') { + throw new Error( + `FOREIGN_REWARDABLE: ${FOREIGN_REWARDABLE} is not supported on ${BRIDGE_MODE} bridge mode` + ) + } + + if (HOME_REWARDABLE === 'BOTH_DIRECTIONS' && FOREIGN_REWARDABLE === 'ONE_DIRECTION') { + throw new Error( + `Combination of HOME_REWARDABLE: ${HOME_REWARDABLE} and FOREIGN_REWARDABLE: ${FOREIGN_REWARDABLE} should be avoided on ${BRIDGE_MODE} bridge mode.` + ) } } if (BRIDGE_MODE === 'ERC_TO_ERC') { @@ -70,7 +142,25 @@ if (BRIDGE_MODE === 'ERC_TO_ERC') { ERC20_TOKEN_ADDRESS: addressValidator(), BRIDGEABLE_TOKEN_NAME: envalid.str(), BRIDGEABLE_TOKEN_SYMBOL: envalid.str(), - BRIDGEABLE_TOKEN_DECIMALS: envalid.num() + BRIDGEABLE_TOKEN_DECIMALS: envalid.num(), + DEPLOY_REWARDABLE_TOKEN: envalid.bool(), + DPOS_STAKING_ADDRESS: addressValidator(), + BLOCK_REWARD_ADDRESS: addressValidator(), + ERC20_EXTENDED_BY_ERC677: envalid.bool() + } + + if (ERC20_EXTENDED_BY_ERC677 === 'true') { + validations = { + ...validations, + FOREIGN_DAILY_LIMIT: bigNumValidator(), + FOREIGN_MIN_AMOUNT_PER_TX: bigNumValidator() + } + } + + if (FOREIGN_REWARDABLE !== 'false') { + throw new Error( + `Collecting fees on Foreign Network on ${BRIDGE_MODE} bridge mode is not supported.` + ) } } if (BRIDGE_MODE === 'ERC_TO_NATIVE') { @@ -81,8 +171,48 @@ if (BRIDGE_MODE === 'ERC_TO_NATIVE') { default: ZERO_ADDRESS }) } + + if (HOME_REWARDABLE === 'ONE_DIRECTION') { + throw new Error( + `Only BOTH_DIRECTIONS is supported for collecting fees on Home Network on ${BRIDGE_MODE} bridge mode.` + ) + } + + if (FOREIGN_REWARDABLE !== 'false') { + throw new Error( + `Collecting fees on Foreign Network on ${BRIDGE_MODE} bridge mode is not supported.` + ) + } + + if (HOME_REWARDABLE === 'BOTH_DIRECTIONS') { + if (!validFeeManagerTypes.includes(HOME_FEE_MANAGER_TYPE)) { + throw new Error( + `Invalid fee manager type: HOME_FEE_MANAGER_TYPE = ${HOME_FEE_MANAGER_TYPE}. Supported values are ${validFeeManagerTypes}` + ) + } + } +} + +if (HOME_REWARDABLE !== 'false' || FOREIGN_REWARDABLE !== 'false') { + validateRewardableAddresses(VALIDATORS, VALIDATORS_REWARD_ACCOUNTS) + validations = { + ...validations, + VALIDATORS_REWARD_ACCOUNTS: addressesValidator(), + HOME_TRANSACTIONS_FEE: envalid.num(), + FOREIGN_TRANSACTIONS_FEE: envalid.num() + } } const env = envalid.cleanEnv(process.env, validations) +if ( + env.BRIDGE_MODE === 'ERC_TO_ERC' && + env.HOME_REWARDABLE === 'true' && + env.BLOCK_REWARD_ADDRESS === ZERO_ADDRESS +) { + throw new Error( + 'Collecting fees on Home Network on ERC_TO_ERC mode without Block Reward contract is not supported.' + ) +} + module.exports = env diff --git a/deploy/src/native_to_erc/foreign.js b/deploy/src/native_to_erc/foreign.js index 39202dc81..1d7ee002e 100644 --- a/deploy/src/native_to_erc/foreign.js +++ b/deploy/src/native_to_erc/foreign.js @@ -2,15 +2,32 @@ const assert = require('assert') const Web3Utils = require('web3-utils') const env = require('../loadEnv') -const { deployContract, privateKeyToAddress, sendRawTxForeign } = require('../deploymentUtils') +const { + deployContract, + privateKeyToAddress, + sendRawTxForeign, + upgradeProxy, + initializeValidators, + transferProxyOwnership, + transferOwnership, + setBridgeContract, + assertStateWithRetry +} = require('../deploymentUtils') const { web3Foreign, deploymentPrivateKey, FOREIGN_RPC_URL } = require('../web3') - -const ERC677BridgeToken = require('../../../build/contracts/ERC677BridgeToken.json') -const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json') -const BridgeValidators = require('../../../build/contracts/BridgeValidators.json') -const ForeignBridge = require('../../../build/contracts/ForeignBridgeNativeToErc.json') +const { + foreignContracts: { + EternalStorageProxy, + BridgeValidators, + RewardableValidators, + ForeignBridgeNativeToErc: ForeignBridge, + ERC677BridgeToken, + ERC677BridgeTokenRewardable, + FeeManagerNativeToErc + } +} = require('../loadContracts') const VALIDATORS = env.VALIDATORS.split(' ') +const VALIDATORS_REWARD_ACCOUNTS = env.VALIDATORS_REWARD_ACCOUNTS.split(' ') const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY, @@ -27,217 +44,305 @@ const { BRIDGEABLE_TOKEN_SYMBOL, BRIDGEABLE_TOKEN_DECIMALS, HOME_DAILY_LIMIT, - HOME_MAX_AMOUNT_PER_TX + HOME_MAX_AMOUNT_PER_TX, + DEPLOY_REWARDABLE_TOKEN, + BLOCK_REWARD_ADDRESS, + DPOS_STAKING_ADDRESS, + FOREIGN_REWARDABLE, + HOME_TRANSACTIONS_FEE } = env const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY) +const isRewardableBridge = FOREIGN_REWARDABLE === 'ONE_DIRECTION' + +async function initializeBridge({ validatorsBridge, bridge, erc677bridgeToken, initialNonce }) { + let nonce = initialNonce + let initializeFBridgeData + + if (isRewardableBridge) { + console.log('\ndeploying implementation for fee manager') + const feeManager = await deployContract(FeeManagerNativeToErc, [], { + from: DEPLOYMENT_ACCOUNT_ADDRESS, + network: 'foreign', + nonce + }) + console.log('[Foreign] feeManager Implementation: ', feeManager.options.address) + nonce++ + + const homeFeeInWei = Web3Utils.toWei(HOME_TRANSACTIONS_FEE.toString(), 'ether') + + console.log('\ninitializing Foreign Bridge with fee contract:\n') + console.log(`Foreign Validators: ${validatorsBridge.options.address}, + FOREIGN_DAILY_LIMIT : ${FOREIGN_DAILY_LIMIT} which is ${Web3Utils.fromWei( + FOREIGN_DAILY_LIMIT + )} in eth, + FOREIGN_MAX_AMOUNT_PER_TX: ${FOREIGN_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + FOREIGN_MAX_AMOUNT_PER_TX + )} in eth, + FOREIGN_MIN_AMOUNT_PER_TX: ${FOREIGN_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + FOREIGN_MIN_AMOUNT_PER_TX + )} in eth, + FOREIGN_GAS_PRICE: ${FOREIGN_GAS_PRICE}, FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS : ${FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS}, + HOME_DAILY_LIMIT: ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth, + HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MAX_AMOUNT_PER_TX + )} in eth, + FOREIGN_BRIDGE_OWNER: ${FOREIGN_BRIDGE_OWNER}, + Fee Manager: ${feeManager.options.address}, + Home Fee: ${homeFeeInWei} which is ${HOME_TRANSACTIONS_FEE * 100}%`) + + initializeFBridgeData = await bridge.methods + .rewardableInitialize( + validatorsBridge.options.address, + erc677bridgeToken.options.address, + FOREIGN_DAILY_LIMIT, + FOREIGN_MAX_AMOUNT_PER_TX, + FOREIGN_MIN_AMOUNT_PER_TX, + FOREIGN_GAS_PRICE, + FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS, + HOME_DAILY_LIMIT, + HOME_MAX_AMOUNT_PER_TX, + FOREIGN_BRIDGE_OWNER, + feeManager.options.address, + homeFeeInWei + ) + .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) + } else { + console.log('\ninitializing Foreign Bridge with following parameters:\n') + console.log(`Foreign Validators: ${validatorsBridge.options.address}, + FOREIGN_DAILY_LIMIT : ${FOREIGN_DAILY_LIMIT} which is ${Web3Utils.fromWei( + FOREIGN_DAILY_LIMIT + )} in eth, + FOREIGN_MAX_AMOUNT_PER_TX: ${FOREIGN_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + FOREIGN_MAX_AMOUNT_PER_TX + )} in eth, + FOREIGN_MIN_AMOUNT_PER_TX: ${FOREIGN_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + FOREIGN_MIN_AMOUNT_PER_TX + )} in eth, + FOREIGN_GAS_PRICE: ${FOREIGN_GAS_PRICE}, FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS : ${FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS}, + HOME_DAILY_LIMIT: ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth, + HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MAX_AMOUNT_PER_TX + )} in eth, + FOREIGN_BRIDGE_OWNER: ${FOREIGN_BRIDGE_OWNER} + `) + + initializeFBridgeData = await bridge.methods + .initialize( + validatorsBridge.options.address, + erc677bridgeToken.options.address, + FOREIGN_DAILY_LIMIT, + FOREIGN_MAX_AMOUNT_PER_TX, + FOREIGN_MIN_AMOUNT_PER_TX, + FOREIGN_GAS_PRICE, + FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS, + HOME_DAILY_LIMIT, + HOME_MAX_AMOUNT_PER_TX, + FOREIGN_BRIDGE_OWNER + ) + .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) + } + + const txInitializeBridge = await sendRawTxForeign({ + data: initializeFBridgeData, + nonce, + to: bridge.options.address, + privateKey: deploymentPrivateKey, + url: FOREIGN_RPC_URL + }) + if (txInitializeBridge.status) { + assert.strictEqual(Web3Utils.hexToNumber(txInitializeBridge.status), 1, 'Transaction Failed') + } else { + await assertStateWithRetry(bridge.methods.isInitialized().call, true) + } + nonce++ + + return nonce +} + async function deployForeign() { - let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) + let nonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) console.log('========================================') console.log('deploying ForeignBridge') console.log('========================================\n') console.log('\n[Foreign] deploying BRIDGEABLE_TOKEN_SYMBOL token') const erc677bridgeToken = await deployContract( - ERC677BridgeToken, + DEPLOY_REWARDABLE_TOKEN ? ERC677BridgeTokenRewardable : ERC677BridgeToken, [BRIDGEABLE_TOKEN_NAME, BRIDGEABLE_TOKEN_SYMBOL, BRIDGEABLE_TOKEN_DECIMALS], - { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', nonce: foreignNonce } + { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', nonce } ) - foreignNonce++ + nonce++ console.log('[Foreign] BRIDGEABLE_TOKEN_SYMBOL: ', erc677bridgeToken.options.address) - console.log('deploying storage for foreign validators') + console.log('\ndeploying storage for foreign validators') const storageValidatorsForeign = await deployContract(EternalStorageProxy, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', - nonce: foreignNonce + nonce }) - foreignNonce++ + nonce++ console.log('[Foreign] BridgeValidators Storage: ', storageValidatorsForeign.options.address) console.log('\ndeploying implementation for foreign validators') - const bridgeValidatorsForeign = await deployContract(BridgeValidators, [], { + const bridgeValidatorsContract = isRewardableBridge ? RewardableValidators : BridgeValidators + const bridgeValidatorsForeign = await deployContract(bridgeValidatorsContract, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', - nonce: foreignNonce + nonce }) - foreignNonce++ + nonce++ console.log( '[Foreign] BridgeValidators Implementation: ', bridgeValidatorsForeign.options.address ) console.log('\nhooking up eternal storage to BridgeValidators') - const upgradeToBridgeVForeignData = await storageValidatorsForeign.methods - .upgradeTo('1', bridgeValidatorsForeign.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txUpgradeToBridgeVForeign = await sendRawTxForeign({ - data: upgradeToBridgeVForeignData, - nonce: foreignNonce, - to: storageValidatorsForeign.options.address, - privateKey: deploymentPrivateKey, + await upgradeProxy({ + proxy: storageValidatorsForeign, + implementationAddress: bridgeValidatorsForeign.options.address, + version: '1', + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual( - Web3Utils.hexToNumber(txUpgradeToBridgeVForeign.status), - 1, - 'Transaction Failed' - ) - foreignNonce++ + nonce++ console.log('\ninitializing Foreign Bridge Validators with following parameters:\n') - console.log( - `REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}` - ) bridgeValidatorsForeign.options.address = storageValidatorsForeign.options.address - const initializeForeignData = await bridgeValidatorsForeign.methods - .initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, FOREIGN_VALIDATORS_OWNER) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txInitializeForeign = await sendRawTxForeign({ - data: initializeForeignData, - nonce: foreignNonce, - to: bridgeValidatorsForeign.options.address, - privateKey: deploymentPrivateKey, + await initializeValidators({ + contract: bridgeValidatorsForeign, + isRewardableBridge, + requiredNumber: REQUIRED_NUMBER_OF_VALIDATORS, + validators: VALIDATORS, + rewardAccounts: VALIDATORS_REWARD_ACCOUNTS, + owner: FOREIGN_VALIDATORS_OWNER, + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txInitializeForeign.status), 1, 'Transaction Failed') - foreignNonce++ + nonce++ console.log('\nTransferring ownership of ValidatorsProxy\n') - const validatorsForeignOwnershipData = await storageValidatorsForeign.methods - .transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txValidatorsForeignOwnershipData = await sendRawTxForeign({ - data: validatorsForeignOwnershipData, - nonce: foreignNonce, - to: storageValidatorsForeign.options.address, - privateKey: deploymentPrivateKey, + await transferProxyOwnership({ + proxy: storageValidatorsForeign, + newOwner: FOREIGN_UPGRADEABLE_ADMIN, + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual( - Web3Utils.hexToNumber(txValidatorsForeignOwnershipData.status), - 1, - 'Transaction Failed' - ) - foreignNonce++ + nonce++ console.log('\ndeploying foreignBridge storage\n') const foreignBridgeStorage = await deployContract(EternalStorageProxy, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', - nonce: foreignNonce + nonce }) - foreignNonce++ + nonce++ console.log('[Foreign] ForeignBridge Storage: ', foreignBridgeStorage.options.address) console.log('\ndeploying foreignBridge implementation\n') const foreignBridgeImplementation = await deployContract(ForeignBridge, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', - nonce: foreignNonce + nonce }) - foreignNonce++ + nonce++ console.log( '[Foreign] ForeignBridge Implementation: ', foreignBridgeImplementation.options.address ) console.log('\nhooking up ForeignBridge storage to ForeignBridge implementation') - const upgradeToForeignBridgeData = await foreignBridgeStorage.methods - .upgradeTo('1', foreignBridgeImplementation.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txUpgradeToForeignBridge = await sendRawTxForeign({ - data: upgradeToForeignBridgeData, - nonce: foreignNonce, - to: foreignBridgeStorage.options.address, - privateKey: deploymentPrivateKey, + await upgradeProxy({ + proxy: foreignBridgeStorage, + implementationAddress: foreignBridgeImplementation.options.address, + version: '1', + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual( - Web3Utils.hexToNumber(txUpgradeToForeignBridge.status), - 1, - 'Transaction Failed' - ) - foreignNonce++ + nonce++ - console.log('\ninitializing Foreign Bridge with following parameters:\n') - console.log(`Foreign Validators: ${storageValidatorsForeign.options.address}, - FOREIGN_DAILY_LIMIT : ${FOREIGN_DAILY_LIMIT} which is ${Web3Utils.fromWei( - FOREIGN_DAILY_LIMIT - )} in eth, - FOREIGN_MAX_AMOUNT_PER_TX: ${FOREIGN_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( - FOREIGN_MAX_AMOUNT_PER_TX - )} in eth, - FOREIGN_MIN_AMOUNT_PER_TX: ${FOREIGN_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( - FOREIGN_MIN_AMOUNT_PER_TX - )} in eth - `) foreignBridgeImplementation.options.address = foreignBridgeStorage.options.address - const initializeFBridgeData = await foreignBridgeImplementation.methods - .initialize( - storageValidatorsForeign.options.address, - erc677bridgeToken.options.address, - FOREIGN_DAILY_LIMIT, - FOREIGN_MAX_AMOUNT_PER_TX, - FOREIGN_MIN_AMOUNT_PER_TX, - FOREIGN_GAS_PRICE, - FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS, - HOME_DAILY_LIMIT, - HOME_MAX_AMOUNT_PER_TX, - FOREIGN_BRIDGE_OWNER - ) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txInitializeBridge = await sendRawTxForeign({ - data: initializeFBridgeData, - nonce: foreignNonce, - to: foreignBridgeStorage.options.address, - privateKey: deploymentPrivateKey, - url: FOREIGN_RPC_URL + nonce = await initializeBridge({ + validatorsBridge: storageValidatorsForeign, + bridge: foreignBridgeImplementation, + erc677bridgeToken, + initialNonce: nonce }) - assert.strictEqual(Web3Utils.hexToNumber(txInitializeBridge.status), 1, 'Transaction Failed') - foreignNonce++ console.log('\nset bridge contract on ERC677BridgeToken') - const setBridgeContractData = await erc677bridgeToken.methods - .setBridgeContract(foreignBridgeStorage.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const setBridgeContract = await sendRawTxForeign({ - data: setBridgeContractData, - nonce: foreignNonce, - to: erc677bridgeToken.options.address, - privateKey: deploymentPrivateKey, + await setBridgeContract({ + contract: erc677bridgeToken, + bridgeAddress: foreignBridgeStorage.options.address, + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(setBridgeContract.status), 1, 'Transaction Failed') - foreignNonce++ + nonce++ + + if (DEPLOY_REWARDABLE_TOKEN) { + console.log('\nset BlockReward contract on ERC677BridgeTokenRewardable') + const setBlockRewardContractData = await erc677bridgeToken.methods + .setBlockRewardContract(BLOCK_REWARD_ADDRESS) + .encodeABI() + const setBlockRewardContract = await sendRawTxForeign({ + data: setBlockRewardContractData, + nonce, + to: erc677bridgeToken.options.address, + privateKey: deploymentPrivateKey, + url: FOREIGN_RPC_URL + }) + if (setBlockRewardContract.status) { + assert.strictEqual( + Web3Utils.hexToNumber(setBlockRewardContract.status), + 1, + 'Transaction Failed' + ) + } else { + await assertStateWithRetry( + erc677bridgeToken.methods.blockRewardContract().call, + BLOCK_REWARD_ADDRESS + ) + } + nonce++ + + console.log('\nset Staking contract on ERC677BridgeTokenRewardable') + const setStakingContractData = await erc677bridgeToken.methods + .setStakingContract(DPOS_STAKING_ADDRESS) + .encodeABI() + const setStakingContract = await sendRawTxForeign({ + data: setStakingContractData, + nonce, + to: erc677bridgeToken.options.address, + privateKey: deploymentPrivateKey, + url: FOREIGN_RPC_URL + }) + if (setStakingContract.status) { + assert.strictEqual(Web3Utils.hexToNumber(setStakingContract.status), 1, 'Transaction Failed') + } else { + await assertStateWithRetry( + erc677bridgeToken.methods.validatorSetContract().call, + DPOS_STAKING_ADDRESS + ) + } + nonce++ + } console.log('transferring ownership of ERC677BridgeToken token to foreignBridge contract') - const txOwnershipData = await erc677bridgeToken.methods - .transferOwnership(foreignBridgeStorage.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txOwnership = await sendRawTxForeign({ - data: txOwnershipData, - nonce: foreignNonce, - to: erc677bridgeToken.options.address, - privateKey: deploymentPrivateKey, + await transferOwnership({ + contract: erc677bridgeToken, + newOwner: foreignBridgeStorage.options.address, + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txOwnership.status), 1, 'Transaction Failed') - foreignNonce++ - - const bridgeOwnershipData = await foreignBridgeStorage.methods - .transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txBridgeOwnershipData = await sendRawTxForeign({ - data: bridgeOwnershipData, - nonce: foreignNonce, - to: foreignBridgeStorage.options.address, - privateKey: deploymentPrivateKey, + nonce++ + + console.log('transferring proxy ownership to multisig for foreign bridge Proxy contract') + await transferProxyOwnership({ + proxy: foreignBridgeStorage, + newOwner: FOREIGN_UPGRADEABLE_ADMIN, + nonce, url: FOREIGN_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txBridgeOwnershipData.status), 1, 'Transaction Failed') - foreignNonce++ console.log('\nForeign Deployment Bridge completed\n') return { diff --git a/deploy/src/native_to_erc/home.js b/deploy/src/native_to_erc/home.js index a8002587d..65eb4c907 100644 --- a/deploy/src/native_to_erc/home.js +++ b/deploy/src/native_to_erc/home.js @@ -2,14 +2,29 @@ const assert = require('assert') const Web3Utils = require('web3-utils') const env = require('../loadEnv') -const { deployContract, privateKeyToAddress, sendRawTxHome } = require('../deploymentUtils') +const { + deployContract, + privateKeyToAddress, + sendRawTxHome, + upgradeProxy, + initializeValidators, + transferProxyOwnership, + assertStateWithRetry +} = require('../deploymentUtils') const { web3Home, deploymentPrivateKey, HOME_RPC_URL } = require('../web3') - -const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json') -const BridgeValidators = require('../../../build/contracts/BridgeValidators.json') -const HomeBridge = require('../../../build/contracts/HomeBridgeNativeToErc.json') +const { + homeContracts: { + EternalStorageProxy, + BridgeValidators, + RewardableValidators, + FeeManagerNativeToErc, + HomeBridgeNativeToErc: HomeBridge, + FeeManagerNativeToErcBothDirections + } +} = require('../loadContracts') const VALIDATORS = env.VALIDATORS.split(' ') +const VALIDATORS_REWARD_ACCOUNTS = env.VALIDATORS_REWARD_ACCOUNTS.split(' ') const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY, @@ -23,153 +38,222 @@ const { HOME_MIN_AMOUNT_PER_TX, HOME_REQUIRED_BLOCK_CONFIRMATIONS, FOREIGN_DAILY_LIMIT, - FOREIGN_MAX_AMOUNT_PER_TX + FOREIGN_MAX_AMOUNT_PER_TX, + HOME_REWARDABLE, + HOME_TRANSACTIONS_FEE, + FOREIGN_TRANSACTIONS_FEE } = env const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY) +const isBothDirectionsFeeManager = HOME_REWARDABLE === 'BOTH_DIRECTIONS' +const isRewardableBridge = HOME_REWARDABLE === 'ONE_DIRECTION' || isBothDirectionsFeeManager + +async function initializeBridge({ validatorsBridge, bridge, initialNonce }) { + let nonce = initialNonce + let initializeHomeBridgeData + + if (isRewardableBridge) { + console.log('\ndeploying implementation for fee manager') + const feeManagerContract = isBothDirectionsFeeManager + ? FeeManagerNativeToErcBothDirections + : FeeManagerNativeToErc + const feeManager = await deployContract(feeManagerContract, [], { + from: DEPLOYMENT_ACCOUNT_ADDRESS, + nonce + }) + console.log('[Home] feeManager Implementation: ', feeManager.options.address) + nonce++ + + const homeFee = isBothDirectionsFeeManager ? HOME_TRANSACTIONS_FEE.toString() : '0' + const homeFeeInWei = Web3Utils.toWei(homeFee, 'ether') + const foreignFeeInWei = Web3Utils.toWei(FOREIGN_TRANSACTIONS_FEE.toString(), 'ether') + + console.log('\ninitializing Home Bridge with fee contract:\n') + console.log(`Home Validators: ${validatorsBridge.options.address}, + HOME_DAILY_LIMIT : ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth, + HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MAX_AMOUNT_PER_TX + )} in eth, + HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MIN_AMOUNT_PER_TX + )} in eth, + HOME_GAS_PRICE: ${HOME_GAS_PRICE}, HOME_REQUIRED_BLOCK_CONFIRMATIONS : ${HOME_REQUIRED_BLOCK_CONFIRMATIONS}, + FOREIGN_DAILY_LIMIT: ${FOREIGN_DAILY_LIMIT} which is ${Web3Utils.fromWei( + FOREIGN_DAILY_LIMIT + )} in eth, + FOREIGN_MAX_AMOUNT_PER_TX: ${FOREIGN_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + FOREIGN_MAX_AMOUNT_PER_TX + )} in eth, + HOME_BRIDGE_OWNER: ${HOME_BRIDGE_OWNER}, + Fee Manager: ${feeManager.options.address}, + Home Fee: ${homeFeeInWei} which is ${homeFee * 100}% + Foreign Fee: ${foreignFeeInWei} which is ${FOREIGN_TRANSACTIONS_FEE * 100}%`) + + initializeHomeBridgeData = await bridge.methods + .rewardableInitialize( + validatorsBridge.options.address, + HOME_DAILY_LIMIT, + HOME_MAX_AMOUNT_PER_TX, + HOME_MIN_AMOUNT_PER_TX, + HOME_GAS_PRICE, + HOME_REQUIRED_BLOCK_CONFIRMATIONS, + FOREIGN_DAILY_LIMIT, + FOREIGN_MAX_AMOUNT_PER_TX, + HOME_BRIDGE_OWNER, + feeManager.options.address, + homeFeeInWei, + foreignFeeInWei + ) + .encodeABI() + } else { + console.log('\ninitializing Home Bridge with following parameters:\n') + console.log(`Home Validators: ${validatorsBridge.options.address}, + HOME_DAILY_LIMIT : ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth, + HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MAX_AMOUNT_PER_TX + )} in eth, + HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + HOME_MIN_AMOUNT_PER_TX + )} in eth, + HOME_GAS_PRICE: ${HOME_GAS_PRICE}, HOME_REQUIRED_BLOCK_CONFIRMATIONS : ${HOME_REQUIRED_BLOCK_CONFIRMATIONS}, + FOREIGN_DAILY_LIMIT: ${FOREIGN_DAILY_LIMIT} which is ${Web3Utils.fromWei( + FOREIGN_DAILY_LIMIT + )} in eth, + FOREIGN_MAX_AMOUNT_PER_TX: ${FOREIGN_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( + FOREIGN_MAX_AMOUNT_PER_TX + )} in eth, + HOME_BRIDGE_OWNER: ${HOME_BRIDGE_OWNER} + `) + initializeHomeBridgeData = await bridge.methods + .initialize( + validatorsBridge.options.address, + HOME_DAILY_LIMIT, + HOME_MAX_AMOUNT_PER_TX, + HOME_MIN_AMOUNT_PER_TX, + HOME_GAS_PRICE, + HOME_REQUIRED_BLOCK_CONFIRMATIONS, + FOREIGN_DAILY_LIMIT, + FOREIGN_MAX_AMOUNT_PER_TX, + HOME_BRIDGE_OWNER + ) + .encodeABI() + } + + const txInitializeHomeBridge = await sendRawTxHome({ + data: initializeHomeBridgeData, + nonce, + to: bridge.options.address, + privateKey: deploymentPrivateKey, + url: HOME_RPC_URL + }) + if (txInitializeHomeBridge.status) { + assert.strictEqual( + Web3Utils.hexToNumber(txInitializeHomeBridge.status), + 1, + 'Transaction Failed' + ) + } else { + await assertStateWithRetry(bridge.methods.isInitialized().call, true) + } + nonce++ + + return nonce +} + async function deployHome() { - let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) + let nonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) + console.log('deploying storage for home validators') const storageValidatorsHome = await deployContract(EternalStorageProxy, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, - nonce: homeNonce + nonce }) console.log('[Home] BridgeValidators Storage: ', storageValidatorsHome.options.address) - homeNonce++ + nonce++ console.log('\ndeploying implementation for home validators') - const bridgeValidatorsHome = await deployContract(BridgeValidators, [], { + const bridgeValidatorsContract = isRewardableBridge ? RewardableValidators : BridgeValidators + const bridgeValidatorsHome = await deployContract(bridgeValidatorsContract, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, - nonce: homeNonce + nonce }) console.log('[Home] BridgeValidators Implementation: ', bridgeValidatorsHome.options.address) - homeNonce++ + nonce++ console.log('\nhooking up eternal storage to BridgeValidators') - const upgradeToBridgeVHomeData = await storageValidatorsHome.methods - .upgradeTo('1', bridgeValidatorsHome.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txUpgradeToBridgeVHome = await sendRawTxHome({ - data: upgradeToBridgeVHomeData, - nonce: homeNonce, - to: storageValidatorsHome.options.address, - privateKey: deploymentPrivateKey, + await upgradeProxy({ + proxy: storageValidatorsHome, + implementationAddress: bridgeValidatorsHome.options.address, + version: '1', + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txUpgradeToBridgeVHome.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ console.log('\ninitializing Home Bridge Validators with following parameters:\n') - console.log( - `REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}` - ) bridgeValidatorsHome.options.address = storageValidatorsHome.options.address - const initializeData = await bridgeValidatorsHome.methods - .initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, HOME_VALIDATORS_OWNER) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txInitialize = await sendRawTxHome({ - data: initializeData, - nonce: homeNonce, - to: bridgeValidatorsHome.options.address, - privateKey: deploymentPrivateKey, + await initializeValidators({ + contract: bridgeValidatorsHome, + isRewardableBridge, + requiredNumber: REQUIRED_NUMBER_OF_VALIDATORS, + validators: VALIDATORS, + rewardAccounts: VALIDATORS_REWARD_ACCOUNTS, + owner: HOME_VALIDATORS_OWNER, + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txInitialize.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ console.log('transferring proxy ownership to multisig for Validators Proxy contract') - const proxyDataTransfer = await storageValidatorsHome.methods - .transferProxyOwnership(HOME_UPGRADEABLE_ADMIN) - .encodeABI() - const txProxyDataTransfer = await sendRawTxHome({ - data: proxyDataTransfer, - nonce: homeNonce, - to: storageValidatorsHome.options.address, - privateKey: deploymentPrivateKey, + await transferProxyOwnership({ + proxy: storageValidatorsHome, + newOwner: HOME_UPGRADEABLE_ADMIN, + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txProxyDataTransfer.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ console.log('\ndeploying homeBridge storage\n') const homeBridgeStorage = await deployContract(EternalStorageProxy, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, - nonce: homeNonce + nonce }) - homeNonce++ + nonce++ console.log('[Home] HomeBridge Storage: ', homeBridgeStorage.options.address) console.log('\ndeploying homeBridge implementation\n') const homeBridgeImplementation = await deployContract(HomeBridge, [], { from: DEPLOYMENT_ACCOUNT_ADDRESS, - nonce: homeNonce + nonce }) - homeNonce++ + nonce++ console.log('[Home] HomeBridge Implementation: ', homeBridgeImplementation.options.address) console.log('\nhooking up HomeBridge storage to HomeBridge implementation') - const upgradeToHomeBridgeData = await homeBridgeStorage.methods - .upgradeTo('1', homeBridgeImplementation.options.address) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txUpgradeToHomeBridge = await sendRawTxHome({ - data: upgradeToHomeBridgeData, - nonce: homeNonce, - to: homeBridgeStorage.options.address, - privateKey: deploymentPrivateKey, + await upgradeProxy({ + proxy: homeBridgeStorage, + implementationAddress: homeBridgeImplementation.options.address, + version: '1', + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txUpgradeToHomeBridge.status), 1, 'Transaction Failed') - homeNonce++ + nonce++ - console.log('\ninitializing Home Bridge with following parameters:\n') - console.log(`Home Validators: ${storageValidatorsHome.options.address}, - HOME_DAILY_LIMIT : ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth, - HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( - HOME_MAX_AMOUNT_PER_TX - )} in eth, - HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei( - HOME_MIN_AMOUNT_PER_TX - )} in eth, - HOME_GAS_PRICE: ${HOME_GAS_PRICE}, HOME_REQUIRED_BLOCK_CONFIRMATIONS : ${HOME_REQUIRED_BLOCK_CONFIRMATIONS} - `) homeBridgeImplementation.options.address = homeBridgeStorage.options.address - const initializeHomeBridgeData = await homeBridgeImplementation.methods - .initialize( - storageValidatorsHome.options.address, - HOME_DAILY_LIMIT, - HOME_MAX_AMOUNT_PER_TX, - HOME_MIN_AMOUNT_PER_TX, - HOME_GAS_PRICE, - HOME_REQUIRED_BLOCK_CONFIRMATIONS, - FOREIGN_DAILY_LIMIT, - FOREIGN_MAX_AMOUNT_PER_TX, - HOME_BRIDGE_OWNER - ) - .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) - const txInitializeHomeBridge = await sendRawTxHome({ - data: initializeHomeBridgeData, - nonce: homeNonce, - to: homeBridgeStorage.options.address, - privateKey: deploymentPrivateKey, - url: HOME_RPC_URL + nonce = await initializeBridge({ + validatorsBridge: storageValidatorsHome, + bridge: homeBridgeImplementation, + initialNonce: nonce }) - assert.strictEqual(Web3Utils.hexToNumber(txInitializeHomeBridge.status), 1, 'Transaction Failed') - homeNonce++ console.log('transferring proxy ownership to multisig for Home bridge Proxy contract') - const homeBridgeProxyData = await homeBridgeStorage.methods - .transferProxyOwnership(HOME_UPGRADEABLE_ADMIN) - .encodeABI() - const txhomeBridgeProxyData = await sendRawTxHome({ - data: homeBridgeProxyData, - nonce: homeNonce, - to: homeBridgeStorage.options.address, - privateKey: deploymentPrivateKey, + await transferProxyOwnership({ + proxy: homeBridgeStorage, + newOwner: HOME_UPGRADEABLE_ADMIN, + nonce, url: HOME_RPC_URL }) - assert.strictEqual(Web3Utils.hexToNumber(txhomeBridgeProxyData.status), 1, 'Transaction Failed') - homeNonce++ console.log('\nHome Deployment Bridge completed\n') return { diff --git a/deploy/src/utils/deployBlockReward.js b/deploy/src/utils/deployBlockReward.js index 4c0d9a3dc..aa38edaeb 100644 --- a/deploy/src/utils/deployBlockReward.js +++ b/deploy/src/utils/deployBlockReward.js @@ -1,7 +1,9 @@ const Web3Utils = require('web3-utils') const { web3Home, deploymentPrivateKey, HOME_RPC_URL } = require('../web3') const { deployContract, privateKeyToAddress, sendRawTxHome } = require('../deploymentUtils') -const BlockReward = require('../../../build/contracts/BlockReward.json') +const { + homeContracts: { BlockReward } +} = require('../loadContracts') const env = require('../loadEnv') const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = env diff --git a/deploy/src/utils/deployERC20Token.js b/deploy/src/utils/deployERC20Token.js index f18922397..ff798943c 100644 --- a/deploy/src/utils/deployERC20Token.js +++ b/deploy/src/utils/deployERC20Token.js @@ -5,7 +5,9 @@ const env = require('../loadEnv') const { deployContract, privateKeyToAddress, sendRawTxForeign } = require('../deploymentUtils') const { web3Foreign, deploymentPrivateKey, FOREIGN_RPC_URL } = require('../web3') -const ERC677BridgeToken = require('../../../build/contracts/ERC677BridgeToken.json') +const { + foreignContracts: { ERC677BridgeToken } +} = require('../loadContracts') const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY, diff --git a/deploy/src/utils/setBlockReward.js b/deploy/src/utils/setBlockReward.js index 4709361c8..7bfe88dcb 100644 --- a/deploy/src/utils/setBlockReward.js +++ b/deploy/src/utils/setBlockReward.js @@ -1,6 +1,8 @@ const { web3Home, deploymentPrivateKey, HOME_RPC_URL } = require('../web3') const { privateKeyToAddress, sendRawTxHome } = require('../deploymentUtils') -const HomeBridge = require('../../../build/contracts/HomeBridgeErcToNative.json') +const { + homeContracts: { HomeBridgeErcToNative: HomeBridge } +} = require('../loadContracts') const env = require('../loadEnv') const { BLOCK_REWARD_ADDRESS, DEPLOYMENT_ACCOUNT_PRIVATE_KEY, HOME_BRIDGE_ADDRESS } = env diff --git a/deploy/src/web3.js b/deploy/src/web3.js index b475a1646..685a9daba 100644 --- a/deploy/src/web3.js +++ b/deploy/src/web3.js @@ -15,7 +15,7 @@ const foreignProvider = new Web3.providers.HttpProvider(FOREIGN_RPC_URL) const web3Foreign = new Web3(foreignProvider) const { HOME_DEPLOYMENT_GAS_PRICE, FOREIGN_DEPLOYMENT_GAS_PRICE } = env -const GAS_LIMIT = env.DEPLOYMENT_GAS_LIMIT +const GAS_LIMIT_EXTRA = env.DEPLOYMENT_GAS_LIMIT_EXTRA const deploymentPrivateKey = Buffer.from(DEPLOYMENT_ACCOUNT_PRIVATE_KEY, 'hex') @@ -25,7 +25,7 @@ module.exports = { deploymentPrivateKey, HOME_RPC_URL, FOREIGN_RPC_URL, - GAS_LIMIT, + GAS_LIMIT_EXTRA, HOME_DEPLOYMENT_GAS_PRICE, FOREIGN_DEPLOYMENT_GAS_PRICE, GET_RECEIPT_INTERVAL_IN_MILLISECONDS diff --git a/docs/ERC-TO-ERC.md b/docs/ERC-TO-ERC.md new file mode 100644 index 000000000..cf624bafa --- /dev/null +++ b/docs/ERC-TO-ERC.md @@ -0,0 +1,58 @@ +## Gas Consumption `ERC-TO-ERC` Bridge Mode + +#### Deployment +##### Home + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +EternalStorageProxy|deployment|378510|378510|378510 +BridgeValidators|deployment|1144207|1144207|1144207 +EternalStorageProxy|upgradeTo|35871|30924|30913 +BridgeValidators|initialize|187738|280847|253949 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +EternalStorageProxy|deployment|378510|378510|378510 +HomeBridgeErcToErc|deployment|3528509|3528509|3528509 +EternalStorageProxy|upgradeTo|35871|30924|30913 +ERC677BridgeToken|deployment|1498202|1499226|1498829 +ERC677BridgeToken|setBridgeContract|29432|44432|39432 +ERC677BridgeToken|transferOwnership|30860|30924|30913 +HomeBridgeErcToErc|initialize|212299|213195|213003 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +Total| |7521315|7621514|7588994 + +##### Foreign + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +EternalStorageProxy|deployment|378510|378510|378510 +BridgeValidators|deployment|1144207|1144207|1144207 +EternalStorageProxy|upgradeTo|35871|30924|30913 +BridgeValidators|initialize|187738|280847|253949 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +EternalStorageProxy|deployment|378510|378510|378510 +ForeignBridgeErcToErc|deployment|2449436|2449436|2449436 +EternalStorageProxy|upgradeTo|35871|30924|30913 +ForeignBridgeErcToErc|initialize|150614|150614|150614 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +Total| |4822063|4905278|4878358 + +#### Usage + +##### Validators + + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +To sign at the Home (each validator)| +HomeBridgeErcToErc|submitSignature|159386|275159|220171 +To relay signatures from the Home to the Foreign (one validator)| +ForeignBridgeErcToErc|executeSignatures|73779|115769|93027 +To sign and relay from the Foreign to the Home (each validator)| +HomeBridgeErcToErc|executeAffirmation|79336|134607|108215 + +##### Users + + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +To request transfer from the Home to the Foreign| +ERC677BridgeToken|transferAndCall|58370|166206|92399 +To request transfer from the Foreign to the Home| +ERC677BridgeToken|transfer|37691|86589|55000 + diff --git a/docs/ERC-TO-NATIVE-WITH-REWARD.md b/docs/ERC-TO-NATIVE-WITH-REWARD.md new file mode 100644 index 000000000..518aee20d --- /dev/null +++ b/docs/ERC-TO-NATIVE-WITH-REWARD.md @@ -0,0 +1,56 @@ +## Gas Consumption `ERC-TO-NATIVE` Bridge Mode with Reward contract + +#### Deployment +##### Home + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +EternalStorageProxy|deployment|378510|378510|378510 +RewardableValidators|deployment|1615790|1615790|1615790 +EternalStorageProxy|upgradeTo|35871|30924|30913 +RewardableValidators|initialize|202711|423292|318008 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +EternalStorageProxy|deployment|378510|378510|378510 +HomeBridgeErcToNative|deployment|5644337|5644337|5644337 +EternalStorageProxy|upgradeTo|35871|30924|30913 +FeeManagerErcToNative|deployment|1068197|1068197|1068197 +HomeBridgeErcToNative|rewardableInitialize|353084|353148|353132 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +Total| |9774187|9984938|9879616 + +##### Foreign + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +EternalStorageProxy|deployment|378510|378510|378510 +BridgeValidators|deployment|1351491|1351491|1351491 +EternalStorageProxy|upgradeTo|35871|30924|30913 +BridgeValidators|initialize|210762|306607|270900 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +EternalStorageProxy|deployment|378510|378510|378510 +ForeignBridgeErcToNative|deployment|2863900|2863900|2863900 +EternalStorageProxy|upgradeTo|35871|30924|30913 +ForeignBridgeErcToNative|initialize|239130|239130|239130 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +Total| |5555351|5641302|5605573 + +#### Usage + +##### Validators + + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +To sign at the Home (each validator)| +HomeBridgeErcToNative|submitSignature|159926|307729|219658 +To relay signatures from the Home to the Foreign (one validator)| +ForeignBridgeErcToNative|executeSignatures|83142|140737|114527 +To sign and relay from the Foreign to the Home (each validator)| +HomeBridgeErcToNative|executeAffirmation|67422|318558|142697 + +##### Users + + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +To request transfer from the Home to the Foreign| +HomeBridgeErcToNative|fallback|83622|83622|83622 +To request transfer from the Foreign to the Home| +ERC677BridgeToken|transfer|37691|86589|55000 + diff --git a/docs/ERC-TO-NATIVE.md b/docs/ERC-TO-NATIVE.md new file mode 100644 index 000000000..7f4e5814c --- /dev/null +++ b/docs/ERC-TO-NATIVE.md @@ -0,0 +1,55 @@ +## Gas Consumption `ERC-TO-NATIVE` Bridge Mode + +#### Deployment +##### Home + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +EternalStorageProxy|deployment|378510|378510|378510 +BridgeValidators|deployment|1351491|1351491|1351491 +EternalStorageProxy|upgradeTo|35871|30924|30913 +BridgeValidators|initialize|210762|306607|270900 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +EternalStorageProxy|deployment|378510|378510|378510 +HomeBridgeErcToNative|deployment|5644337|5644337|5644337 +EternalStorageProxy|upgradeTo|35871|30924|30913 +HomeBridgeErcToNative|initialize|264356|281376|278561 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +Total| |8361014|8463985|8425441 + +##### Foreign + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +EternalStorageProxy|deployment|378510|378510|378510 +BridgeValidators|deployment|1351491|1351491|1351491 +EternalStorageProxy|upgradeTo|35871|30924|30913 +BridgeValidators|initialize|210762|306607|270900 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +EternalStorageProxy|deployment|378510|378510|378510 +ForeignBridgeErcToNative|deployment|2863900|2863900|2863900 +EternalStorageProxy|upgradeTo|35871|30924|30913 +ForeignBridgeErcToNative|initialize|239130|239130|239130 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +Total| |5555351|5641302|5605573 + +#### Usage + +##### Validators + + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +To sign at the Home (each validator)| +HomeBridgeErcToNative|submitSignature|159926|275699|221104 +To relay signatures from the Home to the Foreign (one validator)| +ForeignBridgeErcToNative|executeSignatures|83142|140737|114527 +To sign and relay from the Foreign to the Home (each validator)| +HomeBridgeErcToNative|executeAffirmation|67379|166131|110341 + +##### Users + + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +To request transfer from the Home to the Foreign| +HomeBridgeErcToNative|fallback|81045|81045|81045 +To request transfer from the Foreign to the Home| +ERC677BridgeToken|transfer|37691|86589|55000 + diff --git a/docs/NATIVE-TO-ERC-WITH-REWARD.md b/docs/NATIVE-TO-ERC-WITH-REWARD.md new file mode 100644 index 000000000..db3f2bf83 --- /dev/null +++ b/docs/NATIVE-TO-ERC-WITH-REWARD.md @@ -0,0 +1,120 @@ +## Gas Consumption `NATIVE-TO-ERC` Bridge Mode with Reward contract on Home and Foreign networks + +#### Deployment +##### Home + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +EternalStorageProxy|deployment|378510|378510|378510 +RewardableValidators|deployment|1615790|1615790|1615790 +EternalStorageProxy|upgradeTo|35871|30924|30913 +RewardableValidators|initialize|202711|423292|318008 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +EternalStorageProxy|deployment|378510|378510|378510 +HomeBridgeNativeToErc|deployment|4841729|4841729|4841729 +EternalStorageProxy|upgradeTo|35871|30924|30913 +FeeManagerNativeToErc|deployment|1079956|1079956|1079956 +HomeBridgeNativeToErc|rewardableInitialize|315276|315340|315304 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +Total| |8945530|9156281|9050939 + +##### Foreign + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +ERC677BridgeToken|deployment|1463536|1464560|1464170 +EternalStorageProxy|deployment|378510|378510|378510 +RewardableValidators|deployment|1615790|1615790|1615790 +EternalStorageProxy|upgradeTo|35871|30924|30913 +RewardableValidators|initialize|202711|423292|318008 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +EternalStorageProxy|deployment|378510|378510|378510 +ForeignBridgeNativeToErc|deployment|3931739|3931739|3931739 +EternalStorageProxy|upgradeTo|35871|30924|30913 +FeeManagerNativeToErc|deployment|1079956|1079956|1079956 +ForeignBridgeNativeToErc|rewardableInitialize|329022|329086|329077 +ERC677BridgeToken|setBridgeContract|29432|44432|39432 +ERC677BridgeToken|transferOwnership|30860|30924|30913 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +Total| |9573114|9799953|9689237 + +#### Usage + +##### Validators + + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +To sign at the Home (each validator)| +HomeBridgeNativeToErc|submitSignature|159880|287671|227125 +To relay signatures from the Home to the Foreign (one validator)| +ForeignBridgeNativeToErc|executeSignatures|193143|374488|288553 +To sign and relay from the Foreign to the Home (each validator)| +HomeBridgeNativeToErc|executeAffirmation|67313|206296|104845 + +##### Users + + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +To request transfer from the Home to the Foreign| +HomeBridgeNativeToErc|fallback|51199|51199|51199 +To request transfer from the Foreign to the Home| +ERC677BridgeToken|transferAndCall|58676|166206|92613 + + + +## Gas Consumption `NATIVE-TO-ERC` Bridge Mode with Reward contract on Home network + +#### Deployment +##### Home + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +EternalStorageProxy|deployment|378510|378510|378510 +RewardableValidators|deployment|1615790|1615790|1615790 +EternalStorageProxy|upgradeTo|35871|30924|30913 +RewardableValidators|initialize|202711|423292|318008 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +EternalStorageProxy|deployment|378510|378510|378510 +HomeBridgeNativeToErc|deployment|4841729|4841729|4841729 +EternalStorageProxy|upgradeTo|35871|30924|30913 +FeeManagerNativeToErcBothDirections|deployment|1004365|1004365|1004365 +HomeBridgeNativeToErc|rewardableInitialize|315276|330680|325073 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +Total| |8869939|9096030|8985117 + +##### Foreign + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +ERC677BridgeToken|deployment|1463536|1464560|1464170 +EternalStorageProxy|deployment|378510|378510|378510 +BridgeValidators|deployment|1351491|1351491|1351491 +EternalStorageProxy|upgradeTo|35871|30924|30913 +BridgeValidators|initialize|210762|306607|270900 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +EternalStorageProxy|deployment|378510|378510|378510 +ForeignBridgeNativeToErc|deployment|3931739|3931739|3931739 +EternalStorageProxy|upgradeTo|35871|30924|30913 +ForeignBridgeNativeToErc|initialize|281275|281339|281328 +ERC677BridgeToken|setBridgeContract|29432|44432|39432 +ERC677BridgeToken|transferOwnership|30860|30924|30913 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +Total| |8189163|8291266|8250125 + +#### Usage + +##### Validators + + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +To sign at the Home (each validator)| +HomeBridgeNativeToErc|submitSignature|159880|308541|219741 +To relay signatures from the Home to the Foreign (one validator)| +ForeignBridgeNativeToErc|executeSignatures|99365|172087|138314 +To sign and relay from the Foreign to the Home (each validator)| +HomeBridgeNativeToErc|executeAffirmation|67313|206445|104857 + +##### Users + + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +To request transfer from the Home to the Foreign| +HomeBridgeNativeToErc|fallback|51177,|51177,|51177, +To request transfer from the Foreign to the Home| +ERC677BridgeToken|transferAndCall|58676|166206|92613 diff --git a/docs/NATIVE-TO-ERC.md b/docs/NATIVE-TO-ERC.md new file mode 100644 index 000000000..f073fe80e --- /dev/null +++ b/docs/NATIVE-TO-ERC.md @@ -0,0 +1,57 @@ +## Gas Consumption `NATIVE-TO-ERC` Bridge Mode + +#### Deployment +##### Home + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +EternalStorageProxy|deployment|378510|378510|378510 +BridgeValidators|deployment|1351491|1351491|1351491 +EternalStorageProxy|upgradeTo|35871|30924|30913 +BridgeValidators|initialize|210762|306607|270900 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +EternalStorageProxy|deployment|378510|378510|378510 +HomeBridgeNativeToErc|deployment|4841729|4841729|4841729 +EternalStorageProxy|upgradeTo|35871|30924|30913 +HomeBridgeNativeToErc|initialize|257416|258312|258003 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +Total| |7551466|7638313|7602275 + +##### Foreign + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +ERC677BridgeToken|deployment|1463536|1464560|1464170 +EternalStorageProxy|deployment|378510|378510|378510 +BridgeValidators|deployment|1351491|1351491|1351491 +EternalStorageProxy|upgradeTo|35871|30924|30913 +BridgeValidators|initialize|210762|306607|270900 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +EternalStorageProxy|deployment|378510|378510|378510 +ForeignBridgeNativeToErc|deployment|3931739|3931739|3931739 +EternalStorageProxy|upgradeTo|35871|30924|30913 +ForeignBridgeNativeToErc|initialize|281275|281339|281328 +ERC677BridgeToken|setBridgeContract|29432|44432|39432 +ERC677BridgeToken|transferOwnership|30860|30924|30913 +EternalStorageProxy|transferProxyOwnership|30653|30653|30653 +Total| |8189163|8291266|8250125 + +#### Usage + +##### Validators + + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +To sign at the Home (each validator)| +HomeBridgeNativeToErc|submitSignature|159816|275743|221116 +To relay signatures from the Home to the Foreign (one validator)| +ForeignBridgeNativeToErc|executeSignatures|99365|172087|138314 +To sign and relay from the Foreign to the Home (each validator)| +HomeBridgeNativeToErc|executeAffirmation|67313|133052|102046 + +##### Users + + Contract | Method | Min | Max | Avg +---- | ---- | ---- | ---- | ---- +To request transfer from the Home to the Foreign| +HomeBridgeNativeToErc|fallback|47848|47848|47848 +To request transfer from the Foreign to the Home| +ERC677BridgeToken|transferAndCall|58676|166206|92613 diff --git a/flatten.sh b/flatten.sh index 1f1fe20da..e9ca1a049 100755 --- a/flatten.sh +++ b/flatten.sh @@ -7,16 +7,40 @@ fi mkdir -p flats/native_to_erc20 mkdir -p flats/erc20_to_erc20 mkdir -p flats/erc20_to_native +mkdir -p flats/validators -./node_modules/.bin/truffle-flattener contracts/upgradeable_contracts/native_to_erc20/ForeignBridgeNativeToErc.sol > flats/native_to_erc20/ForeignBridgeNativeToErc_flat.sol -./node_modules/.bin/truffle-flattener contracts/upgradeable_contracts/native_to_erc20/HomeBridgeNativeToErc.sol > flats/native_to_erc20/HomeBridgeNativeToErc_flat.sol +FLATTENER=./node_modules/.bin/truffle-flattener +BRIDGE_CONTRACTS_DIR=contracts/upgradeable_contracts +VALIDATOR_CONTRACTS_DIR=contracts/upgradeable_contracts -./node_modules/.bin/truffle-flattener contracts/upgradeable_contracts/erc20_to_erc20/HomeBridgeErcToErc.sol > flats/erc20_to_erc20/HomeBridgeErcToErc_flat.sol -./node_modules/.bin/truffle-flattener contracts/upgradeable_contracts/erc20_to_erc20/ForeignBridgeErcToErc.sol > flats/erc20_to_erc20/ForeignBridgeErcToErc_flat.sol +echo "Flattening common bridge contracts" +${FLATTENER} contracts/upgradeability/EternalStorageProxy.sol > flats/EternalStorageProxy_flat.sol +${FLATTENER} contracts/upgradeability/ClassicEternalStorageProxy.sol > flats/ClassicEternalStorageProxy_flat.sol +${FLATTENER} contracts/ERC677BridgeToken.sol > flats/ERC677BridgeToken_flat.sol +${FLATTENER} contracts/ERC677BridgeTokenRewardable.sol > flats/ERC677BridgeTokenRewardable_flat.sol + +echo "Flattening bridge validators contracts" +${FLATTENER} ${VALIDATOR_CONTRACTS_DIR}/BridgeValidators.sol > flats/validators/BridgeValidators_flat.sol +${FLATTENER} ${VALIDATOR_CONTRACTS_DIR}/RewardableValidators.sol > flats/validators/RewardableValidators_flat.sol + +echo "Flattening contracts related to native-to-erc bridge" +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/native_to_erc20/ForeignBridgeNativeToErc.sol > flats/native_to_erc20/ForeignBridgeNativeToErc_flat.sol +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/native_to_erc20/HomeBridgeNativeToErc.sol > flats/native_to_erc20/HomeBridgeNativeToErc_flat.sol +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/native_to_erc20/ClassicHomeBridgeNativeToErc.sol > flats/native_to_erc20/ClassicHomeBridgeNativeToErc_flat.sol +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/native_to_erc20/FeeManagerNativeToErc.sol > flats/native_to_erc20/FeeManagerNativeToErc_flat.sol +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/native_to_erc20/FeeManagerNativeToErcBothDirections.sol > flats/native_to_erc20/FeeManagerNativeToErcBothDirections_flat.sol + +echo "Flattening contracts related to erc-to-erc bridge" +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/erc20_to_erc20/HomeBridgeErcToErc.sol > flats/erc20_to_erc20/HomeBridgeErcToErc_flat.sol +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/erc20_to_erc20/POSDAOHomeBridgeErcToErc.sol > flats/erc20_to_erc20/POSDAOHomeBridgeErcToErc_flat.sol +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/erc20_to_erc20/ForeignBridgeErcToErc.sol > flats/erc20_to_erc20/ForeignBridgeErcToErc_flat.sol +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/erc20_to_erc20/ForeignBridgeErc677ToErc677.sol > flats/erc20_to_erc20/ForeignBridgeErc677ToErc677_flat.sol +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/erc20_to_erc20/FeeManagerErcToErcPOSDAO.sol > flats/erc20_to_erc20/FeeManagerErcToErcPOSDAO_flat.sol + +echo "Flattening contracts related to erc-to-native bridge" +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/erc20_to_native/HomeBridgeErcToNative.sol > flats/erc20_to_native/HomeBridgeErcToNative_flat.sol +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/erc20_to_native/ForeignBridgeErcToNative.sol > flats/erc20_to_native/ForeignBridgeErcToNative_flat.sol +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/erc20_to_native/FeeManagerErcToNative.sol > flats/erc20_to_native/FeeManagerErcToNative_flat.sol +${FLATTENER} ${BRIDGE_CONTRACTS_DIR}/erc20_to_native/FeeManagerErcToNativePOSDAO.sol > flats/erc20_to_native/FeeManagerErcToNativePOSDAO_flat.sol -./node_modules/.bin/truffle-flattener contracts/upgradeable_contracts/erc20_to_native/HomeBridgeErcToNative.sol > flats/erc20_to_native/HomeBridgeErcToNative_flat.sol -./node_modules/.bin/truffle-flattener contracts/upgradeable_contracts/erc20_to_native/ForeignBridgeErcToNative.sol > flats/erc20_to_native/ForeignBridgeErcToNative_flat.sol -./node_modules/.bin/truffle-flattener contracts/upgradeability/EternalStorageProxy.sol > flats/EternalStorageProxy_flat.sol -./node_modules/.bin/truffle-flattener contracts/upgradeable_contracts/BridgeValidators.sol > flats/BridgeValidators_flat.sol -./node_modules/.bin/truffle-flattener contracts/ERC677BridgeToken.sol > flats/ERC677BridgeToken_flat.sol diff --git a/migrations/.gitkeep b/migrations/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/migrations/1_initial_migration.js b/migrations/1_initial_migration.js deleted file mode 100644 index 09b416e01..000000000 --- a/migrations/1_initial_migration.js +++ /dev/null @@ -1,6 +0,0 @@ -var Migrations = artifacts.require("./Migrations.sol"); - -module.exports = async function(deployer, network, accounts) { - const PROXY_OWNER = process.env.PROXY_OWNER || accounts[0]; - await deployer.deploy(Migrations, {from: PROXY_OWNER}); -}; diff --git a/migrations/2_bridge_deployment.js b/migrations/2_bridge_deployment.js deleted file mode 100644 index e2d53ea79..000000000 --- a/migrations/2_bridge_deployment.js +++ /dev/null @@ -1,27 +0,0 @@ -const POA20 = artifacts.require("./ERC677BridgeToken.sol"); -const BridgeValidators = artifacts.require("./BridgeValidators.sol"); -const HomeBridge = artifacts.require("./HomeBridgeNativeToErc.sol"); -const ForeignBridge = artifacts.require("./ForeignBridgeNativeToErc.sol"); - -module.exports = async function(deployer, network, accounts) { - if(process.env.DEPLOY_NORMAL === true){ - let validators = ["0xb8988b690910913c97a090c3a6f80fad8b3a4683"] - const homeDailyLimit = '1000000000000000000' // 1 ether - const foreignDailyLimit = '1000000000000000000' // 1 ether - console.log('deploying token') - await deployer.deploy(POA20, "POA ERC20 on Foundation", "POA20", 18) - const erc677token = await POA20.deployed() - console.log('deploying validators') - await deployer.deploy(BridgeValidators, '1', validators); - const validatorContract = await BridgeValidators.deployed(); - console.log('deploying home') - await deployer.deploy(HomeBridge, validatorContract.address, homeDailyLimit); - console.log('deploying ForeignBridge') - await deployer.deploy(ForeignBridge, validatorContract.address, erc677token.address, foreignDailyLimit); - const foreignBridge = await ForeignBridge.deployed(); - - await erc677token.transferOwnership(foreignBridge.address) - console.log('all is done') - } - -}; diff --git a/migrations/3_upgradeable_deployment.js b/migrations/3_upgradeable_deployment.js deleted file mode 100644 index 3d94ba4f5..000000000 --- a/migrations/3_upgradeable_deployment.js +++ /dev/null @@ -1,98 +0,0 @@ -const POA20 = artifacts.require("./ERC677BridgeToken.sol"); -const BridgeValidators = artifacts.require("./BridgeValidators.sol"); -const HomeBridge = artifacts.require("./HomeBridgeNativeToErc.sol"); -const ForeignBridge = artifacts.require("./ForeignBridgeNativeToErc.sol"); -const EternalStorageProxy = artifacts.require('EternalStorageProxy') - -module.exports = async function(deployer, network, accounts) { - if(network !== 'test' && network !== 'ganache'){ - const VALIDATORS = process.env.VALIDATORS ? process.env.VALIDATORS.split(" ") : [accounts[0]]; - const REQUIRED_NUMBER_OF_VALIDATORS = process.env.REQUIRED_VALIDATORS || VALIDATORS.length - const PROXY_OWNER = process.env.PROXY_OWNER || accounts[0]; - const homeDailyLimit = process.env.HOME_LIMIT || '1000000000000000000' // 1 ether - const foreignDailyLimit = process.env.FOREIGN_LIMIT || '1000000000000000000' // 1 ether - const MAX_AMOUNT_PER_TX = process.env.MAX_AMOUNT_PER_TX || '100000000000000000' // 0.1 ether - const MIN_AMOUNT_PER_TX = process.env.MIN_AMOUNT_PER_TX || '10000000000000000' // 0.01 ether - const HOME_REQUIRED_BLOCK_CONFIRMATIONS = process.env.HOME_REQUIRED_BLOCK_CONFIRMATIONS || '1' - const HOME_GAS_PRICE = process.env.HOME_GAS_PRICE || '1000000000'; - const FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS = process.env.FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS || '8'; - const FOREIGN_GAS_PRICE = process.env.FOREIGN_GAS_PRICE || '1000000000'; - - console.log('storage for home validators') - await deployer.deploy(EternalStorageProxy, {from: PROXY_OWNER}); - const storageBridgeValidators = await EternalStorageProxy.deployed() - - console.log('deploying token') - await deployer.deploy(POA20, "POA ERC20 on Foundation", "POA20", 18) - const erc677token = await POA20.deployed() - - console.log('deploying validators') - await deployer.deploy(BridgeValidators); - const validatorContract = await BridgeValidators.deployed(); - - console.log('hooking up eternal storage to BridgeValidators') - //truffle sucks, it uses web3 0.20, hence I need to work around in order to generate data param - var bridgeValidatorsWeb3 = web3.eth.contract(BridgeValidators.abi); - var bridgeValidatorsWeb3Instance = bridgeValidatorsWeb3.at(validatorContract.address); - var initializeDataValidators = bridgeValidatorsWeb3Instance.initialize.getData(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, PROXY_OWNER); - await storageBridgeValidators.upgradeTo('1', validatorContract.address, {from: PROXY_OWNER}); - await web3.eth.sendTransaction({ - from: PROXY_OWNER, - to: storageBridgeValidators.address, - data: initializeDataValidators, - value: 0, - gas: 4700000 - }) - - console.log('deploying home storage on home network') - await deployer.deploy(EternalStorageProxy, {from: PROXY_OWNER}); - const homeBridgeUpgradeable = await EternalStorageProxy.deployed() - await deployer.deploy(HomeBridge); - const homeBridgeImplementation = await HomeBridge.deployed(); - var homeBridgeWeb3 = web3.eth.contract(HomeBridge.abi); - var homeBridgeWeb3Instance = homeBridgeWeb3.at(homeBridgeImplementation.address); - var initializeDataHome = homeBridgeWeb3Instance.initialize.getData( - storageBridgeValidators.address, - homeDailyLimit, - MAX_AMOUNT_PER_TX, - MIN_AMOUNT_PER_TX, - HOME_GAS_PRICE, - HOME_REQUIRED_BLOCK_CONFIRMATIONS); - await homeBridgeUpgradeable.upgradeTo('1', homeBridgeImplementation.address, {from: PROXY_OWNER}); - await web3.eth.sendTransaction({ - from: PROXY_OWNER, - to: homeBridgeUpgradeable.address, - data: initializeDataHome, - value: 0, - gas: 4700000 - }) - - console.log('deploying ForeignBridge') - await deployer.deploy(EternalStorageProxy, {from: PROXY_OWNER}); - const foreignBridgeUpgradeable = await EternalStorageProxy.deployed() - await deployer.deploy(ForeignBridge); - const foreignBridgeImplementation = await ForeignBridge.deployed(); - var foreignBridgeWeb3 = web3.eth.contract(ForeignBridge.abi); - var foreignBridgeWeb3Instance = foreignBridgeWeb3.at(foreignBridgeImplementation.address); - var initializeDataForeign = foreignBridgeWeb3Instance.initialize - .getData(storageBridgeValidators.address, erc677token.address, foreignDailyLimit, MAX_AMOUNT_PER_TX, MIN_AMOUNT_PER_TX, FOREIGN_GAS_PRICE, FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS); - await foreignBridgeUpgradeable.upgradeTo('1', foreignBridgeImplementation.address, {from: PROXY_OWNER}); - - await web3.eth.sendTransaction({ - from: PROXY_OWNER, - to: foreignBridgeUpgradeable.address, - data: initializeDataForeign, - value: 0, - gas: 4700000 - }) - - await erc677token.transferOwnership(foreignBridgeUpgradeable.address) - console.log('all is done', ` - validators: ${VALIDATORS} - Owner: ${PROXY_OWNER} - Foreign Bridge: ${foreignBridgeUpgradeable.address} - Home Bridge: ${homeBridgeUpgradeable.address} - POA20: ${erc677token.address}`) - } - -}; diff --git a/package-lock.json b/package-lock.json index 37f350ac1..c48820c95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,14 +4,71 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@sindresorhus/is": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", - "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==" + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@resolver-engine/core": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@resolver-engine/core/-/core-0.2.1.tgz", + "integrity": "sha512-nsLQHmPJ77QuifqsIvqjaF5B9aHnDzJjp73Q1z6apY3e9nqYrx4Dtowhpsf7Jwftg/XzVDEMQC+OzUBNTS+S1A==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "request": "^2.85.0" + } + }, + "@resolver-engine/fs": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@resolver-engine/fs/-/fs-0.2.1.tgz", + "integrity": "sha512-7kJInM1Qo2LJcKyDhuYzh9ZWd+mal/fynfL9BNjWOiTcOpX+jNfqb/UmGUqros5pceBITlWGqS4lU709yHFUbg==", + "dev": true, + "requires": { + "@resolver-engine/core": "^0.2.1", + "debug": "^3.1.0" + } + }, + "@resolver-engine/imports": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@resolver-engine/imports/-/imports-0.2.2.tgz", + "integrity": "sha512-u5/HUkvo8q34AA+hnxxqqXGfby5swnH0Myw91o3Sm2TETJlNKXibFGSKBavAH+wvWdBi4Z5gS2Odu0PowgVOUg==", + "dev": true, + "requires": { + "@resolver-engine/core": "^0.2.1", + "debug": "^3.1.0", + "hosted-git-info": "^2.6.0" + } + }, + "@resolver-engine/imports-fs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@resolver-engine/imports-fs/-/imports-fs-0.2.2.tgz", + "integrity": "sha512-gFCgMvCwyppjwq0UzIjde/WI+yDs3oatJhozG9xdjJdewwtd7LiF0T5i9lrHAUtqrQbqoFE4E+ZMRVHWpWHpKQ==", + "dev": true, + "requires": { + "@resolver-engine/fs": "^0.2.1", + "@resolver-engine/imports": "^0.2.2", + "debug": "^3.1.0" + } }, "@types/concat-stream": { "version": "1.6.0", - "resolved": "http://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.0.tgz", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-OU2+C7X+5Gs42JZzXoto7yOQ0A0=", "dev": true, "requires": { @@ -20,7 +77,7 @@ }, "@types/form-data": { "version": "0.0.33", - "resolved": "http://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", "integrity": "sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=", "dev": true, "requires": { @@ -28,15 +85,15 @@ } }, "@types/node": { - "version": "9.6.35", - "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.35.tgz", - "integrity": "sha512-h5zvHS8wXHGa+Gcqs9K8vqCgOtqjr0+NqG/DDJmQIX1wpR9HivAfgV8bjcD3mGM4bPfQw5Aneb2Pn8355L83jA==", + "version": "10.14.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.4.tgz", + "integrity": "sha512-DT25xX/YgyPKiHFOpNuANIQIVvYEwCWXgK2jYYwqgaMrYE6+tq+DtmMwlD3drl6DJbUwtlIDnn0d7tIn/EbXBg==", "dev": true }, "@types/qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-mNhVdZHdtKHMMxbqzNK3RzkBcN1cux3AvuCYGTvjEIQT2uheH3eCAyYsbMbh2Bq8nXkeOWs1kyDiF7geWRFQ4Q==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-47kAAs3yV/hROraCTQYDMh4p/6zI9+gtssjD0kq9OWsGdLcBge59rl49FnCuJ+iWxEKiqFz6KXzeGH5DRVjNJA==", "dev": true }, "abbrev": { @@ -52,75 +109,38 @@ "dev": true, "requires": { "web3": "^0.18.4" - }, - "dependencies": { - "bignumber.js": { - "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", - "from": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", - "dev": true - }, - "web3": { - "version": "0.18.4", - "resolved": "https://registry.npmjs.org/web3/-/web3-0.18.4.tgz", - "integrity": "sha1-gewXhBRUkfLqqJVbMcBgSeB8Xn0=", - "dev": true, - "requires": { - "bignumber.js": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", - "crypto-js": "^3.1.4", - "utf8": "^2.1.1", - "xhr2": "*", - "xmlhttprequest": "*" - } - } } }, - "accepts": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", - "requires": { - "mime-types": "~2.1.18", - "negotiator": "0.6.1" - } + "acorn": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "dev": true }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } + "acorn-jsx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "dev": true }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", "dev": true, "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true + "dev": true, + "optional": true }, "ansi-align": { "version": "2.0.0", @@ -165,9 +185,10 @@ } }, "ansi-escapes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true }, "ansi-regex": { "version": "2.1.1", @@ -178,15 +199,11 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "requires": { "color-convert": "^1.9.0" } }, - "any-observable": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.2.0.tgz", - "integrity": "sha1-xnhwBYADV5AJCD9UrAq6+1wz0kI=" - }, "anymatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", @@ -195,8 +212,24 @@ "requires": { "micromatch": "^3.1.4", "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } } }, + "app-module-path": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/app-module-path/-/app-module-path-2.2.0.tgz", + "integrity": "sha1-ZBqlXft9am8KgUHEucCqULbCTdU=" + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -215,7 +248,8 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true }, "arr-union": { "version": "3.1.0", @@ -223,40 +257,22 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=" - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, "requires": { - "array-uniq": "^1.0.1" + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" } }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" - }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" - }, "asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -264,14 +280,19 @@ "dev": true }, "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true }, "assertion-error": { "version": "1.1.0", @@ -285,860 +306,706 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, - "ast-types": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.3.tgz", - "integrity": "sha512-XA5o5dsNw8MhyW0Q7MWXJWc4oOzZKbdsEJq45h7c8q/d9DwWZ5F2ugUc1PuMLPGsUnphCt/cNDHu8JeBbxf1qA==" + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true }, "async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", - "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", - "requires": { - "lodash": "^4.14.0" - } + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.2.tgz", + "integrity": "sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg==", "dev": true }, - "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true }, "atob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", - "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true }, "aws4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "kind-of": "^6.0.0" } }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "babel-core": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", - "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.0", - "debug": "^2.6.8", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.7", - "slash": "^1.0.0", - "source-map": "^0.5.6" - }, - "dependencies": { - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } } } }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - }, - "dependencies": { - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" - } + "tweetnacl": "^0.14.3" } }, - "babel-helper-bindify-decorators": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz", - "integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "bignumber.js": { + "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", + "from": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", + "dev": true }, - "babel-helper-builder-binary-assignment-operator-visitor": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", - "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", - "requires": { - "babel-helper-explode-assignable-expression": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "file-uri-to-path": "1.0.0" } }, - "babel-helper-define-map": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "boxen": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", + "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "dev": true, "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, - "babel-helper-explode-assignable-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", - "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "babel-helper-explode-class": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz", - "integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=", + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, "requires": { - "babel-helper-bindify-decorators": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } } }, - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", - "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=" }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "browserify-sha3": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/browserify-sha3/-/browserify-sha3-0.0.4.tgz", + "integrity": "sha1-CGxHuMgjFsnUcCLCYYWVRXbdjiY=", + "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "js-sha3": "^0.6.1", + "safe-buffer": "^5.1.1" } }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" } }, - "babel-helper-regex": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", - "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true }, - "babel-helper-remap-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", - "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", - "requires": { - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "capture-stack-trace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", + "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", + "dev": true }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" } }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "check-error": "^1.0.2" } }, - "babel-plugin-syntax-async-functions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", - "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=" - }, - "babel-plugin-syntax-async-generators": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", - "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=" - }, - "babel-plugin-syntax-class-constructor-call": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz", - "integrity": "sha1-nLnTn+Q8hgC+yBRkVt3L1OGnZBY=" - }, - "babel-plugin-syntax-class-properties": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", - "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=" - }, - "babel-plugin-syntax-decorators": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", - "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=" - }, - "babel-plugin-syntax-dynamic-import": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", - "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=" - }, - "babel-plugin-syntax-exponentiation-operator": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", - "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=" - }, - "babel-plugin-syntax-export-extensions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz", - "integrity": "sha1-cKFITw+QiaToStRLrDU8lbmxJyE=" - }, - "babel-plugin-syntax-flow": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", - "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=" - }, - "babel-plugin-syntax-object-rest-spread": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", - "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=" - }, - "babel-plugin-syntax-trailing-function-commas": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", - "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=" + "chai-bn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.1.1.tgz", + "integrity": "sha512-e1npVXt3cQfZ6oQET9oP38vNj/4HeJ4ojeUpuC8YzhVbTJpIDqANVt7TKi7Dq9yKlHySk2FqbmiMih35iT4DYg==", + "dev": true }, - "babel-plugin-transform-async-generator-functions": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz", - "integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { - "babel-helper-remap-async-to-generator": "^6.24.1", - "babel-plugin-syntax-async-generators": "^6.5.0", - "babel-runtime": "^6.22.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, - "babel-plugin-transform-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", - "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", - "requires": { - "babel-helper-remap-async-to-generator": "^6.24.1", - "babel-plugin-syntax-async-functions": "^6.8.0", - "babel-runtime": "^6.22.0" - } + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true }, - "babel-plugin-transform-class-constructor-call": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz", - "integrity": "sha1-gNwoVQWsBn3LjWxl4vbxGrd2Xvk=", - "requires": { - "babel-plugin-syntax-class-constructor-call": "^6.18.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", + "dev": true }, - "babel-plugin-transform-class-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz", - "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-plugin-syntax-class-properties": "^6.8.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true }, - "babel-plugin-transform-decorators": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz", - "integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=", + "chokidar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz", + "integrity": "sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A==", + "dev": true, "requires": { - "babel-helper-explode-class": "^6.24.1", - "babel-plugin-syntax-decorators": "^6.13.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-types": "^6.24.1" + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" } }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", - "requires": { - "babel-runtime": "^6.22.0" - } + "ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } } }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } + "cli-boxes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", + "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "dev": true }, - "babel-plugin-transform-es2015-classes": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, "requires": { - "babel-helper-define-map": "^6.24.1", - "babel-helper-function-name": "^6.24.1", - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-helper-replace-supers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "restore-cursor": "^2.0.0" } }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", - "requires": { - "babel-runtime": "^6.22.0" - } + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true }, - "babel-plugin-transform-es2015-duplicate-keys": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", - "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" } }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", - "requires": { - "babel-runtime": "^6.22.0" - } + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "color-name": "1.1.3" } }, - "babel-plugin-transform-es2015-modules-amd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", - "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", - "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", - "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", - "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-systemjs": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", - "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, - "babel-plugin-transform-es2015-modules-umd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", - "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", - "requires": { - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } + "colors": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", + "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", + "dev": true }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "dev": true, "requires": { - "babel-helper-replace-supers": "^6.24.1", - "babel-runtime": "^6.22.0" + "delayed-stream": "~1.0.0" } }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", - "requires": { - "babel-helper-call-delegate": "^6.24.1", - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", - "requires": { - "babel-runtime": "^6.22.0" - } + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, - "babel-plugin-transform-es2015-sticky-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", - "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "configstore": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", + "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" } }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", - "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", - "requires": { - "babel-runtime": "^6.22.0" - } + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", - "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "regexpu-core": "^2.0.0" - } + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true }, - "babel-plugin-transform-exponentiation-operator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", - "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", - "requires": { - "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", - "babel-plugin-syntax-exponentiation-operator": "^6.8.0", - "babel-runtime": "^6.22.0" - } + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, - "babel-plugin-transform-export-extensions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz", - "integrity": "sha1-U3OLR+deghhYnuqUbLvTkQm75lM=", + "create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, "requires": { - "babel-plugin-syntax-export-extensions": "^6.8.0", - "babel-runtime": "^6.22.0" + "capture-stack-trace": "^1.0.0" } }, - "babel-plugin-transform-flow-strip-types": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", - "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "requires": { - "babel-plugin-syntax-flow": "^6.18.0", - "babel-runtime": "^6.22.0" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, - "babel-plugin-transform-object-rest-spread": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", - "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", - "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-runtime": "^6.26.0" - } + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "dev": true }, - "babel-plugin-transform-regenerator": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", - "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", - "requires": { - "regenerator-transform": "^0.10.0" - } + "crypto-js": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.8.tgz", + "integrity": "sha1-cV8HC/YBTyrpkqmLOSkli3E/CNU=", + "dev": true }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true }, - "babel-preset-es2015": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", - "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, "requires": { - "babel-plugin-check-es2015-constants": "^6.22.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.24.1", - "babel-plugin-transform-es2015-classes": "^6.24.1", - "babel-plugin-transform-es2015-computed-properties": "^6.24.1", - "babel-plugin-transform-es2015-destructuring": "^6.22.0", - "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1", - "babel-plugin-transform-es2015-for-of": "^6.22.0", - "babel-plugin-transform-es2015-function-name": "^6.24.1", - "babel-plugin-transform-es2015-literals": "^6.22.0", - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1", - "babel-plugin-transform-es2015-modules-umd": "^6.24.1", - "babel-plugin-transform-es2015-object-super": "^6.24.1", - "babel-plugin-transform-es2015-parameters": "^6.24.1", - "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "^6.24.1", - "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0", - "babel-plugin-transform-es2015-unicode-regex": "^6.24.1", - "babel-plugin-transform-regenerator": "^6.24.1" + "assert-plus": "^1.0.0" } }, - "babel-preset-stage-1": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz", - "integrity": "sha1-dpLNfc1oSZB+auSgqFWJz7niv7A=", - "requires": { - "babel-plugin-transform-class-constructor-call": "^6.24.1", - "babel-plugin-transform-export-extensions": "^6.22.0", - "babel-preset-stage-2": "^6.24.1" - } + "death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha1-AaqcQB7dknUFFEcLgmY5DGbGcxg=", + "dev": true }, - "babel-preset-stage-2": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz", - "integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=", + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { - "babel-plugin-syntax-dynamic-import": "^6.18.0", - "babel-plugin-transform-class-properties": "^6.24.1", - "babel-plugin-transform-decorators": "^6.24.1", - "babel-preset-stage-3": "^6.24.1" + "ms": "2.0.0" } }, - "babel-preset-stage-3": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz", - "integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=", - "requires": { - "babel-plugin-syntax-trailing-function-commas": "^6.22.0", - "babel-plugin-transform-async-generator-functions": "^6.24.1", - "babel-plugin-transform-async-to-generator": "^6.24.1", - "babel-plugin-transform-exponentiation-operator": "^6.24.1", - "babel-plugin-transform-object-rest-spread": "^6.22.0" - } + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - }, - "dependencies": { - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "requires": { - "source-map": "^0.5.6" - } - } - } + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "type-detect": "^4.0.0" } }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - }, - "dependencies": { - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - } - } + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - }, - "dependencies": { - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - } - } + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "object-keys": "^1.0.12" } }, - "babylon": { - "version": "7.0.0-beta.42", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.42.tgz", - "integrity": "sha512-h6E/OkkvcBw/JimbL0p8dIaxrcuQn3QmIYGC/GtJlRYif5LTKBYPHXYwqluJpfS/kOXoz0go+9mkmOVC0M+zWw==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", @@ -1170,89 +1037,163 @@ } } }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" - }, - "bignumber.js": { - "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", - "from": "bignumber.js@git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, - "binary-extensions": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", - "dev": true + "diff": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", + "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==" }, - "binaryextensions": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.1.tgz", - "integrity": "sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA==" - }, - "bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" - }, - "body-parser": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", - "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", - "requires": { - "bytes": "3.0.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.1", - "http-errors": "~1.6.2", - "iconv-lite": "0.4.19", - "on-finished": "~2.3.0", - "qs": "6.5.1", - "raw-body": "2.3.2", - "type-is": "~1.6.15" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - } + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" } }, - "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, "requires": { - "hoek": "4.x.x" + "is-obj": "^1.0.0" } }, - "boxen": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "dev": true, "requires": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "dev": true, + "requires": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" + }, + "dependencies": { + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "dev": true, + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "eslint": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", + "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.9.1", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^5.0.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.2.2", + "js-yaml": "^3.13.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0" }, "dependencies": { "ansi-regex": { @@ -1261,28 +1202,34 @@ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "ms": "^2.1.1" } }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -1294,697 +1241,479 @@ } } }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "eslint-config-airbnb-base": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz", + "integrity": "sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw==", + "dev": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "eslint-restricted-globals": "^0.1.1", + "object.assign": "^4.1.0", + "object.entries": "^1.0.4" } }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "eslint-config-prettier": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-4.2.0.tgz", + "integrity": "sha512-y0uWc/FRfrHhpPZCYflWC8aE0KRJRY04rdZVfl8cL3sEZmOYyaBdhdlQPjKZBnuRMyLVK+JUZr7HaZFClQiH4w==", "dev": true, "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "get-stdin": "^6.0.0" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" }, "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "ms": "2.0.0" } } } }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "browser-stdout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", - "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=" - }, - "browserify-sha3": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/browserify-sha3/-/browserify-sha3-0.0.1.tgz", - "integrity": "sha1-P/NKMAbvFcD7NWflQbkaI0ASPRE=", + "eslint-module-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz", + "integrity": "sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw==", + "dev": true, "requires": { - "js-sha3": "^0.3.1" + "debug": "^2.6.8", + "pkg-dir": "^2.0.0" }, "dependencies": { - "js-sha3": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.3.1.tgz", - "integrity": "sha1-hhIoAhQvCChQKg0d7h2V4lO7AkM=" + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } } } }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "buffer-to-arraybuffer": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", - "integrity": "sha1-YGSkD6dutDxyOrqe+PbhIW0QURo=" - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" - }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "cacheable-request": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", - "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", - "requires": { - "clone-response": "1.0.2", - "get-stream": "3.0.0", - "http-cache-semantics": "3.8.1", - "keyv": "3.0.0", - "lowercase-keys": "1.0.0", - "normalize-url": "2.0.1", - "responselike": "1.0.2" - } - }, - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" - }, - "capture-stack-trace": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "dev": true, - "optional": true, - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, - "chai": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", - "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", + "eslint-plugin-es": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.4.0.tgz", + "integrity": "sha512-XfFmgFdIUDgvaRAlaXUkxrRg5JSADoRC8IkKLc/cISeR3yHVMefFHQZpcyXXEUUPHfy5DwviBcrfqlyqEwlQVw==", "dev": true, "requires": { - "assertion-error": "^1.0.1", - "check-error": "^1.0.1", - "deep-eql": "^3.0.0", - "get-func-name": "^2.0.0", - "pathval": "^1.0.0", - "type-detect": "^4.0.0" + "eslint-utils": "^1.3.0", + "regexpp": "^2.0.1" } }, - "chai-as-promised": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", - "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "eslint-plugin-import": { + "version": "2.17.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.17.2.tgz", + "integrity": "sha512-m+cSVxM7oLsIpmwNn2WXTJoReOF9f/CtLMo7qOVmKd1KntBy0hEcuNZ3erTmWjx+DxRO0Zcrm5KwAvI9wHcV5g==", "dev": true, "requires": { - "check-error": "^1.0.2" - } - }, - "chai-bignumber": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/chai-bignumber/-/chai-bignumber-2.0.2.tgz", - "integrity": "sha512-BIdRNjRaoRj4bMsZLKbIZPMNKqmwnzNiyxqBYDSs6dFOCs9w8OHPuUE8e1bH60i1IhOzT0NjLtCD+lKEWB1KTQ==", - "dev": true - }, - "chalk": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "array-includes": "^3.0.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.0", + "has": "^1.0.3", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "read-pkg-up": "^2.0.0", + "resolve": "^1.10.0" }, "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } }, - "supports-color": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, "requires": { - "has-flag": "^3.0.0" + "esutils": "^2.0.2", + "isarray": "^1.0.0" } - } - } - }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" - }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", - "dev": true - }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true - }, - "chokidar": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz", - "integrity": "sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.1.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^2.1.1", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.0" - } - }, - "ci-info": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.3.tgz", - "integrity": "sha512-SK/846h/Rcy8q9Z9CAwGBLfCJ6EkjJWdpelWDufQpqVDYq2Wnnv8zlSO6AMQap02jvhVruKKpEtQOufo3pFhLg==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "locate-path": "^2.0.0" } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true } } }, - "cli-boxes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-spinners": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz", - "integrity": "sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw=" - }, - "cli-table": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", - "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", - "requires": { - "colors": "1.0.3" - }, - "dependencies": { - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" - } - } - }, - "cli-table3": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", - "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "eslint-plugin-node": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-9.0.1.tgz", + "integrity": "sha512-fljT5Uyy3lkJzuqhxrYanLSsvaILs9I7CmQ31atTtZ0DoIzRbbvInBh4cQ1CrthFHInHYBQxfPmPt6KLHXNXdw==", "dev": true, "requires": { - "colors": "^1.1.2", - "object-assign": "^4.1.0", - "string-width": "^2.1.1" + "eslint-plugin-es": "^1.4.0", + "eslint-utils": "^1.3.1", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.0.0" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "ignore": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.1.tgz", + "integrity": "sha512-DWjnQIFLenVrwyRCKZT+7a7/U4Cqgar4WG8V++K3hw+lrW1hc/SIwdiGmtxKCVACmHULTuGeBbHJmbwW7/sAvA==", "dev": true }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "resolve": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.1.tgz", + "integrity": "sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "path-parse": "^1.0.6" } }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } + "semver": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", + "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", + "dev": true } } }, - "cli-truncate": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", - "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "eslint-plugin-prettier": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.1.tgz", + "integrity": "sha512-/PMttrarPAY78PLvV3xfWibMOdMDl57hmlQ2XqFeA37wd+CJ7WSxV7txqjVPHi/AAFKd2lX0ZqfsOc/i5yFCSQ==", + "dev": true, "requires": { - "slice-ansi": "0.0.4", - "string-width": "^1.0.1" + "prettier-linter-helpers": "^1.0.0" } }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" + "eslint-restricted-globals": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=", + "dev": true }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + } } }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + "eslint-utils": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", + "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", + "dev": true }, - "clone-buffer": { + "eslint-visitor-keys": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=" + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "espree": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", + "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "dev": true, "requires": { - "mimic-response": "^1.0.0" + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" } }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=" + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true }, - "cloneable-readable": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz", - "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, "requires": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" + "estraverse": "^4.0.0" + }, + "dependencies": { + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + } } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + }, + "dependencies": { + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + } + } }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "dev": true }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "eth-gas-reporter": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.1.12.tgz", + "integrity": "sha512-Ao5uiXSA5Ep5fi/YvGCsFJMelMKj0fMJkAvWYzPVe1h3Mg9Z7X3Rs51ovG9izFZH7wSqnqydiC6SKDhZWpxK2g==", "dev": true, "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "abi-decoder": "^1.0.8", + "cli-table3": "^0.5.0", + "colors": "^1.1.2", + "lodash": "^4.17.4", + "mocha": "^4.1.0", + "req-cwd": "^2.0.0", + "request": "^2.83.0", + "request-promise-native": "^1.0.5", + "sha1": "^1.1.1", + "shelljs": "^0.7.8", + "solidity-parser-antlr": "^0.2.10", + "sync-request": "^6.0.0" } }, - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "ethereumjs-testrpc-sc": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/ethereumjs-testrpc-sc/-/ethereumjs-testrpc-sc-6.1.6.tgz", + "integrity": "sha512-iv2qiGBFgk9mn5Nq2enX8dG5WQ7Lk+FCqpnxfPfH4Ns8KLPwttmNOy264nh3SXDJJvcQwz/XnlLteDQVILotbg==", + "dev": true, "requires": { - "color-name": "^1.1.1" + "source-map-support": "^0.5.3" } }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "colors": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.1.tgz", - "integrity": "sha512-s8+wktIuDSLffCywiwSxQOMqtPxML11a/dtHE17tMn4B1MSWw/C22EKf7M2KGUBcDaVFEGT+S8N02geDXeuNKg==" - }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "requires": { - "delayed-stream": "~1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, - "commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" - }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "configstore": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", - "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", - "dev": true, - "requires": { - "dot-prop": "^4.1.0", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "convert-source-map": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=" - }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", - "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "cors": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz", - "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=", - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, - "create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "capture-stack-trace": "^1.0.0" - } - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { - "lru-cache": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz", - "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" } } } }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, "requires": { - "boom": "5.x.x" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, "requires": { - "hoek": "4.x.x" + "is-plain-object": "^2.0.4" } } } }, - "crypto-js": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.8.tgz", - "integrity": "sha1-cV8HC/YBTyrpkqmLOSkli3E/CNU=", - "dev": true - }, - "crypto-random-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", - "dev": true - }, - "dargs": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-5.1.0.tgz", - "integrity": "sha1-7H6lDHhWTNNsnV7Bj2Yyn63ieCk=" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "date-fns": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz", - "integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==" - }, - "dateformat": { + "external-editor": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==" - }, - "death": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", - "integrity": "sha1-AaqcQB7dknUFFEcLgmY5DGbGcxg=", - "dev": true - }, - "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", "dev": true, "requires": { - "type-detect": "^4.0.0" + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" } }, - "deep-extend": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", - "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=" - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", @@ -2016,1311 +1745,1038 @@ } } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true }, - "detect-conflict": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/detect-conflict/-/detect-conflict-1.0.1.tgz", - "integrity": "sha1-CIZXpmqWHAUBnbfEIwiDsca0F24=" + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "requires": { - "repeating": "^2.0.0" - } + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true }, - "diff": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", - "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==" - }, - "dom-walk": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", - "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" - }, - "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { - "is-obj": "^1.0.0" - } - }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, - "requires": { - "jsbn": "~0.1.0" + "escape-string-regexp": "^1.0.5" } }, - "editions": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", - "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==" - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "ejs": { - "version": "2.5.8", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.8.tgz", - "integrity": "sha512-QIDZL54fyV8MDcAsO91BMH1ft2qGGaHIJsJIA/+t+7uvXol1dm413fPcUgUb4k8F/9457rx4/KFE4XfDifrQxQ==" - }, - "elegant-spinner": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", - "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=" - }, - "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" + "flat-cache": "^2.0.1" } }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" }, - "enhanced-resolve": { + "fill-range": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz", - "integrity": "sha512-jox/62b2GofV1qTUQTMPEJSDIGycS43evqYzD/KVtEb9OCoki9cnacUPxCrZa7JfPzZSYOCZhu9O9luaMxAX8g==", - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" - } - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "requires": { - "prr": "~1.0.1" - } - }, - "error": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", - "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", - "requires": { - "string-template": "~0.2.1", - "xtend": "~4.0.0" - } - }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "escodegen": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "esprima": "^2.7.1", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.2.0" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "dependencies": { - "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true - }, - "source-map": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, - "optional": true, "requires": { - "amdefine": ">=0.0.4" + "is-extendable": "^0.1.0" } } } }, - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" - }, - "estraverse": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "eth-gas-reporter": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.1.12.tgz", - "integrity": "sha512-Ao5uiXSA5Ep5fi/YvGCsFJMelMKj0fMJkAvWYzPVe1h3Mg9Z7X3Rs51ovG9izFZH7wSqnqydiC6SKDhZWpxK2g==", + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "abi-decoder": "^1.0.8", - "cli-table3": "^0.5.0", - "colors": "^1.1.2", - "lodash": "^4.17.4", - "mocha": "^4.1.0", - "req-cwd": "^2.0.0", - "request": "^2.83.0", - "request-promise-native": "^1.0.5", - "sha1": "^1.1.1", - "shelljs": "^0.7.8", - "solidity-parser-antlr": "^0.2.10", - "sync-request": "^6.0.0" - }, - "dependencies": { - "req-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", - "integrity": "sha1-1AgrTURZgDZkD7c93qAe1T20nrw=", - "dev": true, - "requires": { - "req-from": "^2.0.0" - } - }, - "req-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", - "integrity": "sha1-10GI5H+TeW9Kpx327jWuaJ8+DnA=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "shelljs": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", - "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - } - } - }, - "eth-lib": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.27.tgz", - "integrity": "sha512-B8czsfkJYzn2UIEMwjc7Mbj+Cy72V+/OXH/tb44LV8jhrjizQJJ325xMOMyk3+ETa6r6oi0jsUY14+om8mQMWA==", - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "keccakjs": "^0.2.1", - "nano-json-stream-parser": "^0.1.2", - "servify": "^0.1.12", - "ws": "^3.0.0", - "xhr-request-promise": "^0.1.2" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, - "ethereumjs-testrpc-sc": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/ethereumjs-testrpc-sc/-/ethereumjs-testrpc-sc-6.1.2.tgz", - "integrity": "sha512-dBTav4AZQ7zuajmICv1k7bEesqS+8f0u0wciXNUJZb842RTBi0lgKEDF8WgZshzv4ThI+XVQSRNV/A+seiK4aA==", + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, "requires": { - "source-map-support": "^0.5.3", - "webpack-cli": "^2.0.9" + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" } }, - "ethjs-unit": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", - "integrity": "sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk=", + "flatted": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", + "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, "requires": { - "bn.js": "4.11.6", - "number-to-bn": "1.7.0" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" } }, - "event-stream": { - "version": "3.3.4", - "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "duplexer": "~0.1.1", - "from": "~0", - "map-stream": "~0.1.0", - "pause-stream": "0.0.11", - "split": "0.3", - "stream-combiner": "~0.0.4", - "through": "~2.3.1" + "map-cache": "^0.2.2" } }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" } }, - "exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=" + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "fsevents": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz", + "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==", "dev": true, + "optional": true, "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.0" }, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "abbrev": { + "version": "1.1.1", + "bundled": true, "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } + "optional": true }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "requires": { - "fill-range": "^2.1.0" - }, - "dependencies": { - "fill-range": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", - "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^1.1.3", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "requires": { - "kind-of": "^3.0.2" - } + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, "requires": { - "isarray": "1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "express": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", - "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", - "requires": { - "accepts": "~1.3.5", - "array-flatten": "1.1.1", - "body-parser": "1.18.2", - "content-disposition": "0.5.2", - "content-type": "~1.0.4", - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.1.1", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.3", - "qs": "6.5.1", - "range-parser": "~1.2.0", - "safe-buffer": "5.1.1", - "send": "0.16.2", - "serve-static": "1.13.2", - "setprototypeof": "1.1.0", - "statuses": "~1.4.0", - "type-is": "~1.6.16", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, "debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "bundled": true, + "dev": true, + "optional": true, "requires": { "ms": "2.0.0" } }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" - } - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, "dev": true, + "optional": true, "requires": { - "is-plain-object": "^2.0.4" + "minipass": "^2.2.1" } - } - } - }, - "external-editor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", - "integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA==", - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { + }, + "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, "dev": true, + "optional": true, "requires": { - "is-descriptor": "^1.0.0" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" } }, - "extend-shallow": { + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, "dev": true, + "optional": true, "requires": { - "is-extendable": "^0.1.0" + "safer-buffer": ">= 2.1.2 < 3" } }, - "is-accessor-descriptor": { + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "bundled": true, "dev": true, + "optional": true, "requires": { - "kind-of": "^6.0.0" + "number-is-nan": "^1.0.0" } }, - "is-data-descriptor": { + "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, "dev": true, + "optional": true, "requires": { - "kind-of": "^6.0.0" + "brace-expansion": "^1.1.7" } }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, "dev": true, + "optional": true, "requires": { - "is-extendable": "^0.1.0" + "minipass": "^2.2.1" } - } - } - }, - "finalhandler": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", - "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.4.0", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, "requires": { - "ms": "2.0.0" + "minimist": "0.0.8" } }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" - } - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "first-chunk-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz", - "integrity": "sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=", - "requires": { - "readable-stream": "^2.0.2" - } - }, - "flow-parser": { - "version": "0.68.0", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.68.0.tgz", - "integrity": "sha1-nMlmIKEC4xajFLa81WIFzqzoYtg=" - }, - "for-each": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.2.tgz", - "integrity": "sha1-LEBFC5NI6X8oEyJZO6lnBLmr1NQ=", - "requires": { - "is-function": "~1.0.0" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "requires": { - "for-in": "^1.0.1" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", - "dev": true - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.3.tgz", - "integrity": "sha512-X+57O5YkDTiEQGiw8i7wYc2nQgweIekqkepI8Q3y4wVlurgBt2SuwxTeYUYMZIGpLZH3r/TsMjczCMXE5ZOt7Q==", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.9.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", + "ms": { + "version": "2.0.0", "bundled": true, "dev": true, "optional": true }, - "ansi-regex": { - "version": "2.1.1", + "needle": { + "version": "2.2.4", "bundled": true, - "dev": true + "dev": true, + "optional": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } }, - "aproba": { - "version": "1.2.0", + "node-pre-gyp": { + "version": "0.10.3", "bundled": true, "dev": true, - "optional": true + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } }, - "are-we-there-yet": { - "version": "1.1.4", + "nopt": { + "version": "4.0.1", "bundled": true, "dev": true, "optional": true, "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "abbrev": "1", + "osenv": "^0.1.4" } }, - "balanced-match": { - "version": "1.0.0", + "npm-bundled": { + "version": "1.0.5", "bundled": true, - "dev": true + "dev": true, + "optional": true }, - "brace-expansion": { - "version": "1.1.11", + "npm-packlist": { + "version": "1.2.0", "bundled": true, "dev": true, + "optional": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" } }, - "chownr": { + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { "version": "1.0.1", "bundled": true, "dev": true, "optional": true }, - "code-point-at": { - "version": "1.1.0", + "object-assign": { + "version": "4.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, - "concat-map": { - "version": "0.0.1", + "once": { + "version": "1.4.0", "bundled": true, - "dev": true + "dev": true, + "requires": { + "wrappy": "1" + } }, - "console-control-strings": { - "version": "1.1.0", + "os-homedir": { + "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, - "core-util-is": { + "os-tmpdir": { "version": "1.0.2", "bundled": true, "dev": true, "optional": true }, - "debug": { - "version": "2.6.9", + "osenv": { + "version": "0.1.5", "bundled": true, "dev": true, "optional": true, "requires": { - "ms": "2.0.0" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, - "deep-extend": { - "version": "0.4.2", + "path-is-absolute": { + "version": "1.0.1", "bundled": true, "dev": true, "optional": true }, - "delegates": { - "version": "1.0.0", + "process-nextick-args": { + "version": "2.0.0", "bundled": true, "dev": true, "optional": true }, - "detect-libc": { - "version": "1.0.3", + "rc": { + "version": "1.2.8", "bundled": true, "dev": true, - "optional": true + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } }, - "fs-minipass": { - "version": "1.2.5", + "readable-stream": { + "version": "2.3.6", "bundled": true, "dev": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "fs.realpath": { - "version": "1.0.0", + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", "bundled": true, "dev": true, "optional": true }, - "gauge": { - "version": "2.7.4", + "sax": { + "version": "1.2.4", "bundled": true, "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } + "optional": true }, - "glob": { - "version": "7.1.2", + "semver": { + "version": "5.6.0", "bundled": true, "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } + "optional": true }, - "has-unicode": { - "version": "2.0.1", + "set-blocking": { + "version": "2.0.0", "bundled": true, "dev": true, "optional": true }, - "iconv-lite": { - "version": "0.4.21", + "signal-exit": { + "version": "3.0.2", "bundled": true, "dev": true, - "optional": true, - "requires": { - "safer-buffer": "^2.1.0" - } + "optional": true }, - "ignore-walk": { - "version": "3.0.1", + "string-width": { + "version": "1.0.2", "bundled": true, "dev": true, "optional": true, "requires": { - "minimatch": "^3.0.4" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, - "inflight": { - "version": "1.0.6", + "string_decoder": { + "version": "1.1.1", "bundled": true, "dev": true, "optional": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "safe-buffer": "~5.1.0" } }, - "inherits": { - "version": "2.0.3", + "strip-ansi": { + "version": "3.0.1", "bundled": true, - "dev": true + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } }, - "ini": { - "version": "1.3.5", + "strip-json-comments": { + "version": "2.0.1", "bundled": true, "dev": true, "optional": true }, - "is-fullwidth-code-point": { - "version": "1.0.0", + "tar": { + "version": "4.4.8", "bundled": true, "dev": true, + "optional": true, "requires": { - "number-is-nan": "^1.0.0" + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" } }, - "isarray": { - "version": "1.0.0", + "util-deprecate": { + "version": "1.0.2", "bundled": true, "dev": true, "optional": true }, - "minimatch": { - "version": "3.0.4", + "wide-align": { + "version": "1.1.3", "bundled": true, "dev": true, + "optional": true, "requires": { - "brace-expansion": "^1.1.7" + "string-width": "^1.0.2 || 2" } }, - "minimist": { - "version": "0.0.8", + "wrappy": { + "version": "1.0.2", "bundled": true, "dev": true }, - "minipass": { - "version": "2.2.4", + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "ganache-cli": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/ganache-cli/-/ganache-cli-6.4.3.tgz", + "integrity": "sha512-3G+CK4ojipDvxQHlpX8PjqaOMRWVcaLZZSW97Bv7fdcPTXQwkji2yY5CY6J12Atiub4M4aJc0va+q3HXeerbIA==", + "requires": { + "bn.js": "4.11.8", + "source-map-support": "0.5.9", + "yargs": "11.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true + }, + "bn.js": { + "version": "4.11.8", + "bundled": true + }, + "buffer-from": { + "version": "1.1.1", + "bundled": true + }, + "camelcase": { + "version": "4.1.0", + "bundled": true + }, + "cliui": { + "version": "4.1.0", "bundled": true, - "dev": true, "requires": { - "safe-buffer": "^5.1.1", - "yallist": "^3.0.0" + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" } }, - "minizlib": { + "code-point-at": { "version": "1.1.0", + "bundled": true + }, + "cross-spawn": { + "version": "5.1.0", "bundled": true, - "dev": true, - "optional": true, "requires": { - "minipass": "^2.2.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, - "mkdirp": { - "version": "0.5.1", + "decamelize": { + "version": "1.2.0", + "bundled": true + }, + "execa": { + "version": "0.7.0", "bundled": true, - "dev": true, "requires": { - "minimist": "0.0.8" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, - "ms": { - "version": "2.0.0", + "find-up": { + "version": "2.1.0", "bundled": true, - "dev": true, - "optional": true + "requires": { + "locate-path": "^2.0.0" + } }, - "needle": { - "version": "2.2.0", + "get-caller-file": { + "version": "1.0.3", + "bundled": true + }, + "get-stream": { + "version": "3.0.0", + "bundled": true + }, + "invert-kv": { + "version": "1.0.0", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true + }, + "lcid": { + "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true, "requires": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" + "invert-kv": "^1.0.0" } }, - "node-pre-gyp": { - "version": "0.9.1", + "locate-path": { + "version": "2.0.0", "bundled": true, - "dev": true, - "optional": true, "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" } }, - "nopt": { - "version": "4.0.1", + "lru-cache": { + "version": "4.1.4", "bundled": true, - "dev": true, - "optional": true, "requires": { - "abbrev": "1", - "osenv": "^0.1.4" + "pseudomap": "^1.0.2", + "yallist": "^3.0.2" } }, - "npm-bundled": { - "version": "1.0.3", + "mem": { + "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "requires": { + "mimic-fn": "^1.0.0" + } }, - "npm-packlist": { - "version": "1.1.10", + "mimic-fn": { + "version": "1.2.0", + "bundled": true + }, + "npm-run-path": { + "version": "2.0.2", "bundled": true, - "dev": true, - "optional": true, "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" + "path-key": "^2.0.0" } }, - "npmlog": { - "version": "4.1.2", + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "os-locale": { + "version": "2.1.0", "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, "requires": { - "wrappy": "1" + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" } }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true + "p-finally": { + "version": "1.0.0", + "bundled": true }, - "osenv": { - "version": "0.1.5", + "p-limit": { + "version": "1.3.0", "bundled": true, - "dev": true, - "optional": true, "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" + "p-try": "^1.0.0" } }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { + "p-locate": { "version": "2.0.0", "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.6", - "bundled": true, - "dev": true, - "optional": true, "requires": { - "deep-extend": "~0.4.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } + "p-limit": "^1.1.0" } }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } + "p-try": { + "version": "1.0.0", + "bundled": true }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.0.5" - } + "path-exists": { + "version": "3.0.0", + "bundled": true }, - "safe-buffer": { - "version": "5.1.1", - "bundled": true, - "dev": true + "path-key": { + "version": "2.0.1", + "bundled": true }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true + "pseudomap": { + "version": "1.0.2", + "bundled": true }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true + "require-directory": { + "version": "2.1.1", + "bundled": true }, - "semver": { - "version": "5.5.0", - "bundled": true, - "dev": true, - "optional": true + "require-main-filename": { + "version": "1.0.1", + "bundled": true }, "set-blocking": { "version": "2.0.0", + "bundled": true + }, + "shebang-command": { + "version": "1.2.0", "bundled": true, - "dev": true, - "optional": true + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true }, "signal-exit": { "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true + "bundled": true }, - "string-width": { - "version": "1.0.2", + "source-map": { + "version": "0.6.1", + "bundled": true + }, + "source-map-support": { + "version": "0.5.9", "bundled": true, - "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "string_decoder": { - "version": "1.1.1", + "string-width": { + "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true, "requires": { - "safe-buffer": "~5.1.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "strip-ansi": { - "version": "3.0.1", + "version": "4.0.0", "bundled": true, - "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^3.0.0" } }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true + "strip-eof": { + "version": "1.0.0", + "bundled": true }, - "tar": { - "version": "4.4.1", + "which": { + "version": "1.3.1", "bundled": true, - "dev": true, - "optional": true, "requires": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", - "yallist": "^3.0.2" + "isexe": "^2.0.0" } }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true + "which-module": { + "version": "2.0.0", + "bundled": true }, - "wide-align": { - "version": "1.1.2", + "wrap-ansi": { + "version": "2.1.0", "bundled": true, - "dev": true, - "optional": true, "requires": { - "string-width": "^1.0.2" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } } }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true + "y18n": { + "version": "3.2.1", + "bundled": true }, "yallist": { "version": "3.0.2", + "bundled": true + }, + "yargs": { + "version": "11.1.0", "bundled": true, - "dev": true + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" + } + }, + "yargs-parser": { + "version": "9.0.2", + "bundled": true, + "requires": { + "camelcase": "^4.1.0" + } } } }, - "ganache-cli": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ganache-cli/-/ganache-cli-6.1.0.tgz", - "integrity": "sha512-FdTeyk4uLRHGeFiMe+Qnh4Hc5KiTVqvRVVvLDFJEVVKC1P1yHhEgZeh9sp1KhuvxSrxToxgJS25UapYQwH4zHw==", - "requires": { - "source-map-support": "^0.5.3", - "webpack-cli": "^2.0.9" - } - }, "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" }, "get-func-name": { "version": "2.0.0", @@ -3334,6 +2790,12 @@ "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", "dev": true }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", @@ -3349,140 +2811,32 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, "requires": { "assert-plus": "^1.0.0" } }, - "gh-got": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gh-got/-/gh-got-6.0.0.tgz", - "integrity": "sha512-F/mS+fsWQMo1zfgG9MD8KWvTWPPzzhuVwY++fhQ5Ggd+0P+CAMHtzMZhNxG+TqGfHDChJKsbh6otfMGqO2AKBw==", - "requires": { - "got": "^7.0.0", - "is-plain-obj": "^1.1.0" - }, - "dependencies": { - "got": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", - "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", - "requires": { - "decompress-response": "^3.2.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-plain-obj": "^1.1.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "p-cancelable": "^0.3.0", - "p-timeout": "^1.1.1", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "url-parse-lax": "^1.0.0", - "url-to-options": "^1.0.1" - } - }, - "p-cancelable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", - "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==" - }, - "p-timeout": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", - "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", - "requires": { - "p-finally": "^1.0.0" - } - } - } - }, - "github-username": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/github-username/-/github-username-4.1.0.tgz", - "integrity": "sha1-y+KABBiDIG2kISrp5LXxacML9Bc=", - "requires": { - "gh-got": "^6.0.0" - } - }, "glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.2", + "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, - "glob-all": { + "glob-parent": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-all/-/glob-all-3.1.0.tgz", - "integrity": "sha1-iRPd+17hrHgSZWJBsD1SF8ZLAqs=", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, "requires": { - "glob": "^7.0.5", - "yargs": "~1.2.6" - }, - "dependencies": { - "minimist": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.1.0.tgz", - "integrity": "sha1-md9lelJXTCHJBXSX33QnkLK0wN4=" - }, - "yargs": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.2.6.tgz", - "integrity": "sha1-nHtKgv1dWVsr8Xq23MQxNUMv40s=", - "requires": { - "minimist": "^0.1.0" - } - } - } - }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "requires": { - "is-glob": "^2.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" }, "dependencies": { "is-glob": { @@ -3496,15 +2850,6 @@ } } }, - "global": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", - "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", - "requires": { - "min-document": "^2.19.0", - "process": "~0.5.1" - } - }, "global-dirs": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", @@ -3514,44 +2859,11 @@ "ini": "^1.3.4" } }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" - }, - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true }, "got": { "version": "6.7.1", @@ -3573,99 +2885,71 @@ } }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "grouped-queue": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-0.3.3.tgz", - "integrity": "sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=", - "requires": { - "lodash": "^4.17.2" - } + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, "growl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", - "dev": true + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", + "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==" }, "handlebars": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", - "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", + "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", "dev": true, "requires": { - "async": "^1.4.0", + "neo-async": "^2.6.0", "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" }, "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true } } }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true }, "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, "requires": { - "ajv": "^5.1.0", + "ajv": "^6.5.5", "har-schema": "^2.0.0" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "function-bind": "^1.1.1" } }, - "has-color": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", - "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=" - }, "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" + }, + "has-symbols": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, - "has-symbol-support-x": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", - "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" - }, - "has-to-string-tag-x": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", - "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", - "requires": { - "has-symbol-support-x": "^1.4.1" - } - }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -3698,111 +2982,43 @@ } } }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", - "requires": { - "boom": "4.x.x", - "cryptiles": "3.x.x", - "hoek": "4.x.x", - "sntp": "2.x.x" - } - }, "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, - "homedir-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", - "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", - "requires": { - "parse-passwd": "^1.0.0" - } - }, "hosted-git-info": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", - "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==" + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true }, "http-basic": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-7.0.0.tgz", - "integrity": "sha1-gvClBr6UJzLsje6+6A50bvVzbbo=", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.1.tgz", + "integrity": "sha512-RRPtpg/R7HbDEoICA1MlLy0IH0D/1ShY9AcvY6U2zqT/8mjjJ893H/2URxx6JtFYEfL3IlKTkQQcKwTyLuubKA==", "dev": true, "requires": { - "@types/concat-stream": "^1.6.0", - "@types/node": "^9.4.1", - "caseless": "~0.12.0", - "concat-stream": "^1.4.6", + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", "http-response-object": "^3.0.1", "parse-cache-control": "^1.0.1" } }, - "http-cache-semantics": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, "http-response-object": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.1.tgz", - "integrity": "sha512-6L0Fkd6TozA8kFSfh9Widst0wfza3U1Ex2RjJ6zNDK0vR1U1auUR6jY4Nn2Xl7CCy0ikFmxW1XcspVpb9RvwTg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", "dev": true, "requires": { - "@types/node": "^9.3.0" + "@types/node": "^10.0.3" } }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -3810,9 +3026,19 @@ } }, "iconv-lite": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true }, "ignore-by-default": { "version": "1.0.1", @@ -3820,6 +3046,24 @@ "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", "dev": true }, + "import-fresh": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", + "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -3829,15 +3073,8 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "requires": { - "repeating": "^2.0.0" - } + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true }, "inflight": { "version": "1.0.6", @@ -3856,89 +3093,93 @@ "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true }, "inquirer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", - "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz", + "integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==", + "dev": true, "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", - "external-editor": "^2.1.0", + "external-editor": "^3.0.3", "figures": "^2.0.0", - "lodash": "^4.3.0", + "lodash": "^4.17.11", "mute-stream": "0.0.7", "run-async": "^2.2.0", - "rxjs": "^5.5.2", + "rxjs": "^6.4.0", "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", + "strip-ansi": "^5.1.0", "through": "^2.3.6" }, "dependencies": { "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } } } } }, "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" - }, - "into-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", - "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", - "requires": { - "from2": "^2.1.1", - "p-is-promise": "^1.1.0" - } - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "requires": { - "loose-envify": "^1.0.0" - } + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true }, "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, - "ipaddr.js": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", - "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=" - }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", @@ -3962,7 +3203,8 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true }, "is-binary-path": { "version": "1.0.1", @@ -3976,23 +3218,22 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "requires": { - "builtin-modules": "^1.0.0" - } + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true }, "is-ci": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.1.0.tgz", - "integrity": "sha512-c7TnwxLePuqIlxHgr7xtxzycJPegNHFuIrBkwbf8hc58//+Op1CqFkyS+xnIMkwn9UsJIwc174BIjkyBmSpjKg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", "dev": true, "requires": { - "ci-info": "^1.0.0" + "ci-info": "^1.5.0" } }, "is-data-descriptor": { @@ -4015,6 +3256,12 @@ } } }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -4034,23 +3281,11 @@ } } }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "requires": { - "is-primitive": "^2.0.0" - } - }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true }, "is-extglob": { "version": "2.1.1", @@ -4058,14 +3293,6 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -4074,25 +3301,15 @@ "number-is-nan": "^1.0.0" } }, - "is-function": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz", - "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=" - }, "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { "is-extglob": "^2.1.1" } }, - "is-hex-prefixed": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", - "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=" - }, "is-installed-globally": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", @@ -4113,6 +3330,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -4121,6 +3339,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -4133,43 +3352,6 @@ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, - "is-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", - "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" - }, - "is-observable": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-0.2.0.tgz", - "integrity": "sha1-s2ExHYPG5dcmyr9eJQsCNxBvWuI=", - "requires": { - "symbol-observable": "^0.2.2" - }, - "dependencies": { - "symbol-observable": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-0.2.4.tgz", - "integrity": "sha1-lag9smGG1q9+ehjb2XYKL4bQj0A=" - } - } - }, - "is-odd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", - "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", - "dev": true, - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - } - } - }, "is-path-inside": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", @@ -4179,11 +3361,6 @@ "path-is-inside": "^1.0.1" } }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" - }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -4193,20 +3370,11 @@ "isobject": "^3.0.1" } }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" - }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true }, "is-redirect": { "version": "1.0.0", @@ -4214,43 +3382,58 @@ "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", "dev": true }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, "is-retry-allowed": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", - "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" - }, - "is-scoped": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-scoped/-/is-scoped-1.0.0.tgz", - "integrity": "sha1-RJypgpnnEwOCViieyytUDcQ3yzA=", - "requires": { - "scoped-regex": "^1.0.0" - } + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", + "dev": true }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true }, "isexe": { "version": "2.0.0", @@ -4266,7 +3449,8 @@ "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true }, "istanbul": { "version": "0.4.5", @@ -4296,18 +3480,6 @@ "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", "dev": true }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true - }, "glob": { "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", @@ -4321,7 +3493,13 @@ "path-is-absolute": "^1.0.0" } }, - "nopt": { + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", @@ -4335,227 +3513,77 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true - } - } - }, - "istextorbinary": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.2.1.tgz", - "integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==", - "requires": { - "binaryextensions": "2", - "editions": "^1.3.3", - "textextensions": "2" - } - }, - "isurl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", - "requires": { - "has-to-string-tag-x": "^1.2.0", - "is-object": "^1.0.1" - } - }, - "jade": { - "version": "0.26.3", - "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", - "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", - "dev": true, - "requires": { - "commander": "0.6.1", - "mkdirp": "0.3.0" - }, - "dependencies": { - "commander": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", - "dev": true }, - "mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", - "dev": true + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } } } }, "js-sha3": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz", - "integrity": "sha1-uvDA6MVK1ZA0R9+Wreekobynmko=", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.6.1.tgz", + "integrity": "sha1-W4n3enR3Z5h39YxKB1JAk0sflcA=", "dev": true }, "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "js-yaml": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz", - "integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + } } }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true - }, - "jscodeshift": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.5.0.tgz", - "integrity": "sha512-JAcQINNMFpdzzpKJN8k5xXjF3XDuckB1/48uScSzcnNyK199iWEc9AxKL9OoX5144M2w5zEx9Qs4/E/eBZZUlw==", - "requires": { - "babel-plugin-transform-flow-strip-types": "^6.8.0", - "babel-preset-es2015": "^6.9.0", - "babel-preset-stage-1": "^6.5.0", - "babel-register": "^6.9.0", - "babylon": "^7.0.0-beta.30", - "colors": "^1.1.2", - "flow-parser": "^0.*", - "lodash": "^4.13.1", - "micromatch": "^2.3.7", - "neo-async": "^2.5.0", - "node-dir": "0.1.8", - "nomnom": "^1.8.1", - "recast": "^0.14.1", - "temp": "^0.8.1", - "write-file-atomic": "^1.2.0" - }, - "dependencies": { - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "^1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "write-file-atomic": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", - "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" - } - } - } - }, - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" - }, - "json-parse-better-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.1.tgz", - "integrity": "sha512-xyQpxeWWMKyJps9CuGJYeng6ssI5bpqS9ltQpdVQ90t4ql6NdnxFKh95JcRt2cun/DjMVNrdjniLPuMA69xmCw==" + "dev": true }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true }, "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true }, "jsonfile": { "version": "2.4.0", @@ -4569,6 +3597,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -4576,21 +3605,25 @@ "verror": "1.10.0" } }, - "keccakjs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/keccakjs/-/keccakjs-0.2.1.tgz", - "integrity": "sha1-HWM6+QfvMFu/ny+mFtVsRFYd+k0=", + "keccak": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-1.4.0.tgz", + "integrity": "sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw==", "requires": { - "browserify-sha3": "^0.0.1", - "sha3": "^1.1.0" + "bindings": "^1.2.1", + "inherits": "^2.0.3", + "nan": "^2.2.1", + "safe-buffer": "^5.1.0" } }, - "keyv": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", - "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "keccakjs": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/keccakjs/-/keccakjs-0.2.3.tgz", + "integrity": "sha512-BjLkNDcfaZ6l8HBG9tH0tpmDv3sS2mA7FNQxFHpCdzP3Gb2MVruXBSuoM66SnVxKJpAr5dKGdkHD+bDokt8fTg==", + "dev": true, "requires": { - "json-buffer": "3.0.0" + "browserify-sha3": "^0.0.4", + "sha3": "^1.2.2" } }, "kind-of": { @@ -4616,13 +3649,6 @@ "package-json": "^4.0.0" } }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true, - "optional": true - }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -4641,207 +3667,11 @@ "type-check": "~0.3.2" } }, - "listr": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.13.0.tgz", - "integrity": "sha1-ILsLowuuZg7oTMBQPfS+PVYjiH0=", - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "figures": "^1.7.0", - "indent-string": "^2.1.0", - "is-observable": "^0.2.0", - "is-promise": "^2.1.0", - "is-stream": "^1.1.0", - "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.4.0", - "listr-verbose-renderer": "^0.4.0", - "log-symbols": "^1.0.2", - "log-update": "^1.0.2", - "ora": "^0.2.3", - "p-map": "^1.1.1", - "rxjs": "^5.4.2", - "stream-to-observable": "^0.2.0", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "requires": { - "chalk": "^1.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "listr-silent-renderer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", - "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=" - }, - "listr-update-renderer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz", - "integrity": "sha1-NE2YDaLKLosUW6MFkI8yrj9MyKc=", - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^1.0.2", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=" - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "requires": { - "chalk": "^1.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "listr-verbose-renderer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz", - "integrity": "sha1-ggb0z21S3cWCfl/RSYng6WWTOjU=", - "requires": { - "chalk": "^1.1.3", - "cli-cursor": "^1.0.2", - "date-fns": "^1.27.2", - "figures": "^1.7.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "requires": { - "restore-cursor": "^1.0.1" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, - "onetime": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=" - }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, "load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", @@ -4850,16 +3680,6 @@ "strip-bom": "^2.0.0" } }, - "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0" - } - }, "locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", @@ -4877,90 +3697,37 @@ } }, "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true }, "lodash.assign": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "requires": { - "chalk": "^2.0.1" - } - }, - "log-update": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz", - "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=", - "requires": { - "ansi-escapes": "^1.0.0", - "cli-cursor": "^1.0.2" - }, - "dependencies": { - "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" - }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "requires": { - "restore-cursor": "^1.0.1" - } - }, - "onetime": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=" - }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - } - } - } + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true }, - "longest": { + "lowercase-keys": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", "dev": true }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "requires": { - "js-tokens": "^3.0.0" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, - "lowercase-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", - "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, "make-dir": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz", - "integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, "requires": { "pify": "^3.0.0" }, @@ -4968,7 +3735,8 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true } } }, @@ -4978,12 +3746,6 @@ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true }, - "map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", - "dev": true - }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", @@ -4993,11 +3755,6 @@ "object-visit": "^1.0.0" } }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, "mem": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", @@ -5006,87 +3763,11 @@ "mimic-fn": "^1.0.0" } }, - "mem-fs": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/mem-fs/-/mem-fs-1.1.3.tgz", - "integrity": "sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw=", - "requires": { - "through2": "^2.0.0", - "vinyl": "^1.1.0", - "vinyl-file": "^2.0.0" - } - }, - "mem-fs-editor": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mem-fs-editor/-/mem-fs-editor-3.0.2.tgz", - "integrity": "sha1-3Qpuryu4prN3QAZ6pUnrUwEFr58=", - "requires": { - "commondir": "^1.0.1", - "deep-extend": "^0.4.0", - "ejs": "^2.3.1", - "glob": "^7.0.3", - "globby": "^6.1.0", - "mkdirp": "^0.5.0", - "multimatch": "^2.0.0", - "rimraf": "^2.2.8", - "through2": "^2.0.0", - "vinyl": "^2.0.1" - }, - "dependencies": { - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" - }, - "clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=" - }, - "replace-ext": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=" - }, - "vinyl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.1.0.tgz", - "integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=", - "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - } - } - } - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, "memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=" }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -5108,22 +3789,19 @@ "to-regex": "^3.0.2" } }, - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" - }, "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==", + "dev": true }, "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "dev": true, "requires": { - "mime-db": "~1.33.0" + "mime-db": "~1.38.0" } }, "mimic-fn": { @@ -5131,29 +3809,6 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" }, - "mimic-response": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz", - "integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=" - }, - "min-document": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "requires": { - "dom-walk": "^0.1.0" - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -5211,47 +3866,6 @@ "he": "1.1.1", "mkdirp": "0.5.1", "supports-color": "4.4.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "growl": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", - "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==" - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "requires": { - "has-flag": "^2.0.0" - } - } } }, "ms": { @@ -5259,36 +3873,21 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "multimatch": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", - "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", - "requires": { - "array-differ": "^1.0.0", - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "minimatch": "^3.0.0" - } - }, "mute-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true }, "nan": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" }, - "nano-json-stream-parser": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", - "integrity": "sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=" - }, "nanomatch": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", - "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -5296,7 +3895,6 @@ "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", "is-windows": "^1.0.2", "kind-of": "^6.0.2", "object.pick": "^1.3.0", @@ -5305,53 +3903,42 @@ "to-regex": "^3.0.1" } }, - "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true }, "neo-async": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.0.tgz", - "integrity": "sha512-nJmSswG4As/MkRq7QZFuH/sf/yuv8ODdMZrY4Bedjp77a5MK4A6s7YbBB64c9u79EBUOfXUXBvArmvzTD0X+6g==" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "dev": true }, "nice-try": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", - "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==" - }, - "node-dir": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.8.tgz", - "integrity": "sha1-VfuN62mQcHB/tn+RpGDwRIKUx30=" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true }, "nodemon": { - "version": "1.17.3", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.17.3.tgz", - "integrity": "sha512-8AtS+wA5u6qoE12LONjqOzUzxAI5ObzSw6U5LgqpaO/0y6wwId4l5dN0ZulYyYdpLZD1MbkBp7GjG1hqaoRqYg==", + "version": "1.18.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.18.10.tgz", + "integrity": "sha512-we51yBb1TfEvZamFchRgcfLbVYgg0xlGbyXmOtbBzDwxwgewYS/YbZ5tnlnsH51+AoSTTsT3A2E/FloUbtH8cQ==", "dev": true, "requires": { - "chokidar": "^2.0.2", + "chokidar": "^2.1.0", "debug": "^3.1.0", "ignore-by-default": "^1.0.1", "minimatch": "^3.0.4", - "pstree.remy": "^1.1.0", + "pstree.remy": "^1.1.6", "semver": "^5.5.0", "supports-color": "^5.2.0", "touch": "^3.1.0", "undefsafe": "^2.0.2", - "update-notifier": "^2.3.0" + "update-notifier": "^2.5.0" }, "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -5359,9 +3946,9 @@ "dev": true }, "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -5369,37 +3956,6 @@ } } }, - "nomnom": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", - "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", - "requires": { - "chalk": "~0.4.0", - "underscore": "~1.6.0" - }, - "dependencies": { - "ansi-styles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", - "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=" - }, - "chalk": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", - "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", - "requires": { - "ansi-styles": "~1.0.0", - "has-color": "~0.1.0", - "strip-ansi": "~0.1.0" - } - }, - "strip-ansi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", - "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=" - } - } - }, "nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", @@ -5410,40 +3966,22 @@ } }, "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, "requires": { "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", + "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "normalize-url": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", - "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", - "requires": { - "prepend-http": "^2.0.0", - "query-string": "^5.0.1", - "sort-keys": "^2.0.0" - }, - "dependencies": { - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" - } - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, "npm-run-path": { "version": "2.0.2", @@ -5458,24 +3996,17 @@ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, - "number-to-bn": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", - "integrity": "sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA=", - "requires": { - "bn.js": "4.11.6", - "strip-hex-prefix": "1.0.0" - } - }, "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true }, "object-copy": { "version": "0.1.0", @@ -5508,6 +4039,12 @@ } } }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -5517,13 +4054,28 @@ "isobject": "^3.0.0" } }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "dev": true, "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" } }, "object.pick": { @@ -5535,14 +4087,6 @@ "isobject": "^3.0.1" } }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5555,14 +4099,15 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, "requires": { "mimic-fn": "^1.0.0" } }, "openzeppelin-solidity": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/openzeppelin-solidity/-/openzeppelin-solidity-1.10.0.tgz", - "integrity": "sha512-igkrumQQ2lrN2zjeQV4Dnb0GpTBj1fzMcd8HPyBUqwI0hhuscX/HzXiqKT6gFQl1j9Wy/ppVVs9fqL/foF7Gmg==" + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/openzeppelin-solidity/-/openzeppelin-solidity-1.12.0.tgz", + "integrity": "sha512-WlorzMXIIurugiSdw121RVD5qA3EfSI7GybTn+/Du0mPNgairjt29NpVTAaH8eLjAeAwlw46y7uQKy0NYem/gA==" }, "optimist": { "version": "0.6.1", @@ -5596,77 +4141,16 @@ "wordwrap": "~1.0.0" } }, - "ora": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz", - "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", - "requires": { - "chalk": "^1.1.1", - "cli-cursor": "^1.0.2", - "cli-spinners": "^0.1.2", - "object-assign": "^4.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "requires": { - "restore-cursor": "^1.0.1" - } - }, - "onetime": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=" - }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, "original-require": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/original-require/-/original-require-1.0.1.tgz", "integrity": "sha1-DxMEcVhM0zURxew4yNWSE/msXiA=" }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, "os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, "requires": { "lcid": "^1.0.0" } @@ -5674,40 +4158,18 @@ "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "p-cancelable": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.0.tgz", - "integrity": "sha512-/AodqPe1y/GYbhSlnMjxukLGQfQIgsmjSy2CXCNB96kg4ozKvmlovuHEKICToOO/yS3LLWgrWI1dFtFfrePS1g==" - }, - "p-each-series": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", - "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", - "requires": { - "p-reduce": "^1.0.0" - } + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" }, - "p-is-promise": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", - "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=" - }, - "p-lazy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-lazy/-/p-lazy-1.0.0.tgz", - "integrity": "sha1-7FPIAvLuOsKPFmzILQsrAt4nqDU=" - }, "p-limit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "requires": { "p-try": "^1.0.0" } @@ -5720,24 +4182,6 @@ "p-limit": "^1.1.0" } }, - "p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==" - }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=" - }, - "p-timeout": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", - "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", - "requires": { - "p-finally": "^1.0.0" - } - }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", @@ -5755,65 +4199,30 @@ "semver": "^5.1.0" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-cache-control": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104=", "dev": true }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, - "parse-headers": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.1.tgz", - "integrity": "sha1-aug6eqJanZtwCswoaYzR8e1+lTY=", - "requires": { - "for-each": "^0.3.2", - "trim": "0.0.1" - } - }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, "requires": { "error-ex": "^1.2.0" } }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" - }, - "parseurl": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" - }, "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", @@ -5830,6 +4239,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, "requires": { "pinkie-promise": "^2.0.0" } @@ -5851,19 +4261,16 @@ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true }, "path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, "requires": { "graceful-fs": "^4.1.2", "pify": "^2.0.0", @@ -5876,15 +4283,6 @@ "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", "dev": true }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "dev": true, - "requires": { - "through": "~2.3" - } - }, "pegjs": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.10.0.tgz", @@ -5894,26 +4292,50 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, "requires": { "pinkie": "^2.0.0" } }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + } + } + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -5929,68 +4351,43 @@ "prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" - }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true }, "prettier": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.11.1.tgz", - "integrity": "sha512-T/KD65Ot0PB97xTrG8afQ46x3oiVhnfGjGESSI9NWYcG92+OUPZKkwHqGWXH2t9jK1crnQjubECW0FuOth+hxw==" - }, - "pretty-bytes": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz", - "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=" - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.17.1.tgz", + "integrity": "sha512-TzGRNvuUSmPgwivDqkZ9tM/qTGW9hqDKWOE9YHiyQdixlKbv7kvEqsmDPrcHJTKwthU774TQwZXVtaQ/mMsvjg==", + "dev": true }, - "process": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", - "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, - "promise": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.2.tgz", - "integrity": "sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw==", - "dev": true, - "requires": { - "asap": "~2.0.6" - } + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true }, - "proxy-addr": { + "progress": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", - "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.6.0" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true }, - "ps-tree": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.0.tgz", - "integrity": "sha1-tCGyQUDWID8e08dplrRCewjowBQ=", + "promise": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.3.tgz", + "integrity": "sha512-HeRDUL1RJiLhyA0/grn+PTShlBAcLuh/1BJGtrvjwbvRDCTLLMEz9rOGCV+R3vHY4MixIuoMEd9Yq/XvsTPcjw==", "dev": true, "requires": { - "event-stream": "~3.3.0" + "asap": "~2.0.6" } }, "pseudomap": { @@ -5998,105 +4395,37 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, + "psl": { + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", + "dev": true + }, "pstree.remy": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.0.tgz", - "integrity": "sha512-q5I5vLRMVtdWa8n/3UEzZX7Lfghzrg9eG2IKk2ENLSofKRCXVqMvMUHxCKgXNaqH/8ebhBxrqftHWnyTFweJ5Q==", - "dev": true, - "requires": { - "ps-tree": "^1.1.0" - } + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.6.tgz", + "integrity": "sha512-NdF35+QsqD7EgNEI5mkI/X+UwaxVEbQaz9f4IooEmMUv6ZPmlTQYGjBPJGgrlzNdjSvIy4MWMg6Q6vCgBO2K+w==", + "dev": true }, "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true }, "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" - }, - "query-string": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", - "requires": { - "decode-uri-component": "^0.2.0", - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, - "randomatic": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", - "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "randomhex": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/randomhex/-/randomhex-0.1.5.tgz", - "integrity": "sha1-us7vmCMpCRQA8qKRLGzQLxCU9YU=" - }, - "range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" - }, - "raw-body": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", - "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", - "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.2", - "iconv-lite": "0.4.19", - "unpipe": "1.0.0" - }, - "dependencies": { - "depd": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" - }, - "http-errors": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", - "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", - "requires": { - "depd": "1.1.1", - "inherits": "2.0.3", - "setprototypeof": "1.0.3", - "statuses": ">= 1.3.1 < 2" - } - }, - "setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" - } - } + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true }, "rc": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.6.tgz", - "integrity": "sha1-6xiYnG1PTxYsOZ953dKfODVWgJI=", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "requires": { - "deep-extend": "~0.4.0", + "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" @@ -6110,26 +4439,11 @@ } } }, - "read-chunk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz", - "integrity": "sha1-agTAkoAF7Z1C4aasVgDhnLx/9lU=", - "requires": { - "pify": "^3.0.0", - "safe-buffer": "^5.1.1" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - } - } - }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, "requires": { "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", @@ -6140,91 +4454,47 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" } }, "readable-stream": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz", - "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", + "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "readdirp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", - "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "minimatch": "^3.0.2", - "readable-stream": "^2.0.2", - "set-immediate-shim": "^1.0.1" - } - }, - "recast": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.14.7.tgz", - "integrity": "sha512-/nwm9pkrcWagN40JeJhkPaRxiHXBRkXyRh/hgU088Z/v+qCy+zIHHY6bC6o7NaKAxPqtE6nD8zBH1LfU0/Wx6A==", - "requires": { - "ast-types": "0.11.3", - "esprima": "~4.0.0", - "private": "~0.1.5", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" } }, "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, "requires": { "resolve": "^1.1.6" } }, - "regenerate": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", - "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==" - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "regenerator-transform": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", - "requires": { - "babel-runtime": "^6.18.0", - "babel-types": "^6.19.0", - "private": "^0.1.6" - } - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "requires": { - "is-equal-shallow": "^0.1.3" - } - }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -6235,20 +4505,16 @@ "safe-regex": "^1.1.0" } }, - "regexpu-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", - "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", - "requires": { - "regenerate": "^1.2.1", - "regjsgen": "^0.2.0", - "regjsparser": "^0.1.4" - } + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true }, "registry-auth-token": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", - "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", + "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", "dev": true, "requires": { "rc": "^1.1.6", @@ -6264,120 +4530,88 @@ "rc": "^1.0.1" } }, - "regjsgen": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" - }, - "regjsparser": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", - "requires": { - "jsesc": "~0.5.0" - } - }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true }, "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "requires": { - "is-finite": "^1.0.0" - } - }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=" + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true }, "req-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-1.0.1.tgz", - "integrity": "sha1-DXOurpJm5penj3l2AZZ352rPD/8=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", + "integrity": "sha1-1AgrTURZgDZkD7c93qAe1T20nrw=", "dev": true, "requires": { - "req-from": "^1.0.1" + "req-from": "^2.0.0" } }, "req-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/req-from/-/req-from-1.0.1.tgz", - "integrity": "sha1-v4HaUUeUfTLRO5R9wSpYrUWHNQ4=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha1-10GI5H+TeW9Kpx327jWuaJ8+DnA=", "dev": true, "requires": { - "resolve-from": "^2.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", - "dev": true - } + "resolve-from": "^3.0.0" } }, "request": { - "version": "2.85.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", - "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, "requires": { "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", + "aws4": "^1.8.0", "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "hawk": "~6.0.2", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "stringstream": "~0.0.5", - "tough-cookie": "~2.3.3", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" + "uuid": "^3.3.2" } }, "request-promise-core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", - "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", "dev": true, "requires": { - "lodash": "^4.13.1" + "lodash": "^4.17.11" } }, "request-promise-native": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", - "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", + "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", "dev": true, "requires": { - "request-promise-core": "1.1.1", - "stealthy-require": "^1.1.0", - "tough-cookie": ">=2.3.3" + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" } }, "require-directory": { @@ -6386,9 +4620,9 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-from-string": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", - "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, "require-main-filename": { "version": "1.0.1", @@ -6396,34 +4630,19 @@ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, "resolve": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz", - "integrity": "sha512-mw7JQNu5ExIkcw4LPih0owX/TZXjD/ZUF/ZQ/pDnkw3ZKhDcZZw5klmBlj6gVMwjQ3Pz5Jgu7F3d0jcDVuEWdw==", - "requires": { - "path-parse": "^1.0.5" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "dev": true, "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" + "path-parse": "^1.0.6" } }, "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true }, "resolve-url": { "version": "0.2.1", @@ -6431,18 +4650,11 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "requires": { - "lowercase-keys": "^1.0.0" - } - }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, "requires": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" @@ -6454,57 +4666,51 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "dev": true, - "optional": true, - "requires": { - "align-text": "^0.1.1" - } - }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } } }, "run-async": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, "requires": { "is-promise": "^2.1.0" } }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", - "requires": { - "rx-lite": "*" - } - }, "rxjs": { - "version": "5.5.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.7.tgz", - "integrity": "sha512-Hxo2ac8gRQjwjtKgukMIwBRbq5+KAeEV5hXM4obYBOAghev41bDQWgFH4svYiU9UnQ5kNww2LgfyBdevCd2HXA==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "dev": true, "requires": { - "symbol-observable": "1.0.1" + "tslib": "^1.9.0" } }, "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -6515,15 +4721,16 @@ "ret": "~0.1.10" } }, - "scoped-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/scoped-regex/-/scoped-regex-1.0.0.tgz", - "integrity": "sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=" + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" }, "semver-diff": { "version": "2.1.0", @@ -6534,75 +4741,11 @@ "semver": "^5.0.3" } }, - "send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" - } - } - }, - "serve-static": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", - "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.16.2" - } - }, - "servify": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", - "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", - "requires": { - "body-parser": "^1.16.0", - "cors": "^2.8.1", - "express": "^4.14.0", - "request": "^2.79.0", - "xhr": "^2.3.3" - } - }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true - }, "set-value": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", @@ -6626,11 +4769,6 @@ } } }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, "sha1": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", @@ -6642,11 +4780,12 @@ } }, "sha3": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/sha3/-/sha3-1.2.0.tgz", - "integrity": "sha1-aYnxtwpJhwWHajc+LGKs6WqpOZo=", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-1.2.2.tgz", + "integrity": "sha1-pmxQmN5MJbyIM27ItIF9AFvKe6k=", + "dev": true, "requires": { - "nan": "^2.0.5" + "nan": "2.10.0" } }, "shebang-command": { @@ -6663,56 +4802,40 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, "shelljs": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.1.tgz", - "integrity": "sha512-YA/iYtZpzFe5HyWVGrb02FjPxc4EMCfpoU/Phg9fQoyMC72u9598OUBrsU8IrtwAKG0tO8IYaqbaLIw+k3IRGA==", + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true, "requires": { "glob": "^7.0.0", "interpret": "^1.0.0", "rechoir": "^0.6.2" } }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, - "simple-concat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", - "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" - }, - "simple-get": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.7.0.tgz", - "integrity": "sha512-RkE9rGPHcxYZ/baYmgJtOSM63vH0Vyq+ma5TijBcLla41SWlh8t6XYIGMR/oeZcmr+/G8k+zrClkkVrtnQ0esg==", + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, "requires": { - "decompress-response": "^3.3.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } } }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" - }, - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=" - }, - "slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" - }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -6729,6 +4852,15 @@ "use": "^3.1.0" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", @@ -6820,14 +4952,6 @@ } } }, - "sntp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", - "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", - "requires": { - "hoek": "4.x.x" - } - }, "sol-explore": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/sol-explore/-/sol-explore-1.6.2.tgz", @@ -6835,241 +4959,152 @@ "dev": true }, "solc": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.24.tgz", - "integrity": "sha512-2xd7Cf1HeVwrIb6Bu1cwY2/TaLRodrppCq3l7rhLimFQgmxptXhTC3+/wesVLpB09F1A2kZgvbMOgH7wvhFnBQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.5.0.tgz", + "integrity": "sha512-mdLHDl9WeYrN+FIKcMc9PlPfnA9DG9ur5QpCDKcv6VC4RINAsTF4EMuXMZMKoQTvZhtLyJIVH/BZ+KU830Z8Xg==", "requires": { "fs-extra": "^0.30.0", + "keccak": "^1.0.2", "memorystream": "^0.3.1", - "require-from-string": "^1.1.0", - "semver": "^5.3.0", - "yargs": "^4.7.1" - } - }, - "solidity-coverage": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.4.15.tgz", - "integrity": "sha512-iA3MT20rh1LllcNwfxAKU3ZBDu8R/4K8jANJAk7BcJU1foOjEh3tYhGqL8w2kRJPIo5XtoW0wxyVt95X2eJk/A==", - "dev": true, - "requires": { - "death": "^1.1.0", - "ethereumjs-testrpc-sc": "6.1.2", - "istanbul": "^0.4.5", - "keccakjs": "^0.2.1", - "req-cwd": "^1.0.1", - "shelljs": "^0.7.4", - "sol-explore": "^1.6.2", - "solidity-parser-sc": "0.4.7", - "web3": "^0.18.4" + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "yargs": "^11.0.0" }, "dependencies": { - "bignumber.js": { - "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", - "from": "bignumber.js@git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", - "dev": true - }, - "commander": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", - "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", - "dev": true + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "dev": true, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "requires": { - "ms": "0.7.1" + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" } }, - "diff": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", - "dev": true + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } }, - "escape-string-regexp": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", - "dev": true + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, - "minimatch": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", - "dev": true, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" } }, - "mocha": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", - "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", - "dev": true, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "requires": { - "commander": "2.3.0", - "debug": "2.2.0", - "diff": "1.4.0", - "escape-string-regexp": "1.0.2", - "glob": "3.2.11", - "growl": "1.9.2", - "jade": "0.26.3", - "mkdirp": "0.5.1", - "supports-color": "1.2.0", - "to-iso-string": "0.0.2" - }, - "dependencies": { - "glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", - "dev": true, - "requires": { - "inherits": "2", - "minimatch": "0.3" - } - } + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", - "dev": true - }, - "shelljs": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", - "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", - "dev": true, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" + "ansi-regex": "^3.0.0" } }, - "solidity-parser-sc": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/solidity-parser-sc/-/solidity-parser-sc-0.4.7.tgz", - "integrity": "sha512-wbX2806sm6thZME1aniqLcLH9HYwNwuKke6aw/FEgupCvoT9Iq5PdwuN9OyHWKGBOVeczpM5tCrnRXWNQ04YVw==", - "dev": true, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "yargs": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", + "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "requires": { - "mocha": "^2.4.5", - "pegjs": "^0.10.0", - "yargs": "^4.6.0" + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" } }, - "supports-color": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", - "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", - "dev": true - }, - "web3": { - "version": "0.18.4", - "resolved": "https://registry.npmjs.org/web3/-/web3-0.18.4.tgz", - "integrity": "sha1-gewXhBRUkfLqqJVbMcBgSeB8Xn0=", - "dev": true, + "yargs-parser": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "requires": { - "bignumber.js": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", - "crypto-js": "^3.1.4", - "utf8": "^2.1.1", - "xhr2": "*", - "xmlhttprequest": "*" + "camelcase": "^4.1.0" } } } }, - "solidity-parser": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/solidity-parser/-/solidity-parser-0.4.0.tgz", - "integrity": "sha1-o0PxPac8kWgyeQNGgOgMSR3jQPo=", + "solidity-coverage": { + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.5.11.tgz", + "integrity": "sha512-qikdsSi6+9XbfvwA0aI7HUVpF9fIFNqRWTw23M89GMDY+b6Gj0wWU9IngJS0fimoZIAdEp3bfChxvpfVcrUesg==", "dev": true, "requires": { - "mocha": "^2.4.5", - "pegjs": "^0.10.0", - "yargs": "^4.6.0" + "death": "^1.1.0", + "ethereumjs-testrpc-sc": "6.1.6", + "istanbul": "^0.4.5", + "keccakjs": "^0.2.1", + "req-cwd": "^1.0.1", + "shelljs": "^0.7.4", + "sol-explore": "^1.6.2", + "solidity-parser-sc": "0.4.11", + "tree-kill": "^1.2.0", + "web3": "^0.18.4" }, "dependencies": { - "commander": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", - "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", - "dev": true - }, - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "dev": true, - "requires": { - "ms": "0.7.1" - } - }, - "diff": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", - "dev": true - }, - "glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", - "dev": true, - "requires": { - "inherits": "2", - "minimatch": "0.3" - } - }, - "minimatch": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "req-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-1.0.1.tgz", + "integrity": "sha1-DXOurpJm5penj3l2AZZ352rPD/8=", "dev": true, "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" + "req-from": "^1.0.1" } }, - "mocha": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", - "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", + "req-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-1.0.1.tgz", + "integrity": "sha1-v4HaUUeUfTLRO5R9wSpYrUWHNQ4=", "dev": true, "requires": { - "commander": "2.3.0", - "debug": "2.2.0", - "diff": "1.4.0", - "escape-string-regexp": "1.0.2", - "glob": "3.2.11", - "growl": "1.9.2", - "jade": "0.26.3", - "mkdirp": "0.5.1", - "supports-color": "1.2.0", - "to-iso-string": "0.0.2" + "resolve-from": "^2.0.0" } }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", - "dev": true - }, - "supports-color": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", - "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", "dev": true } } @@ -7080,26 +5115,30 @@ "integrity": "sha512-EzRI8/TR/ljTXkZAyAjb0w4G20wH2XM7pcNf87ifdV825AbUv7DkY7HmiZCTj6NeKtIx8Y1s0NZWPbj+JTp8Zw==", "dev": true }, - "sort-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", - "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "solidity-parser-sc": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/solidity-parser-sc/-/solidity-parser-sc-0.4.11.tgz", + "integrity": "sha512-1kV5iC7m3CtMDfmHaVNwz2saSGQVIuF16rIxU417Al38MVCWHMQQ5vT6cmLsNwDe60S74auobWij9vNawSeOyw==", + "dev": true, "requires": { - "is-plain-obj": "^1.0.0" + "mocha": "^4.1.0", + "pegjs": "^0.10.0", + "yargs": "^4.6.0" } }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true }, "source-map-resolve": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", - "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "dev": true, "requires": { - "atob": "^2.0.0", + "atob": "^2.1.1", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", @@ -7107,17 +5146,20 @@ } }, "source-map-support": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.4.tgz", - "integrity": "sha512-PETSPG6BjY1AHs2t64vS2aqAgu6dMIMXJULWFBGbh2Gr8nVLbCFDo6i/RMMvviIQ2h1Z8+5gQhVKSn2je9nmdg==", + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.11.tgz", + "integrity": "sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ==", + "dev": true, "requires": { + "buffer-from": "^1.0.0", "source-map": "^0.6.0" }, "dependencies": { "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true } } }, @@ -7128,32 +5170,37 @@ "dev": true }, "spdx-correct": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, "requires": { - "spdx-license-ids": "^1.0.2" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, - "spdx-expression-parse": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", - "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=" - }, - "spdx-license-ids": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", - "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=" + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true }, - "split": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { - "through": "2" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, + "spdx-license-ids": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", + "dev": true + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -7170,9 +5217,10 @@ "dev": true }, "sshpk": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", - "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -7181,6 +5229,7 @@ "ecc-jsbn": "~0.1.1", "getpass": "^0.1.1", "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" } }, @@ -7205,44 +5254,12 @@ } } }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", "dev": true }, - "stream-combiner": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", - "dev": true, - "requires": { - "duplexer": "~0.1.1" - } - }, - "stream-to-observable": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/stream-to-observable/-/stream-to-observable-0.2.0.tgz", - "integrity": "sha1-WdbqOT2HwsDdrBCqDVYbxrpvDhA=", - "requires": { - "any-observable": "^0.2.0" - } - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" - }, - "string-template": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=" - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -7254,18 +5271,14 @@ } }, "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, "requires": { "safe-buffer": "~5.1.0" } }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -7278,32 +5291,16 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, "requires": { "is-utf8": "^0.2.0" } }, - "strip-bom-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz", - "integrity": "sha1-+H217yYT9paKpUWr/h7HKLaoKco=", - "requires": { - "first-chunk-stream": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, - "strip-hex-prefix": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", - "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", - "requires": { - "is-hex-prefixed": "1.0.0" - } - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -7311,23 +5308,17 @@ "dev": true }, "supports-color": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", - "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", - "dev": true, + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", "requires": { - "has-flag": "^1.0.0" + "has-flag": "^2.0.0" } }, - "symbol-observable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", - "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=" - }, "sync-request": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.0.0.tgz", - "integrity": "sha512-jGNIAlCi9iU4X3Dm4oQnNQshDD3h0/1A7r79LyqjbjUnj69sX6mShAXlhRXgImsfVKtTcnra1jfzabdZvp+Lmw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", "dev": true, "requires": { "http-response-object": "^3.0.1", @@ -7344,24 +5335,49 @@ "get-port": "^3.1.0" } }, - "tapable": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.0.0.tgz", - "integrity": "sha512-dQRhbNQkRnaqauC7WqSJ21EEksgT0fYZX2lqXzGkpo8JNig9zGZTYoMGvyI2nWmXlE2VSVXVDu7wLVGu/mQEsg==" - }, - "temp": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", - "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", + "table": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/table/-/table-5.3.3.tgz", + "integrity": "sha512-3wUNCgdWX6PNpOe3amTTPWPuF6VGvgzjKCaO1snFj0z7Y3mUPWf5+zDtxUVGispJkDECPmR29wbzh6bVMOHbcw==", + "dev": true, "requires": { - "os-tmpdir": "^1.0.0", - "rimraf": "~2.2.6" + "ajv": "^6.9.1", + "lodash": "^4.17.11", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" }, "dependencies": { - "rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=" + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } } } }, @@ -7377,17 +5393,13 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" - }, - "textextensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.2.0.tgz", - "integrity": "sha512-j5EMxnryTvKxwH2Cq+Pb43tsf6sdEgw6Pdwxk83mPaq0ToeFJt6WE4J3s5BqY7vmjlLgkgXvhtXUxo80FyBhCA==" + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true }, "then-request": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.0.tgz", - "integrity": "sha512-xA+7uEMc+jsQIoyySJ93Ad08Kuqnik7u6jLS5hR91Z3smAoCfL3M8/MqMlobAa9gzBfO9pA88A/AntfepkkMJQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", "dev": true, "requires": { "@types/concat-stream": "^1.6.0", @@ -7397,16 +5409,16 @@ "caseless": "~0.12.0", "concat-stream": "^1.6.0", "form-data": "^2.2.0", - "http-basic": "^7.0.0", + "http-basic": "^8.1.1", "http-response-object": "^3.0.1", "promise": "^8.0.0", "qs": "^6.4.0" }, "dependencies": { "@types/node": { - "version": "8.10.36", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.36.tgz", - "integrity": "sha512-SL6KhfM7PTqiFmbCW3eVNwVBZ+88Mrzbuvn9olPsfv43mbiWaFY+nRcz/TGGku0/lc2FepdMbImdMY1JrQ+zbw==", + "version": "8.10.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.45.tgz", + "integrity": "sha512-tGVTbA+i3qfXsLbq9rEq/hezaHY55QxQLeXQL2ejNgFAxxrgu8eMmYIOsRcl7hN1uTLVsKOOYacV/rcJM3sfgQ==", "dev": true } } @@ -7414,41 +5426,24 @@ "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true }, "timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, "requires": { "os-tmpdir": "~1.0.2" } }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" - }, - "to-iso-string": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", - "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", - "dev": true - }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -7501,140 +5496,50 @@ } }, "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, "requires": { + "psl": "^1.1.24", "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } } }, - "trim": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", - "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=" - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" + "tree-kill": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", + "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", + "dev": true }, "truffle": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/truffle/-/truffle-4.1.11.tgz", - "integrity": "sha512-VNhc6jexZeM92sNJJr4U8ln3uJ/mJEQO/0y9ZLYc4pccyIskPtl+3r4mzymgGM/Mq5v6MpoQVD6NZgHUVKX+Dw==", + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/truffle/-/truffle-5.0.15.tgz", + "integrity": "sha512-/FAabG/+xv4mADQvm4YXTMWThXrc9Z4MsMCqWixrd6DlQMPBQIV5F86DeYHgkKbp8hRM3oGUdBVfpWRaha6YKg==", "requires": { + "app-module-path": "^2.2.0", "mocha": "^4.1.0", - "original-require": "^1.0.1", - "solc": "0.4.24" + "original-require": "1.0.1", + "solc": "0.5.0" } }, - "truffle-blockchain-utils": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/truffle-blockchain-utils/-/truffle-blockchain-utils-0.0.4.tgz", - "integrity": "sha512-wgRrhwqh0aea08Hz28hUV4tuF2uTVQH/e9kBou+WK04cqrutB5cxQVQ6HGjeZLltxBYOFvhrGOOq4l3WJFnPEA==", - "dev": true - }, - "truffle-config": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/truffle-config/-/truffle-config-1.0.4.tgz", - "integrity": "sha512-E8pvJNAIjs7LNsjkYeS2dgoOnLoSBrTwb1xF5lJwfvZmGMFpKvVL1sa5jpFxozpf/WkRn/rfxy8zTdb3pq16jA==", - "dev": true, - "requires": { - "find-up": "^2.1.0", - "lodash": "^4.17.4", - "original-require": "^1.0.0", - "truffle-error": "^0.0.2", - "truffle-provider": "^0.0.4" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - } - } - }, - "truffle-contract": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/truffle-contract/-/truffle-contract-3.0.4.tgz", - "integrity": "sha512-/1LCtJFf5Jvm5Rv88T0d/rZSKvaiW/yO1SHXLGJgKzLsiG1F/2spFs4HrI1mRxP00opfrYXloEmLtkVV/kcndQ==", - "dev": true, - "requires": { - "ethjs-abi": "0.1.8", - "truffle-blockchain-utils": "^0.0.4", - "truffle-contract-schema": "^2.0.0", - "truffle-error": "0.0.2", - "web3": "^0.20.1" - }, - "dependencies": { - "ethjs-abi": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.1.8.tgz", - "integrity": "sha1-zSiFg+1ijN+tr4re+juh28vKbBg=", - "dev": true, - "requires": { - "bn.js": "4.11.6", - "js-sha3": "0.5.5", - "number-to-bn": "1.7.0" - } - } - } - }, - "truffle-contract-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/truffle-contract-schema/-/truffle-contract-schema-2.0.0.tgz", - "integrity": "sha512-nLlspmu1GKDaluWksBwitHi/7Z3IpRjmBYeO9N+T1nVJD2V4IWJaptCKP1NqnPiJA+FChB7+F7pI6Br51/FtXQ==", - "dev": true, - "requires": { - "ajv": "^5.1.1", - "crypto-js": "^3.1.9-1", - "debug": "^3.1.0" - }, - "dependencies": { - "crypto-js": { - "version": "3.1.9-1", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz", - "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg=", - "dev": true - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "truffle-error": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/truffle-error/-/truffle-error-0.0.2.tgz", - "integrity": "sha1-AbGJt4UFVmrhaJwjnHyi3RIc/kw=", - "dev": true - }, - "truffle-expect": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/truffle-expect/-/truffle-expect-0.0.3.tgz", - "integrity": "sha1-m3XO80O9WW5+XbyHj18bLjGKlEw=", - "dev": true - }, "truffle-flattener": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/truffle-flattener/-/truffle-flattener-1.2.3.tgz", - "integrity": "sha512-DisthKMI1qH+Xbw/S84CLPGeXz/kMkVUxBpz8Elj2kI4paVjEFEFwrq0juQHwxr2w/046r2tUT5usCE38Bw6Qw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/truffle-flattener/-/truffle-flattener-1.3.0.tgz", + "integrity": "sha512-ppJ9xI0tDuvCYjQlcWwMBcOKZph5U4YpG/gChyUVDxOjUIniG5g7y9vZho2PRj1FohPPnOjg1KOAVNlk/bPZrw==", "dev": true, "requires": { + "@resolver-engine/imports-fs": "^0.2.2", "find-up": "^2.1.0", - "semver": "^5.4.1", - "solidity-parser": "^0.4.0", - "truffle-config": "^1.0.2", - "truffle-resolver": "^4.0.1", + "mkdirp": "^0.5.1", + "solidity-parser-antlr": "^0.4.0", "tsort": "0.0.1" }, "dependencies": { @@ -7646,37 +5551,21 @@ "requires": { "locate-path": "^2.0.0" } + }, + "solidity-parser-antlr": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/solidity-parser-antlr/-/solidity-parser-antlr-0.4.2.tgz", + "integrity": "sha512-0OKT2YKZAqPe14HN7Nbo24hjmnyUYh92UjyZG0Zz2rpQhl/w8asX8qHb+ASSXfayQaiW8g9zGIupXEE355tOQQ==", + "dev": true } } }, - "truffle-provider": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/truffle-provider/-/truffle-provider-0.0.4.tgz", - "integrity": "sha512-yVxxjocxnJcFspQ0T4Rjq/1wvvm3iLxidb6oa1EAX5LsnSQLPG8wAM5+JLlJ4FDBsqJdZLGOq1RR5Ln/w7x5JA==", - "dev": true, - "requires": { - "truffle-error": "^0.0.2", - "web3": "^0.20.1" - } - }, - "truffle-provisioner": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/truffle-provisioner/-/truffle-provisioner-0.1.0.tgz", - "integrity": "sha1-Ap5SScEBUwBzhTXgT97ZMaU8T2I=", + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", "dev": true }, - "truffle-resolver": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/truffle-resolver/-/truffle-resolver-4.0.2.tgz", - "integrity": "sha512-HKRd45HSfAqb9/BCOgYq4zkyl2lF40MvPDIGhyoPXFj5/9PSFzclyTkkMOdb+Rnm7oC1vY4cE1/k453lgf81Kw==", - "dev": true, - "requires": { - "async": "^2.1.4", - "truffle-contract": "^3.0.4", - "truffle-expect": "0.0.3", - "truffle-provisioner": "^0.1.0" - } - }, "tsort": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", @@ -7687,6 +5576,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, "requires": { "safe-buffer": "^5.0.1" } @@ -7695,7 +5585,7 @@ "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true + "dev": true }, "type-check": { "version": "0.3.2", @@ -7712,15 +5602,6 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, - "type-is": { - "version": "1.6.16", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.18" - } - }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -7728,77 +5609,32 @@ "dev": true }, "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "version": "3.5.11", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.11.tgz", + "integrity": "sha512-izPJg8RsSyqxbdnqX36ExpbH3K7tDBsAU/VfNv89VkMFy3z39zFjunQGsSHOlGlyIfGLGprGeosgQno3bo2/Kg==", "dev": true, "optional": true, "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" + "commander": "~2.20.0", + "source-map": "~0.6.1" }, "dependencies": { - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true, - "optional": true - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dev": true, - "optional": true, - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true, "optional": true }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dev": true, - "optional": true, - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } } } }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "dev": true, - "optional": true - }, - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" - }, "undefsafe": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", @@ -7806,13 +5642,19 @@ "dev": true, "requires": { "debug": "^2.2.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } } }, - "underscore": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", - "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" - }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", @@ -7857,11 +5699,6 @@ "crypto-random-string": "^1.0.0" } }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -7869,575 +5706,155 @@ "dev": true, "requires": { "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "untildify": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.2.tgz", - "integrity": "sha1-fx8wIFWz/qDz6B3HjrNnZstl4/E=" - }, - "unzip-response": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", - "dev": true - }, - "upath": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.5.tgz", - "integrity": "sha512-qbKn90aDQ0YEwvXoLqj0oiuUYroLX2lVHZ+b+xwjozFasAOC4GneDq5+OaIG5Zj+jFmbz/uO+f7a9qxjktJQww==", - "dev": true - }, - "update-notifier": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", - "dev": true, - "requires": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "requires": { - "prepend-http": "^1.0.1" - } - }, - "url-set-query": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", - "integrity": "sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk=" - }, - "url-to-options": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", - "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" - }, - "use": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", - "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } - }, - "utf8": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", - "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" - }, - "v8-compile-cache": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz", - "integrity": "sha512-ejdrifsIydN1XDH7EuR2hn8ZrkRKUYF7tUcBjBy/lhrCvs2K+zRlbW9UHc0IQ9RsYFZJFqJrieoIHfkCa0DBRA==" - }, - "validate-npm-package-license": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", - "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", - "requires": { - "spdx-correct": "~1.0.0", - "spdx-expression-parse": "~1.0.0" - } - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - }, - "vinyl-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-2.0.0.tgz", - "integrity": "sha1-p+v1/779obfRjRQPyweyI++2dRo=", - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.3.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0", - "strip-bom-stream": "^2.0.0", - "vinyl": "^1.1.0" - } - }, - "web3": { - "version": "0.20.5", - "resolved": "https://registry.npmjs.org/web3/-/web3-0.20.5.tgz", - "integrity": "sha1-xQSNNfe/TixMKAzlH7u8lRKQsWU=", - "dev": true, - "requires": { - "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", - "crypto-js": "^3.1.4", - "utf8": "^2.1.1", - "xhr2": "*", - "xmlhttprequest": "*" - } - }, - "web3-utils": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.0.0-beta.34.tgz", - "integrity": "sha1-lBH8OarvOcpOBhafdiKX2f8CCXA=", - "requires": { - "bn.js": "4.11.6", - "eth-lib": "0.1.27", - "ethjs-unit": "0.1.6", - "number-to-bn": "1.7.0", - "randomhex": "0.1.5", - "underscore": "1.8.3", - "utf8": "2.1.1" - }, - "dependencies": { - "underscore": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", - "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" - }, - "utf8": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.1.tgz", - "integrity": "sha1-LgHbAvfY0JRPdxBPFgnrDDBM92g=" - } - } - }, - "webpack-addons": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/webpack-addons/-/webpack-addons-1.1.5.tgz", - "integrity": "sha512-MGO0nVniCLFAQz1qv22zM02QPjcpAoJdy7ED0i3Zy7SY1IecgXCm460ib7H/Wq7e9oL5VL6S2BxaObxwIcag0g==", - "requires": { - "jscodeshift": "^0.4.0" - }, - "dependencies": { - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" - }, - "ast-types": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.10.1.tgz", - "integrity": "sha512-UY7+9DPzlJ9VM8eY0b2TUZcZvF+1pO0hzMtAyjBYKhOmnvRlqYNYnWdtsMj0V16CGaMlpL0G1jnLbLo4AyotuQ==" - }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "^1.0.0" - } - }, - "jscodeshift": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.4.1.tgz", - "integrity": "sha512-iOX6If+hsw0q99V3n31t4f5VlD1TQZddH08xbT65ZqA7T4Vkx68emrDZMUOLVvCEAJ6NpAk7DECe3fjC/t52AQ==", - "requires": { - "async": "^1.5.0", - "babel-plugin-transform-flow-strip-types": "^6.8.0", - "babel-preset-es2015": "^6.9.0", - "babel-preset-stage-1": "^6.5.0", - "babel-register": "^6.9.0", - "babylon": "^6.17.3", - "colors": "^1.1.2", - "flow-parser": "^0.*", - "lodash": "^4.13.1", - "micromatch": "^2.3.7", - "node-dir": "0.1.8", - "nomnom": "^1.8.1", - "recast": "^0.12.5", - "temp": "^0.8.1", - "write-file-atomic": "^1.2.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "recast": { - "version": "0.12.9", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.12.9.tgz", - "integrity": "sha512-y7ANxCWmMW8xLOaiopiRDlyjQ9ajKRENBH+2wjntIbk3A6ZR1+BLQttkmSHMY7Arl+AAZFwJ10grg2T6f1WI8A==", - "requires": { - "ast-types": "0.10.1", - "core-js": "^2.4.1", - "esprima": "~4.0.0", - "private": "~0.1.5", - "source-map": "~0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "write-file-atomic": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", - "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" - } - } - } - }, - "webpack-cli": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-2.0.13.tgz", - "integrity": "sha512-0lnOi3yla8FsZVuMsbfnNRB/8DlfuDugKdekC+4ykydZG0+UOidMi5J5LLWN4c0VJ8PqC19yMXXkYyCq78OuqA==", - "requires": { - "chalk": "^2.3.2", - "cross-spawn": "^6.0.5", - "diff": "^3.5.0", - "enhanced-resolve": "^4.0.0", - "glob-all": "^3.1.0", - "global-modules": "^1.0.0", - "got": "^8.2.0", - "inquirer": "^5.1.0", - "interpret": "^1.0.4", - "jscodeshift": "^0.5.0", - "listr": "^0.13.0", - "loader-utils": "^1.1.0", - "lodash": "^4.17.5", - "log-symbols": "^2.2.0", - "mkdirp": "^0.5.1", - "p-each-series": "^1.0.0", - "p-lazy": "^1.0.0", - "prettier": "^1.5.3", - "resolve-cwd": "^2.0.0", - "supports-color": "^5.3.0", - "v8-compile-cache": "^1.1.2", - "webpack-addons": "^1.1.5", - "yargs": "^11.0.0", - "yeoman-environment": "^2.0.0", - "yeoman-generator": "^2.0.3" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - }, - "cliui": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.0.0.tgz", - "integrity": "sha512-nY3W5Gu2racvdDk//ELReY+dHjb9PlIcVDFXP72nVIhq2Gy3LuVXYwJoPVudwQnv1shtohpgkdCKT2YaKY0CKw==", - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "requires": { - "locate-path": "^2.0.0" - } - }, - "got": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/got/-/got-8.3.0.tgz", - "integrity": "sha512-kBNy/S2CGwrYgDSec5KTWGKUvupwkkTVAjIsVFF2shXO13xpZdFP4d4kxa//CLX2tN/rV0aYwK8vY6UKWGn2vQ==", - "requires": { - "@sindresorhus/is": "^0.7.0", - "cacheable-request": "^2.1.1", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "into-stream": "^3.1.0", - "is-retry-allowed": "^1.1.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "mimic-response": "^1.0.0", - "p-cancelable": "^0.4.0", - "p-timeout": "^2.0.1", - "pify": "^3.0.0", - "safe-buffer": "^5.1.1", - "timed-out": "^4.0.1", - "url-parse-lax": "^3.0.0", - "url-to-options": "^1.0.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "supports-color": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "requires": { - "prepend-http": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "yargs": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz", - "integrity": "sha512-Rjp+lMYQOWtgqojx1dEWorjCofi1YN7AoFvYV7b1gx/7dAAeuI4kN5SZiEvr0ZmsZTOpDRcCqrpI10L31tFkBw==", - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - } - }, - "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, "requires": { - "camelcase": "^4.1.0" + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true } } }, + "unzip-response": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "dev": true + }, + "upath": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", + "dev": true + }, + "update-notifier": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", + "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", + "dev": true, + "requires": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "utf8": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.1.tgz", + "integrity": "sha1-LgHbAvfY0JRPdxBPFgnrDDBM92g=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "web3": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/web3/-/web3-0.18.4.tgz", + "integrity": "sha1-gewXhBRUkfLqqJVbMcBgSeB8Xn0=", + "dev": true, + "requires": { + "bignumber.js": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", + "crypto-js": "^3.1.4", + "utf8": "^2.1.1", + "xhr2": "*", + "xmlhttprequest": "*" + } + }, "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "requires": { "isexe": "^2.0.0" } @@ -8445,12 +5862,13 @@ "which-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true }, "widest-line": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.0.tgz", - "integrity": "sha1-AUKk6KJD+IgsAjOqDgKBqnYVInM=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", "dev": true, "requires": { "string-width": "^2.1.1" @@ -8492,7 +5910,8 @@ "window-size": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", - "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=" + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=", + "dev": true }, "wordwrap": { "version": "1.0.0", @@ -8514,10 +5933,19 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "write-file-atomic": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", - "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", + "integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==", "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -8525,55 +5953,12 @@ "signal-exit": "^3.0.2" } }, - "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - }, "xdg-basedir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", "dev": true }, - "xhr": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.4.1.tgz", - "integrity": "sha512-pAIU5vBr9Hiy5cpFIbPnwf0C18ZF86DBsZKrlsf87N5De/JbA6RJ83UP/cv+aljl4S40iRVMqP4pr4sF9Dnj0A==", - "requires": { - "global": "~4.3.0", - "is-function": "^1.0.1", - "parse-headers": "^2.0.0", - "xtend": "^4.0.0" - } - }, - "xhr-request": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", - "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", - "requires": { - "buffer-to-arraybuffer": "^0.0.5", - "object-assign": "^4.1.1", - "query-string": "^5.0.1", - "simple-get": "^2.7.0", - "timed-out": "^4.0.1", - "url-set-query": "^1.0.0", - "xhr": "^2.0.4" - } - }, - "xhr-request-promise": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.2.tgz", - "integrity": "sha1-NDxE0e53JrhkgGloLQ+EDIO0Jh0=", - "requires": { - "xhr-request": "^1.0.1" - } - }, "xhr2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.1.4.tgz", @@ -8586,11 +5971,6 @@ "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=", "dev": true }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" - }, "y18n": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", @@ -8605,6 +5985,7 @@ "version": "4.8.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", + "dev": true, "requires": { "cliui": "^3.2.0", "decamelize": "^1.1.1", @@ -8626,205 +6007,11 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", + "dev": true, "requires": { "camelcase": "^3.0.0", "lodash.assign": "^4.0.6" } - }, - "yeoman-environment": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.0.5.tgz", - "integrity": "sha512-6/W7/B54OPHJXob0n0+pmkwFsirC8cokuQkPSmT/D0lCcSxkKtg/BA6ZnjUBIwjuGqmw3DTrT4en++htaUju5g==", - "requires": { - "chalk": "^2.1.0", - "debug": "^3.1.0", - "diff": "^3.3.1", - "escape-string-regexp": "^1.0.2", - "globby": "^6.1.0", - "grouped-queue": "^0.3.3", - "inquirer": "^3.3.0", - "is-scoped": "^1.0.0", - "lodash": "^4.17.4", - "log-symbols": "^2.1.0", - "mem-fs": "^1.1.0", - "text-table": "^0.2.0", - "untildify": "^3.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" - }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.4", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "yeoman-generator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/yeoman-generator/-/yeoman-generator-2.0.3.tgz", - "integrity": "sha512-mODmrZ26a94djmGZZuIiomSGlN4wULdou29ZwcySupb2e9FdvoCl7Ps2FqHFjEHio3kOl/iBeaNqrnx3C3NwWg==", - "requires": { - "async": "^2.6.0", - "chalk": "^2.3.0", - "cli-table": "^0.3.1", - "cross-spawn": "^5.1.0", - "dargs": "^5.1.0", - "dateformat": "^3.0.2", - "debug": "^3.1.0", - "detect-conflict": "^1.0.0", - "error": "^7.0.2", - "find-up": "^2.1.0", - "github-username": "^4.0.0", - "istextorbinary": "^2.1.0", - "lodash": "^4.17.4", - "make-dir": "^1.1.0", - "mem-fs-editor": "^3.0.2", - "minimist": "^1.2.0", - "pretty-bytes": "^4.0.2", - "read-chunk": "^2.1.0", - "read-pkg-up": "^3.0.0", - "rimraf": "^2.6.2", - "run-async": "^2.0.0", - "shelljs": "^0.8.0", - "text-table": "^0.2.0", - "through2": "^2.0.0", - "yeoman-environment": "^2.0.5" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "requires": { - "locate-path": "^2.0.0" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "requires": { - "pify": "^3.0.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" - } - } } } } diff --git a/package.json b/package.json index 299b5b46e..f8897dfe5 100644 --- a/package.json +++ b/package.json @@ -5,26 +5,34 @@ "main": "index.js", "scripts": { "test": "scripts/test.sh", - "deploy": "truffle migrate --reset --network $NETWORK", - "compile": "truffle compile", + "test:gasreport": "GASREPORT=true npm run test", + "compile": "truffle compile && truffle compile spuriousDragon", "flatten": "bash flatten.sh", + "lint:js": "eslint .", + "lint:js:fix": "eslint . --fix", "watch-tests": "./node_modules/.bin/nodemon ./node_modules/.bin/truffle test --network test" }, "author": "POA network", "license": "GPLv3", "dependencies": { - "ganache-cli": "^6.1.0", + "ganache-cli": "^6.4.3", "openzeppelin-solidity": "^1.10.0", - "truffle": "^4.1.11", - "web3-utils": "^1.0.0-beta.34" + "truffle": "^5.0.15" }, "devDependencies": { - "chai": "^4.1.2", + "chai": "^4.2.0", "chai-as-promised": "^7.1.1", - "chai-bignumber": "^2.0.2", + "chai-bn": "^0.1.1", + "eslint": "^5.16.0", + "eslint-config-airbnb-base": "^13.1.0", + "eslint-config-prettier": "^4.2.0", + "eslint-plugin-import": "^2.17.2", + "eslint-plugin-node": "^9.0.1", + "eslint-plugin-prettier": "^3.0.1", "eth-gas-reporter": "^0.1.12", "nodemon": "^1.17.3", - "solidity-coverage": "^0.4.15", + "prettier": "^1.17.1", + "solidity-coverage": "^0.5.11", "truffle-flattener": "^1.2.3" } } diff --git a/scripts/test.sh b/scripts/test.sh index ee231fc30..7b133245a 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -61,5 +61,5 @@ if [ "$SOLIDITY_COVERAGE" = true ]; then cat coverage/lcov.info | node_modules/.bin/coveralls fi else - node_modules/.bin/truffle test "$@" --network ganache + node_modules/.bin/truffle test "$@" fi diff --git a/test/erc_to_erc/foreign_bridge.test.js b/test/erc_to_erc/foreign_bridge.test.js index a6564e59d..7164bfcda 100644 --- a/test/erc_to_erc/foreign_bridge.test.js +++ b/test/erc_to_erc/foreign_bridge.test.js @@ -1,228 +1,336 @@ -const ForeignBridge = artifacts.require("ForeignBridgeErcToErc.sol"); -const ForeignBridgeV2 = artifacts.require("ForeignBridgeV2.sol"); -const BridgeValidators = artifacts.require("BridgeValidators.sol"); -const EternalStorageProxy = artifacts.require("EternalStorageProxy.sol"); - -const ERC677BridgeToken = artifacts.require("ERC677BridgeToken.sol"); -const {ERROR_MSG, ZERO_ADDRESS, INVALID_ARGUMENTS} = require('../setup'); -const {createMessage, sign, signatureToVRS} = require('../helpers/helpers'); -const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether")); -const requireBlockConfirmations = 8; -const gasPrice = web3.toWei('1', 'gwei') -const oneEther = web3.toBigNumber(web3.toWei(1, "ether")); +const ForeignBridge = artifacts.require('ForeignBridgeErcToErc.sol') +const ForeignBridgeErc677ToErc677 = artifacts.require('ForeignBridgeErc677ToErc677.sol') +const ForeignBridgeV2 = artifacts.require('ForeignBridgeV2.sol') +const BridgeValidators = artifacts.require('BridgeValidators.sol') +const EternalStorageProxy = artifacts.require('EternalStorageProxy.sol') +const ERC677BridgeToken = artifacts.require('ERC677BridgeToken.sol') + +const { expect } = require('chai') +const { ERROR_MSG, ZERO_ADDRESS, toBN } = require('../setup') +const { createMessage, sign, signatureToVRS, ether, getEvents } = require('../helpers/helpers') + +const oneEther = ether('1') +const halfEther = ether('0.5') +const requireBlockConfirmations = 8 +const gasPrice = web3.utils.toWei('1', 'gwei') const homeDailyLimit = oneEther const homeMaxPerTx = halfEther const maxPerTx = halfEther - -contract('ForeignBridge_ERC20_to_ERC20', async (accounts) => { - let validatorContract, authorities, owner, token; +const minPerTx = ether('0.01') +const dailyLimit = oneEther +const ZERO = toBN(0) + +contract('ForeignBridge_ERC20_to_ERC20', async accounts => { + let validatorContract + let authorities + let owner + let token before(async () => { validatorContract = await BridgeValidators.new() - authorities = [accounts[1], accounts[2]]; + authorities = [accounts[1], accounts[2]] owner = accounts[0] await validatorContract.initialize(1, authorities, owner) }) describe('#initialize', async () => { it('should initialize', async () => { - token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - let foreignBridge = await ForeignBridge.new(); - - ZERO_ADDRESS.should.be.equal(await foreignBridge.erc20token()); - ZERO_ADDRESS.should.be.equal(await foreignBridge.validatorContract()) - '0'.should.be.bignumber.equal(await foreignBridge.deployedAtBlock()) - false.should.be.equal(await foreignBridge.isInitialized()) - '0'.should.be.bignumber.equal(await foreignBridge.requiredBlockConfirmations()) - - await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, owner).should.be.rejectedWith(INVALID_ARGUMENTS); - - await foreignBridge.initialize(ZERO_ADDRESS, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(validatorContract.address, ZERO_ADDRESS, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(validatorContract.address, owner, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(validatorContract.address, token.address, 0, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, 0, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(owner, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - - await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner); - - token.address.should.be.equal(await foreignBridge.erc20token()); - true.should.be.equal(await foreignBridge.isInitialized()) - validatorContract.address.should.be.equal(await foreignBridge.validatorContract()); - token.address.should.be.equal(await foreignBridge.erc20token()); - (await foreignBridge.deployedAtBlock()).should.be.bignumber.above(0); - requireBlockConfirmations.should.be.bignumber.equal(await foreignBridge.requiredBlockConfirmations()) - const contractGasPrice = await foreignBridge.gasPrice() - contractGasPrice.should.be.bignumber.equal(gasPrice) + token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + const foreignBridge = await ForeignBridge.new() + + expect(await foreignBridge.erc20token()).to.be.equal(ZERO_ADDRESS) + expect(await foreignBridge.validatorContract()).to.be.equal(ZERO_ADDRESS) + expect(await foreignBridge.deployedAtBlock()).to.be.bignumber.equal(ZERO) + expect(await foreignBridge.isInitialized()).to.be.equal(false) + expect(await foreignBridge.requiredBlockConfirmations()).to.be.bignumber.equal(ZERO) + + await foreignBridge + .initialize( + ZERO_ADDRESS, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + validatorContract.address, + ZERO_ADDRESS, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + validatorContract.address, + owner, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + validatorContract.address, + token.address, + 0, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + validatorContract.address, + token.address, + requireBlockConfirmations, + 0, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + owner, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + + await foreignBridge.initialize( + validatorContract.address, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + + expect(await foreignBridge.erc20token()).to.be.equal(token.address) + expect(await foreignBridge.isInitialized()).to.be.equal(true) + expect(await foreignBridge.validatorContract()).to.be.equal(validatorContract.address) + expect(await foreignBridge.deployedAtBlock()).to.be.bignumber.above(ZERO) + expect(await foreignBridge.requiredBlockConfirmations()).to.be.bignumber.equal( + requireBlockConfirmations.toString() + ) + expect(await foreignBridge.gasPrice()).to.be.bignumber.equal(gasPrice) const bridgeMode = '0xba4690f5' // 4 bytes of keccak256('erc-to-erc-core') - const mode = await foreignBridge.getBridgeMode(); - mode.should.be.equal(bridgeMode) - const [major, minor, patch] = await foreignBridge.getBridgeInterfacesVersion() - major.should.be.bignumber.gte(0) - minor.should.be.bignumber.gte(0) - patch.should.be.bignumber.gte(0) + expect(await foreignBridge.getBridgeMode()).to.be.equal(bridgeMode) + const { major, minor, patch } = await foreignBridge.getBridgeInterfacesVersion() + expect(major).to.be.bignumber.gte(ZERO) + expect(minor).to.be.bignumber.gte(ZERO) + expect(patch).to.be.bignumber.gte(ZERO) }) }) + describe('#executeSignatures', async () => { - var value = web3.toBigNumber(web3.toWei(0.25, "ether")); + const value = ether('0.25') let foreignBridge beforeEach(async () => { foreignBridge = await ForeignBridge.new() - token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner); - await token.mint(foreignBridge.address,value); + token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + await foreignBridge.initialize( + validatorContract.address, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + await token.mint(foreignBridge.address, value) }) it('should allow to executeSignatures', async () => { - var recipientAccount = accounts[3]; + const recipientAccount = accounts[3] const balanceBefore = await token.balanceOf(recipientAccount) - var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - var message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address); - var signature = await sign(authorities[0], message) - var vrs = signatureToVRS(signature); + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address) + const signature = await sign(authorities[0], message) + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) - const {logs} = await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled - logs[0].event.should.be.equal("RelayedMessage") + const { logs } = await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled + logs[0].event.should.be.equal('RelayedMessage') logs[0].args.recipient.should.be.equal(recipientAccount) logs[0].args.value.should.be.bignumber.equal(value) - const balanceAfter = await token.balanceOf(recipientAccount); - const balanceAfterBridge = await token.balanceOf(foreignBridge.address); + const balanceAfter = await token.balanceOf(recipientAccount) + const balanceAfterBridge = await token.balanceOf(foreignBridge.address) balanceAfter.should.be.bignumber.equal(balanceBefore.add(value)) - balanceAfterBridge.should.be.bignumber.equal(0) + balanceAfterBridge.should.be.bignumber.equal(ZERO) true.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) }) - it('should allow second withdrawal with different transactionHash but same recipient and value', async ()=> { - var recipientAccount = accounts[3]; + it('should allow second withdrawal with different transactionHash but same recipient and value', async () => { + const recipientAccount = accounts[3] const balanceBefore = await token.balanceOf(recipientAccount) // tx 1 - var value = web3.toBigNumber(web3.toWei(0.25, "ether")); - var transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - var message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address); - var signature = await sign(authorities[0], message) - var vrs = signatureToVRS(signature); + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address) + const signature = await sign(authorities[0], message) + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled // tx 2 - await token.mint(foreignBridge.address,value); - var transactionHash2 = "0x77a496628a776a03d58d7e6059a5937f04bebd8ba4ff89f76dd4bb8ba7e291ee"; - var message2 = createMessage(recipientAccount, value, transactionHash2, foreignBridge.address); - var signature2 = await sign(authorities[0], message2) - var vrs2 = signatureToVRS(signature2); + await token.mint(foreignBridge.address, value) + const transactionHash2 = '0x77a496628a776a03d58d7e6059a5937f04bebd8ba4ff89f76dd4bb8ba7e291ee' + const message2 = createMessage(recipientAccount, value, transactionHash2, foreignBridge.address) + const signature2 = await sign(authorities[0], message2) + const vrs2 = signatureToVRS(signature2) false.should.be.equal(await foreignBridge.relayedMessages(transactionHash2)) - const {logs} = await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.fulfilled + const { logs } = await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.fulfilled - logs[0].event.should.be.equal("RelayedMessage") + logs[0].event.should.be.equal('RelayedMessage') logs[0].args.recipient.should.be.equal(recipientAccount) logs[0].args.value.should.be.bignumber.equal(value) const balanceAfter = await token.balanceOf(recipientAccount) - balanceAfter.should.be.bignumber.equal(balanceBefore.add(value.mul(2))) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(value.mul(toBN(2)))) true.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) true.should.be.equal(await foreignBridge.relayedMessages(transactionHash2)) }) it('should not allow second withdraw (replay attack) with same transactionHash but different recipient', async () => { - var recipientAccount = accounts[3]; - const balanceBefore = await token.balanceOf(recipientAccount) + const recipientAccount = accounts[3] // tx 1 - var transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - var message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address); - var signature = await sign(authorities[0], message) - var vrs = signatureToVRS(signature); + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address) + const signature = await sign(authorities[0], message) + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled // tx 2 - await token.mint(foreignBridge.address,value); - var message2 = createMessage(accounts[4], value, transactionHash, foreignBridge.address); - var signature2 = await sign(authorities[0], message2) - var vrs = signatureToVRS(signature2); + await token.mint(foreignBridge.address, value) + const message2 = createMessage(accounts[4], value, transactionHash, foreignBridge.address) + const signature2 = await sign(authorities[0], message2) + const vrs2 = signatureToVRS(signature2) true.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) - await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message2).should.be.rejectedWith(ERROR_MSG) + await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.rejectedWith(ERROR_MSG) }) it('should not allow withdraw over home max tx limit', async () => { - const recipientAccount = accounts[3]; - const invalidValue = web3.toBigNumber(web3.toWei(0.75, "ether")); - await token.mint(foreignBridge.address, web3.toBigNumber(web3.toWei(5, "ether"))); + const recipientAccount = accounts[3] + const invalidValue = ether('0.75') + await token.mint(foreignBridge.address, ether('5')) - const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const message = createMessage(recipientAccount, invalidValue, transactionHash, foreignBridge.address); + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, invalidValue, transactionHash, foreignBridge.address) const signature = await sign(authorities[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.rejectedWith(ERROR_MSG) }) it('should not allow withdraw over daily home limit', async () => { - const recipientAccount = accounts[3]; - await token.mint(foreignBridge.address, web3.toBigNumber(web3.toWei(5, "ether"))); + const recipientAccount = accounts[3] + await token.mint(foreignBridge.address, ether('5')) - const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const message = createMessage(recipientAccount, halfEther, transactionHash, foreignBridge.address); + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, halfEther, transactionHash, foreignBridge.address) const signature = await sign(authorities[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled - const transactionHash2 = "0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712"; - const message2 = createMessage(recipientAccount, halfEther, transactionHash2, foreignBridge.address); + const transactionHash2 = '0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712' + const message2 = createMessage(recipientAccount, halfEther, transactionHash2, foreignBridge.address) const signature2 = await sign(authorities[0], message2) - const vrs2 = signatureToVRS(signature2); + const vrs2 = signatureToVRS(signature2) await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.fulfilled - const transactionHash3 = "0x022695428093bb292db8e48bd1417c5e1b84c0bf673bd0fff23ed0fb6495b872"; - const message3 = createMessage(recipientAccount, halfEther, transactionHash3, foreignBridge.address); + const transactionHash3 = '0x022695428093bb292db8e48bd1417c5e1b84c0bf673bd0fff23ed0fb6495b872' + const message3 = createMessage(recipientAccount, halfEther, transactionHash3, foreignBridge.address) const signature3 = await sign(authorities[0], message3) - const vrs3 = signatureToVRS(signature3); + const vrs3 = signatureToVRS(signature3) await foreignBridge.executeSignatures([vrs3.v], [vrs3.r], [vrs3.s], message3).should.be.rejectedWith(ERROR_MSG) }) }) - describe('#withdraw with 2 minimum signatures', async () => { - let multisigValidatorContract, twoAuthorities, ownerOfValidatorContract, foreignBridgeWithMultiSignatures - var value = web3.toBigNumber(web3.toWei(0.5, "ether")); + let multisigValidatorContract + let twoAuthorities + let ownerOfValidatorContract + let foreignBridgeWithMultiSignatures + const value = halfEther beforeEach(async () => { multisigValidatorContract = await BridgeValidators.new() - token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - twoAuthorities = [accounts[0], accounts[1]]; + token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + twoAuthorities = [accounts[0], accounts[1]] ownerOfValidatorContract = accounts[3] - const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether")); - await multisigValidatorContract.initialize(2, twoAuthorities, ownerOfValidatorContract, {from: ownerOfValidatorContract}) + await multisigValidatorContract.initialize(2, twoAuthorities, ownerOfValidatorContract, { + from: ownerOfValidatorContract + }) foreignBridgeWithMultiSignatures = await ForeignBridge.new() - const oneEther = web3.toBigNumber(web3.toWei(1, "ether")); - await foreignBridgeWithMultiSignatures.initialize(multisigValidatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner, {from: ownerOfValidatorContract}); - await token.mint(foreignBridgeWithMultiSignatures.address,value); + await foreignBridgeWithMultiSignatures.initialize( + multisigValidatorContract.address, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner, + { from: ownerOfValidatorContract } + ) + await token.mint(foreignBridgeWithMultiSignatures.address, value) }) it('withdraw should fail if not enough signatures are provided', async () => { - - var recipientAccount = accounts[4]; + const recipientAccount = accounts[4] // msg 1 - var transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - var message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address); - var signature = await sign(twoAuthorities[0], message) - var vrs = signatureToVRS(signature); + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address) + const signature = await sign(twoAuthorities[0], message) + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridgeWithMultiSignatures.relayedMessages(transactionHash)) - await foreignBridgeWithMultiSignatures.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.rejectedWith(ERROR_MSG) + await foreignBridgeWithMultiSignatures + .executeSignatures([vrs.v], [vrs.r], [vrs.s], message) + .should.be.rejectedWith(ERROR_MSG) // msg 2 - var signature2 = await sign(twoAuthorities[1], message) - var vrs2 = signatureToVRS(signature2); - const {logs} = await foreignBridgeWithMultiSignatures.executeSignatures([vrs.v, vrs2.v], [vrs.r, vrs2.r], [vrs.s, vrs2.s], message).should.be.fulfilled; - - logs[0].event.should.be.equal("RelayedMessage") + const signature2 = await sign(twoAuthorities[1], message) + const vrs2 = signatureToVRS(signature2) + const { logs } = await foreignBridgeWithMultiSignatures.executeSignatures( + [vrs.v, vrs2.v], + [vrs.r, vrs2.r], + [vrs.s, vrs2.s], + message + ).should.be.fulfilled + + logs[0].event.should.be.equal('RelayedMessage') logs[0].args.recipient.should.be.equal(recipientAccount) logs[0].args.value.should.be.bignumber.equal(value) true.should.be.equal(await foreignBridgeWithMultiSignatures.relayedMessages(transactionHash)) - }) it('withdraw should fail if duplicate signature is provided', async () => { - var recipientAccount = accounts[4]; - var transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - var message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address); - var signature = await sign(twoAuthorities[0], message) - var vrs = signatureToVRS(signature); + const recipientAccount = accounts[4] + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address) + const signature = await sign(twoAuthorities[0], message) + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridgeWithMultiSignatures.relayedMessages(transactionHash)) - await foreignBridgeWithMultiSignatures.executeSignatures([vrs.v, vrs.v], [vrs.r, vrs.r], [vrs.s, vrs.s], message).should.be.rejectedWith(ERROR_MSG) + await foreignBridgeWithMultiSignatures + .executeSignatures([vrs.v, vrs.v], [vrs.r, vrs.r], [vrs.s, vrs.s], message) + .should.be.rejectedWith(ERROR_MSG) }) it('works with 5 validators and 3 required signatures', async () => { @@ -231,109 +339,290 @@ contract('ForeignBridge_ERC20_to_ERC20', async (accounts) => { const ownerOfValidators = accounts[0] const validatorContractWith3Signatures = await BridgeValidators.new() await validatorContractWith3Signatures.initialize(3, authoritiesFiveAccs, ownerOfValidators) - const erc20Token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); + const erc20Token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + const value = halfEther const foreignBridgeWithThreeSigs = await ForeignBridge.new() - await foreignBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, erc20Token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner); - await erc20Token.mint(foreignBridgeWithThreeSigs.address, value); - - const txHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const message = createMessage(recipient, value, txHash, foreignBridgeWithThreeSigs.address); + await foreignBridgeWithThreeSigs.initialize( + validatorContractWith3Signatures.address, + erc20Token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + await erc20Token.mint(foreignBridgeWithThreeSigs.address, value) + + const txHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipient, value, txHash, foreignBridgeWithThreeSigs.address) // signature 1 const signature = await sign(authoritiesFiveAccs[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) // signature 2 const signature2 = await sign(authoritiesFiveAccs[1], message) - const vrs2 = signatureToVRS(signature2); + const vrs2 = signatureToVRS(signature2) // signature 3 const signature3 = await sign(authoritiesFiveAccs[2], message) - const vrs3 = signatureToVRS(signature3); - - - const {logs} = await foreignBridgeWithThreeSigs.executeSignatures([vrs.v, vrs2.v, vrs3.v], [vrs.r, vrs2.r, vrs3.r], [vrs.s, vrs2.s, vrs3.s], message).should.be.fulfilled; - logs[0].event.should.be.equal("RelayedMessage") + const vrs3 = signatureToVRS(signature3) + + const { logs } = await foreignBridgeWithThreeSigs.executeSignatures( + [vrs.v, vrs2.v, vrs3.v], + [vrs.r, vrs2.r, vrs3.r], + [vrs.s, vrs2.s, vrs3.s], + message + ).should.be.fulfilled + logs[0].event.should.be.equal('RelayedMessage') logs[0].args.recipient.should.be.equal(recipient) logs[0].args.value.should.be.bignumber.equal(value) true.should.be.equal(await foreignBridgeWithThreeSigs.relayedMessages(txHash)) }) }) - describe('#upgradeable', async () => { it('can be upgraded', async () => { const REQUIRED_NUMBER_OF_VALIDATORS = 1 const VALIDATORS = [accounts[1]] - const PROXY_OWNER = accounts[0] + const PROXY_OWNER = accounts[0] // Validators Contract - let validatorsProxy = await EternalStorageProxy.new().should.be.fulfilled; - const validatorsContractImpl = await BridgeValidators.new().should.be.fulfilled; - await validatorsProxy.upgradeTo('1', validatorsContractImpl.address).should.be.fulfilled; + let validatorsProxy = await EternalStorageProxy.new().should.be.fulfilled + const validatorsContractImpl = await BridgeValidators.new().should.be.fulfilled + await validatorsProxy.upgradeTo('1', validatorsContractImpl.address).should.be.fulfilled validatorsContractImpl.address.should.be.equal(await validatorsProxy.implementation()) - validatorsProxy = await BridgeValidators.at(validatorsProxy.address); - await validatorsProxy.initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, PROXY_OWNER).should.be.fulfilled; - let token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); + validatorsProxy = await BridgeValidators.at(validatorsProxy.address) + await validatorsProxy.initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, PROXY_OWNER).should.be.fulfilled + const token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) // ForeignBridge V1 Contract - let foreignBridgeProxy = await EternalStorageProxy.new().should.be.fulfilled; - const foreignBridgeImpl = await ForeignBridge.new().should.be.fulfilled; - await foreignBridgeProxy.upgradeTo('1', foreignBridgeImpl.address).should.be.fulfilled; - - foreignBridgeProxy = await ForeignBridge.at(foreignBridgeProxy.address); - await foreignBridgeProxy.initialize(validatorsProxy.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner) + let foreignBridgeProxy = await EternalStorageProxy.new().should.be.fulfilled + const foreignBridgeImpl = await ForeignBridge.new().should.be.fulfilled + await foreignBridgeProxy.upgradeTo('1', foreignBridgeImpl.address).should.be.fulfilled + + foreignBridgeProxy = await ForeignBridge.at(foreignBridgeProxy.address) + await foreignBridgeProxy.initialize( + validatorsProxy.address, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) // Deploy V2 - let foreignImplV2 = await ForeignBridgeV2.new(); - let foreignBridgeProxyUpgrade = await EternalStorageProxy.at(foreignBridgeProxy.address); - await foreignBridgeProxyUpgrade.upgradeTo('2', foreignImplV2.address).should.be.fulfilled; + const foreignImplV2 = await ForeignBridgeV2.new() + const foreignBridgeProxyUpgrade = await EternalStorageProxy.at(foreignBridgeProxy.address) + await foreignBridgeProxyUpgrade.upgradeTo('2', foreignImplV2.address).should.be.fulfilled foreignImplV2.address.should.be.equal(await foreignBridgeProxyUpgrade.implementation()) - let foreignBridgeV2Proxy = await ForeignBridgeV2.at(foreignBridgeProxy.address) - await foreignBridgeV2Proxy.doSomething(accounts[2], {from: accounts[4]}).should.be.rejectedWith(ERROR_MSG) - await foreignBridgeV2Proxy.doSomething(accounts[2], {from: PROXY_OWNER}).should.be.fulfilled; - (await foreignBridgeV2Proxy.something()).should.be.equal(accounts[2]) + const foreignBridgeV2Proxy = await ForeignBridgeV2.at(foreignBridgeProxy.address) + await foreignBridgeV2Proxy.doSomething(accounts[2], { from: accounts[4] }).should.be.rejectedWith(ERROR_MSG) + await foreignBridgeV2Proxy.doSomething(accounts[2], { from: PROXY_OWNER }).should.be.fulfilled + ;(await foreignBridgeV2Proxy.something()).should.be.equal(accounts[2]) }) it('can be deployed via upgradeToAndCall', async () => { const tokenAddress = token.address const validatorsAddress = validatorContract.address - let storageProxy = await EternalStorageProxy.new().should.be.fulfilled; - let foreignBridge = await ForeignBridge.new(); - let data = foreignBridge.initialize.request( - validatorsAddress, tokenAddress, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).params[0].data - await storageProxy.upgradeToAndCall('1', foreignBridge.address, data).should.be.fulfilled; - let finalContract = await ForeignBridge.at(storageProxy.address); - true.should.be.equal(await finalContract.isInitialized()); + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + const foreignBridge = await ForeignBridge.new() + const data = foreignBridge.contract.methods + .initialize(validatorsAddress, tokenAddress, requireBlockConfirmations, gasPrice, '2', '3', '2', owner) + .encodeABI() + await storageProxy.upgradeToAndCall('1', foreignBridge.address, data).should.be.fulfilled + const finalContract = await ForeignBridge.at(storageProxy.address) + true.should.be.equal(await finalContract.isInitialized()) validatorsAddress.should.be.equal(await finalContract.validatorContract()) }) }) - describe('#claimTokens', async () => { it('can send erc20', async () => { - const owner = accounts[0]; - token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - const foreignBridgeImpl = await ForeignBridge.new(); - const storageProxy = await EternalStorageProxy.new().should.be.fulfilled; + const owner = accounts[0] + token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + const foreignBridgeImpl = await ForeignBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled await storageProxy.upgradeTo('1', foreignBridgeImpl.address).should.be.fulfilled - const foreignBridge = await ForeignBridge.at(storageProxy.address); - await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner); - - let tokenSecond = await ERC677BridgeToken.new("Roman Token", "RST", 18); - - await tokenSecond.mint(accounts[0], halfEther).should.be.fulfilled; - halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[0])) - await tokenSecond.transfer(foreignBridge.address, halfEther); - '0'.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[0])) - halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(foreignBridge.address)) - - await foreignBridge.claimTokens(tokenSecond.address, accounts[3], {from: owner}); - '0'.should.be.bignumber.equal(await tokenSecond.balanceOf(foreignBridge.address)) - halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[3])) - + const foreignBridge = await ForeignBridge.at(storageProxy.address) + await foreignBridge.initialize( + validatorContract.address, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + + const tokenSecond = await ERC677BridgeToken.new('Roman Token', 'RST', 18) + + await tokenSecond.mint(accounts[0], halfEther).should.be.fulfilled + expect(await tokenSecond.balanceOf(accounts[0])).to.be.bignumber.equal(halfEther) + + await tokenSecond.transfer(foreignBridge.address, halfEther) + expect(await tokenSecond.balanceOf(accounts[0])).to.be.bignumber.equal(ZERO) + expect(await tokenSecond.balanceOf(foreignBridge.address)).to.be.bignumber.equal(halfEther) + + await foreignBridge.claimTokens(tokenSecond.address, accounts[3], { from: owner }) + expect(await tokenSecond.balanceOf(foreignBridge.address)).to.be.bignumber.equal(ZERO) + expect(await tokenSecond.balanceOf(accounts[3])).to.be.bignumber.equal(halfEther) + }) + }) + describe('#ForeignBridgeErc677ToErc677_onTokenTransfer', async () => { + it('can only be called from token contract', async () => { + const owner = accounts[3] + const user = accounts[4] + token = await ERC677BridgeToken.new('TEST', 'TST', 18, { from: owner }) + const foreignBridge = await ForeignBridgeErc677ToErc677.new() + await foreignBridge.initialize( + validatorContract.address, + token.address, + requireBlockConfirmations, + gasPrice, + dailyLimit, + maxPerTx, + minPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + + await token.mint(user, halfEther, { from: owner }).should.be.fulfilled + await token.transferOwnership(foreignBridge.address, { from: owner }) + await foreignBridge.onTokenTransfer(user, halfEther, '0x00', { from: owner }).should.be.rejectedWith(ERROR_MSG) + + await token.transferAndCall(foreignBridge.address, halfEther, '0x00', { from: user }).should.be.fulfilled + expect(await token.totalSupply()).to.be.bignumber.equal(halfEther) + expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO) + expect(await token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(halfEther) + + const events = await getEvents(foreignBridge, { event: 'UserRequestForAffirmation' }) + expect(events[0].returnValues.recipient).to.be.equal(user) + expect(toBN(events[0].returnValues.value)).to.be.bignumber.equal(halfEther) + }) + it('should not allow to transfer more than maxPerTx limit', async () => { + const owner = accounts[3] + const user = accounts[4] + const valueMoreThanLimit = halfEther.add(toBN(1)) + token = await ERC677BridgeToken.new('TEST', 'TST', 18, { from: owner }) + const foreignBridge = await ForeignBridgeErc677ToErc677.new() + await foreignBridge.initialize( + validatorContract.address, + token.address, + requireBlockConfirmations, + gasPrice, + dailyLimit, + maxPerTx, + minPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + + await token.mint(user, valueMoreThanLimit, { from: owner }).should.be.fulfilled + await token.transferOwnership(foreignBridge.address, { from: owner }) + + await token + .transferAndCall(foreignBridge.address, valueMoreThanLimit, '0x00', { from: user }) + .should.be.rejectedWith(ERROR_MSG) + valueMoreThanLimit.should.be.bignumber.equal(await token.totalSupply()) + valueMoreThanLimit.should.be.bignumber.equal(await token.balanceOf(user)) + + await token.transferAndCall(foreignBridge.address, halfEther, '0x00', { from: user }).should.be.fulfilled + + expect(await token.totalSupply()).to.be.bignumber.equal(valueMoreThanLimit) + expect(await token.balanceOf(user)).to.be.bignumber.equal('1') + expect(await token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(halfEther) + const events = await getEvents(foreignBridge, { event: 'UserRequestForAffirmation' }) + expect(events[0].returnValues.recipient).to.be.equal(user) + expect(toBN(events[0].returnValues.value)).to.be.bignumber.equal(halfEther) + }) + it('should only let to transfer within daily limit', async () => { + const owner = accounts[3] + const user = accounts[4] + const valueMoreThanLimit = halfEther.add(toBN(1)) + token = await ERC677BridgeToken.new('TEST', 'TST', 18, { from: owner }) + const foreignBridge = await ForeignBridgeErc677ToErc677.new() + await foreignBridge.initialize( + validatorContract.address, + token.address, + requireBlockConfirmations, + gasPrice, + dailyLimit, + maxPerTx, + minPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + + await token.mint(user, oneEther.add(toBN(1)), { from: owner }).should.be.fulfilled + await token.transferOwnership(foreignBridge.address, { from: owner }) + + await token + .transferAndCall(foreignBridge.address, valueMoreThanLimit, '0x00', { from: user }) + .should.be.rejectedWith(ERROR_MSG) + oneEther.add(toBN(1)).should.be.bignumber.equal(await token.totalSupply()) + oneEther.add(toBN(1)).should.be.bignumber.equal(await token.balanceOf(user)) + + await token.transferAndCall(foreignBridge.address, halfEther, '0x00', { from: user }).should.be.fulfilled + oneEther.add(toBN(1)).should.be.bignumber.equal(await token.totalSupply()) + valueMoreThanLimit.should.be.bignumber.equal(await token.balanceOf(user)) + const events = await getEvents(foreignBridge, { event: 'UserRequestForAffirmation' }) + expect(events[0].returnValues.recipient).to.be.equal(user) + expect(toBN(events[0].returnValues.value)).to.be.bignumber.equal(halfEther) + + await token.transferAndCall(foreignBridge.address, halfEther, '0x00', { from: user }).should.be.fulfilled + + expect(await token.totalSupply()).to.be.bignumber.equal(oneEther.add(toBN(1))) + expect(await token.balanceOf(user)).to.be.bignumber.equal('1') + expect(await token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(oneEther) + + await token.transferAndCall(foreignBridge.address, '1', '0x00', { from: user }).should.be.rejectedWith(ERROR_MSG) + }) + it('should not let to transfer less than minPerTx', async () => { + const owner = accounts[3] + const user = accounts[4] + const valueLessThanMinPerTx = minPerTx.sub(toBN(1)) + token = await ERC677BridgeToken.new('TEST', 'TST', 18, { from: owner }) + const foreignBridge = await ForeignBridgeErc677ToErc677.new() + await foreignBridge.initialize( + validatorContract.address, + token.address, + requireBlockConfirmations, + gasPrice, + dailyLimit, + maxPerTx, + minPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + + await token.mint(user, oneEther, { from: owner }).should.be.fulfilled + await token.transferOwnership(foreignBridge.address, { from: owner }) + + await token + .transferAndCall(foreignBridge.address, valueLessThanMinPerTx, '0x00', { from: user }) + .should.be.rejectedWith(ERROR_MSG) + expect(await token.totalSupply()).to.be.bignumber.equal(oneEther) + expect(await token.balanceOf(user)).to.be.bignumber.equal(oneEther) + + await token.transferAndCall(foreignBridge.address, minPerTx, '0x00', { from: user }).should.be.fulfilled + + expect(await token.totalSupply()).to.be.bignumber.equal(oneEther) + expect(await token.balanceOf(user)).to.be.bignumber.equal(oneEther.sub(minPerTx)) + expect(await token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(minPerTx) + + const events = await getEvents(foreignBridge, { event: 'UserRequestForAffirmation' }) + expect(events[0].returnValues.recipient).to.be.equal(user) + expect(toBN(events[0].returnValues.value)).to.be.bignumber.equal(minPerTx) }) }) }) diff --git a/test/erc_to_erc/home_bridge.test.js b/test/erc_to_erc/home_bridge.test.js index 25805ce42..c26509e66 100644 --- a/test/erc_to_erc/home_bridge.test.js +++ b/test/erc_to_erc/home_bridge.test.js @@ -1,430 +1,761 @@ -const Web3Utils = require('web3-utils'); -const HomeBridge = artifacts.require("HomeBridgeErcToErc.sol"); -const EternalStorageProxy = artifacts.require("EternalStorageProxy.sol"); -const BridgeValidators = artifacts.require("BridgeValidators.sol"); -const ERC677BridgeToken = artifacts.require("ERC677BridgeToken.sol"); -const {ERROR_MSG, ZERO_ADDRESS} = require('../setup'); -const {createMessage, sign, signatureToVRS} = require('../helpers/helpers'); -const minPerTx = web3.toBigNumber(web3.toWei(0.01, "ether")); -const requireBlockConfirmations = 8; -const gasPrice = Web3Utils.toWei('1', 'gwei'); -const oneEther = web3.toBigNumber(web3.toWei(1, "ether")); -const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether")); +const HomeBridge = artifacts.require('HomeBridgeErcToErc.sol') +const POSDAOHomeBridge = artifacts.require('POSDAOHomeBridgeErcToErc.sol') +const EternalStorageProxy = artifacts.require('EternalStorageProxy.sol') +const BridgeValidators = artifacts.require('BridgeValidators.sol') +const ERC677BridgeToken = artifacts.require('ERC677BridgeToken.sol') +const ERC677BridgeTokenRewardable = artifacts.require('ERC677BridgeTokenRewardable.sol') +const FeeManagerErcToErcPOSDAO = artifacts.require('FeeManagerErcToErcPOSDAO.sol') +const RewardableValidators = artifacts.require('RewardableValidators.sol') +const BlockReward = artifacts.require('BlockReward') + +const { expect } = require('chai') +const { ERROR_MSG, ZERO_ADDRESS, toBN } = require('../setup') +const { createMessage, sign, getEvents, ether, expectEventInLogs } = require('../helpers/helpers') + +const minPerTx = ether('0.01') +const requireBlockConfirmations = 8 +const gasPrice = web3.utils.toWei('1', 'gwei') +const oneEther = ether('1') +const halfEther = ether('0.5') const foreignDailyLimit = oneEther const foreignMaxPerTx = halfEther - - -contract('HomeBridge_ERC20_to_ERC20', async (accounts) => { - let homeContract, validatorContract, authorities, owner, token; +const ZERO = toBN(0) +const markedAsProcessed = toBN(2) + .pow(toBN(255)) + .add(toBN(1)) + +contract('HomeBridge_ERC20_to_ERC20', async accounts => { + let homeContract + let validatorContract + let authorities + let owner + let token before(async () => { validatorContract = await BridgeValidators.new() - authorities = [accounts[1]]; + authorities = [accounts[1]] owner = accounts[0] await validatorContract.initialize(1, authorities, owner) }) - describe('#initialize', async() => { + describe('#initialize', async () => { beforeEach(async () => { homeContract = await HomeBridge.new() - token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); + token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) }) it('sets variables', async () => { - ZERO_ADDRESS.should.be.equal(await homeContract.validatorContract()) - '0'.should.be.bignumber.equal(await homeContract.deployedAtBlock()) - '0'.should.be.bignumber.equal(await homeContract.dailyLimit()) - '0'.should.be.bignumber.equal(await homeContract.maxPerTx()) - false.should.be.equal(await homeContract.isInitialized()) - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.fulfilled; - true.should.be.equal(await homeContract.isInitialized()) - validatorContract.address.should.be.equal(await homeContract.validatorContract()); - (await homeContract.deployedAtBlock()).should.be.bignumber.above(0); - '3'.should.be.bignumber.equal(await homeContract.dailyLimit()) - '2'.should.be.bignumber.equal(await homeContract.maxPerTx()) - '1'.should.be.bignumber.equal(await homeContract.minPerTx()) + expect(await homeContract.validatorContract()).to.be.equal(ZERO_ADDRESS) + expect(await homeContract.deployedAtBlock()).to.be.bignumber.equal(ZERO) + expect(await homeContract.dailyLimit()).to.be.bignumber.equal(ZERO) + expect(await homeContract.maxPerTx()).to.be.bignumber.equal(ZERO) + expect(await homeContract.isInitialized()).to.be.equal(false) + + await homeContract.initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + + expect(await homeContract.isInitialized()).to.be.equal(true) + expect(await homeContract.validatorContract()).to.be.equal(validatorContract.address) + expect(await homeContract.deployedAtBlock()).to.be.bignumber.above(ZERO) + expect(await homeContract.dailyLimit()).to.be.bignumber.equal('3') + expect(await homeContract.maxPerTx()).to.be.bignumber.equal('2') + expect(await homeContract.minPerTx()).to.be.bignumber.equal('1') const bridgeMode = '0xba4690f5' // 4 bytes of keccak256('erc-to-erc-core') - const mode = await homeContract.getBridgeMode(); - mode.should.be.equal(bridgeMode) - const [major, minor, patch] = await homeContract.getBridgeInterfacesVersion() - major.should.be.bignumber.gte(0) - minor.should.be.bignumber.gte(0) - patch.should.be.bignumber.gte(0) + expect(await homeContract.getBridgeMode()).to.be.equal(bridgeMode) + const { major, minor, patch } = await homeContract.getBridgeInterfacesVersion() + expect(major).to.be.bignumber.gte(ZERO) + expect(minor).to.be.bignumber.gte(ZERO) + expect(patch).to.be.bignumber.gte(ZERO) }) it('cant set maxPerTx > dailyLimit', async () => { - false.should.be.equal(await homeContract.isInitialized()) - await homeContract.initialize(validatorContract.address, '1', '2', '1', gasPrice, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(validatorContract.address, '3', '2', '2', gasPrice, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - false.should.be.equal(await homeContract.isInitialized()) + expect(await homeContract.isInitialized()).to.be.equal(false) + + await homeContract + .initialize( + validatorContract.address, + '1', + '2', + '1', + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + validatorContract.address, + '3', + '2', + '2', + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + + expect(await homeContract.isInitialized()).to.be.equal(false) }) it('can be deployed via upgradeToAndCall', async () => { - let storageProxy = await EternalStorageProxy.new().should.be.fulfilled; - let data = homeContract.initialize.request(validatorContract.address, "3", "2", "1", gasPrice, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner).params[0].data - await storageProxy.upgradeToAndCall('1', homeContract.address, data).should.be.fulfilled; - let finalContract = await HomeBridge.at(storageProxy.address); - true.should.be.equal(await finalContract.isInitialized()); - validatorContract.address.should.be.equal(await finalContract.validatorContract()) - "3".should.be.bignumber.equal(await finalContract.dailyLimit()) - "2".should.be.bignumber.equal(await finalContract.maxPerTx()) - "1".should.be.bignumber.equal(await finalContract.minPerTx()) + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + const data = homeContract.contract.methods + .initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + token.address, + '3', + '2', + owner + ) + .encodeABI() + await storageProxy.upgradeToAndCall('1', homeContract.address, data).should.be.fulfilled + const finalContract = await HomeBridge.at(storageProxy.address) + + expect(await finalContract.isInitialized()).to.be.equal(true) + expect(await finalContract.validatorContract()).to.be.equal(validatorContract.address) + expect(await finalContract.dailyLimit()).to.be.bignumber.equal('3') + expect(await finalContract.maxPerTx()).to.be.bignumber.equal('2') + expect(await finalContract.minPerTx()).to.be.bignumber.equal('1') }) it('cant initialize with invalid arguments', async () => { - false.should.be.equal(await homeContract.isInitialized()) - await homeContract.initialize(validatorContract.address, '3', '2', '1', 0, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, 0, token.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(owner, '3', '2', '1', gasPrice, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(ZERO_ADDRESS, '3', '2', '1', gasPrice, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, ZERO_ADDRESS, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, owner, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, token.address, halfEther, oneEther, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.fulfilled; - true.should.be.equal(await homeContract.isInitialized()) + expect(await homeContract.isInitialized()).to.be.equal(false) + + await homeContract + .initialize( + validatorContract.address, + '3', + '2', + '1', + 0, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + 0, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + owner, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + ZERO_ADDRESS, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + ZERO_ADDRESS, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + owner, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + token.address, + halfEther, + oneEther, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract.initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + + expect(await homeContract.isInitialized()).to.be.equal(true) }) }) describe('#fallback', async () => { beforeEach(async () => { homeContract = await HomeBridge.new() - token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner) + token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + await homeContract.initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) }) it('reverts', async () => { - const {logs} = await homeContract.sendTransaction({ - from: accounts[1], - value: 1 - }).should.be.rejectedWith(ERROR_MSG) + await homeContract + .sendTransaction({ + from: accounts[1], + value: 1 + }) + .should.be.rejectedWith(ERROR_MSG) }) }) describe('#setting limits', async () => { - let homeContract; + let homeContract beforeEach(async () => { homeContract = await HomeBridge.new() - token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner) + token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + await homeContract.initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) }) it('#setMaxPerTx allows to set only to owner and cannot be more than daily limit', async () => { - await homeContract.setMaxPerTx(2, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); - await homeContract.setMaxPerTx(2, {from: owner}).should.be.fulfilled; + await homeContract.setMaxPerTx(2, { from: authorities[0] }).should.be.rejectedWith(ERROR_MSG) + await homeContract.setMaxPerTx(2, { from: owner }).should.be.fulfilled - await homeContract.setMaxPerTx(3, {from: owner}).should.be.rejectedWith(ERROR_MSG); + await homeContract.setMaxPerTx(3, { from: owner }).should.be.rejectedWith(ERROR_MSG) }) it('#setMinPerTx allows to set only to owner and cannot be more than daily limit and should be less than maxPerTx', async () => { - await homeContract.setMinPerTx(1, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); - await homeContract.setMinPerTx(1, {from: owner}).should.be.fulfilled; + await homeContract.setMinPerTx(1, { from: authorities[0] }).should.be.rejectedWith(ERROR_MSG) + await homeContract.setMinPerTx(1, { from: owner }).should.be.fulfilled - await homeContract.setMinPerTx(2, {from: owner}).should.be.rejectedWith(ERROR_MSG); + await homeContract.setMinPerTx(2, { from: owner }).should.be.rejectedWith(ERROR_MSG) }) }) describe('#executeAffirmation', async () => { - let homeBridge; + let homeBridge beforeEach(async () => { - homeBridge = await HomeBridge.new(); - token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - await homeBridge.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner); - await token.transferOwnership(homeBridge.address); + homeBridge = await HomeBridge.new() + token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + await homeBridge.initialize( + validatorContract.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + await token.transferOwnership(homeBridge.address) }) it('should allow validator to withdraw', async () => { - const recipient = accounts[5]; - const value = halfEther; + const recipient = accounts[5] + const value = halfEther + const balanceBefore = await token.balanceOf(recipient) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }) + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: authorities[0], + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + + const totalSupply = await token.totalSupply() + const balanceAfter = await token.balanceOf(recipient) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(value)) + totalSupply.should.be.bignumber.equal(value) + + const msgHash = web3.utils.soliditySha3(recipient, value, transactionHash) + const senderHash = web3.utils.soliditySha3(authorities[0], msgHash) + true.should.be.equal(await homeBridge.affirmationsSigned(senderHash)) + markedAsProcessed.should.be.bignumber.equal(await homeBridge.numAffirmationsSigned(msgHash)) + await homeBridge + .executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }) + .should.be.rejectedWith(ERROR_MSG) + }) + + it('should allow validator to withdraw with zero value', async () => { + const recipient = accounts[5] + const value = ZERO const balanceBefore = await token.balanceOf(recipient) - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const {logs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}) - logs[0].event.should.be.equal("SignedForAffirmation"); - logs[0].args.should.be.deep.equal({ + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }) + + expectEventInLogs(logs, 'SignedForAffirmation', { signer: authorities[0], transactionHash - }); - logs[1].event.should.be.equal("AffirmationCompleted"); - logs[1].args.should.be.deep.equal({ + }) + expectEventInLogs(logs, 'AffirmationCompleted', { recipient, value, transactionHash }) + const totalSupply = await token.totalSupply() const balanceAfter = await token.balanceOf(recipient) balanceAfter.should.be.bignumber.equal(balanceBefore.add(value)) totalSupply.should.be.bignumber.equal(value) - const msgHash = Web3Utils.soliditySha3(recipient, value, transactionHash); - const senderHash = Web3Utils.soliditySha3(authorities[0], msgHash) + const msgHash = web3.utils.soliditySha3(recipient, value, transactionHash) + const senderHash = web3.utils.soliditySha3(authorities[0], msgHash) true.should.be.equal(await homeBridge.affirmationsSigned(senderHash)) - const markedAsProcessed = new web3.BigNumber(2).pow(255).add(1); - markedAsProcessed.should.be.bignumber.equal(await homeBridge.numAffirmationsSigned(msgHash)); - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG) + markedAsProcessed.should.be.bignumber.equal(await homeBridge.numAffirmationsSigned(msgHash)) + await homeBridge + .executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }) + .should.be.rejectedWith(ERROR_MSG) }) it('test with 2 signatures required', async () => { - let token2sig = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - let validatorContractWith2Signatures = await BridgeValidators.new() - let authoritiesTwoAccs = [accounts[1], accounts[2], accounts[3]]; - let ownerOfValidators = accounts[0] - await validatorContractWith2Signatures.initialize(2, authoritiesTwoAccs, ownerOfValidators) - let homeBridgeWithTwoSigs = await HomeBridge.new(); - await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, token2sig.address, foreignDailyLimit, foreignMaxPerTx, owner); - await token2sig.transferOwnership(homeBridgeWithTwoSigs.address); - const recipient = accounts[5]; - const value = halfEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; + const token2sig = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + const validatorContractWith2Signatures = await BridgeValidators.new() + const authoritiesThreeAccs = [accounts[1], accounts[2], accounts[3]] + const ownerOfValidators = accounts[0] + await validatorContractWith2Signatures.initialize(2, authoritiesThreeAccs, ownerOfValidators) + const homeBridgeWithTwoSigs = await HomeBridge.new() + await homeBridgeWithTwoSigs.initialize( + validatorContractWith2Signatures.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token2sig.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + await token2sig.transferOwnership(homeBridgeWithTwoSigs.address) + const recipient = accounts[5] + const value = halfEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' const balanceBefore = await token2sig.balanceOf(recipient) - const msgHash = Web3Utils.soliditySha3(recipient, value, transactionHash); + const msgHash = web3.utils.soliditySha3(recipient, value, transactionHash) + + const { logs } = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled - const {logs} = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - logs[0].event.should.be.equal("SignedForAffirmation"); - logs[0].args.should.be.deep.equal({ + expectEventInLogs(logs, 'SignedForAffirmation', { signer: authorities[0], transactionHash - }); - '0'.should.be.bignumber.equal(await token2sig.totalSupply()) - const notProcessed = await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash); - notProcessed.should.be.bignumber.equal(1); + }) + + expect(await token2sig.totalSupply()).to.be.bignumber.equal(ZERO) + const notProcessed = await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash) + notProcessed.should.be.bignumber.equal('1') - await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[0]}).should.be.rejectedWith(ERROR_MSG); - const secondSignature = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; + await homeBridgeWithTwoSigs + .executeAffirmation(recipient, value, transactionHash, { from: authoritiesThreeAccs[0] }) + .should.be.rejectedWith(ERROR_MSG) + const secondSignature = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled const balanceAfter = await token2sig.balanceOf(recipient) balanceAfter.should.be.bignumber.equal(balanceBefore.add(value)) - secondSignature.logs[1].event.should.be.equal("AffirmationCompleted"); - secondSignature.logs[1].args.should.be.deep.equal({ + expectEventInLogs(secondSignature.logs, 'AffirmationCompleted', { recipient, value, transactionHash }) - const senderHash = Web3Utils.soliditySha3(authoritiesTwoAccs[0], msgHash) + const senderHash = web3.utils.soliditySha3(authoritiesThreeAccs[0], msgHash) true.should.be.equal(await homeBridgeWithTwoSigs.affirmationsSigned(senderHash)) - const senderHash2 = Web3Utils.soliditySha3(authoritiesTwoAccs[1], msgHash); + const senderHash2 = web3.utils.soliditySha3(authoritiesThreeAccs[1], msgHash) true.should.be.equal(await homeBridgeWithTwoSigs.affirmationsSigned(senderHash2)) - const markedAsProcessed = await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash); - const processed = new web3.BigNumber(2).pow(255).add(2); - markedAsProcessed.should.be.bignumber.equal(processed) + const processed = toBN(2) + .pow(toBN(255)) + .add(toBN(2)) + expect(await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash)).to.be.bignumber.equal(processed) }) it('should not allow to double submit', async () => { - const recipient = accounts[5]; - const value = '1'; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled; - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); + const recipient = accounts[5] + const value = '1' + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled + await homeBridge + .executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }) + .should.be.rejectedWith(ERROR_MSG) }) it('should not allow non-authorities to execute deposit', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: accounts[7]}).should.be.rejectedWith(ERROR_MSG); + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + await homeBridge + .executeAffirmation(recipient, value, transactionHash, { from: accounts[7] }) + .should.be.rejectedWith(ERROR_MSG) }) it('doesnt allow to deposit if requiredSignatures has changed', async () => { - let token2sig = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - let validatorContractWith2Signatures = await BridgeValidators.new() - let authoritiesTwoAccs = [accounts[1], accounts[2], accounts[3]]; - let ownerOfValidators = accounts[0] - await validatorContractWith2Signatures.initialize(2, authoritiesTwoAccs, ownerOfValidators) - let homeBridgeWithTwoSigs = await HomeBridge.new(); - await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, token2sig.address, foreignDailyLimit, foreignMaxPerTx, owner); - await token2sig.transferOwnership(homeBridgeWithTwoSigs.address); - const recipient = accounts[5]; - const value = halfEther.div(2); - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; + const token2sig = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + const validatorContractWith2Signatures = await BridgeValidators.new() + const authoritiesThreeAccs = [accounts[1], accounts[2], accounts[3]] + const ownerOfValidators = accounts[0] + await validatorContractWith2Signatures.initialize(2, authoritiesThreeAccs, ownerOfValidators) + const homeBridgeWithTwoSigs = await HomeBridge.new() + await homeBridgeWithTwoSigs.initialize( + validatorContractWith2Signatures.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token2sig.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + await token2sig.transferOwnership(homeBridgeWithTwoSigs.address) + const recipient = accounts[5] + const value = halfEther.div(toBN(2)) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' const balanceBefore = await token.balanceOf(recipient) - const msgHash = Web3Utils.soliditySha3(recipient, value, transactionHash); - await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; + await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled + await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled balanceBefore.add(value).should.be.bignumber.equal(await token2sig.balanceOf(recipient)) - await validatorContractWith2Signatures.setRequiredSignatures(3).should.be.fulfilled; - await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[2]}).should.be.rejectedWith(ERROR_MSG); - await validatorContractWith2Signatures.setRequiredSignatures(1).should.be.fulfilled; - await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[2]}).should.be.rejectedWith(ERROR_MSG); + await validatorContractWith2Signatures.setRequiredSignatures(3).should.be.fulfilled + await homeBridgeWithTwoSigs + .executeAffirmation(recipient, value, transactionHash, { from: authoritiesThreeAccs[2] }) + .should.be.rejectedWith(ERROR_MSG) + await validatorContractWith2Signatures.setRequiredSignatures(1).should.be.fulfilled + await homeBridgeWithTwoSigs + .executeAffirmation(recipient, value, transactionHash, { from: authoritiesThreeAccs[2] }) + .should.be.rejectedWith(ERROR_MSG) balanceBefore.add(value).should.be.bignumber.equal(await token2sig.balanceOf(recipient)) - }) it('works with 5 validators and 3 required signatures', async () => { const recipient = accounts[8] const authoritiesFiveAccs = [accounts[1], accounts[2], accounts[3], accounts[4], accounts[5]] - let ownerOfValidators = accounts[0] + const ownerOfValidators = accounts[0] const validatorContractWith3Signatures = await BridgeValidators.new() await validatorContractWith3Signatures.initialize(3, authoritiesFiveAccs, ownerOfValidators) - const token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - - const homeBridgeWithThreeSigs = await HomeBridge.new(); - await homeBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner); - await token.transferOwnership(homeBridgeWithThreeSigs.address); - - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - - const {logs} = await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesFiveAccs[0]}).should.be.fulfilled; - logs[0].event.should.be.equal("SignedForAffirmation"); - logs[0].args.should.be.deep.equal({ + const token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + + const homeBridgeWithThreeSigs = await HomeBridge.new() + await homeBridgeWithThreeSigs.initialize( + validatorContractWith3Signatures.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + await token.transferOwnership(homeBridgeWithThreeSigs.address) + + const value = ether('0.5') + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + const { logs } = await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesFiveAccs[0] + }).should.be.fulfilled + expectEventInLogs(logs, 'SignedForAffirmation', { signer: authorities[0], transactionHash - }); + }) - await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesFiveAccs[1]}).should.be.fulfilled; - const thirdSignature = await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesFiveAccs[2]}).should.be.fulfilled; + await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesFiveAccs[1] + }).should.be.fulfilled + const thirdSignature = await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesFiveAccs[2] + }).should.be.fulfilled - thirdSignature.logs[1].event.should.be.equal("AffirmationCompleted"); - thirdSignature.logs[1].args.should.be.deep.equal({ + expectEventInLogs(thirdSignature.logs, 'AffirmationCompleted', { recipient, value, transactionHash }) }) it('should not allow execute affirmation over foreign max tx limit', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const {logs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled; - - logs[0].event.should.be.equal("AmountLimitExceeded"); - logs[0].args.should.be.deep.equal({ + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled + + expectEventInLogs(logs, 'AmountLimitExceeded', { recipient, value, transactionHash - }); + }) }) it('should fail if txHash already set as above of limits', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const {logs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled; - - logs[0].event.should.be.equal("AmountLimitExceeded"); - logs[0].args.should.be.deep.equal({ + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled + + expectEventInLogs(logs, 'AmountLimitExceeded', { recipient, value, transactionHash - }); + }) - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG) - await homeBridge.executeAffirmation(accounts[6], value, transactionHash, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG) + await homeBridge + .executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }) + .should.be.rejectedWith(ERROR_MSG) + await homeBridge + .executeAffirmation(accounts[6], value, transactionHash, { from: authorities[0] }) + .should.be.rejectedWith(ERROR_MSG) }) it('should not allow execute affirmation over daily foreign limit', async () => { - const recipient = accounts[5]; - const value = halfEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled; - - logs[0].event.should.be.equal("SignedForAffirmation"); - logs[0].args.should.be.deep.equal({ + const recipient = accounts[5] + const value = halfEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled + + expectEventInLogs(logs, 'SignedForAffirmation', { signer: authorities[0], transactionHash - }); - logs[1].event.should.be.equal("AffirmationCompleted"); - logs[1].args.should.be.deep.equal({ + }) + expectEventInLogs(logs, 'AffirmationCompleted', { recipient, value, transactionHash }) - const transactionHash2 = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const { logs: logs2 } = await homeBridge.executeAffirmation(recipient, value, transactionHash2, {from: authorities[0]}).should.be.fulfilled; + const transactionHash2 = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const { logs: logs2 } = await homeBridge.executeAffirmation(recipient, value, transactionHash2, { + from: authorities[0] + }).should.be.fulfilled - logs2[0].event.should.be.equal("SignedForAffirmation"); - logs2[0].args.should.be.deep.equal({ + expectEventInLogs(logs2, 'SignedForAffirmation', { signer: authorities[0], transactionHash: transactionHash2 - }); - logs2[1].event.should.be.equal("AffirmationCompleted"); - logs2[1].args.should.be.deep.equal({ + }) + expectEventInLogs(logs2, 'AffirmationCompleted', { recipient, value, transactionHash: transactionHash2 }) - const transactionHash3 = "0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712"; - const { logs: logs3 } = await homeBridge.executeAffirmation(recipient, value, transactionHash3, {from: authorities[0]}).should.be.fulfilled; + const transactionHash3 = '0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712' + const { logs: logs3 } = await homeBridge.executeAffirmation(recipient, value, transactionHash3, { + from: authorities[0] + }).should.be.fulfilled - logs3[0].event.should.be.equal("AmountLimitExceeded"); - logs3[0].args.should.be.deep.equal({ + expectEventInLogs(logs3, 'AmountLimitExceeded', { recipient, value, transactionHash: transactionHash3 - }); + }) const outOfLimitAmount = await homeBridge.outOfLimitAmount() outOfLimitAmount.should.be.bignumber.equal(halfEther) - const transactionHash4 = "0xc9ffe298d85ec5c515153608924b7bdcf1835539813dcc82cdbcc071170c3196"; - const { logs: logs4 } = await homeBridge.executeAffirmation(recipient, value, transactionHash4, {from: authorities[0]}).should.be.fulfilled; + const transactionHash4 = '0xc9ffe298d85ec5c515153608924b7bdcf1835539813dcc82cdbcc071170c3196' + const { logs: logs4 } = await homeBridge.executeAffirmation(recipient, value, transactionHash4, { + from: authorities[0] + }).should.be.fulfilled - logs4[0].event.should.be.equal("AmountLimitExceeded"); - logs4[0].args.should.be.deep.equal({ + expectEventInLogs(logs4, 'AmountLimitExceeded', { recipient, value, transactionHash: transactionHash4 - }); + }) - const newOutOfLimitAmount = await homeBridge.outOfLimitAmount() - newOutOfLimitAmount.should.be.bignumber.equal(oneEther) + expect(await homeBridge.outOfLimitAmount()).to.be.bignumber.equal(oneEther) }) }) describe('#isAlreadyProcessed', async () => { it('returns ', async () => { - homeBridge = await HomeBridge.new(); - const bn = new web3.BigNumber(2).pow(255); - const processedNumbers = [bn.add(1).toString(10), bn.add(100).toString(10)]; - true.should.be.equal(await homeBridge.isAlreadyProcessed(processedNumbers[0])); - true.should.be.equal(await homeBridge.isAlreadyProcessed(processedNumbers[1])); - false.should.be.equal(await homeBridge.isAlreadyProcessed(10)); + const homeBridge = await HomeBridge.new() + const bn = toBN(2).pow(toBN(255)) + const processedNumbers = [bn.add(toBN(1)).toString(10), bn.add(toBN(100)).toString(10)] + true.should.be.equal(await homeBridge.isAlreadyProcessed(processedNumbers[0])) + true.should.be.equal(await homeBridge.isAlreadyProcessed(processedNumbers[1])) + false.should.be.equal(await homeBridge.isAlreadyProcessed(10)) }) }) describe('#submitSignature', async () => { - let validatorContractWith2Signatures,authoritiesTwoAccs,ownerOfValidators,tokenPOA20,homeBridgeWithTwoSigs + let validatorContractWith2Signatures + let authoritiesThreeAccs + let ownerOfValidators + let homeBridgeWithTwoSigs beforeEach(async () => { - let token2sig = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); + const token2sig = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) validatorContractWith2Signatures = await BridgeValidators.new() - authoritiesTwoAccs = [accounts[1], accounts[2], accounts[3]]; + authoritiesThreeAccs = [accounts[1], accounts[2], accounts[3]] ownerOfValidators = accounts[0] - await validatorContractWith2Signatures.initialize(2, authoritiesTwoAccs, ownerOfValidators) - homeBridgeWithTwoSigs = await HomeBridge.new(); - await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, token2sig.address, foreignDailyLimit, foreignMaxPerTx, owner); - await token2sig.transferOwnership(homeBridgeWithTwoSigs.address); + await validatorContractWith2Signatures.initialize(2, authoritiesThreeAccs, ownerOfValidators) + homeBridgeWithTwoSigs = await HomeBridge.new() + await homeBridgeWithTwoSigs.initialize( + validatorContractWith2Signatures.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token2sig.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + await token2sig.transferOwnership(homeBridgeWithTwoSigs.address) }) it('allows a validator to submit a signature', async () => { - var recipientAccount = accounts[8] - var value = web3.toBigNumber(web3.toWei(0.5, "ether")); - var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - var message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address); - var signature = await sign(authoritiesTwoAccs[0], message) - const {logs} = await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authorities[0]}).should.be.fulfilled; + const recipientAccount = accounts[8] + const value = ether('0.5') + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address) + const signature = await sign(authoritiesThreeAccs[0], message) + const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature, message, { + from: authorities[0] + }).should.be.fulfilled logs[0].event.should.be.equal('SignedForUserRequest') const msgHashFromLog = logs[0].args.messageHash - const signatureFromContract = await homeBridgeWithTwoSigs.signature(msgHashFromLog, 0); - const messageFromContract = await homeBridgeWithTwoSigs.message(msgHashFromLog); - - signature.should.be.equal(signatureFromContract); - messageFromContract.should.be.equal(messageFromContract); - const hashMsg = Web3Utils.soliditySha3(message); - '1'.should.be.bignumber.equal(await homeBridgeWithTwoSigs.numMessagesSigned(hashMsg)) - const hashSenderMsg = Web3Utils.soliditySha3(authorities[0], hashMsg) - true.should.be.equal(await homeBridgeWithTwoSigs.messagesSigned(hashSenderMsg)); + const signatureFromContract = await homeBridgeWithTwoSigs.signature(msgHashFromLog, 0) + const messageFromContract = await homeBridgeWithTwoSigs.message(msgHashFromLog) + + signature.should.be.equal(signatureFromContract) + messageFromContract.should.be.equal(messageFromContract) + const hashMsg = web3.utils.soliditySha3(message) + expect(await homeBridgeWithTwoSigs.numMessagesSigned(hashMsg)).to.be.bignumber.equal('1') + const hashSenderMsg = web3.utils.soliditySha3(authorities[0], hashMsg) + true.should.be.equal(await homeBridgeWithTwoSigs.messagesSigned(hashSenderMsg)) }) it('when enough requiredSignatures are collected, CollectedSignatures event is emitted', async () => { - var recipientAccount = accounts[8] - var value = web3.toBigNumber(web3.toWei(0.5, "ether")); - var homeGasPrice = web3.toBigNumber(0); - var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - var message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address); - const hashMsg = Web3Utils.soliditySha3(message); - var signature = await sign(authoritiesTwoAccs[0], message) - var signature2 = await sign(authoritiesTwoAccs[1], message) - '2'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.rejectedWith(ERROR_MSG); - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[1]}).should.be.rejectedWith(ERROR_MSG); - const {logs} = await homeBridgeWithTwoSigs.submitSignature(signature2, message, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; + const recipientAccount = accounts[8] + const value = ether('0.5') + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address) + const hashMsg = web3.utils.soliditySha3(message) + const signature = await sign(authoritiesThreeAccs[0], message) + const signature2 = await sign(authoritiesThreeAccs[1], message) + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('2') + await homeBridgeWithTwoSigs.submitSignature(signature, message, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled + await homeBridgeWithTwoSigs + .submitSignature(signature, message, { from: authoritiesThreeAccs[0] }) + .should.be.rejectedWith(ERROR_MSG) + await homeBridgeWithTwoSigs + .submitSignature(signature, message, { from: authoritiesThreeAccs[1] }) + .should.be.rejectedWith(ERROR_MSG) + const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled logs.length.should.be.equal(2) logs[1].event.should.be.equal('CollectedSignatures') - logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesTwoAccs[1]) - const markedAsProcessed = new web3.BigNumber(2).pow(255).add(2); + logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesThreeAccs[1]) + const markedAsProcessed = toBN(2) + .pow(toBN(255)) + .add(toBN(2)) markedAsProcessed.should.be.bignumber.equal(await homeBridgeWithTwoSigs.numMessagesSigned(hashMsg)) }) it('works with 5 validators and 3 required signatures', async () => { @@ -432,64 +763,97 @@ contract('HomeBridge_ERC20_to_ERC20', async (accounts) => { const authoritiesFiveAccs = [accounts[1], accounts[2], accounts[3], accounts[4], accounts[5]] const validatorContractWith3Signatures = await BridgeValidators.new() await validatorContractWith3Signatures.initialize(3, authoritiesFiveAccs, ownerOfValidators) - const token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - - const homeBridgeWithThreeSigs = await HomeBridge.new(); - await homeBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner); - - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); - const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithThreeSigs.address); + const token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + + const homeBridgeWithThreeSigs = await HomeBridge.new() + await homeBridgeWithThreeSigs.initialize( + validatorContractWith3Signatures.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + + const value = ether('0.5') + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithThreeSigs.address) const signature = await sign(authoritiesFiveAccs[0], message) const signature2 = await sign(authoritiesFiveAccs[1], message) const signature3 = await sign(authoritiesFiveAccs[2], message) - '3'.should.be.bignumber.equal(await validatorContractWith3Signatures.requiredSignatures()); - - await homeBridgeWithThreeSigs.submitSignature(signature, message, {from: authoritiesFiveAccs[0]}).should.be.fulfilled; - await homeBridgeWithThreeSigs.submitSignature(signature2, message, {from: authoritiesFiveAccs[1]}).should.be.fulfilled; - const {logs} = await homeBridgeWithThreeSigs.submitSignature(signature3, message, {from: authoritiesFiveAccs[2]}).should.be.fulfilled; + expect(await validatorContractWith3Signatures.requiredSignatures()).to.be.bignumber.equal('3') + + await homeBridgeWithThreeSigs.submitSignature(signature, message, { + from: authoritiesFiveAccs[0] + }).should.be.fulfilled + await homeBridgeWithThreeSigs.submitSignature(signature2, message, { + from: authoritiesFiveAccs[1] + }).should.be.fulfilled + const { logs } = await homeBridgeWithThreeSigs.submitSignature(signature3, message, { + from: authoritiesFiveAccs[2] + }).should.be.fulfilled logs.length.should.be.equal(2) logs[1].event.should.be.equal('CollectedSignatures') logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesFiveAccs[2]) }) it('attack when increasing requiredSignatures', async () => { - var recipientAccount = accounts[8] - var value = web3.toBigNumber(web3.toWei(0.5, "ether")); - var homeGasPrice = web3.toBigNumber(0); - var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - var message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address); - var signature = await sign(authoritiesTwoAccs[0], message) - var signature2 = await sign(authoritiesTwoAccs[1], message) - var signature3 = await sign(authoritiesTwoAccs[2], message) - '2'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.rejectedWith(ERROR_MSG); - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[1]}).should.be.rejectedWith(ERROR_MSG); - const {logs} = await homeBridgeWithTwoSigs.submitSignature(signature2, message, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; + const recipientAccount = accounts[8] + const value = ether('0.5') + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address) + const signature = await sign(authoritiesThreeAccs[0], message) + const signature2 = await sign(authoritiesThreeAccs[1], message) + const signature3 = await sign(authoritiesThreeAccs[2], message) + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('2') + + await homeBridgeWithTwoSigs.submitSignature(signature, message, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled + await homeBridgeWithTwoSigs + .submitSignature(signature, message, { from: authoritiesThreeAccs[0] }) + .should.be.rejectedWith(ERROR_MSG) + await homeBridgeWithTwoSigs + .submitSignature(signature, message, { from: authoritiesThreeAccs[1] }) + .should.be.rejectedWith(ERROR_MSG) + const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled logs.length.should.be.equal(2) logs[1].event.should.be.equal('CollectedSignatures') - logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesTwoAccs[1]) - await validatorContractWith2Signatures.setRequiredSignatures(3).should.be.fulfilled; - '3'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - const attackerTx = await homeBridgeWithTwoSigs.submitSignature(signature3, message, {from: authoritiesTwoAccs[2]}).should.be.rejectedWith(ERROR_MSG); + logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesThreeAccs[1]) + await validatorContractWith2Signatures.setRequiredSignatures(3).should.be.fulfilled + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('3') + + await homeBridgeWithTwoSigs + .submitSignature(signature3, message, { from: authoritiesThreeAccs[2] }) + .should.be.rejectedWith(ERROR_MSG) }) it('attack when decreasing requiredSignatures', async () => { - var recipientAccount = accounts[8] - var value = web3.toBigNumber(web3.toWei(0.5, "ether")); - var homeGasPrice = web3.toBigNumber(0); - var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - var message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address); - var signature = await sign(authoritiesTwoAccs[0], message) - var signature2 = await sign(authoritiesTwoAccs[1], message) - var signature3 = await sign(authoritiesTwoAccs[2], message) - '2'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - await validatorContractWith2Signatures.setRequiredSignatures(1).should.be.fulfilled; - '1'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - const {logs} = await homeBridgeWithTwoSigs.submitSignature(signature2, message, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; + const recipientAccount = accounts[8] + const value = ether('0.5') + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address) + const signature = await sign(authoritiesThreeAccs[0], message) + const signature2 = await sign(authoritiesThreeAccs[1], message) + + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('2') + + await homeBridgeWithTwoSigs.submitSignature(signature, message, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled + await validatorContractWith2Signatures.setRequiredSignatures(1).should.be.fulfilled + + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('1') + const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled logs.length.should.be.equal(2) logs[1].event.should.be.equal('CollectedSignatures') - logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesTwoAccs[1]) + logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesThreeAccs[1]) }) }) @@ -500,27 +864,39 @@ contract('HomeBridge_ERC20_to_ERC20', async (accounts) => { it('should return the required message length', async () => { const requiredMessageLength = await homeContract.requiredMessageLength() - '104'.should.be.bignumber.equal(requiredMessageLength) + expect(requiredMessageLength).to.be.bignumber.equal('104') }) }) describe('#fixAssetsAboveLimits', async () => { - let homeBridge; - const zeroValue = web3.toBigNumber(web3.toWei(0, "ether")) + let homeBridge beforeEach(async () => { - const homeBridgeImpl = await HomeBridge.new(); - const storageProxy = await EternalStorageProxy.new().should.be.fulfilled; + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled - homeBridge = await HomeBridge.at(storageProxy.address); - await homeBridge.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, token.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.fulfilled + homeBridge = await HomeBridge.at(storageProxy.address) + await homeBridge.initialize( + validatorContract.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled }) it('Should reduce outOfLimitAmount and not emit any event', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const {logs: affirmationLogs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled - affirmationLogs[0].event.should.be.equal("AmountLimitExceeded"); + affirmationLogs[0].event.should.be.equal('AmountLimitExceeded') const outOfLimitAmount = await homeBridge.outOfLimitAmount() outOfLimitAmount.should.be.bignumber.equal(value) @@ -530,15 +906,17 @@ contract('HomeBridge_ERC20_to_ERC20', async (accounts) => { logs.length.should.be.equal(0) const newOutOfLimitAmount = await homeBridge.outOfLimitAmount() - newOutOfLimitAmount.should.be.bignumber.equal(zeroValue) + newOutOfLimitAmount.should.be.bignumber.equal(ZERO) }) it('Should reduce outOfLimitAmount and emit UserRequestForSignature', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const {logs: affirmationLogs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled - affirmationLogs[0].event.should.be.equal("AmountLimitExceeded"); + affirmationLogs[0].event.should.be.equal('AmountLimitExceeded') const outOfLimitAmount = await homeBridge.outOfLimitAmount() outOfLimitAmount.should.be.bignumber.equal(value) @@ -546,23 +924,26 @@ contract('HomeBridge_ERC20_to_ERC20', async (accounts) => { const { logs } = await homeBridge.fixAssetsAboveLimits(transactionHash, true).should.be.fulfilled logs.length.should.be.equal(1) - logs[0].event.should.be.equal('UserRequestForSignature') - logs[0].args.should.be.deep.equal({ + expectEventInLogs(logs, 'UserRequestForSignature', { recipient, value }) const newOutOfLimitAmount = await homeBridge.outOfLimitAmount() - newOutOfLimitAmount.should.be.bignumber.equal(zeroValue) + newOutOfLimitAmount.should.be.bignumber.equal(ZERO) }) it('Should not be allow to be called by an already fixed txHash', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const transactionHash2 = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled - await homeBridge.executeAffirmation(recipient, value, transactionHash2, {from: authorities[0]}).should.be.fulfilled + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const transactionHash2 = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash2, { + from: authorities[0] + }).should.be.fulfilled const outOfLimitAmount = await homeBridge.outOfLimitAmount() outOfLimitAmount.should.be.bignumber.equal(value.add(value)) @@ -576,42 +957,47 @@ contract('HomeBridge_ERC20_to_ERC20', async (accounts) => { await homeBridge.fixAssetsAboveLimits(transactionHash2, false).should.be.fulfilled const updatedOutOfLimitAmount = await homeBridge.outOfLimitAmount() - updatedOutOfLimitAmount.should.be.bignumber.equal(zeroValue) + updatedOutOfLimitAmount.should.be.bignumber.equal(ZERO) await homeBridge.fixAssetsAboveLimits(transactionHash2, false).should.be.rejectedWith(ERROR_MSG) }) it('Should fail if txHash didnt increase out of limit amount', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const invalidTxHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const invalidTxHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' - const {logs: affirmationLogs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled + const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled - affirmationLogs[0].event.should.be.equal("AmountLimitExceeded"); + affirmationLogs[0].event.should.be.equal('AmountLimitExceeded') await homeBridge.fixAssetsAboveLimits(invalidTxHash, true).should.be.rejectedWith(ERROR_MSG) }) it('Should fail if not called by proxyOwner', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' - const {logs: affirmationLogs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled + const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled - affirmationLogs[0].event.should.be.equal("AmountLimitExceeded"); + affirmationLogs[0].event.should.be.equal('AmountLimitExceeded') - await homeBridge.fixAssetsAboveLimits(transactionHash, true, { from: recipient}).should.be.rejectedWith(ERROR_MSG) - await homeBridge.fixAssetsAboveLimits(transactionHash, true, { from: owner}).should.be.fulfilled + await homeBridge + .fixAssetsAboveLimits(transactionHash, true, { from: recipient }) + .should.be.rejectedWith(ERROR_MSG) + await homeBridge.fixAssetsAboveLimits(transactionHash, true, { from: owner }).should.be.fulfilled }) }) describe('#OwnedUpgradeability', async () => { - it('upgradeabilityAdmin should return the proxy owner', async () => { - const homeBridgeImpl = await HomeBridge.new(); - const storageProxy = await EternalStorageProxy.new().should.be.fulfilled; + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled - const homeBridge = await HomeBridge.at(storageProxy.address); + const homeBridge = await HomeBridge.at(storageProxy.address) const proxyOwner = await storageProxy.proxyOwner() const upgradeabilityAdmin = await homeBridge.upgradeabilityAdmin() @@ -619,4 +1005,743 @@ contract('HomeBridge_ERC20_to_ERC20', async (accounts) => { upgradeabilityAdmin.should.be.equal(proxyOwner) }) }) + + describe('#rewardableInitialize', async () => { + let homeFee + let foreignFee + let homeBridge + let rewardableValidators + let blockRewardContract + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + beforeEach(async () => { + token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + rewardableValidators = await RewardableValidators.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + homeBridge = await POSDAOHomeBridge.new() + homeFee = ether('0.002') + foreignFee = ether('0.002') + blockRewardContract = await BlockReward.new() + }) + it('sets variables', async () => { + const feeManager = await FeeManagerErcToErcPOSDAO.new() + expect(await homeBridge.validatorContract()).to.be.equal(ZERO_ADDRESS) + expect(await homeBridge.deployedAtBlock()).to.be.bignumber.equal(ZERO) + expect(await homeBridge.dailyLimit()).to.be.bignumber.equal(ZERO) + expect(await homeBridge.maxPerTx()).to.be.bignumber.equal(ZERO) + expect(await homeBridge.isInitialized()).to.be.equal(false) + + await homeBridge.rewardableInitialize( + ZERO_ADDRESS, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee, + blockRewardContract.address + ).should.be.rejected + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + 0, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee, + blockRewardContract.address + ).should.be.rejected + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + 0, + foreignDailyLimit, + token.address, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee, + blockRewardContract.address + ).should.be.rejected + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + ZERO_ADDRESS, + homeFee, + foreignFee, + blockRewardContract.address + ).should.be.rejected + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee, + blockRewardContract.address + ).should.be.fulfilled + + expect(await homeBridge.isInitialized()).to.be.equal(true) + expect(await homeBridge.validatorContract()).to.be.equal(rewardableValidators.address) + expect(await homeBridge.deployedAtBlock()).to.be.bignumber.above(ZERO) + expect(await homeBridge.dailyLimit()).to.be.bignumber.equal(oneEther) + expect(await homeBridge.maxPerTx()).to.be.bignumber.equal(halfEther) + expect(await homeBridge.minPerTx()).to.be.bignumber.equal(minPerTx) + const bridgeMode = '0xba4690f5' // 4 bytes of keccak256('erc-to-erc-core') + expect(await homeBridge.getBridgeMode()).to.be.equal(bridgeMode) + const { major, minor, patch } = await homeBridge.getBridgeInterfacesVersion() + expect(major).to.be.bignumber.gte(ZERO) + expect(minor).to.be.bignumber.gte(ZERO) + expect(patch).to.be.bignumber.gte(ZERO) + + const feeManagerContract = await homeBridge.feeManagerContract() + feeManagerContract.should.be.equals(feeManager.address) + const bridgeHomeFee = await homeBridge.getHomeFee() + bridgeHomeFee.should.be.bignumber.equal(homeFee) + const bridgeForeignFee = await homeBridge.getForeignFee() + bridgeForeignFee.should.be.bignumber.equal(foreignFee) + const blockReward = await homeBridge.blockRewardContract() + blockReward.should.be.equals(blockRewardContract.address) + }) + it('can update fee contract', async () => { + const feeManager = await FeeManagerErcToErcPOSDAO.new() + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee, + blockRewardContract.address + ).should.be.fulfilled + + // Given + const newFeeManager = await FeeManagerErcToErcPOSDAO.new() + + // When + await homeBridge.setFeeManagerContract(newFeeManager.address, { from: owner }).should.be.fulfilled + + // Then + const feeManagerContract = await homeBridge.feeManagerContract() + feeManagerContract.should.be.equals(newFeeManager.address) + }) + it('can update fee', async () => { + const feeManager = await FeeManagerErcToErcPOSDAO.new() + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee, + blockRewardContract.address + ).should.be.fulfilled + + // Given + const newHomeFee = ether('0.1') + const newForeignFee = ether('0.4') + + // When + await homeBridge.setHomeFee(newHomeFee, { from: owner }).should.be.fulfilled + await homeBridge.setForeignFee(newForeignFee, { from: owner }).should.be.fulfilled + + // Then + const bridgeHomeFee = await homeBridge.getHomeFee() + const bridgeForeignFee = await homeBridge.getForeignFee() + bridgeHomeFee.should.be.bignumber.equal(newHomeFee) + bridgeForeignFee.should.be.bignumber.equal(newForeignFee) + }) + it('should be able to get fee manager mode', async () => { + // Given + const feeManager = await FeeManagerErcToErcPOSDAO.new() + const bothDirectionsModeHash = '0xd7de965f' + + // When + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee, + blockRewardContract.address + ).should.be.fulfilled + + // Then + const feeManagerMode = await homeBridge.getFeeManagerMode() + feeManagerMode.should.be.equals(bothDirectionsModeHash) + }) + it('should be able to set blockReward contract', async () => { + // Given + const feeManager = await FeeManagerErcToErcPOSDAO.new() + + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee, + blockRewardContract.address + ).should.be.fulfilled + + const blockReward = await homeBridge.blockRewardContract() + blockReward.should.be.equals(blockRewardContract.address) + + // When + const newBlockRewardContract = await BlockReward.new() + await homeBridge.setBlockRewardContract(newBlockRewardContract.address).should.be.fulfilled + + // Then + const newBlockReward = await homeBridge.blockRewardContract() + newBlockReward.should.be.equals(newBlockRewardContract.address) + }) + }) + describe('#onTokenTransfer', async () => { + let homeBridge + beforeEach(async () => { + homeBridge = await HomeBridge.new() + token = await ERC677BridgeToken.new('Some ERC20', 'TEST', 18) + }) + it('should trigger UserRequestForSignature with transfer value', async () => { + // Given + const owner = accounts[0] + const user = accounts[4] + await homeBridge.initialize( + validatorContract.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + const value = halfEther + await token.mint(user, value, { from: owner }).should.be.fulfilled + + // When + await token.transferAndCall(homeBridge.address, value, '0x00', { from: user }).should.be.fulfilled + + // Then + const events = await getEvents(homeBridge, { event: 'UserRequestForSignature' }) + expect(events[0].returnValues.recipient).to.be.equal(user) + expect(toBN(events[0].returnValues.value)).to.be.bignumber.equal(value) + }) + it('should trigger UserRequestForSignature with fee subtracted', async () => { + // Given + const homeBridge = await POSDAOHomeBridge.new() + const owner = accounts[0] + const user = accounts[4] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + const blockRewardContract = await BlockReward.new() + const rewardableValidators = await RewardableValidators.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + const feeManager = await FeeManagerErcToErcPOSDAO.new() + const fee = 0.001 + const homeFee = ether('0.001') + const foreignFee = ether('0.001') + + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee, + blockRewardContract.address + ).should.be.fulfilled + const value = halfEther + const finalValueCalc = 0.5 * (1 - fee) + const finalValue = ether(finalValueCalc.toString()) + await token.mint(user, value, { from: owner }).should.be.fulfilled + + // When + await token.transferAndCall(homeBridge.address, value, '0x00', { from: user }).should.be.fulfilled + + // Then + const events = await getEvents(homeBridge, { event: 'UserRequestForSignature' }) + expect(events[0].returnValues.recipient).to.be.equal(user) + expect(toBN(events[0].returnValues.value)).to.be.bignumber.equal(finalValue) + }) + }) + describe('#rewardable_submitSignatures', () => { + let fee + let homeFee + let foreignFee + let homeBridge + let rewardableValidators + let blockRewardContract + let feeManager + beforeEach(async () => { + token = await ERC677BridgeTokenRewardable.new('Some ERC20', 'RSZT', 18) + rewardableValidators = await RewardableValidators.new() + feeManager = await FeeManagerErcToErcPOSDAO.new() + homeBridge = await POSDAOHomeBridge.new() + fee = 0.001 + homeFee = ether(fee.toString()) + foreignFee = ether(fee.toString()) + blockRewardContract = await BlockReward.new() + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee, + blockRewardContract.address + ).should.be.fulfilled + }) + it('should distribute fee to one validator', async () => { + // Given + const recipient = accounts[9] + const owner = accounts[0] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + await blockRewardContract.setValidatorsRewards(rewards) + await blockRewardContract.setToken(token.address) + await token.setBlockRewardContract(blockRewardContract.address, { from: owner }) + await token.transferOwnership(homeBridge.address, { from: owner }) + + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipient, value, transactionHash, homeBridge.address) + const signature = await sign(validators[0], message) + + const rewardAddressBalanceBefore = await token.balanceOf(rewards[0]) + rewardAddressBalanceBefore.should.be.bignumber.equal('0') + + // When + const { logs } = await homeBridge.submitSignature(signature, message, { from: validators[0] }).should.be.fulfilled + + // Then + logs.length.should.be.equal(3) + logs[1].event.should.be.equal('CollectedSignatures') + expectEventInLogs(logs, 'FeeDistributedFromSignatures', { + feeAmount, + transactionHash + }) + + const finalBridgeBalance = await token.balanceOf(homeBridge.address) + finalBridgeBalance.should.be.bignumber.equal('0') + + const feeDistributed = await blockRewardContract.feeAmount() + feeDistributed.should.be.bignumber.equal(feeAmount) + + const rewardAddressBalanceAfter = await token.balanceOf(rewards[0]) + rewardAddressBalanceAfter.should.be.bignumber.equal(feeAmount) + }) + it('should distribute fee to 3 validators', async () => { + // Given + const recipient = accounts[8] + const owner = accounts[9] + const validators = [accounts[1], accounts[2], accounts[3]] + const rewards = [accounts[4], accounts[5], accounts[6]] + const requiredSignatures = 2 + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + await blockRewardContract.setValidatorsRewards(rewards) + await blockRewardContract.setToken(token.address) + await token.setBlockRewardContract(blockRewardContract.address) + await token.transferOwnership(homeBridge.address) + + const calcValue = 0.5 * (1 - fee) + const value = ether(calcValue.toString()) + const calcFeeAmount = 0.5 * fee + const feeAmount = ether(calcFeeAmount.toString()) + const feePerValidator = toBN(166666666666666) + const feePerValidatorPlusDiff = toBN(166666666666668) + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipient, value, transactionHash, homeBridge.address) + const signature = await sign(validators[0], message) + const signature2 = await sign(validators[1], message) + + // When + await homeBridge.submitSignature(signature, message, { from: validators[0] }).should.be.fulfilled + const { logs } = await homeBridge.submitSignature(signature2, message, { + from: validators[1] + }).should.be.fulfilled + + // Then + logs.length.should.be.equal(3) + logs[1].event.should.be.equal('CollectedSignatures') + expectEventInLogs(logs, 'FeeDistributedFromSignatures', { + feeAmount, + transactionHash + }) + + const finalBridgeBalance = await token.balanceOf(homeBridge.address) + finalBridgeBalance.should.be.bignumber.equal('0') + + const feeDistributed = await blockRewardContract.feeAmount() + feeDistributed.should.be.bignumber.equal(feeAmount) + + const balanceRewardAddress1 = await token.balanceOf(rewards[0]) + const balanceRewardAddress2 = await token.balanceOf(rewards[1]) + const balanceRewardAddress3 = await token.balanceOf(rewards[2]) + + expect(balanceRewardAddress1.eq(feePerValidator) || balanceRewardAddress1.eq(feePerValidatorPlusDiff)).to.equal( + true + ) + expect(balanceRewardAddress2.eq(feePerValidator) || balanceRewardAddress2.eq(feePerValidatorPlusDiff)).to.equal( + true + ) + expect(balanceRewardAddress3.eq(feePerValidator) || balanceRewardAddress3.eq(feePerValidatorPlusDiff)).to.equal( + true + ) + }) + it('should distribute fee to 5 validators', async () => { + // Given + const recipient = accounts[0] + const owner = accounts[0] + const validators = [accounts[0], accounts[1], accounts[2], accounts[3], accounts[4]] + const rewards = [accounts[5], accounts[6], accounts[7], accounts[8], accounts[9]] + const requiredSignatures = 3 + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + await blockRewardContract.setValidatorsRewards(rewards) + await blockRewardContract.setToken(token.address) + await token.setBlockRewardContract(blockRewardContract.address) + await token.transferOwnership(homeBridge.address) + + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const feePerValidator = feeAmount.div(toBN(5)) + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipient, value, transactionHash, homeBridge.address) + const signature = await sign(validators[0], message) + const signature2 = await sign(validators[1], message) + const signature3 = await sign(validators[2], message) + + // When + await homeBridge.submitSignature(signature, message, { from: validators[0] }).should.be.fulfilled + await homeBridge.submitSignature(signature2, message, { from: validators[1] }).should.be.fulfilled + const { logs } = await homeBridge.submitSignature(signature3, message, { + from: validators[2] + }).should.be.fulfilled + + // Then + logs.length.should.be.equal(3) + logs[1].event.should.be.equal('CollectedSignatures') + expectEventInLogs(logs, 'FeeDistributedFromSignatures', { + feeAmount, + transactionHash + }) + + const finalBridgeBalance = await token.balanceOf(homeBridge.address) + finalBridgeBalance.should.be.bignumber.equal('0') + + const feeDistributed = await blockRewardContract.feeAmount() + feeDistributed.should.be.bignumber.equal(feeAmount) + + const balanceRewardAddress1 = await token.balanceOf(rewards[0]) + const balanceRewardAddress2 = await token.balanceOf(rewards[1]) + const balanceRewardAddress3 = await token.balanceOf(rewards[2]) + const balanceRewardAddress4 = await token.balanceOf(rewards[3]) + const balanceRewardAddress5 = await token.balanceOf(rewards[4]) + + balanceRewardAddress1.should.be.bignumber.equal(feePerValidator) + balanceRewardAddress2.should.be.bignumber.equal(feePerValidator) + balanceRewardAddress3.should.be.bignumber.equal(feePerValidator) + balanceRewardAddress4.should.be.bignumber.equal(feePerValidator) + balanceRewardAddress5.should.be.bignumber.equal(feePerValidator) + }) + }) + describe('#rewardable_executeAffirmation', () => { + let fee + let homeFee + let foreignFee + let homeBridge + let rewardableValidators + let blockRewardContract + let feeManager + beforeEach(async () => { + token = await ERC677BridgeTokenRewardable.new('Some ERC20', 'RSZT', 18) + rewardableValidators = await RewardableValidators.new() + feeManager = await FeeManagerErcToErcPOSDAO.new() + homeBridge = await POSDAOHomeBridge.new() + fee = 0.001 + homeFee = ether(fee.toString()) + foreignFee = ether(fee.toString()) + blockRewardContract = await BlockReward.new() + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee, + blockRewardContract.address + ).should.be.fulfilled + }) + it('should distribute fee to one validator', async () => { + // Given + const recipient = accounts[9] + const owner = accounts[0] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + await blockRewardContract.setValidatorsRewards(rewards) + await blockRewardContract.setToken(token.address) + await token.setBlockRewardContract(blockRewardContract.address) + await token.transferOwnership(homeBridge.address) + + const initialValue = halfEther + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + + const rewardAddressBalanceBefore = await token.balanceOf(rewards[0]) + rewardAddressBalanceBefore.should.be.bignumber.equal('0') + + // When + const { logs } = await homeBridge.executeAffirmation(recipient, initialValue, transactionHash, { + from: validators[0] + }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value: initialValue, + transactionHash + }) + + const feeDistributed = await blockRewardContract.feeAmount() + feeDistributed.should.be.bignumber.equal(feeAmount) + + const rewardAddressBalanceAfter = await token.balanceOf(rewards[0]) + rewardAddressBalanceAfter.should.be.bignumber.equal(feeAmount) + + const recipientBalance = await token.balanceOf(recipient) + recipientBalance.should.be.bignumber.equal(value) + }) + it('should distribute fee to 3 validators', async () => { + // Given + const recipient = accounts[8] + const owner = accounts[9] + const validators = [accounts[1], accounts[2], accounts[3]] + const rewards = [accounts[4], accounts[5], accounts[6]] + const requiredSignatures = 2 + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + await blockRewardContract.setValidatorsRewards(rewards) + await blockRewardContract.setToken(token.address) + await token.setBlockRewardContract(blockRewardContract.address) + await token.transferOwnership(homeBridge.address) + + const initialValue = halfEther + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const feePerValidator = toBN(166666666666666) + const feePerValidatorPlusDiff = toBN(166666666666668) + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + + const rewardAddressBalanceBefore = await token.balanceOf(rewards[0]) + rewardAddressBalanceBefore.should.be.bignumber.equal('0') + + // When + await homeBridge.executeAffirmation(recipient, initialValue, transactionHash, { + from: validators[0] + }).should.be.fulfilled + const { logs } = await homeBridge.executeAffirmation(recipient, initialValue, transactionHash, { + from: validators[1] + }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value: initialValue, + transactionHash + }) + + const feeDistributed = await blockRewardContract.feeAmount() + feeDistributed.should.be.bignumber.equal(feeAmount) + + const recipientBalance = await token.balanceOf(recipient) + recipientBalance.should.be.bignumber.equal(value) + + const balanceRewardAddress1 = await token.balanceOf(rewards[0]) + const balanceRewardAddress2 = await token.balanceOf(rewards[1]) + const balanceRewardAddress3 = await token.balanceOf(rewards[2]) + + expect(balanceRewardAddress1.eq(feePerValidator) || balanceRewardAddress1.eq(feePerValidatorPlusDiff)).to.equal( + true + ) + expect(balanceRewardAddress2.eq(feePerValidator) || balanceRewardAddress2.eq(feePerValidatorPlusDiff)).to.equal( + true + ) + expect(balanceRewardAddress3.eq(feePerValidator) || balanceRewardAddress3.eq(feePerValidatorPlusDiff)).to.equal( + true + ) + }) + it('should distribute fee to 5 validators', async () => { + // Given + const recipient = accounts[0] + const owner = accounts[0] + const validators = [accounts[0], accounts[1], accounts[2], accounts[3], accounts[4]] + const rewards = [accounts[5], accounts[6], accounts[7], accounts[8], accounts[9]] + const requiredSignatures = 3 + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + await blockRewardContract.setValidatorsRewards(rewards) + await blockRewardContract.setToken(token.address) + await token.setBlockRewardContract(blockRewardContract.address) + await token.transferOwnership(homeBridge.address) + + const initialValue = halfEther + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const feePerValidator = feeAmount.div(toBN(5)) + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + + const rewardAddressBalanceBefore = await token.balanceOf(rewards[0]) + rewardAddressBalanceBefore.should.be.bignumber.equal('0') + + // When + await homeBridge.executeAffirmation(recipient, initialValue, transactionHash, { + from: validators[0] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, initialValue, transactionHash, { + from: validators[1] + }).should.be.fulfilled + const { logs } = await homeBridge.executeAffirmation(recipient, initialValue, transactionHash, { + from: validators[2] + }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value: initialValue, + transactionHash + }) + + const feeDistributed = await blockRewardContract.feeAmount() + feeDistributed.should.be.bignumber.equal(feeAmount) + + const recipientBalance = await token.balanceOf(recipient) + recipientBalance.should.be.bignumber.equal(value) + + const balanceRewardAddress1 = await token.balanceOf(rewards[0]) + const balanceRewardAddress2 = await token.balanceOf(rewards[1]) + const balanceRewardAddress3 = await token.balanceOf(rewards[2]) + const balanceRewardAddress4 = await token.balanceOf(rewards[3]) + const balanceRewardAddress5 = await token.balanceOf(rewards[4]) + + balanceRewardAddress1.should.be.bignumber.equal(feePerValidator) + balanceRewardAddress2.should.be.bignumber.equal(feePerValidator) + balanceRewardAddress3.should.be.bignumber.equal(feePerValidator) + balanceRewardAddress4.should.be.bignumber.equal(feePerValidator) + balanceRewardAddress5.should.be.bignumber.equal(feePerValidator) + }) + }) }) diff --git a/test/erc_to_native/foreign_bridge.test.js b/test/erc_to_native/foreign_bridge.test.js index b11a783e1..fb40411f0 100644 --- a/test/erc_to_native/foreign_bridge.test.js +++ b/test/erc_to_native/foreign_bridge.test.js @@ -1,241 +1,365 @@ -const ForeignBridge = artifacts.require("ForeignBridgeErcToNative.sol"); -const ForeignBridgeV2 = artifacts.require("ForeignBridgeV2.sol"); -const BridgeValidators = artifacts.require("BridgeValidators.sol"); -const EternalStorageProxy = artifacts.require("EternalStorageProxy.sol"); - -const ERC677BridgeToken = artifacts.require("ERC677BridgeToken.sol"); -const { ERROR_MSG, ZERO_ADDRESS } = require('../setup'); -const { createMessage, sign, signatureToVRS } = require('../helpers/helpers'); -const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether")); -const requireBlockConfirmations = 8; -const gasPrice = web3.toWei('1', 'gwei'); -const oneEther = web3.toBigNumber(web3.toWei(1, "ether")); +const ForeignBridge = artifacts.require('ForeignBridgeErcToNative.sol') +const ForeignBridgeV2 = artifacts.require('ForeignBridgeV2.sol') +const BridgeValidators = artifacts.require('BridgeValidators.sol') +const EternalStorageProxy = artifacts.require('EternalStorageProxy.sol') +const ERC677BridgeToken = artifacts.require('ERC677BridgeToken.sol') + +const { expect } = require('chai') +const { ERROR_MSG, ZERO_ADDRESS, toBN } = require('../setup') +const { createMessage, sign, signatureToVRS, ether } = require('../helpers/helpers') + +const halfEther = ether('0.5') +const requireBlockConfirmations = 8 +const gasPrice = web3.utils.toWei('1', 'gwei') +const oneEther = ether('1') const homeDailyLimit = oneEther const homeMaxPerTx = halfEther const maxPerTx = halfEther +const ZERO = toBN(0) -contract('ForeignBridge_ERC20_to_Native', async (accounts) => { - let validatorContract, authorities, owner, token; +contract('ForeignBridge_ERC20_to_Native', async accounts => { + let validatorContract + let authorities + let owner + let token before(async () => { validatorContract = await BridgeValidators.new() - authorities = [accounts[1], accounts[2]]; + authorities = [accounts[1], accounts[2]] owner = accounts[0] await validatorContract.initialize(1, authorities, owner) }) describe('#initialize', async () => { it('should initialize', async () => { - token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - let foreignBridge = await ForeignBridge.new(); - - ZERO_ADDRESS.should.be.equal(await foreignBridge.erc20token()); - ZERO_ADDRESS.should.be.equal(await foreignBridge.validatorContract()) - '0'.should.be.bignumber.equal(await foreignBridge.deployedAtBlock()) - false.should.be.equal(await foreignBridge.isInitialized()) - '0'.should.be.bignumber.equal(await foreignBridge.requiredBlockConfirmations()) - - await foreignBridge.initialize(ZERO_ADDRESS, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(validatorContract.address, ZERO_ADDRESS, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(validatorContract.address, token.address, 0, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, 0, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(validatorContract.address, owner, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(owner, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, halfEther, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - - await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner); - - token.address.should.be.equal(await foreignBridge.erc20token()); - true.should.be.equal(await foreignBridge.isInitialized()) - validatorContract.address.should.be.equal(await foreignBridge.validatorContract()); - token.address.should.be.equal(await foreignBridge.erc20token()); - (await foreignBridge.deployedAtBlock()).should.be.bignumber.above(0); - requireBlockConfirmations.should.be.bignumber.equal(await foreignBridge.requiredBlockConfirmations()) - const contractGasPrice = await foreignBridge.gasPrice() - contractGasPrice.should.be.bignumber.equal(gasPrice) - const bridgeMode = '0x18762d46' // 4 bytes of keccak256('erc-to-erc-core') - const mode = await foreignBridge.getBridgeMode(); - mode.should.be.equal(bridgeMode) - const [major, minor, patch] = await foreignBridge.getBridgeInterfacesVersion() - major.should.be.bignumber.gte(0) - minor.should.be.bignumber.gte(0) - patch.should.be.bignumber.gte(0) + token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + const foreignBridge = await ForeignBridge.new() + + expect(await foreignBridge.erc20token()).to.be.equal(ZERO_ADDRESS) + expect(await foreignBridge.validatorContract()).to.be.equal(ZERO_ADDRESS) + expect(await foreignBridge.deployedAtBlock()).to.be.bignumber.equal(ZERO) + expect(await foreignBridge.isInitialized()).to.be.equal(false) + expect(await foreignBridge.requiredBlockConfirmations()).to.be.bignumber.equal(ZERO) + + await foreignBridge + .initialize( + ZERO_ADDRESS, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + validatorContract.address, + ZERO_ADDRESS, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + validatorContract.address, + token.address, + 0, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + validatorContract.address, + token.address, + requireBlockConfirmations, + 0, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + validatorContract.address, + owner, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + owner, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + validatorContract.address, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + halfEther, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + + await foreignBridge.initialize( + validatorContract.address, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + + expect(await foreignBridge.erc20token()).to.be.equal(token.address) + expect(await foreignBridge.isInitialized()).to.be.equal(true) + expect(await foreignBridge.validatorContract()).to.be.equal(validatorContract.address) + expect(await foreignBridge.deployedAtBlock()).to.be.bignumber.above(ZERO) + expect(await foreignBridge.requiredBlockConfirmations()).to.be.bignumber.equal( + requireBlockConfirmations.toString() + ) + expect(await foreignBridge.gasPrice()).to.be.bignumber.equal(gasPrice) + const bridgeMode = '0x18762d46' // 4 bytes of keccak256('erc-to-native-core') + expect(await foreignBridge.getBridgeMode()).to.be.equal(bridgeMode) + const { major, minor, patch } = await foreignBridge.getBridgeInterfacesVersion() + expect(major).to.be.bignumber.gte(ZERO) + expect(minor).to.be.bignumber.gte(ZERO) + expect(patch).to.be.bignumber.gte(ZERO) }) }) describe('#executeSignatures', async () => { - const value = web3.toBigNumber(web3.toWei(0.25, "ether")); + const value = ether('0.25') let foreignBridge beforeEach(async () => { foreignBridge = await ForeignBridge.new() - token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner); - await token.mint(foreignBridge.address,value); + token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + await foreignBridge.initialize( + validatorContract.address, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + await token.mint(foreignBridge.address, value) }) it('should allow to executeSignatures', async () => { - const recipientAccount = accounts[3]; + const recipientAccount = accounts[3] const balanceBefore = await token.balanceOf(recipientAccount) - const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address); + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address) const signature = await sign(authorities[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) const { logs } = await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled - logs[0].event.should.be.equal("RelayedMessage") + logs[0].event.should.be.equal('RelayedMessage') logs[0].args.recipient.should.be.equal(recipientAccount) logs[0].args.value.should.be.bignumber.equal(value) - const balanceAfter = await token.balanceOf(recipientAccount); - const balanceAfterBridge = await token.balanceOf(foreignBridge.address); + const balanceAfter = await token.balanceOf(recipientAccount) + const balanceAfterBridge = await token.balanceOf(foreignBridge.address) balanceAfter.should.be.bignumber.equal(balanceBefore.add(value)) - balanceAfterBridge.should.be.bignumber.equal(0) + balanceAfterBridge.should.be.bignumber.equal(ZERO) true.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) }) - it('should allow second withdrawal with different transactionHash but same recipient and value', async ()=> { - const recipientAccount = accounts[3]; + it('should allow second withdrawal with different transactionHash but same recipient and value', async () => { + const recipientAccount = accounts[3] const balanceBefore = await token.balanceOf(recipientAccount) // tx 1 - const value = web3.toBigNumber(web3.toWei(0.25, "ether")); - const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address); + const value = ether('0.25') + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address) const signature = await sign(authorities[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled // tx 2 - await token.mint(foreignBridge.address,value); - var transactionHash2 = "0x77a496628a776a03d58d7e6059a5937f04bebd8ba4ff89f76dd4bb8ba7e291ee"; - var message2 = createMessage(recipientAccount, value, transactionHash2, foreignBridge.address); - var signature2 = await sign(authorities[0], message2) - var vrs2 = signatureToVRS(signature2); + await token.mint(foreignBridge.address, value) + const transactionHash2 = '0x77a496628a776a03d58d7e6059a5937f04bebd8ba4ff89f76dd4bb8ba7e291ee' + const message2 = createMessage(recipientAccount, value, transactionHash2, foreignBridge.address) + const signature2 = await sign(authorities[0], message2) + const vrs2 = signatureToVRS(signature2) false.should.be.equal(await foreignBridge.relayedMessages(transactionHash2)) - const {logs} = await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.fulfilled + const { logs } = await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.fulfilled - logs[0].event.should.be.equal("RelayedMessage") + logs[0].event.should.be.equal('RelayedMessage') logs[0].args.recipient.should.be.equal(recipientAccount) logs[0].args.value.should.be.bignumber.equal(value) const balanceAfter = await token.balanceOf(recipientAccount) - balanceAfter.should.be.bignumber.equal(balanceBefore.add(value.mul(2))) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(value.mul(toBN(2)))) true.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) true.should.be.equal(await foreignBridge.relayedMessages(transactionHash2)) }) it('should not allow second withdraw (replay attack) with same transactionHash but different recipient', async () => { - const recipientAccount = accounts[3]; + const recipientAccount = accounts[3] // tx 1 - const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address); + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address) const signature = await sign(authorities[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled // tx 2 - await token.mint(foreignBridge.address,value); - const message2 = createMessage(accounts[4], value, transactionHash, foreignBridge.address); + await token.mint(foreignBridge.address, value) + const message2 = createMessage(accounts[4], value, transactionHash, foreignBridge.address) const signature2 = await sign(authorities[0], message2) - const vrs2 = signatureToVRS(signature2); + const vrs2 = signatureToVRS(signature2) true.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.rejectedWith(ERROR_MSG) }) it('should not allow withdraw over home max tx limit', async () => { - const recipientAccount = accounts[3]; - const invalidValue = web3.toBigNumber(web3.toWei(0.75, "ether")); - await token.mint(foreignBridge.address, web3.toBigNumber(web3.toWei(5, "ether"))); + const recipientAccount = accounts[3] + const invalidValue = ether('0.75') + await token.mint(foreignBridge.address, ether('5')) - const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const message = createMessage(recipientAccount, invalidValue, transactionHash, foreignBridge.address); + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, invalidValue, transactionHash, foreignBridge.address) const signature = await sign(authorities[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.rejectedWith(ERROR_MSG) }) it('should not allow withdraw over daily home limit', async () => { - const recipientAccount = accounts[3]; - await token.mint(foreignBridge.address, web3.toBigNumber(web3.toWei(5, "ether"))); + const recipientAccount = accounts[3] + await token.mint(foreignBridge.address, ether('5')) - const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const message = createMessage(recipientAccount, halfEther, transactionHash, foreignBridge.address); + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, halfEther, transactionHash, foreignBridge.address) const signature = await sign(authorities[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled - const transactionHash2 = "0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712"; - const message2 = createMessage(recipientAccount, halfEther, transactionHash2, foreignBridge.address); + const transactionHash2 = '0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712' + const message2 = createMessage(recipientAccount, halfEther, transactionHash2, foreignBridge.address) const signature2 = await sign(authorities[0], message2) - const vrs2 = signatureToVRS(signature2); + const vrs2 = signatureToVRS(signature2) await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.fulfilled - const transactionHash3 = "0x022695428093bb292db8e48bd1417c5e1b84c0bf673bd0fff23ed0fb6495b872"; - const message3 = createMessage(recipientAccount, halfEther, transactionHash3, foreignBridge.address); + const transactionHash3 = '0x022695428093bb292db8e48bd1417c5e1b84c0bf673bd0fff23ed0fb6495b872' + const message3 = createMessage(recipientAccount, halfEther, transactionHash3, foreignBridge.address) const signature3 = await sign(authorities[0], message3) - const vrs3 = signatureToVRS(signature3); + const vrs3 = signatureToVRS(signature3) await foreignBridge.executeSignatures([vrs3.v], [vrs3.r], [vrs3.s], message3).should.be.rejectedWith(ERROR_MSG) }) }) describe('#withdraw with 2 minimum signatures', async () => { - let multisigValidatorContract, twoAuthorities, ownerOfValidatorContract, foreignBridgeWithMultiSignatures - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); + let multisigValidatorContract + let twoAuthorities + let ownerOfValidatorContract + let foreignBridgeWithMultiSignatures + const value = halfEther beforeEach(async () => { multisigValidatorContract = await BridgeValidators.new() - token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - twoAuthorities = [accounts[0], accounts[1]]; + token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + twoAuthorities = [accounts[0], accounts[1]] ownerOfValidatorContract = accounts[3] - await multisigValidatorContract.initialize(2, twoAuthorities, ownerOfValidatorContract, {from: ownerOfValidatorContract}) + await multisigValidatorContract.initialize(2, twoAuthorities, ownerOfValidatorContract, { + from: ownerOfValidatorContract + }) foreignBridgeWithMultiSignatures = await ForeignBridge.new() - await foreignBridgeWithMultiSignatures.initialize(multisigValidatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner, {from: ownerOfValidatorContract}); - await token.mint(foreignBridgeWithMultiSignatures.address,value); + await foreignBridgeWithMultiSignatures.initialize( + multisigValidatorContract.address, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner, + { from: ownerOfValidatorContract } + ) + await token.mint(foreignBridgeWithMultiSignatures.address, value) }) it('withdraw should fail if not enough signatures are provided', async () => { - const recipientAccount = accounts[4]; + const recipientAccount = accounts[4] // msg 1 - const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address); + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address) const signature = await sign(twoAuthorities[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridgeWithMultiSignatures.relayedMessages(transactionHash)) - await foreignBridgeWithMultiSignatures.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.rejectedWith(ERROR_MSG) + await foreignBridgeWithMultiSignatures + .executeSignatures([vrs.v], [vrs.r], [vrs.s], message) + .should.be.rejectedWith(ERROR_MSG) // msg 2 const signature2 = await sign(twoAuthorities[1], message) - const vrs2 = signatureToVRS(signature2); + const vrs2 = signatureToVRS(signature2) - const {logs} = await foreignBridgeWithMultiSignatures.executeSignatures([vrs.v, vrs2.v], [vrs.r, vrs2.r], [vrs.s, vrs2.s], message).should.be.fulfilled; + const { logs } = await foreignBridgeWithMultiSignatures.executeSignatures( + [vrs.v, vrs2.v], + [vrs.r, vrs2.r], + [vrs.s, vrs2.s], + message + ).should.be.fulfilled - logs[0].event.should.be.equal("RelayedMessage") + logs[0].event.should.be.equal('RelayedMessage') logs[0].args.recipient.should.be.equal(recipientAccount) logs[0].args.value.should.be.bignumber.equal(value) true.should.be.equal(await foreignBridgeWithMultiSignatures.relayedMessages(transactionHash)) }) it('withdraw should fail if duplicate signature is provided', async () => { - const recipientAccount = accounts[4]; - const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address); + const recipientAccount = accounts[4] + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address) const signature = await sign(twoAuthorities[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridgeWithMultiSignatures.relayedMessages(transactionHash)) - await foreignBridgeWithMultiSignatures.executeSignatures([vrs.v, vrs.v], [vrs.r, vrs.r], [vrs.s, vrs.s], message).should.be.rejectedWith(ERROR_MSG) + await foreignBridgeWithMultiSignatures + .executeSignatures([vrs.v, vrs.v], [vrs.r, vrs.r], [vrs.s, vrs.s], message) + .should.be.rejectedWith(ERROR_MSG) }) it('works with 5 validators and 3 required signatures', async () => { const recipient = accounts[8] @@ -243,31 +367,44 @@ contract('ForeignBridge_ERC20_to_Native', async (accounts) => { const ownerOfValidators = accounts[0] const validatorContractWith3Signatures = await BridgeValidators.new() await validatorContractWith3Signatures.initialize(3, authoritiesFiveAccs, ownerOfValidators) - const erc20Token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); + const erc20Token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + const value = halfEther const foreignBridgeWithThreeSigs = await ForeignBridge.new() - await foreignBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, erc20Token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner); - await erc20Token.mint(foreignBridgeWithThreeSigs.address, value); - - const txHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const message = createMessage(recipient, value, txHash, foreignBridgeWithThreeSigs.address); + await foreignBridgeWithThreeSigs.initialize( + validatorContractWith3Signatures.address, + erc20Token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + await erc20Token.mint(foreignBridgeWithThreeSigs.address, value) + + const txHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipient, value, txHash, foreignBridgeWithThreeSigs.address) // signature 1 const signature = await sign(authoritiesFiveAccs[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) // signature 2 const signature2 = await sign(authoritiesFiveAccs[1], message) - const vrs2 = signatureToVRS(signature2); + const vrs2 = signatureToVRS(signature2) // signature 3 const signature3 = await sign(authoritiesFiveAccs[2], message) - const vrs3 = signatureToVRS(signature3); - - - const {logs} = await foreignBridgeWithThreeSigs.executeSignatures([vrs.v, vrs2.v, vrs3.v], [vrs.r, vrs2.r, vrs3.r], [vrs.s, vrs2.s, vrs3.s], message).should.be.fulfilled; - logs[0].event.should.be.equal("RelayedMessage") + const vrs3 = signatureToVRS(signature3) + + const { logs } = await foreignBridgeWithThreeSigs.executeSignatures( + [vrs.v, vrs2.v, vrs3.v], + [vrs.r, vrs2.r, vrs3.r], + [vrs.s, vrs2.s, vrs3.s], + message + ).should.be.fulfilled + logs[0].event.should.be.equal('RelayedMessage') logs[0].args.recipient.should.be.equal(recipient) logs[0].args.value.should.be.bignumber.equal(value) true.should.be.equal(await foreignBridgeWithThreeSigs.relayedMessages(txHash)) @@ -278,30 +415,39 @@ contract('ForeignBridge_ERC20_to_Native', async (accounts) => { it('can be upgraded', async () => { const REQUIRED_NUMBER_OF_VALIDATORS = 1 const VALIDATORS = [accounts[1]] - const PROXY_OWNER = accounts[0] + const PROXY_OWNER = accounts[0] // Validators Contract - let validatorsProxy = await EternalStorageProxy.new().should.be.fulfilled; - const validatorsContractImpl = await BridgeValidators.new().should.be.fulfilled; - await validatorsProxy.upgradeTo('1', validatorsContractImpl.address).should.be.fulfilled; + let validatorsProxy = await EternalStorageProxy.new().should.be.fulfilled + const validatorsContractImpl = await BridgeValidators.new().should.be.fulfilled + await validatorsProxy.upgradeTo('1', validatorsContractImpl.address).should.be.fulfilled validatorsContractImpl.address.should.be.equal(await validatorsProxy.implementation()) - validatorsProxy = await BridgeValidators.at(validatorsProxy.address); - await validatorsProxy.initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, PROXY_OWNER).should.be.fulfilled; - let token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); + validatorsProxy = await BridgeValidators.at(validatorsProxy.address) + await validatorsProxy.initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, PROXY_OWNER).should.be.fulfilled + const token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) // ForeignBridge V1 Contract - let foreignBridgeProxy = await EternalStorageProxy.new().should.be.fulfilled; - const foreignBridgeImpl = await ForeignBridge.new().should.be.fulfilled; - await foreignBridgeProxy.upgradeTo('1', foreignBridgeImpl.address).should.be.fulfilled; - - foreignBridgeProxy = await ForeignBridge.at(foreignBridgeProxy.address); - await foreignBridgeProxy.initialize(validatorsProxy.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner) + let foreignBridgeProxy = await EternalStorageProxy.new().should.be.fulfilled + const foreignBridgeImpl = await ForeignBridge.new().should.be.fulfilled + await foreignBridgeProxy.upgradeTo('1', foreignBridgeImpl.address).should.be.fulfilled + + foreignBridgeProxy = await ForeignBridge.at(foreignBridgeProxy.address) + await foreignBridgeProxy.initialize( + validatorsProxy.address, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) // Deploy V2 - let foreignImplV2 = await ForeignBridgeV2.new(); - let foreignBridgeProxyUpgrade = await EternalStorageProxy.at(foreignBridgeProxy.address); - await foreignBridgeProxyUpgrade.upgradeTo('2', foreignImplV2.address).should.be.fulfilled; + const foreignImplV2 = await ForeignBridgeV2.new() + const foreignBridgeProxyUpgrade = await EternalStorageProxy.at(foreignBridgeProxy.address) + await foreignBridgeProxyUpgrade.upgradeTo('2', foreignImplV2.address).should.be.fulfilled foreignImplV2.address.should.be.equal(await foreignBridgeProxyUpgrade.implementation()) }) @@ -309,40 +455,51 @@ contract('ForeignBridge_ERC20_to_Native', async (accounts) => { const tokenAddress = token.address const validatorsAddress = validatorContract.address - const storageProxy = await EternalStorageProxy.new().should.be.fulfilled; - const foreignBridge = await ForeignBridge.new(); - const data = foreignBridge.initialize.request(validatorsAddress, tokenAddress, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner).params[0].data + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + const foreignBridge = await ForeignBridge.new() + const data = foreignBridge.contract.methods + .initialize(validatorsAddress, tokenAddress, requireBlockConfirmations, gasPrice, '2', '3', '2', owner) + .encodeABI() - await storageProxy.upgradeToAndCall('1', foreignBridge.address, data).should.be.fulfilled; + await storageProxy.upgradeToAndCall('1', foreignBridge.address, data).should.be.fulfilled - let finalContract = await ForeignBridge.at(storageProxy.address); - true.should.be.equal(await finalContract.isInitialized()); + const finalContract = await ForeignBridge.at(storageProxy.address) + true.should.be.equal(await finalContract.isInitialized()) validatorsAddress.should.be.equal(await finalContract.validatorContract()) }) }) describe('#claimTokens', async () => { it('can send erc20', async () => { - const owner = accounts[0]; - token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18); - const foreignBridgeImpl = await ForeignBridge.new(); - const storageProxy = await EternalStorageProxy.new().should.be.fulfilled; + const owner = accounts[0] + token = await ERC677BridgeToken.new('Some ERC20', 'RSZT', 18) + const foreignBridgeImpl = await ForeignBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled await storageProxy.upgradeTo('1', foreignBridgeImpl.address).should.be.fulfilled - const foreignBridge = await ForeignBridge.at(storageProxy.address); - - await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, owner); - const tokenSecond = await ERC677BridgeToken.new("Roman Token", "RST", 18); - - await tokenSecond.mint(accounts[0], halfEther).should.be.fulfilled; - halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[0])) - - await tokenSecond.transfer(foreignBridge.address, halfEther); - '0'.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[0])) - halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(foreignBridge.address)) - - await foreignBridge.claimTokens(tokenSecond.address, accounts[3], {from: owner}); - '0'.should.be.bignumber.equal(await tokenSecond.balanceOf(foreignBridge.address)) - halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[3])) + const foreignBridge = await ForeignBridge.at(storageProxy.address) + + await foreignBridge.initialize( + validatorContract.address, + token.address, + requireBlockConfirmations, + gasPrice, + maxPerTx, + homeDailyLimit, + homeMaxPerTx, + owner + ) + const tokenSecond = await ERC677BridgeToken.new('Roman Token', 'RST', 18) + + await tokenSecond.mint(accounts[0], halfEther).should.be.fulfilled + expect(await tokenSecond.balanceOf(accounts[0])).to.be.bignumber.equal(halfEther) + + await tokenSecond.transfer(foreignBridge.address, halfEther) + expect(await tokenSecond.balanceOf(accounts[0])).to.be.bignumber.equal(ZERO) + expect(await tokenSecond.balanceOf(foreignBridge.address)).to.be.bignumber.equal(halfEther) + + await foreignBridge.claimTokens(tokenSecond.address, accounts[3], { from: owner }) + expect(await tokenSecond.balanceOf(foreignBridge.address)).to.be.bignumber.equal(ZERO) + expect(await tokenSecond.balanceOf(accounts[3])).to.be.bignumber.equal(halfEther) }) }) }) diff --git a/test/erc_to_native/home_bridge.test.js b/test/erc_to_native/home_bridge.test.js index 9660f7b2d..25b59bc76 100644 --- a/test/erc_to_native/home_bridge.test.js +++ b/test/erc_to_native/home_bridge.test.js @@ -1,21 +1,30 @@ -const Web3Utils = require('web3-utils') const HomeBridge = artifacts.require('HomeBridgeErcToNative.sol') const EternalStorageProxy = artifacts.require('EternalStorageProxy.sol') const BridgeValidators = artifacts.require('BridgeValidators.sol') const BlockReward = artifacts.require('BlockReward') -const {ERROR_MSG, ZERO_ADDRESS} = require('../setup'); -const {createMessage, sign } = require('../helpers/helpers'); -const minPerTx = web3.toBigNumber(web3.toWei(0.01, "ether")); -const requireBlockConfirmations = 8; -const gasPrice = Web3Utils.toWei('1', 'gwei'); -const oneEther = web3.toBigNumber(web3.toWei(1, "ether")); -const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether")); +const RewardableValidators = artifacts.require('RewardableValidators.sol') +const FeeManagerErcToNative = artifacts.require('FeeManagerErcToNative.sol') +const FeeManagerErcToNativePOSDAO = artifacts.require('FeeManagerErcToNativePOSDAO') + +const { expect } = require('chai') +const { ERROR_MSG, ZERO_ADDRESS, toBN } = require('../setup') +const { createMessage, sign, ether, expectEventInLogs } = require('../helpers/helpers') + +const minPerTx = ether('0.01') +const requireBlockConfirmations = 8 +const gasPrice = web3.utils.toWei('1', 'gwei') +const oneEther = ether('1') +const halfEther = ether('0.5') const foreignDailyLimit = oneEther const foreignMaxPerTx = halfEther - - -contract('HomeBridge_ERC20_to_Native', async (accounts) => { - let homeContract, validatorContract, blockRewardContract, authorities, owner; +const ZERO = toBN(0) + +contract('HomeBridge_ERC20_to_Native', async accounts => { + let homeContract + let validatorContract + let blockRewardContract + let authorities + let owner before(async () => { validatorContract = await BridgeValidators.new() blockRewardContract = await BlockReward.new() @@ -24,42 +33,62 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { await validatorContract.initialize(1, authorities, owner) }) - describe('#initialize', async() => { + describe('#initialize', async () => { beforeEach(async () => { homeContract = await HomeBridge.new() }) it('sets variables', async () => { - ZERO_ADDRESS.should.be.equal(await homeContract.validatorContract()) - '0'.should.be.bignumber.equal(await homeContract.deployedAtBlock()) - '0'.should.be.bignumber.equal(await homeContract.dailyLimit()) - '0'.should.be.bignumber.equal(await homeContract.maxPerTx()) - false.should.be.equal(await homeContract.isInitialized()) - ZERO_ADDRESS.should.be.equal(await homeContract.blockRewardContract()) - - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.fulfilled - - true.should.be.equal(await homeContract.isInitialized()) - validatorContract.address.should.be.equal(await homeContract.validatorContract()) - blockRewardContract.address.should.be.equal(await homeContract.blockRewardContract()); - (await homeContract.deployedAtBlock()).should.be.bignumber.above(0) - '3'.should.be.bignumber.equal(await homeContract.dailyLimit()) - '2'.should.be.bignumber.equal(await homeContract.maxPerTx()) - '1'.should.be.bignumber.equal(await homeContract.minPerTx()) - const contractGasPrice = await homeContract.gasPrice() - contractGasPrice.should.be.bignumber.equal(gasPrice) + expect(await homeContract.validatorContract()).to.be.equal(ZERO_ADDRESS) + expect(await homeContract.deployedAtBlock()).to.be.bignumber.equal(ZERO) + expect(await homeContract.dailyLimit()).to.be.bignumber.equal(ZERO) + expect(await homeContract.maxPerTx()).to.be.bignumber.equal(ZERO) + expect(await homeContract.isInitialized()).to.be.equal(false) + expect(await homeContract.blockRewardContract()).to.be.equal(ZERO_ADDRESS) + + await homeContract.initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + + expect(await homeContract.isInitialized()).to.be.equal(true) + expect(await homeContract.validatorContract()).to.be.equal(validatorContract.address) + expect(await homeContract.deployedAtBlock()).to.be.bignumber.above(ZERO) + expect(await homeContract.dailyLimit()).to.be.bignumber.equal('3') + expect(await homeContract.maxPerTx()).to.be.bignumber.equal('2') + expect(await homeContract.minPerTx()).to.be.bignumber.equal('1') + expect(await homeContract.blockRewardContract()).to.be.equal(blockRewardContract.address) + expect(await homeContract.gasPrice()).to.be.bignumber.equal(gasPrice) const bridgeMode = '0x18762d46' // 4 bytes of keccak256('erc-to-native-core') - const mode = await homeContract.getBridgeMode(); - mode.should.be.equal(bridgeMode) - const [major, minor, patch] = await homeContract.getBridgeInterfacesVersion() - major.should.be.bignumber.gte(0) - minor.should.be.bignumber.gte(0) - patch.should.be.bignumber.gte(0) + expect(await homeContract.getBridgeMode()).to.be.equal(bridgeMode) + const { major, minor, patch } = await homeContract.getBridgeInterfacesVersion() + expect(major).to.be.bignumber.gte(ZERO) + expect(minor).to.be.bignumber.gte(ZERO) + expect(patch).to.be.bignumber.gte(ZERO) }) it('can update block reward contract', async () => { ZERO_ADDRESS.should.be.equal(await homeContract.blockRewardContract()) - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.fulfilled + await homeContract.initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled blockRewardContract.address.should.be.equal(await homeContract.blockRewardContract()) @@ -68,7 +97,9 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { secondBlockRewardContract.address.should.be.equal(await homeContract.blockRewardContract()) const thirdBlockRewardContract = await BlockReward.new() - await homeContract.setBlockRewardContract(thirdBlockRewardContract.address, {from: accounts[4]}).should.be.rejectedWith(ERROR_MSG) + await homeContract + .setBlockRewardContract(thirdBlockRewardContract.address, { from: accounts[4] }) + .should.be.rejectedWith(ERROR_MSG) secondBlockRewardContract.address.should.be.equal(await homeContract.blockRewardContract()) const notAContract = accounts[5] @@ -82,131 +113,509 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { it('cant set maxPerTx > dailyLimit', async () => { false.should.be.equal(await homeContract.isInitialized()) - await homeContract.initialize(validatorContract.address, '1', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG) - await homeContract.initialize(validatorContract.address, '3', '2', '2', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + validatorContract.address, + '1', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + validatorContract.address, + '3', + '2', + '2', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) false.should.be.equal(await homeContract.isInitialized()) }) it('can be deployed via upgradeToAndCall', async () => { - let storageProxy = await EternalStorageProxy.new().should.be.fulfilled; - let data = homeContract.initialize.request(validatorContract.address, "3", "2", "1", gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner).params[0].data + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + const data = homeContract.contract.methods + .initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + '3', + '2', + owner + ) + .encodeABI() await storageProxy.upgradeToAndCall('1', homeContract.address, data).should.be.fulfilled - let finalContract = await HomeBridge.at(storageProxy.address); - - true.should.be.equal(await finalContract.isInitialized()) - validatorContract.address.should.be.equal(await finalContract.validatorContract()) - blockRewardContract.address.should.be.equal(await finalContract.blockRewardContract()) - "3".should.be.bignumber.equal(await finalContract.dailyLimit()) - "2".should.be.bignumber.equal(await finalContract.maxPerTx()) - "1".should.be.bignumber.equal(await finalContract.minPerTx()) + const finalContract = await HomeBridge.at(storageProxy.address) + + expect(await finalContract.isInitialized()).to.be.equal(true) + expect(await finalContract.validatorContract()).to.be.equal(validatorContract.address) + expect(await finalContract.dailyLimit()).to.be.bignumber.equal('3') + expect(await finalContract.maxPerTx()).to.be.bignumber.equal('2') + expect(await finalContract.minPerTx()).to.be.bignumber.equal('1') + expect(await finalContract.blockRewardContract()).to.be.equal(blockRewardContract.address) }) it('can be upgraded keeping the state', async () => { const homeOwner = accounts[8] - const storageProxy = await EternalStorageProxy.new().should.be.fulfilled; + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled const proxyOwner = await storageProxy.proxyOwner() - const data = homeContract.initialize.request(validatorContract.address, "3", "2", "1", gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, homeOwner).params[0].data + const data = homeContract.contract.methods + .initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + '3', + '2', + homeOwner + ) + .encodeABI() await storageProxy.upgradeToAndCall('1', homeContract.address, data).should.be.fulfilled - const finalContract = await HomeBridge.at(storageProxy.address); - - true.should.be.equal(await finalContract.isInitialized()) - validatorContract.address.should.be.equal(await finalContract.validatorContract()) - blockRewardContract.address.should.be.equal(await finalContract.blockRewardContract()) - "3".should.be.bignumber.equal(await finalContract.dailyLimit()) - "2".should.be.bignumber.equal(await finalContract.maxPerTx()) - "1".should.be.bignumber.equal(await finalContract.minPerTx()) - const upgradeabilityAdmin = await finalContract.upgradeabilityAdmin() - upgradeabilityAdmin.should.be.equal(proxyOwner) + const finalContract = await HomeBridge.at(storageProxy.address) + + expect(await finalContract.isInitialized()).to.be.equal(true) + expect(await finalContract.validatorContract()).to.be.equal(validatorContract.address) + expect(await finalContract.dailyLimit()).to.be.bignumber.equal('3') + expect(await finalContract.maxPerTx()).to.be.bignumber.equal('2') + expect(await finalContract.minPerTx()).to.be.bignumber.equal('1') + expect(await finalContract.blockRewardContract()).to.be.equal(blockRewardContract.address) + expect(await finalContract.upgradeabilityAdmin()).to.be.equal(proxyOwner) const homeContractV2 = await HomeBridge.new() await storageProxy.upgradeTo('2', homeContractV2.address).should.be.fulfilled - const finalContractV2 = await HomeBridge.at(storageProxy.address); + const finalContractV2 = await HomeBridge.at(storageProxy.address) + + expect(await finalContractV2.isInitialized()).to.be.equal(true) + expect(await finalContractV2.validatorContract()).to.be.equal(validatorContract.address) + expect(await finalContractV2.dailyLimit()).to.be.bignumber.equal('3') + expect(await finalContractV2.maxPerTx()).to.be.bignumber.equal('2') + expect(await finalContractV2.minPerTx()).to.be.bignumber.equal('1') + expect(await finalContractV2.blockRewardContract()).to.be.equal(blockRewardContract.address) + expect(await finalContractV2.upgradeabilityAdmin()).to.be.equal(proxyOwner) + }) + it('cant initialize with invalid arguments', async () => { + false.should.be.equal(await homeContract.isInitialized()) + await homeContract + .initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + 0, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + owner, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + ZERO_ADDRESS, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + owner, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + halfEther, + oneEther, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract.initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + true.should.be.equal(await homeContract.isInitialized()) + }) + }) - validatorContract.address.should.be.equal(await finalContractV2.validatorContract()) - blockRewardContract.address.should.be.equal(await finalContractV2.blockRewardContract()) - "3".should.be.bignumber.equal(await finalContractV2.dailyLimit()) - "2".should.be.bignumber.equal(await finalContractV2.maxPerTx()) - "1".should.be.bignumber.equal(await finalContractV2.minPerTx()) - const upgradeabilityAdminV2 = await finalContractV2.upgradeabilityAdmin() - upgradeabilityAdminV2.should.be.equal(proxyOwner) + describe('#rewardableInitialize', async () => { + let feeManager + let homeFee + let foreignFee + beforeEach(async () => { + feeManager = await FeeManagerErcToNative.new() + homeContract = await HomeBridge.new() + homeFee = ether('0.001') + foreignFee = ether('0.002') + }) + it('sets variables', async () => { + expect(await homeContract.validatorContract()).to.be.equal(ZERO_ADDRESS) + expect(await homeContract.deployedAtBlock()).to.be.bignumber.equal(ZERO) + expect(await homeContract.dailyLimit()).to.be.bignumber.equal(ZERO) + expect(await homeContract.maxPerTx()).to.be.bignumber.equal(ZERO) + expect(await homeContract.isInitialized()).to.be.equal(false) + expect(await homeContract.blockRewardContract()).to.be.equal(ZERO_ADDRESS) + + await homeContract.rewardableInitialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ).should.be.fulfilled + + expect(await homeContract.isInitialized()).to.be.equal(true) + expect(await homeContract.validatorContract()).to.be.equal(validatorContract.address) + expect(await homeContract.deployedAtBlock()).to.be.bignumber.above(ZERO) + expect(await homeContract.dailyLimit()).to.be.bignumber.equal('3') + expect(await homeContract.maxPerTx()).to.be.bignumber.equal('2') + expect(await homeContract.minPerTx()).to.be.bignumber.equal('1') + expect(await homeContract.blockRewardContract()).to.be.equal(blockRewardContract.address) + expect(await homeContract.gasPrice()).to.be.bignumber.equal(gasPrice) + const bridgeMode = '0x18762d46' // 4 bytes of keccak256('erc-to-native-core') + expect(await homeContract.getBridgeMode()).to.be.equal(bridgeMode) + const { major, minor, patch } = await homeContract.getBridgeInterfacesVersion() + expect(major).to.be.bignumber.gte(ZERO) + expect(minor).to.be.bignumber.gte(ZERO) + expect(patch).to.be.bignumber.gte(ZERO) + + const feeManagerContract = await homeContract.feeManagerContract() + feeManagerContract.should.be.equals(feeManager.address) + const bridgeHomeFee = await homeContract.getHomeFee() + bridgeHomeFee.should.be.bignumber.equal(homeFee) + const bridgeForeignFee = await homeContract.getForeignFee() + bridgeForeignFee.should.be.bignumber.equal(foreignFee) }) + it('cant initialize with invalid arguments', async () => { false.should.be.equal(await homeContract.isInitialized()) - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, 0, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(owner, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(ZERO_ADDRESS, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, owner, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, halfEther, oneEther, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner).should.be.fulfilled; + await homeContract + .rewardableInitialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + 0, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .rewardableInitialize( + owner, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .rewardableInitialize( + ZERO_ADDRESS, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .rewardableInitialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + owner, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .rewardableInitialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + halfEther, + oneEther, + owner, + feeManager.address, + homeFee, + foreignFee + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .rewardableInitialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + ZERO_ADDRESS, + homeFee, + foreignFee + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract.rewardableInitialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ).should.be.fulfilled true.should.be.equal(await homeContract.isInitialized()) }) + + it('can update fee contract', async () => { + await homeContract.rewardableInitialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ).should.be.fulfilled + + // Given + const newFeeManager = await FeeManagerErcToNative.new() + + // When + await homeContract.setFeeManagerContract(newFeeManager.address, { from: owner }).should.be.fulfilled + + // Then + const feeManagerContract = await homeContract.feeManagerContract() + feeManagerContract.should.be.equals(newFeeManager.address) + }) + + it('can update fee', async () => { + await homeContract.rewardableInitialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ).should.be.fulfilled + + // Given + const newHomeFee = ether('0.1') + const newForeignFee = ether('0.2') + + // When + await homeContract.setHomeFee(newHomeFee, { from: owner }).should.be.fulfilled + await homeContract.setForeignFee(newForeignFee, { from: owner }).should.be.fulfilled + + // Then + const bridgeHomeFee = await homeContract.getHomeFee() + bridgeHomeFee.should.be.bignumber.equal(newHomeFee) + const bridgeForeignFee = await homeContract.getForeignFee() + bridgeForeignFee.should.be.bignumber.equal(newForeignFee) + }) }) describe('#fallback', async () => { beforeEach(async () => { homeContract = await HomeBridge.new() - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner) + await homeContract.initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) }) it('should accept native coins', async () => { const currentDay = await homeContract.getCurrentDay() - '0'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay)) + expect(await homeContract.totalSpentPerDay(currentDay)).to.be.bignumber.equal(ZERO) await blockRewardContract.addMintedTotallyByBridge(10, homeContract.address) const minted = await blockRewardContract.mintedTotallyByBridge(homeContract.address) - minted.should.be.bignumber.equal(10) + minted.should.be.bignumber.equal('10') + + const { logs } = await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled - const {logs} = await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled + expectEventInLogs(logs, 'UserRequestForSignature', { recipient: accounts[1], value: toBN(1) }) + expect(await homeContract.totalSpentPerDay(currentDay)).to.be.bignumber.equal('1') + expect(await homeContract.totalBurntCoins()).to.be.bignumber.equal('1') - logs[0].event.should.be.equal('UserRequestForSignature') - logs[0].args.should.be.deep.equal({ recipient: accounts[1], value: new web3.BigNumber(1) }) - '1'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay)) - '1'.should.be.bignumber.equal(await homeContract.totalBurntCoins()) - const homeContractBalance = await web3.eth.getBalance(homeContract.address) - homeContractBalance.should.be.bignumber.equal('0') + const homeContractBalance = toBN(await web3.eth.getBalance(homeContract.address)) + homeContractBalance.should.be.bignumber.equal(ZERO) }) it('should accumulate burnt coins', async () => { await blockRewardContract.addMintedTotallyByBridge(10, homeContract.address) const currentDay = await homeContract.getCurrentDay() - '0'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay)) + expect(await homeContract.totalSpentPerDay(currentDay)).to.be.bignumber.equal(ZERO) await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled - '1'.should.be.bignumber.equal(await homeContract.totalBurntCoins()) + expect(await homeContract.totalBurntCoins()).to.be.bignumber.equal('1') await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled - '2'.should.be.bignumber.equal(await homeContract.totalBurntCoins()) + expect(await homeContract.totalBurntCoins()).to.be.bignumber.equal('2') await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled - '3'.should.be.bignumber.equal(await homeContract.totalBurntCoins()) + expect(await homeContract.totalBurntCoins()).to.be.bignumber.equal('3') - const homeContractBalance = await web3.eth.getBalance(homeContract.address) - homeContractBalance.should.be.bignumber.equal('0') + const homeContractBalance = toBN(await web3.eth.getBalance(homeContract.address)) + homeContractBalance.should.be.bignumber.equal(ZERO) }) it('doesnt let you send more than daily limit', async () => { await blockRewardContract.addMintedTotallyByBridge(10, homeContract.address) const currentDay = await homeContract.getCurrentDay() - '0'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay)) + expect(await homeContract.totalSpentPerDay(currentDay)).to.be.bignumber.equal(ZERO) await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled - '1'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay)) - '1'.should.be.bignumber.equal(await homeContract.totalBurntCoins()) + expect(await homeContract.totalSpentPerDay(currentDay)).to.be.bignumber.equal('1') + expect(await homeContract.totalBurntCoins()).to.be.bignumber.equal('1') - await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled; - '2'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay)) + await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled + expect(await homeContract.totalSpentPerDay(currentDay)).to.be.bignumber.equal('2') - await homeContract.sendTransaction({ from: accounts[1], value: 2 }).should.be.rejectedWith(ERROR_MSG); + await homeContract.sendTransaction({ from: accounts[1], value: 2 }).should.be.rejectedWith(ERROR_MSG) - await homeContract.setDailyLimit(4).should.be.fulfilled; - await homeContract.sendTransaction({ from: accounts[1], value: 2 }).should.be.fulfilled; - '4'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay)) - '4'.should.be.bignumber.equal(await homeContract.totalBurntCoins()) + await homeContract.setDailyLimit(4).should.be.fulfilled + await homeContract.sendTransaction({ from: accounts[1], value: 2 }).should.be.fulfilled + expect(await homeContract.totalSpentPerDay(currentDay)).to.be.bignumber.equal('4') + expect(await homeContract.totalBurntCoins()).to.be.bignumber.equal('4') }) it('doesnt let you send more than max amount per tx', async () => { @@ -216,45 +625,49 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { from: accounts[1], value: 1 }).should.be.fulfilled - await homeContract.sendTransaction({ - from: accounts[1], - value: 3 - }).should.be.rejectedWith(ERROR_MSG) - await homeContract.setMaxPerTx(100).should.be.rejectedWith(ERROR_MSG); - await homeContract.setDailyLimit(100).should.be.fulfilled; - await homeContract.setMaxPerTx(99).should.be.fulfilled; - //meets max per tx and daily limit + await homeContract + .sendTransaction({ + from: accounts[1], + value: 3 + }) + .should.be.rejectedWith(ERROR_MSG) + await homeContract.setMaxPerTx(100).should.be.rejectedWith(ERROR_MSG) + await homeContract.setDailyLimit(100).should.be.fulfilled + await homeContract.setMaxPerTx(99).should.be.fulfilled + // meets max per tx and daily limit await homeContract.sendTransaction({ from: accounts[1], value: 99 }).should.be.fulfilled - //above daily limit - await homeContract.sendTransaction({ - from: accounts[1], - value: 1 - }).should.be.rejectedWith(ERROR_MSG) - + // above daily limit + await homeContract + .sendTransaction({ + from: accounts[1], + value: 1 + }) + .should.be.rejectedWith(ERROR_MSG) }) it('should not let to deposit less than minPerTx', async () => { - const newDailyLimit = 100; - const newMaxPerTx = 50; - const newMinPerTx = 20; + const newDailyLimit = 100 + const newMaxPerTx = 50 + const newMinPerTx = 20 await blockRewardContract.addMintedTotallyByBridge(200, homeContract.address) - await homeContract.setDailyLimit(newDailyLimit).should.be.fulfilled; - await homeContract.setMaxPerTx(newMaxPerTx).should.be.fulfilled; - await homeContract.setMinPerTx(newMinPerTx).should.be.fulfilled; + await homeContract.setDailyLimit(newDailyLimit).should.be.fulfilled + await homeContract.setMaxPerTx(newMaxPerTx).should.be.fulfilled + await homeContract.setMinPerTx(newMinPerTx).should.be.fulfilled await homeContract.sendTransaction({ from: accounts[1], value: newMinPerTx }).should.be.fulfilled - await homeContract.sendTransaction({ from: accounts[1], value: newMinPerTx - 1 }).should.be.rejectedWith(ERROR_MSG) + await homeContract + .sendTransaction({ from: accounts[1], value: newMinPerTx - 1 }) + .should.be.rejectedWith(ERROR_MSG) }) it('should fail if not enough bridged tokens', async () => { - const initiallyMinted = await blockRewardContract.mintedTotallyByBridge(homeContract.address) - initiallyMinted.should.be.bignumber.equal(0) + initiallyMinted.should.be.bignumber.equal(ZERO) await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.rejectedWith(ERROR_MSG) @@ -269,59 +682,70 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { const minted = await blockRewardContract.mintedTotallyByBridge(homeContract.address) const burnt = await homeContract.totalBurntCoins() - minted.should.be.bignumber.equal(2) - burnt.should.be.bignumber.equal(2) + minted.should.be.bignumber.equal('2') + burnt.should.be.bignumber.equal('2') }) }) describe('#setting limits', async () => { - let homeContract; + let homeContract beforeEach(async () => { homeContract = await HomeBridge.new() - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner) + await homeContract.initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) }) it('setMaxPerTx allows to set only to owner and cannot be more than daily limit', async () => { - await homeContract.setMaxPerTx(2, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); - await homeContract.setMaxPerTx(2, {from: owner}).should.be.fulfilled; + await homeContract.setMaxPerTx(2, { from: authorities[0] }).should.be.rejectedWith(ERROR_MSG) + await homeContract.setMaxPerTx(2, { from: owner }).should.be.fulfilled - await homeContract.setMaxPerTx(3, {from: owner}).should.be.rejectedWith(ERROR_MSG); + await homeContract.setMaxPerTx(3, { from: owner }).should.be.rejectedWith(ERROR_MSG) const maxPerTx = await homeContract.maxPerTx() - maxPerTx.should.be.bignumber.equal(web3.toBigNumber(2)) + maxPerTx.should.be.bignumber.equal(toBN(2)) }) it('setMinPerTx allows to set only to owner and cannot be more than daily limit and should be less than maxPerTx', async () => { - await homeContract.setMinPerTx(1, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); - await homeContract.setMinPerTx(1, {from: owner}).should.be.fulfilled; + await homeContract.setMinPerTx(1, { from: authorities[0] }).should.be.rejectedWith(ERROR_MSG) + await homeContract.setMinPerTx(1, { from: owner }).should.be.fulfilled - await homeContract.setMinPerTx(2, {from: owner}).should.be.rejectedWith(ERROR_MSG); + await homeContract.setMinPerTx(2, { from: owner }).should.be.rejectedWith(ERROR_MSG) const minPerTx = await homeContract.minPerTx() - minPerTx.should.be.bignumber.equal(web3.toBigNumber(1)) + minPerTx.should.be.bignumber.equal(toBN(1)) }) it('setExecutionMaxPerTx allows to set only to owner and cannot be more than execution daily limit', async () => { - const newValue = web3.toBigNumber(web3.toWei(0.3, "ether")); + const newValue = ether('0.3') const initialExecutionMaxPerTx = await homeContract.executionMaxPerTx() initialExecutionMaxPerTx.should.be.bignumber.not.equal(newValue) - await homeContract.setExecutionMaxPerTx(newValue, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); - await homeContract.setExecutionMaxPerTx(newValue, {from: owner}).should.be.fulfilled; + await homeContract.setExecutionMaxPerTx(newValue, { from: authorities[0] }).should.be.rejectedWith(ERROR_MSG) + await homeContract.setExecutionMaxPerTx(newValue, { from: owner }).should.be.fulfilled - await homeContract.setExecutionMaxPerTx(oneEther, {from: owner}).should.be.rejectedWith(ERROR_MSG); + await homeContract.setExecutionMaxPerTx(oneEther, { from: owner }).should.be.rejectedWith(ERROR_MSG) const executionMaxPerTx = await homeContract.executionMaxPerTx() executionMaxPerTx.should.be.bignumber.equal(newValue) }) it('executionDailyLimit allows to set only to owner', async () => { - const newValue = web3.toBigNumber(web3.toWei(1.5, "ether")); + const newValue = ether('1.5') - const initialExecutionDailyLimit= await homeContract.executionDailyLimit() + const initialExecutionDailyLimit = await homeContract.executionDailyLimit() initialExecutionDailyLimit.should.be.bignumber.not.equal(newValue) - await homeContract.setExecutionDailyLimit(newValue, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); - await homeContract.setExecutionDailyLimit(newValue, {from: owner}).should.be.fulfilled; + await homeContract.setExecutionDailyLimit(newValue, { from: authorities[0] }).should.be.rejectedWith(ERROR_MSG) + await homeContract.setExecutionDailyLimit(newValue, { from: owner }).should.be.fulfilled const executionDailyLimit = await homeContract.executionDailyLimit() executionDailyLimit.should.be.bignumber.equal(newValue) @@ -329,10 +753,21 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { }) describe('#executeAffirmation', async () => { - let homeBridge; + let homeBridge beforeEach(async () => { - homeBridge = await HomeBridge.new(); - await homeBridge.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner); + homeBridge = await HomeBridge.new() + await homeBridge.initialize( + validatorContract.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) await blockRewardContract.sendTransaction({ from: accounts[2], value: oneEther @@ -340,144 +775,230 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { }) it('should allow validator to executeAffirmation', async () => { - const recipient = accounts[5]; - const value = halfEther; + const recipient = accounts[5] + const value = halfEther const balanceBefore = await web3.eth.getBalance(recipient) - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const {logs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }) - logs[0].event.should.be.equal("SignedForAffirmation"); - logs[0].args.should.be.deep.equal({ + expectEventInLogs(logs, 'SignedForAffirmation', { signer: authorities[0], transactionHash - }); - logs[1].event.should.be.equal("AffirmationCompleted"); - logs[1].args.should.be.deep.equal({ + }) + expectEventInLogs(logs, 'AffirmationCompleted', { recipient, value, transactionHash }) - const balanceAfter = await web3.eth.getBalance(recipient) - balanceAfter.should.be.bignumber.equal(balanceBefore.add(value)) + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) + balanceAfter.should.be.bignumber.equal(toBN(balanceBefore).add(value)) - const msgHash = Web3Utils.soliditySha3(recipient, value, transactionHash); - const senderHash = Web3Utils.soliditySha3(authorities[0], msgHash) + const msgHash = web3.utils.soliditySha3(recipient, value, transactionHash) + const senderHash = web3.utils.soliditySha3(authorities[0], msgHash) + true.should.be.equal(await homeBridge.affirmationsSigned(senderHash)) + }) + + it('should allow validator to executeAffirmation with zero value', async () => { + const recipient = accounts[5] + const value = ZERO + const balanceBefore = await web3.eth.getBalance(recipient) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }) + + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: authorities[0], + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) + balanceAfter.should.be.bignumber.equal(toBN(balanceBefore).add(value)) + + const msgHash = web3.utils.soliditySha3(recipient, value, transactionHash) + const senderHash = web3.utils.soliditySha3(authorities[0], msgHash) true.should.be.equal(await homeBridge.affirmationsSigned(senderHash)) }) it('test with 2 signatures required', async () => { const validatorContractWith2Signatures = await BridgeValidators.new() - const authoritiesTwoAccs = [accounts[1], accounts[2], accounts[3]]; + const authoritiesThreeAccs = [accounts[1], accounts[2], accounts[3]] const ownerOfValidators = accounts[0] - await validatorContractWith2Signatures.initialize(2, authoritiesTwoAccs, ownerOfValidators) - const homeBridgeWithTwoSigs = await HomeBridge.new(); - await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner); - const recipient = accounts[5]; - const value = halfEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const balanceBefore = await web3.eth.getBalance(recipient) - const msgHash = Web3Utils.soliditySha3(recipient, value, transactionHash); + await validatorContractWith2Signatures.initialize(2, authoritiesThreeAccs, ownerOfValidators) + const homeBridgeWithTwoSigs = await HomeBridge.new() + await homeBridgeWithTwoSigs.initialize( + validatorContractWith2Signatures.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + const recipient = accounts[5] + const value = halfEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + const msgHash = web3.utils.soliditySha3(recipient, value, transactionHash) + + const { logs } = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled + expectEventInLogs(logs, 'SignedForAffirmation', { signer: authorities[0], transactionHash }) - const { logs } = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - logs[0].event.should.be.equal("SignedForAffirmation"); - logs[0].args.should.be.deep.equal({ signer: authorities[0], transactionHash }); - const notProcessed = await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash); - notProcessed.should.be.bignumber.equal(1); + const notProcessed = await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash) + notProcessed.should.be.bignumber.equal('1') - await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[0]}).should.be.rejectedWith(ERROR_MSG); - const secondSignature = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; + await homeBridgeWithTwoSigs + .executeAffirmation(recipient, value, transactionHash, { from: authoritiesThreeAccs[0] }) + .should.be.rejectedWith(ERROR_MSG) + const secondSignature = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled - const balanceAfter = await web3.eth.getBalance(recipient) + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) balanceAfter.should.be.bignumber.equal(balanceBefore.add(value)) - secondSignature.logs[1].event.should.be.equal("AffirmationCompleted"); - secondSignature.logs[1].args.should.be.deep.equal({ recipient, value, transactionHash }) + expectEventInLogs(secondSignature.logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) - const senderHash = Web3Utils.soliditySha3(authoritiesTwoAccs[0], msgHash) + const senderHash = web3.utils.soliditySha3(authoritiesThreeAccs[0], msgHash) true.should.be.equal(await homeBridgeWithTwoSigs.affirmationsSigned(senderHash)) - const senderHash2 = Web3Utils.soliditySha3(authoritiesTwoAccs[1], msgHash); + const senderHash2 = web3.utils.soliditySha3(authoritiesThreeAccs[1], msgHash) true.should.be.equal(await homeBridgeWithTwoSigs.affirmationsSigned(senderHash2)) - const markedAsProcessed = await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash); - const processed = new web3.BigNumber(2).pow(255).add(2); + const markedAsProcessed = await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash) + const processed = toBN(2) + .pow(toBN(255)) + .add(toBN(2)) markedAsProcessed.should.be.bignumber.equal(processed) }) it('should not allow non-validator to execute affirmation', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: accounts[7]}).should.be.rejectedWith(ERROR_MSG); + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + await homeBridge + .executeAffirmation(recipient, value, transactionHash, { from: accounts[7] }) + .should.be.rejectedWith(ERROR_MSG) }) it('should fail if the block reward contract is not set', async () => { - homeBridge = await HomeBridge.new(); - await homeBridge.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, ZERO_ADDRESS, foreignDailyLimit, foreignMaxPerTx, owner); - - const recipient = accounts[5]; - const value = halfEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG) + homeBridge = await HomeBridge.new() + await homeBridge.initialize( + validatorContract.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + ZERO_ADDRESS, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + + const recipient = accounts[5] + const value = halfEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + await homeBridge + .executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }) + .should.be.rejectedWith(ERROR_MSG) }) it('works with 5 validators and 3 required signatures', async () => { const recipient = accounts[8] const authoritiesFiveAccs = [accounts[1], accounts[2], accounts[3], accounts[4], accounts[5]] - let ownerOfValidators = accounts[0] + const ownerOfValidators = accounts[0] const validatorContractWith3Signatures = await BridgeValidators.new() await validatorContractWith3Signatures.initialize(3, authoritiesFiveAccs, ownerOfValidators) - const homeBridgeWithThreeSigs = await HomeBridge.new(); - await homeBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner); - - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; + const homeBridgeWithThreeSigs = await HomeBridge.new() + await homeBridgeWithThreeSigs.initialize( + validatorContractWith3Signatures.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + + const value = halfEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + const { logs } = await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesFiveAccs[0] + }).should.be.fulfilled - const {logs} = await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesFiveAccs[0]}).should.be.fulfilled; - logs[0].event.should.be.equal("SignedForAffirmation"); - logs[0].args.should.be.deep.equal({ + expectEventInLogs(logs, 'SignedForAffirmation', { signer: authorities[0], transactionHash - }); + }) - await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesFiveAccs[1]}).should.be.fulfilled; - const thirdSignature = await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesFiveAccs[2]}).should.be.fulfilled; + await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesFiveAccs[1] + }).should.be.fulfilled + const thirdSignature = await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesFiveAccs[2] + }).should.be.fulfilled - thirdSignature.logs[1].event.should.be.equal("AffirmationCompleted"); - thirdSignature.logs[1].args.should.be.deep.equal({ + expectEventInLogs(thirdSignature.logs, 'AffirmationCompleted', { recipient, value, transactionHash }) }) it('should not allow execute affirmation over foreign max tx limit', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const {logs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled; + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled - logs[0].event.should.be.equal("AmountLimitExceeded"); - logs[0].args.should.be.deep.equal({ + expectEventInLogs(logs, 'AmountLimitExceeded', { recipient, value, transactionHash - }); + }) }) it('should fail if txHash already set as above of limits', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const {logs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled; + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled - logs[0].event.should.be.equal("AmountLimitExceeded"); - logs[0].args.should.be.deep.equal({ + expectEventInLogs(logs, 'AmountLimitExceeded', { recipient, value, transactionHash - }); + }) - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG) - await homeBridge.executeAffirmation(accounts[6], value, transactionHash, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG) + await homeBridge + .executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }) + .should.be.rejectedWith(ERROR_MSG) + await homeBridge + .executeAffirmation(accounts[6], value, transactionHash, { from: authorities[0] }) + .should.be.rejectedWith(ERROR_MSG) }) it('should not allow execute affirmation over daily foreign limit', async () => { await blockRewardContract.sendTransaction({ @@ -485,61 +1006,63 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { value: oneEther }).should.be.fulfilled - const recipient = accounts[5]; - const value = halfEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled; + const recipient = accounts[5] + const value = halfEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled - logs[0].event.should.be.equal("SignedForAffirmation"); - logs[0].args.should.be.deep.equal({ + expectEventInLogs(logs, 'SignedForAffirmation', { signer: authorities[0], transactionHash - }); - logs[1].event.should.be.equal("AffirmationCompleted"); - logs[1].args.should.be.deep.equal({ + }) + expectEventInLogs(logs, 'AffirmationCompleted', { recipient, value, transactionHash }) - const transactionHash2 = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const { logs: logs2 } = await homeBridge.executeAffirmation(recipient, value, transactionHash2, {from: authorities[0]}).should.be.fulfilled; + const transactionHash2 = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const { logs: logs2 } = await homeBridge.executeAffirmation(recipient, value, transactionHash2, { + from: authorities[0] + }).should.be.fulfilled - logs2[0].event.should.be.equal("SignedForAffirmation"); - logs2[0].args.should.be.deep.equal({ + expectEventInLogs(logs2, 'SignedForAffirmation', { signer: authorities[0], transactionHash: transactionHash2 - }); - logs2[1].event.should.be.equal("AffirmationCompleted"); - logs2[1].args.should.be.deep.equal({ + }) + expectEventInLogs(logs2, 'AffirmationCompleted', { recipient, value, transactionHash: transactionHash2 }) - const transactionHash3 = "0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712"; - const { logs: logs3 } = await homeBridge.executeAffirmation(recipient, value, transactionHash3, {from: authorities[0]}).should.be.fulfilled; + const transactionHash3 = '0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712' + const { logs: logs3 } = await homeBridge.executeAffirmation(recipient, value, transactionHash3, { + from: authorities[0] + }).should.be.fulfilled - logs3[0].event.should.be.equal("AmountLimitExceeded"); - logs3[0].args.should.be.deep.equal({ + expectEventInLogs(logs3, 'AmountLimitExceeded', { recipient, value, transactionHash: transactionHash3 - }); + }) const outOfLimitAmount = await homeBridge.outOfLimitAmount() outOfLimitAmount.should.be.bignumber.equal(halfEther) - const transactionHash4 = "0xc9ffe298d85ec5c515153608924b7bdcf1835539813dcc82cdbcc071170c3196"; - const { logs: logs4 } = await homeBridge.executeAffirmation(recipient, value, transactionHash4, {from: authorities[0]}).should.be.fulfilled; + const transactionHash4 = '0xc9ffe298d85ec5c515153608924b7bdcf1835539813dcc82cdbcc071170c3196' + const { logs: logs4 } = await homeBridge.executeAffirmation(recipient, value, transactionHash4, { + from: authorities[0] + }).should.be.fulfilled - logs4[0].event.should.be.equal("AmountLimitExceeded"); - logs4[0].args.should.be.deep.equal({ + expectEventInLogs(logs4, 'AmountLimitExceeded', { recipient, value, transactionHash: transactionHash4 - }); + }) const newOutOfLimitAmount = await homeBridge.outOfLimitAmount() newOutOfLimitAmount.should.be.bignumber.equal(oneEther) @@ -547,54 +1070,78 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { }) describe('#submitSignature', async () => { - let validatorContractWith2Signatures,authoritiesTwoAccs,ownerOfValidators,homeBridgeWithTwoSigs + let validatorContractWith2Signatures + let authoritiesThreeAccs + let ownerOfValidators + let homeBridgeWithTwoSigs beforeEach(async () => { validatorContractWith2Signatures = await BridgeValidators.new() - authoritiesTwoAccs = [accounts[1], accounts[2], accounts[3]]; + authoritiesThreeAccs = [accounts[1], accounts[2], accounts[3]] ownerOfValidators = accounts[0] - await validatorContractWith2Signatures.initialize(2, authoritiesTwoAccs, ownerOfValidators) - homeBridgeWithTwoSigs = await HomeBridge.new(); - await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner); + await validatorContractWith2Signatures.initialize(2, authoritiesThreeAccs, ownerOfValidators) + homeBridgeWithTwoSigs = await HomeBridge.new() + await homeBridgeWithTwoSigs.initialize( + validatorContractWith2Signatures.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) }) it('allows a validator to submit a signature', async () => { const recipientAccount = accounts[8] - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); - const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address); + const value = halfEther + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address) - const signature = await sign(authoritiesTwoAccs[0], message) - const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authorities[0]}).should.be.fulfilled; + const signature = await sign(authoritiesThreeAccs[0], message) + const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature, message, { + from: authorities[0] + }).should.be.fulfilled logs[0].event.should.be.equal('SignedForUserRequest') const { messageHash } = logs[0].args - const signatureFromContract = await homeBridgeWithTwoSigs.signature(messageHash, 0); - const messageFromContract = await homeBridgeWithTwoSigs.message(messageHash); - signature.should.be.equal(signatureFromContract); - messageFromContract.should.be.equal(messageFromContract); - const hashMsg = Web3Utils.soliditySha3(message); - const hashSenderMsg = Web3Utils.soliditySha3(authorities[0], hashMsg) - true.should.be.equal(await homeBridgeWithTwoSigs.messagesSigned(hashSenderMsg)); + const signatureFromContract = await homeBridgeWithTwoSigs.signature(messageHash, 0) + const messageFromContract = await homeBridgeWithTwoSigs.message(messageHash) + signature.should.be.equal(signatureFromContract) + messageFromContract.should.be.equal(messageFromContract) + const hashMsg = web3.utils.soliditySha3(message) + const hashSenderMsg = web3.utils.soliditySha3(authorities[0], hashMsg) + true.should.be.equal(await homeBridgeWithTwoSigs.messagesSigned(hashSenderMsg)) }) it('when enough requiredSignatures are collected, CollectedSignatures event is emitted', async () => { const recipientAccount = accounts[8] - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); - const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address); + const value = halfEther + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address) - const signature = await sign(authoritiesTwoAccs[0], message) - const signature2 = await sign(authoritiesTwoAccs[1], message) - '2'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); + const signature = await sign(authoritiesThreeAccs[0], message) + const signature2 = await sign(authoritiesThreeAccs[1], message) + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('2') - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.rejectedWith(ERROR_MSG); - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[1]}).should.be.rejectedWith(ERROR_MSG); - const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; + await homeBridgeWithTwoSigs.submitSignature(signature, message, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled + await homeBridgeWithTwoSigs + .submitSignature(signature, message, { from: authoritiesThreeAccs[0] }) + .should.be.rejectedWith(ERROR_MSG) + await homeBridgeWithTwoSigs + .submitSignature(signature, message, { from: authoritiesThreeAccs[1] }) + .should.be.rejectedWith(ERROR_MSG) + const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled logs.length.should.be.equal(2) logs[1].event.should.be.equal('CollectedSignatures') - logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesTwoAccs[1]) + logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesThreeAccs[1]) }) it('works with 5 validators and 3 required signatures', async () => { const recipientAccount = accounts[8] @@ -602,65 +1149,96 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { const validatorContractWith3Signatures = await BridgeValidators.new() await validatorContractWith3Signatures.initialize(3, authoritiesFiveAccs, ownerOfValidators) - const homeBridgeWithThreeSigs = await HomeBridge.new(); - await homeBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner); - - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); - const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithThreeSigs.address); + const homeBridgeWithThreeSigs = await HomeBridge.new() + await homeBridgeWithThreeSigs.initialize( + validatorContractWith3Signatures.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + + const value = halfEther + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithThreeSigs.address) const signature = await sign(authoritiesFiveAccs[0], message) const signature2 = await sign(authoritiesFiveAccs[1], message) const signature3 = await sign(authoritiesFiveAccs[2], message) - '3'.should.be.bignumber.equal(await validatorContractWith3Signatures.requiredSignatures()); + expect(await validatorContractWith3Signatures.requiredSignatures()).to.be.bignumber.equal('3') - await homeBridgeWithThreeSigs.submitSignature(signature, message, {from: authoritiesFiveAccs[0]}).should.be.fulfilled; - await homeBridgeWithThreeSigs.submitSignature(signature2, message, {from: authoritiesFiveAccs[1]}).should.be.fulfilled; - const {logs} = await homeBridgeWithThreeSigs.submitSignature(signature3, message, {from: authoritiesFiveAccs[2]}).should.be.fulfilled; + await homeBridgeWithThreeSigs.submitSignature(signature, message, { + from: authoritiesFiveAccs[0] + }).should.be.fulfilled + await homeBridgeWithThreeSigs.submitSignature(signature2, message, { + from: authoritiesFiveAccs[1] + }).should.be.fulfilled + const { logs } = await homeBridgeWithThreeSigs.submitSignature(signature3, message, { + from: authoritiesFiveAccs[2] + }).should.be.fulfilled logs.length.should.be.equal(2) logs[1].event.should.be.equal('CollectedSignatures') logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesFiveAccs[2]) }) it('attack when increasing requiredSignatures', async () => { const recipientAccount = accounts[8] - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); - const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address); - const signature = await sign(authoritiesTwoAccs[0], message) - const signature2 = await sign(authoritiesTwoAccs[1], message) - const signature3 = await sign(authoritiesTwoAccs[2], message) - '2'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.rejectedWith(ERROR_MSG); - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[1]}).should.be.rejectedWith(ERROR_MSG); - const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; + const value = halfEther + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address) + const signature = await sign(authoritiesThreeAccs[0], message) + const signature2 = await sign(authoritiesThreeAccs[1], message) + const signature3 = await sign(authoritiesThreeAccs[2], message) + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('2') + + await homeBridgeWithTwoSigs.submitSignature(signature, message, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled + await homeBridgeWithTwoSigs + .submitSignature(signature, message, { from: authoritiesThreeAccs[0] }) + .should.be.rejectedWith(ERROR_MSG) + await homeBridgeWithTwoSigs + .submitSignature(signature, message, { from: authoritiesThreeAccs[1] }) + .should.be.rejectedWith(ERROR_MSG) + const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled logs.length.should.be.equal(2) logs[1].event.should.be.equal('CollectedSignatures') - logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesTwoAccs[1]) + logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesThreeAccs[1]) - await validatorContractWith2Signatures.setRequiredSignatures(3).should.be.fulfilled; - '3'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - await homeBridgeWithTwoSigs.submitSignature(signature3, message, {from: authoritiesTwoAccs[2]}).should.be.rejectedWith(ERROR_MSG); + await validatorContractWith2Signatures.setRequiredSignatures(3).should.be.fulfilled + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('3') + await homeBridgeWithTwoSigs + .submitSignature(signature3, message, { from: authoritiesThreeAccs[2] }) + .should.be.rejectedWith(ERROR_MSG) }) it('attack when decreasing requiredSignatures', async () => { const recipientAccount = accounts[8] - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); - const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address); - const signature = await sign(authoritiesTwoAccs[0], message) - const signature2 = await sign(authoritiesTwoAccs[1], message) - '2'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - await validatorContractWith2Signatures.setRequiredSignatures(1).should.be.fulfilled; - '1'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; + const value = halfEther + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address) + const signature = await sign(authoritiesThreeAccs[0], message) + const signature2 = await sign(authoritiesThreeAccs[1], message) + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('2') + + await homeBridgeWithTwoSigs.submitSignature(signature, message, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled + await validatorContractWith2Signatures.setRequiredSignatures(1).should.be.fulfilled + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('1') + const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled logs.length.should.be.equal(2) logs[1].event.should.be.equal('CollectedSignatures') - logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesTwoAccs[1]) + logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesThreeAccs[1]) }) }) @@ -670,27 +1248,38 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { }) it('should return the required message length', async () => { - const requiredMessageLength = await homeContract.requiredMessageLength() - '104'.should.be.bignumber.equal(requiredMessageLength) + expect(await homeContract.requiredMessageLength()).to.be.bignumber.equal('104') }) }) describe('#fixAssetsAboveLimits', async () => { - let homeBridge; - const zeroValue = web3.toBigNumber(web3.toWei(0, "ether")) + let homeBridge beforeEach(async () => { - const homeBridgeImpl = await HomeBridge.new(); - const storageProxy = await EternalStorageProxy.new().should.be.fulfilled; + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled - homeBridge = await HomeBridge.at(storageProxy.address); - await homeBridge.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx, owner); + homeBridge = await HomeBridge.at(storageProxy.address) + await homeBridge.initialize( + validatorContract.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) }) it('Should reduce outOfLimitAmount and not emit any event', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const {logs: affirmationLogs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled - affirmationLogs[0].event.should.be.equal("AmountLimitExceeded"); + affirmationLogs[0].event.should.be.equal('AmountLimitExceeded') const outOfLimitAmount = await homeBridge.outOfLimitAmount() outOfLimitAmount.should.be.bignumber.equal(value) @@ -700,15 +1289,17 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { logs.length.should.be.equal(0) const newOutOfLimitAmount = await homeBridge.outOfLimitAmount() - newOutOfLimitAmount.should.be.bignumber.equal(zeroValue) + newOutOfLimitAmount.should.be.bignumber.equal(ZERO) }) it('Should reduce outOfLimitAmount and emit UserRequestForSignature', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const {logs: affirmationLogs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled - affirmationLogs[0].event.should.be.equal("AmountLimitExceeded"); + affirmationLogs[0].event.should.be.equal('AmountLimitExceeded') const outOfLimitAmount = await homeBridge.outOfLimitAmount() outOfLimitAmount.should.be.bignumber.equal(value) @@ -716,23 +1307,26 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { const { logs } = await homeBridge.fixAssetsAboveLimits(transactionHash, true).should.be.fulfilled logs.length.should.be.equal(1) - logs[0].event.should.be.equal('UserRequestForSignature') - logs[0].args.should.be.deep.equal({ + expectEventInLogs(logs, 'UserRequestForSignature', { recipient, value }) const newOutOfLimitAmount = await homeBridge.outOfLimitAmount() - newOutOfLimitAmount.should.be.bignumber.equal(zeroValue) + newOutOfLimitAmount.should.be.bignumber.equal(ZERO) }) it('Should not be allow to be called by an already fixed txHash', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const transactionHash2 = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const transactionHash2 = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled - await homeBridge.executeAffirmation(recipient, value, transactionHash2, {from: authorities[0]}).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash2, { + from: authorities[0] + }).should.be.fulfilled const outOfLimitAmount = await homeBridge.outOfLimitAmount() outOfLimitAmount.should.be.bignumber.equal(value.add(value)) @@ -746,42 +1340,47 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { await homeBridge.fixAssetsAboveLimits(transactionHash2, false).should.be.fulfilled const updatedOutOfLimitAmount = await homeBridge.outOfLimitAmount() - updatedOutOfLimitAmount.should.be.bignumber.equal(zeroValue) + updatedOutOfLimitAmount.should.be.bignumber.equal(ZERO) await homeBridge.fixAssetsAboveLimits(transactionHash2, false).should.be.rejectedWith(ERROR_MSG) }) it('Should fail if txHash didnt increase out of limit amount', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const invalidTxHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const invalidTxHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' - const {logs: affirmationLogs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled + const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled - affirmationLogs[0].event.should.be.equal("AmountLimitExceeded"); + affirmationLogs[0].event.should.be.equal('AmountLimitExceeded') await homeBridge.fixAssetsAboveLimits(invalidTxHash, true).should.be.rejectedWith(ERROR_MSG) }) it('Should fail if not called by proxyOwner', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' - const {logs: affirmationLogs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled + const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled - affirmationLogs[0].event.should.be.equal("AmountLimitExceeded"); + affirmationLogs[0].event.should.be.equal('AmountLimitExceeded') - await homeBridge.fixAssetsAboveLimits(transactionHash, true, { from: recipient}).should.be.rejectedWith(ERROR_MSG) - await homeBridge.fixAssetsAboveLimits(transactionHash, true, { from: owner}).should.be.fulfilled + await homeBridge + .fixAssetsAboveLimits(transactionHash, true, { from: recipient }) + .should.be.rejectedWith(ERROR_MSG) + await homeBridge.fixAssetsAboveLimits(transactionHash, true, { from: owner }).should.be.fulfilled }) }) describe('#OwnedUpgradeability', async () => { - it('upgradeabilityAdmin should return the proxy owner', async () => { - const homeBridgeImpl = await HomeBridge.new(); - const storageProxy = await EternalStorageProxy.new().should.be.fulfilled; + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled - const homeBridge = await HomeBridge.at(storageProxy.address); + const homeBridge = await HomeBridge.at(storageProxy.address) const proxyOwner = await storageProxy.proxyOwner() const upgradeabilityAdmin = await homeBridge.upgradeabilityAdmin() @@ -789,4 +1388,1363 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => { upgradeabilityAdmin.should.be.equal(proxyOwner) }) }) + + describe('#feeManager', async () => { + let homeBridge + let rewardableValidators + const owner = accounts[9] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + beforeEach(async () => { + rewardableValidators = await RewardableValidators.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + homeBridge = await HomeBridge.at(storageProxy.address) + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.sendTransaction({ + from: accounts[2], + value: oneEther + }).should.be.fulfilled + }) + it('should be able to set and get fee manager contract', async () => { + // Given + const feeManager = await FeeManagerErcToNative.new() + + // When + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + + // Then + const feeManagerContract = await homeBridge.feeManagerContract() + feeManagerContract.should.be.equals(feeManager.address) + }) + it('should be able to set and get fees', async () => { + // Given + // 10% fee + const homeFee = ether('0.1') + const foreignFee = ether('0.2') + const feeManager = await FeeManagerErcToNative.new() + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + + // When + await homeBridge.setHomeFee(homeFee, { from: owner }).should.be.fulfilled + await homeBridge.setForeignFee(foreignFee, { from: owner }).should.be.fulfilled + + // Then + const bridgeHomeFee = await homeBridge.getHomeFee() + bridgeHomeFee.should.be.bignumber.equal(homeFee) + const bridgeForeignFee = await homeBridge.getForeignFee() + bridgeForeignFee.should.be.bignumber.equal(foreignFee) + }) + it('should be able to get fee manager mode', async () => { + // Given + const feeManager = await FeeManagerErcToNative.new() + const bothDirectionsModeHash = '0xd7de965f' + + // When + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + + // Then + const feeManagerMode = await homeBridge.getFeeManagerMode() + feeManagerMode.should.be.equals(bothDirectionsModeHash) + }) + }) + describe('#feeManager_ExecuteAffirmation', async () => { + it('should distribute fee to validator', async () => { + // Initialize + const owner = accounts[9] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + const rewardableValidators = await RewardableValidators.new() + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + const homeBridge = await HomeBridge.at(storageProxy.address) + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.sendTransaction({ + from: accounts[2], + value: oneEther + }).should.be.fulfilled + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feeManager = await FeeManagerErcToNative.new() + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setForeignFee(feeInWei, { from: owner }).should.be.fulfilled + + const recipient = accounts[5] + const value = halfEther + const valueCalc = 0.5 * (1 - fee) + const finalValue = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + const rewardAddressBalanceBefore = toBN(await web3.eth.getBalance(rewards[0])) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + // When + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[0] + }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: validators[0], + transactionHash + }) + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) + const rewardAddressBalanceAfter = toBN(await web3.eth.getBalance(rewards[0])) + + rewardAddressBalanceAfter.should.be.bignumber.equal(rewardAddressBalanceBefore.add(feeAmount)) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(finalValue)) + }) + it('should distribute fee to 3 validators', async () => { + // Initialize + const owner = accounts[9] + const validators = [accounts[1], accounts[2], accounts[3]] + const rewards = [accounts[4], accounts[5], accounts[6]] + const requiredSignatures = 2 + const rewardableValidators = await RewardableValidators.new() + const homeBridgeImpl = await HomeBridge.new() + const blockRewardContract = await BlockReward.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + const homeBridge = await HomeBridge.at(storageProxy.address) + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.sendTransaction({ + from: accounts[0], + value: halfEther + }).should.be.fulfilled + + // Given + const initialBlockRewardBalance = toBN(await web3.eth.getBalance(blockRewardContract.address)) + initialBlockRewardBalance.should.be.bignumber.equal(halfEther) + + const value = halfEther + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const valueCalc = 0.5 * (1 - fee) + const finalValue = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + // totalFee / 3 + const feePerValidator = toBN(166666666666666) + const feePerValidatorPlusDiff = toBN(166666666666668) + const feeManager = await FeeManagerErcToNative.new() + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setForeignFee(feeInWei, { from: owner }).should.be.fulfilled + + const recipient = accounts[8] + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + + const initialBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const initialBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const initialBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + // When + const { logs: logsValidator1 } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[0] + }).should.be.fulfilled + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[1] + }).should.be.fulfilled + + // Then + logsValidator1.length.should.be.equals(1) + + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: validators[1], + transactionHash + }) + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(finalValue)) + + const updatedBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const updatedBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const updatedBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + + expect( + updatedBalanceRewardAddress1.eq(initialBalanceRewardAddress1.add(feePerValidator)) || + updatedBalanceRewardAddress1.eq(initialBalanceRewardAddress1.add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + updatedBalanceRewardAddress2.eq(initialBalanceRewardAddress2.add(feePerValidator)) || + updatedBalanceRewardAddress2.eq(initialBalanceRewardAddress2.add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + updatedBalanceRewardAddress3.eq(initialBalanceRewardAddress3.add(feePerValidator)) || + updatedBalanceRewardAddress3.eq(initialBalanceRewardAddress3.add(feePerValidatorPlusDiff)) + ).to.equal(true) + + const blockRewardBalance = toBN(await web3.eth.getBalance(blockRewardContract.address)) + blockRewardBalance.should.be.bignumber.equal(ZERO) + }) + it('should distribute fee to 5 validators', async () => { + // Initialize + const owner = accounts[0] + const validators = [accounts[0], accounts[1], accounts[2], accounts[3], accounts[4]] + const rewards = [accounts[5], accounts[6], accounts[7], accounts[8], accounts[9]] + const requiredSignatures = 5 + const rewardableValidators = await RewardableValidators.new() + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + const homeBridge = await HomeBridge.at(storageProxy.address) + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.sendTransaction({ + from: accounts[0], + value: oneEther + }).should.be.fulfilled + + // Given + const value = halfEther + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const feePerValidator = feeAmount.div(toBN(5)) + const feeManager = await FeeManagerErcToNative.new() + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setForeignFee(feeInWei, { from: owner }).should.be.fulfilled + + const recipient = '0xf4BEF13F9f4f2B203FAF0C3cBbaAbe1afE056955' + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + + const initialBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const initialBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const initialBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + const initialBalanceRewardAddress4 = toBN(await web3.eth.getBalance(rewards[3])) + const initialBalanceRewardAddress5 = toBN(await web3.eth.getBalance(rewards[4])) + + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + // When + const { logs: logsValidator1 } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[0] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[1] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[2] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[3] + }).should.be.fulfilled + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[4] + }).should.be.fulfilled + + // Then + logsValidator1.length.should.be.equals(1) + + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: validators[4], + transactionHash + }) + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(value.sub(feeAmount))) + + const updatedBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const updatedBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const updatedBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + const updatedBalanceRewardAddress4 = toBN(await web3.eth.getBalance(rewards[3])) + const updatedBalanceRewardAddress5 = toBN(await web3.eth.getBalance(rewards[4])) + + updatedBalanceRewardAddress1.should.be.bignumber.equal(initialBalanceRewardAddress1.add(feePerValidator)) + updatedBalanceRewardAddress2.should.be.bignumber.equal(initialBalanceRewardAddress2.add(feePerValidator)) + updatedBalanceRewardAddress3.should.be.bignumber.equal(initialBalanceRewardAddress3.add(feePerValidator)) + updatedBalanceRewardAddress4.should.be.bignumber.equal(initialBalanceRewardAddress4.add(feePerValidator)) + updatedBalanceRewardAddress5.should.be.bignumber.equal(initialBalanceRewardAddress5.add(feePerValidator)) + }) + }) + describe('#feeManager_fallback', async () => { + let homeBridge + let rewardableValidators + const owner = accounts[9] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + beforeEach(async () => { + rewardableValidators = await RewardableValidators.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + homeBridge = await HomeBridge.at(storageProxy.address) + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.addMintedTotallyByBridge(oneEther, homeBridge.address) + }) + + it('should subtract fee from value', async () => { + // Given + // 0.1% fee + const value = halfEther + const recipient = accounts[8] + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const valueCalc = 0.5 * (1 - fee) + const finalValue = ether(valueCalc.toString()) + const feeManager = await FeeManagerErcToNative.new() + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setHomeFee(feeInWei, { from: owner }).should.be.fulfilled + + // When + const { logs } = await homeBridge.sendTransaction({ from: recipient, value }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'UserRequestForSignature', { + recipient, + value: finalValue + }) + const currentDay = await homeBridge.getCurrentDay() + value.should.be.bignumber.equal(await homeBridge.totalSpentPerDay(currentDay)) + finalValue.should.be.bignumber.equal(await homeBridge.totalBurntCoins()) + const homeBridgeBalance = await web3.eth.getBalance(homeBridge.address) + expect(toBN(homeBridgeBalance)).to.be.bignumber.equal(value.sub(finalValue)) + }) + }) + describe('#feeManager_submitSignature', async () => { + it('should distribute fee to validator', async () => { + // Initialize + const owner = accounts[9] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + const rewardableValidators = await RewardableValidators.new() + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + const homeBridge = await HomeBridge.at(storageProxy.address) + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.addMintedTotallyByBridge(oneEther, homeBridge.address) + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feeManager = await FeeManagerErcToNative.new() + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setHomeFee(feeInWei, { from: owner }).should.be.fulfilled + + const recipient = accounts[5] + const initialValue = halfEther + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const rewardAddressBalanceBefore = toBN(await web3.eth.getBalance(rewards[0])) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + const initialBridgeBalance = await web3.eth.getBalance(homeBridge.address) + expect(toBN(initialBridgeBalance)).to.be.bignumber.equal(ZERO) + + // When + await homeBridge.sendTransaction({ from: recipient, value: initialValue }).should.be.fulfilled + + const afterTransferBridgeBalance = toBN(await web3.eth.getBalance(homeBridge.address)) + afterTransferBridgeBalance.should.be.bignumber.equal(feeAmount) + + const message = createMessage(recipient, value, transactionHash, homeBridge.address) + + const signature = await sign(validators[0], message) + + const { logs } = await homeBridge.submitSignature(signature, message, { from: validators[0] }).should.be.fulfilled + + // Then + logs.length.should.be.equal(3) + logs[1].event.should.be.equal('CollectedSignatures') + logs[2].event.should.be.equal('FeeDistributedFromSignatures') + + const finalBridgeBalance = await web3.eth.getBalance(homeBridge.address) + expect(toBN(finalBridgeBalance)).to.be.bignumber.equal(ZERO) + + const rewardAddressBalanceAfter = await web3.eth.getBalance(rewards[0]) + expect(toBN(rewardAddressBalanceAfter)).to.be.bignumber.equal(toBN(rewardAddressBalanceBefore).add(feeAmount)) + }) + it('should distribute fee to 3 validators', async () => { + // Initialize + const owner = accounts[9] + const validators = [accounts[1], accounts[2], accounts[3]] + const rewards = [accounts[4], accounts[5], accounts[6]] + const requiredSignatures = 3 + const rewardableValidators = await RewardableValidators.new() + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + const homeBridge = await HomeBridge.at(storageProxy.address) + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.addMintedTotallyByBridge(oneEther, homeBridge.address) + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feeManager = await FeeManagerErcToNative.new() + const feePerValidator = toBN(166666666666666) + const feePerValidatorPlusDiff = toBN(166666666666668) + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setHomeFee(feeInWei, { from: owner }).should.be.fulfilled + + const recipient = accounts[7] + const initialValue = halfEther + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + const initialBridgeBalance = toBN(await web3.eth.getBalance(homeBridge.address)) + initialBridgeBalance.should.be.bignumber.equal(ZERO) + + const initialBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const initialBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const initialBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + + // When + await homeBridge.sendTransaction({ from: recipient, value: initialValue }).should.be.fulfilled + + const afterTransferBridgeBalance = toBN(await web3.eth.getBalance(homeBridge.address)) + afterTransferBridgeBalance.should.be.bignumber.equal(feeAmount) + + const message = createMessage(recipient, value, transactionHash, homeBridge.address) + + const signature = await sign(validators[0], message) + const signature2 = await sign(validators[1], message) + const signature3 = await sign(validators[2], message) + + await homeBridge.submitSignature(signature, message, { from: validators[0] }).should.be.fulfilled + await homeBridge.submitSignature(signature2, message, { from: validators[1] }).should.be.fulfilled + const { logs } = await homeBridge.submitSignature(signature3, message, { + from: validators[2] + }).should.be.fulfilled + + // Then + logs.length.should.be.equal(3) + logs[1].event.should.be.equal('CollectedSignatures') + logs[2].event.should.be.equal('FeeDistributedFromSignatures') + + const updatedBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const updatedBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const updatedBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + + const bridgeBalance = toBN(await web3.eth.getBalance(homeBridge.address)) + bridgeBalance.should.be.bignumber.equal(ZERO) + + expect( + updatedBalanceRewardAddress1.eq(initialBalanceRewardAddress1.add(feePerValidator)) || + updatedBalanceRewardAddress1.eq(initialBalanceRewardAddress1.add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + updatedBalanceRewardAddress2.eq(initialBalanceRewardAddress2.add(feePerValidator)) || + updatedBalanceRewardAddress2.eq(initialBalanceRewardAddress2.add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + updatedBalanceRewardAddress3.eq(initialBalanceRewardAddress3.add(feePerValidator)) || + updatedBalanceRewardAddress3.eq(initialBalanceRewardAddress3.add(feePerValidatorPlusDiff)) + ).to.equal(true) + }) + it('should distribute fee to 5 validators', async () => { + // Initialize + const owner = accounts[0] + const validators = [accounts[0], accounts[1], accounts[2], accounts[3], accounts[4]] + const rewards = [accounts[5], accounts[6], accounts[7], accounts[8], accounts[9]] + const requiredSignatures = 5 + const rewardableValidators = await RewardableValidators.new() + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + const homeBridge = await HomeBridge.at(storageProxy.address) + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.addMintedTotallyByBridge(oneEther, homeBridge.address) + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feeManager = await FeeManagerErcToNative.new() + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setHomeFee(feeInWei, { from: owner }).should.be.fulfilled + + const recipient = accounts[0] + const initialValue = halfEther + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const feePerValidator = feeAmount.div(toBN(5)) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + const initialBridgeBalance = toBN(await web3.eth.getBalance(homeBridge.address)) + initialBridgeBalance.should.be.bignumber.equal(ZERO) + + const initialBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const initialBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const initialBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + const initialBalanceRewardAddress4 = toBN(await web3.eth.getBalance(rewards[3])) + const initialBalanceRewardAddress5 = toBN(await web3.eth.getBalance(rewards[4])) + + // When + await homeBridge.sendTransaction({ from: recipient, value: initialValue }).should.be.fulfilled + + const afterTransferBridgeBalance = toBN(await web3.eth.getBalance(homeBridge.address)) + afterTransferBridgeBalance.should.be.bignumber.equal(feeAmount) + + const message = createMessage(recipient, value, transactionHash, homeBridge.address) + + const signature = await sign(validators[0], message) + const signature2 = await sign(validators[1], message) + const signature3 = await sign(validators[2], message) + const signature4 = await sign(validators[3], message) + const signature5 = await sign(validators[4], message) + + await homeBridge.submitSignature(signature, message, { from: validators[0] }).should.be.fulfilled + await homeBridge.submitSignature(signature2, message, { from: validators[1] }).should.be.fulfilled + await homeBridge.submitSignature(signature3, message, { from: validators[2] }).should.be.fulfilled + await homeBridge.submitSignature(signature4, message, { from: validators[3] }).should.be.fulfilled + const { logs } = await homeBridge.submitSignature(signature5, message, { + from: validators[4] + }).should.be.fulfilled + + // Then + logs.length.should.be.equal(3) + logs[1].event.should.be.equal('CollectedSignatures') + logs[2].event.should.be.equal('FeeDistributedFromSignatures') + + const updatedBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const updatedBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const updatedBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + const updatedBalanceRewardAddress4 = toBN(await web3.eth.getBalance(rewards[3])) + const updatedBalanceRewardAddress5 = toBN(await web3.eth.getBalance(rewards[4])) + + updatedBalanceRewardAddress1.should.be.bignumber.equal(initialBalanceRewardAddress1.add(feePerValidator)) + updatedBalanceRewardAddress2.should.be.bignumber.equal(initialBalanceRewardAddress2.add(feePerValidator)) + updatedBalanceRewardAddress3.should.be.bignumber.equal(initialBalanceRewardAddress3.add(feePerValidator)) + updatedBalanceRewardAddress4.should.be.bignumber.equal(initialBalanceRewardAddress4.add(feePerValidator)) + updatedBalanceRewardAddress5.should.be.bignumber.equal(initialBalanceRewardAddress5.add(feePerValidator)) + }) + }) + describe('#FeeManager_random', async () => { + it('should return value between 0 and 3', async () => { + // Given + const feeManager = await FeeManagerErcToNative.new() + + for (let i = 0; i < 10; i++) { + // send Tx to generate new blocks + await feeManager.setHomeFee(0).should.be.fulfilled + + // When + const result = await feeManager.random(3) + + // Then + expect(result).to.be.bignumber.gte(ZERO) + expect(result).to.be.bignumber.lt('3') + } + }) + }) + describe('#feeManager_ExecuteAffirmation_POSDAO', async () => { + it('should distribute fee to validator', async () => { + // Initialize + const owner = accounts[9] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + const rewardableValidators = await RewardableValidators.new() + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + const homeBridge = await HomeBridge.at(storageProxy.address) + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + + await blockRewardContract.setValidatorsRewards(rewards) + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.sendTransaction({ + from: accounts[2], + value: oneEther + }).should.be.fulfilled + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feeManager = await FeeManagerErcToNativePOSDAO.new() + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setForeignFee(feeInWei, { from: owner }).should.be.fulfilled + + const recipient = accounts[5] + const value = halfEther + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const valueCalc = 0.5 * (1 - fee) + const finalValue = ether(valueCalc.toString()) + const balanceBefore = await web3.eth.getBalance(recipient) + const rewardAddressBalanceBefore = await web3.eth.getBalance(rewards[0]) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + // When + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[0] + }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: validators[0], + transactionHash + }) + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + const balanceAfter = await web3.eth.getBalance(recipient) + const rewardAddressBalanceAfter = await web3.eth.getBalance(rewards[0]) + + expect(toBN(rewardAddressBalanceAfter)).to.be.bignumber.equal(toBN(rewardAddressBalanceBefore).add(feeAmount)) + expect(toBN(balanceAfter)).to.be.bignumber.equal(toBN(balanceBefore).add(finalValue)) + + const feeAmountBlockReward = await blockRewardContract.feeAmount() + feeAmountBlockReward.should.be.bignumber.equal(feeAmount) + }) + it('should distribute fee to 3 validators', async () => { + // Initialize + const owner = accounts[9] + const validators = [accounts[1], accounts[2], accounts[3]] + const rewards = [accounts[4], accounts[5], accounts[6]] + const requiredSignatures = 2 + const rewardableValidators = await RewardableValidators.new() + const homeBridgeImpl = await HomeBridge.new() + const blockRewardContract = await BlockReward.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + const homeBridge = await HomeBridge.at(storageProxy.address) + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await blockRewardContract.setValidatorsRewards(rewards) + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.sendTransaction({ + from: accounts[0], + value: halfEther + }).should.be.fulfilled + + // Given + const initialBlockRewardBalance = await web3.eth.getBalance(blockRewardContract.address) + expect(toBN(initialBlockRewardBalance)).to.be.bignumber.equal(halfEther) + + const value = halfEther + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const valueCalc = 0.5 * (1 - fee) + const finalValue = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + // totalFee / 3 + const feePerValidator = toBN(166666666666666) + const feePerValidatorPlusDiff = toBN(166666666666668) + const feeManager = await FeeManagerErcToNativePOSDAO.new() + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setForeignFee(feeInWei, { from: owner }).should.be.fulfilled + + const recipient = accounts[8] + const balanceBefore = await web3.eth.getBalance(recipient) + + const initialBalanceRewardAddress1 = await web3.eth.getBalance(rewards[0]) + const initialBalanceRewardAddress2 = await web3.eth.getBalance(rewards[1]) + const initialBalanceRewardAddress3 = await web3.eth.getBalance(rewards[2]) + + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + // When + const { logs: logsValidator1 } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[0] + }).should.be.fulfilled + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[1] + }).should.be.fulfilled + + // Then + logsValidator1.length.should.be.equals(1) + + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: validators[1], + transactionHash + }) + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + + const balanceAfter = await web3.eth.getBalance(recipient) + expect(toBN(balanceAfter)).to.be.bignumber.equal(toBN(balanceBefore).add(finalValue)) + + const updatedBalanceRewardAddress1 = await web3.eth.getBalance(rewards[0]) + const updatedBalanceRewardAddress2 = await web3.eth.getBalance(rewards[1]) + const updatedBalanceRewardAddress3 = await web3.eth.getBalance(rewards[2]) + + expect( + toBN(updatedBalanceRewardAddress1).eq(toBN(initialBalanceRewardAddress1).add(feePerValidator)) || + toBN(updatedBalanceRewardAddress1).eq(toBN(initialBalanceRewardAddress1).add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + toBN(updatedBalanceRewardAddress2).eq(toBN(initialBalanceRewardAddress2).add(feePerValidator)) || + toBN(updatedBalanceRewardAddress2).eq(toBN(initialBalanceRewardAddress2).add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + toBN(updatedBalanceRewardAddress3).eq(toBN(initialBalanceRewardAddress3).add(feePerValidator)) || + toBN(updatedBalanceRewardAddress3).eq(toBN(initialBalanceRewardAddress3).add(feePerValidatorPlusDiff)) + ).to.equal(true) + + const feeAmountBlockReward = await blockRewardContract.feeAmount() + expect(toBN(feeAmountBlockReward)).to.be.bignumber.equal(feeAmount) + + const blockRewardBalance = await web3.eth.getBalance(blockRewardContract.address) + expect(toBN(blockRewardBalance)).to.be.bignumber.equal(ZERO) + }) + it('should distribute fee to 5 validators', async () => { + // Initialize + const owner = accounts[0] + const validators = [accounts[0], accounts[1], accounts[2], accounts[3], accounts[4]] + const rewards = [accounts[5], accounts[6], accounts[7], accounts[8], accounts[9]] + const requiredSignatures = 5 + const rewardableValidators = await RewardableValidators.new() + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + const homeBridge = await HomeBridge.at(storageProxy.address) + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await blockRewardContract.setValidatorsRewards(rewards) + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.sendTransaction({ + from: accounts[0], + value: oneEther + }).should.be.fulfilled + + // Given + const value = halfEther + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const feePerValidator = feeAmount.div(toBN(5)) + const feeManager = await FeeManagerErcToNativePOSDAO.new() + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setForeignFee(feeInWei, { from: owner }).should.be.fulfilled + + const recipient = '0xf4BEF13F9f4f2B203FAF0C3cBbaAbe1afE056955' + const balanceBefore = await web3.eth.getBalance(recipient) + + const initialBalanceRewardAddress1 = await web3.eth.getBalance(rewards[0]) + const initialBalanceRewardAddress2 = await web3.eth.getBalance(rewards[1]) + const initialBalanceRewardAddress3 = await web3.eth.getBalance(rewards[2]) + const initialBalanceRewardAddress4 = await web3.eth.getBalance(rewards[3]) + const initialBalanceRewardAddress5 = await web3.eth.getBalance(rewards[4]) + + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + // When + const { logs: logsValidator1 } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[0] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[1] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[2] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[3] + }).should.be.fulfilled + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[4] + }).should.be.fulfilled + + // Then + logsValidator1.length.should.be.equals(1) + + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: validators[4], + transactionHash + }) + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + + const balanceAfter = await web3.eth.getBalance(recipient) + expect(toBN(balanceAfter)).to.be.bignumber.equal(toBN(balanceBefore).add(value.sub(feeAmount))) + + const updatedBalanceRewardAddress1 = await web3.eth.getBalance(rewards[0]) + const updatedBalanceRewardAddress2 = await web3.eth.getBalance(rewards[1]) + const updatedBalanceRewardAddress3 = await web3.eth.getBalance(rewards[2]) + const updatedBalanceRewardAddress4 = await web3.eth.getBalance(rewards[3]) + const updatedBalanceRewardAddress5 = await web3.eth.getBalance(rewards[4]) + + expect(toBN(updatedBalanceRewardAddress1)).to.be.bignumber.equal( + toBN(initialBalanceRewardAddress1).add(feePerValidator) + ) + expect(toBN(updatedBalanceRewardAddress2)).to.be.bignumber.equal( + toBN(initialBalanceRewardAddress2).add(feePerValidator) + ) + expect(toBN(updatedBalanceRewardAddress3)).to.be.bignumber.equal( + toBN(initialBalanceRewardAddress3).add(feePerValidator) + ) + expect(toBN(updatedBalanceRewardAddress4)).to.be.bignumber.equal( + toBN(initialBalanceRewardAddress4).add(feePerValidator) + ) + expect(toBN(updatedBalanceRewardAddress5)).to.be.bignumber.equal( + toBN(initialBalanceRewardAddress5).add(feePerValidator) + ) + + const feeAmountBlockReward = await blockRewardContract.feeAmount() + expect(toBN(feeAmountBlockReward)).to.be.bignumber.equal(feeAmount) + }) + }) + describe('#feeManager_fallback_POSDAO', async () => { + let homeBridge + let rewardableValidators + const owner = accounts[9] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + beforeEach(async () => { + rewardableValidators = await RewardableValidators.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + homeBridge = await HomeBridge.at(storageProxy.address) + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.addMintedTotallyByBridge(oneEther, homeBridge.address) + }) + + it('should subtract fee from value', async () => { + // Given + // 0.1% fee + const value = halfEther + const recipient = accounts[8] + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feeManager = await FeeManagerErcToNativePOSDAO.new() + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setHomeFee(feeInWei, { from: owner }).should.be.fulfilled + + // When + const { logs } = await homeBridge.sendTransaction({ from: recipient, value }).should.be.fulfilled + + // Then + const valueCalc = 0.5 * (1 - fee) + const finalValue = ether(valueCalc.toString()) + expectEventInLogs(logs, 'UserRequestForSignature', { + recipient, + value: finalValue + }) + const currentDay = await homeBridge.getCurrentDay() + value.should.be.bignumber.equal(await homeBridge.totalSpentPerDay(currentDay)) + value.should.be.bignumber.equal(await homeBridge.totalBurntCoins()) + const homeBridgeBalance = await web3.eth.getBalance(homeBridge.address) + expect(toBN(homeBridgeBalance)).to.be.bignumber.equal(ZERO) + }) + }) + describe('#feeManager_submitSignature_POSDAO', async () => { + it('should distribute fee to validator', async () => { + // Initialize + const owner = accounts[9] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + const rewardableValidators = await RewardableValidators.new() + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + const homeBridge = await HomeBridge.at(storageProxy.address) + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await blockRewardContract.setValidatorsRewards(rewards) + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.addMintedTotallyByBridge(oneEther, homeBridge.address) + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feeManager = await FeeManagerErcToNativePOSDAO.new() + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setHomeFee(feeInWei, { from: owner }).should.be.fulfilled + + const recipient = accounts[5] + const initialValue = halfEther + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const rewardAddressBalanceBefore = await web3.eth.getBalance(rewards[0]) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + const initialBridgeBalance = await web3.eth.getBalance(homeBridge.address) + expect(toBN(initialBridgeBalance)).to.be.bignumber.equal(ZERO) + + // When + await homeBridge.sendTransaction({ from: recipient, value: initialValue }).should.be.fulfilled + + const afterTransferBridgeBalance = await web3.eth.getBalance(homeBridge.address) + expect(toBN(afterTransferBridgeBalance)).to.be.bignumber.equal(ZERO) + + const message = createMessage(recipient, value, transactionHash, homeBridge.address) + + const signature = await sign(validators[0], message) + + const { logs } = await homeBridge.submitSignature(signature, message, { from: validators[0] }).should.be.fulfilled + + // Then + logs.length.should.be.equal(3) + logs[1].event.should.be.equal('CollectedSignatures') + expectEventInLogs(logs, 'FeeDistributedFromSignatures', { + feeAmount, + transactionHash + }) + + const finalBridgeBalance = await web3.eth.getBalance(homeBridge.address) + expect(toBN(finalBridgeBalance)).to.be.bignumber.equal(ZERO) + + const rewardAddressBalanceAfter = await web3.eth.getBalance(rewards[0]) + expect(toBN(rewardAddressBalanceAfter)).to.be.bignumber.equal(toBN(rewardAddressBalanceBefore).add(feeAmount)) + + const feeAmountBlockReward = await blockRewardContract.feeAmount() + expect(toBN(feeAmountBlockReward)).to.be.bignumber.equal(feeAmount) + }) + it('should distribute fee to 3 validators', async () => { + // Initialize + const owner = accounts[9] + const validators = [accounts[1], accounts[2], accounts[3]] + const rewards = [accounts[4], accounts[5], accounts[6]] + const requiredSignatures = 3 + const rewardableValidators = await RewardableValidators.new() + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + const homeBridge = await HomeBridge.at(storageProxy.address) + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await blockRewardContract.setValidatorsRewards(rewards) + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.addMintedTotallyByBridge(oneEther, homeBridge.address) + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feeManager = await FeeManagerErcToNativePOSDAO.new() + const feePerValidator = toBN(166666666666666) + const feePerValidatorPlusDiff = toBN(166666666666668) + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setHomeFee(feeInWei, { from: owner }).should.be.fulfilled + + const recipient = accounts[7] + const initialValue = halfEther + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + const initialBridgeBalance = await web3.eth.getBalance(homeBridge.address) + expect(toBN(initialBridgeBalance)).to.be.bignumber.equal(ZERO) + + const initialBalanceRewardAddress1 = await web3.eth.getBalance(rewards[0]) + const initialBalanceRewardAddress2 = await web3.eth.getBalance(rewards[1]) + const initialBalanceRewardAddress3 = await web3.eth.getBalance(rewards[2]) + + // When + await homeBridge.sendTransaction({ from: recipient, value: initialValue }).should.be.fulfilled + + const afterTransferBridgeBalance = await web3.eth.getBalance(homeBridge.address) + expect(toBN(afterTransferBridgeBalance)).to.be.bignumber.equal(ZERO) + + const message = createMessage(recipient, value, transactionHash, homeBridge.address) + + const signature = await sign(validators[0], message) + const signature2 = await sign(validators[1], message) + const signature3 = await sign(validators[2], message) + + await homeBridge.submitSignature(signature, message, { from: validators[0] }).should.be.fulfilled + await homeBridge.submitSignature(signature2, message, { from: validators[1] }).should.be.fulfilled + const { logs } = await homeBridge.submitSignature(signature3, message, { + from: validators[2] + }).should.be.fulfilled + + // Then + logs.length.should.be.equal(3) + logs[1].event.should.be.equal('CollectedSignatures') + expectEventInLogs(logs, 'FeeDistributedFromSignatures', { + feeAmount, + transactionHash + }) + + const updatedBalanceRewardAddress1 = await web3.eth.getBalance(rewards[0]) + const updatedBalanceRewardAddress2 = await web3.eth.getBalance(rewards[1]) + const updatedBalanceRewardAddress3 = await web3.eth.getBalance(rewards[2]) + + const bridgeBalance = await web3.eth.getBalance(homeBridge.address) + expect(toBN(bridgeBalance)).to.be.bignumber.equal(ZERO) + + expect( + toBN(updatedBalanceRewardAddress1).eq(toBN(initialBalanceRewardAddress1).add(feePerValidator)) || + toBN(updatedBalanceRewardAddress1).eq(toBN(initialBalanceRewardAddress1).add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + toBN(updatedBalanceRewardAddress2).eq(toBN(initialBalanceRewardAddress2).add(feePerValidator)) || + toBN(updatedBalanceRewardAddress2).eq(toBN(initialBalanceRewardAddress2).add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + toBN(updatedBalanceRewardAddress3).eq(toBN(initialBalanceRewardAddress3).add(feePerValidator)) || + toBN(updatedBalanceRewardAddress3).eq(toBN(initialBalanceRewardAddress3).add(feePerValidatorPlusDiff)) + ).to.equal(true) + + const feeAmountBlockReward = await blockRewardContract.feeAmount() + expect(toBN(feeAmountBlockReward)).to.be.bignumber.equal(feeAmount) + }) + it('should distribute fee to 5 validators', async () => { + // Initialize + const owner = accounts[0] + const validators = [accounts[0], accounts[1], accounts[2], accounts[3], accounts[4]] + const rewards = [accounts[5], accounts[6], accounts[7], accounts[8], accounts[9]] + const requiredSignatures = 5 + const rewardableValidators = await RewardableValidators.new() + const homeBridgeImpl = await HomeBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled + const homeBridge = await HomeBridge.at(storageProxy.address) + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await blockRewardContract.setValidatorsRewards(rewards) + await homeBridge.initialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + blockRewardContract.address, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + await blockRewardContract.addMintedTotallyByBridge(oneEther, homeBridge.address) + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feeManager = await FeeManagerErcToNativePOSDAO.new() + await homeBridge.setFeeManagerContract(feeManager.address, { from: owner }).should.be.fulfilled + await homeBridge.setHomeFee(feeInWei, { from: owner }).should.be.fulfilled + + const recipient = accounts[0] + const initialValue = halfEther + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const feePerValidator = feeAmount.div(toBN(5)) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + const initialBridgeBalance = await web3.eth.getBalance(homeBridge.address) + expect(toBN(initialBridgeBalance)).to.be.bignumber.equal(ZERO) + + const initialBalanceRewardAddress1 = await web3.eth.getBalance(rewards[0]) + const initialBalanceRewardAddress2 = await web3.eth.getBalance(rewards[1]) + const initialBalanceRewardAddress3 = await web3.eth.getBalance(rewards[2]) + const initialBalanceRewardAddress4 = await web3.eth.getBalance(rewards[3]) + const initialBalanceRewardAddress5 = await web3.eth.getBalance(rewards[4]) + + // When + await homeBridge.sendTransaction({ from: recipient, value: initialValue }).should.be.fulfilled + + const afterTransferBridgeBalance = await web3.eth.getBalance(homeBridge.address) + expect(toBN(afterTransferBridgeBalance)).to.be.bignumber.equal(ZERO) + + const message = createMessage(recipient, value, transactionHash, homeBridge.address) + + const signature = await sign(validators[0], message) + const signature2 = await sign(validators[1], message) + const signature3 = await sign(validators[2], message) + const signature4 = await sign(validators[3], message) + const signature5 = await sign(validators[4], message) + + await homeBridge.submitSignature(signature, message, { from: validators[0] }).should.be.fulfilled + await homeBridge.submitSignature(signature2, message, { from: validators[1] }).should.be.fulfilled + await homeBridge.submitSignature(signature3, message, { from: validators[2] }).should.be.fulfilled + await homeBridge.submitSignature(signature4, message, { from: validators[3] }).should.be.fulfilled + const { logs } = await homeBridge.submitSignature(signature5, message, { + from: validators[4] + }).should.be.fulfilled + + // Then + logs.length.should.be.equal(3) + logs[1].event.should.be.equal('CollectedSignatures') + expectEventInLogs(logs, 'FeeDistributedFromSignatures', { + feeAmount, + transactionHash + }) + + const updatedBalanceRewardAddress1 = await web3.eth.getBalance(rewards[0]) + const updatedBalanceRewardAddress2 = await web3.eth.getBalance(rewards[1]) + const updatedBalanceRewardAddress3 = await web3.eth.getBalance(rewards[2]) + const updatedBalanceRewardAddress4 = await web3.eth.getBalance(rewards[3]) + const updatedBalanceRewardAddress5 = await web3.eth.getBalance(rewards[4]) + + expect(toBN(updatedBalanceRewardAddress1)).to.be.bignumber.equal( + toBN(initialBalanceRewardAddress1).add(feePerValidator) + ) + expect(toBN(updatedBalanceRewardAddress2)).to.be.bignumber.equal( + toBN(initialBalanceRewardAddress2).add(feePerValidator) + ) + expect(toBN(updatedBalanceRewardAddress3)).to.be.bignumber.equal( + toBN(initialBalanceRewardAddress3).add(feePerValidator) + ) + expect(toBN(updatedBalanceRewardAddress4)).to.be.bignumber.equal( + toBN(initialBalanceRewardAddress4).add(feePerValidator) + ) + expect(toBN(updatedBalanceRewardAddress5)).to.be.bignumber.equal( + toBN(initialBalanceRewardAddress5).add(feePerValidator) + ) + + const feeAmountBlockReward = await blockRewardContract.feeAmount() + feeAmountBlockReward.should.be.bignumber.equal(feeAmount) + }) + }) }) diff --git a/test/helpers/helpers.js b/test/helpers/helpers.js index cb276a2a8..41e10bfcb 100644 --- a/test/helpers/helpers.js +++ b/test/helpers/helpers.js @@ -1,113 +1,164 @@ +const { expect } = require('chai') +const { BN } = require('../setup') + // returns a Promise that resolves with a hex string that is the signature of // `data` signed with the key of `address` function sign(address, data) { - return new Promise(function(resolve, reject) { - web3.eth.sign(address, data, function(err, result) { + return new Promise((resolve, reject) => { + web3.eth.sign(data, address, (err, result) => { if (err !== null) { - return reject(err); - } else { - return resolve(normalizeSignature(result)); - //return resolve(result); + return reject(err) } + return resolve(normalizeSignature(result)) + // return resolve(result); }) }) } -module.exports.sign = sign; +module.exports.sign = sign // geth && testrpc has different output of eth_sign than parity // https://github.com/ethereumjs/testrpc/issues/243#issuecomment-326750236 -function normalizeSignature(signature) { - signature = strip0x(signature); +function normalizeSignature(rawSignature) { + const signature = strip0x(rawSignature) // increase v by 27... - return "0x" + signature.substr(0, 128) + (parseInt(signature.substr(128), 16) + 27).toString(16); + return `0x${signature.substr(0, 128)}${(parseInt(signature.substr(128), 16) + 27).toString(16)}` } -module.exports.normalizeSignature = normalizeSignature; +module.exports.normalizeSignature = normalizeSignature // strips leading "0x" if present function strip0x(input) { - return input.replace(/^0x/, ""); + return input.replace(/^0x/, '') } -module.exports.strip0x = strip0x; +module.exports.strip0x = strip0x // extracts and returns the `v`, `r` and `s` values from a `signature`. // all inputs and outputs are hex strings with leading '0x'. -function signatureToVRS(signature) { - assert.equal(signature.length, 2 + 32 * 2 + 32 * 2 + 2); - signature = strip0x(signature); - var v = parseInt(signature.substr(64 * 2), 16); - var r = "0x" + signature.substr(0, 32 * 2); - var s = "0x" + signature.substr(32 * 2, 32 * 2); - return {v: v, r: r, s: s}; +function signatureToVRS(rawSignature) { + assert.equal(rawSignature.length, 2 + 32 * 2 + 32 * 2 + 2) + const signature = strip0x(rawSignature) + const v = parseInt(signature.substr(64 * 2), 16) + const r = `0x${signature.substr(0, 32 * 2)}` + const s = `0x${signature.substr(32 * 2, 32 * 2)}` + return { v, r, s } } -module.exports.signatureToVRS = signatureToVRS; +module.exports.signatureToVRS = signatureToVRS // returns BigNumber `num` converted to a little endian hex string // that is exactly 32 bytes long. // `num` must represent an unsigned integer function bigNumberToPaddedBytes32(num) { - assert(web3._extend.utils.isBigNumber(num)); - assert(num.isInteger()); - assert(!num.isNegative()); - var result = strip0x(num.toString(16)); + let result = strip0x(num.toString(16)) while (result.length < 64) { - result = "0" + result; + result = `0${result}` } - return "0x" + result; + return `0x${result}` } -module.exports.bigNumberToPaddedBytes32 = bigNumberToPaddedBytes32; +module.exports.bigNumberToPaddedBytes32 = bigNumberToPaddedBytes32 // returns an promise that resolves to an object // that maps `addresses` to their current balances function getBalances(addresses) { - return Promise.all(addresses.map(function(address) { - return web3.eth.getBalance(address); - })).then(function(balancesArray) { - let addressToBalance = {}; - addresses.forEach(function(address, index) { - addressToBalance[address] = balancesArray[index]; - }); - return addressToBalance; + return Promise.all( + addresses.map(address => { + return web3.eth.getBalance(address) + }) + ).then(balancesArray => { + const addressToBalance = {} + addresses.forEach((address, index) => { + addressToBalance[address] = balancesArray[index] + }) + return addressToBalance }) } -module.exports.getBalances = getBalances; - +module.exports.getBalances = getBalances // returns hex string of the bytes of the message // composed from `recipient`, `value` and `transactionHash` // that is relayed from `foreign` to `home` on withdraw -function createMessage(recipient, value, transactionHash, contractAddress) { - web3._extend.utils.isBigNumber(value); - recipient = strip0x(recipient); - assert.equal(recipient.length, 20 * 2); +function createMessage(rawRecipient, rawValue, rawTransactionHash, rawContractAddress) { + const recipient = strip0x(rawRecipient) + assert.equal(recipient.length, 20 * 2) - var value = strip0x(bigNumberToPaddedBytes32(value)); - assert.equal(value.length, 64); + const value = strip0x(bigNumberToPaddedBytes32(rawValue)) + assert.equal(value.length, 64) - transactionHash = strip0x(transactionHash); - assert.equal(transactionHash.length, 32 * 2); + const transactionHash = strip0x(rawTransactionHash) + assert.equal(transactionHash.length, 32 * 2) - contractAddress = strip0x(contractAddress); - assert.equal(contractAddress.length, 20 * 2); + const contractAddress = strip0x(rawContractAddress) + assert.equal(contractAddress.length, 20 * 2) - var message = "0x" + recipient + value + transactionHash + contractAddress; - var expectedMessageLength = (20 + 32 + 32 + 20) * 2 + 2; - assert.equal(message.length, expectedMessageLength); - return message; + const message = `0x${recipient}${value}${transactionHash}${contractAddress}` + const expectedMessageLength = (20 + 32 + 32 + 20) * 2 + 2 + assert.equal(message.length, expectedMessageLength) + return message } -module.exports.createMessage = createMessage; +module.exports.createMessage = createMessage // returns array of integers progressing from `start` up to, but not including, `end` function range(start, end) { - var result = []; - for (var i = start; i < end; i++) { - result.push(i); + const result = [] + for (let i = start; i < end; i++) { + result.push(i) } - return result; + return result } -module.exports.range = range; +module.exports.range = range // just used to signal/document that we're explicitely ignoring/expecting an error -function ignoreExpectedError() { +function ignoreExpectedError() {} +module.exports.ignoreExpectedError = ignoreExpectedError + +const getEvents = (truffleInstance, filter, fromBlock = 0, toBlock = 'latest') => + truffleInstance.contract.getPastEvents(filter.event, { fromBlock, toBlock }) + +module.exports.getEvents = getEvents + +function ether(n) { + return new BN(web3.utils.toWei(n, 'ether')) } -module.exports.ignoreExpectedError = ignoreExpectedError; + +module.exports.ether = ether + +function expectEventInLogs(logs, eventName, eventArgs = {}) { + const events = logs.filter(e => e.event === eventName) + expect(events.length > 0).to.equal(true, `There is no '${eventName}'`) + + const exception = [] + const event = events.find(e => { + for (const [k, v] of Object.entries(eventArgs)) { + try { + contains(e.args, k, v) + } catch (error) { + exception.push(error) + return false + } + } + return true + }) + + if (event === undefined) { + throw exception[0] + } + + return event +} + +function contains(args, key, value) { + expect(key in args).to.equal(true, `Unknown event argument '${key}'`) + + if (value === null) { + expect(args[key]).to.equal(null) + } else if (isBN(args[key])) { + expect(args[key]).to.be.bignumber.equal(value) + } else { + expect(args[key]).to.be.equal(value) + } +} + +function isBN(object) { + return BN.isBN(object) || object instanceof BN +} + +module.exports.expectEventInLogs = expectEventInLogs diff --git a/test/mockContracts/ERC677BridgeTokenRewardableMock.sol b/test/mockContracts/ERC677BridgeTokenRewardableMock.sol new file mode 100644 index 000000000..2fd7f0c97 --- /dev/null +++ b/test/mockContracts/ERC677BridgeTokenRewardableMock.sol @@ -0,0 +1,22 @@ +pragma solidity 0.4.24; + +import '../../contracts/ERC677BridgeTokenRewardable.sol'; + + +contract ERC677BridgeTokenRewardableMock is ERC677BridgeTokenRewardable { + + constructor( + string _name, + string _symbol, + uint8 _decimals + ) public ERC677BridgeTokenRewardable(_name, _symbol, _decimals) {} + + function setBlockRewardContractMock(address _blockRewardContract) public { + blockRewardContract = _blockRewardContract; + } + + function setStakingContractMock(address _stakingContract) public { + stakingContract = _stakingContract; + } + +} diff --git a/test/native_to_erc/foreign_bridge_test.js b/test/native_to_erc/foreign_bridge_test.js index 7bff1378a..3e43832a2 100644 --- a/test/native_to_erc/foreign_bridge_test.js +++ b/test/native_to_erc/foreign_bridge_test.js @@ -1,265 +1,357 @@ -const ForeignBridge = artifacts.require("ForeignBridgeNativeToErc.sol"); -const ForeignBridgeV2 = artifacts.require("ForeignBridgeV2.sol"); -const BridgeValidators = artifacts.require("BridgeValidators.sol"); -const EternalStorageProxy = artifacts.require("EternalStorageProxy.sol"); - -const POA20 = artifacts.require("ERC677BridgeToken.sol"); -const {ERROR_MSG, ZERO_ADDRESS, ERROR_MSG_OPCODE} = require('../setup'); -const {createMessage, sign, signatureToVRS, strip0x} = require('../helpers/helpers'); -const oneEther = web3.toBigNumber(web3.toWei(1, "ether")); -const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether")); -const minPerTx = web3.toBigNumber(web3.toWei(0.01, "ether")); -const Web3Utils = require('web3-utils'); -const requireBlockConfirmations = 8; -const gasPrice = Web3Utils.toWei('1', 'gwei'); +const ForeignBridge = artifacts.require('ForeignBridgeNativeToErc.sol') +const ForeignBridgeV2 = artifacts.require('ForeignBridgeV2.sol') +const BridgeValidators = artifacts.require('BridgeValidators.sol') +const EternalStorageProxy = artifacts.require('EternalStorageProxy.sol') +const FeeManagerNativeToErc = artifacts.require('FeeManagerNativeToErc.sol') +const RewardableValidators = artifacts.require('RewardableValidators.sol') +const POA20 = artifacts.require('ERC677BridgeToken.sol') + +const { expect } = require('chai') +const { ERROR_MSG, ZERO_ADDRESS, toBN } = require('../setup') +const { createMessage, sign, signatureToVRS, getEvents, ether } = require('../helpers/helpers') + +const oneEther = ether('1') +const halfEther = ether('0.5') +const minPerTx = ether('0.01') +const requireBlockConfirmations = 8 +const gasPrice = web3.utils.toWei('1', 'gwei') const homeDailyLimit = oneEther const homeMaxPerTx = halfEther +const ZERO = toBN(0) -const getEvents = function(contract, filter) { - return new Promise((resolve, reject) => { - var event = contract[filter.event](); - event.watch(); - event.get((error, logs) => { - if(logs.length > 0){ - resolve(logs); - } else { - throw Error("Failed to find filtered event for " + filter.event); - } - }); - event.stopWatching(); - }); -} -contract('ForeignBridge', async (accounts) => { - let validatorContract, authorities, owner, token; +contract('ForeignBridge', async accounts => { + let validatorContract + let authorities + let owner + let token before(async () => { validatorContract = await BridgeValidators.new() - authorities = [accounts[1], accounts[2]]; + authorities = [accounts[1], accounts[2]] owner = accounts[0] await validatorContract.initialize(1, authorities, owner) }) describe('#initialize', async () => { it('should initialize', async () => { - token = await POA20.new("POA ERC20 Foundation", "POA20", 18); - let foreignBridge = await ForeignBridge.new(); - - ZERO_ADDRESS.should.be.equal(await foreignBridge.validatorContract()) - '0'.should.be.bignumber.equal(await foreignBridge.deployedAtBlock()) - '0'.should.be.bignumber.equal(await foreignBridge.dailyLimit()) - '0'.should.be.bignumber.equal(await foreignBridge.maxPerTx()) - false.should.be.equal(await foreignBridge.isInitialized()) - - await foreignBridge.initialize(ZERO_ADDRESS, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(validatorContract.address, ZERO_ADDRESS, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, 0, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(owner, token.address, oneEther, halfEther, minPerTx, requireBlockConfirmations, gasPrice, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(validatorContract.address, owner, oneEther, halfEther, minPerTx, requireBlockConfirmations, gasPrice, homeDailyLimit, homeMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner); - - true.should.be.equal(await foreignBridge.isInitialized()) - validatorContract.address.should.be.equal(await foreignBridge.validatorContract()); - (await foreignBridge.deployedAtBlock()).should.be.bignumber.above(0); - oneEther.should.be.bignumber.equal(await foreignBridge.dailyLimit()) - halfEther.should.be.bignumber.equal(await foreignBridge.maxPerTx()) - minPerTx.should.be.bignumber.equal(await foreignBridge.minPerTx()) + token = await POA20.new('POA ERC20 Foundation', 'POA20', 18) + const foreignBridge = await ForeignBridge.new() + + expect(await foreignBridge.validatorContract()).to.be.equal(ZERO_ADDRESS) + expect(await foreignBridge.deployedAtBlock()).to.be.bignumber.equal(ZERO) + expect(await foreignBridge.isInitialized()).to.be.equal(false) + expect(await foreignBridge.requiredBlockConfirmations()).to.be.bignumber.equal(ZERO) + expect(await foreignBridge.dailyLimit()).to.be.bignumber.equal(ZERO) + expect(await foreignBridge.maxPerTx()).to.be.bignumber.equal(ZERO) + + await foreignBridge + .initialize( + ZERO_ADDRESS, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + validatorContract.address, + ZERO_ADDRESS, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + validatorContract.address, + token.address, + oneEther, + halfEther, + minPerTx, + 0, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + owner, + token.address, + oneEther, + halfEther, + minPerTx, + requireBlockConfirmations, + gasPrice, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .initialize( + validatorContract.address, + owner, + oneEther, + halfEther, + minPerTx, + requireBlockConfirmations, + gasPrice, + homeDailyLimit, + homeMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge.initialize( + validatorContract.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) + + expect(await foreignBridge.isInitialized()).to.be.equal(true) + expect(await foreignBridge.validatorContract()).to.be.equal(validatorContract.address) + expect(await foreignBridge.deployedAtBlock()).to.be.bignumber.above(ZERO) + expect(await foreignBridge.requiredBlockConfirmations()).to.be.bignumber.equal( + requireBlockConfirmations.toString() + ) + expect(await foreignBridge.gasPrice()).to.be.bignumber.equal(gasPrice) + expect(await foreignBridge.dailyLimit()).to.be.bignumber.equal(oneEther) + expect(await foreignBridge.maxPerTx()).to.be.bignumber.equal(halfEther) + expect(await foreignBridge.minPerTx()).to.be.bignumber.equal(minPerTx) const bridgeMode = '0x92a8d7fe' // 4 bytes of keccak256('native-to-erc-core') - const mode = await foreignBridge.getBridgeMode(); - mode.should.be.equal(bridgeMode) - const [major, minor, patch] = await foreignBridge.getBridgeInterfacesVersion() - major.should.be.bignumber.gte(0) - minor.should.be.bignumber.gte(0) - patch.should.be.bignumber.gte(0) + expect(await foreignBridge.getBridgeMode()).to.be.equal(bridgeMode) + const { major, minor, patch } = await foreignBridge.getBridgeInterfacesVersion() + expect(major).to.be.bignumber.gte(ZERO) + expect(minor).to.be.bignumber.gte(ZERO) + expect(patch).to.be.bignumber.gte(ZERO) }) }) + describe('#executeSignatures', async () => { + let foreignBridge beforeEach(async () => { foreignBridge = await ForeignBridge.new() - token = await POA20.new("POA ERC20 Foundation", "POA20", 18); - const oneEther = web3.toBigNumber(web3.toWei(1, "ether")); - const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether")); - await foreignBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner); - oneEther.should.be.bignumber.equal(await foreignBridge.dailyLimit()); - await token.transferOwnership(foreignBridge.address); + token = await POA20.new('POA ERC20 Foundation', 'POA20', 18) + await foreignBridge.initialize( + validatorContract.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) + await token.transferOwnership(foreignBridge.address) }) it('should allow to deposit', async () => { - var recipientAccount = accounts[3]; + const recipientAccount = accounts[3] const balanceBefore = await token.balanceOf(recipientAccount) const totalSupplyBefore = await token.totalSupply() - var value = web3.toBigNumber(web3.toWei(0.25, "ether")); - var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - var message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address); - var signature = await sign(authorities[0], message) - var vrs = signatureToVRS(signature); + const value = ether('0.25') + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address) + const signature = await sign(authorities[0], message) + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) - const {logs} = await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled - logs[0].event.should.be.equal("RelayedMessage") + const { logs } = await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled + logs[0].event.should.be.equal('RelayedMessage') logs[0].args.recipient.should.be.equal(recipientAccount) logs[0].args.value.should.be.bignumber.equal(value) - logs[0].args.transactionHash.should.be.equal(transactionHash); + logs[0].args.transactionHash.should.be.equal(transactionHash) - const balanceAfter = await token.balanceOf(recipientAccount); - const totalSupplyAfter = await token.totalSupply(); + const balanceAfter = await token.balanceOf(recipientAccount) + const totalSupplyAfter = await token.totalSupply() balanceAfter.should.be.bignumber.equal(balanceBefore.add(value)) totalSupplyAfter.should.be.bignumber.equal(totalSupplyBefore.add(value)) true.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) }) it('should reject if address is not foreign address', async () => { - var recipientAccount = accounts[3]; - const balanceBefore = await token.balanceOf(recipientAccount) - const totalSupplyBefore = await token.totalSupply() - var value = web3.toBigNumber(web3.toWei(0.25, "ether")); - var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - var message = createMessage(recipientAccount, value, transactionHash, accounts[0]); - var signature = await sign(authorities[0], message) - var vrs = signatureToVRS(signature); + const recipientAccount = accounts[3] + const value = ether('0.25') + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, accounts[0]) + const signature = await sign(authorities[0], message) + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.rejectedWith(ERROR_MSG) - }) - it('should allow second deposit with different transactionHash but same recipient and value', async ()=> { - var recipientAccount = accounts[3]; + it('should allow second deposit with different transactionHash but same recipient and value', async () => { + const recipientAccount = accounts[3] const balanceBefore = await token.balanceOf(recipientAccount) // tx 1 - var value = web3.toBigNumber(web3.toWei(0.25, "ether")); - var homeGasPrice = web3.toBigNumber(0); - var transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - var message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address); - var signature = await sign(authorities[0], message) - var vrs = signatureToVRS(signature); + const value = ether('0.25') + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address) + const signature = await sign(authorities[0], message) + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled // tx 2 - var transactionHash2 = "0x77a496628a776a03d58d7e6059a5937f04bebd8ba4ff89f76dd4bb8ba7e291ee"; - var message2 = createMessage(recipientAccount, value, transactionHash2, foreignBridge.address); - var signature2 = await sign(authorities[0], message2) - var vrs2 = signatureToVRS(signature2); + const transactionHash2 = '0x77a496628a776a03d58d7e6059a5937f04bebd8ba4ff89f76dd4bb8ba7e291ee' + const message2 = createMessage(recipientAccount, value, transactionHash2, foreignBridge.address) + const signature2 = await sign(authorities[0], message2) + const vrs2 = signatureToVRS(signature2) false.should.be.equal(await foreignBridge.relayedMessages(transactionHash2)) - const {logs} = await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.fulfilled + const { logs } = await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.fulfilled - logs[0].event.should.be.equal("RelayedMessage") + logs[0].event.should.be.equal('RelayedMessage') logs[0].args.recipient.should.be.equal(recipientAccount) logs[0].args.value.should.be.bignumber.equal(value) - logs[0].args.transactionHash.should.be.equal(transactionHash2); + logs[0].args.transactionHash.should.be.equal(transactionHash2) const totalSupply = await token.totalSupply() const balanceAfter = await token.balanceOf(recipientAccount) - balanceAfter.should.be.bignumber.equal(balanceBefore.add(value.mul(2))) - totalSupply.should.be.bignumber.equal(value.mul(2)) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(value.mul(toBN(2)))) + totalSupply.should.be.bignumber.equal(value.mul(toBN(2))) true.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) true.should.be.equal(await foreignBridge.relayedMessages(transactionHash2)) }) it('should not allow second deposit (replay attack) with same transactionHash but different recipient', async () => { - var recipientAccount = accounts[3]; - const balanceBefore = await token.balanceOf(recipientAccount) + const recipientAccount = accounts[3] // tx 1 - var value = web3.toBigNumber(web3.toWei(0.5, "ether")); - var homeGasPrice = web3.toBigNumber(0); - var transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - var message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address); - var signature = await sign(authorities[0], message) - var vrs = signatureToVRS(signature); + const value = halfEther + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address) + const signature = await sign(authorities[0], message) + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled // tx 2 - var message2 = createMessage(accounts[4], value, transactionHash, foreignBridge.address); - var signature2 = await sign(authorities[0], message2) - var vrs = signatureToVRS(signature2); + const message2 = createMessage(accounts[4], value, transactionHash, foreignBridge.address) + const signature2 = await sign(authorities[0], message2) + const vrs2 = signatureToVRS(signature2) true.should.be.equal(await foreignBridge.relayedMessages(transactionHash)) - await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message2).should.be.rejectedWith(ERROR_MSG) + await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.rejectedWith(ERROR_MSG) }) it('should not allow withdraw over home max tx limit', async () => { - const recipientAccount = accounts[3]; - const invalidValue = web3.toBigNumber(web3.toWei(0.75, "ether")); + const recipientAccount = accounts[3] + const invalidValue = ether('0.75') - const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const message = createMessage(recipientAccount, invalidValue, transactionHash, foreignBridge.address); + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, invalidValue, transactionHash, foreignBridge.address) const signature = await sign(authorities[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.rejectedWith(ERROR_MSG) }) it('should not allow withdraw over daily home limit', async () => { - const recipientAccount = accounts[3]; + const recipientAccount = accounts[3] - const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const message = createMessage(recipientAccount, halfEther, transactionHash, foreignBridge.address); + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, halfEther, transactionHash, foreignBridge.address) const signature = await sign(authorities[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled - const transactionHash2 = "0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712"; - const message2 = createMessage(recipientAccount, halfEther, transactionHash2, foreignBridge.address); + const transactionHash2 = '0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712' + const message2 = createMessage(recipientAccount, halfEther, transactionHash2, foreignBridge.address) const signature2 = await sign(authorities[0], message2) - const vrs2 = signatureToVRS(signature2); + const vrs2 = signatureToVRS(signature2) await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.fulfilled - const transactionHash3 = "0x022695428093bb292db8e48bd1417c5e1b84c0bf673bd0fff23ed0fb6495b872"; - const message3 = createMessage(recipientAccount, halfEther, transactionHash3, foreignBridge.address); + const transactionHash3 = '0x022695428093bb292db8e48bd1417c5e1b84c0bf673bd0fff23ed0fb6495b872' + const message3 = createMessage(recipientAccount, halfEther, transactionHash3, foreignBridge.address) const signature3 = await sign(authorities[0], message3) - const vrs3 = signatureToVRS(signature3); + const vrs3 = signatureToVRS(signature3) await foreignBridge.executeSignatures([vrs3.v], [vrs3.r], [vrs3.s], message3).should.be.rejectedWith(ERROR_MSG) }) }) describe('#executeSignatures with 2 minimum signatures', async () => { - let multisigValidatorContract, twoAuthorities, ownerOfValidatorContract, foreignBridgeWithMultiSignatures + let multisigValidatorContract + let twoAuthorities + let ownerOfValidatorContract + let foreignBridgeWithMultiSignatures beforeEach(async () => { multisigValidatorContract = await BridgeValidators.new() - token = await POA20.new("POA ERC20 Foundation", "POA20", 18); - twoAuthorities = [accounts[0], accounts[1]]; + token = await POA20.new('POA ERC20 Foundation', 'POA20', 18) + twoAuthorities = [accounts[0], accounts[1]] ownerOfValidatorContract = accounts[3] - const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether")); - await multisigValidatorContract.initialize(2, twoAuthorities, ownerOfValidatorContract, {from: ownerOfValidatorContract}) + await multisigValidatorContract.initialize(2, twoAuthorities, ownerOfValidatorContract, { + from: ownerOfValidatorContract + }) foreignBridgeWithMultiSignatures = await ForeignBridge.new() - const oneEther = web3.toBigNumber(web3.toWei(1, "ether")); - await foreignBridgeWithMultiSignatures.initialize(multisigValidatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner, {from: ownerOfValidatorContract}); - await token.transferOwnership(foreignBridgeWithMultiSignatures.address); + await foreignBridgeWithMultiSignatures.initialize( + multisigValidatorContract.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner, + { from: ownerOfValidatorContract } + ) + await token.transferOwnership(foreignBridgeWithMultiSignatures.address) }) it('deposit should fail if not enough signatures are provided', async () => { - - var recipientAccount = accounts[4]; - const balanceBefore = await web3.eth.getBalance(recipientAccount) - const homeBalanceBefore = await web3.eth.getBalance(foreignBridgeWithMultiSignatures.address) + const recipientAccount = accounts[4] // msg 1 - var value = web3.toBigNumber(web3.toWei(0.5, "ether")); - var homeGasPrice = web3.toBigNumber(0); - var transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - var message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address); - var signature = await sign(twoAuthorities[0], message) - var vrs = signatureToVRS(signature); + const value = halfEther + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address) + const signature = await sign(twoAuthorities[0], message) + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridgeWithMultiSignatures.relayedMessages(transactionHash)) - await foreignBridgeWithMultiSignatures.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.rejectedWith(ERROR_MSG) + await foreignBridgeWithMultiSignatures + .executeSignatures([vrs.v], [vrs.r], [vrs.s], message) + .should.be.rejectedWith(ERROR_MSG) // msg 2 - var signature2 = await sign(twoAuthorities[1], message) - var vrs2 = signatureToVRS(signature2); - const {logs} = await foreignBridgeWithMultiSignatures.executeSignatures([vrs.v, vrs2.v], [vrs.r, vrs2.r], [vrs.s, vrs2.s], message).should.be.fulfilled; + const signature2 = await sign(twoAuthorities[1], message) + const vrs2 = signatureToVRS(signature2) + const { logs } = await foreignBridgeWithMultiSignatures.executeSignatures( + [vrs.v, vrs2.v], + [vrs.r, vrs2.r], + [vrs.s, vrs2.s], + message + ).should.be.fulfilled - logs[0].event.should.be.equal("RelayedMessage") + logs[0].event.should.be.equal('RelayedMessage') logs[0].args.recipient.should.be.equal(recipientAccount) logs[0].args.value.should.be.bignumber.equal(value) - logs[0].args.transactionHash.should.be.equal(transactionHash); - const balanceAfter = await token.balanceOf(recipientAccount) + logs[0].args.transactionHash.should.be.equal(transactionHash) true.should.be.equal(await foreignBridgeWithMultiSignatures.relayedMessages(transactionHash)) - }) it('deposit should fail if duplicate signature is provided', async () => { - var recipientAccount = accounts[4]; - const balanceBefore = await web3.eth.getBalance(recipientAccount) - const homeBalanceBefore = await web3.eth.getBalance(foreignBridgeWithMultiSignatures.address) + const recipientAccount = accounts[4] // msg 1 - var value = web3.toBigNumber(web3.toWei(0.5, "ether")); - var homeGasPrice = web3.toBigNumber(0); - var transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - var message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address); - var signature = await sign(twoAuthorities[0], message) - var vrs = signatureToVRS(signature); + const value = halfEther + const transactionHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address) + const signature = await sign(twoAuthorities[0], message) + const vrs = signatureToVRS(signature) false.should.be.equal(await foreignBridgeWithMultiSignatures.relayedMessages(transactionHash)) - await foreignBridgeWithMultiSignatures.executeSignatures([vrs.v, vrs.v], [vrs.r, vrs.r], [vrs.s, vrs.s], message).should.be.rejectedWith(ERROR_MSG) + await foreignBridgeWithMultiSignatures + .executeSignatures([vrs.v, vrs.v], [vrs.r, vrs.r], [vrs.s, vrs.s], message) + .should.be.rejectedWith(ERROR_MSG) }) it('works with 5 validators and 3 required signatures', async () => { const recipient = accounts[8] @@ -267,132 +359,222 @@ contract('ForeignBridge', async (accounts) => { const ownerOfValidators = accounts[0] const validatorContractWith3Signatures = await BridgeValidators.new() await validatorContractWith3Signatures.initialize(3, authoritiesFiveAccs, ownerOfValidators) - const erc20Token = await POA20.new("Some ERC20", "RSZT", 18); - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); + const erc20Token = await POA20.new('Some ERC20', 'RSZT', 18) + const value = halfEther const foreignBridgeWithThreeSigs = await ForeignBridge.new() - await foreignBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, erc20Token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner); - await erc20Token.transferOwnership(foreignBridgeWithThreeSigs.address); + await foreignBridgeWithThreeSigs.initialize( + validatorContractWith3Signatures.address, + erc20Token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) + await erc20Token.transferOwnership(foreignBridgeWithThreeSigs.address) - const txHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const message = createMessage(recipient, value, txHash, foreignBridgeWithThreeSigs.address); + const txHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const message = createMessage(recipient, value, txHash, foreignBridgeWithThreeSigs.address) // signature 1 const signature = await sign(authoritiesFiveAccs[0], message) - const vrs = signatureToVRS(signature); + const vrs = signatureToVRS(signature) // signature 2 const signature2 = await sign(authoritiesFiveAccs[1], message) - const vrs2 = signatureToVRS(signature2); + const vrs2 = signatureToVRS(signature2) // signature 3 const signature3 = await sign(authoritiesFiveAccs[2], message) - const vrs3 = signatureToVRS(signature3); - + const vrs3 = signatureToVRS(signature3) - const {logs} = await foreignBridgeWithThreeSigs.executeSignatures([vrs.v, vrs2.v, vrs3.v], [vrs.r, vrs2.r, vrs3.r], [vrs.s, vrs2.s, vrs3.s], message).should.be.fulfilled; - logs[0].event.should.be.equal("RelayedMessage") + const { logs } = await foreignBridgeWithThreeSigs.executeSignatures( + [vrs.v, vrs2.v, vrs3.v], + [vrs.r, vrs2.r, vrs3.r], + [vrs.s, vrs2.s, vrs3.s], + message + ).should.be.fulfilled + logs[0].event.should.be.equal('RelayedMessage') logs[0].args.recipient.should.be.equal(recipient) logs[0].args.value.should.be.bignumber.equal(value) true.should.be.equal(await foreignBridgeWithThreeSigs.relayedMessages(txHash)) }) }) - describe('#onTokenTransfer', async () => { - it('can only be called from token contract', async ()=> { + it('can only be called from token contract', async () => { const owner = accounts[3] const user = accounts[4] - token = await POA20.new("POA ERC20 Foundation", "POA20", 18, {from: owner}); - foreignBridge = await ForeignBridge.new(); - await foreignBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner); - await token.mint(user, halfEther, {from: owner }).should.be.fulfilled; - await token.transferOwnership(foreignBridge.address, {from: owner}); - await foreignBridge.onTokenTransfer(user, halfEther, '0x00', {from: owner}).should.be.rejectedWith(ERROR_MSG); - await token.transferAndCall(foreignBridge.address, halfEther, '0x00', {from: user}).should.be.fulfilled; - '0'.should.be.bignumber.equal(await token.totalSupply()); - '0'.should.be.bignumber.equal(await token.balanceOf(user)); + token = await POA20.new('POA ERC20 Foundation', 'POA20', 18, { from: owner }) + const foreignBridge = await ForeignBridge.new() + await foreignBridge.initialize( + validatorContract.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) + await token.mint(user, halfEther, { from: owner }).should.be.fulfilled + await token.transferOwnership(foreignBridge.address, { from: owner }) + await foreignBridge.onTokenTransfer(user, halfEther, '0x00', { from: owner }).should.be.rejectedWith(ERROR_MSG) + await token.transferAndCall(foreignBridge.address, halfEther, '0x00', { from: user }).should.be.fulfilled + expect(await token.totalSupply()).to.be.bignumber.equal(ZERO) + expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO) }) it('should not allow to burn more than the limit', async () => { const owner = accounts[3] const user = accounts[4] - const valueMoreThanLimit = halfEther.add(1); - token = await POA20.new("POA ERC20 Foundation", "POA20", 18, {from: owner}); - foreignBridge = await ForeignBridge.new(); - await foreignBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner); - await token.mint(user, valueMoreThanLimit, {from: owner }).should.be.fulfilled; - await token.transferOwnership(foreignBridge.address, {from: owner}); - await token.transferAndCall(foreignBridge.address, valueMoreThanLimit, '0x00', {from: user}).should.be.rejectedWith(ERROR_MSG); - valueMoreThanLimit.should.be.bignumber.equal(await token.totalSupply()); - valueMoreThanLimit.should.be.bignumber.equal(await token.balanceOf(user)); - const {logs} = await token.transferAndCall(foreignBridge.address, halfEther, '0x00', {from: user}).should.be.fulfilled; - '1'.should.be.bignumber.equal(await token.totalSupply()); - '1'.should.be.bignumber.equal(await token.balanceOf(user)); - const events = await getEvents(foreignBridge, {event: 'UserRequestForAffirmation'}); - events[0].args.should.be.deep.equal({ - recipient: user, - value: halfEther - }) + const valueMoreThanLimit = halfEther.add(toBN(1)) + token = await POA20.new('POA ERC20 Foundation', 'POA20', 18, { from: owner }) + const foreignBridge = await ForeignBridge.new() + + await foreignBridge.initialize( + validatorContract.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) + await token.mint(user, valueMoreThanLimit, { from: owner }).should.be.fulfilled + await token.transferOwnership(foreignBridge.address, { from: owner }) + + await token + .transferAndCall(foreignBridge.address, valueMoreThanLimit, '0x00', { from: user }) + .should.be.rejectedWith(ERROR_MSG) + + valueMoreThanLimit.should.be.bignumber.equal(await token.totalSupply()) + valueMoreThanLimit.should.be.bignumber.equal(await token.balanceOf(user)) + + await token.transferAndCall(foreignBridge.address, halfEther, '0x00', { from: user }).should.be.fulfilled + + expect(await token.totalSupply()).to.be.bignumber.equal('1') + expect(await token.balanceOf(user)).to.be.bignumber.equal('1') + + const events = await getEvents(foreignBridge, { event: 'UserRequestForAffirmation' }) + expect(events[0].returnValues.recipient).to.be.equal(user) + expect(toBN(events[0].returnValues.value)).to.be.bignumber.equal(halfEther) }) it('should only let to send within maxPerTx limit', async () => { const owner = accounts[3] const user = accounts[4] - const valueMoreThanLimit = halfEther.add(1); - token = await POA20.new("POA ERC20 Foundation", "POA20", 18, {from: owner}); - foreignBridge = await ForeignBridge.new(); - await foreignBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner); - await token.mint(user, oneEther.add(1), {from: owner }).should.be.fulfilled; - await token.transferOwnership(foreignBridge.address, {from: owner}); - await token.transferAndCall(foreignBridge.address, valueMoreThanLimit, '0x00', {from: user}).should.be.rejectedWith(ERROR_MSG); - oneEther.add(1).should.be.bignumber.equal(await token.totalSupply()); - oneEther.add(1).should.be.bignumber.equal(await token.balanceOf(user)); - await token.transferAndCall(foreignBridge.address, halfEther, '0x00', {from: user}).should.be.fulfilled; - valueMoreThanLimit.should.be.bignumber.equal(await token.totalSupply()); - valueMoreThanLimit.should.be.bignumber.equal(await token.balanceOf(user)); - await token.transferAndCall(foreignBridge.address, halfEther, '0x00', {from: user}).should.be.fulfilled; - '1'.should.be.bignumber.equal(await token.totalSupply()); - '1'.should.be.bignumber.equal(await token.balanceOf(user)); - await token.transferAndCall(foreignBridge.address, '1', '0x00', {from: user}).should.be.rejectedWith(ERROR_MSG); + const valueMoreThanLimit = halfEther.add(toBN(1)) + token = await POA20.new('POA ERC20 Foundation', 'POA20', 18, { from: owner }) + const foreignBridge = await ForeignBridge.new() + await foreignBridge.initialize( + validatorContract.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) + await token.mint(user, oneEther.add(toBN(1)), { from: owner }).should.be.fulfilled + + await token.transferOwnership(foreignBridge.address, { from: owner }) + + await token + .transferAndCall(foreignBridge.address, valueMoreThanLimit, '0x00', { from: user }) + .should.be.rejectedWith(ERROR_MSG) + + oneEther.add(toBN(1)).should.be.bignumber.equal(await token.totalSupply()) + oneEther.add(toBN(1)).should.be.bignumber.equal(await token.balanceOf(user)) + + await token.transferAndCall(foreignBridge.address, halfEther, '0x00', { from: user }).should.be.fulfilled + + valueMoreThanLimit.should.be.bignumber.equal(await token.totalSupply()) + valueMoreThanLimit.should.be.bignumber.equal(await token.balanceOf(user)) + + await token.transferAndCall(foreignBridge.address, halfEther, '0x00', { from: user }).should.be.fulfilled + + expect(await token.totalSupply()).to.be.bignumber.equal('1') + expect(await token.balanceOf(user)).to.be.bignumber.equal('1') + await token.transferAndCall(foreignBridge.address, '1', '0x00', { from: user }).should.be.rejectedWith(ERROR_MSG) }) it('should not let to withdraw less than minPerTx', async () => { const owner = accounts[3] const user = accounts[4] - const valueLessThanMinPerTx = minPerTx.sub(1); - token = await POA20.new("POA ERC20 Foundation", "POA20", 18, {from: owner}); - foreignBridge = await ForeignBridge.new(); - await foreignBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner); - await token.mint(user, oneEther, {from: owner }).should.be.fulfilled; - await token.transferOwnership(foreignBridge.address, {from: owner}); - await token.transferAndCall(foreignBridge.address, valueLessThanMinPerTx, '0x00', {from: user}).should.be.rejectedWith(ERROR_MSG); - oneEther.should.be.bignumber.equal(await token.totalSupply()); - oneEther.should.be.bignumber.equal(await token.balanceOf(user)); - await token.transferAndCall(foreignBridge.address, minPerTx, '0x00', {from: user}).should.be.fulfilled; - oneEther.sub(minPerTx).should.be.bignumber.equal(await token.totalSupply()); - oneEther.sub(minPerTx).should.be.bignumber.equal(await token.balanceOf(user)); + const valueLessThanMinPerTx = minPerTx.sub(toBN(1)) + token = await POA20.new('POA ERC20 Foundation', 'POA20', 18, { from: owner }) + const foreignBridge = await ForeignBridge.new() + await foreignBridge.initialize( + validatorContract.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) + await token.mint(user, oneEther, { from: owner }).should.be.fulfilled + await token.transferOwnership(foreignBridge.address, { from: owner }) + + await token + .transferAndCall(foreignBridge.address, valueLessThanMinPerTx, '0x00', { from: user }) + .should.be.rejectedWith(ERROR_MSG) + + oneEther.should.be.bignumber.equal(await token.totalSupply()) + oneEther.should.be.bignumber.equal(await token.balanceOf(user)) + + await token.transferAndCall(foreignBridge.address, minPerTx, '0x00', { from: user }).should.be.fulfilled + + oneEther.sub(minPerTx).should.be.bignumber.equal(await token.totalSupply()) + oneEther.sub(minPerTx).should.be.bignumber.equal(await token.balanceOf(user)) }) }) describe('#setting limits', async () => { - let foreignBridge; + let foreignBridge beforeEach(async () => { - token = await POA20.new("POA ERC20 Foundation", "POA20", 18); - foreignBridge = await ForeignBridge.new(); - await foreignBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner); + token = await POA20.new('POA ERC20 Foundation', 'POA20', 18) + foreignBridge = await ForeignBridge.new() + await foreignBridge.initialize( + validatorContract.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) await token.transferOwnership(foreignBridge.address) }) it('#setMaxPerTx allows to set only to owner and cannot be more than daily limit', async () => { - await foreignBridge.setMaxPerTx(halfEther, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.setMaxPerTx(halfEther, {from: owner}).should.be.fulfilled; + await foreignBridge.setMaxPerTx(halfEther, { from: authorities[0] }).should.be.rejectedWith(ERROR_MSG) + await foreignBridge.setMaxPerTx(halfEther, { from: owner }).should.be.fulfilled - await foreignBridge.setMaxPerTx(oneEther, {from: owner}).should.be.rejectedWith(ERROR_MSG); + await foreignBridge.setMaxPerTx(oneEther, { from: owner }).should.be.rejectedWith(ERROR_MSG) }) it('#setMinPerTx allows to set only to owner and cannot be more than daily limit and should be less than maxPerTx', async () => { - await foreignBridge.setMinPerTx(minPerTx, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); - await foreignBridge.setMinPerTx(minPerTx, {from: owner}).should.be.fulfilled; + await foreignBridge.setMinPerTx(minPerTx, { from: authorities[0] }).should.be.rejectedWith(ERROR_MSG) + await foreignBridge.setMinPerTx(minPerTx, { from: owner }).should.be.fulfilled - await foreignBridge.setMinPerTx(oneEther, {from: owner}).should.be.rejectedWith(ERROR_MSG); + await foreignBridge.setMinPerTx(oneEther, { from: owner }).should.be.rejectedWith(ERROR_MSG) }) }) @@ -400,114 +582,653 @@ contract('ForeignBridge', async (accounts) => { it('can be upgraded', async () => { const REQUIRED_NUMBER_OF_VALIDATORS = 1 const VALIDATORS = [accounts[1]] - const PROXY_OWNER = accounts[0] - const FOREIGN_DAILY_LIMIT = oneEther; - const FOREIGN_MAX_AMOUNT_PER_TX = halfEther; - const FOREIGN_MIN_AMOUNT_PER_TX = minPerTx; + const PROXY_OWNER = accounts[0] + const FOREIGN_DAILY_LIMIT = oneEther + const FOREIGN_MAX_AMOUNT_PER_TX = halfEther + const FOREIGN_MIN_AMOUNT_PER_TX = minPerTx // Validators Contract - let validatorsProxy = await EternalStorageProxy.new().should.be.fulfilled; - const validatorsContractImpl = await BridgeValidators.new().should.be.fulfilled; - await validatorsProxy.upgradeTo('1', validatorsContractImpl.address).should.be.fulfilled; + let validatorsProxy = await EternalStorageProxy.new().should.be.fulfilled + const validatorsContractImpl = await BridgeValidators.new().should.be.fulfilled + await validatorsProxy.upgradeTo('1', validatorsContractImpl.address).should.be.fulfilled validatorsContractImpl.address.should.be.equal(await validatorsProxy.implementation()) - validatorsProxy = await BridgeValidators.at(validatorsProxy.address); - await validatorsProxy.initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, PROXY_OWNER).should.be.fulfilled; + validatorsProxy = await BridgeValidators.at(validatorsProxy.address) + await validatorsProxy.initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, PROXY_OWNER).should.be.fulfilled // POA20 - let token = await POA20.new("POA ERC20 Foundation", "POA20", 18); + const token = await POA20.new('POA ERC20 Foundation', 'POA20', 18) // ForeignBridge V1 Contract - let foreignBridgeProxy = await EternalStorageProxy.new().should.be.fulfilled; - const foreignBridgeImpl = await ForeignBridge.new().should.be.fulfilled; - await foreignBridgeProxy.upgradeTo('1', foreignBridgeImpl.address).should.be.fulfilled; + let foreignBridgeProxy = await EternalStorageProxy.new().should.be.fulfilled + const foreignBridgeImpl = await ForeignBridge.new().should.be.fulfilled + await foreignBridgeProxy.upgradeTo('1', foreignBridgeImpl.address).should.be.fulfilled - foreignBridgeProxy = await ForeignBridge.at(foreignBridgeProxy.address); - await foreignBridgeProxy.initialize(validatorsProxy.address, token.address, FOREIGN_DAILY_LIMIT, FOREIGN_MAX_AMOUNT_PER_TX, FOREIGN_MIN_AMOUNT_PER_TX, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner) - await token.transferOwnership(foreignBridgeProxy.address).should.be.fulfilled; + foreignBridgeProxy = await ForeignBridge.at(foreignBridgeProxy.address) + await foreignBridgeProxy.initialize( + validatorsProxy.address, + token.address, + FOREIGN_DAILY_LIMIT, + FOREIGN_MAX_AMOUNT_PER_TX, + FOREIGN_MIN_AMOUNT_PER_TX, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) + await token.transferOwnership(foreignBridgeProxy.address).should.be.fulfilled - foreignBridgeProxy.address.should.be.equal(await token.owner()); + foreignBridgeProxy.address.should.be.equal(await token.owner()) // Deploy V2 - let foreignImplV2 = await ForeignBridgeV2.new(); - let foreignBridgeProxyUpgrade = await EternalStorageProxy.at(foreignBridgeProxy.address); - await foreignBridgeProxyUpgrade.upgradeTo('2', foreignImplV2.address).should.be.fulfilled; + const foreignImplV2 = await ForeignBridgeV2.new() + const foreignBridgeProxyUpgrade = await EternalStorageProxy.at(foreignBridgeProxy.address) + await foreignBridgeProxyUpgrade.upgradeTo('2', foreignImplV2.address).should.be.fulfilled foreignImplV2.address.should.be.equal(await foreignBridgeProxyUpgrade.implementation()) }) it('can be deployed via upgradeToAndCall', async () => { const tokenAddress = token.address const validatorsAddress = validatorContract.address - const FOREIGN_DAILY_LIMIT = oneEther; - const FOREIGN_MAX_AMOUNT_PER_TX = halfEther; - const FOREIGN_MIN_AMOUNT_PER_TX = minPerTx; - - let storageProxy = await EternalStorageProxy.new().should.be.fulfilled; - let foreignBridge = await ForeignBridge.new(); - let data = foreignBridge.initialize.request( - validatorsAddress, tokenAddress, FOREIGN_DAILY_LIMIT, FOREIGN_MAX_AMOUNT_PER_TX, FOREIGN_MIN_AMOUNT_PER_TX, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner).params[0].data - await storageProxy.upgradeToAndCall('1', foreignBridge.address, data).should.be.fulfilled; - let finalContract = await ForeignBridge.at(storageProxy.address); - true.should.be.equal(await finalContract.isInitialized()); + const FOREIGN_DAILY_LIMIT = '3' + const FOREIGN_MAX_AMOUNT_PER_TX = '2' + const FOREIGN_MIN_AMOUNT_PER_TX = '1' + + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + const foreignBridge = await ForeignBridge.new() + const data = foreignBridge.contract.methods + .initialize( + validatorsAddress, + tokenAddress, + FOREIGN_DAILY_LIMIT, + FOREIGN_MAX_AMOUNT_PER_TX, + FOREIGN_MIN_AMOUNT_PER_TX, + gasPrice, + requireBlockConfirmations, + '3', + '2', + owner + ) + .encodeABI() + await storageProxy.upgradeToAndCall('1', foreignBridge.address, data).should.be.fulfilled + const finalContract = await ForeignBridge.at(storageProxy.address) + true.should.be.equal(await finalContract.isInitialized()) validatorsAddress.should.be.equal(await finalContract.validatorContract()) - FOREIGN_DAILY_LIMIT.should.be.bignumber.equal(await finalContract.dailyLimit()) - FOREIGN_MAX_AMOUNT_PER_TX.should.be.bignumber.equal(await finalContract.maxPerTx()) - FOREIGN_MIN_AMOUNT_PER_TX.should.be.bignumber.equal(await finalContract.minPerTx()) + + expect(await finalContract.dailyLimit()).to.be.bignumber.equal(FOREIGN_DAILY_LIMIT) + expect(await finalContract.maxPerTx()).to.be.bignumber.equal(FOREIGN_MAX_AMOUNT_PER_TX) + expect(await finalContract.minPerTx()).to.be.bignumber.equal(FOREIGN_MIN_AMOUNT_PER_TX) }) it('can transfer ownership', async () => { - const token = await POA20.new("POA ERC20 Foundation", "POA20", 18); - const foreignBridge = await ForeignBridge.new(); - const storageProxy = await EternalStorageProxy.new().should.be.fulfilled; - const data = foreignBridge.initialize.request( - validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner).params[0].data - await storageProxy.upgradeToAndCall('1', foreignBridge.address, data).should.be.fulfilled; + const token = await POA20.new('POA ERC20 Foundation', 'POA20', 18) + const foreignBridge = await ForeignBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + const data = foreignBridge.contract.methods + .initialize( + validatorContract.address, + token.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + '3', + '2', + owner + ) + .encodeABI() + await storageProxy.upgradeToAndCall('1', foreignBridge.address, data).should.be.fulfilled await storageProxy.transferProxyOwnership(owner).should.be.fulfilled }) }) describe('#claimTokens', async () => { it('can send erc20', async () => { - const owner = accounts[0]; - token = await POA20.new("POA ERC20 Foundation", "POA20", 18); - const foreignBridgeImpl = await ForeignBridge.new(); - const storageProxy = await EternalStorageProxy.new().should.be.fulfilled; + const owner = accounts[0] + token = await POA20.new('POA ERC20 Foundation', 'POA20', 18) + const foreignBridgeImpl = await ForeignBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled await storageProxy.upgradeTo('1', foreignBridgeImpl.address).should.be.fulfilled - const foreignBridge = await ForeignBridge.at(storageProxy.address); - await foreignBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner); + const foreignBridge = await ForeignBridge.at(storageProxy.address) + await foreignBridge.initialize( + validatorContract.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) await token.transferOwnership(foreignBridge.address) - let tokenSecond = await POA20.new("Roman Token", "RST", 18); + const tokenSecond = await POA20.new('Roman Token', 'RST', 18) - await tokenSecond.mint(accounts[0], halfEther).should.be.fulfilled; - halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[0])) - await tokenSecond.transfer(foreignBridge.address, halfEther); - '0'.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[0])) - halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(foreignBridge.address)) + await tokenSecond.mint(accounts[0], halfEther).should.be.fulfilled + expect(await tokenSecond.balanceOf(accounts[0])).to.be.bignumber.equal(halfEther) - await foreignBridge.claimTokens(tokenSecond.address, accounts[3], {from: owner}); - '0'.should.be.bignumber.equal(await tokenSecond.balanceOf(foreignBridge.address)) - halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[3])) + await tokenSecond.transfer(foreignBridge.address, halfEther) + expect(await tokenSecond.balanceOf(accounts[0])).to.be.bignumber.equal(ZERO) + expect(await tokenSecond.balanceOf(foreignBridge.address)).to.be.bignumber.equal(halfEther) + await foreignBridge.claimTokens(tokenSecond.address, accounts[3], { from: owner }) + expect(await tokenSecond.balanceOf(foreignBridge.address)).to.be.bignumber.equal(ZERO) + expect(await tokenSecond.balanceOf(accounts[3])).to.be.bignumber.equal(halfEther) }) it('also calls claimTokens on tokenAddress', async () => { - const owner = accounts[0]; - token = await POA20.new("POA ERC20 Foundation", "POA20", 18); - const foreignBridgeImpl = await ForeignBridge.new(); - const storageProxy = await EternalStorageProxy.new().should.be.fulfilled; + const owner = accounts[0] + token = await POA20.new('POA ERC20 Foundation', 'POA20', 18) + const foreignBridgeImpl = await ForeignBridge.new() + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled await storageProxy.upgradeTo('1', foreignBridgeImpl.address).should.be.fulfilled - const foreignBridge = await ForeignBridge.at(storageProxy.address); - await foreignBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, homeDailyLimit, homeMaxPerTx, owner); + const foreignBridge = await ForeignBridge.at(storageProxy.address) + await foreignBridge.initialize( + validatorContract.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner + ) + await token.transferOwnership(foreignBridge.address) + + const tokenSecond = await POA20.new('Roman Token', 'RST', 18) + + await tokenSecond.mint(accounts[0], 150).should.be.fulfilled + expect(await tokenSecond.balanceOf(accounts[0])).to.be.bignumber.equal('150') + + await tokenSecond.transfer(token.address, '150') + expect(await tokenSecond.balanceOf(accounts[0])).to.be.bignumber.equal(ZERO) + expect(await tokenSecond.balanceOf(token.address)).to.be.bignumber.equal('150') + + await foreignBridge.claimTokensFromErc677(tokenSecond.address, accounts[3], { from: owner }) + expect(await tokenSecond.balanceOf(foreignBridge.address)).to.be.bignumber.equal(ZERO) + expect(await tokenSecond.balanceOf(accounts[3])).to.be.bignumber.equal('150') + }) + }) + + describe('#rewardableInitialize', async () => { + let homeFee + let foreignBridge + let token + let rewardableValidators + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + beforeEach(async () => { + token = await POA20.new('POA ERC20 Foundation', 'POA20', 18) + rewardableValidators = await RewardableValidators.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + foreignBridge = await ForeignBridge.new() + homeFee = ether('0.001') + }) + it('sets variables', async () => { + const feeManager = await FeeManagerNativeToErc.new() + expect(await foreignBridge.validatorContract()).to.be.equal(ZERO_ADDRESS) + expect(await foreignBridge.deployedAtBlock()).to.be.bignumber.equal(ZERO) + expect(await foreignBridge.isInitialized()).to.be.equal(false) + expect(await foreignBridge.requiredBlockConfirmations()).to.be.bignumber.equal(ZERO) + expect(await foreignBridge.dailyLimit()).to.be.bignumber.equal(ZERO) + expect(await foreignBridge.maxPerTx()).to.be.bignumber.equal(ZERO) + + await foreignBridge + .rewardableInitialize( + ZERO_ADDRESS, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner, + feeManager.address, + homeFee + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .rewardableInitialize( + rewardableValidators.address, + ZERO_ADDRESS, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner, + feeManager.address, + homeFee + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .rewardableInitialize( + rewardableValidators.address, + token.address, + oneEther, + halfEther, + minPerTx, + 0, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner, + feeManager.address, + homeFee + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .rewardableInitialize( + owner, + token.address, + oneEther, + halfEther, + minPerTx, + requireBlockConfirmations, + gasPrice, + homeDailyLimit, + homeMaxPerTx, + owner, + feeManager.address, + homeFee + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .rewardableInitialize( + rewardableValidators.address, + owner, + oneEther, + halfEther, + minPerTx, + requireBlockConfirmations, + gasPrice, + homeDailyLimit, + homeMaxPerTx, + owner, + feeManager.address, + homeFee + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge + .rewardableInitialize( + rewardableValidators.address, + owner, + oneEther, + halfEther, + minPerTx, + requireBlockConfirmations, + gasPrice, + homeDailyLimit, + homeMaxPerTx, + owner, + ZERO_ADDRESS, + homeFee + ) + .should.be.rejectedWith(ERROR_MSG) + await foreignBridge.rewardableInitialize( + rewardableValidators.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner, + feeManager.address, + homeFee + ).should.be.fulfilled + + expect(await foreignBridge.isInitialized()).to.be.equal(true) + expect(await foreignBridge.validatorContract()).to.be.equal(rewardableValidators.address) + expect(await foreignBridge.deployedAtBlock()).to.be.bignumber.above(ZERO) + expect(await foreignBridge.requiredBlockConfirmations()).to.be.bignumber.equal( + requireBlockConfirmations.toString() + ) + expect(await foreignBridge.gasPrice()).to.be.bignumber.equal(gasPrice) + expect(await foreignBridge.dailyLimit()).to.be.bignumber.equal(oneEther) + expect(await foreignBridge.maxPerTx()).to.be.bignumber.equal(halfEther) + expect(await foreignBridge.minPerTx()).to.be.bignumber.equal(minPerTx) + const bridgeMode = '0x92a8d7fe' // 4 bytes of keccak256('native-to-erc-core') + expect(await foreignBridge.getBridgeMode()).to.be.equal(bridgeMode) + const { major, minor, patch } = await foreignBridge.getBridgeInterfacesVersion() + expect(major).to.be.bignumber.gte(ZERO) + expect(minor).to.be.bignumber.gte(ZERO) + expect(patch).to.be.bignumber.gte(ZERO) + + expect(await foreignBridge.feeManagerContract()).to.be.equals(feeManager.address) + expect(await foreignBridge.getHomeFee()).to.be.bignumber.equals(homeFee) + }) + + it('can update fee contract', async () => { + const feeManager = await FeeManagerNativeToErc.new() + await foreignBridge.rewardableInitialize( + rewardableValidators.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner, + feeManager.address, + homeFee + ).should.be.fulfilled + + // Given + const newFeeManager = await FeeManagerNativeToErc.new() + + // When + await foreignBridge.setFeeManagerContract(newFeeManager.address, { from: owner }).should.be.fulfilled + + // Then + expect(await foreignBridge.feeManagerContract()).to.be.equals(newFeeManager.address) + }) + + it('can update fee', async () => { + const feeManager = await FeeManagerNativeToErc.new() + await foreignBridge.rewardableInitialize( + rewardableValidators.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner, + feeManager.address, + homeFee + ).should.be.fulfilled + + // Given + const newHomeFee = ether('0.1') + + // When + await foreignBridge.setHomeFee(newHomeFee, { from: owner }).should.be.fulfilled + + // Then + expect(await foreignBridge.getHomeFee()).to.be.bignumber.equals(newHomeFee) + }) + + it('should be able to get fee manager mode', async () => { + // Given + const feeManager = await FeeManagerNativeToErc.new() + const oneDirectionsModeHash = '0xf2aed8f7' + + // When + await foreignBridge.rewardableInitialize( + rewardableValidators.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner, + feeManager.address, + homeFee + ).should.be.fulfilled + + // Then + expect(await foreignBridge.getFeeManagerMode()).to.be.equals(oneDirectionsModeHash) + }) + }) + + describe('#RewardableBridge_executeSignatures', async () => { + let feeManager + let foreignBridge + let token + let rewardableValidators + beforeEach(async () => { + feeManager = await FeeManagerNativeToErc.new() + token = await POA20.new('POA ERC20 Foundation', 'POA20', 18) + rewardableValidators = await RewardableValidators.new() + foreignBridge = await ForeignBridge.new() + }) + it('should distribute fee to validator', async () => { + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const value = halfEther + const valueCalc = 0.5 * (1 - fee) + const feeAmountCalc = 0.5 * fee + const finalUserValue = ether(valueCalc.toString()) + const feeAmount = ether(feeAmountCalc.toString()) + + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + await foreignBridge.rewardableInitialize( + rewardableValidators.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner, + feeManager.address, + feeInWei + ).should.be.fulfilled + await token.transferOwnership(foreignBridge.address) + + const recipientAccount = accounts[3] + const balanceBefore = await token.balanceOf(recipientAccount) + const initialBalanceRewardAddress = await token.balanceOf(rewards[0]) + const totalSupplyBefore = await token.totalSupply() + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address) + const signature = await sign(validators[0], message) + const vrs = signatureToVRS(signature) + + const { logs } = await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled + + logs[0].event.should.be.equal('FeeDistributedFromSignatures') + logs[0].args.feeAmount.should.be.bignumber.equal(feeAmount) + logs[0].args.transactionHash.should.be.equal(transactionHash) + + logs[1].event.should.be.equal('RelayedMessage') + logs[1].args.recipient.should.be.equal(recipientAccount) + logs[1].args.value.should.be.bignumber.equal(value) + logs[1].args.transactionHash.should.be.equal(transactionHash) + + const balanceAfter = await token.balanceOf(recipientAccount) + const totalSupplyAfter = await token.totalSupply() + balanceAfter.should.be.bignumber.equal(balanceBefore.add(finalUserValue)) + totalSupplyAfter.should.be.bignumber.equal(totalSupplyBefore.add(value)) + + const updatedBalanceRewardAddress = await token.balanceOf(rewards[0]) + updatedBalanceRewardAddress.should.be.bignumber.equal(initialBalanceRewardAddress.add(feeAmount)) + }) + it('should distribute fee to 3 validators', async () => { + // Given + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feePerValidator = toBN(166666666666666) + const feePerValidatorPlusDiff = toBN(166666666666668) + const value = halfEther + const valueCalc = 0.5 * (1 - fee) + const feeAmountCalc = 0.5 * fee + const finalUserValue = ether(valueCalc.toString()) + const feeAmount = ether(feeAmountCalc.toString()) + + const validators = [accounts[1], accounts[2], accounts[3]] + const rewards = [accounts[4], accounts[5], accounts[6]] + const requiredSignatures = 3 + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + await foreignBridge.rewardableInitialize( + rewardableValidators.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner, + feeManager.address, + feeInWei + ).should.be.fulfilled + await token.transferOwnership(foreignBridge.address) + + const recipientAccount = accounts[7] + const balanceBefore = await token.balanceOf(recipientAccount) + const totalSupplyBefore = await token.totalSupply() + + const initialBalanceRewardAddress1 = await token.balanceOf(rewards[0]) + const initialBalanceRewardAddress2 = await token.balanceOf(rewards[1]) + const initialBalanceRewardAddress3 = await token.balanceOf(rewards[2]) + + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address) + const signature1 = await sign(validators[0], message) + const signature2 = await sign(validators[1], message) + const signature3 = await sign(validators[2], message) + const vrs = signatureToVRS(signature1) + const vrs2 = signatureToVRS(signature2) + const vrs3 = signatureToVRS(signature3) + + // When + const { logs } = await foreignBridge.executeSignatures( + [vrs.v, vrs2.v, vrs3.v], + [vrs.r, vrs2.r, vrs3.r], + [vrs.s, vrs2.s, vrs3.s], + message + ).should.be.fulfilled + + // Then + logs[0].event.should.be.equal('FeeDistributedFromSignatures') + logs[0].args.feeAmount.should.be.bignumber.equal(feeAmount) + logs[0].args.transactionHash.should.be.equal(transactionHash) + + logs[1].event.should.be.equal('RelayedMessage') + logs[1].args.recipient.should.be.equal(recipientAccount) + logs[1].args.value.should.be.bignumber.equal(value) + logs[1].args.transactionHash.should.be.equal(transactionHash) + + const balanceAfter = await token.balanceOf(recipientAccount) + const totalSupplyAfter = await token.totalSupply() + balanceAfter.should.be.bignumber.equal(balanceBefore.add(finalUserValue)) + totalSupplyAfter.should.be.bignumber.equal(totalSupplyBefore.add(value)) + + const updatedBalanceRewardAddress1 = await token.balanceOf(rewards[0]) + const updatedBalanceRewardAddress2 = await token.balanceOf(rewards[1]) + const updatedBalanceRewardAddress3 = await token.balanceOf(rewards[2]) + + expect( + updatedBalanceRewardAddress1.eq(initialBalanceRewardAddress1.add(feePerValidator)) || + updatedBalanceRewardAddress1.eq(initialBalanceRewardAddress1.add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + updatedBalanceRewardAddress2.eq(initialBalanceRewardAddress2.add(feePerValidator)) || + updatedBalanceRewardAddress2.eq(initialBalanceRewardAddress2.add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + updatedBalanceRewardAddress3.eq(initialBalanceRewardAddress3.add(feePerValidator)) || + updatedBalanceRewardAddress3.eq(initialBalanceRewardAddress3.add(feePerValidatorPlusDiff)) + ).to.equal(true) + }) + it('should distribute fee to 5 validators', async () => { + // Given + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const value = halfEther + const valueCalc = 0.5 * (1 - fee) + const feeAmountCalc = 0.5 * fee + const finalUserValue = ether(valueCalc.toString()) + const feeAmount = ether(feeAmountCalc.toString()) + const feePerValidator = feeAmount.div(toBN(5)) + + const validators = [accounts[0], accounts[1], accounts[2], accounts[3], accounts[4]] + const rewards = [accounts[5], accounts[6], accounts[7], accounts[8], accounts[9]] + const requiredSignatures = 3 + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + await foreignBridge.rewardableInitialize( + rewardableValidators.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + homeDailyLimit, + homeMaxPerTx, + owner, + feeManager.address, + feeInWei + ).should.be.fulfilled await token.transferOwnership(foreignBridge.address) - let tokenSecond = await POA20.new("Roman Token", "RST", 18); + const recipientAccount = accounts[0] + const balanceBefore = await token.balanceOf(recipientAccount) + const totalSupplyBefore = await token.totalSupply() + + const initialBalanceRewardAddress1 = await token.balanceOf(rewards[0]) + const initialBalanceRewardAddress2 = await token.balanceOf(rewards[1]) + const initialBalanceRewardAddress3 = await token.balanceOf(rewards[2]) + const initialBalanceRewardAddress4 = await token.balanceOf(rewards[3]) + const initialBalanceRewardAddress5 = await token.balanceOf(rewards[4]) + + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address) + const signature1 = await sign(validators[0], message) + const signature2 = await sign(validators[1], message) + const signature3 = await sign(validators[2], message) + const vrs = signatureToVRS(signature1) + const vrs2 = signatureToVRS(signature2) + const vrs3 = signatureToVRS(signature3) + + // When + const { logs } = await foreignBridge.executeSignatures( + [vrs.v, vrs2.v, vrs3.v], + [vrs.r, vrs2.r, vrs3.r], + [vrs.s, vrs2.s, vrs3.s], + message + ).should.be.fulfilled + + // Then + logs[0].event.should.be.equal('FeeDistributedFromSignatures') + logs[0].args.feeAmount.should.be.bignumber.equal(feeAmount) + logs[0].args.transactionHash.should.be.equal(transactionHash) + + logs[1].event.should.be.equal('RelayedMessage') + logs[1].args.recipient.should.be.equal(recipientAccount) + logs[1].args.value.should.be.bignumber.equal(value) + logs[1].args.transactionHash.should.be.equal(transactionHash) + + const balanceAfter = await token.balanceOf(recipientAccount) + const totalSupplyAfter = await token.totalSupply() + balanceAfter.should.be.bignumber.equal(balanceBefore.add(finalUserValue)) + totalSupplyAfter.should.be.bignumber.equal(totalSupplyBefore.add(value)) - await tokenSecond.mint(accounts[0], 150).should.be.fulfilled; - '150'.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[0])) - await tokenSecond.transfer(token.address, '150'); - '0'.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[0])) - '150'.should.be.bignumber.equal(await tokenSecond.balanceOf(token.address)) + const updatedBalanceRewardAddress1 = await token.balanceOf(rewards[0]) + const updatedBalanceRewardAddress2 = await token.balanceOf(rewards[1]) + const updatedBalanceRewardAddress3 = await token.balanceOf(rewards[2]) + const updatedBalanceRewardAddress4 = await token.balanceOf(rewards[3]) + const updatedBalanceRewardAddress5 = await token.balanceOf(rewards[4]) - await foreignBridge.claimTokensFromErc677(tokenSecond.address, accounts[3], {from: owner}); - '0'.should.be.bignumber.equal(await tokenSecond.balanceOf(foreignBridge.address)) - '150'.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[3])) + updatedBalanceRewardAddress1.should.be.bignumber.equal(initialBalanceRewardAddress1.add(feePerValidator)) + updatedBalanceRewardAddress2.should.be.bignumber.equal(initialBalanceRewardAddress2.add(feePerValidator)) + updatedBalanceRewardAddress3.should.be.bignumber.equal(initialBalanceRewardAddress3.add(feePerValidator)) + updatedBalanceRewardAddress4.should.be.bignumber.equal(initialBalanceRewardAddress4.add(feePerValidator)) + updatedBalanceRewardAddress5.should.be.bignumber.equal(initialBalanceRewardAddress5.add(feePerValidator)) }) }) }) diff --git a/test/native_to_erc/home_bridge_test.js b/test/native_to_erc/home_bridge_test.js index 39aefcace..8fb3d78a7 100644 --- a/test/native_to_erc/home_bridge_test.js +++ b/test/native_to_erc/home_bridge_test.js @@ -1,82 +1,169 @@ -const Web3Utils = require('web3-utils'); -const HomeBridge = artifacts.require("HomeBridgeNativeToErc.sol"); -const EternalStorageProxy = artifacts.require("EternalStorageProxy.sol"); -const BridgeValidators = artifacts.require("BridgeValidators.sol"); -const RevertFallback = artifacts.require("RevertFallback.sol"); -const {ERROR_MSG, ZERO_ADDRESS} = require('../setup'); -const {createMessage, sign, signatureToVRS} = require('../helpers/helpers'); -const minPerTx = web3.toBigNumber(web3.toWei(0.01, "ether")); -const requireBlockConfirmations = 8; -const gasPrice = Web3Utils.toWei('1', 'gwei'); -const oneEther = web3.toBigNumber(web3.toWei(1, "ether")); -const twoEther = web3.toBigNumber(web3.toWei(2, "ether")); -const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether")); +const HomeBridge = artifacts.require('HomeBridgeNativeToErc.sol') +const EternalStorageProxy = artifacts.require('EternalStorageProxy.sol') +const BridgeValidators = artifacts.require('BridgeValidators.sol') +const RevertFallback = artifacts.require('RevertFallback.sol') +const FeeManagerNativeToErc = artifacts.require('FeeManagerNativeToErc.sol') +const FeeManagerNativeToErcBothDirections = artifacts.require('FeeManagerNativeToErcBothDirections.sol') +const RewardableValidators = artifacts.require('RewardableValidators.sol') + +const { expect } = require('chai') +const { ERROR_MSG, ZERO_ADDRESS, toBN } = require('../setup') +const { createMessage, sign, ether, expectEventInLogs } = require('../helpers/helpers') + +const minPerTx = ether('0.01') +const requireBlockConfirmations = 8 +const gasPrice = web3.utils.toWei('1', 'gwei') +const oneEther = ether('1') +const twoEther = ether('2') +const halfEther = ether('0.5') const foreignDailyLimit = oneEther const foreignMaxPerTx = halfEther +const ZERO = toBN(0) -contract('HomeBridge', async (accounts) => { - let homeContract, validatorContract, authorities, owner; +contract('HomeBridge', async accounts => { + let homeContract + let validatorContract + let authorities + let owner before(async () => { validatorContract = await BridgeValidators.new() - authorities = [accounts[1]]; + authorities = [accounts[1]] owner = accounts[0] await validatorContract.initialize(1, authorities, owner) }) - describe('#initialize', async() => { + + describe('#initialize', async () => { beforeEach(async () => { homeContract = await HomeBridge.new() }) it('sets variables', async () => { - ZERO_ADDRESS.should.be.equal(await homeContract.validatorContract()) - '0'.should.be.bignumber.equal(await homeContract.deployedAtBlock()) - '0'.should.be.bignumber.equal(await homeContract.dailyLimit()) - '0'.should.be.bignumber.equal(await homeContract.maxPerTx()) - false.should.be.equal(await homeContract.isInitialized()) - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner).should.be.fulfilled; - true.should.be.equal(await homeContract.isInitialized()) - validatorContract.address.should.be.equal(await homeContract.validatorContract()); - (await homeContract.deployedAtBlock()).should.be.bignumber.above(0); - '3'.should.be.bignumber.equal(await homeContract.dailyLimit()) - '2'.should.be.bignumber.equal(await homeContract.maxPerTx()) - '1'.should.be.bignumber.equal(await homeContract.minPerTx()) + expect(await homeContract.validatorContract()).to.be.equal(ZERO_ADDRESS) + expect(await homeContract.deployedAtBlock()).to.be.bignumber.equal(ZERO) + expect(await homeContract.dailyLimit()).to.be.bignumber.equal(ZERO) + expect(await homeContract.maxPerTx()).to.be.bignumber.equal(ZERO) + expect(await homeContract.isInitialized()).to.be.equal(false) + + await homeContract.initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled + + expect(await homeContract.isInitialized()).to.be.equal(true) + expect(await homeContract.validatorContract()).to.be.equal(validatorContract.address) + expect(await homeContract.deployedAtBlock()).to.be.bignumber.above(ZERO) + expect(await homeContract.dailyLimit()).to.be.bignumber.equal('3') + expect(await homeContract.maxPerTx()).to.be.bignumber.equal('2') + expect(await homeContract.minPerTx()).to.be.bignumber.equal('1') + expect(await homeContract.gasPrice()).to.be.bignumber.equal(gasPrice) const bridgeMode = '0x92a8d7fe' // 4 bytes of keccak256('native-to-erc-core') - const mode = await homeContract.getBridgeMode(); - mode.should.be.equal(bridgeMode) - const [major, minor, patch] = await homeContract.getBridgeInterfacesVersion() - major.should.be.bignumber.gte(0) - minor.should.be.bignumber.gte(0) - patch.should.be.bignumber.gte(0) + expect(await homeContract.getBridgeMode()).to.be.equal(bridgeMode) + const { major, minor, patch } = await homeContract.getBridgeInterfacesVersion() + expect(major).to.be.bignumber.gte(ZERO) + expect(minor).to.be.bignumber.gte(ZERO) + expect(patch).to.be.bignumber.gte(ZERO) }) it('cant set maxPerTx > dailyLimit', async () => { false.should.be.equal(await homeContract.isInitialized()) - await homeContract.initialize(validatorContract.address, '1', '2', '1', gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(validatorContract.address, '3', '2', '2', gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); + await homeContract + .initialize( + validatorContract.address, + '1', + '2', + '1', + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + validatorContract.address, + '3', + '2', + '2', + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) false.should.be.equal(await homeContract.isInitialized()) }) it('can be deployed via upgradeToAndCall', async () => { - let storageProxy = await EternalStorageProxy.new().should.be.fulfilled; - let data = homeContract.initialize.request(validatorContract.address, "3", "2", "1", gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner).params[0].data - await storageProxy.upgradeToAndCall('1', homeContract.address, data).should.be.fulfilled; - let finalContract = await HomeBridge.at(storageProxy.address); - true.should.be.equal(await finalContract.isInitialized()); - validatorContract.address.should.be.equal(await finalContract.validatorContract()) - "3".should.be.bignumber.equal(await finalContract.dailyLimit()) - "2".should.be.bignumber.equal(await finalContract.maxPerTx()) - "1".should.be.bignumber.equal(await finalContract.minPerTx()) + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + const data = homeContract.contract.methods + .initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, '3', '2', owner) + .encodeABI() + await storageProxy.upgradeToAndCall('1', homeContract.address, data).should.be.fulfilled + const finalContract = await HomeBridge.at(storageProxy.address) + + expect(await finalContract.isInitialized()).to.be.equal(true) + expect(await finalContract.validatorContract()).to.be.equal(validatorContract.address) + expect(await finalContract.dailyLimit()).to.be.bignumber.equal('3') + expect(await finalContract.maxPerTx()).to.be.bignumber.equal('2') + expect(await finalContract.minPerTx()).to.be.bignumber.equal('1') }) it('cant initialize with invalid arguments', async () => { false.should.be.equal(await homeContract.isInitialized()) - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, 0, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(owner, '3', '2', '1', gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(ZERO_ADDRESS, '3', '2', '1', gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner).should.be.rejectedWith(ERROR_MSG); - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner).should.be.fulfilled; + await homeContract + .initialize(validatorContract.address, '3', '2', '1', gasPrice, 0, foreignDailyLimit, foreignMaxPerTx, owner) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + owner, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract + .initialize( + ZERO_ADDRESS, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + .should.be.rejectedWith(ERROR_MSG) + await homeContract.initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ).should.be.fulfilled true.should.be.equal(await homeContract.isInitialized()) }) it('can transfer ownership', async () => { - let storageProxy = await EternalStorageProxy.new().should.be.fulfilled; - let data = homeContract.initialize.request(validatorContract.address, "3", "2", "1", gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner).params[0].data - await storageProxy.upgradeToAndCall('1', homeContract.address, data).should.be.fulfilled; + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + const data = homeContract.contract.methods + .initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, '3', '2', owner) + .encodeABI() + await storageProxy.upgradeToAndCall('1', homeContract.address, data).should.be.fulfilled await storageProxy.transferProxyOwnership(owner).should.be.fulfilled }) }) @@ -84,31 +171,44 @@ contract('HomeBridge', async (accounts) => { describe('#fallback', async () => { beforeEach(async () => { homeContract = await HomeBridge.new() - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner) + await homeContract.initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) }) - it('should accept POA', async () => { + it('should accept native coins', async () => { const currentDay = await homeContract.getCurrentDay() - '0'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay)) - const {logs} = await homeContract.sendTransaction({ + expect(await homeContract.totalSpentPerDay(currentDay)).to.be.bignumber.equal(ZERO) + + const { logs } = await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled - '1'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay)) - await homeContract.sendTransaction({ - from: accounts[1], - value: 3 - }).should.be.rejectedWith(ERROR_MSG); - logs[0].event.should.be.equal('UserRequestForSignature') - logs[0].args.should.be.deep.equal({ - recipient: accounts[1], - value: new web3.BigNumber(1) - }) - await homeContract.setDailyLimit(4).should.be.fulfilled; + expect(await homeContract.totalSpentPerDay(currentDay)).to.be.bignumber.equal('1') + + expectEventInLogs(logs, 'UserRequestForSignature', { recipient: accounts[1], value: toBN(1) }) + + await homeContract + .sendTransaction({ + from: accounts[1], + value: 3 + }) + .should.be.rejectedWith(ERROR_MSG) + + await homeContract.setDailyLimit(4).should.be.fulfilled await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled - '2'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay)) + + expect(await homeContract.totalSpentPerDay(currentDay)).to.be.bignumber.equal('2') }) it('doesnt let you send more than max amount per tx', async () => { @@ -116,366 +216,497 @@ contract('HomeBridge', async (accounts) => { from: accounts[1], value: 1 }).should.be.fulfilled - await homeContract.sendTransaction({ - from: accounts[1], - value: 3 - }).should.be.rejectedWith(ERROR_MSG) - await homeContract.setMaxPerTx(100).should.be.rejectedWith(ERROR_MSG); - await homeContract.setDailyLimit(100).should.be.fulfilled; - await homeContract.setMaxPerTx(99).should.be.fulfilled; - //meets max per tx and daily limit + await homeContract + .sendTransaction({ + from: accounts[1], + value: 3 + }) + .should.be.rejectedWith(ERROR_MSG) + await homeContract.setMaxPerTx(100).should.be.rejectedWith(ERROR_MSG) + await homeContract.setDailyLimit(100).should.be.fulfilled + await homeContract.setMaxPerTx(99).should.be.fulfilled + // meets max per tx and daily limit await homeContract.sendTransaction({ from: accounts[1], value: 99 }).should.be.fulfilled - //above daily limit - await homeContract.sendTransaction({ - from: accounts[1], - value: 1 - }).should.be.rejectedWith(ERROR_MSG) - + // above daily limit + await homeContract + .sendTransaction({ + from: accounts[1], + value: 1 + }) + .should.be.rejectedWith(ERROR_MSG) }) it('should not let to deposit less than minPerTx', async () => { - const newDailyLimit = 100; - const newMaxPerTx = 50; - const newMinPerTx = 20; - await homeContract.setDailyLimit(newDailyLimit).should.be.fulfilled; - await homeContract.setMaxPerTx(newMaxPerTx).should.be.fulfilled; - await homeContract.setMinPerTx(newMinPerTx).should.be.fulfilled; + const newDailyLimit = 100 + const newMaxPerTx = 50 + const newMinPerTx = 20 + await homeContract.setDailyLimit(newDailyLimit).should.be.fulfilled + await homeContract.setMaxPerTx(newMaxPerTx).should.be.fulfilled + await homeContract.setMinPerTx(newMinPerTx).should.be.fulfilled await homeContract.sendTransaction({ from: accounts[1], value: newMinPerTx }).should.be.fulfilled - await homeContract.sendTransaction({ - from: accounts[1], - value: newMinPerTx - 1 - }).should.be.rejectedWith(ERROR_MSG) + await homeContract + .sendTransaction({ + from: accounts[1], + value: newMinPerTx - 1 + }) + .should.be.rejectedWith(ERROR_MSG) }) }) describe('#setting limits', async () => { - let homeContract; + let homeContract beforeEach(async () => { homeContract = await HomeBridge.new() - await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner) + await homeContract.initialize( + validatorContract.address, + '3', + '2', + '1', + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) }) it('#setMaxPerTx allows to set only to owner and cannot be more than daily limit', async () => { - await homeContract.setMaxPerTx(2, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); - await homeContract.setMaxPerTx(2, {from: owner}).should.be.fulfilled; + await homeContract.setMaxPerTx(2, { from: authorities[0] }).should.be.rejectedWith(ERROR_MSG) + await homeContract.setMaxPerTx(2, { from: owner }).should.be.fulfilled - await homeContract.setMaxPerTx(3, {from: owner}).should.be.rejectedWith(ERROR_MSG); + await homeContract.setMaxPerTx(3, { from: owner }).should.be.rejectedWith(ERROR_MSG) }) it('#setMinPerTx allows to set only to owner and cannot be more than daily limit and should be less than maxPerTx', async () => { - await homeContract.setMinPerTx(1, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); - await homeContract.setMinPerTx(1, {from: owner}).should.be.fulfilled; + await homeContract.setMinPerTx(1, { from: authorities[0] }).should.be.rejectedWith(ERROR_MSG) + await homeContract.setMinPerTx(1, { from: owner }).should.be.fulfilled - await homeContract.setMinPerTx(2, {from: owner}).should.be.rejectedWith(ERROR_MSG); + await homeContract.setMinPerTx(2, { from: owner }).should.be.rejectedWith(ERROR_MSG) }) }) describe('#executeAffirmation', async () => { - let homeBridge; + let homeBridge beforeEach(async () => { - homeBridge = await HomeBridge.new(); - await homeBridge.initialize(validatorContract.address, twoEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner); - const {logs} = await homeBridge.sendTransaction({ + homeBridge = await HomeBridge.new() + await homeBridge.initialize( + validatorContract.address, + twoEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) + await homeBridge.sendTransaction({ from: accounts[2], value: halfEther }).should.be.fulfilled }) it('should allow validator to executeAffirmation', async () => { - const recipient = accounts[5]; - const value = halfEther; - const balanceBefore = await web3.eth.getBalance(recipient) - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const {logs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}) - logs[0].event.should.be.equal("SignedForAffirmation"); - logs[0].args.should.be.deep.equal({ + const recipient = accounts[5] + const value = halfEther + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }) + + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: authorities[0], + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + const homeBalanceAfter = toBN(await web3.eth.getBalance(homeBridge.address)) + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(value)) + homeBalanceAfter.should.be.bignumber.equal(ZERO) + + const msgHash = web3.utils.soliditySha3(recipient, value, transactionHash) + const senderHash = web3.utils.soliditySha3(authorities[0], msgHash) + true.should.be.equal(await homeBridge.affirmationsSigned(senderHash)) + }) + + it('should allow validator to executeAffirmation with zero value', async () => { + const recipient = accounts[5] + const value = ZERO + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }) + + expectEventInLogs(logs, 'SignedForAffirmation', { signer: authorities[0], transactionHash - }); - logs[1].event.should.be.equal("AffirmationCompleted"); - logs[1].args.should.be.deep.equal({ + }) + expectEventInLogs(logs, 'AffirmationCompleted', { recipient, value, transactionHash }) - const homeBalanceAfter = await web3.eth.getBalance(homeBridge.address) - const balanceAfter = await web3.eth.getBalance(recipient) + + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) balanceAfter.should.be.bignumber.equal(balanceBefore.add(value)) - homeBalanceAfter.should.be.bignumber.equal(0) - const msgHash = Web3Utils.soliditySha3(recipient, value, transactionHash); - const senderHash = Web3Utils.soliditySha3(authorities[0], msgHash) + const msgHash = web3.utils.soliditySha3(recipient, value, transactionHash) + const senderHash = web3.utils.soliditySha3(authorities[0], msgHash) true.should.be.equal(await homeBridge.affirmationsSigned(senderHash)) }) it('test with 2 signatures required', async () => { - let validatorContractWith2Signatures = await BridgeValidators.new() - let authoritiesTwoAccs = [accounts[1], accounts[2], accounts[3]]; - let ownerOfValidators = accounts[0] - await validatorContractWith2Signatures.initialize(2, authoritiesTwoAccs, ownerOfValidators) - let homeBridgeWithTwoSigs = await HomeBridge.new(); - await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, twoEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner); + const validatorContractWith2Signatures = await BridgeValidators.new() + const authoritiesThreeAccs = [accounts[1], accounts[2], accounts[3]] + const ownerOfValidators = accounts[0] + await validatorContractWith2Signatures.initialize(2, authoritiesThreeAccs, ownerOfValidators) + const homeBridgeWithTwoSigs = await HomeBridge.new() + await homeBridgeWithTwoSigs.initialize( + validatorContractWith2Signatures.address, + twoEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) await homeBridgeWithTwoSigs.sendTransaction({ from: accounts[2], value: halfEther }).should.be.fulfilled - const homeBalanceBefore = await web3.eth.getBalance(homeBridgeWithTwoSigs.address) + const homeBalanceBefore = toBN(await web3.eth.getBalance(homeBridgeWithTwoSigs.address)) homeBalanceBefore.should.be.bignumber.equal(halfEther) - const recipient = accounts[5]; - const value = halfEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const balanceBefore = await web3.eth.getBalance(recipient) - const msgHash = Web3Utils.soliditySha3(recipient, value, transactionHash); + const recipient = accounts[5] + const value = halfEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + const msgHash = web3.utils.soliditySha3(recipient, value, transactionHash) - const {logs} = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - logs[0].event.should.be.equal("SignedForAffirmation"); - logs[0].args.should.be.deep.equal({ - signer: authorities[0], - transactionHash - }); + const { logs } = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled + + expectEventInLogs(logs, 'SignedForAffirmation', { signer: authorities[0], transactionHash }) halfEther.should.be.bignumber.equal(await web3.eth.getBalance(homeBridgeWithTwoSigs.address)) - const notProcessed = await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash); - notProcessed.should.be.bignumber.equal(1); + const notProcessed = await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash) + notProcessed.should.be.bignumber.equal('1') - await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[0]}).should.be.rejectedWith(ERROR_MSG); - const secondSignature = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; + await homeBridgeWithTwoSigs + .executeAffirmation(recipient, value, transactionHash, { from: authoritiesThreeAccs[0] }) + .should.be.rejectedWith(ERROR_MSG) + const secondSignature = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled - const balanceAfter = await web3.eth.getBalance(recipient) + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) balanceAfter.should.be.bignumber.equal(balanceBefore.add(value)) - '0'.should.be.bignumber.equal(await web3.eth.getBalance(homeBridgeWithTwoSigs.address)) + expect(toBN(await web3.eth.getBalance(homeBridgeWithTwoSigs.address))).to.be.bignumber.equal(ZERO) - secondSignature.logs[1].event.should.be.equal("AffirmationCompleted"); - secondSignature.logs[1].args.should.be.deep.equal({ + expectEventInLogs(secondSignature.logs, 'AffirmationCompleted', { recipient, value, transactionHash }) - const senderHash = Web3Utils.soliditySha3(authoritiesTwoAccs[0], msgHash) + const senderHash = web3.utils.soliditySha3(authoritiesThreeAccs[0], msgHash) true.should.be.equal(await homeBridgeWithTwoSigs.affirmationsSigned(senderHash)) - const senderHash2 = Web3Utils.soliditySha3(authoritiesTwoAccs[1], msgHash); + const senderHash2 = web3.utils.soliditySha3(authoritiesThreeAccs[1], msgHash) true.should.be.equal(await homeBridgeWithTwoSigs.affirmationsSigned(senderHash2)) - const markedAsProcessed = await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash); - const processed = new web3.BigNumber(2).pow(255).add(2); + const markedAsProcessed = await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash) + const processed = toBN(2) + .pow(toBN(255)) + .add(toBN(2)) markedAsProcessed.should.be.bignumber.equal(processed) }) it('should not allow to double submit', async () => { - const recipient = accounts[5]; - const value = '1'; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled; - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); + const recipient = accounts[5] + const value = '1' + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled + await homeBridge + .executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }) + .should.be.rejectedWith(ERROR_MSG) }) it('should not allow non-authorities to execute withdraw', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: accounts[7]}).should.be.rejectedWith(ERROR_MSG); + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + await homeBridge + .executeAffirmation(recipient, value, transactionHash, { from: accounts[7] }) + .should.be.rejectedWith(ERROR_MSG) }) it('doesnt allow to withdraw if requiredSignatures has changed', async () => { - let validatorContractWith2Signatures = await BridgeValidators.new() - let authoritiesTwoAccs = [accounts[1], accounts[2], accounts[3]]; - let ownerOfValidators = accounts[0] - await validatorContractWith2Signatures.initialize(2, authoritiesTwoAccs, ownerOfValidators) - let homeBridgeWithTwoSigs = await HomeBridge.new(); - await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner); + const validatorContractWith2Signatures = await BridgeValidators.new() + const authoritiesThreeAccs = [accounts[1], accounts[2], accounts[3]] + const ownerOfValidators = accounts[0] + await validatorContractWith2Signatures.initialize(2, authoritiesThreeAccs, ownerOfValidators) + const homeBridgeWithTwoSigs = await HomeBridge.new() + await homeBridgeWithTwoSigs.initialize( + validatorContractWith2Signatures.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) await homeBridgeWithTwoSigs.sendTransaction({ from: accounts[2], value: halfEther }).should.be.fulfilled - const homeBalanceBefore = await web3.eth.getBalance(homeBridgeWithTwoSigs.address) + const homeBalanceBefore = toBN(await web3.eth.getBalance(homeBridgeWithTwoSigs.address)) homeBalanceBefore.should.be.bignumber.equal(halfEther) - const recipient = accounts[5]; - const value = halfEther.div(2); - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const balanceBefore = await web3.eth.getBalance(recipient) - const msgHash = Web3Utils.soliditySha3(recipient, value, transactionHash); + const recipient = accounts[5] + const value = halfEther.div(toBN(2)) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + + await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled + await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled + expect(toBN(await web3.eth.getBalance(recipient))).to.be.bignumber.equal(balanceBefore.add(value)) - await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; - balanceBefore.add(value).should.be.bignumber.equal(await web3.eth.getBalance(recipient)) - await validatorContractWith2Signatures.setRequiredSignatures(3).should.be.fulfilled; - await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[2]}).should.be.rejectedWith(ERROR_MSG); - await validatorContractWith2Signatures.setRequiredSignatures(1).should.be.fulfilled; - await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[2]}).should.be.rejectedWith(ERROR_MSG); - balanceBefore.add(value).should.be.bignumber.equal(await web3.eth.getBalance(recipient)) + await validatorContractWith2Signatures.setRequiredSignatures(3).should.be.fulfilled + await homeBridgeWithTwoSigs + .executeAffirmation(recipient, value, transactionHash, { from: authoritiesThreeAccs[2] }) + .should.be.rejectedWith(ERROR_MSG) + await validatorContractWith2Signatures.setRequiredSignatures(1).should.be.fulfilled + await homeBridgeWithTwoSigs + .executeAffirmation(recipient, value, transactionHash, { from: authoritiesThreeAccs[2] }) + .should.be.rejectedWith(ERROR_MSG) + expect(toBN(await web3.eth.getBalance(recipient))).to.be.bignumber.equal(balanceBefore.add(value)) }) it('force withdraw if the recepient has fallback to revert', async () => { - const revertFallbackContract = await RevertFallback.new(); - await revertFallbackContract.receiveEth({from: accounts[0], value: halfEther}) - await web3.eth.getBalance(revertFallbackContract.address).should.be.bignumber.equal(halfEther) - - const transactionHash = "0x106335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const {logs} = await homeBridge.executeAffirmation(revertFallbackContract.address, halfEther, transactionHash, {from: authorities[0]}) - logs[0].event.should.be.equal("SignedForAffirmation"); - logs[0].args.should.be.deep.equal({ + const revertFallbackContract = await RevertFallback.new() + await revertFallbackContract.receiveEth({ from: accounts[0], value: halfEther }) + expect(toBN(await web3.eth.getBalance(revertFallbackContract.address))).to.be.bignumber.equal(halfEther) + + const transactionHash = '0x106335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs } = await homeBridge.executeAffirmation(revertFallbackContract.address, halfEther, transactionHash, { + from: authorities[0] + }) + + expectEventInLogs(logs, 'SignedForAffirmation', { signer: authorities[0], transactionHash - }); - logs[1].event.should.be.equal("AffirmationCompleted"); - logs[1].args.should.be.deep.equal({ + }) + expectEventInLogs(logs, 'AffirmationCompleted', { recipient: revertFallbackContract.address, value: halfEther, transactionHash }) - const homeBalanceAfter = await web3.eth.getBalance(homeBridge.address) - const balanceAfter = await web3.eth.getBalance(revertFallbackContract.address) + const homeBalanceAfter = toBN(await web3.eth.getBalance(homeBridge.address)) + const balanceAfter = toBN(await web3.eth.getBalance(revertFallbackContract.address)) balanceAfter.should.be.bignumber.equal(halfEther.add(halfEther)) - homeBalanceAfter.should.be.bignumber.equal(0) - + homeBalanceAfter.should.be.bignumber.equal(ZERO) }) it('works with 5 validators and 3 required signatures', async () => { const recipient = accounts[8] const authoritiesFiveAccs = [accounts[1], accounts[2], accounts[3], accounts[4], accounts[5]] - let ownerOfValidators = accounts[0] + const ownerOfValidators = accounts[0] const validatorContractWith3Signatures = await BridgeValidators.new() await validatorContractWith3Signatures.initialize(3, authoritiesFiveAccs, ownerOfValidators) - const homeBridgeWithThreeSigs = await HomeBridge.new(); - await homeBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner); + const homeBridgeWithThreeSigs = await HomeBridge.new() + await homeBridgeWithThreeSigs.initialize( + validatorContractWith3Signatures.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; + const value = halfEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' await homeBridgeWithThreeSigs.sendTransaction({ from: recipient, value: halfEther }).should.be.fulfilled - const {logs} = await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesFiveAccs[0]}).should.be.fulfilled; - logs[0].event.should.be.equal("SignedForAffirmation"); - logs[0].args.should.be.deep.equal({ + const { logs } = await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesFiveAccs[0] + }).should.be.fulfilled + expectEventInLogs(logs, 'SignedForAffirmation', { signer: authorities[0], transactionHash - }); + }) - await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesFiveAccs[1]}).should.be.fulfilled; - const thirdSignature = await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesFiveAccs[2]}).should.be.fulfilled; + await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesFiveAccs[1] + }).should.be.fulfilled + const thirdSignature = await homeBridgeWithThreeSigs.executeAffirmation(recipient, value, transactionHash, { + from: authoritiesFiveAccs[2] + }).should.be.fulfilled - thirdSignature.logs[1].event.should.be.equal("AffirmationCompleted"); - thirdSignature.logs[1].args.should.be.deep.equal({ + expectEventInLogs(thirdSignature.logs, 'AffirmationCompleted', { recipient, value, transactionHash }) }) it('should not allow execute affirmation over foreign max tx limit', async () => { - const recipient = accounts[5]; - const value = oneEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; + const recipient = accounts[5] + const value = oneEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' - await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); + await homeBridge + .executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }) + .should.be.rejectedWith(ERROR_MSG) }) it('should not allow execute affirmation over daily foreign limit', async () => { + await homeBridge.sendTransaction({ from: accounts[2], value: halfEther }).should.be.fulfilled + await homeBridge.sendTransaction({ from: accounts[2], value: halfEther }).should.be.fulfilled - await homeBridge.sendTransaction({ from: accounts[2], value: halfEther }).should.be.fulfilled; - await homeBridge.sendTransaction({ from: accounts[2], value: halfEther }).should.be.fulfilled; - - const recipient = accounts[5]; - const value = halfEther; - const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415"; - const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled; + const recipient = accounts[5] + const value = halfEther + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: authorities[0] + }).should.be.fulfilled - logs[0].event.should.be.equal("SignedForAffirmation"); - logs[0].args.should.be.deep.equal({ + expectEventInLogs(logs, 'SignedForAffirmation', { signer: authorities[0], transactionHash - }); - logs[1].event.should.be.equal("AffirmationCompleted"); - logs[1].args.should.be.deep.equal({ + }) + expectEventInLogs(logs, 'AffirmationCompleted', { recipient, value, transactionHash }) - const transactionHash2 = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121"; - const { logs: logs2 } = await homeBridge.executeAffirmation(recipient, value, transactionHash2, {from: authorities[0]}).should.be.fulfilled; + const transactionHash2 = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121' + const { logs: logs2 } = await homeBridge.executeAffirmation(recipient, value, transactionHash2, { + from: authorities[0] + }).should.be.fulfilled - logs2[0].event.should.be.equal("SignedForAffirmation"); - logs2[0].args.should.be.deep.equal({ + expectEventInLogs(logs2, 'SignedForAffirmation', { signer: authorities[0], transactionHash: transactionHash2 - }); - logs2[1].event.should.be.equal("AffirmationCompleted"); - logs2[1].args.should.be.deep.equal({ + }) + expectEventInLogs(logs2, 'AffirmationCompleted', { recipient, value, transactionHash: transactionHash2 }) - const transactionHash3 = "0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712"; - await homeBridge.executeAffirmation(recipient, value, transactionHash3, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG); + const transactionHash3 = '0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712' + await homeBridge + .executeAffirmation(recipient, value, transactionHash3, { from: authorities[0] }) + .should.be.rejectedWith(ERROR_MSG) }) }) + describe('#isAlreadyProcessed', async () => { it('returns ', async () => { - homeBridge = await HomeBridge.new(); - const bn = new web3.BigNumber(2).pow(255); - const processedNumbers = [bn.add(1).toString(10), bn.add(100).toString(10)]; - true.should.be.equal(await homeBridge.isAlreadyProcessed(processedNumbers[0])); - true.should.be.equal(await homeBridge.isAlreadyProcessed(processedNumbers[1])); - false.should.be.equal(await homeBridge.isAlreadyProcessed(10)); + const homeBridge = await HomeBridge.new() + const bn = toBN(2).pow(toBN(255)) + const processedNumbers = [bn.add(toBN(1)).toString(10), bn.add(toBN(100)).toString(10)] + true.should.be.equal(await homeBridge.isAlreadyProcessed(processedNumbers[0])) + true.should.be.equal(await homeBridge.isAlreadyProcessed(processedNumbers[1])) + false.should.be.equal(await homeBridge.isAlreadyProcessed(10)) }) }) describe('#submitSignature', async () => { - let validatorContractWith2Signatures,authoritiesTwoAccs,ownerOfValidators,tokenPOA20,homeBridgeWithTwoSigs + let validatorContractWith2Signatures + let authoritiesThreeAccs + let ownerOfValidators + let homeBridgeWithTwoSigs beforeEach(async () => { validatorContractWith2Signatures = await BridgeValidators.new() - authoritiesTwoAccs = [accounts[1], accounts[2], accounts[3]]; + authoritiesThreeAccs = [accounts[1], accounts[2], accounts[3]] ownerOfValidators = accounts[0] - await validatorContractWith2Signatures.initialize(2, authoritiesTwoAccs, ownerOfValidators) - homeBridgeWithTwoSigs = await HomeBridge.new(); - await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner); + await validatorContractWith2Signatures.initialize(2, authoritiesThreeAccs, ownerOfValidators) + homeBridgeWithTwoSigs = await HomeBridge.new() + await homeBridgeWithTwoSigs.initialize( + validatorContractWith2Signatures.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) }) it('allows a validator to submit a signature', async () => { - var recipientAccount = accounts[8] - var value = web3.toBigNumber(web3.toWei(0.5, "ether")); - var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - var message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address); - var signature = await sign(authoritiesTwoAccs[0], message) - const {logs} = await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authorities[0]}).should.be.fulfilled; + const recipientAccount = accounts[8] + const value = halfEther + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address) + const signature = await sign(authoritiesThreeAccs[0], message) + const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature, message, { + from: authorities[0] + }).should.be.fulfilled logs[0].event.should.be.equal('SignedForUserRequest') const msgHashFromLog = logs[0].args.messageHash - const signatureFromContract = await homeBridgeWithTwoSigs.signature(msgHashFromLog, 0); - const messageFromContract = await homeBridgeWithTwoSigs.message(msgHashFromLog); - signature.should.be.equal(signatureFromContract); - messageFromContract.should.be.equal(messageFromContract); - const hashMsg = Web3Utils.soliditySha3(message); - const hashSenderMsg = Web3Utils.soliditySha3(authorities[0], hashMsg) - true.should.be.equal(await homeBridgeWithTwoSigs.messagesSigned(hashSenderMsg)); + const signatureFromContract = await homeBridgeWithTwoSigs.signature(msgHashFromLog, 0) + const messageFromContract = await homeBridgeWithTwoSigs.message(msgHashFromLog) + signature.should.be.equal(signatureFromContract) + messageFromContract.should.be.equal(messageFromContract) + const hashMsg = web3.utils.soliditySha3(message) + const hashSenderMsg = web3.utils.soliditySha3(authorities[0], hashMsg) + true.should.be.equal(await homeBridgeWithTwoSigs.messagesSigned(hashSenderMsg)) }) it('when enough requiredSignatures are collected, CollectedSignatures event is emitted', async () => { - var recipientAccount = accounts[8] - var value = web3.toBigNumber(web3.toWei(0.5, "ether")); - var homeGasPrice = web3.toBigNumber(0); - var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - var message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address); - var signature = await sign(authoritiesTwoAccs[0], message) - var signature2 = await sign(authoritiesTwoAccs[1], message) - '2'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.rejectedWith(ERROR_MSG); - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[1]}).should.be.rejectedWith(ERROR_MSG); - const {logs} = await homeBridgeWithTwoSigs.submitSignature(signature2, message, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; + const recipientAccount = accounts[8] + const value = halfEther + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address) + const signature = await sign(authoritiesThreeAccs[0], message) + const signature2 = await sign(authoritiesThreeAccs[1], message) + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('2') + await homeBridgeWithTwoSigs.submitSignature(signature, message, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled + await homeBridgeWithTwoSigs + .submitSignature(signature, message, { from: authoritiesThreeAccs[0] }) + .should.be.rejectedWith(ERROR_MSG) + await homeBridgeWithTwoSigs + .submitSignature(signature, message, { from: authoritiesThreeAccs[1] }) + .should.be.rejectedWith(ERROR_MSG) + const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled logs.length.should.be.equal(2) logs[1].event.should.be.equal('CollectedSignatures') - logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesTwoAccs[1]) + logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesThreeAccs[1]) }) it('works with 5 validators and 3 required signatures', async () => { const recipientAccount = accounts[8] @@ -483,62 +714,95 @@ contract('HomeBridge', async (accounts) => { const validatorContractWith3Signatures = await BridgeValidators.new() await validatorContractWith3Signatures.initialize(3, authoritiesFiveAccs, ownerOfValidators) - const homeBridgeWithThreeSigs = await HomeBridge.new(); - await homeBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, foreignDailyLimit, foreignMaxPerTx, owner); + const homeBridgeWithThreeSigs = await HomeBridge.new() + await homeBridgeWithThreeSigs.initialize( + validatorContractWith3Signatures.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner + ) - const value = web3.toBigNumber(web3.toWei(0.5, "ether")); - const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithThreeSigs.address); + const value = halfEther + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithThreeSigs.address) const signature = await sign(authoritiesFiveAccs[0], message) const signature2 = await sign(authoritiesFiveAccs[1], message) const signature3 = await sign(authoritiesFiveAccs[2], message) - '3'.should.be.bignumber.equal(await validatorContractWith3Signatures.requiredSignatures()); + expect(await validatorContractWith3Signatures.requiredSignatures()).to.be.bignumber.equal('3') - await homeBridgeWithThreeSigs.submitSignature(signature, message, {from: authoritiesFiveAccs[0]}).should.be.fulfilled; - await homeBridgeWithThreeSigs.submitSignature(signature2, message, {from: authoritiesFiveAccs[1]}).should.be.fulfilled; - const {logs} = await homeBridgeWithThreeSigs.submitSignature(signature3, message, {from: authoritiesFiveAccs[2]}).should.be.fulfilled; + await homeBridgeWithThreeSigs.submitSignature(signature, message, { + from: authoritiesFiveAccs[0] + }).should.be.fulfilled + await homeBridgeWithThreeSigs.submitSignature(signature2, message, { + from: authoritiesFiveAccs[1] + }).should.be.fulfilled + const { logs } = await homeBridgeWithThreeSigs.submitSignature(signature3, message, { + from: authoritiesFiveAccs[2] + }).should.be.fulfilled logs.length.should.be.equal(2) logs[1].event.should.be.equal('CollectedSignatures') logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesFiveAccs[2]) }) it('attack when increasing requiredSignatures', async () => { - var recipientAccount = accounts[8] - var value = web3.toBigNumber(web3.toWei(0.5, "ether")); - var homeGasPrice = web3.toBigNumber(0); - var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - var message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address); - var signature = await sign(authoritiesTwoAccs[0], message) - var signature2 = await sign(authoritiesTwoAccs[1], message) - var signature3 = await sign(authoritiesTwoAccs[2], message) - '2'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.rejectedWith(ERROR_MSG); - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[1]}).should.be.rejectedWith(ERROR_MSG); - const {logs} = await homeBridgeWithTwoSigs.submitSignature(signature2, message, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; + const recipientAccount = accounts[8] + const value = halfEther + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address) + const signature = await sign(authoritiesThreeAccs[0], message) + const signature2 = await sign(authoritiesThreeAccs[1], message) + const signature3 = await sign(authoritiesThreeAccs[2], message) + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('2') + + await homeBridgeWithTwoSigs.submitSignature(signature, message, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled + await homeBridgeWithTwoSigs + .submitSignature(signature, message, { from: authoritiesThreeAccs[0] }) + .should.be.rejectedWith(ERROR_MSG) + await homeBridgeWithTwoSigs + .submitSignature(signature, message, { from: authoritiesThreeAccs[1] }) + .should.be.rejectedWith(ERROR_MSG) + const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled + logs.length.should.be.equal(2) logs[1].event.should.be.equal('CollectedSignatures') - logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesTwoAccs[1]) - await validatorContractWith2Signatures.setRequiredSignatures(3).should.be.fulfilled; - '3'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - const attackerTx = await homeBridgeWithTwoSigs.submitSignature(signature3, message, {from: authoritiesTwoAccs[2]}).should.be.rejectedWith(ERROR_MSG); + logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesThreeAccs[1]) + + await validatorContractWith2Signatures.setRequiredSignatures(3).should.be.fulfilled + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('3') + + await homeBridgeWithTwoSigs + .submitSignature(signature3, message, { from: authoritiesThreeAccs[2] }) + .should.be.rejectedWith(ERROR_MSG) }) it('attack when decreasing requiredSignatures', async () => { - var recipientAccount = accounts[8] - var value = web3.toBigNumber(web3.toWei(0.5, "ether")); - var homeGasPrice = web3.toBigNumber(0); - var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80"; - var message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address); - var signature = await sign(authoritiesTwoAccs[0], message) - var signature2 = await sign(authoritiesTwoAccs[1], message) - var signature3 = await sign(authoritiesTwoAccs[2], message) - '2'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.fulfilled; - await validatorContractWith2Signatures.setRequiredSignatures(1).should.be.fulfilled; - '1'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures()); - const {logs} = await homeBridgeWithTwoSigs.submitSignature(signature2, message, {from: authoritiesTwoAccs[1]}).should.be.fulfilled; + const recipientAccount = accounts[8] + const value = halfEther + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address) + const signature = await sign(authoritiesThreeAccs[0], message) + const signature2 = await sign(authoritiesThreeAccs[1], message) + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('2') + + await homeBridgeWithTwoSigs.submitSignature(signature, message, { + from: authoritiesThreeAccs[0] + }).should.be.fulfilled + await validatorContractWith2Signatures.setRequiredSignatures(1).should.be.fulfilled + expect(await validatorContractWith2Signatures.requiredSignatures()).to.be.bignumber.equal('1') + const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, { + from: authoritiesThreeAccs[1] + }).should.be.fulfilled + logs.length.should.be.equal(2) logs[1].event.should.be.equal('CollectedSignatures') - logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesTwoAccs[1]) + logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesThreeAccs[1]) }) }) @@ -548,8 +812,1176 @@ contract('HomeBridge', async (accounts) => { }) it('should return the required message length', async () => { - const requiredMessageLength = await homeContract.requiredMessageLength() - '104'.should.be.bignumber.equal(requiredMessageLength) + expect(await homeContract.requiredMessageLength()).to.be.bignumber.equal('104') + }) + }) + + describe('#rewardableInitialize', async () => { + let homeFee + let foreignFee + let homeBridge + let rewardableValidators + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + beforeEach(async () => { + rewardableValidators = await RewardableValidators.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner).should.be.fulfilled + homeBridge = await HomeBridge.new() + homeFee = ZERO + foreignFee = ether('0.002') + }) + it('sets variables', async () => { + const feeManager = await FeeManagerNativeToErc.new() + expect(await homeBridge.validatorContract()).to.be.equal(ZERO_ADDRESS) + expect(await homeBridge.deployedAtBlock()).to.be.bignumber.equal(ZERO) + expect(await homeBridge.dailyLimit()).to.be.bignumber.equal(ZERO) + expect(await homeBridge.maxPerTx()).to.be.bignumber.equal(ZERO) + expect(await homeBridge.isInitialized()).to.be.equal(false) + + await homeBridge + .rewardableInitialize( + ZERO_ADDRESS, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ) + .should.be.rejectedWith(ERROR_MSG) + await homeBridge + .rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + 0, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ) + .should.be.rejectedWith(ERROR_MSG) + await homeBridge + .rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + 0, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ) + .should.be.rejectedWith(ERROR_MSG) + await homeBridge + .rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + ZERO_ADDRESS, + homeFee, + foreignFee + ) + .should.be.rejectedWith(ERROR_MSG) + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ).should.be.fulfilled + + expect(await homeBridge.isInitialized()).to.be.equal(true) + expect(await homeBridge.validatorContract()).to.be.equal(rewardableValidators.address) + expect(await homeBridge.deployedAtBlock()).to.be.bignumber.above(ZERO) + expect(await homeBridge.dailyLimit()).to.be.bignumber.equal(oneEther) + expect(await homeBridge.maxPerTx()).to.be.bignumber.equal(halfEther) + expect(await homeBridge.minPerTx()).to.be.bignumber.equal(minPerTx) + expect(await homeBridge.gasPrice()).to.be.bignumber.equal(gasPrice) + const bridgeMode = '0x92a8d7fe' // 4 bytes of keccak256('native-to-erc-core') + expect(await homeBridge.getBridgeMode()).to.be.equal(bridgeMode) + const { major, minor, patch } = await homeBridge.getBridgeInterfacesVersion() + expect(major).to.be.bignumber.gte(ZERO) + expect(minor).to.be.bignumber.gte(ZERO) + expect(patch).to.be.bignumber.gte(ZERO) + + const feeManagerContract = await homeBridge.feeManagerContract() + feeManagerContract.should.be.equals(feeManager.address) + const bridgeForeignFee = await homeBridge.getForeignFee() + bridgeForeignFee.should.be.bignumber.equal(foreignFee) + }) + + it('can update fee contract', async () => { + const feeManager = await FeeManagerNativeToErc.new() + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ).should.be.fulfilled + + // Given + const newFeeManager = await FeeManagerNativeToErc.new() + + // When + await homeBridge.setFeeManagerContract(newFeeManager.address, { from: owner }).should.be.fulfilled + + // Then + const feeManagerContract = await homeBridge.feeManagerContract() + feeManagerContract.should.be.equals(newFeeManager.address) + }) + + it('can update fee', async () => { + const feeManager = await FeeManagerNativeToErc.new() + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ).should.be.fulfilled + + // Given + const newForeignFee = ether('0.2') + + // When + await homeBridge.setForeignFee(newForeignFee, { from: owner }).should.be.fulfilled + + // Then + const bridgeForeignFee = await homeBridge.getForeignFee() + bridgeForeignFee.should.be.bignumber.equal(newForeignFee) + }) + it('should be able to get fee manager mode', async () => { + // Given + const feeManager = await FeeManagerNativeToErc.new() + const oneDirectionsModeHash = '0xf2aed8f7' + + // When + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + homeFee, + foreignFee + ).should.be.fulfilled + + // Then + const feeManagerMode = await homeBridge.getFeeManagerMode() + feeManagerMode.should.be.equals(oneDirectionsModeHash) + }) + }) + + describe('#feeManager_OneDirection_fallback', () => { + it('should not subtract fee from value', async () => { + // Initialize + const user = accounts[0] + const owner = accounts[9] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + const rewardableValidators = await RewardableValidators.new() + const homeBridge = await HomeBridge.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + const feeManager = await FeeManagerNativeToErc.new() + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const notUsedFee = ZERO + const value = halfEther + + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + notUsedFee, + feeInWei + ).should.be.fulfilled + + // When + const { logs } = await homeBridge.sendTransaction({ + from: user, + value + }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'UserRequestForSignature', { + recipient: user, + value + }) + }) + }) + + describe('#feeManager_OneDirection_submitSignature', () => { + it('should not distribute fee to validator', async () => { + // Initialize + const user = accounts[0] + const owner = accounts[9] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + const rewardableValidators = await RewardableValidators.new() + const homeBridge = await HomeBridge.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + const feeManager = await FeeManagerNativeToErc.new() + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const notUsedFee = ZERO + const value = halfEther + + const rewardAddressBalanceBefore = await web3.eth.getBalance(rewards[0]) + + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + notUsedFee, + feeInWei + ).should.be.fulfilled + + await homeBridge.sendTransaction({ + from: user, + value + }).should.be.fulfilled + + // When + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(user, value, transactionHash, homeBridge.address) + const signature = await sign(validators[0], message) + const { logs } = await homeBridge.submitSignature(signature, message, { from: validators[0] }).should.be.fulfilled + + // Then + logs.length.should.be.equal(2) + logs[1].event.should.be.equal('CollectedSignatures') + + const bridgeBalance = toBN(await web3.eth.getBalance(homeBridge.address)) + bridgeBalance.should.be.bignumber.equal(value) + + const rewardAddressBalanceAfter = toBN(await web3.eth.getBalance(rewards[0])) + rewardAddressBalanceAfter.should.be.bignumber.equal(rewardAddressBalanceBefore) + }) + }) + + describe('#feeManager_OneDirection_ExecuteAffirmation', async () => { + it('should distribute fee to validator', async () => { + // Initialize + const owner = accounts[9] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + const rewardableValidators = await RewardableValidators.new() + const homeBridge = await HomeBridge.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + const feeManager = await FeeManagerNativeToErc.new() + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const notUsedFee = ZERO + const value = halfEther + const valueCalc = 0.5 * (1 - fee) + const finalUserValue = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + notUsedFee, + feeInWei + ).should.be.fulfilled + await homeBridge.sendTransaction({ + from: accounts[0], + value: halfEther + }).should.be.fulfilled + + const recipient = accounts[5] + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + const rewardAddressBalanceBefore = toBN(await web3.eth.getBalance(rewards[0])) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + // When + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[0] + }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: validators[0], + transactionHash + }) + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) + const rewardAddressBalanceAfter = toBN(await web3.eth.getBalance(rewards[0])) + + rewardAddressBalanceAfter.should.be.bignumber.equal(rewardAddressBalanceBefore.add(feeAmount)) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(finalUserValue)) + }) + it('should distribute fee to 3 validators', async () => { + // Given + const owner = accounts[9] + const validators = [accounts[1], accounts[2], accounts[3]] + const rewards = [accounts[4], accounts[5], accounts[6]] + const requiredSignatures = 2 + const rewardableValidators = await RewardableValidators.new() + + const value = halfEther + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const notUsedFee = ZERO + const feePerValidator = toBN(166666666666666) + const feePerValidatorPlusDiff = toBN(166666666666668) + const valueCalc = 0.5 * (1 - fee) + const finalUserValue = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + + const homeBridge = await HomeBridge.new() + const feeManager = await FeeManagerNativeToErc.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + notUsedFee, + feeInWei + ).should.be.fulfilled + await homeBridge.sendTransaction({ + from: accounts[0], + value: halfEther + }).should.be.fulfilled + + const recipient = accounts[8] + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + + const initialBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const initialBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const initialBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + // When + const { logs: logsValidator1 } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[0] + }).should.be.fulfilled + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[1] + }).should.be.fulfilled + + // Then + logsValidator1.length.should.be.equals(1) + + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: validators[1], + transactionHash + }) + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(finalUserValue)) + + const updatedBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const updatedBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const updatedBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + + expect( + updatedBalanceRewardAddress1.eq(initialBalanceRewardAddress1.add(feePerValidator)) || + updatedBalanceRewardAddress1.eq(initialBalanceRewardAddress1.add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + updatedBalanceRewardAddress2.eq(initialBalanceRewardAddress2.add(feePerValidator)) || + updatedBalanceRewardAddress2.eq(initialBalanceRewardAddress2.add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + updatedBalanceRewardAddress3.eq(initialBalanceRewardAddress3.add(feePerValidator)) || + updatedBalanceRewardAddress3.eq(initialBalanceRewardAddress3.add(feePerValidatorPlusDiff)) + ).to.equal(true) + + const homeBridgeBalance = toBN(await web3.eth.getBalance(homeBridge.address)) + homeBridgeBalance.should.be.bignumber.equal(ZERO) + }) + it('should distribute fee to 5 validators', async () => { + // Given + const owner = accounts[0] + const validators = [accounts[0], accounts[1], accounts[2], accounts[3], accounts[4]] + const rewards = [accounts[5], accounts[6], accounts[7], accounts[8], accounts[9]] + const requiredSignatures = 5 + + const value = halfEther + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const notUsedFee = ZERO + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const feePerValidator = feeAmount.div(toBN(5)) + + const rewardableValidators = await RewardableValidators.new() + const homeBridge = await HomeBridge.new() + const feeManager = await FeeManagerNativeToErc.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + notUsedFee, + feeInWei + ).should.be.fulfilled + await homeBridge.sendTransaction({ + from: accounts[0], + value: halfEther + }).should.be.fulfilled + + const recipient = '0xf4BEF13F9f4f2B203FAF0C3cBbaAbe1afE056955' + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + + const initialBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const initialBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const initialBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + const initialBalanceRewardAddress4 = toBN(await web3.eth.getBalance(rewards[3])) + const initialBalanceRewardAddress5 = toBN(await web3.eth.getBalance(rewards[4])) + + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + // When + const { logs: logsValidator1 } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[0] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[1] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[2] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[3] + }).should.be.fulfilled + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[4] + }).should.be.fulfilled + + // Then + logsValidator1.length.should.be.equals(1) + + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: validators[4], + transactionHash + }) + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(value.sub(feeAmount))) + + const updatedBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const updatedBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const updatedBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + const updatedBalanceRewardAddress4 = toBN(await web3.eth.getBalance(rewards[3])) + const updatedBalanceRewardAddress5 = toBN(await web3.eth.getBalance(rewards[4])) + + updatedBalanceRewardAddress1.should.be.bignumber.equal(initialBalanceRewardAddress1.add(feePerValidator)) + updatedBalanceRewardAddress2.should.be.bignumber.equal(initialBalanceRewardAddress2.add(feePerValidator)) + updatedBalanceRewardAddress3.should.be.bignumber.equal(initialBalanceRewardAddress3.add(feePerValidator)) + updatedBalanceRewardAddress4.should.be.bignumber.equal(initialBalanceRewardAddress4.add(feePerValidator)) + updatedBalanceRewardAddress5.should.be.bignumber.equal(initialBalanceRewardAddress5.add(feePerValidator)) + }) + }) + + describe('#feeManager_BothDirections_fallback', () => { + it('should subtract fee from value', async () => { + // Initialize + const user = accounts[0] + const owner = accounts[9] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + const rewardableValidators = await RewardableValidators.new() + const homeBridge = await HomeBridge.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + const feeManager = await FeeManagerNativeToErcBothDirections.new() + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const value = halfEther + + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + feeInWei, + feeInWei + ).should.be.fulfilled + + // When + const { logs } = await homeBridge.sendTransaction({ + from: user, + value + }).should.be.fulfilled + + // Then + const valueCalc = 0.5 * (1 - fee) + const finalValue = ether(valueCalc.toString()) + expectEventInLogs(logs, 'UserRequestForSignature', { + recipient: user, + value: finalValue + }) + }) + }) + + describe('#feeManager_BothDirections_submitSignature', () => { + it('should distribute fee to validator', async () => { + // Initialize + const user = accounts[0] + const owner = accounts[9] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + const rewardableValidators = await RewardableValidators.new() + const homeBridge = await HomeBridge.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + const feeManager = await FeeManagerNativeToErcBothDirections.new() + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const initialValue = halfEther + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + + const rewardAddressBalanceBefore = toBN(await web3.eth.getBalance(rewards[0])) + + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + feeInWei, + feeInWei + ).should.be.fulfilled + + await homeBridge.sendTransaction({ + from: user, + value: initialValue + }).should.be.fulfilled + + // When + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(user, value, transactionHash, homeBridge.address) + const signature = await sign(validators[0], message) + const { logs } = await homeBridge.submitSignature(signature, message, { from: validators[0] }).should.be.fulfilled + + // Then + logs.length.should.be.equal(3) + logs[1].event.should.be.equal('CollectedSignatures') + expectEventInLogs(logs, 'FeeDistributedFromSignatures', { + feeAmount, + transactionHash + }) + + const bridgeBalance = toBN(await web3.eth.getBalance(homeBridge.address)) + bridgeBalance.should.be.bignumber.equal(value) + + const rewardAddressBalanceAfter = toBN(await web3.eth.getBalance(rewards[0])) + rewardAddressBalanceAfter.should.be.bignumber.equal(rewardAddressBalanceBefore.add(feeAmount)) + }) + it('should distribute fee to 3 validators', async () => { + // Initialize + const user = accounts[0] + const owner = accounts[9] + const validators = [accounts[1], accounts[2], accounts[3]] + const rewards = [accounts[4], accounts[5], accounts[6]] + const requiredSignatures = 3 + const rewardableValidators = await RewardableValidators.new() + const homeBridge = await HomeBridge.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + const feeManager = await FeeManagerNativeToErcBothDirections.new() + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feePerValidator = toBN(166666666666666) + const feePerValidatorPlusDiff = toBN(166666666666668) + const initialValue = halfEther + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + feeInWei, + feeInWei + ).should.be.fulfilled + + await homeBridge.sendTransaction({ + from: user, + value: initialValue + }).should.be.fulfilled + + const initialBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const initialBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const initialBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + + // When + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(user, value, transactionHash, homeBridge.address) + const signature = await sign(validators[0], message) + const signature2 = await sign(validators[1], message) + const signature3 = await sign(validators[2], message) + + await homeBridge.submitSignature(signature, message, { from: validators[0] }).should.be.fulfilled + await homeBridge.submitSignature(signature2, message, { from: validators[1] }).should.be.fulfilled + const { logs } = await homeBridge.submitSignature(signature3, message, { + from: validators[2] + }).should.be.fulfilled + + // Then + logs.length.should.be.equal(3) + logs[1].event.should.be.equal('CollectedSignatures') + expectEventInLogs(logs, 'FeeDistributedFromSignatures', { + feeAmount, + transactionHash + }) + + const updatedBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const updatedBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const updatedBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + + expect( + updatedBalanceRewardAddress1.eq(initialBalanceRewardAddress1.add(feePerValidator)) || + updatedBalanceRewardAddress1.eq(initialBalanceRewardAddress1.add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + updatedBalanceRewardAddress2.eq(initialBalanceRewardAddress2.add(feePerValidator)) || + updatedBalanceRewardAddress2.eq(initialBalanceRewardAddress2.add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + updatedBalanceRewardAddress3.eq(initialBalanceRewardAddress3.add(feePerValidator)) || + updatedBalanceRewardAddress3.eq(initialBalanceRewardAddress3.add(feePerValidatorPlusDiff)) + ).to.equal(true) + }) + it('should distribute fee to 5 validators', async () => { + // Initialize + const user = accounts[0] + const owner = accounts[9] + const validators = [accounts[0], accounts[1], accounts[2], accounts[3], accounts[4]] + const rewards = [accounts[5], accounts[6], accounts[7], accounts[8], accounts[9]] + const requiredSignatures = 5 + const rewardableValidators = await RewardableValidators.new() + const homeBridge = await HomeBridge.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + const feeManager = await FeeManagerNativeToErcBothDirections.new() + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const initialValue = halfEther + const valueCalc = 0.5 * (1 - fee) + const value = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const feePerValidator = feeAmount.div(toBN(5)) + + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + feeInWei, + feeInWei + ).should.be.fulfilled + + await homeBridge.sendTransaction({ + from: user, + value: initialValue + }).should.be.fulfilled + + const initialBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const initialBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const initialBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + const initialBalanceRewardAddress4 = toBN(await web3.eth.getBalance(rewards[3])) + const initialBalanceRewardAddress5 = toBN(await web3.eth.getBalance(rewards[4])) + + // When + const transactionHash = '0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80' + const message = createMessage(user, value, transactionHash, homeBridge.address) + const signature = await sign(validators[0], message) + const signature2 = await sign(validators[1], message) + const signature3 = await sign(validators[2], message) + const signature4 = await sign(validators[3], message) + const signature5 = await sign(validators[4], message) + + await homeBridge.submitSignature(signature, message, { from: validators[0] }).should.be.fulfilled + await homeBridge.submitSignature(signature2, message, { from: validators[1] }).should.be.fulfilled + await homeBridge.submitSignature(signature3, message, { from: validators[2] }).should.be.fulfilled + await homeBridge.submitSignature(signature4, message, { from: validators[3] }).should.be.fulfilled + const { logs } = await homeBridge.submitSignature(signature5, message, { + from: validators[4] + }).should.be.fulfilled + + // Then + logs.length.should.be.equal(3) + logs[1].event.should.be.equal('CollectedSignatures') + expectEventInLogs(logs, 'FeeDistributedFromSignatures', { + feeAmount, + transactionHash + }) + + const updatedBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const updatedBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const updatedBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + const updatedBalanceRewardAddress4 = toBN(await web3.eth.getBalance(rewards[3])) + const updatedBalanceRewardAddress5 = toBN(await web3.eth.getBalance(rewards[4])) + + updatedBalanceRewardAddress1.should.be.bignumber.equal(initialBalanceRewardAddress1.add(feePerValidator)) + updatedBalanceRewardAddress2.should.be.bignumber.equal(initialBalanceRewardAddress2.add(feePerValidator)) + updatedBalanceRewardAddress3.should.be.bignumber.equal(initialBalanceRewardAddress3.add(feePerValidator)) + updatedBalanceRewardAddress4.should.be.bignumber.equal(initialBalanceRewardAddress4.add(feePerValidator)) + updatedBalanceRewardAddress5.should.be.bignumber.equal(initialBalanceRewardAddress5.add(feePerValidator)) + }) + }) + + describe('#feeManager_BothDirections_ExecuteAffirmation', async () => { + it('should distribute fee to validator', async () => { + // Initialize + const owner = accounts[9] + const validators = [accounts[1]] + const rewards = [accounts[2]] + const requiredSignatures = 1 + const rewardableValidators = await RewardableValidators.new() + const homeBridge = await HomeBridge.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + const feeManager = await FeeManagerNativeToErcBothDirections.new() + + // Given + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const value = halfEther + const valueCalc = 0.5 * (1 - fee) + const finalUserValue = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + feeInWei, + feeInWei + ).should.be.fulfilled + await homeBridge.sendTransaction({ + from: accounts[0], + value: halfEther + }).should.be.fulfilled + + const recipient = accounts[5] + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + const rewardAddressBalanceBefore = toBN(await web3.eth.getBalance(rewards[0])) + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + // When + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[0] + }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: validators[0], + transactionHash + }) + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) + const rewardAddressBalanceAfter = toBN(await web3.eth.getBalance(rewards[0])) + + rewardAddressBalanceAfter.should.be.bignumber.equal(rewardAddressBalanceBefore.add(feeAmount)) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(finalUserValue)) + }) + it('should distribute fee to 3 validators', async () => { + // Given + const owner = accounts[9] + const validators = [accounts[1], accounts[2], accounts[3]] + const rewards = [accounts[4], accounts[5], accounts[6]] + const requiredSignatures = 2 + const rewardableValidators = await RewardableValidators.new() + + const value = halfEther + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feePerValidator = toBN(166666666666666) + const feePerValidatorPlusDiff = toBN(166666666666668) + const valueCalc = 0.5 * (1 - fee) + const finalUserValue = ether(valueCalc.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + + const homeBridge = await HomeBridge.new() + const feeManager = await FeeManagerNativeToErcBothDirections.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + feeInWei, + feeInWei + ).should.be.fulfilled + await homeBridge.sendTransaction({ + from: accounts[0], + value: halfEther + }).should.be.fulfilled + + const recipient = accounts[8] + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + + const initialBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const initialBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const initialBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + // When + const { logs: logsValidator1 } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[0] + }).should.be.fulfilled + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[1] + }).should.be.fulfilled + + // Then + logsValidator1.length.should.be.equals(1) + + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: validators[1], + transactionHash + }) + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(finalUserValue)) + + const updatedBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const updatedBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const updatedBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + + expect( + updatedBalanceRewardAddress1.eq(initialBalanceRewardAddress1.add(feePerValidator)) || + updatedBalanceRewardAddress1.eq(initialBalanceRewardAddress1.add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + updatedBalanceRewardAddress2.eq(initialBalanceRewardAddress2.add(feePerValidator)) || + updatedBalanceRewardAddress2.eq(initialBalanceRewardAddress2.add(feePerValidatorPlusDiff)) + ).to.equal(true) + expect( + updatedBalanceRewardAddress3.eq(initialBalanceRewardAddress3.add(feePerValidator)) || + updatedBalanceRewardAddress3.eq(initialBalanceRewardAddress3.add(feePerValidatorPlusDiff)) + ).to.equal(true) + + const homeBridgeBalance = toBN(await web3.eth.getBalance(homeBridge.address)) + homeBridgeBalance.should.be.bignumber.equal('0') + }) + it('should distribute fee to 5 validators', async () => { + // Given + const owner = accounts[0] + const validators = [accounts[0], accounts[1], accounts[2], accounts[3], accounts[4]] + const rewards = [accounts[5], accounts[6], accounts[7], accounts[8], accounts[9]] + const requiredSignatures = 5 + + const value = halfEther + // 0.1% fee + const fee = 0.001 + const feeInWei = ether(fee.toString()) + const feeAmountCalc = 0.5 * fee + const feeAmount = ether(feeAmountCalc.toString()) + const feePerValidator = feeAmount.div(toBN(5)) + + const rewardableValidators = await RewardableValidators.new() + const homeBridge = await HomeBridge.new() + const feeManager = await FeeManagerNativeToErcBothDirections.new() + await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + await homeBridge.rewardableInitialize( + rewardableValidators.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + foreignDailyLimit, + foreignMaxPerTx, + owner, + feeManager.address, + feeInWei, + feeInWei + ).should.be.fulfilled + await homeBridge.sendTransaction({ + from: accounts[0], + value: halfEther + }).should.be.fulfilled + + const recipient = '0xf4BEF13F9f4f2B203FAF0C3cBbaAbe1afE056955' + const balanceBefore = toBN(await web3.eth.getBalance(recipient)) + + const initialBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const initialBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const initialBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + const initialBalanceRewardAddress4 = toBN(await web3.eth.getBalance(rewards[3])) + const initialBalanceRewardAddress5 = toBN(await web3.eth.getBalance(rewards[4])) + + const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415' + + // When + const { logs: logsValidator1 } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[0] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[1] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[2] + }).should.be.fulfilled + await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[3] + }).should.be.fulfilled + const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, { + from: validators[4] + }).should.be.fulfilled + + // Then + logsValidator1.length.should.be.equals(1) + + expectEventInLogs(logs, 'SignedForAffirmation', { + signer: validators[4], + transactionHash + }) + expectEventInLogs(logs, 'FeeDistributedFromAffirmation', { + feeAmount, + transactionHash + }) + expectEventInLogs(logs, 'AffirmationCompleted', { + recipient, + value, + transactionHash + }) + + const balanceAfter = toBN(await web3.eth.getBalance(recipient)) + balanceAfter.should.be.bignumber.equal(balanceBefore.add(value.sub(feeAmount))) + + const updatedBalanceRewardAddress1 = toBN(await web3.eth.getBalance(rewards[0])) + const updatedBalanceRewardAddress2 = toBN(await web3.eth.getBalance(rewards[1])) + const updatedBalanceRewardAddress3 = toBN(await web3.eth.getBalance(rewards[2])) + const updatedBalanceRewardAddress4 = toBN(await web3.eth.getBalance(rewards[3])) + const updatedBalanceRewardAddress5 = toBN(await web3.eth.getBalance(rewards[4])) + + updatedBalanceRewardAddress1.should.be.bignumber.equal(initialBalanceRewardAddress1.add(feePerValidator)) + updatedBalanceRewardAddress2.should.be.bignumber.equal(initialBalanceRewardAddress2.add(feePerValidator)) + updatedBalanceRewardAddress3.should.be.bignumber.equal(initialBalanceRewardAddress3.add(feePerValidator)) + updatedBalanceRewardAddress4.should.be.bignumber.equal(initialBalanceRewardAddress4.add(feePerValidator)) + updatedBalanceRewardAddress5.should.be.bignumber.equal(initialBalanceRewardAddress5.add(feePerValidator)) }) }) }) diff --git a/test/poa20_test.js b/test/poa20_test.js index 4e9ed8b77..55e1d33d4 100644 --- a/test/poa20_test.js +++ b/test/poa20_test.js @@ -1,87 +1,238 @@ -const POA20 = artifacts.require("ERC677BridgeToken.sol"); -const ERC677ReceiverTest = artifacts.require("ERC677ReceiverTest.sol") -const { ERROR_MSG, ZERO_ADDRESS} = require('./setup'); -const Web3Utils = require('web3-utils'); -const HomeErcToErcBridge = artifacts.require("HomeBridgeErcToErc.sol"); -const ForeignNativeToErcBridge = artifacts.require("ForeignBridgeNativeToErc.sol"); -const BridgeValidators = artifacts.require("BridgeValidators.sol"); -const minPerTx = web3.toBigNumber(web3.toWei(0.01, "ether")); -const requireBlockConfirmations = 8; -const gasPrice = Web3Utils.toWei('1', 'gwei'); -const oneEther = web3.toBigNumber(web3.toWei(1, "ether")); -const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether")); +const POA20 = artifacts.require('ERC677BridgeToken.sol') +const POA20RewardableMock = artifacts.require('./mockContracts/ERC677BridgeTokenRewardableMock') +const ERC677ReceiverTest = artifacts.require('ERC677ReceiverTest.sol') +const BlockRewardTest = artifacts.require('BlockReward.sol') +const StakingTest = artifacts.require('Staking.sol') +const HomeErcToErcBridge = artifacts.require('HomeBridgeErcToErc.sol') +const ForeignNativeToErcBridge = artifacts.require('ForeignBridgeNativeToErc.sol') +const BridgeValidators = artifacts.require('BridgeValidators.sol') + +const { expect } = require('chai') +const { ERROR_MSG, ZERO_ADDRESS, BN } = require('./setup') +const { ether, expectEventInLogs } = require('./helpers/helpers') + +const minPerTx = ether('0.01') +const requireBlockConfirmations = 8 +const gasPrice = web3.utils.toWei('1', 'gwei') +const oneEther = ether('1') +const halfEther = ether('0.5') const executionDailyLimit = oneEther const executionMaxPerTx = halfEther +const ZERO = new BN(0) -contract('ERC677BridgeToken', async (accounts) => { +async function testERC677BridgeToken(accounts, rewardable) { let token - let owner = accounts[0] - const user = accounts[1]; + const owner = accounts[0] + const user = accounts[1] + const tokenContract = rewardable ? POA20RewardableMock : POA20 beforeEach(async () => { - token = await POA20.new("POA ERC20 Foundation", "POA20", 18); + token = await tokenContract.new('POA ERC20 Foundation', 'POA20', 18) }) it('default values', async () => { + expect(await token.symbol()).to.be.equal('POA20') + expect(await token.decimals()).to.be.bignumber.equal('18') + expect(await token.name()).to.be.equal('POA ERC20 Foundation') + expect(await token.totalSupply()).to.be.bignumber.equal(ZERO) + expect(await token.mintingFinished()).to.be.equal(false) + + const { major, minor, patch } = await token.getTokenInterfacesVersion() + expect(major).to.be.bignumber.gte(ZERO) + expect(minor).to.be.bignumber.gte(ZERO) + expect(patch).to.be.bignumber.gte(ZERO) + }) - const symbol = await token.symbol() - assert.equal(symbol, 'POA20') + describe('#bridgeContract', async () => { + it('can set bridge contract', async () => { + const homeErcToErcContract = await HomeErcToErcBridge.new() + ;(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS) - const decimals = await token.decimals() - assert.equal(decimals, 18) + await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled + ;(await token.bridgeContract()).should.be.equal(homeErcToErcContract.address) + }) - const name = await token.name() - assert.equal(name, "POA ERC20 Foundation") + it('only owner can set bridge contract', async () => { + const homeErcToErcContract = await HomeErcToErcBridge.new() + ;(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS) - const totalSupply = await token.totalSupply(); - assert.equal(totalSupply, 0); + await token.setBridgeContract(homeErcToErcContract.address, { from: user }).should.be.rejectedWith(ERROR_MSG) + ;(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS) - const mintingFinished = await token.mintingFinished(); - assert.equal(mintingFinished, false); + await token.setBridgeContract(homeErcToErcContract.address, { from: owner }).should.be.fulfilled + ;(await token.bridgeContract()).should.be.equal(homeErcToErcContract.address) + }) + + it('fail to set invalid bridge contract address', async () => { + const invalidContractAddress = '0xaaB52d66283F7A1D5978bcFcB55721ACB467384b' + ;(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS) - const [major, minor, patch] = await token.getTokenInterfacesVersion() - major.should.be.bignumber.gte(0) - minor.should.be.bignumber.gte(0) - patch.should.be.bignumber.gte(0) + await token.setBridgeContract(invalidContractAddress).should.be.rejectedWith(ERROR_MSG) + ;(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS) + + await token.setBridgeContract(ZERO_ADDRESS).should.be.rejectedWith(ERROR_MSG) + ;(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS) + }) }) - describe('#bridgeContract', async() => { - it('can set bridge contract', async () => { - const homeErcToErcContract = await HomeErcToErcBridge.new(); - (await token.bridgeContract()).should.be.equal(ZERO_ADDRESS); + if (rewardable) { + describe('#blockRewardContract', async () => { + it('can set BlockReward contract', async () => { + const blockRewardContract = await BlockRewardTest.new() + ;(await token.blockRewardContract()).should.be.equal(ZERO_ADDRESS) + + await token.setBlockRewardContract(blockRewardContract.address).should.be.fulfilled + ;(await token.blockRewardContract()).should.be.equal(blockRewardContract.address) + }) + + it('only owner can set BlockReward contract', async () => { + const blockRewardContract = await BlockRewardTest.new() + ;(await token.blockRewardContract()).should.be.equal(ZERO_ADDRESS) - await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled; + await token + .setBlockRewardContract(blockRewardContract.address, { from: user }) + .should.be.rejectedWith(ERROR_MSG) + ;(await token.blockRewardContract()).should.be.equal(ZERO_ADDRESS) - (await token.bridgeContract()).should.be.equal(homeErcToErcContract.address); + await token.setBlockRewardContract(blockRewardContract.address, { from: owner }).should.be.fulfilled + ;(await token.blockRewardContract()).should.be.equal(blockRewardContract.address) + }) + + it('fail to set invalid BlockReward contract address', async () => { + const invalidContractAddress = '0xaaB52d66283F7A1D5978bcFcB55721ACB467384b' + ;(await token.blockRewardContract()).should.be.equal(ZERO_ADDRESS) + + await token.setBlockRewardContract(invalidContractAddress).should.be.rejectedWith(ERROR_MSG) + ;(await token.blockRewardContract()).should.be.equal(ZERO_ADDRESS) + + await token.setBlockRewardContract(ZERO_ADDRESS).should.be.rejectedWith(ERROR_MSG) + ;(await token.blockRewardContract()).should.be.equal(ZERO_ADDRESS) + }) }) - it('only owner can set bridge contract', async () => { - const homeErcToErcContract = await HomeErcToErcBridge.new(); - (await token.bridgeContract()).should.be.equal(ZERO_ADDRESS); + describe('#stakingContract', async () => { + it('can set Staking contract', async () => { + const stakingContract = await StakingTest.new() + ;(await token.stakingContract()).should.be.equal(ZERO_ADDRESS) + + await token.setStakingContract(stakingContract.address).should.be.fulfilled + ;(await token.stakingContract()).should.be.equal(stakingContract.address) + }) + + it('only owner can set Staking contract', async () => { + const stakingContract = await StakingTest.new() + ;(await token.stakingContract()).should.be.equal(ZERO_ADDRESS) + + await token.setStakingContract(stakingContract.address, { from: user }).should.be.rejectedWith(ERROR_MSG) + ;(await token.stakingContract()).should.be.equal(ZERO_ADDRESS) + + await token.setStakingContract(stakingContract.address, { from: owner }).should.be.fulfilled + ;(await token.stakingContract()).should.be.equal(stakingContract.address) + }) + + it('fail to set invalid Staking contract address', async () => { + const invalidContractAddress = '0xaaB52d66283F7A1D5978bcFcB55721ACB467384b' + ;(await token.stakingContract()).should.be.equal(ZERO_ADDRESS) - await token.setBridgeContract(homeErcToErcContract.address, {from: user }).should.be.rejectedWith(ERROR_MSG); - (await token.bridgeContract()).should.be.equal(ZERO_ADDRESS); + await token.setStakingContract(invalidContractAddress).should.be.rejectedWith(ERROR_MSG) + ;(await token.stakingContract()).should.be.equal(ZERO_ADDRESS) - await token.setBridgeContract(homeErcToErcContract.address, {from: owner }).should.be.fulfilled; - (await token.bridgeContract()).should.be.equal(homeErcToErcContract.address); + await token.setStakingContract(ZERO_ADDRESS).should.be.rejectedWith(ERROR_MSG) + ;(await token.stakingContract()).should.be.equal(ZERO_ADDRESS) + }) }) - it('fail to set invalid bridge contract address', async () => { - const invalidContractAddress = '0xaaB52d66283F7A1D5978bcFcB55721ACB467384b'; - (await token.bridgeContract()).should.be.equal(ZERO_ADDRESS); + describe('#mintReward', async () => { + it('can only be called by BlockReward contract', async () => { + await token.setBlockRewardContractMock(accounts[2]).should.be.fulfilled + await token.mintReward([], [], { from: user }).should.be.rejectedWith(ERROR_MSG) + await token.mintReward([], [], { from: accounts[2] }).should.be.fulfilled + }) + it('should increase totalSupply and balances', async () => { + const user1 = accounts[1] + const user2 = accounts[2] + const user3 = accounts[3] + + expect(await token.totalSupply()).to.be.bignumber.equal(ZERO) + expect(await token.balanceOf(user1)).to.be.bignumber.equal(ZERO) + expect(await token.balanceOf(user2)).to.be.bignumber.equal(ZERO) + expect(await token.balanceOf(user3)).to.be.bignumber.equal(ZERO) + + await token.setBlockRewardContractMock(accounts[4]).should.be.fulfilled + await token.mintReward([user1, user2, user3], [100, 200, 300], { from: accounts[4] }).should.be.fulfilled + + expect(await token.totalSupply()).to.be.bignumber.equal('600') + expect(await token.balanceOf(user1)).to.be.bignumber.equal('100') + expect(await token.balanceOf(user2)).to.be.bignumber.equal('200') + expect(await token.balanceOf(user3)).to.be.bignumber.equal('300') + }) + }) - await token.setBridgeContract(invalidContractAddress).should.be.rejectedWith(ERROR_MSG); - (await token.bridgeContract()).should.be.equal(ZERO_ADDRESS); + describe('#stake', async () => { + it('can only be called by Staking contract', async () => { + await token.setBlockRewardContractMock(accounts[2]).should.be.fulfilled + await token.mintReward([user], ['100'], { from: accounts[2] }).should.be.fulfilled + await token.setStakingContractMock(accounts[3]).should.be.fulfilled + await token.stake(user, '100', { from: accounts[4] }).should.be.rejectedWith(ERROR_MSG) + await token.stake(user, '100', { from: accounts[3] }).should.be.fulfilled + }) + it("should revert if user doesn't have enough balance", async () => { + await token.setBlockRewardContractMock(accounts[2]).should.be.fulfilled + await token.mintReward([user], ['99'], { from: accounts[2] }).should.be.fulfilled + expect(await token.balanceOf(user)).to.be.bignumber.equal('99') + await token.setStakingContractMock(accounts[3]).should.be.fulfilled + await token.stake(user, '100', { from: accounts[3] }).should.be.rejectedWith(ERROR_MSG) + }) + it("should decrease user's balance and increase Staking's balance", async () => { + await token.setBlockRewardContractMock(accounts[2]).should.be.fulfilled + await token.mintReward([user], ['100'], { from: accounts[2] }).should.be.fulfilled + expect(await token.balanceOf(user)).to.be.bignumber.equal('100') + expect(await token.balanceOf(accounts[3])).to.be.bignumber.equal(ZERO) + await token.setStakingContractMock(accounts[3]).should.be.fulfilled + await token.stake(user, '100', { from: accounts[3] }).should.be.fulfilled + expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO) + expect(await token.balanceOf(accounts[3])).to.be.bignumber.equal('100') + }) + }) - await token.setBridgeContract(ZERO_ADDRESS).should.be.rejectedWith(ERROR_MSG); - (await token.bridgeContract()).should.be.equal(ZERO_ADDRESS); + describe('#withdraw', async () => { + it('can only be called by Staking contract', async () => { + await token.setBlockRewardContractMock(accounts[2]).should.be.fulfilled + await token.mintReward([user], ['100'], { from: accounts[2] }).should.be.fulfilled + await token.setStakingContractMock(accounts[3]).should.be.fulfilled + await token.stake(user, '100', { from: accounts[3] }).should.be.fulfilled + await token.withdraw(user, '100', { from: accounts[4] }).should.be.rejectedWith(ERROR_MSG) + await token.withdraw(user, '100', { from: accounts[3] }).should.be.fulfilled + }) + it("should revert if Staking doesn't have enough balance", async () => { + await token.setBlockRewardContractMock(accounts[2]).should.be.fulfilled + await token.mintReward([user], ['100'], { from: accounts[2] }).should.be.fulfilled + expect(await token.balanceOf(user)).to.be.bignumber.equal('100') + await token.setStakingContractMock(accounts[3]).should.be.fulfilled + await token.stake(user, '100', { from: accounts[3] }).should.be.fulfilled + await token.withdraw(user, '101', { from: accounts[3] }).should.be.rejectedWith(ERROR_MSG) + await token.withdraw(user, '100', { from: accounts[3] }).should.be.fulfilled + }) + it("should decrease Staking's balance and increase user's balance", async () => { + await token.setBlockRewardContractMock(accounts[2]).should.be.fulfilled + await token.mintReward([user], ['100'], { from: accounts[2] }).should.be.fulfilled + expect(await token.balanceOf(user)).to.be.bignumber.equal('100') + expect(await token.balanceOf(accounts[3])).to.be.bignumber.equal(ZERO) + await token.setStakingContractMock(accounts[3]).should.be.fulfilled + await token.stake(user, '100', { from: accounts[3] }).should.be.fulfilled + expect(await token.balanceOf(user)).to.be.bignumber.equal('0') + expect(await token.balanceOf(accounts[3])).to.be.bignumber.equal('100') + await token.withdraw(user, 60, { from: accounts[3] }).should.be.fulfilled + expect(await token.balanceOf(user)).to.be.bignumber.equal('60') + expect(await token.balanceOf(accounts[3])).to.be.bignumber.equal('40') + }) }) - }) + } - describe('#mint', async() => { + describe('#mint', async () => { it('can mint by owner', async () => { - (await token.totalSupply()).should.be.bignumber.equal(0); - await token.mint(user, 1, {from: owner }).should.be.fulfilled; - (await token.totalSupply()).should.be.bignumber.equal(1); - (await token.balanceOf(user)).should.be.bignumber.equal(1); + expect(await token.totalSupply()).to.be.bignumber.equal(ZERO) + await token.mint(user, 1, { from: owner }).should.be.fulfilled + expect(await token.totalSupply()).to.be.bignumber.equal('1') + expect(await token.balanceOf(user)).to.be.bignumber.equal('1') }) it('no one can call finishMinting', async () => { @@ -89,54 +240,77 @@ contract('ERC677BridgeToken', async (accounts) => { }) it('cannot mint by non-owner', async () => { - (await token.totalSupply()).should.be.bignumber.equal(0); - await token.mint(user, 1, {from: user }).should.be.rejectedWith(ERROR_MSG); - (await token.totalSupply()).should.be.bignumber.equal(0); - (await token.balanceOf(user)).should.be.bignumber.equal(0); + expect(await token.totalSupply()).to.be.bignumber.equal(ZERO) + await token.mint(user, 1, { from: user }).should.be.rejectedWith(ERROR_MSG) + expect(await token.totalSupply()).to.be.bignumber.equal(ZERO) + expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO) }) }) - describe('#transfer', async() => { - let homeErcToErcContract, foreignNativeToErcBridge, validatorContract + describe('#transfer', async () => { + let homeErcToErcContract + let foreignNativeToErcBridge + let validatorContract beforeEach(async () => { validatorContract = await BridgeValidators.new() - const authorities = [accounts[2]]; + const authorities = [accounts[2]] await validatorContract.initialize(1, authorities, owner) homeErcToErcContract = await HomeErcToErcBridge.new() - await homeErcToErcContract.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, token.address, executionDailyLimit, executionMaxPerTx, owner) + await homeErcToErcContract.initialize( + validatorContract.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + executionDailyLimit, + executionMaxPerTx, + owner + ) foreignNativeToErcBridge = await ForeignNativeToErcBridge.new() - await foreignNativeToErcBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, executionDailyLimit, executionMaxPerTx, owner); + await foreignNativeToErcBridge.initialize( + validatorContract.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + executionDailyLimit, + executionMaxPerTx, + owner + ) }) it('sends tokens to recipient', async () => { - await token.mint(user, 1, {from: owner }).should.be.fulfilled; - await token.transfer(user, 1, {from: owner}).should.be.rejectedWith(ERROR_MSG); - const {logs} = await token.transfer(owner, 1, {from: user}).should.be.fulfilled; - (await token.balanceOf(owner)).should.be.bignumber.equal(1); - (await token.balanceOf(user)).should.be.bignumber.equal(0); - logs[0].event.should.be.equal("Transfer") - logs[0].args.should.be.deep.equal({ + await token.mint(user, '1', { from: owner }).should.be.fulfilled + await token.transfer(user, 1, { from: owner }).should.be.rejectedWith(ERROR_MSG) + const { logs } = await token.transfer(owner, 1, { from: user }).should.be.fulfilled + expect(await token.balanceOf(owner)).to.be.bignumber.equal('1') + expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO) + expectEventInLogs(logs, 'Transfer', { from: user, to: owner, - value: new web3.BigNumber(1) + value: new BN(1) }) }) it('sends tokens to bridge contract', async () => { - await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled; - await token.mint(user, web3.toWei(1, "ether"), {from: owner }).should.be.fulfilled; + await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled + await token.mint(user, oneEther, { from: owner }).should.be.fulfilled - const result = await token.transfer(homeErcToErcContract.address, minPerTx, {from: user}).should.be.fulfilled; - result.logs[0].event.should.be.equal("Transfer") - result.logs[0].args.should.be.deep.equal({ + const result = await token.transfer(homeErcToErcContract.address, minPerTx, { from: user }).should.be.fulfilled + expectEventInLogs(result.logs, 'Transfer', { from: user, to: homeErcToErcContract.address, value: minPerTx }) - await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled; - const result2 = await token.transfer(foreignNativeToErcBridge.address, minPerTx, {from: user}).should.be.fulfilled; - result2.logs[0].event.should.be.equal("Transfer") - result2.logs[0].args.should.be.deep.equal({ + await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled + const result2 = await token.transfer(foreignNativeToErcBridge.address, minPerTx, { + from: user + }).should.be.fulfilled + expectEventInLogs(result2.logs, 'Transfer', { from: user, to: foreignNativeToErcBridge.address, value: minPerTx @@ -144,18 +318,16 @@ contract('ERC677BridgeToken', async (accounts) => { }) it('sends tokens to contract that does not contains onTokenTransfer method', async () => { - await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled; - await token.mint(user, web3.toWei(1, "ether"), {from: owner }).should.be.fulfilled; + await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled + await token.mint(user, oneEther, { from: owner }).should.be.fulfilled - const result = await token.transfer(validatorContract.address, minPerTx, {from: user}).should.be.fulfilled; - result.logs[0].event.should.be.equal("Transfer") - result.logs[0].args.should.be.deep.equal({ + const result = await token.transfer(validatorContract.address, minPerTx, { from: user }).should.be.fulfilled + expectEventInLogs(result.logs, 'Transfer', { from: user, to: validatorContract.address, value: minPerTx }) - result.logs[1].event.should.be.equal("ContractFallbackCallFailed") - result.logs[1].args.should.be.deep.equal({ + expectEventInLogs(result.logs, 'ContractFallbackCallFailed', { from: user, to: validatorContract.address, value: minPerTx @@ -163,77 +335,135 @@ contract('ERC677BridgeToken', async (accounts) => { }) it('fail to send tokens to bridge contract out of limits', async () => { - const lessThanMin = web3.toBigNumber(web3.toWei(0.0001, "ether")) - await token.mint(user, web3.toWei(1, "ether"), {from: owner }).should.be.fulfilled; + const lessThanMin = ether('0.0001') + await token.mint(user, oneEther, { from: owner }).should.be.fulfilled - await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled; - await token.transfer(homeErcToErcContract.address, lessThanMin, {from: user}).should.be.rejectedWith(ERROR_MSG); + await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled + await token.transfer(homeErcToErcContract.address, lessThanMin, { from: user }).should.be.rejectedWith(ERROR_MSG) - await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled; - await token.transfer(foreignNativeToErcBridge.address, lessThanMin, {from: user}).should.be.rejectedWith(ERROR_MSG); + await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled + await token + .transfer(foreignNativeToErcBridge.address, lessThanMin, { from: user }) + .should.be.rejectedWith(ERROR_MSG) }) + + if (rewardable) { + it('fail to send tokens to Staking contract directly', async () => { + const amount = ether('1') + const stakingContractAddress = accounts[2] + const arbitraryAccountAddress = accounts[3] + await token.setStakingContractMock(stakingContractAddress, { from: owner }).should.be.fulfilled + await token.mint(user, amount, { from: owner }).should.be.fulfilled + await token.transfer(stakingContractAddress, amount, { from: user }).should.be.rejectedWith(ERROR_MSG) + await token.transfer(arbitraryAccountAddress, amount, { from: user }).should.be.fulfilled + }) + } }) - describe("#burn", async () => { - it('can burn', async() => { - await token.burn(100, {from: owner}).should.be.rejectedWith(ERROR_MSG); - await token.mint(user, 1, {from: owner }).should.be.fulfilled; - await token.burn(1, {from: user}).should.be.fulfilled; - (await token.totalSupply()).should.be.bignumber.equal(0); - (await token.balanceOf(user)).should.be.bignumber.equal(0); + if (rewardable) { + describe('#transferFrom', async () => { + it('fail to send tokens to Staking contract directly', async () => { + const amount = ether('1') + const user2 = accounts[2] + const stakingContractAddress = accounts[3] + const arbitraryAccountAddress = accounts[4] + await token.setStakingContractMock(stakingContractAddress, { from: owner }).should.be.fulfilled + await token.mint(user, amount, { from: owner }).should.be.fulfilled + await token.approve(user2, amount, { from: user }).should.be.fulfilled + await token + .transferFrom(user, stakingContractAddress, amount, { from: user2 }) + .should.be.rejectedWith(ERROR_MSG) + await token.transferFrom(user, arbitraryAccountAddress, amount, { from: user2 }).should.be.fulfilled + }) + }) + } + + describe('#burn', async () => { + it('can burn', async () => { + await token.burn(100, { from: owner }).should.be.rejectedWith(ERROR_MSG) + await token.mint(user, 1, { from: owner }).should.be.fulfilled + await token.burn(1, { from: user }).should.be.fulfilled + expect(await token.totalSupply()).to.be.bignumber.equal(ZERO) + expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO) }) }) describe('#transferAndCall', () => { - let homeErcToErcContract, foreignNativeToErcBridge, validatorContract + let homeErcToErcContract + let foreignNativeToErcBridge + let validatorContract beforeEach(async () => { validatorContract = await BridgeValidators.new() - const authorities = [accounts[2]]; + const authorities = [accounts[2]] await validatorContract.initialize(1, authorities, owner) homeErcToErcContract = await HomeErcToErcBridge.new() - await homeErcToErcContract.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, token.address, executionDailyLimit, executionMaxPerTx, owner) + await homeErcToErcContract.initialize( + validatorContract.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + token.address, + executionDailyLimit, + executionMaxPerTx, + owner + ) foreignNativeToErcBridge = await ForeignNativeToErcBridge.new() - await foreignNativeToErcBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, executionDailyLimit, executionMaxPerTx, owner); + await foreignNativeToErcBridge.initialize( + validatorContract.address, + token.address, + oneEther, + halfEther, + minPerTx, + gasPrice, + requireBlockConfirmations, + executionDailyLimit, + executionMaxPerTx, + owner + ) }) it('calls contractFallback', async () => { - const receiver = await ERC677ReceiverTest.new(); - (await receiver.from()).should.be.equal('0x0000000000000000000000000000000000000000'); - (await receiver.value()).should.be.bignumber.equal('0'); - (await receiver.data()).should.be.equal('0x'); - (await receiver.someVar()).should.be.bignumber.equal('0'); - - var ERC677ReceiverTestWeb3 = web3.eth.contract(ERC677ReceiverTest.abi); - var ERC677ReceiverTestWeb3Instance = ERC677ReceiverTestWeb3.at(receiver.address); - var callDoSomething123 = ERC677ReceiverTestWeb3Instance.doSomething.getData(123); - - await token.mint(user, 1, {from: owner }).should.be.fulfilled; - await token.transferAndCall(token.address, 1, callDoSomething123, {from: user}).should.be.rejectedWith(ERROR_MSG); - await token.transferAndCall('0x0000000000000000000000000000000000000000', 1, callDoSomething123, {from: user}).should.be.rejectedWith(ERROR_MSG); - await token.transferAndCall(receiver.address, 1, callDoSomething123, {from: user}).should.be.fulfilled; - (await token.balanceOf(receiver.address)).should.be.bignumber.equal(1); - (await token.balanceOf(user)).should.be.bignumber.equal(0); - (await receiver.from()).should.be.equal(user); - (await receiver.value()).should.be.bignumber.equal(1); - (await receiver.data()).should.be.equal(callDoSomething123); - (await receiver.someVar()).should.be.bignumber.equal('123'); + const receiver = await ERC677ReceiverTest.new() + expect(await receiver.from()).to.be.equal(ZERO_ADDRESS) + expect(await receiver.value()).to.be.bignumber.equal(ZERO) + expect(await receiver.data()).to.be.equal(null) + expect(await receiver.someVar()).to.be.bignumber.equal(ZERO) + + const callDoSomething123 = receiver.contract.methods.doSomething(123).encodeABI() + await token.mint(user, '1', { from: owner }).should.be.fulfilled + await token + .transferAndCall(token.address, '1', callDoSomething123, { from: user }) + .should.be.rejectedWith(ERROR_MSG) + await token + .transferAndCall(ZERO_ADDRESS, '1', callDoSomething123, { from: user }) + .should.be.rejectedWith(ERROR_MSG) + await token.transferAndCall(receiver.address, '1', callDoSomething123, { from: user }).should.be.fulfilled + expect(await token.balanceOf(receiver.address)).to.be.bignumber.equal('1') + expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO) + expect(await receiver.from()).to.be.equal(user) + expect(await receiver.value()).to.be.bignumber.equal('1') + expect(await receiver.data()).to.be.equal(callDoSomething123) + expect(await receiver.someVar()).to.be.bignumber.equal('123') }) it('sends tokens to bridge contract', async () => { - await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled; - await token.mint(user, web3.toWei(1, "ether"), {from: owner }).should.be.fulfilled; + await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled + await token.mint(user, oneEther, { from: owner }).should.be.fulfilled - const result = await token.transferAndCall(homeErcToErcContract.address, minPerTx, '0x', {from: user}).should.be.fulfilled; - result.logs[0].event.should.be.equal("Transfer") - result.logs[0].args.should.be.deep.equal({ + const result = await token.transferAndCall(homeErcToErcContract.address, minPerTx, '0x', { + from: user + }).should.be.fulfilled + expectEventInLogs(result.logs, 'Transfer', { from: user, to: homeErcToErcContract.address, value: minPerTx }) - await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled; - const result2 = await token.transferAndCall(foreignNativeToErcBridge.address, minPerTx, '0x', {from: user}).should.be.fulfilled; - result2.logs[0].event.should.be.equal("Transfer") - result2.logs[0].args.should.be.deep.equal({ + await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled + const result2 = await token.transferAndCall(foreignNativeToErcBridge.address, minPerTx, '0x', { from: user }) + .should.be.fulfilled + expectEventInLogs(result2.logs, 'Transfer', { from: user, to: foreignNativeToErcBridge.address, value: minPerTx @@ -241,69 +471,81 @@ contract('ERC677BridgeToken', async (accounts) => { }) it('fail to sends tokens to contract that does not contains onTokenTransfer method', async () => { - await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled; - await token.mint(user, web3.toWei(1, "ether"), {from: owner }).should.be.fulfilled; + await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled + await token.mint(user, oneEther, { from: owner }).should.be.fulfilled - await token.transferAndCall(validatorContract.address, minPerTx, '0x', {from: user}).should.be.rejectedWith(ERROR_MSG); + await token + .transferAndCall(validatorContract.address, minPerTx, '0x', { from: user }) + .should.be.rejectedWith(ERROR_MSG) }) it('fail to send tokens to bridge contract out of limits', async () => { - const lessThanMin = web3.toBigNumber(web3.toWei(0.0001, "ether")) - await token.mint(user, web3.toWei(1, "ether"), {from: owner }).should.be.fulfilled; - - await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled; - await token.transferAndCall(homeErcToErcContract.address, lessThanMin, '0x', {from: user}).should.be.rejectedWith(ERROR_MSG); - - await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled; - await token.transferAndCall(foreignNativeToErcBridge.address, lessThanMin, '0x', {from: user}).should.be.rejectedWith(ERROR_MSG); + const lessThanMin = ether('0.0001') + await token.mint(user, oneEther, { from: owner }).should.be.fulfilled + + await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled + await token + .transferAndCall(homeErcToErcContract.address, lessThanMin, '0x', { from: user }) + .should.be.rejectedWith(ERROR_MSG) + + await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled + await token + .transferAndCall(foreignNativeToErcBridge.address, lessThanMin, '0x', { from: user }) + .should.be.rejectedWith(ERROR_MSG) }) }) describe('#claimtokens', async () => { - it('can take send ERC20 tokens', async ()=> { - const owner = accounts[0]; - const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether")); - let tokenSecond = await POA20.new("Roman Token", "RST", 18); + it('can take send ERC20 tokens', async () => { + const owner = accounts[0] + const halfEther = ether('0.5') + const tokenSecond = await tokenContract.new('Roman Token', 'RST', 18) - await tokenSecond.mint(accounts[0], halfEther).should.be.fulfilled; + await tokenSecond.mint(accounts[0], halfEther).should.be.fulfilled halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[0])) - await tokenSecond.transfer(token.address, halfEther); - '0'.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[0])) - halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(token.address)) + await tokenSecond.transfer(token.address, halfEther) + expect(await tokenSecond.balanceOf(accounts[0])).to.be.bignumber.equal(ZERO) + expect(await tokenSecond.balanceOf(token.address)).to.be.bignumber.equal(halfEther) - await token.claimTokens(tokenSecond.address, accounts[3], {from: owner}); - '0'.should.be.bignumber.equal(await tokenSecond.balanceOf(token.address)) + await token.claimTokens(tokenSecond.address, accounts[3], { from: owner }) + expect(await tokenSecond.balanceOf(token.address)).to.be.bignumber.equal(ZERO) halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[3])) - }) }) describe('#transfer', async () => { it('if transfer called on contract, onTokenTransfer is also invoked', async () => { - const receiver = await ERC677ReceiverTest.new(); - (await receiver.from()).should.be.equal('0x0000000000000000000000000000000000000000'); - (await receiver.value()).should.be.bignumber.equal('0'); - (await receiver.data()).should.be.equal('0x'); - (await receiver.someVar()).should.be.bignumber.equal('0'); - - await token.mint(user, 1, {from: owner }).should.be.fulfilled; - const {logs} = await token.transfer(receiver.address, 1, {from: user}).should.be.fulfilled; - - (await token.balanceOf(receiver.address)).should.be.bignumber.equal(1); - (await token.balanceOf(user)).should.be.bignumber.equal(0); - (await receiver.from()).should.be.equal(user); - (await receiver.value()).should.be.bignumber.equal(1); - (await receiver.data()).should.be.equal('0x'); - logs[0].event.should.be.equal("Transfer") + const receiver = await ERC677ReceiverTest.new() + expect(await receiver.from()).to.be.equal(ZERO_ADDRESS) + expect(await receiver.value()).to.be.bignumber.equal(ZERO) + expect(await receiver.data()).to.be.equal(null) + expect(await receiver.someVar()).to.be.bignumber.equal(ZERO) + + await token.mint(user, 1, { from: owner }).should.be.fulfilled + const { logs } = await token.transfer(receiver.address, '1', { from: user }).should.be.fulfilled + + expect(await token.balanceOf(receiver.address)).to.be.bignumber.equal('1') + expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO) + expect(await receiver.from()).to.be.equal(user) + expect(await receiver.value()).to.be.bignumber.equal('1') + expect(await receiver.data()).to.be.equal(null) + expect(logs[0].event).to.be.equal('Transfer') }) it('if transfer called on contract, still works even if onTokenTransfer doesnot exist', async () => { - const someContract = await POA20.new("Some", "Token", 18); - await token.mint(user, 2, {from: owner }).should.be.fulfilled; - const tokenTransfer = await token.transfer(someContract.address, 1, {from: user}).should.be.fulfilled; - const tokenTransfer2 = await token.transfer(accounts[0], 1, {from: user}).should.be.fulfilled; - (await token.balanceOf(someContract.address)).should.be.bignumber.equal(1); - (await token.balanceOf(user)).should.be.bignumber.equal(0); - tokenTransfer.logs[0].event.should.be.equal("Transfer") - tokenTransfer2.logs[0].event.should.be.equal("Transfer") - + const someContract = await tokenContract.new('Some', 'Token', 18) + await token.mint(user, '2', { from: owner }).should.be.fulfilled + const tokenTransfer = await token.transfer(someContract.address, '1', { from: user }).should.be.fulfilled + const tokenTransfer2 = await token.transfer(accounts[0], '1', { from: user }).should.be.fulfilled + expect(await token.balanceOf(someContract.address)).to.be.bignumber.equal('1') + expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO) + tokenTransfer.logs[0].event.should.be.equal('Transfer') + tokenTransfer2.logs[0].event.should.be.equal('Transfer') }) }) +} + +contract('ERC677BridgeToken', async accounts => { + await testERC677BridgeToken(accounts, false) +}) + +contract('ERC677BridgeTokenRewardable', async accounts => { + await testERC677BridgeToken(accounts, true) }) diff --git a/test/rewardable_validators_test.js b/test/rewardable_validators_test.js new file mode 100644 index 000000000..2a2055e70 --- /dev/null +++ b/test/rewardable_validators_test.js @@ -0,0 +1,296 @@ +const BridgeValidators = artifacts.require('RewardableValidators.sol') +const EternalStorageProxy = artifacts.require('EternalStorageProxy.sol') + +const { expect } = require('chai') +const { ERROR_MSG, ZERO_ADDRESS, F_ADDRESS, BN } = require('./setup') +const { expectEventInLogs } = require('./helpers/helpers') + +const ZERO = new BN(0) + +contract('RewardableValidators', async accounts => { + let bridgeValidators + const owner = accounts[0] + + beforeEach(async () => { + bridgeValidators = await BridgeValidators.new() + }) + + describe('#initialize', async () => { + it('sets values', async () => { + expect(await bridgeValidators.owner()).to.be.equal(ZERO_ADDRESS) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal(ZERO) + expect(await bridgeValidators.isValidator(accounts[0])).to.be.equal(false) + expect(await bridgeValidators.isValidator(accounts[1])).to.be.equal(false) + expect(await bridgeValidators.isInitialized()).to.be.equal(false) + expect(await bridgeValidators.requiredSignatures()).to.be.bignumber.equal(ZERO) + expect(await bridgeValidators.deployedAtBlock()).to.be.bignumber.equal(ZERO) + + await bridgeValidators + .initialize(3, accounts.slice(0, 3), accounts.slice(3, 5), accounts[2], { + from: accounts[2] + }) + .should.be.rejectedWith(ERROR_MSG) + await bridgeValidators + .initialize(1, [accounts[0]], [ZERO_ADDRESS], accounts[1], { from: accounts[1] }) + .should.be.rejectedWith(ERROR_MSG) + await bridgeValidators + .initialize(1, [ZERO_ADDRESS], [accounts[0]], accounts[1], { from: accounts[1] }) + .should.be.rejectedWith(ERROR_MSG) + await bridgeValidators + .initialize(1, [F_ADDRESS], [accounts[0]], accounts[1], { from: accounts[1] }) + .should.be.rejectedWith(ERROR_MSG) + await bridgeValidators.initialize(2, accounts.slice(0, 2), accounts.slice(2, 4), accounts[2], { + from: accounts[2] + }).should.be.fulfilled + await bridgeValidators + .initialize(2, accounts.slice(0, 2), accounts.slice(2, 4), accounts[2], { + from: accounts[2] + }) + .should.be.rejectedWith(ERROR_MSG) + + expect(await bridgeValidators.isInitialized()).to.be.equal(true) + expect(await bridgeValidators.requiredSignatures()).to.be.bignumber.equal('2') + expect(await bridgeValidators.isValidator(accounts[0])).to.be.equal(true) + expect(await bridgeValidators.isValidator(accounts[1])).to.be.equal(true) + expect(await bridgeValidators.owner()).to.be.equal(accounts[2]) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('2') + expect(await bridgeValidators.deployedAtBlock()).to.be.bignumber.above(ZERO) + const { major, minor, patch } = await bridgeValidators.getBridgeValidatorsInterfacesVersion() + expect(major).to.be.bignumber.gte(ZERO) + expect(minor).to.be.bignumber.gte(ZERO) + expect(patch).to.be.bignumber.gte(ZERO) + }) + }) + + describe('#addValidator', async () => { + const owner = accounts[2] + const validators = [accounts[0], accounts[1]] + const rewards = accounts.slice(2, 4) + const requiredSignatures = 2 + beforeEach(async () => { + await bridgeValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('2') + }) + it('adds validator', async () => { + const newValidator = accounts[4] + const newReward = accounts[5] + + false.should.be.equal(await bridgeValidators.isValidator(newValidator)) + await bridgeValidators + .addRewardableValidator(newValidator, newReward, { from: validators[0] }) + .should.be.rejectedWith(ERROR_MSG) + const { logs } = await bridgeValidators.addRewardableValidator(newValidator, newReward, { + from: owner + }).should.be.fulfilled + expect(await bridgeValidators.isValidator(newValidator)).to.be.equal(true) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('3') + expectEventInLogs(logs, 'ValidatorAdded', { validator: newValidator }) + + const rewardAddress = await bridgeValidators.getValidatorRewardAddress(newValidator) + expect(rewardAddress).to.be.equal(newReward) + }) + + it('cannot add already existing validator', async () => { + true.should.be.equal(await bridgeValidators.isValidator(validators[0])) + await bridgeValidators + .addRewardableValidator(validators[0], rewards[0], { from: owner }) + .should.be.rejectedWith(ERROR_MSG) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('2') + }) + + it(`cannot add 0xf as validator address`, async () => { + // Given + await bridgeValidators + .addRewardableValidator(F_ADDRESS, rewards[0], { from: owner }) + .should.be.rejectedWith(ERROR_MSG) + }) + + it(`cannot add 0x0 as validator address`, async () => { + await bridgeValidators + .addRewardableValidator(ZERO_ADDRESS, rewards[0], { from: owner }) + .should.be.rejectedWith(ERROR_MSG) + }) + + it(`cannot add 0x0 as reward address`, async () => { + await bridgeValidators + .addRewardableValidator(accounts[4], ZERO_ADDRESS, { from: owner }) + .should.be.rejectedWith(ERROR_MSG) + }) + }) + + describe('#removeValidator', async () => { + const owner = accounts[2] + const validators = [accounts[0], accounts[1], accounts[3]] + const rewards = accounts.slice(4, 7) + const requiredSignatures = 2 + beforeEach(async () => { + await bridgeValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('3') + }) + + it('removes validator', async () => { + const toRemove = validators[0] + expect(await bridgeValidators.isValidator(toRemove)).to.be.equal(true) + await bridgeValidators.removeValidator(toRemove, { from: validators[0] }).should.be.rejectedWith(ERROR_MSG) + const { logs } = await bridgeValidators.removeValidator(toRemove, { from: owner }).should.be.fulfilled + expect(await bridgeValidators.isValidator(toRemove)).to.be.equal(false) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('2') + expectEventInLogs(logs, 'ValidatorRemoved', { validator: toRemove }) + }) + + it('cannot remove if it will break requiredSignatures', async () => { + const toRemove = validators[0] + const toRemove2 = validators[1] + true.should.be.equal(await bridgeValidators.isValidator(toRemove)) + true.should.be.equal(await bridgeValidators.isValidator(toRemove)) + await bridgeValidators.removeValidator(toRemove, { from: owner }).should.be.fulfilled + await bridgeValidators.removeValidator(toRemove2, { from: owner }).should.be.rejectedWith(ERROR_MSG) + false.should.be.equal(await bridgeValidators.isValidator(toRemove)) + true.should.be.equal(await bridgeValidators.isValidator(toRemove2)) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('2') + }) + + it('cannot remove non-existent validator', async () => { + false.should.be.equal(await bridgeValidators.isValidator(accounts[4])) + await bridgeValidators.removeValidator(accounts[4], { from: owner }).should.be.rejectedWith(ERROR_MSG) + await bridgeValidators.removeValidator(ZERO_ADDRESS, { from: owner }).should.be.rejectedWith(ERROR_MSG) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('3') + }) + }) + + describe('#setRequiredSignatures', async () => { + const owner = accounts[2] + const validators = [accounts[0], accounts[1], accounts[3]] + const rewards = accounts.slice(4, 7) + const requiredSignatures = '2' + beforeEach(async () => { + await bridgeValidators.initialize(requiredSignatures, validators, rewards, owner, { + from: owner + }).should.be.fulfilled + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('3') + }) + + it('sets req signatures', async () => { + const newReqSig = '3' + expect(await bridgeValidators.requiredSignatures()).to.be.bignumber.equal(requiredSignatures) + await bridgeValidators.setRequiredSignatures(newReqSig, { from: validators[0] }).should.be.rejectedWith(ERROR_MSG) + await bridgeValidators.setRequiredSignatures(newReqSig, { from: owner }).should.be.fulfilled + expect(await bridgeValidators.requiredSignatures()).to.be.bignumber.equal(newReqSig) + }) + it('cannot set more than validators count', async () => { + const newReqSig = '4' + expect(await bridgeValidators.requiredSignatures()).to.be.bignumber.equal(requiredSignatures) + await bridgeValidators.setRequiredSignatures(newReqSig, { from: owner }).should.be.rejectedWith(ERROR_MSG) + expect(await bridgeValidators.requiredSignatures()).to.be.bignumber.equal(requiredSignatures) + }) + }) + + describe('#upgradable', async () => { + it('can be upgraded via upgradeToAndCall', async () => { + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + const requiredSignatures = '2' + const validators = [accounts[0], accounts[1]] + const rewards = accounts.slice(3, 5) + const owner = accounts[2] + const data = bridgeValidators.contract.methods + .initialize(requiredSignatures, validators, rewards, owner) + .encodeABI() + await storageProxy.upgradeToAndCall('1', bridgeValidators.address, data).should.be.fulfilled + const finalContract = await BridgeValidators.at(storageProxy.address) + true.should.be.equal(await finalContract.isInitialized()) + expect(await finalContract.requiredSignatures()).to.be.bignumber.equal(requiredSignatures) + + true.should.be.equal(await finalContract.isValidator(validators[0])) + true.should.be.equal(await finalContract.isValidator(validators[1])) + owner.should.be.equal(await finalContract.owner()) + expect(await finalContract.validatorCount()).to.be.bignumber.equal(validators.length.toString()) + }) + }) + + describe('#single list remove', () => { + it(`should remove ${accounts[0]} - without Proxy`, async () => { + // Given + const { initialize, isInitialized, removeValidator } = bridgeValidators + await initialize(1, accounts.slice(0, 2), accounts.slice(2, 4), owner, { from: owner }).should.be.fulfilled + true.should.be.equal(await isInitialized()) + + // When + const { logs } = await removeValidator(accounts[0], { from: owner }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'ValidatorRemoved', { validator: accounts[0] }) + }) + + it(`Removed validator should return zero address on nextValidator`, async () => { + // Given + const { initialize, isInitialized, removeValidator, getNextValidator } = bridgeValidators + await initialize(1, accounts.slice(0, 2), accounts.slice(2, 4), owner, { from: owner }).should.be.fulfilled + true.should.be.equal(await isInitialized()) + const initialNextValidator = await getNextValidator(accounts[0]) + + // When + const { logs } = await removeValidator(accounts[0], { from: owner }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'ValidatorRemoved', { validator: accounts[0] }) + + const updatedNextValidator = await getNextValidator(accounts[0]) + + initialNextValidator.should.be.equals(accounts[1]) + updatedNextValidator.should.be.equals(ZERO_ADDRESS) + }) + + accounts.slice(0, 5).forEach(validator => { + it(`should remove ${validator} - with Proxy`, async () => { + // Given + const proxy = await EternalStorageProxy.new() + const bridgeValidatorsImpl = await BridgeValidators.new() + await proxy.upgradeTo('1', bridgeValidatorsImpl.address) + bridgeValidators = await BridgeValidators.at(proxy.address) + const { initialize, isInitialized, removeValidator } = bridgeValidators + await initialize(1, accounts.slice(0, 5), accounts.slice(5), owner, { from: owner }).should.be.fulfilled + true.should.be.equal(await isInitialized()) + + // When + const { logs } = await removeValidator(validator, { from: owner }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'ValidatorRemoved', { validator }) + }) + }) + }) + + describe('#reward address', () => { + it(`reward address is properly assigned`, async () => { + // Given + const { initialize, isInitialized, getValidatorRewardAddress } = bridgeValidators + await initialize(1, accounts.slice(0, 5), accounts.slice(5), owner, { from: owner }).should.be.fulfilled + + // When + expect(await isInitialized()).to.be.equal(true) + + // Then + for (let i = 0; i < accounts.slice(0, 5).length; i++) { + const validator = accounts[i] + expect(await getValidatorRewardAddress(validator)).to.be.equal(accounts[i + 5]) + } + }) + }) + describe('#Validators list', () => { + it('should return validators list', async () => { + // Given + const validators = accounts.slice(0, 5) + const { initialize, validatorList } = bridgeValidators + + // When + await initialize(1, validators, accounts.slice(5), owner, { from: owner }).should.be.fulfilled + + // Then + expect(await validatorList()).to.be.eql(validators) + }) + }) +}) diff --git a/test/setup.js b/test/setup.js index c8f0382ab..900217a8c 100644 --- a/test/setup.js +++ b/test/setup.js @@ -1,11 +1,15 @@ -var BigNumber = web3.BigNumber; +const { BN } = web3.utils require('chai') .use(require('chai-as-promised')) - .use(require('chai-bignumber')(BigNumber)) - .should(); + .use(require('chai-bn')(BN)) -exports.ERROR_MSG = 'VM Exception while processing transaction: revert'; -exports.ERROR_MSG_OPCODE = 'VM Exception while processing transaction: invalid opcode'; +require('chai/register-should') + +exports.BN = BN +exports.toBN = web3.utils.toBN +exports.ERROR_MSG = 'VM Exception while processing transaction: revert' +exports.ERROR_MSG_OPCODE = 'VM Exception while processing transaction: invalid opcode' exports.ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' +exports.F_ADDRESS = '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF' exports.INVALID_ARGUMENTS = 'Invalid number of arguments to Solidity function' diff --git a/test/validators_test.js b/test/validators_test.js index d5070f1de..57a62af0f 100644 --- a/test/validators_test.js +++ b/test/validators_test.js @@ -1,148 +1,237 @@ -const BridgeValidators = artifacts.require("BridgeValidators.sol"); -const EternalStorageProxy = artifacts.require("EternalStorageProxy.sol"); -const {ERROR_MSG, ERROR_MSG_OPCODE, ZERO_ADDRESS} = require('./setup'); - -contract('BridgeValidators', async (accounts) => { - let token - let owner = accounts[0] - const user = accounts[1]; +const BridgeValidators = artifacts.require('BridgeValidators.sol') +const EternalStorageProxy = artifacts.require('EternalStorageProxy.sol') + +const { expect } = require('chai') +const { ERROR_MSG, ZERO_ADDRESS, F_ADDRESS, BN } = require('./setup') +const { expectEventInLogs } = require('./helpers/helpers') + +const ZERO = new BN(0) + +contract('BridgeValidators', async accounts => { + let bridgeValidators + const owner = accounts[0] + beforeEach(async () => { - bridgeValidators = await BridgeValidators.new(); + bridgeValidators = await BridgeValidators.new() }) + describe('#initialize', async () => { it('sets values', async () => { - // function initialize(uint256 _requiredSignatures, address[] _initialValidators, address _owner) public { - '0x0000000000000000000000000000000000000000'.should.be.equal(await bridgeValidators.owner()) - '0'.should.be.bignumber.equal(await bridgeValidators.validatorCount()) - false.should.be.equal(await bridgeValidators.isValidator(accounts[0])) - false.should.be.equal(await bridgeValidators.isValidator(accounts[1])) - false.should.be.equal(await bridgeValidators.isInitialized()) - '0'.should.be.bignumber.equal(await bridgeValidators.requiredSignatures()) - '0'.should.be.bignumber.equal(await bridgeValidators.deployedAtBlock()) - await bridgeValidators.initialize(3, [accounts[0], accounts[1]], accounts[2], {from: accounts[2]}).should.be.rejectedWith(ERROR_MSG) - await bridgeValidators.initialize(2, [accounts[0], accounts[1]], accounts[2], {from: accounts[2]}).should.be.fulfilled; - await bridgeValidators.initialize(2, [accounts[0], accounts[1]], accounts[2], {from: accounts[2]}).should.be.rejectedWith(ERROR_MSG); - true.should.be.equal(await bridgeValidators.isInitialized()) - '2'.should.be.bignumber.equal(await bridgeValidators.requiredSignatures()) - true.should.be.equal(await bridgeValidators.isValidator(accounts[0])) - true.should.be.equal(await bridgeValidators.isValidator(accounts[1])) - accounts[2].should.be.equal(await bridgeValidators.owner()) - '2'.should.be.bignumber.equal(await bridgeValidators.validatorCount()); - (await bridgeValidators.deployedAtBlock()).should.be.bignumber.above(0) - const [major, minor, patch] = await bridgeValidators.getBridgeValidatorsInterfacesVersion() - major.should.be.bignumber.gte(0) - minor.should.be.bignumber.gte(0) - patch.should.be.bignumber.gte(0) + expect(await bridgeValidators.owner()).to.be.equal(ZERO_ADDRESS) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal(ZERO) + expect(await bridgeValidators.isValidator(accounts[0])).to.be.equal(false) + expect(await bridgeValidators.isValidator(accounts[1])).to.be.equal(false) + expect(await bridgeValidators.isInitialized()).to.be.equal(false) + expect(await bridgeValidators.requiredSignatures()).to.be.bignumber.equal(ZERO) + expect(await bridgeValidators.deployedAtBlock()).to.be.bignumber.equal(ZERO) + + await bridgeValidators + .initialize(1, [ZERO_ADDRESS], accounts[1], { from: accounts[1] }) + .should.be.rejectedWith(ERROR_MSG) + await bridgeValidators + .initialize(1, [F_ADDRESS], accounts[1], { from: accounts[1] }) + .should.be.rejectedWith(ERROR_MSG) + await bridgeValidators.initialize(2, accounts.slice(0, 2), accounts[2], { from: accounts[2] }).should.be.fulfilled + await bridgeValidators + .initialize(2, accounts.slice(0, 2), accounts[2], { from: accounts[2] }) + .should.be.rejectedWith(ERROR_MSG) + + expect(await bridgeValidators.isInitialized()).to.be.equal(true) + expect(await bridgeValidators.requiredSignatures()).to.be.bignumber.equal('2') + expect(await bridgeValidators.isValidator(accounts[0])).to.be.equal(true) + expect(await bridgeValidators.isValidator(accounts[1])).to.be.equal(true) + expect(await bridgeValidators.owner()).to.be.equal(accounts[2]) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('2') + expect(await bridgeValidators.deployedAtBlock()).to.be.bignumber.above(ZERO) + const { major, minor, patch } = await bridgeValidators.getBridgeValidatorsInterfacesVersion() + expect(major).to.be.bignumber.gte(ZERO) + expect(minor).to.be.bignumber.gte(ZERO) + expect(patch).to.be.bignumber.gte(ZERO) }) }) describe('#addValidator', async () => { - let owner = accounts[2]; - let validators = [accounts[0], accounts[1]]; - let requiredSignatures = 2; + const owner = accounts[2] + const validators = [accounts[0], accounts[1]] + const requiredSignatures = 2 beforeEach(async () => { - await bridgeValidators.initialize(requiredSignatures, validators, owner, {from: owner}).should.be.fulfilled - '2'.should.be.bignumber.equal(await bridgeValidators.validatorCount()) + await bridgeValidators.initialize(requiredSignatures, validators, owner, { from: owner }).should.be.fulfilled + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('2') }) it('adds validator', async () => { - let newValidator = accounts[3]; + const newValidator = accounts[4] false.should.be.equal(await bridgeValidators.isValidator(newValidator)) - await bridgeValidators.addValidator(newValidator, {from: validators[0]}).should.be.rejectedWith(ERROR_MSG) - const {logs} = await bridgeValidators.addValidator(newValidator, {from: owner}).should.be.fulfilled - true.should.be.equal(await bridgeValidators.isValidator(newValidator)) - '3'.should.be.bignumber.equal(await bridgeValidators.validatorCount()) - logs[0].event.should.be.equal('ValidatorAdded') - logs[0].args.should.be.deep.equal({validator: newValidator}) + await bridgeValidators.addValidator(newValidator, { from: validators[0] }).should.be.rejectedWith(ERROR_MSG) + const { logs } = await bridgeValidators.addValidator(newValidator, { from: owner }).should.be.fulfilled + expect(await bridgeValidators.isValidator(newValidator)).to.be.equal(true) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('3') + expectEventInLogs(logs, 'ValidatorAdded', { validator: newValidator }) }) it('cannot add already existing validator', async () => { true.should.be.equal(await bridgeValidators.isValidator(validators[0])) - await bridgeValidators.addValidator(validators[0], {from: owner}).should.be.rejectedWith(ERROR_MSG) - await bridgeValidators.addValidator(ZERO_ADDRESS, {from: owner}).should.be.rejectedWith(ERROR_MSG) - '2'.should.be.bignumber.equal(await bridgeValidators.validatorCount()) + await bridgeValidators.addValidator(validators[0], { from: owner }).should.be.rejectedWith(ERROR_MSG) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('2') + }) + + it(`cannot add 0xf as validator address`, async () => { + // Given + await bridgeValidators.addValidator(F_ADDRESS, { from: owner }).should.be.rejectedWith(ERROR_MSG) + }) + + it(`cannot add 0x0 as validator address`, async () => { + await bridgeValidators.addValidator(ZERO_ADDRESS, { from: owner }).should.be.rejectedWith(ERROR_MSG) }) }) describe('#removeValidator', async () => { - let owner = accounts[2]; - let validators = [accounts[0], accounts[1], accounts[3]]; - let requiredSignatures = 2; + const owner = accounts[2] + const validators = [accounts[0], accounts[1], accounts[3]] + const requiredSignatures = 2 beforeEach(async () => { - await bridgeValidators.initialize(requiredSignatures, validators, owner, {from: owner}).should.be.fulfilled - '3'.should.be.bignumber.equal(await bridgeValidators.validatorCount()) + await bridgeValidators.initialize(requiredSignatures, validators, owner, { from: owner }).should.be.fulfilled + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('3') }) it('removes validator', async () => { - let toRemove = validators[0]; - true.should.be.equal(await bridgeValidators.isValidator(toRemove)) - await bridgeValidators.removeValidator(toRemove, {from: validators[0]}).should.be.rejectedWith(ERROR_MSG) - const {logs} = await bridgeValidators.removeValidator(toRemove, {from: owner}).should.be.fulfilled - false.should.be.equal(await bridgeValidators.isValidator(toRemove)) - '2'.should.be.bignumber.equal(await bridgeValidators.validatorCount()) - logs[0].event.should.be.equal('ValidatorRemoved') - logs[0].args.should.be.deep.equal({validator: toRemove}) + const toRemove = validators[0] + expect(await bridgeValidators.isValidator(toRemove)).to.be.equal(true) + await bridgeValidators.removeValidator(toRemove, { from: validators[0] }).should.be.rejectedWith(ERROR_MSG) + const { logs } = await bridgeValidators.removeValidator(toRemove, { from: owner }).should.be.fulfilled + expect(await bridgeValidators.isValidator(toRemove)).to.be.equal(false) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('2') + expectEventInLogs(logs, 'ValidatorRemoved', { validator: toRemove }) }) it('cannot remove if it will break requiredSignatures', async () => { - let toRemove = validators[0]; - let toRemove2 = validators[1]; + const toRemove = validators[0] + const toRemove2 = validators[1] true.should.be.equal(await bridgeValidators.isValidator(toRemove)) true.should.be.equal(await bridgeValidators.isValidator(toRemove)) - await bridgeValidators.removeValidator(toRemove, {from: owner}).should.be.fulfilled - await bridgeValidators.removeValidator(toRemove2, {from: owner}).should.be.rejectedWith(ERROR_MSG) + await bridgeValidators.removeValidator(toRemove, { from: owner }).should.be.fulfilled + await bridgeValidators.removeValidator(toRemove2, { from: owner }).should.be.rejectedWith(ERROR_MSG) false.should.be.equal(await bridgeValidators.isValidator(toRemove)) true.should.be.equal(await bridgeValidators.isValidator(toRemove2)) - '2'.should.be.bignumber.equal(await bridgeValidators.validatorCount()) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('2') }) it('cannot remove non-existent validator', async () => { false.should.be.equal(await bridgeValidators.isValidator(accounts[4])) - await bridgeValidators.removeValidator(accounts[4], {from: owner}).should.be.rejectedWith(ERROR_MSG) - await bridgeValidators.removeValidator(ZERO_ADDRESS, {from: owner}).should.be.rejectedWith(ERROR_MSG) - '3'.should.be.bignumber.equal(await bridgeValidators.validatorCount()) + await bridgeValidators.removeValidator(accounts[4], { from: owner }).should.be.rejectedWith(ERROR_MSG) + await bridgeValidators.removeValidator(ZERO_ADDRESS, { from: owner }).should.be.rejectedWith(ERROR_MSG) + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('3') }) }) describe('#setRequiredSignatures', async () => { - let owner = accounts[2]; - let validators = [accounts[0], accounts[1], accounts[3]]; - let requiredSignatures = 2; + const owner = accounts[2] + const validators = [accounts[0], accounts[1], accounts[3]] + const requiredSignatures = '2' beforeEach(async () => { - await bridgeValidators.initialize(requiredSignatures, validators, owner, {from: owner}).should.be.fulfilled - '3'.should.be.bignumber.equal(await bridgeValidators.validatorCount()) + await bridgeValidators.initialize(requiredSignatures, validators, owner, { from: owner }).should.be.fulfilled + expect(await bridgeValidators.validatorCount()).to.be.bignumber.equal('3') }) it('sets req signatures', async () => { - let newReqSig = 3; - requiredSignatures.should.be.bignumber.equal(await bridgeValidators.requiredSignatures()); - await bridgeValidators.setRequiredSignatures(newReqSig, {from: validators[0]}).should.be.rejectedWith(ERROR_MSG) - await bridgeValidators.setRequiredSignatures(newReqSig, {from: owner}).should.be.fulfilled - newReqSig.should.be.bignumber.equal(await bridgeValidators.requiredSignatures()); + const newReqSig = '3' + expect(await bridgeValidators.requiredSignatures()).to.be.bignumber.equal(requiredSignatures) + await bridgeValidators.setRequiredSignatures(newReqSig, { from: validators[0] }).should.be.rejectedWith(ERROR_MSG) + await bridgeValidators.setRequiredSignatures(newReqSig, { from: owner }).should.be.fulfilled + expect(await bridgeValidators.requiredSignatures()).to.be.bignumber.equal(newReqSig) }) it('cannot set more than validators count', async () => { - let newReqSig = 4; - requiredSignatures.should.be.bignumber.equal(await bridgeValidators.requiredSignatures()); - await bridgeValidators.setRequiredSignatures(newReqSig, {from: owner}).should.be.rejectedWith(ERROR_MSG) - requiredSignatures.should.be.bignumber.equal(await bridgeValidators.requiredSignatures()); + const newReqSig = '4' + expect(await bridgeValidators.requiredSignatures()).to.be.bignumber.equal(requiredSignatures) + await bridgeValidators.setRequiredSignatures(newReqSig, { from: owner }).should.be.rejectedWith(ERROR_MSG) + expect(await bridgeValidators.requiredSignatures()).to.be.bignumber.equal(requiredSignatures) }) }) + describe('#upgradable', async () => { it('can be upgraded via upgradeToAndCall', async () => { - let storageProxy = await EternalStorageProxy.new().should.be.fulfilled; - let required_signatures = 2; - let validators = [accounts[0], accounts[1]]; - let owner = accounts[2] - let data = bridgeValidators.initialize.request(required_signatures, validators, owner).params[0].data - await storageProxy.upgradeToAndCall('1', bridgeValidators.address, data).should.be.fulfilled; - let finalContract = await BridgeValidators.at(storageProxy.address); - true.should.be.equal(await finalContract.isInitialized()); - required_signatures.should.be.bignumber.equal(await finalContract.requiredSignatures()) + const storageProxy = await EternalStorageProxy.new().should.be.fulfilled + const requiredSignatures = '2' + const validators = [accounts[0], accounts[1]] + const owner = accounts[2] + const data = bridgeValidators.contract.methods.initialize(requiredSignatures, validators, owner).encodeABI() + await storageProxy.upgradeToAndCall('1', bridgeValidators.address, data).should.be.fulfilled + const finalContract = await BridgeValidators.at(storageProxy.address) + true.should.be.equal(await finalContract.isInitialized()) + expect(await finalContract.requiredSignatures()).to.be.bignumber.equal(requiredSignatures) true.should.be.equal(await finalContract.isValidator(validators[0])) true.should.be.equal(await finalContract.isValidator(validators[1])) owner.should.be.equal(await finalContract.owner()) - validators.length.should.be.bignumber.equal(await finalContract.validatorCount()) + expect(await finalContract.validatorCount()).to.be.bignumber.equal(validators.length.toString()) + }) + }) + + describe('#single list remove', () => { + it(`should remove ${accounts[0]} - without Proxy`, async () => { + // Given + const { initialize, isInitialized, removeValidator } = bridgeValidators + await initialize(1, accounts.slice(0, 2), owner, { from: owner }).should.be.fulfilled + true.should.be.equal(await isInitialized()) + + // When + const { logs } = await removeValidator(accounts[0], { from: owner }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'ValidatorRemoved', { validator: accounts[0] }) + }) + + it(`Removed validator should return zero address on nextValidator`, async () => { + // Given + const { initialize, isInitialized, removeValidator, getNextValidator } = bridgeValidators + await initialize(1, accounts.slice(0, 2), owner, { from: owner }).should.be.fulfilled + true.should.be.equal(await isInitialized()) + const initialNextValidator = await getNextValidator(accounts[0]) + + // When + const { logs } = await removeValidator(accounts[0], { from: owner }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'ValidatorRemoved', { validator: accounts[0] }) + + const updatedNextValidator = await getNextValidator(accounts[0]) + + initialNextValidator.should.be.equals(accounts[1]) + updatedNextValidator.should.be.equals(ZERO_ADDRESS) + }) + + accounts.slice(0, 5).forEach(validator => { + it(`should remove ${validator} - with Proxy`, async () => { + // Given + const proxy = await EternalStorageProxy.new() + const bridgeValidatorsImpl = await BridgeValidators.new() + await proxy.upgradeTo('1', bridgeValidatorsImpl.address) + bridgeValidators = await BridgeValidators.at(proxy.address) + const { initialize, isInitialized, removeValidator } = bridgeValidators + await initialize(1, accounts.slice(0, 5), owner, { from: owner }).should.be.fulfilled + true.should.be.equal(await isInitialized()) + + // When + const { logs } = await removeValidator(validator, { from: owner }).should.be.fulfilled + + // Then + expectEventInLogs(logs, 'ValidatorRemoved', { validator }) + }) + }) + }) + + describe('#Validators list', () => { + it('should return validators list', async () => { + // Given + const validators = accounts.slice(0, 5) + const { initialize, validatorList } = bridgeValidators + await initialize(1, validators, owner, { from: owner }).should.be.fulfilled + + // When + const returnedList = await validatorList() + + // Then + returnedList.should.be.eql(validators) }) }) }) diff --git a/truffle-config.js b/truffle-config.js index a6330d6d5..33730c37c 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -1,4 +1,45 @@ +const spuriousDragonVersion = process.argv[3] === 'spuriousDragon' +const contractsBuildDirectory = spuriousDragonVersion ? './build/spuriousDragon' : './build/contracts' +const evmVersion = spuriousDragonVersion ? 'spuriousDragon' : 'byzantium' +const mochaOptions = + process.env.GASREPORT === 'true' + ? { + reporter: 'eth-gas-reporter', + reporterOptions: { + currency: 'USD', + gasPrice: 1 + } + } + : {} + module.exports = { - // See - // to customize your Truffle configuration! -}; + contracts_build_directory: contractsBuildDirectory, + networks: { + coverage: { + host: 'localhost', + network_id: '*', // eslint-disable-line camelcase + port: 8555, + gas: 0xfffffffffff, + gasPrice: 0x01 + }, + ganache: { + host: '127.0.0.1', + port: 8545, + network_id: '*', // eslint-disable-line camelcase + gasPrice: 100000000000 + } + }, + compilers: { + solc: { + version: '0.4.24', + settings: { + optimizer: { + enabled: true, + runs: 200 + }, + evmVersion + } + } + }, + mocha: mochaOptions +} diff --git a/truffle.js b/truffle.js deleted file mode 100644 index 3468c855d..000000000 --- a/truffle.js +++ /dev/null @@ -1,63 +0,0 @@ -module.exports = { - networks: { - development: { - host: "localhost", - port: 7545, - network_id: "*", - gasPrice: 1000000000 - }, - test: { - host: "localhost", - port: 7545, - network_id: "*", - gasPrice: 1000000000 - }, - kovan: { - host: "localhost", - port: "8591", - network_id: "*", - gas: 4700000, - gasPrice: 1000000000 - }, - core: { - host: "localhost", - port: "8777", - network_id: "*", - gas: 4700000, - gasPrice: 1000000000 - }, - sokol: { - host: "localhost", - port: "8545", - network_id: "*", - gas: 4700000, - gasPrice: 1000000000 - }, - coverage: { - host: 'localhost', - network_id: '*', // eslint-disable-line camelcase - port: 8555, - gas: 0xfffffffffff, - gasPrice: 0x01, - }, - ganache: { - host: 'localhost', - port: 8545, - network_id: '*', // eslint-disable-line camelcase - gasPrice: 1000000000 - } - }, - solc: { - optimizer: { - enabled: true, - runs: 200 - } - }, - mocha: { - reporter: 'eth-gas-reporter', - reporterOptions : { - currency: 'USD', - gasPrice: 1 - } - } -};