diff --git a/contracts/0-FineGrainedPermissions/0-FineGrainedPermissions.sol b/contracts/0-FineGrainedPermissions/0-FineGrainedPermissions.sol deleted file mode 100644 index ad4f84e..0000000 --- a/contracts/0-FineGrainedPermissions/0-FineGrainedPermissions.sol +++ /dev/null @@ -1,54 +0,0 @@ -pragma solidity ^0.4.24; - -import "@thetta/core/contracts/tokens/StdDaoToken.sol"; -import "@thetta/core/contracts/IDaoBase.sol"; -import "@thetta/core/contracts/DaoClient.sol"; - -// This is an example of a more fine grained permissions. -// DaoBase allows us to permit 'issueTokens'/'burnTokens' only for all tokens at once. -// -// So if you have 3 tokens (governance, rep, repdev) -> any member that can issueTokens -// for 1st, will be able to issueTokens for the 2nd, etc. -// -// Imagine you want: -// 1. create your own more fine grained permissions - issueTokensGovr, issueTokensRep, issueTokensRepDev -// 2. to permit issueTokensGovr to CEO -// 3. to permit issueTokensRep tnd issueTokensRepDev to Managers -// -// This contract shows how to do that: -contract ExampleOfFineGrainedPerms is DaoClient { - StdDaoToken public tokenGovernance; - // Generic reputation - StdDaoToken public tokenReputation; - // Reputation for Devs - StdDaoToken public tokenReputationDev; - -//// - constructor(IDaoBase _daoBase) public DaoClient(_daoBase){ - // 1 - create tokens - tokenGovernance = new StdDaoToken("YourDaoGovToken","GOV",18, true, false, 10**25); - tokenReputation = new StdDaoToken("YourDaoRepToken","REP",18, true, true, 10**25); - tokenReputationDev = new StdDaoToken("YourDaoRepDevToken","REPD",18, true, false, 10**25); - - // 2 - transfer ownership to the Dao - tokenGovernance.transferOwnership(daoBase); - tokenReputation.transferOwnership(daoBase); - tokenReputationDev.transferOwnership(daoBase); - } - -// ACTIONS: - function issueTokensGovr(address _to, uint _amount) external isCanDo("CUSTOM_issueTokensGovr"){ - // you should grant issueTokens permission to THIS contract - daoBase.issueTokens(tokenGovernance, _to, _amount); - } - - function issueTokensRep(address _to, uint _amount) external isCanDo("CUSTOM_issueTokensRep"){ - // you should grant issueTokens permission to THIS contract - daoBase.issueTokens(tokenReputation, _to, _amount); - } - - function issueTokensRepDev(address _to, uint _amount) external isCanDo("CUSTOM_issueTokensRepDev"){ - // you should grant issueTokens permission to THIS contract - daoBase.issueTokens(tokenReputationDev, _to, _amount); - } -} diff --git a/contracts/0-FineGrainedPermissions/README.md b/contracts/0-FineGrainedPermissions/README.md deleted file mode 100644 index b3470e1..0000000 --- a/contracts/0-FineGrainedPermissions/README.md +++ /dev/null @@ -1,15 +0,0 @@ - # FineGrainedPermissions - --- - ## Description -This is an example of a more fine grained permissions. -DaoBase allows us to permit 'issueTokens'/'burnTokens' only for all tokens at once. - -So if you have 3 tokens (governance, rep, repdev) -> any member that can issueTokens -for 1st, will be able to issueTokens for the 2nd, etc. - -Imagine you want: -1. create your own more fine grained permissions - issueTokensGovr, issueTokensRep, issueTokensRepDev -2. to permit issueTokensGovr to CEO -3. to permit issueTokensRep tnd issueTokensRepDev to Managers - -This contract shows how to do that. \ No newline at end of file diff --git a/contracts/1-HierarchyDao/HierarchyDaoFactory.sol b/contracts/1-HierarchyDao/HierarchyDaoFactory.sol deleted file mode 100644 index a71f804..0000000 --- a/contracts/1-HierarchyDao/HierarchyDaoFactory.sol +++ /dev/null @@ -1,91 +0,0 @@ -pragma solidity ^0.4.24; - -import "@thetta/core/contracts/DaoBase.sol"; -import "@thetta/core/contracts/DaoBaseWithUnpackers.sol"; -import "@thetta/core/contracts/DaoBaseAuto.sol"; -import "@thetta/core/contracts/tokens/StdDaoToken.sol"; -import "@thetta/core/contracts/IDaoBase.sol"; -import "@thetta/core/contracts/DaoStorage.sol"; -import "@thetta/core/contracts/utils/UtilsLib.sol"; -import "@thetta/core/contracts/governance/InformalProposal.sol"; -import "./HierarcyDao.sol"; - -contract HierarchyDaoFactory { - DaoStorage public store; - StdDaoToken public token; - DaoBaseWithUnpackers public daoBase; - HierarchyDao public hierarcyDao; - DaoBaseAuto public hierarchyDaoAuto; - - constructor( - address _boss, - address[] _managers, - address[] _employees, - address[] _outsiders - ) public { - createDao(_boss, _managers, _employees, _outsiders); - setupHierarchyDaoAuto(); - daoBase.renounceOwnership(); - } - - function createDao( - address _boss, - address[] _managers, - address[] _employees, - address[] _outsiders - ) internal { - // 1 - create - token = new StdDaoToken("StdToken", "STDT", 18, true, false, 10**25); - address[] tokens; - tokens.push(address(token)); - store = new DaoStorage(tokens); - daoBase = new DaoBaseWithUnpackers(store); - hierarcyDao = new HierarchyDao(IDaoBase(daoBase)); - - store.allowActionByAddress(daoBase.MANAGE_GROUPS(), address(this)); - store.transferOwnership(daoBase); - token.transferOwnership(daoBase); - - setPermissions(_boss, _managers, _employees); - } - - function setPermissions(address _boss, address[] _managers, address[] _employees) internal { - - // 1 - grant all permissions to the boss - daoBase.addGroupMember("Managers", _boss); - daoBase.addGroupMember("Employees", _boss); - - daoBase.allowActionByAddress(daoBase.ISSUE_TOKENS(), _boss); - daoBase.allowActionByAddress(daoBase.UPGRADE_DAO_CONTRACT(), _boss); - - // 2 - set managers group permission - daoBase.allowActionByAnyMemberOfGroup(daoBase.ADD_NEW_PROPOSAL(), "Managers"); - - // 4 - the rest is by voting only (requires addNewProposal permission) - // so accessable by Managers only even with voting - daoBase.allowActionByVoting(daoBase.MANAGE_GROUPS(), token); - - // 5 - populate groups - uint i = 0; - for(i = 0; i < _managers.length; ++i) { - daoBase.addGroupMember("Managers", _managers[i]); - } - for(i = 0; i < _employees.length; ++i){ - daoBase.addGroupMember("Employees", _employees[i]); - } - - } - - function setupHierarchyDaoAuto() internal { - hierarchyDaoAuto = new DaoBaseAuto(daoBase); - - // set voring params 1 person 1 vote - uint8 VOTING_TYPE_1P1V = 1; - hierarchyDaoAuto.setVotingParams(daoBase.MANAGE_GROUPS(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("Managers"), bytes32(50), bytes32(50), 0); - - daoBase.allowActionByAddress(daoBase.ADD_NEW_PROPOSAL(), hierarchyDaoAuto); - daoBase.allowActionByAddress(daoBase.MANAGE_GROUPS(), hierarchyDaoAuto); - - hierarchyDaoAuto.transferOwnership(msg.sender); - } -} \ No newline at end of file diff --git a/contracts/1-HierarchyDao/HierarcyDao.sol b/contracts/1-HierarchyDao/HierarcyDao.sol deleted file mode 100644 index 69d45f4..0000000 --- a/contracts/1-HierarchyDao/HierarcyDao.sol +++ /dev/null @@ -1,8 +0,0 @@ -pragma solidity ^0.4.24; -import "@thetta/core/contracts/IDaoBase.sol"; -import "@thetta/core/contracts/DaoClient.sol"; - -contract HierarchyDao is DaoClient { - constructor(IDaoBase _daoBase)public DaoClient(_daoBase){ - } -} diff --git a/contracts/1-HierarchyDao/README.md b/contracts/1-HierarchyDao/README.md deleted file mode 100644 index d3b79ba..0000000 --- a/contracts/1-HierarchyDao/README.md +++ /dev/null @@ -1,4 +0,0 @@ - # HierarchyDao - --- - ## Description -Hierarchy DAO with boss => managers => employees. \ No newline at end of file diff --git a/contracts/2-BoD/BodDao.sol b/contracts/2-BoD/BodDao.sol deleted file mode 100644 index f52347f..0000000 --- a/contracts/2-BoD/BodDao.sol +++ /dev/null @@ -1,8 +0,0 @@ -pragma solidity ^0.4.24; -import "@thetta/core/contracts/IDaoBase.sol"; -import "@thetta/core/contracts/DaoClient.sol"; - -contract BodDao is DaoClient { - constructor(IDaoBase _daoBase)public DaoClient(_daoBase){ - } -} diff --git a/contracts/2-BoD/BodDaoFactory.sol b/contracts/2-BoD/BodDaoFactory.sol deleted file mode 100644 index c813de6..0000000 --- a/contracts/2-BoD/BodDaoFactory.sol +++ /dev/null @@ -1,80 +0,0 @@ -pragma solidity ^0.4.24; - -import "@thetta/core/contracts/DaoBase.sol"; -import "@thetta/core/contracts/DaoBaseWithUnpackers.sol"; -import "@thetta/core/contracts/DaoBaseAuto.sol"; -import "@thetta/core/contracts/DaoStorage.sol"; -import "@thetta/core/contracts/tokens/StdDaoToken.sol"; -import "@thetta/core/contracts/utils/UtilsLib.sol"; -import "@thetta/core/contracts/tasks/WeiGenericTask.sol"; - -import "./BodDao.sol"; - -contract BodDaoFactory { - DaoBaseWithUnpackers public daoBase; - DaoBaseAuto public bodDaoAuto; - DaoStorage public store; - StdDaoToken public token; - BodDao public bodDao; - - address[] tokens; - - constructor(address _creator, address[] _directors, address[] _employees) public { - createDao(_creator, _directors, _employees); - setupBodDaoAuto(); - daoBase.renounceOwnership(); - } - - function createDao(address _creator, address[] _directors, address[] _employees) internal { - // 1 - create - token = new StdDaoToken("StdToken", "STDT", 18, true, true, 10**25); - tokens.push(address(token)); - store = new DaoStorage(tokens); - daoBase = new DaoBaseWithUnpackers(store); - bodDao = new BodDao(IDaoBase(daoBase)); - - store.allowActionByAddress(daoBase.MANAGE_GROUPS(), address(this)); - - token.transferOwnership(daoBase); - store.transferOwnership(daoBase); - // 2 - setup - - // 1 - creator is in BoD initially - daoBase.addGroupMember("BoD", _creator); - daoBase.addGroupMember("Employees", _creator); - - // 2 - set BoD group permissions - daoBase.allowActionByAnyMemberOfGroup(daoBase.ADD_NEW_PROPOSAL(), "BoD"); - - // 4 - the rest is by voting only (requires addNewProposal permission) - daoBase.allowActionByVoting(daoBase.MANAGE_GROUPS(), token); - daoBase.allowActionByVoting(daoBase.ISSUE_TOKENS(), token); - daoBase.allowActionByVoting(daoBase.UPGRADE_DAO_CONTRACT(), token); - - // 5 - populate groups - uint i = 0; - for(i = 0; i < _directors.length; ++i){ - daoBase.addGroupMember("BoD", _directors[i]); - } - - for(i = 0; i < _employees.length; ++i){ - daoBase.addGroupMember("Employees", _employees[i]); - } - } - - function setupBodDaoAuto() internal { - bodDaoAuto = new DaoBaseAuto(daoBase); - - uint VOTING_TYPE_1P1V = 1; - bodDaoAuto.setVotingParams(daoBase.MANAGE_GROUPS(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("BoD"), bytes32(49), bytes32(49), 0); - bodDaoAuto.setVotingParams(daoBase.ISSUE_TOKENS(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("BoD"), bytes32(49), bytes32(49), 0); - bodDaoAuto.setVotingParams(daoBase.UPGRADE_DAO_CONTRACT(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("BoD"), bytes32(49), bytes32(49), 0); - - daoBase.allowActionByAddress(daoBase.MANAGE_GROUPS(), bodDaoAuto); - daoBase.allowActionByAddress(daoBase.ISSUE_TOKENS(), bodDaoAuto); - daoBase.allowActionByAddress(daoBase.ADD_NEW_PROPOSAL(), bodDaoAuto); - - bodDaoAuto.transferOwnership(msg.sender); - } - -} diff --git a/contracts/2-BoD/README.md b/contracts/2-BoD/README.md deleted file mode 100644 index 025e898..0000000 --- a/contracts/2-BoD/README.md +++ /dev/null @@ -1,4 +0,0 @@ - # Board of Directors DAO - --- - ## Description -DAO of directors to manage the company. \ No newline at end of file diff --git a/contracts/3-DevZenDao/DevZenDao.sol b/contracts/3-DevZenDao/DevZenDao.sol deleted file mode 100644 index bd271f4..0000000 --- a/contracts/3-DevZenDao/DevZenDao.sol +++ /dev/null @@ -1,119 +0,0 @@ -pragma solidity ^0.4.24; - -// to enable Params passing to constructor and method -pragma experimental ABIEncoderV2; - -import "@thetta/core/contracts/DaoBase.sol"; -import "@thetta/core/contracts/DaoBaseImpersonated.sol"; -import "@thetta/core/contracts/IDaoBase.sol"; -import "@thetta/core/contracts/tokens/StdDaoToken.sol"; - -import "./DevZenDaoCore.sol"; - -contract DevZenDao is DevZenDaoCore { - - constructor( - IDaoBase _daoBase, - address[] _tokens - ) public DevZenDaoCore(_daoBase, _tokens) {} - - // --------------------------------------------- - // These methods should be called by DevZen team: - //---------------------------------------------- - - /** - * @dev Change the DAO parameters - * This method should require voting! - * Notice: DevZen_updateDaoParams is a custom action! - */ - function setParam(bytes32 _param, uint _value) public isCanDo(DEV_ZEN_UPDATE_DAO_PARAMS) { - super._setParam(_param, _value); - } - - /** - * @dev Withdraw all collected ETH to the _output. - * This method should require voting! - * Notice: DevZen_withdrawEther is a custom action! - */ - function withdrawEther(address _output) public isCanDo(DEV_ZEN_WITHDRAW_ETHER) { - super._withdrawEther(_output); - } - - /** - * @dev Select next episode's host - * This method should require voting! - * Notice: DevZen_selectNextHost is a custom action! - */ - function selectNextHost(address _nextHost) public isCanDo(DEV_ZEN_SELECT_NEXT_HOST) { - super._selectNextHost(_nextHost); - } - - /** - * @dev Changes the guest in "legal" way - * @param _guest New guest address - * When guest is changed via this function we ensure that stake is returned to previous guest. - */ - function changeTheGuest(address _guest) public isCanDo(DEV_ZEN_CHANGE_GUEST) { - super._changeTheGuest(_guest); - } - - /** - * @dev Set the guest (emergency) - * In normal circumst. people should use 'becomeTheNextShowGuest' method. - * However, sometimes DevZen team should be able to fix the next guest! - * Notice: DevZen_emergencyChangeGuest is a custom action! - */ - function emergency_ChangeTheGuest(address _guest) public isCanDo(DEV_ZEN_EMERGENCY_CHANGE_GUEST) { - super._emergency_ChangeTheGuest(_guest); - } - - /** - * @dev Move to next episode - * @param _guestHasCome Whether the guest(initual or emergency) has come to the show - * Should be called right AFTER the recording of the current episode - * Notice: DevZen_moveToNextEpisode is a custom action! - */ - function moveToNextEpisode(bool _guestHasCome) public isCanDo(DEV_ZEN_MOVE_TO_NEXT_EPISODE) { - super._moveToNextEpisode(_guestHasCome); - } - - // ------------------------------------------------------ - // These methods should be called by DevZen token holders - // ------------------------------------------------------ - // Any patron (DevZen token holder) can use DevZen tokens to run ads: Burn k tokens to add your add into the slot (linear, no priority). - function runAdsInTheNextEpisode(string _adText) public { - super._runAdsInTheNextEpisode(_adText); - } - - /** - * @dev Become the next guest. - * To become a guest sender should buy 5 DZT and approve dao to put them at stake. Sender will get back tokens after the show. - */ - function becomeTheNextShowGuest() public { - super._becomeTheNextShowGuest(); - } - - // ---------------------------------------------- - // These methods should be called by any address: - // ---------------------------------------------- - - /** - * @dev Any listener can get a ERC20 “devzen” tokens by sending X ETHers to the DevZen DAO and becomes a “patron” (i.e. token holder). - */ - function buyTokens() external payable { - super._buyTokens(); - } - - /** - * @dev Check that 1 week has passed since the last episode - * @return true if 1 week has passed else false - */ - function isOneWeekPassed() public view returns(bool) { - return super._isOneWeekPassed(); - } - - // do not allow to send ETH here. Instead use buyTokens method - function() { - revert(); - } -} diff --git a/contracts/3-DevZenDao/DevZenDaoAuto.sol b/contracts/3-DevZenDao/DevZenDaoAuto.sol deleted file mode 100644 index ac5bc72..0000000 --- a/contracts/3-DevZenDao/DevZenDaoAuto.sol +++ /dev/null @@ -1,71 +0,0 @@ -pragma solidity ^0.4.24; -// to enable Params passing to constructor and method -pragma experimental ABIEncoderV2; - -import "@thetta/core/contracts/DaoBaseAuto.sol"; - -import "./DevZenDao.sol"; -import "./DevZenDaoCore.sol"; -import "./DevZenDaoWithUnpackers.sol"; - -contract DevZenDaoAuto is DaoBaseAuto{ - event UpdateDaoParamsAuto(); - event WithdrawEtherAuto(); - event SelectNextHostAuto(); - event ChangeTheGuestAuto(); - event Emergency_ChangeTheGuestAuto(); - event MoveToNextEpisodeAuto(); - - DevZenDaoWithUnpackers devZenDao; - constructor(IDaoBase _daoBase, DevZenDaoWithUnpackers _devZenDao) public DaoBaseAuto(_daoBase){ - devZenDao = _devZenDao; - } - - function updateDaoParamsAuto(bytes32 _param, uint _value) public returns(address proposalOut) { - emit UpdateDaoParamsAuto(); - bytes32[] memory params = new bytes32[](2); - params[0] = _param; - params[1] = bytes32(_value); - return doAction(devZenDao.DEV_ZEN_UPDATE_DAO_PARAMS(), devZenDao, msg.sender, "updateDaoParamsGeneric(bytes32[])", params); - } - - function withdrawEtherAuto(address _output) public returns(address proposalOut) { - emit WithdrawEtherAuto(); - bytes32[] memory params = new bytes32[](1); - params[0] = bytes32(_output); - return doAction(devZenDao.DEV_ZEN_WITHDRAW_ETHER(), devZenDao, msg.sender, "withdrawEtherGeneric(bytes32[])", params); - } - - function selectNextHostAuto(address _nextHost) public returns(address proposalOut) { - emit SelectNextHostAuto(); - bytes32[] memory params = new bytes32[](1); - params[0] = bytes32(_nextHost); - return doAction(devZenDao.DEV_ZEN_SELECT_NEXT_HOST(), devZenDao, msg.sender, "selectNextHostGeneric(bytes32[])", params); - } - - function changeTheGuestAuto(address _guest) public returns(address proposalOut) { - emit ChangeTheGuestAuto(); - bytes32[] memory params = new bytes32[](1); - params[0] = bytes32(_guest); - return doAction(devZenDao.DEV_ZEN_CHANGE_GUEST(), devZenDao, msg.sender, "changeTheGuestGeneric(bytes32[])", params); - } - - function emergency_ChangeTheGuestAuto(address _guest) public returns(address proposalOut) { - emit Emergency_ChangeTheGuestAuto(); - bytes32[] memory params = new bytes32[](1); - params[0] = bytes32(_guest); - return doAction(devZenDao.DEV_ZEN_EMERGENCY_CHANGE_GUEST(), devZenDao, msg.sender, "emergency_ChangeTheGuestGeneric(bytes32[])", params); - } - - function moveToNextEpisodeAuto(bool _guestHasCome) public returns(address proposalOut) { - emit MoveToNextEpisodeAuto(); - bytes32[] memory params = new bytes32[](1); - if(_guestHasCome){ - params[0] = bytes32(1); - }else{ - params[0] = bytes32(0); - } - return doAction(devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), devZenDao, msg.sender, "moveToNextEpisodeGeneric(bytes32[])", params); - } - -} diff --git a/contracts/3-DevZenDao/DevZenDaoAutoTestable.sol b/contracts/3-DevZenDao/DevZenDaoAutoTestable.sol deleted file mode 100644 index ae694c0..0000000 --- a/contracts/3-DevZenDao/DevZenDaoAutoTestable.sol +++ /dev/null @@ -1,58 +0,0 @@ -pragma solidity ^0.4.24; -// to enable Params passing to constructor and method -pragma experimental ABIEncoderV2; - -import "@thetta/core/contracts/DaoBaseAuto.sol"; - -import "./DevZenDao.sol"; -import "./DevZenDaoCore.sol"; -import "./DevZenDaoWithUnpackersTestable.sol"; - -contract DevZenDaoAutoTestable is DaoBaseAuto{ - DevZenDaoWithUnpackersTestable devZenDao; - constructor(IDaoBase _daoBase, DevZenDaoWithUnpackersTestable _devZenDao) public DaoBaseAuto(_daoBase){ - devZenDao = _devZenDao; - } - - function updateDaoParamsAuto(bytes32 _param, uint _value) public returns(address proposalOut) { - bytes32[] memory params = new bytes32[](2); - params[0] = _param; - params[1] = bytes32(_value); - return doAction(devZenDao.DEV_ZEN_UPDATE_DAO_PARAMS(), daoBase, msg.sender, "updateDaoParamsGeneric(bytes32[])", params); - } - - function withdrawEtherAuto(address _output) public returns(address proposalOut) { - bytes32[] memory params = new bytes32[](1); - params[0] = bytes32(_output); - return doAction(devZenDao.DEV_ZEN_WITHDRAW_ETHER(), devZenDao, msg.sender, "withdrawEtherGeneric(bytes32[])", params); - } - - function selectNextHostAuto(address _nextHost) public returns(address proposalOut) { - bytes32[] memory params = new bytes32[](1); - params[0] = bytes32(_nextHost); - return doAction(devZenDao.DEV_ZEN_SELECT_NEXT_HOST(), devZenDao, msg.sender, "selectNextHostGeneric(bytes32[])", params); - } - - function changeTheGuestAuto(address _guest) public returns(address proposalOut) { - bytes32[] memory params = new bytes32[](1); - params[0] = bytes32(_guest); - return doAction(devZenDao.DEV_ZEN_CHANGE_GUEST(), devZenDao, msg.sender, "changeTheGuestGeneric(bytes32[])", params); - } - - function emergency_ChangeTheGuestAuto(address _guest) public returns(address proposalOut) { - bytes32[] memory params = new bytes32[](1); - params[0] = bytes32(_guest); - return doAction(devZenDao.DEV_ZEN_EMERGENCY_CHANGE_GUEST(), devZenDao, msg.sender, "emergency_ChangeTheGuestGeneric(bytes32[])", params); - } - - function moveToNextEpisodeAuto(bool _guestHasCome) public returns(address proposalOut) { - bytes32[] memory params = new bytes32[](1); - if(_guestHasCome){ - params[0] = bytes32(1); - }else{ - params[0] = bytes32(0); - } - return doAction(devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), devZenDao, msg.sender, "moveToNextEpisodeGeneric(bytes32[])", params); - } - -} diff --git a/contracts/3-DevZenDao/DevZenDaoCore.sol b/contracts/3-DevZenDao/DevZenDaoCore.sol deleted file mode 100644 index af53c67..0000000 --- a/contracts/3-DevZenDao/DevZenDaoCore.sol +++ /dev/null @@ -1,303 +0,0 @@ -pragma solidity ^0.4.24; - -// to enable Params passing to constructor and method -pragma experimental ABIEncoderV2; - -import "@thetta/core/contracts/DaoBase.sol"; -import "@thetta/core/contracts/DaoClient.sol"; -import "@thetta/core/contracts/DaoStorage.sol"; -import "@thetta/core/contracts/tokens/StdDaoToken.sol"; -import "zeppelin-solidity/contracts/ownership/Ownable.sol"; -/** - * @title DevZenDaoCore - * @dev This is the DAO for russian most famous "for hard-core developers only" podcast. - * I was a guest of show #198 (July 30, 2018) - * We discussed how Thetta can be applied to their structure. You can read the blog post here - TODO. - * - * ## Requirements: - * - * 1) Any listener can get a ERC20 “devzen” tokens by sending X ETHers to the DevZen DAO and becomes a “patron” (i.e. token holder). - * 2) Any patron can use DevZen tokens to run ads: Burn k tokens to add your add into the slot (linear, no priority). - * 3) Any team member can use Reputation to govern the DAO, i.e., change the parameters. Also, reputation is used in the votes to select the next host and to add or remove moderator. - * 4) To become a guest, a listener has to become a patron first (i.e., they have to buy some DevZen tokens), then they must stake S tokens for D days. After the show has ended, S tokens are returned to the patron. If the guest missed the show (that is bad), the tokens are burned. - * - * ## Token model (example): - * - * DevZen tokens are minted each week: - * 10 tokens for 5 ads slots - * 0 free floating tokens - * DevZen tokens are burned: - * 2 tokens per 1 ads slot (if ads is running in the current episode) - * Reputation tokens are minted each week: - * 2 tokens as reputation incentive for 1 host - * 2 tokens as reputation incentive for 4 moderators - * 1 tokens as incentive for 1 guest -*/ -contract DevZenDaoCore is DaoClient { - StdDaoToken public devZenToken; - StdDaoToken public repToken; - NextEpisode public nextEpisode; - - bytes32 public constant DEV_ZEN_UPDATE_DAO_PARAMS = keccak256("DevZen_updateDaoParams"); - bytes32 public constant DEV_ZEN_WITHDRAW_ETHER = keccak256("DevZen_withdrawEther"); - bytes32 public constant DEV_ZEN_SELECT_NEXT_HOST = keccak256("DevZen_selectNextHost"); - bytes32 public constant DEV_ZEN_CHANGE_GUEST = keccak256("DevZen_changeGuest"); - bytes32 public constant DEV_ZEN_EMERGENCY_CHANGE_GUEST = keccak256("DevZen_emergencyChangeGuest"); - bytes32 public constant DEV_ZEN_MOVE_TO_NEXT_EPISODE = keccak256("DevZen_moveToNextEpisode"); - - bytes32 public constant MINT_TOKENS_PER_WEEK_AMOUNT = 0xc9b51a76ddd807905ae4f432305a7941a6eeed3018a217456051bf48a64b23cc; - bytes32 public constant MINT_REPUTATION_TOKENS_PER_WEEK_AMOUNT = 0xf62293a5f827624aae2cb3ccf2a626acfb00192eb976ac25c0b6fcfe9099f109; - bytes32 public constant ONE_AD_SLOT_PRICE = 0x2fc30c0260b9c2120dbb43e5716b23b323cb0059511c89856fe497bcaf93cbe0; - bytes32 public constant ONE_TOKEN_PRICE_IN_WEI = 0x1d18f55c54a96a26d4aaa596d526372f95c7cef9f217e9bbe766cea168596907; - bytes32 public constant BECOME_GUEST_STAKE = 0x3016d4c48f6a1e0a92b321085915d5914a9ab2c36783443e2b6066054b37f7c4; - bytes32 public constant REP_TOKENS_REWARD_HOST = 0x91a208a4a1aa03cdcf19de90fdf6add60ea8d103a63e151f2b189cc77dfc8cf7; - bytes32 public constant REP_TOKENS_REWARD_GUEST = 0x9cf4c579edc10b766d99450c69f14a06144239d4923ded8d12e0a7d6ec69a048; - bytes32 public constant REP_TOKENS_REWARD_TEAM_MEMBERS = 0x8097db39df04019c8a72c19c6369ebda43741c8e2a45d27badc3e4ff8ecc3d0b; - - event DevZenDaoCore_WithdrawEther(address _output); - event DevZenDaoCore_SelectNextHost(address _nextHost); - event DevZenDaoCore_ChangeTheGuest(address _guest); - event DevZenDaoCore_BurnGuestStake(); - event DevZenDaoCore_Emergency_ChangeTheGuest(address _guest); - event DevZenDaoCore_MoveToNextEpisode(bool _guestHasCome); - event DevZenDaoCore_RunAdsInTheNextEpisode(string _adText); - event DevZenDaoCore_BecomeTheNextShowGuest(); - event DevZenDaoCore_BuyTokens(); - event DevZenDaoCore_IsOneWeekPassed(); - event DevZenDaoCore_SetGuest(address _guest); - - event SetParam(bytes32 _param, uint _value); - - mapping (bytes32 => uint) public params; - - // this is changed each week in 'moveToNextEpisode' method - struct NextEpisode { - address nextShowHost; - address nextShowGuest; - address prevShowHost; - address prevShowGuest; - string[] adSlots; - uint usedSlots; - uint createdAt; - bool isEmergencyGuest; - } - - constructor(IDaoBase _daoBase, address[] _tokens) public DaoClient(_daoBase){ - devZenToken = StdDaoToken(_tokens[0]); - repToken = StdDaoToken(_tokens[1]); - } - // --------------------------------------------- - // These methods should be called by DevZen team: - //---------------------------------------------- - /** - * @dev Change the DAO parameters - */ - function _setParam(bytes32 _param, uint _value) internal { - emit SetParam(_param, _value); - params[_param] = _value; - } - - /** - * @dev Withdraw all collected ETH to the _output. - */ - function _withdrawEther(address _output) internal { - emit DevZenDaoCore_WithdrawEther(_output); - // TODO: better to use moneyflow instead of _output - // Specifying _output can lead to hacks and money loss! - _output.transfer(address(this).balance); - } - - /** - * @dev Select next episode's host - */ - function _selectNextHost(address _nextHost) internal { - emit DevZenDaoCore_SelectNextHost(_nextHost); - // 1 - check if host is still not selected - require(0x0==nextEpisode.nextShowHost); - // 2 - select next host - nextEpisode.nextShowHost = _nextHost; - } - - /** - * @dev Guest did not appear -> penalize him) - */ - function _burnGuestStake() internal { - emit DevZenDaoCore_BurnGuestStake(); - daoBase.burnTokens(devZenToken, address(this), params[BECOME_GUEST_STAKE]); - } - - /** - * @dev Changes the guest in "legal" way - * @param _guest New guest address - * When guest is changed via this function we ensure that stake is returned to previous guest. - */ - function _changeTheGuest(address _guest) internal { - emit DevZenDaoCore_ChangeTheGuest(_guest); - // 0 - check that next show guest exists - require(0x0 != nextEpisode.nextShowGuest); - // 1 - save previous guest address for future use - address prevGuest = nextEpisode.nextShowGuest; - // 2 - set the new guest - _setGuest(_guest); - // 3 - if previous guest is not emergency guest then return stake - if(!nextEpisode.isEmergencyGuest) { - devZenToken.transfer(prevGuest, params[BECOME_GUEST_STAKE]); - } - // 4 - mark guest as legal - nextEpisode.isEmergencyGuest = false; - } - - /** - * @dev Set the guest (emergency) - * In normal circumst. people should use 'becomeTheNextShowGuest' method. - * However, sometimes DevZen team should be able to fix the next guest! - */ - function _emergency_ChangeTheGuest(address _guest) internal { - // emit DevZenDaoCore_Emergency_ChangeTheGuest(_guest); - // 1 - check that next show guest exists - require(nextEpisode.nextShowGuest != 0x0); - // 2 - set next show guest - nextEpisode.nextShowGuest = _guest; - // 3 - mark guest as emergency guest - nextEpisode.isEmergencyGuest = true; - } - - /** - * @dev Move to next episode - * @param _guestHasCome Whether the guest(initual or emergency) has come to the show - * Should be called right AFTER the recording of the current episode - */ - function _moveToNextEpisode(bool _guestHasCome) internal { - emit DevZenDaoCore_MoveToNextEpisode(_guestHasCome); - // 1 - check if 1 week is passed - require(_isOneWeekPassed()); - // 2 - mint tokens - // We are minting X tokens to this address (to the DevZen DAO contract itself) - // Current contract is the owner of the devZenToken contract, so it can do anything with it (mint/burn tokens) - daoBase.issueTokens(address(devZenToken), address(this), params[MINT_TOKENS_PER_WEEK_AMOUNT]); - daoBase.issueTokens(address(repToken), address(this), params[MINT_REPUTATION_TOKENS_PER_WEEK_AMOUNT]); - // 3 - clear next host and next guest - nextEpisode.prevShowHost = nextEpisode.nextShowHost; - nextEpisode.prevShowGuest = nextEpisode.nextShowGuest; - nextEpisode.nextShowHost = 0x0; - nextEpisode.nextShowGuest = 0x0; - nextEpisode.usedSlots = 0; - nextEpisode.createdAt = now; - // 4 - mint DZTREP tokens to the Guest - if(_guestHasCome) { - daoBase.issueTokens(address(repToken), nextEpisode.prevShowGuest, params[REP_TOKENS_REWARD_GUEST]); - } - // 5 - mint some reputation tokens to the Host - daoBase.issueTokens(address(repToken), nextEpisode.prevShowHost, params[REP_TOKENS_REWARD_HOST]); - // TODO: - // 6 - mint some reputation tokens to the rest of the DevZen team! - uint teamMembers = daoBase.getMembersCount("DevZenTeam"); - assert(teamMembers>=1); - uint perMember = params[REP_TOKENS_REWARD_TEAM_MEMBERS] / (teamMembers - 1); - address member; - for(uint i=0; i= tokensToPurchase); - // 3 - if ok -> transfer tokens to the msg.sender - devZenToken.transfer(msg.sender, tokensToPurchase); - } - - /** - * @dev Check that 1 week has passed since the last episode - * @return true if 1 week has passed else false - */ - function _isOneWeekPassed() internal view returns(bool) { - emit DevZenDaoCore_IsOneWeekPassed(); - // return true if this is the 1st episode - if(nextEpisode.createdAt == 0) return true; - return nextEpisode.createdAt + 7 days <= now; - } - - // do not allow to send ETH here. Instead use buyTokens method - function(){ - revert(); - } - - //----------------------------------------------- - // These are helper methods for usage in contract - //----------------------------------------------- - /** - * @dev Sets the guest for next show in "legal" way - * @param _guest New guest address - * New guest should have enough DZT and should allow current contract to transfer his stake - */ - function _setGuest(address _guest) internal { - // emit DevZenDaoCore_SetGuest(_guest); - // 0 - check that guest has required amount of tokens - require(devZenToken.balanceOf(_guest) >= params[BECOME_GUEST_STAKE]); - // 1 - check that guest has allowed current contract to put 5 DZT at stake - require(devZenToken.allowance(_guest, address(this)) >= params[BECOME_GUEST_STAKE]); - // 3 - lock tokens, transfer tokens from guest to current contract - devZenToken.transferFrom(_guest, address(this), params[BECOME_GUEST_STAKE]); - // 4 - select next guest - - nextEpisode.nextShowGuest = _guest; - } -} diff --git a/contracts/3-DevZenDao/DevZenDaoFactory.sol b/contracts/3-DevZenDao/DevZenDaoFactory.sol deleted file mode 100644 index 9b77a50..0000000 --- a/contracts/3-DevZenDao/DevZenDaoFactory.sol +++ /dev/null @@ -1,129 +0,0 @@ -pragma solidity ^0.4.22; - -// to enable Params passing to constructor and method -pragma experimental ABIEncoderV2; - -import "@thetta/core/contracts/DaoBaseWithUnpackers.sol"; -import "@thetta/core/contracts/IDaoBase.sol"; -import "@thetta/core/contracts/DaoStorage.sol"; -import "@thetta/core/contracts/DaoBaseAuto.sol"; -import "@thetta/core/contracts/tokens/StdDaoToken.sol"; -import "@thetta/core/contracts/utils/UtilsLib.sol"; - -import "./DevZenDao.sol"; -import "./DevZenDaoAuto.sol"; -import "./DevZenDaoCore.sol"; - -import "./DevZenDaoWithUnpackers.sol"; - -// DevZen tokens: -// 10 tokens for 5 ads slots -// 0 free floating tokens -// Reputation tokens: -// 2 tokens as reputation incentive for 1 host -// 2 tokens as reputation incentive for 4 moderators -// 1 tokens as incentive for 1 guest - -contract DevZenDaoFactory { - DevZenDaoWithUnpackers public devZenDao; - DaoBaseWithUnpackers public daoBase; - DaoStorage store; - DevZenDaoAuto public devZenDaoAuto; - - constructor(address _boss, address[] _devZenTeam) public{ - createDao(_boss, _devZenTeam); - setupDevZenDaoAuto(); - daoBase.renounceOwnership(); - } - - function createDao(address _boss, address[] _devZenTeam) internal returns(address) { - StdDaoToken devZenToken = new StdDaoToken("DevZenToken", "DZT", 18, true, true, 10**25); - StdDaoToken repToken = new StdDaoToken("DevZenRepToken", "DZTREP", 18, true, true, 10**25); - - address[] tokens; - tokens.push(address(devZenToken)); - tokens.push(address(repToken)); - store = new DaoStorage(tokens); - daoBase = new DaoBaseWithUnpackers(store); - - createNewContract(IDaoBase(daoBase), tokens); - - store.allowActionByAddress(daoBase.MANAGE_GROUPS(),address(this)); - store.allowActionByAddress(daoBase.ISSUE_TOKENS(),address(devZenDao)); - store.allowActionByAddress(daoBase.BURN_TOKENS(),address(devZenDao)); - store.allowActionByAddress(devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), _boss); - store.allowActionByAddress(devZenDao.DEV_ZEN_UPDATE_DAO_PARAMS(), address(this)); - store.transferOwnership(daoBase); - - devZenDao.setParam(devZenDao.MINT_TOKENS_PER_WEEK_AMOUNT(), 10 * 10**18); - devZenDao.setParam(devZenDao.MINT_REPUTATION_TOKENS_PER_WEEK_AMOUNT(), 5 * 10**18); - devZenDao.setParam(devZenDao.ONE_AD_SLOT_PRICE(), 2 * 10**18); // Current ETH price is ~$450. One token will be worth ~$45. One ad will cost ~$90 (2 tokens) - devZenDao.setParam(devZenDao.ONE_TOKEN_PRICE_IN_WEI(), 10**17); //) To become a guest user should put 5 tokens at stake - devZenDao.setParam(devZenDao.BECOME_GUEST_STAKE(), 5 * 10**18); - devZenDao.setParam(devZenDao.REP_TOKENS_REWARD_HOST(), 2 * 10**18); - devZenDao.setParam(devZenDao.REP_TOKENS_REWARD_GUEST(), 1 * 10**18); - devZenDao.setParam(devZenDao.REP_TOKENS_REWARD_TEAM_MEMBERS(), 2 * 10**18); - - devZenToken.transferOwnership(daoBase); - repToken.transferOwnership(daoBase); - - // 2 - setup - daoBase.addGroupMember("DevZenTeam", _boss); - - uint i = 0; - for(i=0; i<_devZenTeam.length; ++i){ - daoBase.addGroupMember("DevZenTeam", _devZenTeam[i]); - } - - // 1 - set DevZenTeam group permissions - daoBase.allowActionByAnyMemberOfGroup(daoBase.ADD_NEW_PROPOSAL(),"DevZenTeam"); - daoBase.allowActionByVoting(daoBase.MANAGE_GROUPS(), devZenDao.repToken()); - daoBase.allowActionByVoting(daoBase.UPGRADE_DAO_CONTRACT(), devZenDao.repToken()); - - // 2 - set custom DevZenTeam permissions - daoBase.allowActionByVoting(devZenDao.DEV_ZEN_UPDATE_DAO_PARAMS(), devZenDao.repToken()); - daoBase.allowActionByVoting(devZenDao.DEV_ZEN_WITHDRAW_ETHER(), devZenDao.repToken()); - daoBase.allowActionByVoting(devZenDao.DEV_ZEN_SELECT_NEXT_HOST(), devZenDao.repToken()); - daoBase.allowActionByVoting(devZenDao.DEV_ZEN_CHANGE_GUEST(), devZenDao.repToken()); - daoBase.allowActionByVoting(devZenDao.DEV_ZEN_EMERGENCY_CHANGE_GUEST(), devZenDao.repToken()); - daoBase.allowActionByVoting(devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), devZenDao.repToken()); - - // 3 - return - // - return devZenDao; - } - - function createNewContract(IDaoBase _daoBase, address[] _tokens) internal { - devZenDao = new DevZenDaoWithUnpackers(_daoBase, _tokens); - } - - function setupDevZenDaoAuto() internal { - // TODO: add all custom actions to the DaoBaseAuto derived contract - - devZenDaoAuto = new DevZenDaoAuto(IDaoBase(daoBase), devZenDao); - - daoBase.allowActionByAddress(daoBase.ADD_NEW_PROPOSAL(), devZenDaoAuto); - daoBase.allowActionByAddress(daoBase.MANAGE_GROUPS(), devZenDaoAuto); - daoBase.allowActionByAddress(daoBase.UPGRADE_DAO_CONTRACT(), devZenDaoAuto); - - daoBase.allowActionByAddress(devZenDao.DEV_ZEN_UPDATE_DAO_PARAMS(), devZenDaoAuto); - daoBase.allowActionByAddress(devZenDao.DEV_ZEN_WITHDRAW_ETHER(), devZenDaoAuto); - daoBase.allowActionByAddress(devZenDao.DEV_ZEN_SELECT_NEXT_HOST(), devZenDaoAuto); - daoBase.allowActionByAddress(devZenDao.DEV_ZEN_CHANGE_GUEST(), devZenDaoAuto); - daoBase.allowActionByAddress(devZenDao.DEV_ZEN_EMERGENCY_CHANGE_GUEST(), devZenDaoAuto); - daoBase.allowActionByAddress(devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), devZenDaoAuto); - - uint VOTING_TYPE_1P1V = 1; - devZenDaoAuto.setVotingParams(daoBase.MANAGE_GROUPS(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(daoBase.REMOVE_GROUP_MEMBER(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(daoBase.UPGRADE_DAO_CONTRACT(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(devZenDao.DEV_ZEN_UPDATE_DAO_PARAMS(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(devZenDao.DEV_ZEN_WITHDRAW_ETHER(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(devZenDao.DEV_ZEN_SELECT_NEXT_HOST(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(devZenDao.DEV_ZEN_CHANGE_GUEST(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(devZenDao.DEV_ZEN_EMERGENCY_CHANGE_GUEST(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - - devZenDaoAuto.transferOwnership(daoBase); - } -} diff --git a/contracts/3-DevZenDao/DevZenDaoFactoryTestable.sol b/contracts/3-DevZenDao/DevZenDaoFactoryTestable.sol deleted file mode 100644 index 0ecbbe9..0000000 --- a/contracts/3-DevZenDao/DevZenDaoFactoryTestable.sol +++ /dev/null @@ -1,117 +0,0 @@ -pragma solidity ^0.4.24; - -// to enable Params passing to constructor and method -pragma experimental ABIEncoderV2; - -import "@thetta/core/contracts/IDaoBase.sol"; -import "@thetta/core/contracts/DaoBaseWithUnpackers.sol"; - -import "./DevZenDaoFactory.sol"; -import "./DevZenDaoTestable.sol"; -import "./DevZenDaoAutoTestable.sol"; -import "./DevZenDaoWithUnpackersTestable.sol"; -import "./DevZenDaoCore.sol"; - -contract DevZenDaoFactoryTestable { - DevZenDaoWithUnpackersTestable public devZenDao; - DaoBaseWithUnpackers public daoBase; - DaoStorage store; - DevZenDaoAutoTestable public devZenDaoAuto; - - constructor(address _boss, address[] _devZenTeam) public{ - createDao(_boss, _devZenTeam); - setupDevZenDaoAuto(); - daoBase.renounceOwnership(); - } - - function createDao(address _boss, address[] _devZenTeam) internal returns(address) { - StdDaoToken devZenToken = new StdDaoToken("DevZenToken", "DZT", 18, true, true, 10**25); - StdDaoToken repToken = new StdDaoToken("DevZenRepToken", "DZTREP", 18, true, true, 10**25); - - address[] tokens; - tokens.push(address(devZenToken)); - tokens.push(address(repToken)); - store = new DaoStorage(tokens); - daoBase = new DaoBaseWithUnpackers(store); - - createNewContract(IDaoBase(daoBase), tokens); - - store.allowActionByAddress(daoBase.MANAGE_GROUPS(),address(this)); - store.allowActionByAddress(daoBase.ISSUE_TOKENS(),address(devZenDao)); - store.allowActionByAddress(daoBase.BURN_TOKENS(),address(devZenDao)); - store.allowActionByAddress(devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), _boss); - store.transferOwnership(daoBase); - - devZenDao.setParam(devZenDao.MINT_TOKENS_PER_WEEK_AMOUNT(), 10 * 10**18); - devZenDao.setParam(devZenDao.MINT_REPUTATION_TOKENS_PER_WEEK_AMOUNT(), 5 * 10**18); - devZenDao.setParam(devZenDao.ONE_AD_SLOT_PRICE(), 2 * 10**18); // Current ETH price is ~$450. One token will be worth ~$45. One ad will cost ~$90 (2 tokens) - devZenDao.setParam(devZenDao.ONE_TOKEN_PRICE_IN_WEI(), 10**17); //) To become a guest user should put 5 tokens at stake - devZenDao.setParam(devZenDao.BECOME_GUEST_STAKE(), 5 * 10**18); - devZenDao.setParam(devZenDao.REP_TOKENS_REWARD_HOST(), 2 * 10**18); - devZenDao.setParam(devZenDao.REP_TOKENS_REWARD_GUEST(), 1 * 10**18); - devZenDao.setParam(devZenDao.REP_TOKENS_REWARD_TEAM_MEMBERS(), 2 * 10**18); - - devZenToken.transferOwnership(daoBase); - repToken.transferOwnership(daoBase); - - // 2 - setup - daoBase.addGroupMember("DevZenTeam", _boss); - - uint i = 0; - for(i=0; i<_devZenTeam.length; ++i){ - daoBase.addGroupMember("DevZenTeam", _devZenTeam[i]); - } - - // 1 - set DevZenTeam group permissions - daoBase.allowActionByAnyMemberOfGroup(daoBase.ADD_NEW_PROPOSAL(),"DevZenTeam"); - daoBase.allowActionByVoting(daoBase.MANAGE_GROUPS(), devZenDao.repToken()); - daoBase.allowActionByVoting(daoBase.UPGRADE_DAO_CONTRACT(), devZenDao.repToken()); - - // 2 - set custom DevZenTeam permissions - daoBase.allowActionByVoting(devZenDao.DEV_ZEN_UPDATE_DAO_PARAMS(), devZenDao.repToken()); - daoBase.allowActionByVoting(devZenDao.DEV_ZEN_WITHDRAW_ETHER(), devZenDao.repToken()); - daoBase.allowActionByVoting(devZenDao.DEV_ZEN_SELECT_NEXT_HOST(), devZenDao.repToken()); - daoBase.allowActionByVoting(devZenDao.DEV_ZEN_CHANGE_GUEST(), devZenDao.repToken()); - daoBase.allowActionByVoting(devZenDao.DEV_ZEN_EMERGENCY_CHANGE_GUEST(), devZenDao.repToken()); - daoBase.allowActionByVoting(devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), devZenDao.repToken()); - - // 3 - return - // - return devZenDao; - } - - function createNewContract(IDaoBase _daoBase, address[] _tokens) internal { - devZenDao = new DevZenDaoWithUnpackersTestable(_daoBase, _tokens); - } - - function setupDevZenDaoAuto() internal { - // TODO: add all custom actions to the DaoBaseAuto derived contract - - devZenDaoAuto = new DevZenDaoAutoTestable(IDaoBase(daoBase), devZenDao); - - daoBase.allowActionByAddress(daoBase.ADD_NEW_PROPOSAL(), devZenDaoAuto); - daoBase.allowActionByAddress(daoBase.MANAGE_GROUPS(), devZenDaoAuto); - daoBase.allowActionByAddress(daoBase.UPGRADE_DAO_CONTRACT(), devZenDaoAuto); - - daoBase.allowActionByAddress(devZenDao.DEV_ZEN_UPDATE_DAO_PARAMS(), devZenDaoAuto); - daoBase.allowActionByAddress(devZenDao.DEV_ZEN_WITHDRAW_ETHER(), devZenDaoAuto); - daoBase.allowActionByAddress(devZenDao.DEV_ZEN_SELECT_NEXT_HOST(), devZenDaoAuto); - daoBase.allowActionByAddress(devZenDao.DEV_ZEN_CHANGE_GUEST(), devZenDaoAuto); - daoBase.allowActionByAddress(devZenDao.DEV_ZEN_EMERGENCY_CHANGE_GUEST(), devZenDaoAuto); - daoBase.allowActionByAddress(devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), devZenDaoAuto); - - uint VOTING_TYPE_1P1V = 1; - devZenDaoAuto.setVotingParams(daoBase.MANAGE_GROUPS(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(daoBase.REMOVE_GROUP_MEMBER(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(daoBase.UPGRADE_DAO_CONTRACT(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(devZenDao.DEV_ZEN_UPDATE_DAO_PARAMS(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(devZenDao.DEV_ZEN_WITHDRAW_ETHER(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(devZenDao.DEV_ZEN_SELECT_NEXT_HOST(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(devZenDao.DEV_ZEN_CHANGE_GUEST(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(devZenDao.DEV_ZEN_EMERGENCY_CHANGE_GUEST(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - devZenDaoAuto.setVotingParams(devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("DevZenTeam"), bytes32(65), bytes32(65), 0); - - devZenDaoAuto.transferOwnership(daoBase); - } - -} \ No newline at end of file diff --git a/contracts/3-DevZenDao/DevZenDaoTestable.sol b/contracts/3-DevZenDao/DevZenDaoTestable.sol deleted file mode 100644 index c235b75..0000000 --- a/contracts/3-DevZenDao/DevZenDaoTestable.sol +++ /dev/null @@ -1,133 +0,0 @@ - -pragma solidity ^0.4.24; - -// to enable Params passing to constructor and method -pragma experimental ABIEncoderV2; - -import "@thetta/core/contracts/DaoBase.sol"; -import "@thetta/core/contracts/IDaoBase.sol"; -import "@thetta/core/contracts/tokens/StdDaoToken.sol"; - -import "./DevZenDaoCore.sol"; - -/** - * @title DevZenDaoTestable - * @dev DevZenDaoTestable is for testing DevZenDaoCore. - * The difference between DevZenDao and DevZenDaoTestable is that there are no Thetta's isCanDo() modifiers in DevZenDaoTestable - * which helps in testing only the logic. - */ -contract DevZenDaoTestable is DevZenDaoCore { - - constructor(IDaoBase _daoBase, address[] _tokens) public - DevZenDaoCore(_daoBase, _tokens) {} - - // --------------------------------------------- - // These methods should be called by DevZen team: - //---------------------------------------------- - - /** - * @dev Change the DAO parameters - */ - function setParam(bytes32 _param, uint _value) public { - super._setParam(_param, _value); - } - - /** - * @dev Withdraw all collected ETH to the _output. - */ - function withdrawEther(address _output) public { - super._withdrawEther(_output); - } - - /** - * @dev Select next episode's host - */ - function selectNextHost(address _nextHost) public { - super._selectNextHost(_nextHost); - } - - /** - * @dev Guest did not appear -> penalize him) - */ - function burnGuestStake() public { - super._burnGuestStake(); - } - - /** - * @dev Changes the guest in "legal" way - */ - function changeTheGuest(address _guest) public { - super._changeTheGuest(_guest); - } - - /** - * @dev Set the guest (emergency) - * In normal circumst. people should use 'becomeTheNextShowGuest' method. - * However, sometimes DevZen team should be able to fix the next guest! - */ - function emergency_ChangeTheGuest(address _guest) public { - super._emergency_ChangeTheGuest(_guest); - } - - /** - * @dev Move to next episode - * @param _guestHasCome Whether the guest(initual or emergency) has come to the show - * Should be called right AFTER the recording of the current episode - */ - function moveToNextEpisode(bool _guestHasCome) public { - super._moveToNextEpisode(_guestHasCome); - } - - // ------------------------------------------------------ - // These methods should be called by DevZen token holders - // ------------------------------------------------------ - - // Any patron (DevZen token holder) can use DevZen tokens to run ads: Burn k tokens to add your add into the slot (linear, no priority). - function runAdsInTheNextEpisode(string _adText) public { - super._runAdsInTheNextEpisode(_adText); - } - - /** - * @dev Become the next guest. - * To become a guest sender should buy 5 DZT and approve dao to put them at stake. Sender will get back tokens after the show. - */ - function becomeTheNextShowGuest() public { - super._becomeTheNextShowGuest(); - } - - // ---------------------------------------------- - // These methods should be called by any address: - // ---------------------------------------------- - - /** - * @dev Any listener can get a ERC20 “devzen” tokens by sending X ETHers to the DevZen DAO and becomes a “patron” (i.e. token holder). - */ - function buyTokens() external payable { - super._buyTokens(); - } - - /** - * @dev Check that 1 week has passed since the last episode - * @return true if 1 week has passed else false - */ - function isOneWeekPassed() public view returns(bool) { - return super._isOneWeekPassed(); - } - - // do not allow to send ETH here. Instead use buyTokens method - function() { - revert(); - } - - //----------------------------------------------- - // These are helper methods for usage in contract - //----------------------------------------------- - - /** - * @dev Sets the guest for next show in "legal" way - */ - function setGuest(address _guest) public { - super._setGuest(_guest); - } - -} \ No newline at end of file diff --git a/contracts/3-DevZenDao/DevZenDaoWithUnpackers.sol b/contracts/3-DevZenDao/DevZenDaoWithUnpackers.sol deleted file mode 100644 index 03d8f7c..0000000 --- a/contracts/3-DevZenDao/DevZenDaoWithUnpackers.sol +++ /dev/null @@ -1,43 +0,0 @@ -pragma solidity ^0.4.24; -pragma experimental ABIEncoderV2; - -import "@thetta/core/contracts/utils/UtilsLib.sol"; -import "@thetta/core/contracts/DaoBase.sol"; -import "./DevZenDao.sol"; - -contract DevZenDaoWithUnpackers is DevZenDao { - constructor(IDaoBase _daoBase, address[] _tokens) public - DevZenDao(_daoBase, _tokens){} - - function updateDaoParamsGeneric(bytes32[] _params) external { - bytes32 param = _params[0]; - uint value = uint(_params[1]); - setParam(param, value); - } - - function withdrawEtherGeneric(bytes32[] _params) external { - address output = address(_params[0]); - withdrawEther(output); - } - - function selectNextHostGeneric(bytes32[] _params) external { - address nextHost = address(_params[0]); - selectNextHost(nextHost); - } - - function changeTheGuestGeneric(bytes32[] _params) external { - address guest = address(_params[0]); - changeTheGuest(guest); - } - - function emergency_ChangeTheGuestGeneric(bytes32[] _params) external { - address guest = address(_params[0]); - emergency_ChangeTheGuest(guest); - } - - function moveToNextEpisodeGeneric(bytes32[] _params) external { - uint guestHasCome = uint(_params[0]); // TypeError: Explicit type conversion not allowed from "bytes32" to "bool" - moveToNextEpisode(guestHasCome==1); - } - -} diff --git a/contracts/3-DevZenDao/DevZenDaoWithUnpackersTestable.sol b/contracts/3-DevZenDao/DevZenDaoWithUnpackersTestable.sol deleted file mode 100644 index 7334917..0000000 --- a/contracts/3-DevZenDao/DevZenDaoWithUnpackersTestable.sol +++ /dev/null @@ -1,44 +0,0 @@ -pragma solidity ^0.4.24; -pragma experimental ABIEncoderV2; - -import "@thetta/core/contracts/utils/UtilsLib.sol"; -import "@thetta/core/contracts/DaoBase.sol"; -import "./DevZenDao.sol"; -import "./DevZenDaoTestable.sol"; - -contract DevZenDaoWithUnpackersTestable is DevZenDaoTestable { - constructor(IDaoBase _daoBase, address[] _tokens) public - DevZenDaoTestable(_daoBase, _tokens){} - - function updateDaoParamsGeneric(bytes32[] _params) external { - bytes32 param = _params[0]; - uint value = uint(_params[1]); - setParam(param, value); - } - - function withdrawEtherGeneric(bytes32[] _params) external { - address output = address(_params[0]); - withdrawEther(output); - } - - function selectNextHostGeneric(bytes32[] _params) external { - address nextHost = address(_params[0]); - selectNextHost(nextHost); - } - - function changeTheGuestGeneric(bytes32[] _params) external { - address guest = address(_params[0]); - changeTheGuest(guest); - } - - function emergency_ChangeTheGuestGeneric(bytes32[] _params) external { - address guest = address(_params[0]); - emergency_ChangeTheGuest(guest); - } - - function moveToNextEpisodeGeneric(bytes32[] _params) external { - uint guestHasCome = uint(_params[0]); // TypeError: Explicit type conversion not allowed from "bytes32" to "bool" - moveToNextEpisode(guestHasCome==1); - } - -} diff --git a/contracts/3-DevZenDao/README.md b/contracts/3-DevZenDao/README.md deleted file mode 100644 index 15dc51f..0000000 --- a/contracts/3-DevZenDao/README.md +++ /dev/null @@ -1,23 +0,0 @@ - # DevZenDao - --- - ## Description - This is the DAO for russian most famous "for hard-core developers only" podcast. - I was a guest of show #198 (July 30, 2018) - We discussed how Thetta can be applied to their structure. You can read the blog post here - TODO. -## Requirements -1) Any listener can get a ERC20 “devzen” tokens by sending X ETHers to the DevZen DAO and becomes a “patron” (i.e. token holder). -2) Any patron can use DevZen tokens to run ads: Burn k tokens to add your add into the slot (linear, no priority). -3) Any team member can use Reputation to govern the DAO, i.e., change the parameters. Also, reputation is used in the votes to select the next host and to add or remove moderator. -4) To become a guest, a listener has to become a patron first (i.e., they have to buy some DevZen tokens), then they must stake S tokens for D days. After the show has ended, S tokens are returned to the patron. If the guest missed the show (that is bad), the tokens are burned. -## Token model (example) -DevZen tokens are minted each week: - - 10 tokens for 5 ads slots - - 0 free floating tokens - -DevZen tokens are burned: - - 2 tokens per 1 ads slot (if ads is running in the current episode) - -Reputation tokens are minted each week: -- 2 tokens as reputation incentive for 1 host -- 2 tokens as reputation incentive for 4 moderators -- 1 tokens as incentive for 1 guest \ No newline at end of file diff --git a/contracts/Daico/Daico.sol b/contracts/Daico/Daico.sol index d2a73a5..06284d3 100644 --- a/contracts/Daico/Daico.sol +++ b/contracts/Daico/Daico.sol @@ -1,385 +1,512 @@ pragma solidity ^0.4.24; import "zeppelin-solidity/contracts/math/SafeMath.sol"; -import "zeppelin-solidity/contracts/ownership/Ownable.sol"; import "zeppelin-solidity/contracts/token/ERC20/ERC20.sol"; +import "./IDaico.sol"; -/** - * @title Daico - */ -contract Daico is Ownable { - +contract Daico is IDaico { using SafeMath for uint; - ERC20 public daiToken; - ERC20 public projectToken; - - address public projectOwner; - - uint public minQuorumRate; - uint public minVoteRate; - uint public tapsCount; - uint public tokenHoldersCount; - uint[] public tapAmounts; - uint[] public tapTimestampsFinishAt; - - enum VotingType { ReleaseTap, ReleaseTapDecreasedQuorum, ChangeRoadmap, ChangeRoadmapDecreasedQuorum, TerminateProject, TerminateProjectDecreasedQuorum } - enum VotingResult { Accept, Decline, QuorumNotReached, NoDecision } + event InvestEvent(uint _amount, address _sender, uint _total, uint _tapSum, uint _startedAt); + event Vote(uint _amount, address _sender, bool _vote); + + enum TapStage { + Preparing, + Investing, + Voting, + VotingDQ, + RoadmapPreparing, + RoadmapVoting, + RoadmapVotingDQ, + Success, + Terminated + } - mapping(uint => mapping(uint => uint)) public tapVotings; - mapping(uint => uint) public tapVotingsCount; + // Voting result + enum VR { + NoResult, + NoCons, + Success, + Decline + } - mapping(uint => Voting) public votings; - uint public votingsCount; + uint votesD = 7 days; + uint addVotesD = 7 days; + uint investD = 7 days; + uint roadmapD = 21 days; + uint infinity = 99999 days; + + uint quorumPercent = 70; + uint declinePercent = 80; + uint consensusPercent = 70; + + address owner; + address STOContractAddress; + ERC20 daiToken; + uint createdAt; + uint startedAt; + bool newRoadmapProposed; + uint roadmapsCount; + mapping(uint=>uint) tapToRId; // tapId -> roadmapId + mapping(uint=>Roadmap) roadmaps; // roadmapId -> roadmap + + + struct Roadmap { + uint tapsCount; + uint investorsCount; + mapping(uint=>Tap) taps; + mapping(uint=>Investor) investors; + } - mapping(uint => TapPayment) public tapPayments; + struct Investor { + address addr; + uint invested; + } - struct TapPayment { - uint amount; - uint createdAt; - bool isWithdrawn; + struct Tap { + uint funds; + uint duration; + bool isWithdrawed; + mapping(uint => Voting) votings; // 0, 1, 2, 3 – max } struct Voting { - uint tapIndex; - uint yesVotesCount; - uint noVotesCount; - uint quorumRate; - uint createdAt; - uint finishAt; - VotingType votingType; - mapping(address => bool) voted; + uint pro; + uint versus; + address[] voted; } /** - * Modifiers - */ + * @param _owner owner address + * @param _daiToken evercity token address + * @param _STOContractAddress address of the project token + * @param _returnAddress address to return tokens if project fails + * @param _tapFunds array of tap amount to invest + * @param _tapDurations array of tap durations + */ + constructor( + address _owner, + address _daiToken, + address _STOContractAddress, + address _returnAddress, + uint[] memory _tapFunds, + uint[] memory _tapDurations) public + { + require(_tapFunds.length == _tapDurations.length); + STOContractAddress = _STOContractAddress; + daiToken = ERC20(_daiToken); + owner = _owner; + createdAt = now; + + roadmaps[roadmapsCount].tapsCount = _tapFunds.length; + Tap memory tap; + for(uint tapFundsNum = 0; tapFundsNum < _tapFunds.length; tapFundsNum++) { + require(_tapDurations[tapFundsNum] > 7); + tapToRId[tapFundsNum] = 0; // just for clearness; + + tap.funds = _tapFunds[tapFundsNum]; + tap.duration = _tapDurations[tapFundsNum]*(1 days); + tap.isWithdrawed = false; + roadmaps[roadmapsCount].taps[tapFundsNum] = tap; + } + roadmapsCount += 1; + } /** - * Modifier checks that method can be called only by investor / project token holder - */ - modifier onlyInvestor() { - require(projectToken.balanceOf(msg.sender) > 0); - _; + * @dev this function will replace current roadmap to the proposed one if it was accepted + this function will be called at the first investment operation for a new roadmap + */ + function _replaceRoadmapToProposedOne() internal { + (uint curTapNum, TapStage[] memory tapStages, uint v) = getTapsInfo(); + for(uint tapNum = 0; tapNum < roadmaps[roadmapsCount - 1].tapsCount; tapNum++) { + if(tapNum > curTapNum) tapToRId[tapNum] = roadmapsCount - 1; + } } - + /** - * Modifier checks that tap index exists - */ - modifier validTapIndex(uint _tapIndex) { - require(_tapIndex < tapsCount); - _; + * @dev interface for the STOContract to add an investor + * @param _amount – token amount, that investor going to invest + * @param _investorAddress – address of an investor + */ + function addInvestor(uint _amount, address _investorAddress) public { + require(STOContractAddress == msg.sender); + (uint curTapNum, TapStage[] memory tapStages, uint votNum) = getTapsInfo(); + require(tapStages[curTapNum] == TapStage.Investing); + require(_amount > 0); + + if(newRoadmapProposed) _replaceRoadmapToProposedOne(); curTapNum += 1; + + uint rmNum = tapToRId[curTapNum]; + uint invId = _getInvestorId(_investorAddress); + + require(amountOfAllInvestments(curTapNum) + _amount <= tapAmountsSum(curTapNum)); + daiToken.transferFrom(STOContractAddress, address(this), _amount); + + bool notInvestor = (invId == roadmaps[rmNum].investorsCount); + if(notInvestor) { + uint invCount = roadmaps[rmNum].investorsCount; + roadmaps[rmNum].investors[invCount] = Investor(_investorAddress, _amount); + roadmaps[rmNum].investorsCount += 1; + } else { + roadmaps[rmNum].investors[invId].invested += _amount; + } + + + if(areAllFundsCollected(curTapNum) && (startedAt==0)) { + startedAt = now; + newRoadmapProposed = false; + } + + emit InvestEvent(_amount, _investorAddress, amountOfAllInvestments(curTapNum), tapAmountsSum(curTapNum), startedAt); } /** - * Modifier checks that voting index exists - */ - modifier validVotingIndex(uint _votingIndex) { - require(_votingIndex < votingsCount); - _; + * @param _tapNum – number of a tap + * @return are all funds for a this _tapNum collected or not + */ + function areAllFundsCollected(uint _tapNum) internal view returns(bool) { + return amountOfAllInvestments(_tapNum) >= tapAmountsSum(_tapNum); } /** - * @dev Contract constructor - * @param _daiTokenAddress address of the DAI token contract, project gets payments in DAI tokens - * @param _projectTokenAddress project token address, investors hold this token - * @param _projectOwnerAddress project owner address who can receive tap payments - * @param _tapsCount how many times project should get payments, NOTICE: we can get taps count from _tapAmounts.length but contract deployer can force so that _tapsCount != _tapAmounts.length - * @param _tapAmounts array of DAI token amounts in wei that describes how many tokens project gets per single stage - * @param _tapTimestampsFinishAt array of deadline timestamps, project should get payment before each deadline timestamp - * @param _minQuorumRate min quorum rate, 100 == 100% - * @param _minVoteRate min vote rate for proposal to be accepted/declined, 100 == 100% - * @param _tokenHoldersCount amount of token holders - */ - constructor( - address _daiTokenAddress, - address _projectTokenAddress, - address _projectOwnerAddress, - uint _tapsCount, - uint[] _tapAmounts, - uint[] _tapTimestampsFinishAt, - uint _minQuorumRate, - uint _minVoteRate, - uint _tokenHoldersCount - ) public { - // validation - require(_daiTokenAddress != address(0)); - require(_projectTokenAddress != address(0)); - require(_projectOwnerAddress != address(0)); - require(_tapsCount > 0); - require(_tapAmounts.length == _tapsCount); - require(_tapTimestampsFinishAt.length == _tapsCount); - require(_minQuorumRate > 0); - require(_minVoteRate > 0); - require(_tokenHoldersCount > 0); - // setting contract properties - daiToken = ERC20(_daiTokenAddress); - projectToken = ERC20(_projectTokenAddress); - projectOwner = _projectOwnerAddress; - tapsCount = _tapsCount; - tapAmounts = _tapAmounts; - tapTimestampsFinishAt = _tapTimestampsFinishAt; - minQuorumRate = _minQuorumRate; - minVoteRate = _minVoteRate; - tokenHoldersCount = _tokenHoldersCount; - // create initial ReleaseTap votings for all taps - for(uint i = 0; i < tapsCount; i++) { - uint createdAt = tapTimestampsFinishAt[i] - 7 days; - _createVoting(i, minQuorumRate, createdAt, tapTimestampsFinishAt[i], VotingType.ReleaseTap); + * @dev sum can vary for a different _tapNum in cases when roadmap have been changed + * @param _tapNum – number of a tap + * @return sum – sum of all gotten investments for a specific tap + */ + function amountOfAllInvestments(uint _tapNum) public view returns(uint sum) { + uint rmNum = tapToRId[_tapNum]; + uint invCount = roadmaps[rmNum].investorsCount; + for(uint invNum = 0; invNum < invCount; invNum++) { + sum += roadmaps[rmNum].investors[invNum].invested; } } - - /** - * Public methods - */ /** - * @dev Returns voting result - * @param _votingIndex voting index - * @return voting result - */ - function getVotingResult(uint _votingIndex) public view validVotingIndex(_votingIndex) returns(VotingResult) { - Voting memory voting = votings[_votingIndex]; - uint totalVotesCount = voting.yesVotesCount.add(voting.noVotesCount); - // check whether quorum is reached - if(totalVotesCount.mul(100) <= tokenHoldersCount.mul(voting.quorumRate)) { - return VotingResult.QuorumNotReached; - } - // check whether voting result is strongly accepted - if(voting.yesVotesCount.mul(100) >= totalVotesCount.mul(minVoteRate)) { - return VotingResult.Accept; + * @dev sum of all tap amounts; output can vary for a different _tapNum in cases when roadmap have been changed + * @param _tapNum – number of the tap (to get an appropriate roadmap) + * @return sum – sum of tap amounts + */ + function tapAmountsSum(uint _tapNum) public view returns(uint sum) { + uint rmNum = tapToRId[_tapNum]; + uint tapsCount = roadmaps[rmNum].tapsCount; + for(uint tapNum = 0; tapNum < tapsCount; tapNum++) { + sum += roadmaps[rmNum].taps[tapNum].funds; } - // check whether voting result is strongly declined - if(voting.noVotesCount.mul(100) >= totalVotesCount.mul(minVoteRate)) { - return VotingResult.Decline; + } + + /** + * @dev withdrawal interface for the investors; works in a cases when project fails + * @dev returns all tokens to the investors that was not spent yet + */ + function returnTokens() external { + (uint curTapNum, TapStage[] memory tapStages, uint votNum) = getTapsInfo(); + uint rmNum = tapToRId[curTapNum]; + require(tapStages[curTapNum] == TapStage.Terminated); + + uint remainder = daiToken.balanceOf(address(this)); + uint part; + Investor memory investor; + + for(uint invNum = 0; invNum = latestVoting.finishAt); - - // if investor wants to create voting of type ChangeRoadmap - if(_votingType == VotingType.ChangeRoadmap) { - // check that latest voting is of types ReleaseTap, ReleaseTapDecreasedQuorum, TerminateProject, TerminateProjectDecreasedQuorum - require(latestVoting.votingType == VotingType.ReleaseTap || latestVoting.votingType == VotingType.ReleaseTapDecreasedQuorum || latestVoting.votingType == VotingType.TerminateProject || latestVoting.votingType == VotingType.TerminateProjectDecreasedQuorum); - // if latest voting is ReleaseTap - if(latestVoting.votingType == VotingType.ReleaseTap || latestVoting.votingType == VotingType.ReleaseTapDecreasedQuorum) { - // check that latest voting result is no decision - require(votingResult == VotingResult.NoDecision); + * @return current_tap – number of the current tap + * @return tapStages array – array of a states for all tap stages + * @return current voting num – number of the current voting + */ + function getTapsInfo() public view returns(uint, TapStage[], uint) { // curren_tap, tapstages, current_voting + uint maximalTapsAmount = 0; + for(uint rmNum = 0; rmNum < roadmapsCount; rmNum++) { + if(roadmaps[rmNum].tapsCount > maximalTapsAmount) { + maximalTapsAmount = roadmaps[rmNum].tapsCount; } - // if latest voting is TerminateProject - if(latestVoting.votingType == VotingType.TerminateProject || latestVoting.votingType == VotingType.TerminateProjectDecreasedQuorum) { - // check that latest voting result is decline - require(votingResult == VotingResult.Decline); - } - // create a new voting - _createVoting(_tapIndex, minQuorumRate, now + 3 weeks, now + 4 weeks, VotingType.ChangeRoadmap); - } + } - // if investor wants to create voting of type ChangeRoadmapDecreasedQuorum - if(_votingType == VotingType.ChangeRoadmapDecreasedQuorum) { - // check that latest voting is of type ChangeRoadmap or ChangeRoadmapDecreasedQuorum - require(latestVoting.votingType == VotingType.ChangeRoadmap || latestVoting.votingType == VotingType.ChangeRoadmapDecreasedQuorum); - // check that latest voting result has not reached quorum or has no decision - require((votingResult == VotingResult.QuorumNotReached) || (votingResult == VotingResult.NoDecision)); - // create a new voting - _createVoting(_tapIndex, 50, now + 3 weeks, now + 4 weeks, VotingType.ChangeRoadmapDecreasedQuorum); - } + TapStage[] memory tapStages = new TapStage[](maximalTapsAmount); + uint start = 0; + uint tapD; + uint votNum = 0; - // if investor wants to create voting of type TerminateProject - if(_votingType == VotingType.TerminateProject) { - // check that latest voting is of types: ReleaseTap, ReleaseTapDecreasedQuorum, ChangeRoadmap, ChangeRoadmapDecreasedQuorum - require(latestVoting.votingType == VotingType.ReleaseTap || latestVoting.votingType == VotingType.ReleaseTapDecreasedQuorum || latestVoting.votingType == VotingType.ChangeRoadmap || latestVoting.votingType == VotingType.ChangeRoadmapDecreasedQuorum); - // check that latest voting result is decline - require(votingResult == VotingResult.Decline); - // create a new voting - _createVoting(_tapIndex, minQuorumRate, now, now + 2 weeks, VotingType.TerminateProject); + for(uint tapNum = 0; tapNum < maximalTapsAmount; tapNum++) { + tapD = _getTap(tapNum).duration; + (votNum, tapStages[tapNum], start) = getTapStage(tapNum, tapD, start); + if((tapStages[tapNum]!=TapStage.Success)) return (tapNum, tapStages, votNum); } - // if investor wants to create voting of type TerminateProjectDecreasedQuorum - if(_votingType == VotingType.TerminateProjectDecreasedQuorum) { - // check that latest voting is of type TerminateProject or TerminateProjectDecreasedQuorum - require(latestVoting.votingType == VotingType.TerminateProject || latestVoting.votingType == VotingType.TerminateProjectDecreasedQuorum); - // check that latest voting result has not reached quorum or has no decision - require((votingResult == VotingResult.QuorumNotReached) || (votingResult == VotingResult.NoDecision)); - // create a new voting - _createVoting(_tapIndex, 50, now, now + 2 weeks, VotingType.TerminateProjectDecreasedQuorum); - } - } - - /** - * @dev Voting by investor - * @param _votingIndex voting index - * @param _isYes positive/negative decision - */ - function vote(uint _votingIndex, bool _isYes) external onlyInvestor validVotingIndex(_votingIndex) { - // validation - require(now >= votings[_votingIndex].createdAt); - require(now < votings[_votingIndex].finishAt); - require(!votings[_votingIndex].voted[msg.sender]); - require(!isProjectTerminated()); - // vote - votings[_votingIndex].voted[msg.sender] = true; - if(_isYes) { - votings[_votingIndex].yesVotesCount = votings[_votingIndex].yesVotesCount.add(1); - } else { - votings[_votingIndex].noVotesCount = votings[_votingIndex].noVotesCount.add(1); - } + return (tapNum, tapStages, votNum); } /** - * Evercity member / owner methods - */ + * @param _tapNum – number of the tap + * @param _tapD – tap duration + * @param _start – start time of the current tap + * @return current voting num – number of the current voting + * @return tapStage – state of the current tap + * @return NewstartTime – start time of the next tap + */ + function getTapStage(uint _tapNum, uint _tapD, uint _start) public view returns(uint, TapStage, uint) { + bool invC = areAllFundsCollected(_tapNum); + uint RmV = _start + _tapD + roadmapD + votesD; + uint addVRmV = _start + _tapD + addVotesD + roadmapD + votesD; + + if((startedAt == 0) && (now < createdAt + investD)) return (0, TapStage.Investing, 0); + if((startedAt == 0) && (now >= createdAt + investD)) return (0, TapStage.Terminated, 0); + if((_tapNum==0)) return (0, TapStage.Success, 0); + + // _tapNum _start time duration voting1 voting2 voting3 voting4 + //---------------------------------------------------------------------------------------------------------- + if(at(_start, _tapD-votesD) &&thisCase(_tapNum, VR.NoResult, VR.NoResult, VR.NoResult, VR.NoResult)) return (0, TapStage.Preparing, 0); + if(at(_start+_tapD-votesD, votesD) && thisCase(_tapNum, VR.NoResult, VR.NoResult, VR.NoResult, VR.NoResult)) return (0, TapStage.Voting, 0); + if(at(investD, infinity) && thisCase(_tapNum, VR.Decline, VR.NoResult, VR.NoResult, VR.NoResult)) return (0, TapStage.Terminated, 0); + if(at(investD, infinity) && thisCase(_tapNum, VR.Success, VR.NoResult, VR.NoResult, VR.NoResult)) return (0, TapStage.Success, _start + _tapD); + if(at(_start+_tapD, addVotesD)&& thisCase(_tapNum, VR.NoResult, VR.NoResult, VR.NoResult, VR.NoResult)) return (1, TapStage.VotingDQ, 0); + if(at(_start+_tapD, infinity) && thisCase(_tapNum, VR.NoResult, VR.NoResult, VR.NoResult, VR.NoResult)) return (0, TapStage.Terminated, 0); + if(at(_start+_tapD, infinity) && thisCase(_tapNum, VR.NoResult, VR.Decline, VR.NoResult, VR.NoResult)) return (0, TapStage.Terminated, 0); + if(at(_start+_tapD, infinity) && thisCase(_tapNum, VR.NoResult, VR.Success, VR.NoResult, VR.NoResult)) return (0, TapStage.Success, _start + _tapD + addVotesD); + if(at(_start+_tapD+addVotesD, roadmapD) && thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.NoResult, VR.NoResult)) return (0, TapStage.RoadmapPreparing, 0); + if(at(addVRmV-votesD, votesD) && thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.NoResult, VR.NoResult)) return (2, TapStage.RoadmapVoting, 0); + if(at(addVRmV, investD) && thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.Success, VR.NoResult)) return (0, TapStage.Investing, 0); + if(at(addVRmV, infinity) && thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.Success, VR.NoResult) && invC) return (0, TapStage.Success, addVRmV + investD); + if(at(addVRmV, infinity) && thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.Success, VR.NoResult) && !invC) return (0, TapStage.Terminated, 0); + if(at(_start+_tapD+addVotesD, infinity) && thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.NoCons, VR.NoResult)) return (0, TapStage.Terminated, 0); + if(at(_start+_tapD+addVotesD, infinity) && thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.Decline, VR.NoResult)) return (0, TapStage.Terminated, 0); + if(at(addVRmV, addVotesD)&& thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.NoResult, VR.NoResult)) return (3, TapStage.RoadmapVotingDQ, 0); + if(at(addVRmV+addVotesD, investD) && thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.NoResult, VR.Success )) return (0, TapStage.Investing, 0); + if(at(addVRmV+investD, infinity) && thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.NoResult, VR.NoResult )) return (0, TapStage.Terminated, 0); + if(at(addVRmV+investD, infinity) && thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.NoResult, VR.NoCons )) return (0, TapStage.Terminated, 0); + if(at(addVRmV+investD, infinity) && thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.NoResult, VR.Decline )) return (0, TapStage.Terminated, 0); + if(at(addVRmV+addVotesD, infinity) && thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.NoResult, VR.Success ) && invC) return (0, TapStage.Success, addVRmV + addVotesD + investD); + if(at(addVRmV+addVotesD, infinity) && thisCase(_tapNum, VR.NoResult, VR.NoCons, VR.NoResult, VR.Success ) && !invC) return (0, TapStage.Terminated, 0); + if(at(_start+_tapD, roadmapD) && thisCase(_tapNum, VR.NoCons, VR.NoResult, VR.NoResult, VR.NoResult)) return (0, TapStage.RoadmapPreparing, 0); + if(at(_start+_tapD+roadmapD, votesD) && thisCase(_tapNum, VR.NoCons, VR.NoResult, VR.NoResult, VR.NoResult)) return (1, TapStage.RoadmapVoting, 0); + if(at(addVRmV+addVotesD+investD, infinity) && thisCase(_tapNum, VR.NoCons, VR.Decline, VR.NoResult, VR.NoResult)) return (0, TapStage.Terminated, 0); + if(at(addVRmV+addVotesD+investD, infinity) && thisCase(_tapNum, VR.NoCons, VR.NoCons, VR.NoResult, VR.NoResult)) return (0, TapStage.Terminated, 0); + if(at(RmV, investD) && thisCase(_tapNum, VR.NoCons, VR.Success, VR.NoResult, VR.NoResult)) return (0, TapStage.Investing, 0); + if(at(RmV, infinity) && thisCase(_tapNum, VR.NoCons, VR.Success, VR.NoResult, VR.NoResult) && invC) return (0, TapStage.Success, RmV + investD); + if(at(RmV, infinity) && thisCase(_tapNum, VR.NoCons, VR.Success, VR.NoResult, VR.NoResult) && !invC) return (0, TapStage.Terminated, 0); + if(at(RmV, addVotesD)&& thisCase(_tapNum, VR.NoCons, VR.NoResult, VR.NoResult, VR.NoResult)) return (2, TapStage.RoadmapVotingDQ, 0); + if(at(RmV+addVotesD, investD) && thisCase(_tapNum, VR.NoCons, VR.NoResult, VR.Success, VR.NoResult)) return (0, TapStage.Investing, 0); + if(at(RmV+investD, infinity) && thisCase(_tapNum, VR.NoCons, VR.NoResult, VR.NoResult, VR.NoResult)) return (0, TapStage.Terminated, 0); + if(at(RmV+investD, infinity) && thisCase(_tapNum, VR.NoCons, VR.NoResult, VR.Decline, VR.NoResult)) return (0, TapStage.Terminated, 0); + if(at(RmV+investD, infinity) && thisCase(_tapNum, VR.NoCons, VR.NoResult, VR.NoCons, VR.NoResult)) return (0, TapStage.Terminated, 0); + if(at(RmV+addVotesD, infinity) && thisCase(_tapNum, VR.NoCons, VR.NoCons, VR.Success, VR.NoResult) && invC) return (0, TapStage.Success, addVRmV + addVotesD + investD); + if(at(RmV+addVotesD, infinity) && thisCase(_tapNum, VR.NoCons, VR.NoCons, VR.Success, VR.NoResult) && !invC) return (0, TapStage.Terminated, 0); + //---------------------------------------------------------------------------------------------------------- + return (0, TapStage.Preparing, 0); + } /** - * @dev Creates a new voting by owner. Owner can create votings only of type ReleaseTapDecreasedQuorum - * @param _tapIndex tap index - * @param _votingType voting type - */ - function createVotingByOwner(uint _tapIndex, VotingType _votingType) external onlyOwner validTapIndex(_tapIndex) { - // validation - require(_votingType == VotingType.ReleaseTapDecreasedQuorum); - uint latestVotingIndex = tapVotings[_tapIndex][tapVotingsCount[_tapIndex].sub(1)]; - Voting memory latestVoting = votings[latestVotingIndex]; - // check that latest voting is finished - require(now >= latestVoting.finishAt); - // check that latest voting is of type ReleaseTap or ReleaseTapDecreasedQuorum - require(latestVoting.votingType == VotingType.ReleaseTap || latestVoting.votingType == VotingType.ReleaseTapDecreasedQuorum); - // check that latest voting result is quorum not reached - require(getVotingResult(latestVotingIndex) == VotingResult.QuorumNotReached); - // create a new voting - _createVoting(_tapIndex, 50, now, now + 7 days, VotingType.ReleaseTapDecreasedQuorum); + * @dev check that all voting results are the same + * @param _tapNum – number of the tap + * @param _votingRes1 – voting result for a 1 voting in the current tap + * @param _votingRes2 – voting result for a 2 voting in the current tap + * @param _votingRes3 – voting result for a 3 voting in the current tap + * @param _votingRes4 – voting result for a 4 voting in the current tap + * @return are all voting results the same + */ + function thisCase(uint _tapNum, + VR _votingRes1, + VR _votingRes2, + VR _votingRes3, + VR _votingRes4) public view returns(bool) + { + bool withLessQuorum = false; + if(_votingRes1 != votingState(_tapNum, 0, withLessQuorum)) return false; + withLessQuorum = (_votingRes1 == VR.NoResult); + + if(_votingRes2 != votingState(_tapNum, 1, withLessQuorum)) return false; + withLessQuorum = (_votingRes2 == VR.NoResult); + + if(_votingRes3 != votingState(_tapNum, 2, withLessQuorum)) return false; + withLessQuorum = (_votingRes3 == VR.NoResult); + + if(_votingRes4 != votingState(_tapNum, 3, withLessQuorum)) return false; + + return true; } /** - * @dev Withdraws DAI tokens in case project is terminated - */ - function withdrawFunding() external onlyOwner { - // validation - require(isProjectTerminated()); - // calculate amount of DAI tokens to withdraw - uint amountToWithdraw = 0; - for(uint i = 0; i < tapsCount; i++) { - if(!tapPayments[i].isWithdrawn) { - amountToWithdraw = amountToWithdraw.add(tapAmounts[i]); + * @dev project owner can propose new roadmap in the case case if consensus wasn't reached + * @param _tapFunds – array of amounts to invest for an each tap + * @return _tapDurations – array of durations for an each tap + */ + function proposeNewRoadmap(uint[] _tapFunds, uint[] _tapDurations) external { + (uint curTapNum, TapStage[] memory tapStages, uint votNum) = getTapsInfo(); + uint rmNum; + require(tapStages[curTapNum] == TapStage.RoadmapPreparing); + require(_tapFunds.length == _tapDurations.length); + require(msg.sender == owner); + require(_tapFunds.length >= roadmaps[roadmapsCount - 1].tapsCount); + require(!newRoadmapProposed); + + roadmaps[roadmapsCount].tapsCount = _tapFunds.length; + roadmaps[roadmapsCount].investorsCount = roadmaps[roadmapsCount - 1].investorsCount; + + for(uint tapFundsNum = 0; tapFundsNum < _tapFunds.length; tapFundsNum++) { + rmNum = tapToRId[tapFundsNum]; + require(_tapDurations[tapFundsNum] > 7); + if(tapFundsNum <= curTapNum) { + require(_tapDurations[tapFundsNum]*(1 days) == roadmaps[rmNum].taps[tapFundsNum].duration); + require(_tapFunds[tapFundsNum] == roadmaps[rmNum].taps[tapFundsNum].funds); + } else if(tapFundsNum > curTapNum) { + tapToRId[tapFundsNum] = roadmapsCount; // just for clearness; } + + Tap memory tap; + tap.funds = _tapFunds[tapFundsNum]; + tap.duration = _tapDurations[tapFundsNum]*(1 days); + tap.isWithdrawed = false; + roadmaps[roadmapsCount].taps[tapFundsNum] = tap; + } + + uint invNum; + for(invNum = 0; invNum < roadmaps[roadmapsCount - 1].investorsCount; invNum++) { + roadmaps[roadmapsCount].investors[invNum] = roadmaps[roadmapsCount - 1].investors[invNum]; } - // transfer DAI tokens to owner - daiToken.transfer(owner, amountToWithdraw); + + roadmapsCount += 1; + newRoadmapProposed = true; } /** - * Project owner methods - */ + * @param _from – start time of this time interval + * @param _long – duration of this time interval + * @return is current moment in this time interval + */ + function at(uint _from, uint _long) public view returns(bool) { + return ((now >= _from + startedAt) && (now < startedAt + _from + _long)); + } /** - * @dev Withdraws tap payment by project owner - * @param _tapIndex tap index - */ - function withdrawTapPayment(uint _tapIndex) external validTapIndex(_tapIndex) { - // validation - require(msg.sender == projectOwner); - require(isTapWithdrawAcceptedByInvestors(_tapIndex)); - require(!tapPayments[_tapIndex].isWithdrawn); - // create tap payment - TapPayment memory tapPayment; - tapPayment.amount = tapAmounts[_tapIndex]; - tapPayment.createdAt = now; - tapPayment.isWithdrawn = true; - tapPayments[_tapIndex] = tapPayment; - // transfer DAI tokens for selected tap to project owner - daiToken.transfer(projectOwner, tapAmounts[_tapIndex]); + * @param _tapNum – number of the tap + * @param _voting – current voting + * @param _quorumPercent – quorum percent + * @return is quorum reached for a given voting with given quorum percent + */ + function _isQuorumReached(uint _tapNum, Voting memory _voting, uint _quorumPercent) internal view returns(bool) { + return (_voting.pro.add(_voting.versus).mul(100) >= tapAmountsSum(_tapNum).mul(_quorumPercent)); } /** - * Internal methods - */ + * @param _voting – current voting + * @param _consensusPercent – consensus percent + * @return is consensus reached for a given voting with given consensus percent + */ + function _isConsensusReached(Voting memory _voting, uint _consensusPercent) internal view returns(bool) { + return (_voting.pro.mul(100 - _consensusPercent) >= _voting.versus.mul(_consensusPercent)); + } /** - * @dev Creates a new voting - * @param _tapIndex tap index - * @param _quorumRate quorum rate - * @param _createdAt when voting was created timestamp - * @param _finishAt when voting should be finished timestamp - * @param _votingType voting type - */ - function _createVoting(uint _tapIndex, uint _quorumRate, uint _createdAt, uint _finishAt, VotingType _votingType) internal validTapIndex(_tapIndex) { - // validation - require(_quorumRate > 0); - require(_createdAt > 0); - require(_finishAt > 0); - // create a new voting - Voting memory voting; - voting.tapIndex = _tapIndex; - voting.quorumRate = _quorumRate; - voting.createdAt = _createdAt; - voting.finishAt = _finishAt; - voting.votingType = _votingType; - votings[votingsCount] = voting; - // update contract properties - tapVotings[_tapIndex][tapVotingsCount[_tapIndex]] = votingsCount; - tapVotingsCount[_tapIndex] = tapVotingsCount[_tapIndex].add(1); - votingsCount = votingsCount.add(1); + * @param _voting – current voting + * @param _declinePercent – decline percent + * @return is this voting declined with given decline percent + */ + function _isDeclined(Voting memory _voting, uint _declinePercent) internal view returns(bool) { + return (_voting.versus.mul(100 - _declinePercent) >= _voting.pro.mul(_declinePercent)); } -} + /** + * @dev + * @param _tapNum – number of the tap + * @param _votNum – number of the voting + * @param _isQuorumDecreased – is quorum decreased or not + * @return voting result vor this voting + */ + function votingState(uint _tapNum, uint _votNum, bool _isQuorumDecreased) public view returns(VR) { + uint _quorumPercent = quorumPercent; + if(_isQuorumDecreased) _quorumPercent = quorumPercent - 20; + + uint rmNum = tapToRId[_tapNum]; + Voting memory voting = roadmaps[rmNum].taps[_tapNum].votings[_votNum]; + + if(!_isQuorumReached(_tapNum, voting, _quorumPercent)) return VR.NoResult; + if(_isConsensusReached(voting, consensusPercent)) return VR.Success; + if(_isDeclined(voting, declinePercent)) return VR.Decline; + return VR.NoCons; + } +} \ No newline at end of file diff --git a/contracts/Daico/DaicoAuto.sol b/contracts/Daico/DaicoAuto.sol deleted file mode 100644 index a2d123b..0000000 --- a/contracts/Daico/DaicoAuto.sol +++ /dev/null @@ -1,20 +0,0 @@ -pragma solidity ^0.4.24; - -import "@thetta/core/contracts/utils/GenericCaller.sol"; -import "./DaicoWithUnpackers.sol"; - - -contract DaicoAuto is GenericCaller { - DaicoWithUnpackers public daico; - - constructor(IDaoBase _daoBase, DaicoWithUnpackers _daico) public GenericCaller(_daoBase){ - daico = _daico; - } - - function nextStageAuto(uint _projectNum) public returns(address) { - // require(projects[_projectNum].projectState()==DaicoProject.ProjectState.Basic); - bytes32[] memory params = new bytes32[](1); - params[0] = bytes32(_projectNum); - return doAction(daico.NEXT_STAGE(), daico, msg.sender, "nextStageGeneric(bytes32[])", params); - } -} \ No newline at end of file diff --git a/contracts/Daico/DaicoFactory.sol b/contracts/Daico/DaicoFactory.sol deleted file mode 100644 index fa767a2..0000000 --- a/contracts/Daico/DaicoFactory.sol +++ /dev/null @@ -1,76 +0,0 @@ -pragma solidity ^0.4.24; - -// to enable Params passing to constructor and method -// pragma experimental ABIEncoderV2; - -import "@thetta/core/contracts/DaoBase.sol"; -import "@thetta/core/contracts/IDaoBase.sol"; -import "@thetta/core/contracts/DaoStorage.sol"; -import "@thetta/core/contracts/DaoBaseAuto.sol"; -import "@thetta/core/contracts/tokens/StdDaoToken.sol"; -import "@thetta/core/contracts/utils/UtilsLib.sol"; - -// import "./DaicoProject.sol"; -// import "./Daico.sol"; -import "./DaicoWithUnpackers.sol"; -import "./DaicoAuto.sol"; - - -contract DaicoFactory { - DaicoWithUnpackers public daico; - DaoBase public daoBase; - DaoStorage public store; - DaicoAuto public daicoAuto; - - constructor(address[] _investors) { - createDaico(_investors); - // setupAutoMethods(); - // daoBase.renounceOwnership(); - } - - function createDaico(address[] _investors) { - StdDaoToken daicoToken = new StdDaoToken("DaicoToken", "DAICO", 18, true, true, 10**25); - - address[] tokens; - tokens.push(address(daicoToken)); - // store = new DaoStorage(tokens); - // daoBase = new DaoBase(store); - - // daico = new DaicoWithUnpackers(IDaoBase(daoBase), _investors); - - // store.allowActionByAddress(daoBase.MANAGE_GROUPS(),address(this)); - // store.allowActionByAddress(daoBase.ISSUE_TOKENS(),address(daico)); - // store.allowActionByAddress(daoBase.BURN_TOKENS(),address(daico)); - // store.transferOwnership(daoBase); - - // daicoToken.transferOwnership(daoBase); - - // for(uint i=0; i<_investors.length; ++i){ - // daoBase.addGroupMember("Investors", _investors[i]); - // } - - // // 1 - set investors group permissions - // daoBase.allowActionByAnyMemberOfGroup(daoBase.ADD_NEW_PROPOSAL(),"Investors"); - // daoBase.allowActionByVoting(daoBase.MANAGE_GROUPS(), daicoToken); - - // // 2 - set custom investors permissions - // daoBase.allowActionByVoting(daico.NEXT_STAGE(), daico.daicoToken()); - } - - function setupAutoMethods() internal { - // TODO: add all custom actions to the DaoBaseAuto derived contract - // daicoAuto = new DaicoAuto(IDaoBase(daoBase), daico); - - // daoBase.allowActionByAddress(daoBase.ADD_NEW_PROPOSAL(), daicoAuto); - // daoBase.allowActionByAddress(daoBase.MANAGE_GROUPS(), daicoAuto); - // daoBase.allowActionByAddress(daoBase.UPGRADE_DAO_CONTRACT(), daicoAuto); - // // daoBase.allowActionByAddress(daico.NEXT_STAGE(), daicoAuto); - - // uint VOTING_TYPE_1P1V = 1; - // daicoAuto.setVotingParams(daoBase.MANAGE_GROUPS(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("Investors"), bytes32(70), bytes32(70), bytes32(24*7)); - // daicoAuto.setVotingParams(daoBase.UPGRADE_DAO_CONTRACT(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("Investors"), bytes32(70), bytes32(70), bytes32(24*7)); - // daicoAuto.setVotingParams(daico.NEXT_STAGE(), VOTING_TYPE_1P1V, bytes32(0), UtilsLib.stringToBytes32("Investors"), bytes32(0), bytes32(0), bytes32(24*7)); - - // daicoAuto.transferOwnership(daoBase); - } -} \ No newline at end of file diff --git a/contracts/Daico/DaicoOld.sol b/contracts/Daico/DaicoOld.sol deleted file mode 100644 index b8ce08a..0000000 --- a/contracts/Daico/DaicoOld.sol +++ /dev/null @@ -1,31 +0,0 @@ -pragma solidity ^0.4.24; - -// to enable Params passing to constructor and method -pragma experimental ABIEncoderV2; - -import "@thetta/core/contracts/DaoClient.sol"; -import "@thetta/core/contracts/IDaoBase.sol"; -import "@thetta/core/contracts/tokens/StdDaoToken.sol"; -import "./DaicoProject.sol"; - - -contract DaicoOld is DaoClient { - mapping(uint => DaicoProject) public projects; - uint projectsCount; - address[] public investors; - - bytes32 public NEXT_STAGE = keccak256("nextStage"); - - constructor(IDaoBase _daoBase, address[] _investors) DaoClient(_daoBase) { - investors = _investors; - } - - function addNewProject(uint _stagesCount, uint _stageAmount) { - DaicoProject project = new DaicoProject(_stagesCount, _stageAmount, msg.sender, address(this)); - projects[projectsCount] = project; - projectsCount++; - } - - function addAmountToFund() public payable {} - -} \ No newline at end of file diff --git a/contracts/Daico/DaicoProject.sol b/contracts/Daico/DaicoProject.sol deleted file mode 100644 index 076b55b..0000000 --- a/contracts/Daico/DaicoProject.sol +++ /dev/null @@ -1,66 +0,0 @@ -pragma solidity ^0.4.24; - -// to enable Params passing to constructor and method -pragma experimental ABIEncoderV2; - -import "@thetta/core/contracts/DaoClient.sol"; -import "@thetta/core/contracts/IDaoBase.sol"; -import "@thetta/core/contracts/tokens/StdDaoToken.sol"; -import "@thetta/core/contracts/moneyflow/ether/WeiAbsoluteExpense.sol"; - -// DaicoProject is funds owner -contract DaicoProject { - mapping(uint => WeiAbsoluteExpense) stages; - uint public stageAmount; - uint public stagesCount; - address public projectOwner; - address public daicoAddress; - uint public currentStage = 0; - - uint public blockUntil = 0; - bool public isRemoved = false; - - modifier onlyDaico() { - require(msg.sender==daicoAddress); - _; - } - - modifier onlyProjectOwner() { - require(msg.sender==projectOwner); - _; - } - - constructor(uint _stagesCount, uint _stageAmount, address _projectOwner, address _daicoAddress) { - stageAmount = _stageAmount; - stagesCount = _stagesCount; - projectOwner = _projectOwner; - daicoAddress = _daicoAddress; - - for(uint i=0; i<_stagesCount; i++) { - WeiAbsoluteExpense stage = new WeiAbsoluteExpense(_stageAmount); - - stages[i] = stage; - } - } - - function flushFundsFromStage(uint _stageNum) onlyProjectOwner { - stages[_stageNum].flushTo(projectOwner); - } - - function goToNextStage() onlyDaico { - require(currentStage70) { - projects[projNum].goToNextStage(); - }else if(yesPercent>20) { - uint blockUntil = uint(now) + 30*24*3600*1000; - projects[projNum].setBlock(blockUntil); - } else { - projects[projNum].removeProject(); - } - } -} \ No newline at end of file diff --git a/contracts/Daico/IDaico.sol b/contracts/Daico/IDaico.sol index 09dcd9a..c7717cd 100644 --- a/contracts/Daico/IDaico.sol +++ b/contracts/Daico/IDaico.sol @@ -1,240 +1,8 @@ pragma solidity ^0.4.24; -import "zeppelin-solidity/contracts/ownership/Ownable.sol"; -import "zeppelin-solidity/contracts/token/ERC20/ERC20.sol"; - -/** - * @title IDaico - * How it works: - * 1. Evercity member deploys current contract for some project. - * 2. Contract creates initial votings of type ReleaseTap for each tap. - * 3. Evercity member transfers DAI tokens to DAICO contract address. - * - * ================== - * Common scenarios: - * ================== - * # Successful voting for tap release - * 1. Token holders votes via 'vote()'. - * 2. Quorum reached with positive decision. - * 3. Project owner withdraws DAI tokens for accepted tap via 'withdrawTapPayment()'. - - * # Quorum not reached for 'ReleaseTap' voting - * 1. Token holders votes via 'vote()'. - * 2. Quorum NOT reached. - * 3. Evercity member creates a new voting of type 'ReleaseTapDecreasedQuorum' via 'createVotingByOwner()'. - * 4. Quorum reached with positive decision. - * 5. Project owner withdraws DAI tokens for accepted tap via 'withdrawTapPayment()'. - * - * # Quorum reached but minVoteRate with positive decisions is not reached - * 1. Token holders votes via 'vote()'. - * 2. Quorum reached but minVoteRate with positive decisions is not reached - * 3. One of the investors creates a new voting of type 'ChangeRoadmap' via 'createVotingByInvestor()'. - * 4. Quorum reached with positive decision. - * 5. Project owner withdraws DAI tokens for accepted tap via 'withdrawTapPayment()'. - * - * # Voting strongly against tap release - * 1. Token holders votes via 'vote()'. - * 2. Quorum reached and more than minVoteRate token holders voted against tap release. - * 3. One of the investors creates a new voting of type 'TerminateProject' via 'createVotingByInvestor()'. - * 4. Quorum reached with positive decision. - * 5. Evercity member withdraws left DAI tokens via 'withdrawFunding()'. - * - * =================== - * All scenario steps: - * =================== - * # ReleaseTap/ReleaseTapDecreasedQuorum - * - voting of type ReleaseTap or ReleaseTapDecreasedQuorum finishes with Accept result => project owner withdraws DAI tokens via 'withdrawTapPayment()' - * - voting of type ReleaseTap or ReleaseTapDecreasedQuorum finishes with Decline result => one of the investors creates a voting of type TerminateProject via 'createVotingByInvestor()' - * - voting of type ReleaseTap or ReleaseTapDecreasedQuorum finishes with QuorumNotReached result => evercity member creates a voting of type ReleaseTapDecreasedQuorum via 'createVotingByOwner()' - * - voting of type ReleaseTap or ReleaseTapDecreasedQuorum finishes with NoDecision result => one of the investors creates a voting of type ChangeRoadmap via 'createVotingByInvestor()' - * - * # ChangeRoadmap/ChangeRoadmapDecreasedQuorum - * - voting of type ChangeRoadmap or ChangeRoadmapDecreasedQuorum finishes with Accept result => project owner withdraws DAI tokens via 'withdrawTapPayment()' - * - voting of type ChangeRoadmap or ChangeRoadmapDecreasedQuorum finishes with Decline result => one of the investors creates a voting of type TerminateProject via 'createVotingByInvestor()' - * - voting of type ChangeRoadmap or ChangeRoadmapDecreasedQuorum finishes with QuorumNotReached result => one of the investors creates a voting of type ChangeRoadmapDecreasedQuorum via 'createVotingByInvestor()' - * - voting of type ChangeRoadmap or ChangeRoadmapDecreasedQuorum finishes with NoDecision result => one of the investors creates a voting of type ChangeRoadmapDecreasedQuorum via 'createVotingByInvestor()' - * - * # TerminateProject/TerminateProjectDecreasedQuorum - * - voting of type TerminateProject or TerminateProjectDecreasedQuorum finishes with Accept result => evervity member withdraws DAI tokens via 'withdrawFunding()' - * - voting of type TerminateProject or TerminateProjectDecreasedQuorum finishes with Decline result => one of the investors creates a voting of type ChangeRoadmap via 'createVotingByInvestor()' - * - voting of type TerminateProject or TerminateProjectDecreasedQuorum finishes with QuorumNotReached result => one of the investors creates a voting of type TerminateProjectDecreasedQuorum via 'createVotingByInvestor()' - * - voting of type TerminateProject or TerminateProjectDecreasedQuorum finishes with NoDecision result => one of the investors creates a voting of type TerminateProjectDecreasedQuorum via 'createVotingByInvestor()' - */ -contract IDaico is Ownable { - - ERC20 public daiToken; - ERC20 public projectToken; - - address public projectOwner; - - uint public minQuorumRate; - uint public minVoteRate; - uint public tapsCount; - uint public tokenHoldersCount; - uint[] public tapAmounts; - uint[] public tapTimestampsFinishAt; - - enum VotingType { ReleaseTap, ReleaseTapDecreasedQuorum, ChangeRoadmap, TerminateProject } - enum VotingResult { Accept, Decline, QuorumNotReached, NoDecision } - - mapping(uint => mapping(uint => uint)) public tapVotings; - mapping(uint => uint) public tapVotingsCount; - - mapping(uint => Voting) public votings; - uint public votingsCount; - - mapping(uint => TapPayment) public tapPayments; - uint public tapPaymentsCount; - - struct TapPayment { - uint amount; - uint createdAt; - bool isWithdrawn; - } - - struct Voting { - uint tapIndex; - uint yesVotesCount; - uint noVotesCount; - uint quorumRate; - uint createdAt; - uint finishAt; - VotingType votingType; - mapping(address => bool) voted; - } - - /** - * @dev Contract constructor - * @param _daiTokenAddress address of the DAI token contract, project gets payments in DAI tokens - * @param _projectTokenAddress project token address, investors hold this token - * @param _projectOwnerAddress project owner address who can receive tap payments - * @param _tapsCount how many times project should get payments, NOTICE: we can get taps count from _tapAmounts.length but contract deployer can force so that _tapsCount != _tapAmounts.length - * @param _tapAmounts array of DAI token amounts in wei that describes how many tokens project gets per single stage - * @param _tapTimestampsFinishAt array of deadline timestamps, project should get payment before each deadline timestamp - * @param _minQuorumRate min quorum rate, 100 == 100% - * @param _minVoteRate min vote rate for proposal to be accepted/declined, 100 == 100% - * @param _tokenHoldersCount amount of token holders - */ - constructor( - address _daiTokenAddress, - address _projectTokenAddress, - address _projectOwnerAddress, - uint _tapsCount, - uint[] _tapAmounts, - uint[] _tapTimestampsFinishAt, - uint _minQuorumRate, - uint _minVoteRate, - uint _tokenHoldersCount - ) public {} - - /** - * Public methods - */ - - /** - * @dev Returns voting result for voting. - * There are 4 voting results: - * - Accept: proposal accepted, majority of investors said 'yes' - * - Decline: proposal declined, majority of investors said 'no' - * - QuorumNotReached: not enough investors voted - * - NoDecision: no consensus among investors, ex: 50% of 'yes' vs 50% of 'no' votes - * @param _votingIndex voting index - * @return voting result - */ - function getVotingResult(uint _votingIndex) public view returns(VotingResult); - - /** - * @dev Checks whether investor already voted in particular voting - * @param _votingIndex voting index - * @param _investorAddress investor address - * @return whether investor has already voted in particular voting - */ - function isInvestorVoted(uint _votingIndex, address _investorAddress) external view returns(bool); - - /** - * @dev Checks whether project is terminated. - * Project is terminated when the last voting is of type TerminateProject/TerminateProjectDecreasedQuorum with Accept result. - * When project is terminated contract owner(evercity member) can withdraw DAI tokens via 'withdrawFunding()'. - * @return is project terminated - */ - function isProjectTerminated() public view returns(bool); - - /** - * @dev Checks whether tap withdraw is accepted by investors for project owner - * @param _tapIndex tap index - * @return whether withdraw is accepted - */ - function isTapWithdrawAcceptedByInvestors(uint _tapIndex) public view returns(bool); - - /** - * Investor methods - */ - - /** - * @dev Creates a new voting by investor. Investors can create votings of 4 types: ChangeRoadmap, ChangeRoadmapDecreasedQuorum, TerminateProject, TerminateProjectDecreasedQuorum. - * @param _tapIndex tap index - * @param _votingType voting type - */ - function createVotingByInvestor(uint _tapIndex, VotingType _votingType) external; - - /** - * @dev Vote method for token holder - * Preconditions: - * - Is token holder(has at least 1 project token) - * - Valid voting index - * - Is valid voting period - * - Investor hasn't voted earlier for this proposal - * - Project is not terminated - * @param _votingIndex voting index - * @param _isYes decision, yes or no - */ - function vote(uint _votingIndex, bool _isYes) external; - - /** - * Owner / evercity member methods - */ - - /** - * @dev Creates a new voting by owner. Owner can create votings only of type ReleaseTapDecreasedQuorum - * @param _tapIndex tap index - * @param _votingType voting type - */ - function createVotingByOwner(uint _tapIndex, VotingType _votingType) external; - - /** - * @dev Withdraws all left DAI tokens to owner address - * Preconditions: - * - contract is terminated in case of successful TerminateProject voting - */ - function withdrawFunding() external; - - /** - * Project owner methods - */ - - /** - * @dev Withdraws tap payment by project owner - * Preconditions: - * - Valid tap index - * - Tap is not yet withdrawn - * - Tap withdrawal is accepted by investors - * @param _tapIndex tap index - * Result: DAI tokens for current tap are transfered to project owner address - */ - function withdrawTapPayment(uint _tapIndex) external; - - /** - * Internal methods - */ - - /** - * @dev Creates a new voting for tap - * @param _tapIndex tap index - * @param _quorumRate quorum rate - * @param _createdAt when voting was created timestamp - * @param _finishAt when voting should be finished timestamp - * @param _votingType voting type - */ - function _createVoting(uint _tapIndex, uint _quorumRate, uint _createdAt, uint _finishAt, VotingType _votingType) internal; +contract IDaico { + function addInvestor(uint _amount, address _investorAddress) public; + function vote(bool _vote) external; + function proposeNewRoadmap(uint[] _tapFunds, uint[] _tapDurations) external; } diff --git a/contracts/Daico/STOContract.sol b/contracts/Daico/STOContract.sol new file mode 100644 index 0000000..8ee0dc0 --- /dev/null +++ b/contracts/Daico/STOContract.sol @@ -0,0 +1,31 @@ +pragma solidity ^0.4.24; + +import "zeppelin-solidity/contracts/token/ERC20/MintableToken.sol"; +import "zeppelin-solidity/contracts/token/ERC20/ERC20.sol"; +import "./IDaico.sol"; + + +contract STOContract is MintableToken { + address public ervercityTokenAddress; + address public daicoAddress; + + constructor(address _ervercityTokenAddress) public { + ervercityTokenAddress = _ervercityTokenAddress; + } + + function setDaicoAddress(address _daicoAddress) public onlyOwner { + daicoAddress = _daicoAddress; + } + + function invest(uint _amount) public { + ERC20(ervercityTokenAddress).transferFrom(msg.sender, address(this), _amount); + ERC20(ervercityTokenAddress).approve(daicoAddress, _amount); + + totalSupply_ = totalSupply_.add(_amount); + balances[msg.sender] = balances[msg.sender].add(_amount); + emit Mint(msg.sender, _amount); + emit Transfer(address(0), msg.sender, _amount); + + IDaico(daicoAddress).addInvestor(_amount, msg.sender); + } +} diff --git a/migrations/2_deploy_contracts_libraries.js b/migrations/2_deploy_contracts_libraries.js deleted file mode 100644 index 8c22957..0000000 --- a/migrations/2_deploy_contracts_libraries.js +++ /dev/null @@ -1,20 +0,0 @@ -var migrateLibs = require('@thetta/core/scripts/migrateLibs'); - -module.exports = function (deployer, network, accounts) { - let additionalContracts = [ "./BodDaoFactory" - , "./DevZenDaoAuto" - , "./DevZenDaoAutoTestable" - , "./DevZenDaoFactory" - , "./DevZenDaoFactoryTestable" - , "./DevZenDaoTestable" - , "./DevZenDaoWithUnpackers" - , "./DevZenDaoWithUnpackersTestable" - , "./HierarchyDaoFactory" - , "./DaicoFactory" - , "./Daico" - , "./DaicoAuto" - , "./DaicoWithUnpackers" - ] - - return migrateLibs(artifacts, additionalContracts, deployer, network, accounts); -}; diff --git a/migrations/3_deploy_devZenDao.js b/migrations/3_deploy_devZenDao.js deleted file mode 100644 index 17673b6..0000000 --- a/migrations/3_deploy_devZenDao.js +++ /dev/null @@ -1,92 +0,0 @@ -var DevZenDaoFactory = artifacts.require("DevZenDaoFactory"); -var StdDaoToken = artifacts.require("StdDaoToken"); -var DaoStorage = artifacts.require("DaoStorage"); -var DaoBaseWithUnpackers = artifacts.require("DaoBaseWithUnpackers"); -var IDaoBase = artifacts.require("IDaoBase"); -var DaoBaseAuto = artifacts.require("DaoBaseAuto"); -var DevZenDao = artifacts.require("DevZenDao"); -var DevZenDaoAuto = artifacts.require("DevZenDaoAuto"); -var DevZenDaoCore = artifacts.require("DevZenDaoCore"); -var DevZenDaoWithUnpackers = artifacts.require("DevZenDaoWithUnpackers"); -const { uintToBytes32, padToBytes, fromUtf8 } = require("../test/utils/helpers"); - -let emp1 = '0x7EaD9f71ef8a32D351ce1966b281300114bF2eab'; -let emp2 = '0x1f27a8F4a8A50898C5735221982eefA80c070073'; -let emp3 = '0xC86d4De6dC26d73BE76a526D951d194BF13C605c'; - -module.exports = function(deployer, network, accounts) { - return deployer.then(async () => { - let devZenToken = await deployer.deploy(StdDaoToken, "DevZenToken", "DZT", 18, true, true, 100000000000000000000); - let repToken = await deployer.deploy(StdDaoToken, "DevZenRepToken", "DZTREP", 18, true, true, 100000000000000000000); - let store = await deployer.deploy(DaoStorage, [devZenToken.address, repToken.address]); - let daoBase = await deployer.deploy(DaoBaseWithUnpackers, store.address); - let devZenDao = await deployer.deploy(DevZenDaoWithUnpackers, daoBase.address, [devZenToken.address, repToken.address]); - - await store.allowActionByAddress(await daoBase.MANAGE_GROUPS(),accounts[0]); - await store.allowActionByAddress(await daoBase.ISSUE_TOKENS(),devZenDao.address); - await store.allowActionByAddress(await daoBase.BURN_TOKENS(),devZenDao.address); - await store.allowActionByAddress(await devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), accounts[0]); - await store.allowActionByAddress(await devZenDao.DEV_ZEN_UPDATE_DAO_PARAMS(), accounts[0]); - - // await await 2 - setup - await store.addGroupMember(web3.sha3("DevZenTeam"), accounts[0]); - await store.addGroupMember(web3.sha3("DevZenTeam"), emp1); - await store.addGroupMember(web3.sha3("DevZenTeam"), emp2); - await store.addGroupMember(web3.sha3("DevZenTeam"), emp3); - - await store.transferOwnership(daoBase.address); - await devZenDao.setParam(await devZenDao.MINT_TOKENS_PER_WEEK_AMOUNT(), 10 * 1e18); - await devZenDao.setParam(await devZenDao.MINT_REPUTATION_TOKENS_PER_WEEK_AMOUNT(), 5 * 1e18); - await devZenDao.setParam(await devZenDao.ONE_AD_SLOT_PRICE(), 2 * 1e18); // Current ETH price is ~$450. One token will be worth ~$45. One ad will cost ~$90 (2 tokens) - await devZenDao.setParam(await devZenDao.ONE_TOKEN_PRICE_IN_WEI(), 1e17); //) To become a guest user should put 5 tokens at stake - - await devZenDao.setParam(await devZenDao.BECOME_GUEST_STAKE(), 5 * 1e18); - await devZenDao.setParam(await devZenDao.REP_TOKENS_REWARD_HOST(), 2 * 1e18); - await devZenDao.setParam(await devZenDao.REP_TOKENS_REWARD_GUEST(), 1 * 1e18); - await devZenDao.setParam(await devZenDao.REP_TOKENS_REWARD_TEAM_MEMBERS(), 2 * 1e18); - - await devZenToken.transferOwnership(daoBase.address); - await repToken.transferOwnership(daoBase.address); - - // 1 - set DevZenTeam group permissions - await daoBase.allowActionByAnyMemberOfGroup(await daoBase.ADD_NEW_PROPOSAL(),"DevZenTeam"); - await daoBase.allowActionByVoting(await daoBase.MANAGE_GROUPS(), repToken.address); - await daoBase.allowActionByVoting(await daoBase.UPGRADE_DAO_CONTRACT(), repToken.address); - - // 2 - set custom DevZenTeam permissions - await daoBase.allowActionByVoting(await devZenDao.DEV_ZEN_UPDATE_DAO_PARAMS(), repToken.address); - await daoBase.allowActionByVoting(await devZenDao.DEV_ZEN_WITHDRAW_ETHER(), repToken.address); - await daoBase.allowActionByVoting(await devZenDao.DEV_ZEN_SELECT_NEXT_HOST(), repToken.address); - await daoBase.allowActionByVoting(await devZenDao.DEV_ZEN_CHANGE_GUEST(), repToken.address); - await daoBase.allowActionByVoting(await devZenDao.DEV_ZEN_EMERGENCY_CHANGE_GUEST(), repToken.address); - await daoBase.allowActionByVoting(await devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), repToken.address); - - let devZenDaoAuto = await deployer.deploy(DevZenDaoAuto, daoBase.address, devZenDao.address); - - await daoBase.allowActionByAddress(await daoBase.ADD_NEW_PROPOSAL(), devZenDaoAuto.address); - await daoBase.allowActionByAddress(await daoBase.MANAGE_GROUPS(), devZenDaoAuto.address); - await daoBase.allowActionByAddress(await daoBase.UPGRADE_DAO_CONTRACT(), devZenDaoAuto.address); - - await daoBase.allowActionByAddress(await devZenDao.DEV_ZEN_UPDATE_DAO_PARAMS(), devZenDaoAuto.address); - await daoBase.allowActionByAddress(await devZenDao.DEV_ZEN_WITHDRAW_ETHER(), devZenDaoAuto.address); - await daoBase.allowActionByAddress(await devZenDao.DEV_ZEN_SELECT_NEXT_HOST(), devZenDaoAuto.address); - await daoBase.allowActionByAddress(await devZenDao.DEV_ZEN_CHANGE_GUEST(), devZenDaoAuto.address); - await daoBase.allowActionByAddress(await devZenDao.DEV_ZEN_EMERGENCY_CHANGE_GUEST(), devZenDaoAuto.address); - await daoBase.allowActionByAddress(await devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), devZenDaoAuto.address); - - let VOTING_TYPE_1P1V = 1; - await devZenDaoAuto.setVotingParams(await daoBase.MANAGE_GROUPS(), VOTING_TYPE_1P1V, uintToBytes32(0), fromUtf8("DevZenTeam"), uintToBytes32(65), uintToBytes32(65), 0); - await devZenDaoAuto.setVotingParams(await daoBase.REMOVE_GROUP_MEMBER(), VOTING_TYPE_1P1V, uintToBytes32(0), fromUtf8("DevZenTeam"), uintToBytes32(65), uintToBytes32(65), 0); - await devZenDaoAuto.setVotingParams(await daoBase.UPGRADE_DAO_CONTRACT(), VOTING_TYPE_1P1V, uintToBytes32(0), fromUtf8("DevZenTeam"), uintToBytes32(65), uintToBytes32(65), 0); - await devZenDaoAuto.setVotingParams(await devZenDao.DEV_ZEN_UPDATE_DAO_PARAMS(), VOTING_TYPE_1P1V, uintToBytes32(0), fromUtf8("DevZenTeam"), uintToBytes32(65), uintToBytes32(65), 0); - await devZenDaoAuto.setVotingParams(await devZenDao.DEV_ZEN_WITHDRAW_ETHER(), VOTING_TYPE_1P1V, uintToBytes32(0), fromUtf8("DevZenTeam"), uintToBytes32(65), uintToBytes32(65), 0); - await devZenDaoAuto.setVotingParams(await devZenDao.DEV_ZEN_SELECT_NEXT_HOST(), VOTING_TYPE_1P1V, uintToBytes32(0), fromUtf8("DevZenTeam"), uintToBytes32(65), uintToBytes32(65), 0); - await devZenDaoAuto.setVotingParams(await devZenDao.DEV_ZEN_CHANGE_GUEST(), VOTING_TYPE_1P1V, uintToBytes32(0), fromUtf8("DevZenTeam"), uintToBytes32(65), uintToBytes32(65), 0); - await devZenDaoAuto.setVotingParams(await devZenDao.DEV_ZEN_EMERGENCY_CHANGE_GUEST(), VOTING_TYPE_1P1V, uintToBytes32(0), fromUtf8("DevZenTeam"), uintToBytes32(65), uintToBytes32(65), 0); - await devZenDaoAuto.setVotingParams(await devZenDao.DEV_ZEN_MOVE_TO_NEXT_EPISODE(), VOTING_TYPE_1P1V, uintToBytes32(0), fromUtf8("DevZenTeam"), uintToBytes32(65), uintToBytes32(65), 0); - - await devZenDaoAuto.transferOwnership(daoBase.address); - - await daoBase.renounceOwnership(); - }); -}; \ No newline at end of file diff --git a/migrations/4_deploy_HierarchyDao.js b/migrations/4_deploy_HierarchyDao.js deleted file mode 100644 index b15fb66..0000000 --- a/migrations/4_deploy_HierarchyDao.js +++ /dev/null @@ -1,54 +0,0 @@ -var StdDaoToken = artifacts.require("StdDaoToken"); -var DaoStorage = artifacts.require("DaoStorage"); -var DaoBase = artifacts.require("DaoBase"); -var IDaoBase = artifacts.require("IDaoBase"); -var DaoBaseAuto = artifacts.require("DaoBaseAuto"); -var HierarchyDao = artifacts.require("HierarchyDao"); -const { uintToBytes32, padToBytes, fromUtf8 } = require("../test/utils/helpers"); - -let mng1 = '0x5a2203e516d8f025eaa37d1f6d7f114ac654da05'; -let mng2 = '0x9dc108ae0579a1c856b8eff862fcab76c6e6ee15'; -let mng3 = '0x564dcf23922de39970b2b442b1a2de8d2fd25330'; -let emp1 = '0xfac20ad5f3bfc1748235edf919d473272ca0fd55'; -let emp2 = '0x38ed1a11e4f2fd85995a058e1f65d41a483a662a'; -let emp3 = '0x92bc71cd9a9a6ad3a1dcacc2b8c9eab13f4d547e'; - -module.exports = function(deployer, network, accounts) { - return deployer.then(async () => { - let token = await deployer.deploy(StdDaoToken, "StdToken", "STD", 18, true, true, 100000000000000000000); - let store = await deployer.deploy(DaoStorage, [token.address]); - let daoBase = await deployer.deploy(DaoBase, store.address); - let hierarchyDao = await deployer.deploy(HierarchyDao, daoBase.address); - - await store.allowActionByAddress(await daoBase.MANAGE_GROUPS(), accounts[0]); - await store.transferOwnership(daoBase.address); - await token.transferOwnership(daoBase.address); - - await daoBase.addGroupMember("Managers", accounts[0]); - await daoBase.addGroupMember("Employees", accounts[0]); - - await daoBase.allowActionByAddress(await daoBase.ISSUE_TOKENS(), accounts[0]); - await daoBase.allowActionByAddress(await daoBase.UPGRADE_DAO_CONTRACT(), accounts[0]); - await daoBase.allowActionByAnyMemberOfGroup(await daoBase.ADD_NEW_PROPOSAL(), "Managers"); - await daoBase.allowActionByVoting(await daoBase.MANAGE_GROUPS(), token.address); - - await daoBase.addGroupMember("Managers", mng1); - await daoBase.addGroupMember("Managers", mng2); - await daoBase.addGroupMember("Managers", mng3); - await daoBase.addGroupMember("Employees", emp1); - await daoBase.addGroupMember("Employees", emp2); - await daoBase.addGroupMember("Employees", emp3); - - let hierarchyDaoAuto = await deployer.deploy(DaoBaseAuto, daoBase.address); - - // set voring params 1 person 1 vote - let VOTING_TYPE_1P1V = 1; - await hierarchyDaoAuto.setVotingParams(await daoBase.MANAGE_GROUPS(), VOTING_TYPE_1P1V, uintToBytes32(0), fromUtf8("Managers"), uintToBytes32(50), uintToBytes32(50), 0); - - await daoBase.allowActionByAddress(await daoBase.ADD_NEW_PROPOSAL(), hierarchyDaoAuto.address); - await daoBase.allowActionByAddress(await daoBase.MANAGE_GROUPS(), hierarchyDaoAuto.address); - - await hierarchyDaoAuto.transferOwnership(daoBase.address); - await daoBase.renounceOwnership(); - }); -}; \ No newline at end of file diff --git a/migrations/5_deploy_BodDao.js b/migrations/5_deploy_BodDao.js deleted file mode 100644 index 8368a93..0000000 --- a/migrations/5_deploy_BodDao.js +++ /dev/null @@ -1,57 +0,0 @@ -var StdDaoToken = artifacts.require("StdDaoToken"); -var DaoStorage = artifacts.require("DaoStorage"); -var DaoBase = artifacts.require("DaoBase"); -var IDaoBase = artifacts.require("IDaoBase"); -var DaoBaseAuto = artifacts.require("DaoBaseAuto"); -var BodDao = artifacts.require("BodDao"); -const { uintToBytes32, padToBytes, fromUtf8 } = require("../test/utils/helpers"); - -let dir1 = '0x5a2203e516d8f025eaa37d1f6d7f114ac654da05'; -let dir2 = '0x9dc108ae0579a1c856b8eff862fcab76c6e6ee15'; -let dir3 = '0x564dcf23922de39970b2b442b1a2de8d2fd25330'; -let emp1 = '0xfac20ad5f3bfc1748235edf919d473272ca0fd55'; -let emp2 = '0x38ed1a11e4f2fd85995a058e1f65d41a483a662a'; -let emp3 = '0x92bc71cd9a9a6ad3a1dcacc2b8c9eab13f4d547e'; - -module.exports = function(deployer, network, accounts) { - return deployer.then(async () => { - let token = await deployer.deploy(StdDaoToken, "StdToken", "STD", 18, true, true, 100000000000000000000); - let store = await deployer.deploy(DaoStorage, [token.address]); - let daoBase = await deployer.deploy(DaoBase, store.address); - let bodDao = await deployer.deploy(BodDao, daoBase.address); - - await store.allowActionByAddress(await daoBase.MANAGE_GROUPS(), accounts[0]); - - await token.transferOwnership(daoBase.address); - await store.transferOwnership(daoBase.address); - - await daoBase.addGroupMember("BoD", accounts[0]); - await daoBase.addGroupMember("Employees", accounts[0]); - - daoBase.allowActionByAnyMemberOfGroup(await daoBase.ADD_NEW_PROPOSAL(), "BoD"); - daoBase.allowActionByVoting(await daoBase.MANAGE_GROUPS(), token.address); - daoBase.allowActionByVoting(await daoBase.ISSUE_TOKENS(), token.address); - daoBase.allowActionByVoting(await daoBase.UPGRADE_DAO_CONTRACT(), token.address); - - await daoBase.addGroupMember("BoD", dir1); - await daoBase.addGroupMember("BoD", dir2); - await daoBase.addGroupMember("BoD", dir3); - await daoBase.addGroupMember("Employees", emp1); - await daoBase.addGroupMember("Employees", emp2); - await daoBase.addGroupMember("Employees", emp3); - - let bodDaoAuto = await deployer.deploy(DaoBaseAuto, daoBase.address); - - let VOTING_TYPE_1P1V = 1; - await bodDaoAuto.setVotingParams(await daoBase.MANAGE_GROUPS(), VOTING_TYPE_1P1V, uintToBytes32(0), fromUtf8("BoD"), uintToBytes32(49), uintToBytes32(49), 0); - await bodDaoAuto.setVotingParams(await daoBase.ISSUE_TOKENS(), VOTING_TYPE_1P1V, uintToBytes32(0), fromUtf8("BoD"), uintToBytes32(49), uintToBytes32(49), 0); - await bodDaoAuto.setVotingParams(await daoBase.UPGRADE_DAO_CONTRACT(), VOTING_TYPE_1P1V, uintToBytes32(0), fromUtf8("BoD"), uintToBytes32(49), uintToBytes32(49), 0); - - await daoBase.allowActionByAddress(await daoBase.MANAGE_GROUPS(), bodDaoAuto.address); - await daoBase.allowActionByAddress(await daoBase.ISSUE_TOKENS(), bodDaoAuto.address); - await daoBase.allowActionByAddress(await daoBase.ADD_NEW_PROPOSAL(), bodDaoAuto.address); - - await bodDaoAuto.transferOwnership(daoBase.address); - await daoBase.renounceOwnership(); - }); -}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a476247..361a512 100644 --- a/package-lock.json +++ b/package-lock.json @@ -125,152 +125,11 @@ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==" }, - "@thetta/core": { - "version": "git+https://github.com/Thetta/Thetta-DAO-Framework.git#1ebae3a32a2b6fec0c6770b28983bc0f6061c5f8", - "from": "git+https://github.com/Thetta/Thetta-DAO-Framework.git#genericCaller", - "requires": { - "babel-eslint": "^8.2.6", - "babel-polyfill": "^6.26.0", - "babel-register": "^6.26.0", - "chai": "4.1.2", - "chai-as-promised": "7.1.1", - "chai-bignumber": "2.0.2", - "coveralls": "^3.0.2", - "docusaurus-init": "^1.0.2", - "eslint": "^5.4.0", - "eslint-config-standard": "^10.2.1", - "eslint-plugin-import": "^2.14.0", - "eslint-plugin-node": "^5.2.1", - "eslint-plugin-promise": "^3.8.0", - "eslint-plugin-standard": "^3.1.0", - "eth-gas-reporter": "^0.1.10", - "ganache-cli": "^6.1.8", - "growl": "^1.10.5", - "install": "^0.12.1", - "solc": "^0.4.24", - "solidity-coverage": "^0.5.7", - "solidity-docgen": "^0.1.0", - "solium": "^1.1.8", - "truffle": "^4.1.14", - "zeppelin-solidity": "^1.12.0" - }, - "dependencies": { - "babel-eslint": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz", - "integrity": "sha512-aCdHjhzcILdP8c9lej7hvXKvQieyRt20SF102SIGyY4cUIiw6UaAtK4j2o3dXX74jEmy0TJ0CEhv4fTIM3SzcA==", - "requires": { - "@babel/code-frame": "7.0.0-beta.44", - "@babel/traverse": "7.0.0-beta.44", - "@babel/types": "7.0.0-beta.44", - "babylon": "7.0.0-beta.44", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "^1.0.0" - } - }, - "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==", - "requires": { - "source-map-support": "^0.5.3" - } - }, - "ganache-cli": { - "version": "6.1.8", - "resolved": "https://registry.npmjs.org/ganache-cli/-/ganache-cli-6.1.8.tgz", - "integrity": "sha512-yXzteu4SIgUL31mnpm9j+x6dpHUw0p/nsRVkcySKq0w+1vDxH9jMErP1QhZAJuTVE6ni4nfvGSNkaQx5cD3jfg==", - "requires": { - "source-map-support": "^0.5.3" - } - }, - "solidity-coverage": { - "version": "0.5.11", - "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.5.11.tgz", - "integrity": "sha512-qikdsSi6+9XbfvwA0aI7HUVpF9fIFNqRWTw23M89GMDY+b6Gj0wWU9IngJS0fimoZIAdEp3bfChxvpfVcrUesg==", - "requires": { - "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" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-support": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", - "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "truffle": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/truffle/-/truffle-4.1.14.tgz", - "integrity": "sha512-e7tTLvKP3bN9dE7MagfWyFjy4ZgoEGbeujECy1me1ENBzbj/aO/+45gs72qsL3+3IkCNNcWNOJjjrm8BYZZNNg==", - "requires": { - "mocha": "^4.1.0", - "original-require": "1.0.1", - "solc": "0.4.24" - } - }, - "zeppelin-solidity": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/zeppelin-solidity/-/zeppelin-solidity-1.12.0.tgz", - "integrity": "sha512-dgjPPnTmx14hAbTeOpTKemDeDCDdwglS0nquOAJG8h5o9zlb43FZafQSrMlIUUSp1EisDZfehrp5loGEYXHZBA==" - } - } - }, - "@types/concat-stream": { - "version": "1.6.0", - "resolved": "http://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.0.tgz", - "integrity": "sha1-OU2+C7X+5Gs42JZzXoto7yOQ0A0=", - "requires": { - "@types/node": "*" - } - }, - "@types/form-data": { - "version": "0.0.33", - "resolved": "http://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", - "integrity": "sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=", - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "9.6.35", - "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.35.tgz", - "integrity": "sha512-h5zvHS8wXHGa+Gcqs9K8vqCgOtqjr0+NqG/DDJmQIX1wpR9HivAfgV8bjcD3mGM4bPfQw5Aneb2Pn8355L83jA==" - }, - "@types/qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-mNhVdZHdtKHMMxbqzNK3RzkBcN1cux3AvuCYGTvjEIQT2uheH3eCAyYsbMbh2Bq8nXkeOWs1kyDiF7geWRFQ4Q==" - }, "abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=" }, - "abi-decoder": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/abi-decoder/-/abi-decoder-1.2.0.tgz", - "integrity": "sha512-y2OKSEW4gf2838Eavc56vQY9V46zaXkf3Jl1WpTfUBbzAVrXSr4JRZAAWv55Tv9s5WNz1rVgBgz5d2aJIL1QCg==", - "requires": { - "web3": "^0.18.4" - } - }, "abstract-leveldown": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz", @@ -279,32 +138,11 @@ "xtend": "~4.0.0" } }, - "acorn": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.2.tgz", - "integrity": "sha512-GXmKIvbrN3TV7aVqAzVFaMW8F8wzVX7voEBRO3bDA64+EX37YSayggRJP5Xig6HYHBkWKpFg9W5gg6orklubhg==" - }, - "acorn-jsx": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.0.tgz", - "integrity": "sha512-XkB50fn0MURDyww9+UYL3c1yLbOBz0ZFvrdYlGB8l+Ije1oSC75qAqrzSPjYQbdnQUzhlUGNKuesryAv0gxZOg==" - }, "aes-js": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-0.2.4.tgz", "integrity": "sha1-lLiBq3FyhtAV+iGeCPtmcJ3aWj0=" }, - "ajv": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz", - "integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==", - "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" - } - }, "align-text": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", @@ -343,89 +181,6 @@ "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==" }, - "anymatch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", - "requires": { - "micromatch": "^2.1.5", - "normalize-path": "^2.0.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" - } - }, - "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" - } - } - } - }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -477,11 +232,6 @@ "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", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" - }, "asn1": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", @@ -515,11 +265,6 @@ "lodash": "^4.17.10" } }, - "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=" - }, "async-eventemitter": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/async-eventemitter/-/async-eventemitter-0.2.4.tgz", @@ -1514,15 +1259,6 @@ "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/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", - "from": "bignumber.js@git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" - }, - "binary-extensions": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", - "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==" - }, "binaryextensions": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.1.tgz", @@ -1708,19 +1444,6 @@ "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "requires": { - "callsites": "^0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" - }, "camelcase": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", @@ -1768,11 +1491,6 @@ "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==" - }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", @@ -1788,11 +1506,6 @@ "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=" - }, "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -1806,45 +1519,6 @@ "functional-red-black-tree": "^1.0.1" } }, - "chokidar": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", - "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", - "requires": { - "anymatch": "^1.3.0", - "async-each": "^1.0.0", - "fsevents": "^1.0.0", - "glob-parent": "^2.0.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^2.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^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" - } - } - } - }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -1854,11 +1528,6 @@ "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==" - }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -1908,16 +1577,6 @@ } } }, - "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==", - "requires": { - "colors": "^1.1.2", - "object-assign": "^4.1.0", - "string-width": "^2.1.1" - } - }, "cli-truncate": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", @@ -2080,11 +1739,6 @@ "typedarray": "^0.0.6" } }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=" - }, "convert-source-map": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", @@ -2169,11 +1823,6 @@ "which": "^1.2.9" } }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" - }, "crypto-js": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.8.tgz", @@ -2320,35 +1969,6 @@ "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "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" - }, - "dependencies": { - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "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" - } - } - } - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2396,23 +2016,6 @@ } } }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "requires": { - "esutils": "^2.0.2" - } - }, - "docusaurus-init": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/docusaurus-init/-/docusaurus-init-1.0.2.tgz", - "integrity": "sha512-vfGstxIL5gK8/PCcGS+gY8MG4iw3fvnzpb3zOsG1kxHTJRekvebKd2x2Y/SPFt38jX15ZjDezrwi7YZX7/DggA==", - "requires": { - "chalk": "^2.1.0", - "shelljs": "^0.7.8" - } - }, "dom-walk": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", @@ -2507,11 +2110,6 @@ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-5.10.0.tgz", "integrity": "sha512-rXbzXWvnQxy+TcqZlARbWVQwgGVVouVJgFZhLVN5htjLxl1thstrP2ZGi0pXC309AbK7gVOPU+ulz/tmpCI7iw==" }, - "eol": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/eol/-/eol-0.9.1.tgz", - "integrity": "sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg==" - }, "errno": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", @@ -2597,358 +2195,25 @@ } } }, - "eslint": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.8.0.tgz", - "integrity": "sha512-Zok6Bru3y2JprqTNm14mgQ15YQu/SMDkWdnmHfFg770DIUlmMFd/gqqzCHekxzjHZJxXv3tmTpH0C1icaYJsRQ==", - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.5.3", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^2.1.0", - "eslint-scope": "^4.0.0", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^4.0.0", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "imurmurhash": "^0.1.4", - "inquirer": "^6.1.0", - "is-resolvable": "^1.1.0", - "js-yaml": "^3.12.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.5", - "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.1", - "require-uncached": "^1.0.3", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.0.2", - "text-table": "^0.2.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "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==", - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" - }, - "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" - } - }, - "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", - "requires": { - "ms": "^2.1.1" - } - }, - "eslint-scope": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "external-editor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", - "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "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==" - }, - "inquirer": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz", - "integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==", - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.0", - "figures": "^2.0.0", - "lodash": "^4.17.10", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.1.0", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "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==" - }, - "rxjs": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", - "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", - "requires": { - "tslib": "^1.9.0" - } - }, - "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" - }, - "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" - } - } - } - }, - "eslint-config-standard": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", - "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=" - }, - "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==", - "requires": { - "debug": "^2.6.9", - "resolve": "^1.5.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" - } - } - } - }, - "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=", - "requires": { - "debug": "^2.6.8", - "pkg-dir": "^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==", - "requires": { - "ms": "2.0.0" - } - }, - "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" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "requires": { - "find-up": "^1.0.0" - } - } - } - }, - "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==", - "requires": { - "contains-path": "^0.1.0", - "debug": "^2.6.8", - "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", - "read-pkg-up": "^2.0.0", - "resolve": "^1.6.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" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - } - } - }, - "eslint-plugin-node": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz", - "integrity": "sha512-xhPXrh0Vl/b7870uEbaumb2Q+LxaEcOQ3kS1jtIXanBAwpMre1l5q/l2l/hESYJGEFKuI78bp6Uw50hlpr7B+g==", - "requires": { - "ignore": "^3.3.6", - "minimatch": "^3.0.4", - "resolve": "^1.3.3", - "semver": "5.3.0" - }, - "dependencies": { - "semver": { - "version": "5.3.0", - "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" - } - } - }, - "eslint-plugin-promise": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.8.0.tgz", - "integrity": "sha512-JiFL9UFR15NKpHyGii1ZcvmtIqa3UTwiDAGb8atSffe43qJ3+1czVGN6UtkklpcJ2DVnqvTMzEKRaJdBkAL2aQ==" - }, - "eslint-plugin-standard": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.1.0.tgz", - "integrity": "sha512-fVcdyuKRr0EZ4fjWl3c+gp1BANFJD1+RaWa2UPYfMZ6jCtp5RG00kSaXnK/dE5sYzt4kaWJ9qdxqUfc0d9kX0w==" - }, - "eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" } }, - "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==" - }, "eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==" }, - "espree": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz", - "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", - "requires": { - "acorn": "^6.0.2", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - } - }, "esprima": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", - "requires": { - "estraverse": "^4.0.0" - } - }, "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", @@ -2997,43 +2262,6 @@ } } }, - "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==", - "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=", - "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=", - "requires": { - "resolve-from": "^3.0.0" - } - } - } - }, "eth-json-rpc-infura": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/eth-json-rpc-infura/-/eth-json-rpc-infura-3.1.2.tgz", @@ -3679,11 +2907,6 @@ "checkpoint-store": "^1.1.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=" - }, "fast-glob": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.2.tgz", @@ -3734,15 +2957,6 @@ "escape-string-regexp": "^1.0.5" } }, - "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=", - "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" - } - }, "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", @@ -3785,17 +2999,6 @@ "readable-stream": "^2.0.2" } }, - "flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", - "requires": { - "circular-json": "^0.3.1", - "del": "^2.0.2", - "graceful-fs": "^4.1.2", - "write": "^0.2.1" - } - }, "flow-parser": { "version": "0.76.0", "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.76.0.tgz", @@ -3876,468 +3079,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", - "optional": true, - "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "debug": { - "version": "2.6.9", - "bundled": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.5.1", - "bundled": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": 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" - } - }, - "glob": { - "version": "7.1.2", - "bundled": 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", - "bundled": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.21", - "bundled": true, - "optional": true, - "requires": { - "safer-buffer": "^2.1.0" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "minipass": { - "version": "2.2.4", - "bundled": true, - "requires": { - "safe-buffer": "^5.1.1", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.1.0", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "needle": { - "version": "2.2.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.10.0", - "bundled": 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" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.3", - "bundled": true, - "optional": true - }, - "npm-packlist": { - "version": "1.1.10", - "bundled": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": 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 - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.7", - "bundled": true, - "optional": true, - "requires": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": 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" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "optional": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-buffer": { - "version": "5.1.1", - "bundled": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "optional": true - }, - "semver": { - "version": "5.5.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "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" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "4.4.1", - "bundled": 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" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "optional": true, - "requires": { - "string-width": "^1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - }, - "yallist": { - "version": "3.0.2", - "bundled": true - } - } - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -4382,11 +3123,6 @@ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" }, - "get-port": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", - "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=" - }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", @@ -4872,32 +3608,11 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz", "integrity": "sha512-Ba4+0M4YvIDUUsprMjhVTU1yN9F2/LJSAl69ZpzaLT4l4j5mwTS6jqqW9Ojvj6lKz/veqPzpJBqGbXspOb533A==" }, - "http-basic": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-7.0.0.tgz", - "integrity": "sha1-gvClBr6UJzLsje6+6A50bvVzbbo=", - "requires": { - "@types/concat-stream": "^1.6.0", - "@types/node": "^9.4.1", - "caseless": "~0.12.0", - "concat-stream": "^1.4.6", - "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-response-object": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.1.tgz", - "integrity": "sha512-6L0Fkd6TozA8kFSfh9Widst0wfza3U1Ex2RjJ6zNDK0vR1U1auUR6jY4Nn2Xl7CCy0ikFmxW1XcspVpb9RvwTg==", - "requires": { - "@types/node": "^9.3.0" - } - }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -5002,11 +3717,6 @@ } } }, - "install": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/install/-/install-0.12.2.tgz", - "integrity": "sha512-+7thTb4Rpvs9mnlhHKGZFJbGOO6kyMgy+gg0sgM5vFzIFK0wrCYXqdlaM71Bi289DTuPHf61puMFsaZBcwDIrg==" - }, "interpret": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", @@ -5047,14 +3757,6 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "requires": { - "binary-extensions": "^1.0.0" - } - }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -5193,27 +3895,6 @@ } } }, - "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=" - }, - "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==", - "requires": { - "is-path-inside": "^1.0.0" - } - }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "requires": { - "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", @@ -5250,11 +3931,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==" - }, "is-retry-allowed": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", @@ -5410,11 +4086,6 @@ "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.3.1.tgz", "integrity": "sha1-hhIoAhQvCChQKg0d7h2V4lO7AkM=" }, - "js-string-escape": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", - "integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=" - }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -5589,11 +4260,6 @@ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, - "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==" - }, "json-stable-stringify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", @@ -5602,11 +4268,6 @@ "jsonify": "~0.0.0" } }, - "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=" - }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -6031,14 +4692,25 @@ } }, "load-json-file": { - "version": "2.0.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", "pify": "^2.0.0", - "strip-bom": "^3.0.0" + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "^0.2.0" + } + } } }, "loader-utils": { @@ -6528,11 +5200,6 @@ "minimatch": "^3.0.0" } }, - "mustache": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.2.tgz", - "integrity": "sha512-KpMNwdQsYz3O/SBS1qJ/o3sqUJ5wSb8gb0pul8CO0S56b9Y2ALm8zCfsjPXsqGFfoNBkDwZuZIAjhsZI03gYVQ==" - }, "mute-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", @@ -6568,11 +5235,6 @@ } } }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" - }, "neo-async": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.1.tgz", @@ -6933,11 +5595,6 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" }, - "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=" - }, "parse-glob": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", @@ -7006,11 +5663,6 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" - }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -7022,11 +5674,13 @@ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" }, "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "requires": { - "pify": "^2.0.0" + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "pathval": { @@ -7082,11 +5736,6 @@ "find-up": "^2.1.0" } }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==" - }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -7132,19 +5781,6 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, - "progress": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz", - "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==" - }, - "promise": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.2.tgz", - "integrity": "sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw==", - "requires": { - "asap": "~2.0.6" - } - }, "promise-to-callback": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/promise-to-callback/-/promise-to-callback-1.0.0.tgz", @@ -7154,15 +5790,6 @@ "set-immediate-shim": "^1.0.1" } }, - "prop-types": { - "version": "15.6.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", - "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", - "requires": { - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" - } - }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -7173,11 +5800,6 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, - "punycode": { - "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.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", @@ -7223,28 +5845,6 @@ "safe-buffer": "^5.1.0" } }, - "react": { - "version": "16.6.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.6.0.tgz", - "integrity": "sha512-zJPnx/jKtuOEXCbQ9BKaxDMxR0001/hzxXwYxG8septeyYGfsgAei6NgfbVgOhbY1WOP2o3VPs/E9HaN+9hV3Q==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.10.0" - } - }, - "react-dom": { - "version": "16.6.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.6.0.tgz", - "integrity": "sha512-Stm2D9dXEUUAQdvpvhvFj/DEXwC2PAL/RwEMhoN4dvvD2ikTlJegEXf97xryg88VIAU22ZAP7n842l+9BTz6+w==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.10.0" - } - }, "read-chunk": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz", @@ -7262,22 +5862,41 @@ } }, "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "requires": { - "load-json-file": "^2.0.0", + "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" + "path-type": "^1.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=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "dependencies": { + "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" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "^2.0.0" + } + } } }, "readable-stream": { @@ -7294,16 +5913,6 @@ "util-deprecate": "~1.0.1" } }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, "recast": { "version": "0.15.2", "resolved": "https://registry.npmjs.org/recast/-/recast-0.15.2.tgz", @@ -7367,11 +5976,6 @@ "safe-regex": "^1.1.0" } }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==" - }, "regexpu-core": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", @@ -7480,24 +6084,6 @@ "uuid": "^3.1.0" } }, - "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=", - "requires": { - "lodash": "^4.13.1" - } - }, - "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=", - "requires": { - "request-promise-core": "1.1.1", - "stealthy-require": "^1.1.0", - "tough-cookie": ">=2.3.3" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -7513,22 +6099,6 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" - } - } - }, "resolve": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", @@ -7664,15 +6234,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "scheduler": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.10.0.tgz", - "integrity": "sha512-+TSTVTCBAA3h8Anei3haDc1IRwMeDmtI/y/o3iBe3Mjl2vwYF9DtPDt929HyRmV/e7au7CLu8sc4C4W0VOs29w==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, "scoped-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/scoped-regex/-/scoped-regex-1.0.0.tgz", @@ -7768,15 +6329,6 @@ "safe-buffer": "^5.0.1" } }, - "sha1": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", - "integrity": "sha1-rdqnqTFo85PxnrKxUJFhjicA+Eg=", - "requires": { - "charenc": ">= 0.0.1", - "crypt": ">= 0.0.1" - } - }, "sha3": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/sha3/-/sha3-1.2.2.tgz", @@ -7928,11 +6480,6 @@ "kind-of": "^3.2.0" } }, - "sol-digger": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/sol-digger/-/sol-digger-0.0.2.tgz", - "integrity": "sha1-QGxKnTHiaef4jrHC6hATGOXgkCU=" - }, "sol-explore": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/sol-explore/-/sol-explore-1.6.2.tgz", @@ -8106,74 +6653,31 @@ "solidity-parser-sc": "0.4.11", "tree-kill": "^1.2.0", "web3": "^0.18.4" - } - }, - "solidity-docgen": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.1.0.tgz", - "integrity": "sha512-F7ufNWmlP5c5hIi66Ijv9tc+HNosyO7ijWq6pRtyBR1WqyJBH/0DJkD6QZI8HkE8p6LEXiPKxGBWbAeVT9Nu9g==", - "requires": { - "commander": "^2.14.1", - "lodash": "^4.17.5", - "mocha": "^5.0.1", - "mustache": "^2.3.0", - "react": "^16.2.0", - "react-dom": "^16.2.0", - "shelljs": "^0.8.1" }, "dependencies": { - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + "bignumber.js": { + "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", + "from": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" }, - "commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" - }, - "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", - "requires": { - "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.2", - "growl": "1.10.5", - "he": "1.1.1", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "supports-color": "5.4.0" - }, - "dependencies": { - "commander": { - "version": "2.15.1", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" - } - } + "utf8": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", + "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=" }, - "shelljs": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz", - "integrity": "sha512-pRXeNrCA2Wd9itwhvLp5LZQvPJ0wU6bcjaTMywHHGX5XWhVN2nzSu7WV0q+oUY7mGK3mgSkDDzP3MgjqdyIgbQ==", + "web3": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/web3/-/web3-0.18.4.tgz", + "integrity": "sha1-gewXhBRUkfLqqJVbMcBgSeB8Xn0=", "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" + "bignumber.js": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", + "crypto-js": "^3.1.4", + "utf8": "^2.1.1", + "xhr2": "*", + "xmlhttprequest": "*" } } } }, - "solidity-parser-antlr": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/solidity-parser-antlr/-/solidity-parser-antlr-0.2.15.tgz", - "integrity": "sha512-EzRI8/TR/ljTXkZAyAjb0w4G20wH2XM7pcNf87ifdV825AbUv7DkY7HmiZCTj6NeKtIx8Y1s0NZWPbj+JTp8Zw==" - }, "solidity-parser-sc": { "version": "0.4.11", "resolved": "https://registry.npmjs.org/solidity-parser-sc/-/solidity-parser-sc-0.4.11.tgz", @@ -8325,68 +6829,6 @@ } } }, - "solium": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/solium/-/solium-1.1.8.tgz", - "integrity": "sha512-fn0lusM6of14CytIDDHK73SGjn6NsVTaCVJjaKCKJyqKhT00rH/hDtvnIeZ2ZTD9z/xaXd4Js2brW3az6AV9RA==", - "requires": { - "ajv": "^5.2.2", - "chokidar": "^1.6.0", - "colors": "^1.1.2", - "commander": "^2.9.0", - "eol": "^0.9.1", - "js-string-escape": "^1.0.1", - "lodash": "^4.14.2", - "sol-digger": "0.0.2", - "sol-explore": "1.6.1", - "solium-plugin-security": "0.1.1", - "solparse": "2.2.5", - "text-table": "^0.2.0" - }, - "dependencies": { - "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" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" - }, - "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=" - }, - "sol-explore": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/sol-explore/-/sol-explore-1.6.1.tgz", - "integrity": "sha1-tZ8HPGn+MyVg1aEMMrqMp/KYbPs=" - }, - "solparse": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/solparse/-/solparse-2.2.5.tgz", - "integrity": "sha512-t7tvtR6KU6QfPYLMv1nlCh9DA8HYIu5tbjHpKu0fhGFZ1NuSp0KKDHfFHv07g6v1xgcuUY3rVqNFjZt5b9+5qA==", - "requires": { - "mocha": "^4.0.1", - "pegjs": "^0.10.0", - "yargs": "^10.0.3" - } - } - } - }, - "solium-plugin-security": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/solium-plugin-security/-/solium-plugin-security-0.1.1.tgz", - "integrity": "sha512-kpLirBwIq4mhxk0Y/nn5cQ6qdJTI+U1LO3gpoNIcqNaW+sI058moXBe2UiHs+9wvF9IzYD49jcKhFTxcR9u9SQ==" - }, "sort-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", @@ -8501,11 +6943,6 @@ } } }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" - }, "strict-uri-encode": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", @@ -8608,11 +7045,6 @@ "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", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" - }, "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", @@ -8626,50 +7058,6 @@ "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==", - "requires": { - "http-response-object": "^3.0.1", - "sync-rpc": "^1.2.1", - "then-request": "^6.0.0" - } - }, - "sync-rpc": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.4.tgz", - "integrity": "sha512-Iug+t1ICVFenUcTnDu8WXFnT+k8IVoLKGh8VA3eXUtl2Rt9SjKX3YEv33OenABqpTPL9QEaHv1+CNn2LK8vMow==", - "requires": { - "get-port": "^3.1.0" - } - }, - "table": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/table/-/table-5.1.0.tgz", - "integrity": "sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==", - "requires": { - "ajv": "^6.5.3", - "lodash": "^4.17.10", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - }, - "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=" - }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", - "requires": { - "is-fullwidth-code-point": "^2.0.0" - } - } - } - }, "tape": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/tape/-/tape-4.9.1.tgz", @@ -8724,31 +7112,6 @@ "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.2.0.tgz", "integrity": "sha512-j5EMxnryTvKxwH2Cq+Pb43tsf6sdEgw6Pdwxk83mPaq0ToeFJt6WE4J3s5BqY7vmjlLgkgXvhtXUxo80FyBhCA==" }, - "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==", - "requires": { - "@types/concat-stream": "^1.6.0", - "@types/form-data": "0.0.33", - "@types/node": "^8.0.0", - "@types/qs": "^6.2.31", - "caseless": "~0.12.0", - "concat-stream": "^1.6.0", - "form-data": "^2.2.0", - "http-basic": "^7.0.0", - "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==" - } - } - }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -8845,58 +7208,25 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" }, "truffle": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/truffle/-/truffle-4.1.13.tgz", - "integrity": "sha1-vydYaYi0/4RWPt+/MrR5QUCKdq0=", + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/truffle/-/truffle-4.1.15.tgz", + "integrity": "sha512-6gaNn9ZjvNjdalJMF/qEDUDoRdieKfdYcyFVpVxd+ogAta5kgJxI3XlEmS79Ih0vBhb00tKa9rBweVJ5892sYg==", "requires": { "mocha": "^4.1.0", "original-require": "1.0.1", - "solc": "0.4.24" + "solc": "0.4.25" }, "dependencies": { - "commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" - }, - "diff": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", - "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==" - }, - "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=" - }, - "mocha": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz", - "integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==", - "requires": { - "browser-stdout": "1.3.0", - "commander": "2.11.0", - "debug": "3.1.0", - "diff": "3.3.1", - "escape-string-regexp": "1.0.5", - "glob": "7.1.2", - "growl": "1.10.3", - "he": "1.1.1", - "mkdirp": "0.5.1", - "supports-color": "4.4.0" - } - }, - "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" + "solc": { + "version": "0.4.25", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.25.tgz", + "integrity": "sha512-jU1YygRVy6zatgXrLY2rRm7HW1d7a8CkkEgNJwvH2VLpWhMFsMdWcJn6kUqZwcSz/Vm+w89dy7Z/aB5p6AFTrg==", + "requires": { + "fs-extra": "^0.30.0", + "memorystream": "^0.3.1", + "require-from-string": "^1.1.0", + "semver": "^5.3.0", + "yargs": "^4.7.1" } } } @@ -8910,6 +7240,29 @@ "ethereumjs-wallet": "^0.6.0", "web3": "^0.18.2", "web3-provider-engine": "^14.0.5" + }, + "dependencies": { + "bignumber.js": { + "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", + "from": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" + }, + "utf8": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", + "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=" + }, + "web3": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/web3/-/web3-0.18.4.tgz", + "integrity": "sha1-gewXhBRUkfLqqJVbMcBgSeB8Xn0=", + "requires": { + "bignumber.js": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", + "crypto-js": "^3.1.4", + "utf8": "^2.1.1", + "xhr2": "*", + "xmlhttprequest": "*" + } + } } }, "tslib": { @@ -9063,14 +7416,6 @@ "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==" }, - "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==", - "requires": { - "punycode": "^2.1.0" - } - }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", @@ -9176,25 +7521,6 @@ } } }, - "web3": { - "version": "0.18.4", - "resolved": "https://registry.npmjs.org/web3/-/web3-0.18.4.tgz", - "integrity": "sha1-gewXhBRUkfLqqJVbMcBgSeB8Xn0=", - "requires": { - "bignumber.js": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", - "crypto-js": "^3.1.4", - "utf8": "^2.1.1", - "xhr2": "*", - "xmlhttprequest": "*" - }, - "dependencies": { - "utf8": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", - "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=" - } - } - }, "web3-provider-engine": { "version": "14.0.6", "resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-14.0.6.tgz", @@ -9552,14 +7878,6 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "requires": { - "mkdirp": "^0.5.1" - } - }, "write-file-atomic": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", @@ -9615,61 +7933,79 @@ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" }, "yargs": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.1.2.tgz", - "integrity": "sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", "requires": { - "cliui": "^4.0.0", + "cliui": "^3.2.0", "decamelize": "^1.1.1", - "find-up": "^2.1.0", "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", "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", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", "y18n": "^3.2.1", - "yargs-parser": "^8.1.0" + "yargs-parser": "^2.4.1" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", "wrap-ansi": "^2.0.0" } }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "requires": { - "ansi-regex": "^3.0.0" + "lcid": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=" } } }, "yargs-parser": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", - "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", "requires": { - "camelcase": "^4.1.0" + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" }, "dependencies": { "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" } } }, diff --git a/package.json b/package.json index 18a2748..1cba4a6 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,6 @@ }, "homepage": "https://web.thetta.io", "dependencies": { - "@thetta/core": "https://github.com/Thetta/Thetta-DAO-Framework.git#genericCaller", "babel-eslint": "^8.2.3", "babel-polyfill": "^6.26.0", "babel-register": "^6.26.0", @@ -31,7 +30,7 @@ "growl": "^1.10.0", "moment": "^2.22.2", "solidity-coverage": "^0.5.5", - "truffle": "^4.1.8", + "truffle": "^4.1.15", "truffle-hdwallet-provider": "0.0.5", "utf8": "^3.0.0", "zeppelin-solidity": "^1.9.0" diff --git a/scripts/test.sh b/scripts/test.sh index aa17c0f..e2bbbfe 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -11,14 +11,14 @@ cleanup() { } ganachecli_running() { - nc -z localhost 8555 + nc -z localhost 8545 } if ganachecli_running; then echo "Using existing ganache-cli instance" else echo "Starting ganache-cli" - ./node_modules/ganache-cli/build/cli.node.js --gasLimit 0xfffffffffff --defaultBalanceEther 200 --port 8555\ + ./node_modules/ganache-cli/build/cli.node.js --gasLimit 0xfffffffffff --defaultBalanceEther 200 --port 8545\ > /dev/null & ganachecli_pid=$! fi diff --git a/test/BoD.functional.tests.js b/test/BoD.functional.tests.js deleted file mode 100644 index fbc5847..0000000 --- a/test/BoD.functional.tests.js +++ /dev/null @@ -1,93 +0,0 @@ -const CheckExceptions = require("./utils/checkexceptions"); -const should = require("./utils/helpers"); - -const BodDaoFactory = artifacts.require("BodDaoFactory"); -const DaoBaseAuto = artifacts.require("DaoBaseAuto"); -const DaoBase = artifacts.require("DaoBase"); -const DaoBaseWithUnpackers = artifacts.require("DaoBaseWithUnpackers"); -const DaoStorage = artifacts.require("DaoStorage"); -const GenericProposal = artifacts.require("GenericProposal"); -const InformalProposal = artifacts.require("InformalProposal"); -const Voting = artifacts.require("Voting"); -const WeiTask = artifacts.require("WeiGenericTask"); - -contract("BodDaoFactory", (accounts) => { - - const creator = accounts[0]; - const director1 = accounts[1]; - const director2 = accounts[2]; - const director3 = accounts[3]; - const employee1 = accounts[4]; - const employee2 = accounts[5]; - - var bodDaoFactory; - let store; - let daoBase; - let bodDaoAuto; - let informalProposal; - let weiTask; - let voting; - - beforeEach(async () => { - bodDaoFactory = await BodDaoFactory.new(creator, [director1, director2, director3], [employee1, employee2]); - daoBase = DaoBaseWithUnpackers.at(await bodDaoFactory.daoBase()); - store = DaoStorage.at(await bodDaoFactory.store()); - bodDaoAuto = DaoBaseAuto.at(await bodDaoFactory.bodDaoAuto()); - informalProposal = await InformalProposal.new("ANY_TEXT"); - weiTask = await WeiTask.new(daoBase.address, "ANY_CAPTION", "ANY_DESC", true, false, 100, Math.floor(Date.now() / 1000), Math.floor(Date.now() / 1000)); - - // adding test proposal which creates a voting - await bodDaoAuto.addGroupMemberAuto("ANY_GROUP", employee1, { from: director1 }).should.be.fulfilled; - const proposalsCount = await store.getProposalsCount(); - const proposalAddress = await store.getProposalAtIndex(proposalsCount - 1); - const genericProposal = GenericProposal.at(proposalAddress); - const votingAddress = await genericProposal.getVoting(); - voting = Voting.at(votingAddress); - }); - - it("BoD member should be able to add new proposal", async () => { - await daoBase.addNewProposal(informalProposal.address, { from: director1 }).should.be.fulfilled; - }); - - it("employee should not be able to add new proposal", async () => { - await CheckExceptions.checkContractThrows( - daoBase.addNewProposal, [informalProposal.address, { from: employee1 }] - ); - }); - - it("BoD member should be able to manage groups only by voting", async () => { - await bodDaoAuto.addGroupMemberAuto("ANY_GROUP", employee1, { from: director1 }).should.be.fulfilled; - }); - - it("BoD member should be able to vote", async () => { - await voting.vote(true, { from: director2 }).should.be.fulfilled; - }); - - it("employee should not be able to vote", async () => { - await CheckExceptions.checkContractThrows( - voting.vote, [true, { from: employee1 }] - ); - }); - - it("50% of persons in a group are required to vote to finish the voting", async () => { - - let isFinished = await voting.isFinished(); - assert.isFalse(isFinished, "half of the users in group has not voted yet"); - - await voting.vote(false, { from: director2 }).should.be.fulfilled; - - isFinished = await voting.isFinished(); - assert.isTrue(isFinished, "half of the users should have voted"); - }); - - it("50% of 'yes' required to finish the voting with 'yes' result", async () => { - - let isYes = await voting.isYes(); - assert.isFalse(isYes, "half of the users in group has not voted for yes"); - - await voting.vote(true, { from: director2 }).should.be.fulfilled; - - isYes = await voting.isYes(); - assert.isTrue(isYes, "half of the users should have voted for yes"); - }); -}); diff --git a/test/Daico.functional.tests.js b/test/Daico.functional.tests.js index 762551d..228c2b3 100644 --- a/test/Daico.functional.tests.js +++ b/test/Daico.functional.tests.js @@ -1,63 +1,254 @@ const moment = require("moment"); -const Daico = artifacts.require("DaicoTestable"); +const Daico = artifacts.require("Daico"); const MintableToken = artifacts.require("MintableToken"); +const STOContract = artifacts.require("STOContract"); -contract("Daico", (accounts) => { +const { increaseTime } = require("./utils/helpers"); - const evercityMemberAddress = accounts[0]; - const projectOwnerAddress = accounts[1]; - const inverstorAddress = accounts[2]; - const otherAddress = accounts[3]; - const minQuorumRate = 70; - const minVoteRate = 70; - const tokenHoldersCount = 5; +contract("Daico functional tests", (accounts) => { + const evercity = accounts[0]; + const projectOwner = accounts[1]; + const investor1 = accounts[2]; + const investor2 = accounts[3]; + const investor3 = accounts[4]; + const investor4 = accounts[5]; + const investor5 = accounts[6]; + const returnFunds = accounts[7]; + const other = accounts[8]; + let stoContract; let daico; let daiToken; let projectToken; + let timestampsFinishAt; + let days = 24*60*60; - beforeEach(async() => { - daiToken = await MintableToken.new(); - projectToken = await MintableToken.new(); - await projectToken.mint(inverstorAddress, 1); - - timestampsFinishAt = [ - moment.unix(web3.eth.getBlock("latest").timestamp).add(1, 'week').unix(), - moment.unix(web3.eth.getBlock("latest").timestamp).add(5, 'weeks').unix() - ]; - daico = await Daico.new(daiToken.address, projectToken.address, projectOwnerAddress, 2, [1, 2], timestampsFinishAt, minVoteRate, minQuorumRate, tokenHoldersCount); - }); + var TS = { + Preparing : 0, + Investing: 1, + Voting : 2, + VotingDQ : 3, + RoadmapPreparing : 4, + RoadmapVoting : 5, + RoadmapVotingDQ : 6, + Success : 7, + Terminated : 8 + } - describe("onlyInvestor()", () => { - it("should revert if method is called not by investor", async() => { - await daico.vote(0, true, {from: otherAddress}).should.be.rejectedWith("revert"); - }); + async function getTaps() { + var data = await daico.getTaps(); + var out = []; + for(var i = 0; i < data[0].length; i++) { + out.push([new web3.BigNumber(data[0][i]).toNumber(), new web3.BigNumber(data[1][i]).toNumber()]) + } + return out; + } + + async function getProjectInfo() { + var data = await daico.proj() + return { + owner: data[0], + token: data[1], + daiToken: data[2], + createdAt: new web3.BigNumber(data[3]).toNumber(), + startedAt: new web3.BigNumber(data[4]).toNumber(), + investDuration: new web3.BigNumber(data[5]).toNumber(), + votingDuration: new web3.BigNumber(data[6]).toNumber(), + additionalDuration: new web3.BigNumber(data[7]).toNumber(), + changeRoadmapDuration: new web3.BigNumber(data[8]).toNumber(), + quorumPercent: new web3.BigNumber(data[9]).toNumber(), + quorumDecresedPercent: new web3.BigNumber(data[10]).toNumber(), + declinePercent: new web3.BigNumber(data[11]).toNumber(), + consensusPercent: new web3.BigNumber(data[12]).toNumber() + } + } + + async function getTapsInfo() { + var data = await daico.getTapsInfo() + data[1] = data[1].map((t)=> new web3.BigNumber(t).toNumber()) + return { + currentTap: new web3.BigNumber(data[0]).toNumber(), + tapsStages: data[1], + currentVoting: new web3.BigNumber(data[2]).toNumber() + + } + } + + function isArrayEquals(arr1, arr2) { + for(var i = 0; i < arr1.length; i++) { + if(arr1[i] != arr2[i]) { + return false; + } + } + return true; + } + + describe("Different scenarios", () => { + beforeEach(async() => { + evercityToken = await MintableToken.new({from: evercity}); + + stoContract = await STOContract.new(evercityToken.address, {from: projectOwner}); + + var returnAddress = evercity; + var tapFunds = [100, 100, 100]; + var tapDurations = [30, 30, 30]; + daico = await Daico.new( + projectOwner, + evercityToken.address, + stoContract.address, + returnAddress, + tapFunds, + tapDurations, {from:projectOwner}); + + await stoContract.setDaicoAddress(daico.address, {from:projectOwner}); + + await evercityToken.mint(investor1, 100, {from:evercity}); + await evercityToken.mint(investor2, 100, {from:evercity}); + await evercityToken.mint(investor3, 100, {from:evercity}); + + await evercityToken.approve(stoContract.address, 100, {from:investor1}); + await evercityToken.approve(stoContract.address, 100, {from:investor2}); + await evercityToken.approve(stoContract.address, 100, {from:investor3}); - it("should call method that can be executed only by investor", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; + await stoContract.invest(100, {from:investor1}); + await stoContract.invest(50, {from:investor2}); + await stoContract.invest(50, {from:investor2}); + await stoContract.invest(100, {from:investor3}); + await stoContract.invest(50, {from:investor3}).should.be.rejectedWith('revert'); }); - }); - describe("validTapIndex()", () => { - it("should revert if tap index does not exist", async() => { - await daico.isTapWithdrawAcceptedByInvestors(2).should.be.rejectedWith("revert"); + it(`1. Сценарий: все голосования происходят вовремя и без задержек, все голоса за`, async() => { + await daico.withdrawFundsFromTap(0, {from:projectOwner}); + assert.equal(new web3.BigNumber(await evercityToken.balanceOf(projectOwner)).toNumber(), 100); + await increaseTime(23*days); + await daico.vote(true, {from: investor1}); + await daico.vote(true, {from: investor2}); + await daico.vote(true, {from: investor3}); + await increaseTime(7*days); // голосование кончилось + + await daico.withdrawFundsFromTap(1, {from:projectOwner}); + assert.equal(new web3.BigNumber(await evercityToken.balanceOf(projectOwner)).toNumber(), 200); + await increaseTime(23*days); // Голосование началось + + await daico.vote(true, {from: investor1}); + await daico.vote(true, {from: investor2}); + await daico.vote(true, {from: investor3}); + await increaseTime(7*days); // голосование кончилось + + await daico.withdrawFundsFromTap(2, {from:projectOwner}); + assert.equal(new web3.BigNumber(await evercityToken.balanceOf(projectOwner)).toNumber(), 300); }); - it("should call method with valid tap index", async() => { - await daico.isTapWithdrawAcceptedByInvestors(1).should.be.fulfilled; + it(`2. Сценарий: задержки при голосовании. в первом голосует 66/70%, во втором (пониженный кворум) – 33/50%. + Проект закрывается, средства возвращаются инвесторам`, async() => { + assert.isTrue(isArrayEquals((await getTapsInfo()).tapsStages, [TS.Success, TS.Preparing, TS.Preparing])); + await increaseTime(23*days); + assert.isTrue(isArrayEquals((await getTapsInfo()).tapsStages, [TS.Success, TS.Voting, TS.Preparing])); + + await daico.vote(true, {from: investor1}); + await daico.vote(true, {from: investor2}); + await increaseTime(7*days); + assert.isTrue(isArrayEquals((await getTapsInfo()).tapsStages, [TS.Success, TS.VotingDQ, TS.Preparing])); + await daico.vote(true, {from: investor1}); + await increaseTime(7*days); + assert.isTrue(isArrayEquals((await getTapsInfo()).tapsStages, [TS.Success, TS.Terminated, TS.Preparing])); + assert.equal(new web3.BigNumber(await evercityToken.balanceOf(projectOwner)).toNumber(), 0); }); - }); - describe("validVotingIndex()", () => { - it("should revert if voting index does not exist", async() => { - await daico.vote(2, true, {from: inverstorAddress}).should.be.rejectedWith("revert"); + it(`3. Сценарий: задержки при голосовании. в первом голосует 66/70%, во втором (пониженный кворум) – 66/50%. + Далее аналогичная ситуация`, async() => { + assert.isTrue(isArrayEquals((await getTapsInfo()).tapsStages, [TS.Success, TS.Preparing, TS.Preparing])); + await increaseTime(23*days); + assert.isTrue(isArrayEquals((await getTapsInfo()).tapsStages, [TS.Success, TS.Voting, TS.Preparing])); + + await daico.vote(true, {from: investor1}); + await daico.vote(true, {from: investor2}); + await increaseTime(7*days); + assert.isTrue(isArrayEquals((await getTapsInfo()).tapsStages, [TS.Success, TS.VotingDQ, TS.Preparing])); + await daico.vote(true, {from: investor1}); + await daico.vote(true, {from: investor2}); + await increaseTime(7*days); + assert.isTrue(isArrayEquals((await getTapsInfo()).tapsStages, [TS.Success, TS.Success, TS.Preparing])); + await increaseTime(23*days); + await daico.vote(true, {from: investor1}); + await daico.vote(true, {from: investor2}); + await increaseTime(7*days); + assert.isTrue(isArrayEquals((await getTapsInfo()).tapsStages, [TS.Success, TS.Success, TS.VotingDQ])); + await daico.vote(true, {from: investor1}); + await daico.vote(true, {from: investor2}); + await increaseTime(7*days); + assert.isTrue(isArrayEquals((await getTapsInfo()).tapsStages, [TS.Success, TS.Success, TS.Success])); + await daico.withdrawFundsFromTap(0, {from:projectOwner}); + await daico.withdrawFundsFromTap(1, {from:projectOwner}); + await daico.withdrawFundsFromTap(2, {from:projectOwner}); + assert.equal(new web3.BigNumber(await evercityToken.balanceOf(projectOwner)).toNumber(), 300); }); - it("should call method with valid tap index", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; + it(`4. Сценарий: отсутствие консенсуса. во втором голосовании один против, + заменяется roadmap (вместо последнего периода [100], [30] предлагается два периода [50, 150], [50, 50]), + его утверждают, привлекаются новые инвестиции`, async() => { + // Есть некоторые особенности в реализации proposeNewRoadmap: + // 1. Стадия дополнительных инвестиций длится ровно неделю, даже если все инвестиции уже собраны. + // 2. Новый roadmap должен содержать и предыдущие taps, притом пройденные taps и текущий в новом roadmap должны быть равны таковым в старом roadmap + // 3. Новый roadmap должен требовать больше денег, чем предыдущий + // 4. Должно быть больше или столько же stage + await daico.withdrawFundsFromTap(0, {from:projectOwner}); + assert.equal(new web3.BigNumber(await evercityToken.balanceOf(projectOwner)).toNumber(), 100); + await increaseTime(23*days); // Голосование началось + await daico.vote(true, {from: investor1}); + await daico.vote(true, {from: investor2}); + await daico.vote(false, {from: investor3}); + await increaseTime(7*days); + + await daico.proposeNewRoadmap([100, 100, 100, 150], [30, 30, 50, 50], {from: projectOwner}); + await increaseTime(21*days); + assert.equal((await getTapsInfo()).tapsStages.toString(), [TS.Success, TS.RoadmapVoting, TS.Preparing, TS.Preparing].toString()) + await daico.vote(true, {from: investor1}); + await daico.vote(true, {from: investor2}); + await daico.vote(true, {from: investor3}); + await increaseTime(7*days); + assert.equal((await getTapsInfo()).tapsStages.toString(), [TS.Success, TS.Investing, TS.Preparing, TS.Preparing].toString()) + + await evercityToken.mint(investor1, 50, {from: evercity}); + await evercityToken.mint(investor2, 50, {from: evercity}); + await evercityToken.mint(investor3, 50, {from: evercity}); + + await evercityToken.approve(stoContract.address, 50, {from:investor1}); + await evercityToken.approve(stoContract.address, 50, {from:investor2}); + await evercityToken.approve(stoContract.address, 50, {from:investor3}); + + await stoContract.invest(50, {from:investor1}); + assert.equal((await getTapsInfo()).tapsStages.toString(), [TS.Success, TS.Investing, TS.Preparing, TS.Preparing].toString()) + + await stoContract.invest(50, {from:investor2}); + assert.equal((await getTapsInfo()).tapsStages.toString(), [TS.Success, TS.Investing, TS.Preparing, TS.Preparing].toString()) + await stoContract.invest(50, {from:investor3}); + await increaseTime(7*days); + assert.equal((await getTapsInfo()).tapsStages.toString(), [TS.Success, TS.Success, TS.Preparing, TS.Preparing].toString()) + await daico.withdrawFundsFromTap(1, {from:projectOwner}); + assert.equal(new web3.BigNumber(await evercityToken.balanceOf(projectOwner)).toNumber(), 200); + + await increaseTime(43*days); // Голосование началось + assert.equal((await getTapsInfo()).tapsStages.toString(), [TS.Success, TS.Success, TS.Voting, TS.Preparing].toString()) + await daico.vote(true, {from: investor1}); + await daico.vote(true, {from: investor2}); + await daico.vote(true, {from: investor3}); + await increaseTime(7*days); + await daico.withdrawFundsFromTap(2, {from:projectOwner}); + assert.equal(new web3.BigNumber(await evercityToken.balanceOf(projectOwner)).toNumber(), 300); + + assert.equal((await getTapsInfo()).tapsStages.toString(), [TS.Success, TS.Success, TS.Success, TS.Preparing].toString()) + await increaseTime(43*days); // Голосование началось + assert.equal((await getTapsInfo()).tapsStages.toString(), [TS.Success, TS.Success, TS.Success, TS.Voting].toString()) + await daico.vote(true, {from: investor1}); + await daico.vote(true, {from: investor2}); + await daico.vote(true, {from: investor3}); + await increaseTime(7*days); + assert.equal((await getTapsInfo()).tapsStages.toString(), [TS.Success, TS.Success, TS.Success, TS.Success].toString()) + await daico.withdrawFundsFromTap(3, {from:projectOwner}); + assert.equal(new web3.BigNumber(await evercityToken.balanceOf(projectOwner)).toNumber(), 450); }); }); - }); diff --git a/test/Daico.tests.js b/test/Daico.tests.js deleted file mode 100644 index d3f4726..0000000 --- a/test/Daico.tests.js +++ /dev/null @@ -1,548 +0,0 @@ -const moment = require("moment"); -const { increaseTime } = require("./utils/helpers"); - -const Daico = artifacts.require("DaicoTestable"); -const MintableToken = artifacts.require("MintableToken"); - -contract("Daico", (accounts) => { - - const evercityMemberAddress = accounts[0]; - const projectOwnerAddress = accounts[1]; - const inverstorAddress = accounts[2]; - const inverstorAddress2 = accounts[3]; - const inverstorAddress3 = accounts[4]; - const inverstorAddress4 = accounts[5]; - const inverstorAddress5 = accounts[6]; - - const VOTING_TYPE_RELEASE_TAP = 0; - const VOTING_TYPE_RELEASE_TAP_DECREASED_QUORUM = 1; - const VOTING_TYPE_CHANGE_ROADMAP = 2; - const VOTING_TYPE_CHANGE_ROADMAP_DECREASED_QUORUM = 3; - const VOTING_TYPE_TERMINATE_PROJECT = 4; - const VOTING_TYPE_TERMINATE_PROJECT_DECREASED_QUORUM = 5; - - const VOTING_RESULT_ACCEPT = 0; - const VOTING_RESULT_DECLINE = 1; - const VOTING_RESULT_QUORUM_NOT_REACHED = 2; - const VOTING_RESULT_NO_DECISION = 3; - - const minQuorumRate = 70; - const minVoteRate = 70; - const tokenHoldersCount = 5; - - let daico; - let daiToken; - let projectToken; - let timestampsFinishAt; - - beforeEach(async() => { - daiToken = await MintableToken.new(); - await daiToken.mint(evercityMemberAddress, 3); - - projectToken = await MintableToken.new(); - await projectToken.mint(inverstorAddress, 1); - await projectToken.mint(inverstorAddress2, 1); - await projectToken.mint(inverstorAddress3, 1); - await projectToken.mint(inverstorAddress4, 1); - - timestampsFinishAt = [ - moment.unix(web3.eth.getBlock("latest").timestamp).add(1, 'week').unix(), - moment.unix(web3.eth.getBlock("latest").timestamp).add(5, 'weeks').unix() - ]; - daico = await Daico.new(daiToken.address, projectToken.address, projectOwnerAddress, 2, [1, 2], timestampsFinishAt, minVoteRate, minQuorumRate, tokenHoldersCount); - await daiToken.transfer(daico.address, 3, {from: evercityMemberAddress}); - }); - - describe("constructor()", () => { - it("should revert if DAI token address is 0x00", async() => { - await Daico.new(0x00, projectToken.address, projectOwnerAddress, 2, [1, 2], timestampsFinishAt, minVoteRate, minQuorumRate, tokenHoldersCount).should.be.rejectedWith("revert"); - }); - - it("should revert if project token address is 0x00", async() => { - await Daico.new(daiToken.address, 0x00, projectOwnerAddress, 2, [1, 2], timestampsFinishAt, minVoteRate, minQuorumRate, tokenHoldersCount).should.be.rejectedWith("revert"); - }); - - it("should revert if project owner address is 0x00", async() => { - await Daico.new(daiToken.address, projectToken.address, 0x00, 2, [1, 2], timestampsFinishAt, minVoteRate, minQuorumRate, tokenHoldersCount).should.be.rejectedWith("revert"); - }); - - it("should revert if taps count is 0", async() => { - await Daico.new(daiToken.address, projectToken.address, projectOwnerAddress, 0, [1, 2], timestampsFinishAt, minVoteRate, minQuorumRate, tokenHoldersCount).should.be.rejectedWith("revert"); - }); - - it("should revert if tap amounts array length not equal to taps count", async() => { - await Daico.new(daiToken.address, projectToken.address, projectOwnerAddress, 2, [], timestampsFinishAt, minVoteRate, minQuorumRate, tokenHoldersCount).should.be.rejectedWith("revert"); - }); - - it("should revert if tap timestamps finish at array length not equal to taps count", async() => { - await Daico.new(daiToken.address, projectToken.address, projectOwnerAddress, 2, [1, 2], [], minVoteRate, minQuorumRate, tokenHoldersCount).should.be.rejectedWith("revert"); - }); - - it("should revert if min quorum rate is 0", async() => { - await Daico.new(daiToken.address, projectToken.address, projectOwnerAddress, 2, [1, 2], timestampsFinishAt, 0, minVoteRate, tokenHoldersCount).should.be.rejectedWith("revert"); - }); - - it("should revert if min vote rate is 0", async() => { - await Daico.new(daiToken.address, projectToken.address, projectOwnerAddress, 2, [1, 2], timestampsFinishAt, minQuorumRate, 0, tokenHoldersCount).should.be.rejectedWith("revert"); - }); - - it("should revert if token holders count is 0", async() => { - await Daico.new(daiToken.address, projectToken.address, projectOwnerAddress, 2, [1, 2], timestampsFinishAt, minQuorumRate, minVoteRate, 0).should.be.rejectedWith("revert"); - }); - - it("should set contract properties", async() => { - const daicoNew = await Daico.new(daiToken.address, projectToken.address, projectOwnerAddress, 2, [1, 2], [3,4], 3, 4, 5).should.be.fulfilled; - assert.equal(await daicoNew.daiToken(), daiToken.address); - assert.equal(await daicoNew.projectToken(), projectToken.address); - assert.equal(await daicoNew.projectOwner(), projectOwnerAddress); - assert.equal(await daicoNew.tapsCount(), 2); - assert.equal(await daicoNew.tapAmounts(0), 1); - assert.equal(await daicoNew.tapAmounts(1), 2); - assert.equal(await daicoNew.tapTimestampsFinishAt(0), 3); - assert.equal(await daicoNew.tapTimestampsFinishAt(1), 4); - assert.equal(await daicoNew.minQuorumRate(), 3); - assert.equal(await daicoNew.minVoteRate(), 4); - assert.equal(await daicoNew.tokenHoldersCount(), 5); - }); - - it("should create initial votings of type ReleaseTap", async() => { - assert.equal(await daico.votingsCount(), 2); - const voting = await daico.votings(0); - assert.equal(voting[5].sub(voting[4]), 7 * 24 * 60 * 60); - assert.equal(voting[6], VOTING_TYPE_RELEASE_TAP); - }); - }); - - describe("createVoting()", () => { - it("should revert if quorum rate is 0", async() => { - await daico.createVoting(0, 0, 1, 1, VOTING_TYPE_RELEASE_TAP).should.be.rejectedWith("revert"); - }); - - it("should revert if created at is 0", async() => { - await daico.createVoting(0, 1, 0, 1, VOTING_TYPE_RELEASE_TAP).should.be.rejectedWith("revert"); - }); - - it("should revert if finish at is 0", async() => { - await daico.createVoting(0, 1, 1, 0, VOTING_TYPE_RELEASE_TAP).should.be.rejectedWith("revert"); - }); - - it("should create a new voting", async() => { - await daico.createVoting(0, 1, 2, 3, VOTING_TYPE_RELEASE_TAP).should.be.fulfilled; - const votingsCount = await daico.votingsCount(); - const voting = await daico.votings(votingsCount.sub(1)); - assert.equal(voting[0], 0); - assert.equal(voting[3], 1); - assert.equal(voting[4], 2); - assert.equal(voting[5], 3); - assert.equal(voting[6], VOTING_TYPE_RELEASE_TAP); - }); - - it("should update contract properties", async() => { - const votingsCountBefore = (await daico.votingsCount()).toNumber(); - const tapVotingsCountBefore = (await daico.tapVotingsCount(0)).toNumber(); - - await daico.createVoting(0, 1, 2, 3, VOTING_TYPE_RELEASE_TAP).should.be.fulfilled; - - const votingsCountAfter = (await daico.votingsCount()).toNumber(); - const tapVotingsCountAfter = (await daico.tapVotingsCount(0)).toNumber(); - - assert.equal(await daico.tapVotings(0, tapVotingsCountAfter - 1), votingsCountAfter - 1); - assert.equal(tapVotingsCountAfter - 1, tapVotingsCountBefore); - assert.equal(votingsCountAfter - 1, votingsCountBefore); - }); - }); - - describe("createVotingByInvestor()", () => { - it("should revert if voting type is not: ChangeRoadmap, ChangeRoadmapDecreasedQuorum, TerminateProject, TerminateProjectDecreasedQuorum", async() => { - await daico.createVotingByInvestor(0, VOTING_TYPE_RELEASE_TAP, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert if last voting is not finished", async() => { - await daico.createVotingByInvestor(0, VOTING_TYPE_CHANGE_ROADMAP, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert on ChangeRoadmap voting type when last voting is not: ReleaseTap, ReleaseTapDecreasedQuorum, TerminateProject, TerminateProjectDecreasedQuorum", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_CHANGE_ROADMAP, {from: inverstorAddress}).should.be.fulfilled; - await increaseTime(28 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_CHANGE_ROADMAP, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert on ChangeRoadmap voting type when last voting is ReleaseTap or ReleaseTapDecreasedQuorum with voting result not NoDecision", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_CHANGE_ROADMAP, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert on ChangeRoadmap voting type when last voting is TerminateProject or TerminateProjectDecreasedQuorum with voting result not Decline", async() => { - await daico.vote(0, false, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT, {from: inverstorAddress}).should.be.fulfilled; - await increaseTime(28 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_CHANGE_ROADMAP, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should create a new voting of type ChangeRoadmap", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_CHANGE_ROADMAP, {from: inverstorAddress}).should.be.fulfilled; - }); - - it("should revert on ChangeRoadmapDecreasedQuorum voting type when last voting is not ChangeRoadmap or ChangeRoadmapDecreasedQuorum", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_CHANGE_ROADMAP_DECREASED_QUORUM, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert on ChangeRoadmapDecreasedQuorum voting type when last voting result is not QuorumNotReached or NoDecision", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_CHANGE_ROADMAP, {from: inverstorAddress}).should.be.fulfilled; - await increaseTime(21 * 24 * 60 * 60); - await daico.vote(2, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(28 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_CHANGE_ROADMAP_DECREASED_QUORUM, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should create a new voting of type ChangeRoadmapDecreasedQuorum", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_CHANGE_ROADMAP, {from: inverstorAddress}).should.be.fulfilled; - await increaseTime(21 * 24 * 60 * 60); - await daico.vote(2, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(2, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(2, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(28 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_CHANGE_ROADMAP_DECREASED_QUORUM, {from: inverstorAddress}).should.be.fulfilled; - }); - - it("should revert on TerminateProject voting type when last voting is not: ReleaseTap, ReleaseTapDecreasedQuorum, ChangeRoadmap, ChangeRoadmapDecreasedQuorum", async() => { - await daico.vote(0, false, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT, {from: inverstorAddress}).should.be.fulfilled; - await increaseTime(14 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert on TerminateProject voting type when last voting result is not Decline", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should create a new voting of type TerminateProject", async() => { - await daico.vote(0, false, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT, {from: inverstorAddress}).should.be.fulfilled; - }); - - it("should revert on TerminateProjectDecreasedQuorum voting type when last voting is not TerminateProject or TerminateProjectDecreasedQuorum", async() => { - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT_DECREASED_QUORUM, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert on TerminateProjectDecreasedQuorum voting type when last voting result is not QuorumReached or NoDecision", async() => { - await daico.vote(0, false, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(2, false, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(2, false, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(2, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(2, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(14 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT_DECREASED_QUORUM, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should create a new voting of type TerminateProjectDecreasedQuorum", async() => { - await daico.vote(0, false, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(2, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(2, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(14 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT_DECREASED_QUORUM, {from: inverstorAddress}).should.be.fulfilled; - }); - }); - - describe("createVotingByOwner()", () => { - it("should revert if voting type is not release tap decreased quorum", async() => { - await daico.createVotingByOwner(0, VOTING_TYPE_RELEASE_TAP, {from: evercityMemberAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert if latest voting for particular tap is not finished", async() => { - await daico.createVotingByOwner(0, VOTING_TYPE_RELEASE_TAP_DECREASED_QUORUM, {from: evercityMemberAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert if latest voting is not ReleaseTap or ReleaseTapDecreasedQuorum", async() => { - await daico.vote(0, false, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT, {from: inverstorAddress}).should.be.fulfilled; - await increaseTime(14 * 24 * 60 * 60); - await daico.createVotingByOwner(0, VOTING_TYPE_RELEASE_TAP_DECREASED_QUORUM, {from: evercityMemberAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert if latest voting result is not quorum not reached", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByOwner(0, VOTING_TYPE_RELEASE_TAP_DECREASED_QUORUM, {from: evercityMemberAddress}).should.be.rejectedWith("revert"); - }); - - it("should create a new voting", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress3}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByOwner(0, VOTING_TYPE_RELEASE_TAP_DECREASED_QUORUM, {from: evercityMemberAddress}).should.be.fulfilled; - }); - }); - - describe("getVotingResult()", () => { - it("should return quorum not reached", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress3}).should.be.fulfilled; - assert.equal(await daico.getVotingResult(0), VOTING_RESULT_QUORUM_NOT_REACHED); - }); - - it("should return accept", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress4}).should.be.fulfilled; - assert.equal(await daico.getVotingResult(0), VOTING_RESULT_ACCEPT); - }); - - it("should return decline", async() => { - await daico.vote(0, false, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - assert.equal(await daico.getVotingResult(0), VOTING_RESULT_DECLINE); - }); - - it("should return no decision", async() => { - await daico.vote(0, false, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress4}).should.be.fulfilled; - assert.equal(await daico.getVotingResult(0), VOTING_RESULT_NO_DECISION); - }); - }); - - describe("isInvestorVoted()", () => { - it("should revert if investor address is 0x00", async() => { - await daico.isInvestorVoted(0, 0x00).should.be.rejectedWith("revert"); - }); - - it("should return false if investor has not yet voted", async() => { - assert.equal(await daico.isInvestorVoted(0, inverstorAddress), false); - }); - - it("should return true if investor has already voted", async() => { - await daico.vote(0, false, {from: inverstorAddress}).should.be.fulfilled; - assert.equal(await daico.isInvestorVoted(0, inverstorAddress), true); - }); - }); - - describe("isProjectTerminated()", () => { - it("should return false if project is not terminated", async() => { - assert.equal(await daico.isProjectTerminated(), false); - }); - - it("should return true if project is terminated", async() => { - await daico.vote(0, false, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress4}).should.be.fulfilled; - assert.equal(await daico.isProjectTerminated(), true); - }); - }); - - describe("isTapWithdrawAcceptedByInvestors()", () => { - it("should return false if investors have not accepted tap release", async() => { - assert.equal(await daico.isTapWithdrawAcceptedByInvestors(0), false); - }); - - it("should return true if investors have accepted tap release", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress4}).should.be.fulfilled; - assert.equal(await daico.isTapWithdrawAcceptedByInvestors(0), true); - }); - }); - - describe("vote()", () => { - it("should revert if it is too early to vote", async() => { - await daico.vote(1, true, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert if it is too late to vote", async() => { - const daicoNew = await Daico.new(daiToken.address, projectToken.address, projectOwnerAddress, 2, [1, 2], timestampsFinishAt, minVoteRate, minQuorumRate, tokenHoldersCount); - await increaseTime(7 * 24 * 60 * 60); - await daicoNew.vote(0, true, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert if project is terminated", async() => { - // terminate project - await daico.vote(0, false, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress4}).should.be.fulfilled; - - await daico.vote(2, false, {from: inverstorAddress5}).should.be.rejectedWith("revert"); - }); - - it("should revert if investor has already voted", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should mark investor as already voted", async() => { - assert.equal(await daico.isInvestorVoted(0, inverstorAddress), false); - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - assert.equal(await daico.isInvestorVoted(0, inverstorAddress), true); - }); - - it("should update yes votes count", async() => { - assert.equal((await daico.votings(0))[1], 0); - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - assert.equal((await daico.votings(0))[1], 1); - }); - - it("should update no votes count", async() => { - assert.equal((await daico.votings(0))[2], 0); - await daico.vote(0, false, {from: inverstorAddress}).should.be.fulfilled; - assert.equal((await daico.votings(0))[2], 1); - }); - }); - - describe("withdrawFunding()", () => { - it("should revert if project is not terminated", async() => { - await daico.withdrawFunding({from: evercityMemberAddress}).should.be.rejectedWith("revert"); - }); - - it("should withdraw DAI tokens", async() => { - // terminate project - await daico.vote(0, false, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, false, {from: inverstorAddress4}).should.be.fulfilled; - await increaseTime(7 * 24 * 60 * 60); - await daico.createVotingByInvestor(0, VOTING_TYPE_TERMINATE_PROJECT, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(2, true, {from: inverstorAddress4}).should.be.fulfilled; - // withdraw DAI tokens - assert.equal(await daiToken.balanceOf(evercityMemberAddress), 0); - await daico.withdrawFunding({from: evercityMemberAddress}).should.be.fulfilled; - assert.equal(await daiToken.balanceOf(evercityMemberAddress), 3); - }); - }); - - describe("withdrawTapPayment()", () => { - it("should revert if caller is not project owner", async() => { - await daico.withdrawTapPayment(0, {from: inverstorAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert if tap release is not accepted by investors", async() => { - await daico.withdrawTapPayment(0, {from: projectOwnerAddress}).should.be.rejectedWith("revert"); - }); - - it("should revert if tap is already withdrawn", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress4}).should.be.fulfilled; - await daico.withdrawTapPayment(0, {from: projectOwnerAddress}).should.be.fulfilled; - await daico.withdrawTapPayment(0, {from: projectOwnerAddress}).should.be.rejectedWith("revert"); - }); - - it("should create a new tap payment", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress4}).should.be.fulfilled; - await daico.withdrawTapPayment(0, {from: projectOwnerAddress}).should.be.fulfilled; - - const tapPayment = await daico.tapPayments(0); - assert.equal(tapPayment[0], 1); - assert.notEqual(tapPayment[1], 0); - assert.equal(tapPayment[2], true); - }); - - it("should transfer DAI tokens to project owner", async() => { - await daico.vote(0, true, {from: inverstorAddress}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress2}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress3}).should.be.fulfilled; - await daico.vote(0, true, {from: inverstorAddress4}).should.be.fulfilled; - - assert.equal(await daiToken.balanceOf(projectOwnerAddress), 0); - await daico.withdrawTapPayment(0, {from: projectOwnerAddress}).should.be.fulfilled; - assert.equal(await daiToken.balanceOf(projectOwnerAddress), 1); - }); - }); - -}); diff --git a/test/DevZenDao.functional.tests.js b/test/DevZenDao.functional.tests.js deleted file mode 100644 index a9712a0..0000000 --- a/test/DevZenDao.functional.tests.js +++ /dev/null @@ -1,321 +0,0 @@ -const { increaseTime } = require("./utils/helpers"); - -const DevZenDaoFactory = artifacts.require("DevZenDaoFactory"); -const DevZenDaoAuto = artifacts.require("DevZenDaoAuto"); -const DevZenDao = artifacts.require("DevZenDao"); -const DaoBase = artifacts.require("DaoBase"); -const IProposal = artifacts.require("IProposal"); -const IVoting = artifacts.require("IVoting"); - -const DevZenDaoWithUnpackers = artifacts.require("DevZenDaoWithUnpackers"); -const StdDaoToken = artifacts.require("StdDaoToken"); - -const getVoting = async(daoBase,i) => { - let pa = await daoBase.getProposalAtIndex(i); - let proposal = await IProposal.at(pa); - let votingAddress = await proposal.getVoting(); - let voting = await IVoting.at(votingAddress); - return voting; -} - -const checkVoting = async(voting, yes, no, finished, isYes) => { - const r1 = await voting.getVotingStats(); - assert.equal(r1[0].toNumber(),yes,'yes'); - assert.equal(r1[1].toNumber(),no,'no'); - assert.strictEqual(await voting.isFinished(),finished,'Voting is still not finished'); - assert.strictEqual(await voting.isYes(),isYes,'Voting is still not finished'); -} - -contract("DevZenDaoAuto", (accounts) => { - - const boss = accounts[0]; - const newBoss = accounts[1] - const guest1 = accounts[2]; - const guest2 = accounts[3]; - const guest3 = accounts[4]; - const teamMember1 = accounts[5]; - const teamMember2 = accounts[6]; - const patron = accounts[7]; - - let devZenDaoFactory; - let devZenDao; - let devZenToken; - let repToken; - let devZenDaoAuto; - let daoBase; - - beforeEach(async () => { - devZenDaoFactory = await DevZenDaoFactory.new(boss, [teamMember1, teamMember2]); - devZenDao = DevZenDao.at(await devZenDaoFactory.devZenDao()); - daoBase = DaoBase.at(await devZenDaoFactory.daoBase()); - devZenToken = StdDaoToken.at(await devZenDao.devZenToken()); - repToken = StdDaoToken.at(await devZenDao.repToken()); - devZenDaoAuto = DevZenDaoAuto.at(await devZenDaoFactory.devZenDaoAuto()); - }); - - describe("addGroupMemberAuto", () => { - it("should add a new group member on successful voting", async() => { - await devZenDaoAuto.addGroupMemberAuto("DevZenTeam", guest1, {from: boss}).should.be.fulfilled; - const voting = await getVoting(daoBase, 0); - - const membersBefore = await daoBase.getGroupMembers("DevZenTeam"); - assert.equal(membersBefore.length, 3); - - await voting.vote(true, {from: teamMember1}).should.be.fulfilled; - - const membersAfter = await daoBase.getGroupMembers("DevZenTeam"); - assert.equal(membersAfter.length, 4); - assert.equal(membersAfter[3], guest1); - }); - - it("should not add a new group member on failed voting", async() => { - await devZenDaoAuto.addGroupMemberAuto("DevZenTeam", guest1, {from: boss}).should.be.fulfilled; - const voting = await getVoting(daoBase, 0); - - const membersBefore = await daoBase.getGroupMembers("DevZenTeam"); - assert.equal(membersBefore.length, 3); - - await voting.vote(false, {from: teamMember1}).should.be.fulfilled; - - const membersAfter = await daoBase.getGroupMembers("DevZenTeam"); - assert.equal(membersAfter.length, 3); - }); - }); - - describe("withdrawEtherAuto", () => { - it("should withdraw ether to specified address", async() => { - await devZenDao.moveToNextEpisode(false, {from:boss}).should.be.fulfilled; - - const initialBalance = web3.eth.getBalance(patron); - const value = web3.toWei(1, "ether"); - await devZenDao.buyTokens({ value: value, from: patron }).should.be.fulfilled; - - const balanceAfterTokensBought = web3.eth.getBalance(patron); - assert.isTrue(initialBalance.toNumber() - balanceAfterTokensBought.toNumber() > value, 'patron should spend 1 ETH on tokens'); - - await devZenDaoAuto.withdrawEtherAuto(patron,{from:teamMember1}).should.be.fulfilled; - voting = await getVoting(daoBase,0); - await checkVoting(voting, 1, 0, false, false); - await voting.vote(true,{from:teamMember2}); - await checkVoting(voting, 2, 0, true, true); - const balanceAfterWithdraw = web3.eth.getBalance(patron); - assert.isTrue(balanceAfterWithdraw.toNumber() > balanceAfterTokensBought.toNumber(), '1 ETH should be withdrawn to patron'); - }); - }); - - describe("selectNextHostAuto", () => { - it("should set next episode's host if it is not yet selected", async() => { - await devZenDaoAuto.selectNextHostAuto(boss, {from:teamMember1}).should.be.fulfilled; - voting = await getVoting(daoBase,0); - await checkVoting(voting, 1, 0, false, false); - await voting.vote(true,{from:teamMember2}); - await checkVoting(voting, 2, 0, true, true); - - const nextEpisode = await devZenDao.nextEpisode(); - const nextShowHostIndex = 0; - assert.equal(nextEpisode[nextShowHostIndex], boss); - }); - - }); - - describe("changeTheGuestAuto", () => { - it("should set the new guest", async() => { - await devZenDao.moveToNextEpisode(false,{from:boss}).should.be.fulfilled; - const value = web3.toWei("0.5", "ether"); - - // guest1 buys 5 DZT - await devZenDao.buyTokens({ value: value, from: guest1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guest1 }); - // guest1 becomes the next show guest - await devZenDao.becomeTheNextShowGuest({ from: guest1 }).should.be.fulfilled; - - const nextShowGuestIndex = 1; - let nextEpisode = await devZenDao.nextEpisode(); - assert.equal(nextEpisode[nextShowGuestIndex], guest1, "guest1 is now guest because he has paid for it"); - - // guest2 buys 5 DZT - await devZenDao.buyTokens({ value: value, from: guest2 }).should.be.fulfilled; - // guest2 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guest2 }); - - // manually change the guest to guest2 - await devZenDaoAuto.changeTheGuestAuto(guest2, {from:teamMember1}).should.be.fulfilled; - voting = await getVoting(daoBase,0); - await checkVoting(voting, 1, 0, false, false); - await voting.vote(true,{from:teamMember2}); - await checkVoting(voting, 2, 0, true, true); - - nextEpisode = await devZenDao.nextEpisode(); - assert.equal(nextEpisode[nextShowGuestIndex], guest2, "guest2 is now guest because he was selected manually"); - }); - - it("should return stake to previous guest", async() => { - await devZenDao.moveToNextEpisode(false, {from:boss}).should.be.fulfilled; - const value = web3.toWei("0.5", "ether"); - - // guest1 buys 5 DZT - await devZenDao.buyTokens({ value: value, from: guest1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guest1 }); - // guest1 becomes the next show guest - await devZenDao.becomeTheNextShowGuest({ from: guest1 }).should.be.fulfilled; - - // guest2 buys 5 DZT - await devZenDao.buyTokens({ value: value, from: guest2 }).should.be.fulfilled; - // guest2 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guest2 }); - - const guest1BalanceBefore = await devZenToken.balanceOf(guest1); - assert.equal(guest1BalanceBefore.toNumber(), 0, "should be 0 because guest1 bought 5 DZT and put them at stake to become a guest") - - // manually change the guest to guest2 - await devZenDaoAuto.changeTheGuestAuto(guest2,{from:teamMember1}).should.be.fulfilled; - voting = await getVoting(daoBase,0); - await checkVoting(voting, 1, 0, false, false); - await voting.vote(true,{from:teamMember2}); - await checkVoting(voting, 2, 0, true, true); - - const guest1BalanceAfter = await devZenToken.balanceOf(guest1); - assert.equal(guest1BalanceAfter.toNumber(), 5e18, "should be 5 because stake is returned to guest1"); - }); - - it("should not return stake to previous guest if it was an emergency guest", async() => { - await devZenDao.moveToNextEpisode(false,{from:boss}).should.be.fulfilled; - const value = web3.toWei("0.5", "ether"); - - // guest1 buys 5 DZT - await devZenDao.buyTokens({ value: value, from: guest1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guest1 }); - // guest1 becomes the next show guest - await devZenDao.becomeTheNextShowGuest({ from: guest1 }).should.be.fulfilled; - - // host sets guest2 an emergency guest - await devZenDaoAuto.emergency_ChangeTheGuestAuto(guest2,{from:teamMember1}).should.be.fulfilled; - voting = await getVoting(daoBase,0); - await checkVoting(voting, 1, 0, false, false); - await voting.vote(true,{from:teamMember2}); - await checkVoting(voting, 2, 0, true, true); - - // guest3 buys 5 DZT - await devZenDao.buyTokens({ value: value, from: guest3 }).should.be.fulfilled; - // guest3 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guest3 }); - - const balanceGuest2Before = await devZenToken.balanceOf(guest2); - assert.equal(balanceGuest2Before.toNumber(), 0, "should be 0 because it is an emergency guest"); - - // host sets "legal" guest - await devZenDaoAuto.changeTheGuestAuto(guest3,{from:teamMember1}).should.be.fulfilled; - voting = await getVoting(daoBase,1); - await checkVoting(voting, 1, 0, false, false); - await voting.vote(true,{from:teamMember2}); - await checkVoting(voting, 2, 0, true, true); - - const balanceGuest2After = await devZenToken.balanceOf(guest2); - assert.equal(balanceGuest2After.toNumber(), 0, "should be 0 because emergency guest put nothing at stake"); - }); - }); - - describe("moveToNextEpisodeAuto", () => { - - it("should mint DZTREP to guest if he came", async() => { - await devZenDaoAuto.moveToNextEpisodeAuto(false,{from:teamMember1}).should.be.fulfilled; - voting = await getVoting(daoBase,0); - await checkVoting(voting, 1, 0, false, false); - await voting.vote(true,{from:teamMember2}); - await checkVoting(voting, 2, 0, true, true); - - // guest1 buys 5 DZT - const value = web3.toWei("0.5", "ether"); - await devZenDao.buyTokens({ value: value, from: guest1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guest1 }); - // guest1 becomes the next show guest - await devZenDao.becomeTheNextShowGuest({ from: guest1 }).should.be.fulfilled; - - const repBalanceBefore = await repToken.balanceOf(guest1); - assert.equal(repBalanceBefore.toNumber(), 0); - - // 7 days passed and guest came - await increaseTime(60 * 60 * 24 * 7); - await devZenDao.moveToNextEpisode(true,{from:boss}).should.be.fulfilled; - - const repTokensRewardGuest = await devZenDao.params(web3.sha3("RepTokensReward_Guest")); - const repTokensRewardGuestIndex = 6; - - const repBalanceAfter = await repToken.balanceOf(guest1); - assert.equal(repBalanceAfter.toNumber(), repTokensRewardGuest.toNumber()); - }); - - it("should transfer guest's stake back if initial guest has come", async() => { - await devZenDaoAuto.moveToNextEpisodeAuto(false,{from:teamMember1}).should.be.fulfilled; - voting = await getVoting(daoBase,0); - await checkVoting(voting, 1, 0, false, false); - await voting.vote(true,{from:teamMember2}); - await checkVoting(voting, 2, 0, true, true); - - // guest1 buys 5 DZT - const value = web3.toWei("0.5", "ether"); - await devZenDao.buyTokens({ value: value, from: guest1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guest1 }); - // guest1 becomes the next show guest - await devZenDao.becomeTheNextShowGuest({ from: guest1 }).should.be.fulfilled; - - const dztBalanceBefore = await devZenToken.balanceOf(guest1); - assert.equal(dztBalanceBefore.toNumber(), 0, "guest's 5 DZT were transfered to contract"); - - // 7 days passed and guest came - await increaseTime(60 * 60 * 24 * 7); - await devZenDao.moveToNextEpisode(true,{from:boss}).should.be.fulfilled; - - const dztBalanceAfter = await devZenToken.balanceOf(guest1); - assert.equal(dztBalanceAfter.toNumber(), 5e18, "guest's 5 DZT were tansfered back to guest"); - }); - }); - - describe("removeGroupMemberAuto", () => { - it("should remove group member on successful voting", async() => { - await devZenDaoAuto.removeGroupMemberAuto("DevZenTeam", teamMember2, {from: boss}).should.be.fulfilled; - const voting = await getVoting(daoBase, 0); - - const membersBefore = await daoBase.getGroupMembers("DevZenTeam"); - assert.equal(membersBefore.length, 3); - - await voting.vote(true, {from: teamMember1}).should.be.fulfilled; - - const membersAfter = await daoBase.getGroupMembers("DevZenTeam"); - assert.equal(membersAfter.length, 2); - }); - - it("should not remove group member on failed voting", async() => { - await devZenDaoAuto.removeGroupMemberAuto("DevZenTeam", teamMember2, {from: boss}).should.be.fulfilled; - const voting = await getVoting(daoBase, 0); - - const membersBefore = await daoBase.getGroupMembers("DevZenTeam"); - assert.equal(membersBefore.length, 3); - - await voting.vote(false, {from: teamMember1}).should.be.fulfilled; - - const membersAfter = await daoBase.getGroupMembers("DevZenTeam"); - assert.equal(membersAfter.length, 3); - }); - }); - - describe("updateDaoParamsAuto", () => { - it("should update param", async() => { - let paramHash = await devZenDao.MINT_TOKENS_PER_WEEK_AMOUNT(); - let paramValueBefore = await devZenDao.params(paramHash); - await devZenDaoAuto.updateDaoParamsAuto(paramHash, paramValueBefore.toNumber()*2, {from:teamMember1}).should.be.fulfilled; - voting = await getVoting(daoBase,0); - await checkVoting(voting, 1, 0, false, false); - await voting.vote(true,{from:teamMember2}); - await checkVoting(voting, 2, 0, true, true); - - let paramValueAfter = await devZenDao.params(paramHash); - assert.equal(paramValueBefore.toNumber()*2, paramValueAfter.toNumber()); - }); - }); -}); \ No newline at end of file diff --git a/test/DevZenDao.testable.functional.tests.js b/test/DevZenDao.testable.functional.tests.js deleted file mode 100644 index cdc3c0c..0000000 --- a/test/DevZenDao.testable.functional.tests.js +++ /dev/null @@ -1,471 +0,0 @@ -const { increaseTime } = require("./utils/helpers"); - -const DevZenDaoFactory = artifacts.require("DevZenDaoFactory"); -const DevZenDaoFactoryTestable = artifacts.require("DevZenDaoFactoryTestable"); -const DevZenDaoTestable = artifacts.require("DevZenDaoTestable"); - -const DevZenDao = artifacts.require("DevZenDao"); -const StdDaoToken = artifacts.require("StdDaoToken"); - -contract("DevZenDaoCore", (accounts) => { - const patronAddr1 = accounts[0]; - const patronAddr2 = accounts[1]; - const hostAddr1 = accounts[2]; - const hostAddr2 = accounts[3]; - const guestAddr1 = accounts[4]; - const guestAddr2 = accounts[5]; - const guestAddr3 = accounts[6]; - const teamMemberAddr1 = accounts[7]; - const teamMemberAddr2 = accounts[8]; - - let devZenDaoFactory; - let devZenDao; - let devZenToken; - let repToken; - - beforeEach(async () => { - devZenDaoFactory = await DevZenDaoFactoryTestable.new(hostAddr1, [teamMemberAddr1, teamMemberAddr2]); - - const devZenDaoAddr = await devZenDaoFactory.devZenDao(); - devZenDao = DevZenDaoTestable.at(devZenDaoAddr); - - const devZenTokenAddr = await devZenDao.devZenToken(); - devZenToken = StdDaoToken.at(devZenTokenAddr); - - const repTokenAddr = await devZenDao.repToken(); - repToken = StdDaoToken.at(repTokenAddr); - }); - - describe("withdrawEther", () => { - it("should withdraw ether to specified address", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - - const initialBalance = web3.eth.getBalance(patronAddr1); - const value = web3.toWei(1, "ether"); - await devZenDao.buyTokens({ value: value, from: patronAddr1 }).should.be.fulfilled; - - const balanceAfterTokensBought = web3.eth.getBalance(patronAddr1); - assert.isTrue(initialBalance.toNumber() - balanceAfterTokensBought.toNumber() > value, 'patron should spend 1 ETH on tokens'); - - await devZenDao.withdrawEther(patronAddr1).should.be.fulfilled; - - const balanceAfterWithdraw = web3.eth.getBalance(patronAddr1); - assert.isTrue(balanceAfterWithdraw.toNumber() > balanceAfterTokensBought.toNumber(), '1 ETH should be withdrawn to patron'); - }); - }); - - describe("selectNextHost", () => { - it("should set next episode's host if it is not yet selected", async() => { - await devZenDao.selectNextHost(hostAddr1).should.be.fulfilled; - const nextEpisode = await devZenDao.nextEpisode(); - const nextShowHostIndex = 0; - assert.equal(nextEpisode[nextShowHostIndex], hostAddr1); - }); - - it("should should throw if next episode's host is already selected", async() => { - await devZenDao.selectNextHost(hostAddr1).should.be.fulfilled; - await devZenDao.selectNextHost(hostAddr2).should.be.rejectedWith("revert"); - }); - }); - - describe("burnGuestStake", () => { - it("should burn guest's stake", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - - const balanceBeforeBurn = await devZenToken.balanceOf(devZenDao.address); - assert.equal(balanceBeforeBurn.toNumber(), 10e18, "on new episode 10 DZT are minted to contract"); - - await devZenDao.burnGuestStake().should.be.fulfilled; - - const balanceAfterBurn = await devZenToken.balanceOf(devZenDao.address); - assert.equal(balanceAfterBurn.toNumber(), 5e18, "burns 5 DZT at guest's stake"); - }); - }); - - describe("changeTheGuest", () => { - it("should throw if next guest is not selected", async() => { - await devZenDao.changeTheGuest(guestAddr1).should.be.rejectedWith("revert"); - }); - - it("should set the new guest", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - const value = web3.toWei("0.5", "ether"); - - // guest1 buys 5 DZT - await devZenDao.buyTokens({ value: value, from: guestAddr1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr1 }); - // guest1 becomes the next show guest - await devZenDao.becomeTheNextShowGuest({ from: guestAddr1 }).should.be.fulfilled; - - const nextShowGuestIndex = 1; - let nextEpisode = await devZenDao.nextEpisode(); - assert.equal(nextEpisode[nextShowGuestIndex], guestAddr1, "guest1 is now guest because he has paid for it"); - - // guest2 buys 5 DZT - await devZenDao.buyTokens({ value: value, from: guestAddr2 }).should.be.fulfilled; - // guest2 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr2 }); - - // manually change the guest to guest2 - await devZenDao.changeTheGuest(guestAddr2).should.be.fulfilled; - - nextEpisode = await devZenDao.nextEpisode(); - assert.equal(nextEpisode[nextShowGuestIndex], guestAddr2, "guest2 is now guest because he was selected manually"); - }); - - it("should return stake to previous guest", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - const value = web3.toWei("0.5", "ether"); - - // guest1 buys 5 DZT - await devZenDao.buyTokens({ value: value, from: guestAddr1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr1 }); - // guest1 becomes the next show guest - await devZenDao.becomeTheNextShowGuest({ from: guestAddr1 }).should.be.fulfilled; - - // guest2 buys 5 DZT - await devZenDao.buyTokens({ value: value, from: guestAddr2 }).should.be.fulfilled; - // guest2 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr2 }); - - const guest1BalanceBefore = await devZenToken.balanceOf(guestAddr1); - assert.equal(guest1BalanceBefore.toNumber(), 0, "should be 0 because guest1 bought 5 DZT and put them at stake to become a guest") - - // manually change the guest to guest2 - await devZenDao.changeTheGuest(guestAddr2).should.be.fulfilled; - - const guest1BalanceAfter = await devZenToken.balanceOf(guestAddr1); - assert.equal(guest1BalanceAfter.toNumber(), 5e18, "should be 5 because stake is returned to guest1"); - }); - - it("should not return stake to previous guest if it was an emergency guest", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - const value = web3.toWei("0.5", "ether"); - - // guest1 buys 5 DZT - await devZenDao.buyTokens({ value: value, from: guestAddr1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr1 }); - // guest1 becomes the next show guest - await devZenDao.becomeTheNextShowGuest({ from: guestAddr1 }).should.be.fulfilled; - - // host sets guest2 an emergency guest - await devZenDao.emergency_ChangeTheGuest(guestAddr2).should.be.fulfilled; - - // guest3 buys 5 DZT - await devZenDao.buyTokens({ value: value, from: guestAddr3 }).should.be.fulfilled; - // guest3 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr3 }); - - const balanceGuest2Before = await devZenToken.balanceOf(guestAddr2); - assert.equal(balanceGuest2Before.toNumber(), 0, "should be 0 because it is an emergency guest"); - - // host sets "legal" guest - await devZenDao.changeTheGuest(guestAddr3).should.be.fulfilled; - - const balanceGuest2After = await devZenToken.balanceOf(guestAddr2); - assert.equal(balanceGuest2After.toNumber(), 0, "should be 0 because emergency guest put nothing at stake"); - }); - }); - - describe("emergency_ChangeTheGuest", () => { - it("should throw if next show guest is not set", async() => { - await devZenDao.emergency_ChangeTheGuest(guestAddr1).should.be.rejectedWith("revert"); - }); - - it("should change next episode's guest and mark guest as updated", async() => { - const guestHasCome = false; - await devZenDao.moveToNextEpisode(guestHasCome).should.be.fulfilled; - // guest1 buys 5 DZT - const value = web3.toWei("0.5", "ether"); - await devZenDao.buyTokens({ value: value, from: guestAddr1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr1 }); - // guest1 becomes the next show guest - await devZenDao.becomeTheNextShowGuest({ from: guestAddr1 }).should.be.fulfilled; - - await devZenDao.emergency_ChangeTheGuest(guestAddr2).should.be.fulfilled; - const nextEpisode = await devZenDao.nextEpisode(); - const nextShowGuestIndex = 1; - const isGuestUpdatedIndex = 6; - assert.equal(nextEpisode[nextShowGuestIndex], guestAddr2); - assert.isTrue(nextEpisode[isGuestUpdatedIndex]); - }); - }); - - describe("moveToNextEpisode", () => { - it("should mint DZT and DZTREP to contract", async() => { - const dztBefore = await devZenToken.balanceOf(devZenDao.address); - const dztRepBebore = await repToken.balanceOf(devZenDao.address); - assert.equal(dztBefore, 0); - assert.equal(dztRepBebore, 0); - - const guestHasCome = false; - await devZenDao.moveToNextEpisode(guestHasCome).should.be.fulfilled; - - const mintTokensPerWeekAmountIndexParam = await devZenDao.params(web3.sha3("MintTokensPerWeekAmount")); - const mintReputationTokensPerWeekAmountParam = await devZenDao.params(web3.sha3("MintReputationTokensPerWeekAmount")); - const mintTokensPerWeekAmountIndex = 0; - const mintReputationTokensPerWeekAmount = 1; - - const dztAfter = await devZenToken.balanceOf(devZenDao.address); - const dztRepAfter = await repToken.balanceOf(devZenDao.address); - assert.equal(dztAfter, mintTokensPerWeekAmountIndexParam.toNumber()); - assert.equal(dztRepAfter, mintReputationTokensPerWeekAmountParam.toNumber()); - }); - - it("should mint DZTREP to guest if he came", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - - // guest1 buys 5 DZT - const value = web3.toWei("0.5", "ether"); - await devZenDao.buyTokens({ value: value, from: guestAddr1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr1 }); - // guest1 becomes the next show guest - await devZenDao.becomeTheNextShowGuest({ from: guestAddr1 }).should.be.fulfilled; - - const repBalanceBefore = await repToken.balanceOf(guestAddr1); - assert.equal(repBalanceBefore.toNumber(), 0); - - // 7 days passed and guest came - await increaseTime(60 * 60 * 24 * 7); - await devZenDao.moveToNextEpisode(true).should.be.fulfilled; - - const repTokensRewardGuestIndexParam = await devZenDao.params(web3.sha3("RepTokensReward_Guest")); - const repTokensRewardGuestIndex = 6; - - const repBalanceAfter = await repToken.balanceOf(guestAddr1); - assert.equal(repBalanceAfter.toNumber(), repTokensRewardGuestIndexParam.toNumber()); - }); - - it("should mint DZTREP to host", async() => { - await devZenDao.selectNextHost(hostAddr1).should.be.fulfilled; - - const repBalanceBefore = await repToken.balanceOf(hostAddr1); - assert.equal(repBalanceBefore.toNumber(), 0); - - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - - const repTokensRewardHostIndexParam = await devZenDao.params(web3.sha3("RepTokensReward_Host")); - const repTokensRewardHostIndex = 5; - - const repBalanceAfter = await repToken.balanceOf(hostAddr1); - assert.equal(repBalanceAfter.toNumber(), repTokensRewardHostIndexParam.toNumber()); - }); - - it("should transfer guest's stake back if initial guest has come", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - - // guest1 buys 5 DZT - const value = web3.toWei("0.5", "ether"); - await devZenDao.buyTokens({ value: value, from: guestAddr1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr1 }); - // guest1 becomes the next show guest - await devZenDao.becomeTheNextShowGuest({ from: guestAddr1 }).should.be.fulfilled; - - const dztBalanceBefore = await devZenToken.balanceOf(guestAddr1); - assert.equal(dztBalanceBefore.toNumber(), 0, "guest's 5 DZT were transfered to contract"); - - // 7 days passed and guest came - await increaseTime(60 * 60 * 24 * 7); - await devZenDao.moveToNextEpisode(true).should.be.fulfilled; - - const dztBalanceAfter = await devZenToken.balanceOf(guestAddr1); - assert.equal(dztBalanceAfter.toNumber(), 5e18, "guest's 5 DZT were tansfered back to guest"); - }); - - it("should burn guest's stake if there was an emergency guest", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - - // guest1 buys 5 DZT - const value = web3.toWei("0.5", "ether"); - await devZenDao.buyTokens({ value: value, from: guestAddr1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr1 }); - // guest1 becomes the next show guest - await devZenDao.becomeTheNextShowGuest({ from: guestAddr1 }).should.be.fulfilled; - - // emergency, guest2 becomes the guest - await devZenDao.emergency_ChangeTheGuest(guestAddr2).should.be.fulfilled; - - const contractBalanceBefore = await devZenToken.balanceOf(devZenDao.address); - - // 7 days passed and emergency guest came - await increaseTime(60 * 60 * 24 * 7); - await devZenDao.moveToNextEpisode(true).should.be.fulfilled; - - const becomeGuestStakeIndexParam = await devZenDao.params(web3.sha3("BecomeGuestStake")); - const becomeGuestStakeIndex = 4; - - const contractBalanceAfter = await devZenToken.balanceOf(devZenDao.address); - assert.equal(contractBalanceAfter.toNumber() - contractBalanceBefore.toNumber(), becomeGuestStakeIndexParam.toNumber(), "5 DZT should be burnt"); - }); - }); - - describe("runAdsInTheNextEpisode", () => { - it("should throw if all 5 slots are not available", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - // buy 10 DZT - const value = web3.toWei(1, "ether"); - await devZenDao.buyTokens({ value: value, from: patronAddr1 }).should.be.fulfilled; - // post 5 ads - for(let i = 0; i < 5; i++) { - await devZenDao.runAdsInTheNextEpisode("ANY_TEXT", {from: patronAddr1}).should.be.fulfilled; - } - await devZenDao.runAdsInTheNextEpisode("ANY_TEXT", {from: patronAddr1}).should.be.rejectedWith("revert"); - }); - - it("should throw if sender does not have enough DZT", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - await devZenDao.runAdsInTheNextEpisode("ANY_TEXT", {from: patronAddr1}).should.be.rejectedWith("revert"); - }); - - it("should burn sender's tokens if sender buys an ad", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - // buy 10 DZT - const value = web3.toWei(1, "ether"); - await devZenDao.buyTokens({ value: value, from: patronAddr1 }).should.be.fulfilled; - - await devZenDao.runAdsInTheNextEpisode("ANY_TEXT", {from: patronAddr1}).should.be.fulfilled; - - const balanceAfterPurchase = await devZenToken.balanceOf(patronAddr1); - assert.equal(balanceAfterPurchase.toNumber(), 8e18, "sender's balance should move from 10 to 8 DZT"); - }); - - it("should add ad to the slot if sender buys an ad", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - // buy 10 DZT - const value = web3.toWei(1, "ether"); - await devZenDao.buyTokens({ value: value, from: patronAddr1 }).should.be.fulfilled; - - await devZenDao.runAdsInTheNextEpisode("ANY_TEXT", {from: patronAddr1}).should.be.fulfilled; - - const nextEpisode = await devZenDao.nextEpisode(); - const usedSlotsIndex = 4; - assert.equal(nextEpisode[usedSlotsIndex].toNumber(), 1, "used slots number should be increased by 1"); - }); - }); - - describe("becomeTheNextShowGuest", () => { - it("should throw if next guest is already selected", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - // guest1 buys 5 DZT, allows to spend them and becomes the next guest - const value = web3.toWei("0.5", "ether"); - await devZenDao.buyTokens({ value: value, from: guestAddr1 }).should.be.fulfilled; - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr1 }); - await devZenDao.becomeTheNextShowGuest({ from: guestAddr1 }).should.be.fulfilled; - // guest2 buys 5 DZT, allows to spend them and wants to become the next guest - await devZenDao.buyTokens({ value: value, from: guestAddr2 }).should.be.fulfilled; - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr2 }); - await devZenDao.becomeTheNextShowGuest({ from: guestAddr2 }).should.be.rejectedWith("revert"); - }); - }); - - describe("buyTokens", () => { - it("should throw if msg.value = 0", async() => { - await devZenDao.buyTokens().should.be.rejectedWith("revert"); - }); - - it("should throw if there is an insufficient DZT amount in contract", async() => { - const value = web3.toWei(1, "ether"); - await devZenDao.buyTokens({ value: value }).should.be.rejectedWith("revert"); - }); - - it("should transfer tokens to sender if there is a sufficient DZT amount", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - - let balancePatron1 = await devZenToken.balanceOf(patronAddr1); - assert.equal(balancePatron1.toNumber(), 0, "should be zero because patron has not purchased tokens yet"); - - const value = web3.toWei(1, "ether"); - await devZenDao.buyTokens({ value: value, from: patronAddr1 }).should.be.fulfilled; - - balancePatron1 = await devZenToken.balanceOf(patronAddr1); - assert.equal(balancePatron1.toNumber(), 10e18, "should be 10 because 1 token costs 0.1 ETH"); - }); - }); - - describe("isOneWeekPassed", () => { - it("should return true if this is the 1st episode", async() => { - const isOneWeekPassed = await devZenDao.isOneWeekPassed(); - assert.isTrue(isOneWeekPassed, "should be true because this is the 1st episode"); - }); - - it("should return true if 7 days have passed", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - await increaseTime(60 * 60 * 24 * 7); - const isOneWeekPassed = await devZenDao.isOneWeekPassed(); - assert.isTrue(isOneWeekPassed, "should be true because 1 week has passed"); - }); - - it("should return false if 7 days have not passed", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - const isOneWeekPassed = await devZenDao.isOneWeekPassed(); - assert.isFalse(isOneWeekPassed, "should be false because 1 week has not passed"); - }); - }); - - describe("setGuest", () => { - it("should throw if sender does not have enough DZT", async() => { - await devZenDao.becomeTheNextShowGuest({ from: guestAddr1 }).should.be.rejectedWith("revert"); - }); - - it("should throw if sender has not allowed dao to put enough DZT at stake", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - // guest1 buys 5 DZT - const value = web3.toWei("0.5", "ether"); - await devZenDao.buyTokens({ value: value, from: guestAddr1 }).should.be.fulfilled; - await devZenDao.becomeTheNextShowGuest({ from: guestAddr1 }).should.be.rejectedWith("revert"); - }); - - it("should lock tokens", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - // guest1 buys 5 DZT - const value = web3.toWei("0.5", "ether"); - await devZenDao.buyTokens({ value: value, from: guestAddr1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr1 }); - - let guestBalance = await devZenToken.balanceOf(guestAddr1); - let contractBalance = await devZenToken.balanceOf(devZenDao.address); - assert.equal(guestBalance, 5e18, "guest balance should be equal 5 DZT"); - assert.equal(contractBalance, 5e18, "contract balance should be equal to 5 DZT, 10 initial DZT - 5 bought by the guest"); - - await devZenDao.becomeTheNextShowGuest({ from: guestAddr1 }).should.be.fulfilled; - - guestBalance = await devZenToken.balanceOf(guestAddr1); - contractBalance = await devZenToken.balanceOf(devZenDao.address); - assert.equal(guestBalance, 0, "guest balance should be 0 because he has put his 5 DZT at stake"); - assert.equal(contractBalance, 10e18, "contract balance should be equal to 10 DZT, 10 initial DZT - 5 bought by the guest + 5 put at stake by the guest"); - }); - - it("should set next show guest", async() => { - await devZenDao.moveToNextEpisode(false).should.be.fulfilled; - // guest1 buys 5 DZT - const value = web3.toWei("0.5", "ether"); - await devZenDao.buyTokens({ value: value, from: guestAddr1 }).should.be.fulfilled; - // guest1 allows to spend his 5 DZT - await devZenToken.approve(devZenDao.address, 5e18, { from: guestAddr1 }); - - await devZenDao.becomeTheNextShowGuest({ from: guestAddr1 }).should.be.fulfilled; - - const nextEpisode = await devZenDao.nextEpisode(); - const nextShowGuestIndex = 1; - assert.equal(nextEpisode[nextShowGuestIndex], guestAddr1, "guest1 should be the next show guest"); - }); - }); - - describe("setParam", () => { - it("should set param", async() => { - let paramHash = await devZenDao.MINT_TOKENS_PER_WEEK_AMOUNT(); - let paramValueBefore = await devZenDao.params(paramHash); - await devZenDao.setParam(paramHash, 2*paramValueBefore.toNumber()).should.be.fulfilled; - let paramValueAfter = await devZenDao.params(paramHash); - assert.equal(paramValueBefore.toNumber()*2, paramValueAfter.toNumber()); - }); - }); -}); \ No newline at end of file diff --git a/test/HierarchyDao.functional.tests.js b/test/HierarchyDao.functional.tests.js deleted file mode 100644 index 3560522..0000000 --- a/test/HierarchyDao.functional.tests.js +++ /dev/null @@ -1,84 +0,0 @@ -const CheckExceptions = require("./utils/checkexceptions"); -const should = require("./utils/helpers"); - -const DaoBaseAuto = artifacts.require("DaoBaseAuto"); -const DaoStorage = artifacts.require("DaoStorage"); -const DaoBaseWithUnpackers = artifacts.require("DaoBaseWithUnpackers"); - -const GenericProposal = artifacts.require("GenericProposal"); -const HierarchyDao = artifacts.require("HierarchyDao"); -const HierarchyDaoFactory = artifacts.require("HierarchyDaoFactory"); -const InformalProposal = artifacts.require("InformalProposal"); -const StdDaoToken = artifacts.require("StdDaoToken"); - -contract('HierarchyDaoFactory', (accounts) => { - const boss = accounts[0]; - const manager1 = accounts[1]; - const manager2 = accounts[2]; - const employee1 = accounts[3]; - const employee2 = accounts[4]; - const outsiderWithTokens = accounts[5]; - const outsiderWithoutTokens = accounts[6]; - - let hierarchyDaoFactory; - let daoBase; - let store; - let hierarchyDaoAuto; - let informalProposal; - let stdDaoToken; - - before(async () => { - hierarchyDaoFactory = await HierarchyDaoFactory.new(boss, [manager1, manager2], [employee1, employee2], [outsiderWithTokens, outsiderWithoutTokens]); - daoBase = DaoBaseWithUnpackers.at(await hierarchyDaoFactory.daoBase()); - store = DaoStorage.at(await hierarchyDaoFactory.store()); - hierarchyDaoAuto = DaoBaseAuto.at(await hierarchyDaoFactory.hierarchyDaoAuto()); - stdDaoToken = StdDaoToken.at(await hierarchyDaoFactory.token()); - informalProposal = await InformalProposal.new("ANY_TEXT"); - }); - - it("boss should be a member of 2 groups: managers and employees", async () => { - const isManager = await daoBase.isGroupMember("Managers", boss); - const isEmployee = await daoBase.isGroupMember("Employees", boss); - - assert.isTrue(isManager, "boss should be in the managers group"); - assert.isTrue(isEmployee, "boss should be in the employees group"); - }); - - it("boss should be able to issue new tokens", async() => { - await daoBase.issueTokens(stdDaoToken.address, employee1, 100, { from: boss }).should.be.fulfilled; - const employee1Balance = await stdDaoToken.balanceOf(employee1); - assert.equal(employee1Balance, 100); - }); - - it("manager should be able to add new proposal", async () => { - await daoBase.addNewProposal(informalProposal.address, { from: manager1 }).should.be.fulfilled; - }); - - it("manager should not be able to issue tokens", async() => { - await CheckExceptions.checkContractThrows( - daoBase.issueTokens, [stdDaoToken.address, employee1, 100, { from: manager1 }] - ); - }); - - it("boss should be able to manage groups only by voting", async () => { - await hierarchyDaoAuto.addGroupMemberAuto("ANY_GROUP", employee1, { from: boss }).should.be.fulfilled; - }); - - it("manager should be able to manage groups only by voting", async () => { - await hierarchyDaoAuto.addGroupMemberAuto("ANY_OTHER_GROUP", employee1, { from: manager1 }).should.be.fulfilled; - }); - - it("outsider (not in groups) with tokens should not be able to add new proposal", async () => { - await daoBase.issueTokens(stdDaoToken.address, outsiderWithTokens, 100, { from: boss }).should.be.fulfilled; - await CheckExceptions.checkContractThrows( - daoBase.addNewProposal, [informalProposal.address, { from: outsiderWithTokens }] - ); - }); - - it("outsider (not in groups) without tokens should not be able to add new proposal", async () => { - await CheckExceptions.checkContractThrows( - daoBase.addNewProposal, [informalProposal.address, { from: outsiderWithoutTokens }] - ); - }); - -}); diff --git a/test/utils/helpers.js b/test/utils/helpers.js index 461b37a..64899ee 100644 --- a/test/utils/helpers.js +++ b/test/utils/helpers.js @@ -7,30 +7,22 @@ const utf8 = require('utf8'); /** * Increases latest block time by duration in seconds */ -const increaseTime = function increaseTime (duration) { - - const id = Date.now(); - - return new Promise((resolve, reject) => { - web3.currentProvider.sendAsync({ - jsonrpc: '2.0', - method: 'evm_increaseTime', - params: [duration], - id: id, - }, err1 => { - if (err1) return reject(err1); - - web3.currentProvider.sendAsync({ - jsonrpc: '2.0', - method: 'evm_mine', - id: id + 1, - }, (err2, res) => { - return err2 ? reject(err2) : resolve(res); - }); - }); - }); +async function increaseTime (duration) { + var id = Date.now(); + await web3.currentProvider.sendAsync({ + jsonrpc: '2.0', + method: 'evm_increaseTime', + params: [duration], + id: id + }, function (err) { if (err) console.log('err:', err); }); + await web3.currentProvider.sendAsync({ + jsonrpc: '2.0', + method: 'evm_mine', + id: id + 1 + }, function (err) { if (err) console.log('err:', err); }); } + function uintToBytes32(n) { n = Number(n).toString(16); while (n.length < 64) { diff --git a/truffle.js b/truffle.js index 658c81e..f998f0c 100644 --- a/truffle.js +++ b/truffle.js @@ -9,7 +9,7 @@ module.exports = { networks: { development: { host: "localhost", - port: 8555, + port: 8545, network_id: "*", gas: 100000000 },