From 28f784b04867078e1eed61987d59415ac7f423a2 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Mon, 12 Nov 2018 23:46:54 +0200 Subject: [PATCH 01/93] added VestingEscrowWallet --- contracts/wallet/VestingEscrowWallet.sol | 109 +++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 contracts/wallet/VestingEscrowWallet.sol diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol new file mode 100644 index 000000000..4f178f289 --- /dev/null +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -0,0 +1,109 @@ +pragma solidity ^0.4.24; + +import "../../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol"; +import "../../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol"; +import "../interfaces/IERC20.sol"; + +/** + * @title Wallet for core vesting escrow functionality + */ +contract VestingEscrowWallet is Ownable { + using SafeMath for uint256; + + struct VestingSchedule { + uint256 numberOfTokens; + uint256 vestingDuration; + uint256 vestingFrequency; + uint256 startDate; + } + + struct VestingData { + VestingSchedule[] schedules; + uint256 index; + } + + IERC20 public token; + address public treasury; + + uint256 public unassignedTokens; + + mapping (address => VestingData) internal schedules; + address[] users; + + event AddVestingSchedule( + address _user, + uint256 _numberOfTokens, + uint256 _vestingDuration, + uint256 _vestingFrequency, + uint256 _startDate, + uint256 _timestamp + ); + event RevokeVestingSchedules(address _user, uint256 _timestamp); + event RevokeVestingSchedule(address _user, uint256 index, uint256 _timestamp); + + constructor(address _tokenAddress, address _treasury) { + token = IERC20(_tokenAddress); + treasury = _treasury; + } + + function addVestingSchedule( + address _user, + uint256 _numberOfTokens, + uint256 _vestingDuration, + uint256 _vestingFrequency, + uint256 _startDate + ) + public + onlyOwner + { + //TODO validation + VestingSchedule schedule; + schedule.numberOfTokens = _numberOfTokens; + schedule.vestingDuration = _vestingDuration; + schedule.vestingFrequency = _vestingFrequency; + schedule.startDate = _startDate; + //add user to the schedule list only if adding first schedule + if (schedules[_user].schedules.length == 0) { + schedules[_user].index = users.length; + users.push(_user); + } + schedules[_user].schedules.push(schedule); + /*solium-disable-next-line security/no-block-members*/ + emit AddVestingSchedule(_user, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate, now); + } + + function revokeVestingSchedule(address _user, uint256 index) public onlyOwner { + //TODO validation + + /*solium-disable-next-line security/no-block-members*/ + emit RevokeVestingSchedule(_user, index, now); + } + + function revokeVestingSchedules(address _user) public onlyOwner { + //TODO validation + uint256 index = schedules[_user].index; + users[index] = users[users.length - 1]; + users.length--; + if (index != users.length) { + schedules[users[index]].index = index; + } + delete schedules[_user]; + /*solium-disable-next-line security/no-block-members*/ + emit RevokeVestingSchedules(_user, now); + } + + function editVestingSchedule( + address _user, + uint256 index, + uint256 _numberOfTokens, + uint256 _vestingDuration, + uint256 _vestingFrequency, + uint256 _startDate + ) + public + onlyOwner + { + + } + +} From de2f1ebe0d20f1e4a82aa70fa395ba3fb8362a1c Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Tue, 13 Nov 2018 18:03:21 +0200 Subject: [PATCH 02/93] added z_vesting_escrow_wallet.js --- contracts/wallet/VestingEscrowWallet.sol | 16 ++--- test/helpers/createInstances.js | 14 ++++- test/z_vesting_escrow_wallet.js | 78 ++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 test/z_vesting_escrow_wallet.js diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index 4f178f289..0c7897702 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -27,8 +27,8 @@ contract VestingEscrowWallet is Ownable { uint256 public unassignedTokens; - mapping (address => VestingData) internal schedules; - address[] users; + mapping (address => VestingData) public schedules; + address[] public users; event AddVestingSchedule( address _user, @@ -41,7 +41,7 @@ contract VestingEscrowWallet is Ownable { event RevokeVestingSchedules(address _user, uint256 _timestamp); event RevokeVestingSchedule(address _user, uint256 index, uint256 _timestamp); - constructor(address _tokenAddress, address _treasury) { + constructor(address _tokenAddress, address _treasury) public { token = IERC20(_tokenAddress); treasury = _treasury; } @@ -53,11 +53,11 @@ contract VestingEscrowWallet is Ownable { uint256 _vestingFrequency, uint256 _startDate ) - public + external onlyOwner { //TODO validation - VestingSchedule schedule; + VestingSchedule memory schedule; schedule.numberOfTokens = _numberOfTokens; schedule.vestingDuration = _vestingDuration; schedule.vestingFrequency = _vestingFrequency; @@ -72,14 +72,14 @@ contract VestingEscrowWallet is Ownable { emit AddVestingSchedule(_user, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate, now); } - function revokeVestingSchedule(address _user, uint256 index) public onlyOwner { + function revokeVestingSchedule(address _user, uint256 index) external onlyOwner { //TODO validation /*solium-disable-next-line security/no-block-members*/ emit RevokeVestingSchedule(_user, index, now); } - function revokeVestingSchedules(address _user) public onlyOwner { + function revokeVestingSchedules(address _user) external onlyOwner { //TODO validation uint256 index = schedules[_user].index; users[index] = users[users.length - 1]; @@ -100,7 +100,7 @@ contract VestingEscrowWallet is Ownable { uint256 _vestingFrequency, uint256 _startDate ) - public + external onlyOwner { diff --git a/test/helpers/createInstances.js b/test/helpers/createInstances.js index 2021d350e..319c61f51 100644 --- a/test/helpers/createInstances.js +++ b/test/helpers/createInstances.js @@ -30,6 +30,7 @@ const PolyTokenFaucet = artifacts.require("./PolyTokenFaucet.sol"); const DummySTOFactory = artifacts.require("./DummySTOFactory.sol"); const MockBurnFactory = artifacts.require("./MockBurnFactory.sol"); const MockWrongTypeFactory = artifacts.require("./MockWrongTypeFactory.sol"); +const VestingEscrowWallet = artifacts.require("./VestingEscrowWallet.sol"); const Web3 = require("web3"); const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); // Hardcoded development port @@ -65,6 +66,7 @@ let I_PolymathRegistry; let I_SecurityTokenRegistryProxy; let I_STRProxied; let I_MRProxied; +let I_VestingEscrowWallet; // Initial fee for ticker registry and security token registry const initRegFee = web3.utils.toWei("250"); @@ -97,7 +99,7 @@ export async function setUpPolymathNetwork(account_polymath, token_owner) { } -async function deployPolyRegistryAndPolyToken(account_polymath, token_owner) { +export async function deployPolyRegistryAndPolyToken(account_polymath, token_owner) { // Step 0: Deploy the PolymathRegistry I_PolymathRegistry = await PolymathRegistry.new({ from: account_polymath }); @@ -422,6 +424,16 @@ export async function deployMockWrongTypeRedemptionAndVerifyed(accountPolymath, return new Array(I_MockWrongTypeBurnFactory); } +export async function deployVestingEscrowWallet(accountPolymath, polyToken, treasury) { + I_VestingEscrowWallet = await VestingEscrowWallet.new(polyToken, treasury, { from: accountPolymath }); + assert.notEqual( + I_VestingEscrowWallet.address.valueOf(), + "0x0000000000000000000000000000000000000000", + "VestingEscrowWallet contract was not deployed" + ); + + return new Array(I_VestingEscrowWallet); +} /// Helper function diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js new file mode 100644 index 000000000..565be8ce9 --- /dev/null +++ b/test/z_vesting_escrow_wallet.js @@ -0,0 +1,78 @@ +import {deployPolyRegistryAndPolyToken, deployVestingEscrowWallet} from "./helpers/createInstances"; +import latestTime from "./helpers/latestTime"; +import {duration} from "./helpers/utils"; + +const VestingEscrowWallet = artifacts.require('./VestingEscrowWallet.sol'); + +const Web3 = require('web3'); +const BigNumber = require('bignumber.js'); +const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));// Hardcoded development port + +contract('VestingEscrowWallet', accounts => { + + // Accounts Variable declaration + let account_polymath; + let account_issuer; + let token_owner; + let account_user1; + let account_user2; + let account_user3; + + let message = "Transaction Should Fail!"; + + // Contract Instance Declaration + let I_VestingEscrowWallet; + let I_PolyToken; + let I_PolymathRegistry; + + before(async () => { + // Accounts setup + account_polymath = accounts[0]; + account_issuer = accounts[1]; + + token_owner = account_issuer; + + account_user1 = accounts[7]; + account_user2 = accounts[8]; + account_user3 = accounts[9]; + + // Step 1: Deploy the PolyToken + [I_PolymathRegistry, I_PolyToken] = await deployPolyRegistryAndPolyToken(account_polymath, token_owner); + + // STEP 2: Deploy the VestingEscrowWallet + [I_VestingEscrowWallet] = await deployVestingEscrowWallet(account_polymath, I_PolyToken.address, token_owner); + + // Printing all the contract addresses + console.log(` + --------------------- Polymath Network Smart Contracts: --------------------- + PolymathRegistry: ${I_PolymathRegistry.address} + PolyToken: ${I_PolyToken.address} + + VestingEscrowWalle: ${I_VestingEscrowWallet.address} + ----------------------------------------------------------------------------- + `); + }); + + describe("Adding Vesting Schedule", async () => { + + it("Should add Vesting Schedule to the user address", async () => { + const tx = await I_VestingEscrowWallet.addVestingSchedule(account_user1, 100000, duration.years(4), duration.years(1), latestTime(), {from: account_polymath}); + + console.log("====================================================="); + console.log(tx.logs); + console.log("====================================================="); + + // assert.equal(tx.logs[2].args._types[0].toNumber(), 4, "ScheduledCheckpoint doesn't get deployed"); + // assert.equal(tx.logs[2].args._types[1].toNumber(), 2, "ScheduledCheckpoint doesn't get deployed"); + // assert.equal( + // web3.utils.toAscii(tx.logs[2].args._name) + // .replace(/\u0000/g, ''), + // "ScheduledCheckpoint", + // "ScheduledCheckpoint module was not added" + // ); + }); + + + }); + +}); \ No newline at end of file From ee2c89d441cec4bee183d25b09a8e9ea0592f855 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Tue, 13 Nov 2018 19:59:03 +0200 Subject: [PATCH 03/93] refactored add and revoke methods --- contracts/wallet/VestingEscrowWallet.sol | 82 ++++++++++++++++-------- test/z_vesting_escrow_wallet.js | 47 ++++++++------ 2 files changed, 82 insertions(+), 47 deletions(-) diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index 0c7897702..2e8ce15ab 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -28,18 +28,18 @@ contract VestingEscrowWallet is Ownable { uint256 public unassignedTokens; mapping (address => VestingData) public schedules; - address[] public users; + address[] public beneficiaries; event AddVestingSchedule( - address _user, + address _beneficiary, uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, uint256 _startDate, uint256 _timestamp ); - event RevokeVestingSchedules(address _user, uint256 _timestamp); - event RevokeVestingSchedule(address _user, uint256 index, uint256 _timestamp); + event RevokeVestingSchedules(address _beneficiary, uint256 _timestamp); + event RevokeVestingSchedule(address _beneficiary, uint256 index, uint256 _timestamp); constructor(address _tokenAddress, address _treasury) public { token = IERC20(_tokenAddress); @@ -47,7 +47,7 @@ contract VestingEscrowWallet is Ownable { } function addVestingSchedule( - address _user, + address _beneficiary, uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, @@ -56,44 +56,62 @@ contract VestingEscrowWallet is Ownable { external onlyOwner { + require(_beneficiary != address(0), "Invalid beneficiary address"); //TODO validation + VestingSchedule memory schedule; schedule.numberOfTokens = _numberOfTokens; schedule.vestingDuration = _vestingDuration; schedule.vestingFrequency = _vestingFrequency; schedule.startDate = _startDate; - //add user to the schedule list only if adding first schedule - if (schedules[_user].schedules.length == 0) { - schedules[_user].index = users.length; - users.push(_user); + //add beneficiary to the schedule list only if adding first schedule + if (schedules[_beneficiary].schedules.length == 0) { + schedules[_beneficiary].index = beneficiaries.length; + beneficiaries.push(_beneficiary); } - schedules[_user].schedules.push(schedule); + schedules[_beneficiary].schedules.push(schedule); /*solium-disable-next-line security/no-block-members*/ - emit AddVestingSchedule(_user, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate, now); + emit AddVestingSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate, now); } - function revokeVestingSchedule(address _user, uint256 index) external onlyOwner { - //TODO validation - + function revokeVestingSchedule(address _beneficiary, uint256 index) external onlyOwner { + require(_beneficiary != address(0), "Invalid beneficiary address"); + require(index < schedules[_beneficiary].schedules.length, "Schedule not found"); + VestingSchedule[] storage vestingSchedule = schedules[_beneficiary].schedules; + vestingSchedule[index] = vestingSchedule[vestingSchedule.length - 1]; + vestingSchedule.length--; + if (vestingSchedule.length == 0) { + _revokeVestingSchedules(_beneficiary); + } /*solium-disable-next-line security/no-block-members*/ - emit RevokeVestingSchedule(_user, index, now); + emit RevokeVestingSchedule(_beneficiary, index, now); } - function revokeVestingSchedules(address _user) external onlyOwner { - //TODO validation - uint256 index = schedules[_user].index; - users[index] = users[users.length - 1]; - users.length--; - if (index != users.length) { - schedules[users[index]].index = index; - } - delete schedules[_user]; + function revokeVestingSchedules(address _beneficiary) external onlyOwner { + require(_beneficiary != address(0), "Invalid beneficiary address"); + _revokeVestingSchedules(_beneficiary); /*solium-disable-next-line security/no-block-members*/ - emit RevokeVestingSchedules(_user, now); + emit RevokeVestingSchedules(_beneficiary, now); + } + + function getVestingSchedule(address _beneficiary, uint256 index) external onlyOwner returns(uint256, uint256, uint256, uint256) { + require(_beneficiary != address(0), "Invalid beneficiary address"); + require(index < schedules[_beneficiary].schedules.length, "Schedule not found"); + return ( + schedules[_beneficiary].schedules[index].numberOfTokens, + schedules[_beneficiary].schedules[index].vestingDuration, + schedules[_beneficiary].schedules[index].vestingFrequency, + schedules[_beneficiary].schedules[index].startDate + ); + } + + function getVestingScheduleCount(address _beneficiary, uint256 index) external onlyOwner returns(uint256) { + require(_beneficiary != address(0), "Invalid beneficiary address"); + return schedules[_beneficiary].schedules.length; } function editVestingSchedule( - address _user, + address _beneficiary, uint256 index, uint256 _numberOfTokens, uint256 _vestingDuration, @@ -103,7 +121,19 @@ contract VestingEscrowWallet is Ownable { external onlyOwner { + //TODO implement + } + + + function _revokeVestingSchedules(address _beneficiary) private { + uint256 index = schedules[_beneficiary].index; + beneficiaries[index] = beneficiaries[beneficiaries.length - 1]; + beneficiaries.length--; + if (index != beneficiaries.length) { + schedules[beneficiaries[index]].index = index; + } + delete schedules[_beneficiary]; } } diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 565be8ce9..4b4b8adbb 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -14,9 +14,9 @@ contract('VestingEscrowWallet', accounts => { let account_polymath; let account_issuer; let token_owner; - let account_user1; - let account_user2; - let account_user3; + let account_beneficiary1; + let account_beneficiary2; + let account_beneficiary3; let message = "Transaction Should Fail!"; @@ -32,9 +32,9 @@ contract('VestingEscrowWallet', accounts => { token_owner = account_issuer; - account_user1 = accounts[7]; - account_user2 = accounts[8]; - account_user3 = accounts[9]; + account_beneficiary1 = accounts[7]; + account_beneficiary2 = accounts[8]; + account_beneficiary3 = accounts[9]; // Step 1: Deploy the PolyToken [I_PolymathRegistry, I_PolyToken] = await deployPolyRegistryAndPolyToken(account_polymath, token_owner); @@ -55,21 +55,26 @@ contract('VestingEscrowWallet', accounts => { describe("Adding Vesting Schedule", async () => { - it("Should add Vesting Schedule to the user address", async () => { - const tx = await I_VestingEscrowWallet.addVestingSchedule(account_user1, 100000, duration.years(4), duration.years(1), latestTime(), {from: account_polymath}); - - console.log("====================================================="); - console.log(tx.logs); - console.log("====================================================="); - - // assert.equal(tx.logs[2].args._types[0].toNumber(), 4, "ScheduledCheckpoint doesn't get deployed"); - // assert.equal(tx.logs[2].args._types[1].toNumber(), 2, "ScheduledCheckpoint doesn't get deployed"); - // assert.equal( - // web3.utils.toAscii(tx.logs[2].args._name) - // .replace(/\u0000/g, ''), - // "ScheduledCheckpoint", - // "ScheduledCheckpoint module was not added" - // ); + it("Should add Vesting Schedule to the beneficiary address", async () => { + let numberOfTokens = 100000; + let vestingDuration = duration.years(4); + let vestingFrequency = duration.years(1); + let startDate = latestTime(); + const tx = await I_VestingEscrowWallet.addVestingSchedule( + account_beneficiary1, + numberOfTokens, + vestingDuration, + vestingFrequency, + startDate, + {from: account_polymath} + ); + + let log = tx.logs[0]; + assert.equal(log.args._beneficiary, account_beneficiary1); + assert.equal(log.args._numberOfTokens, numberOfTokens); + assert.equal(log.args._vestingDuration, vestingDuration); + assert.equal(log.args._vestingFrequency, vestingFrequency); + assert.equal(log.args._startDate, startDate); }); From 1fadb74e91a68644d451b9edf326932b2d21e9ac Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 14 Nov 2018 13:51:56 +0200 Subject: [PATCH 04/93] added nextDate to schedule --- contracts/wallet/VestingEscrowWallet.sol | 51 +++++++++++++++++------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index 2e8ce15ab..448c0ebe2 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -15,11 +15,13 @@ contract VestingEscrowWallet is Ownable { uint256 vestingDuration; uint256 vestingFrequency; uint256 startDate; + uint256 nextDate; } struct VestingData { - VestingSchedule[] schedules; uint256 index; + VestingSchedule[] schedules; + uint256 availableTokens; } IERC20 public token; @@ -64,6 +66,7 @@ contract VestingEscrowWallet is Ownable { schedule.vestingDuration = _vestingDuration; schedule.vestingFrequency = _vestingFrequency; schedule.startDate = _startDate; + schedule.nextDate = _startDate + _vestingFrequency; //add beneficiary to the schedule list only if adding first schedule if (schedules[_beneficiary].schedules.length == 0) { schedules[_beneficiary].index = beneficiaries.length; @@ -77,10 +80,10 @@ contract VestingEscrowWallet is Ownable { function revokeVestingSchedule(address _beneficiary, uint256 index) external onlyOwner { require(_beneficiary != address(0), "Invalid beneficiary address"); require(index < schedules[_beneficiary].schedules.length, "Schedule not found"); - VestingSchedule[] storage vestingSchedule = schedules[_beneficiary].schedules; - vestingSchedule[index] = vestingSchedule[vestingSchedule.length - 1]; - vestingSchedule.length--; - if (vestingSchedule.length == 0) { + VestingSchedule[] storage schedule = schedules[_beneficiary].schedules; + schedule[index] = schedule[schedule.length - 1]; + schedule.length--; + if (schedule.length == 0) { _revokeVestingSchedules(_beneficiary); } /*solium-disable-next-line security/no-block-members*/ @@ -89,6 +92,7 @@ contract VestingEscrowWallet is Ownable { function revokeVestingSchedules(address _beneficiary) external onlyOwner { require(_beneficiary != address(0), "Invalid beneficiary address"); + delete schedules[_beneficiary].schedules; _revokeVestingSchedules(_beneficiary); /*solium-disable-next-line security/no-block-members*/ emit RevokeVestingSchedules(_beneficiary, now); @@ -97,11 +101,12 @@ contract VestingEscrowWallet is Ownable { function getVestingSchedule(address _beneficiary, uint256 index) external onlyOwner returns(uint256, uint256, uint256, uint256) { require(_beneficiary != address(0), "Invalid beneficiary address"); require(index < schedules[_beneficiary].schedules.length, "Schedule not found"); + VestingSchedule schedule = schedules[_beneficiary].schedules[index]; return ( - schedules[_beneficiary].schedules[index].numberOfTokens, - schedules[_beneficiary].schedules[index].vestingDuration, - schedules[_beneficiary].schedules[index].vestingFrequency, - schedules[_beneficiary].schedules[index].startDate + schedule.numberOfTokens, + schedule.vestingDuration, + schedule.vestingFrequency, + schedule.startDate ); } @@ -125,15 +130,31 @@ contract VestingEscrowWallet is Ownable { } + function _update(address _beneficiary) internal { + VestingData data = schedules[_beneficiary]; + for (uint256 i = 0; i < data.schedules.length; i++) { + VestingSchedule schedule = data.schedules[i]; + if (schedule.nextDate <= now) { + schedule.nextDate = schedule.nextDate.add(schedule.vestingFrequency); + + } + } + } function _revokeVestingSchedules(address _beneficiary) private { - uint256 index = schedules[_beneficiary].index; - beneficiaries[index] = beneficiaries[beneficiaries.length - 1]; - beneficiaries.length--; - if (index != beneficiaries.length) { - schedules[beneficiaries[index]].index = index; + if (_canBeRemoved(_beneficiary)) { + uint256 index = schedules[_beneficiary].index; + beneficiaries[index] = beneficiaries[beneficiaries.length - 1]; + beneficiaries.length--; + if (index != beneficiaries.length) { + schedules[beneficiaries[index]].index = index; + } + delete schedules[_beneficiary]; } - delete schedules[_beneficiary]; + } + + function _canBeRemoved(address _beneficiary) private returns(bool) { + return (schedules[_beneficiary].availableTokens == 0); } } From d7896ddbb1eda4ed34df2ced4d4af6f0aa46c074 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 14 Nov 2018 16:43:14 +0200 Subject: [PATCH 05/93] added _update, State, lockedTokens --- contracts/wallet/VestingEscrowWallet.sol | 92 ++++++++++++++++-------- 1 file changed, 63 insertions(+), 29 deletions(-) diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index 448c0ebe2..a222210c0 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -1,35 +1,43 @@ pragma solidity ^0.4.24; -import "../../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol"; -import "../../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol"; +import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; +import "openzeppelin-solidity/contracts/math/SafeMath.sol"; +//TODO ? import "../interfaces/IERC20.sol"; +import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol"; /** * @title Wallet for core vesting escrow functionality */ contract VestingEscrowWallet is Ownable { using SafeMath for uint256; + using SafeERC20 for ERC20Basic; struct VestingSchedule { uint256 numberOfTokens; + uint256 lockedTokens; uint256 vestingDuration; uint256 vestingFrequency; uint256 startDate; uint256 nextDate; + State state; } struct VestingData { uint256 index; VestingSchedule[] schedules; uint256 availableTokens; + uint256 claimedTokens; } + enum State {STARTED, COMPLETED} + IERC20 public token; address public treasury; uint256 public unassignedTokens; - mapping (address => VestingData) public schedules; + mapping (address => VestingData) public vestingData; address[] public beneficiaries; event AddVestingSchedule( @@ -59,31 +67,39 @@ contract VestingEscrowWallet is Ownable { onlyOwner { require(_beneficiary != address(0), "Invalid beneficiary address"); - //TODO validation + require(_numberOfTokens > 0, "Number of tokens should be greater than zero"); + require(_vestingDuration % _vestingFrequency == 0, "Duration should be divided entirely by frequency"); + uint256 periodCount = _vestingDuration.div(_vestingFrequency); + require(_numberOfTokens % periodCount == 0, "Number of tokens should be divided entirely by period count"); + require(_numberOfTokens <= unassignedTokens, "Wallet doesn't contain enough unassigned tokens"); VestingSchedule memory schedule; + unassignedTokens = unassignedTokens.sub(_numberOfTokens); schedule.numberOfTokens = _numberOfTokens; + schedule.lockedTokens = _numberOfTokens; schedule.vestingDuration = _vestingDuration; schedule.vestingFrequency = _vestingFrequency; schedule.startDate = _startDate; - schedule.nextDate = _startDate + _vestingFrequency; + schedule.nextDate = _startDate.add(schedule.vestingFrequency); + schedule.state = State.STARTED; //add beneficiary to the schedule list only if adding first schedule - if (schedules[_beneficiary].schedules.length == 0) { - schedules[_beneficiary].index = beneficiaries.length; + if (vestingData[_beneficiary].schedules.length == 0) { + vestingData[_beneficiary].index = beneficiaries.length; beneficiaries.push(_beneficiary); } - schedules[_beneficiary].schedules.push(schedule); + vestingData[_beneficiary].schedules.push(schedule); /*solium-disable-next-line security/no-block-members*/ emit AddVestingSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate, now); } function revokeVestingSchedule(address _beneficiary, uint256 index) external onlyOwner { require(_beneficiary != address(0), "Invalid beneficiary address"); - require(index < schedules[_beneficiary].schedules.length, "Schedule not found"); - VestingSchedule[] storage schedule = schedules[_beneficiary].schedules; - schedule[index] = schedule[schedule.length - 1]; - schedule.length--; - if (schedule.length == 0) { + require(index < vestingData[_beneficiary].schedules.length, "Schedule not found"); + VestingSchedule[] storage schedules = vestingData[_beneficiary].schedules; + unassignedTokens = unassignedTokens.add(schedules[index].lockedTokens); + schedules[index] = schedules[schedules.length - 1]; + schedules.length--; + if (schedules.length == 0) { _revokeVestingSchedules(_beneficiary); } /*solium-disable-next-line security/no-block-members*/ @@ -92,32 +108,39 @@ contract VestingEscrowWallet is Ownable { function revokeVestingSchedules(address _beneficiary) external onlyOwner { require(_beneficiary != address(0), "Invalid beneficiary address"); - delete schedules[_beneficiary].schedules; + VestingData data = vestingData[_beneficiary]; + for (uint256 i = 0; i < data.schedules.length; i++) { + unassignedTokens = unassignedTokens.add(data.schedules[i].lockedTokens); + } + delete vestingData[_beneficiary].schedules; _revokeVestingSchedules(_beneficiary); /*solium-disable-next-line security/no-block-members*/ emit RevokeVestingSchedules(_beneficiary, now); } - function getVestingSchedule(address _beneficiary, uint256 index) external onlyOwner returns(uint256, uint256, uint256, uint256) { + function getVestingSchedule(address _beneficiary, uint256 _index) external onlyOwner returns(uint256, uint256, uint256, uint256, uint256, uint256, State) { require(_beneficiary != address(0), "Invalid beneficiary address"); - require(index < schedules[_beneficiary].schedules.length, "Schedule not found"); - VestingSchedule schedule = schedules[_beneficiary].schedules[index]; + require(_index < vestingData[_beneficiary].schedules.length, "Schedule not found"); + VestingSchedule schedule = vestingData[_beneficiary].schedules[_index]; return ( schedule.numberOfTokens, + schedule.lockedTokens, schedule.vestingDuration, schedule.vestingFrequency, - schedule.startDate + schedule.startDate, + schedule.nextDate, + schedule.state ); } - function getVestingScheduleCount(address _beneficiary, uint256 index) external onlyOwner returns(uint256) { + function getVestingScheduleCount(address _beneficiary) external onlyOwner returns(uint256) { require(_beneficiary != address(0), "Invalid beneficiary address"); - return schedules[_beneficiary].schedules.length; + return vestingData[_beneficiary].schedules.length; } function editVestingSchedule( address _beneficiary, - uint256 index, + uint256 _index, uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, @@ -130,31 +153,42 @@ contract VestingEscrowWallet is Ownable { } + + function _update(address _beneficiary) internal { - VestingData data = schedules[_beneficiary]; + VestingData data = vestingData[_beneficiary]; for (uint256 i = 0; i < data.schedules.length; i++) { VestingSchedule schedule = data.schedules[i]; - if (schedule.nextDate <= now) { - schedule.nextDate = schedule.nextDate.add(schedule.vestingFrequency); - + /*solium-disable-next-line security/no-block-members*/ + if (schedule.state == State.STARTED && schedule.nextDate <= now) { + uint256 periodCount = schedule.vestingDuration.div(schedule.vestingFrequency); + uint256 numberOfTokens = schedule.numberOfTokens.div(periodCount); + data.availableTokens = data.availableTokens.add(numberOfTokens); + schedule.lockedTokens = schedule.lockedTokens.sub(numberOfTokens); + + if (schedule.nextDate == schedule.startDate.add(schedule.vestingDuration)) { + schedule.state = State.COMPLETED; + } else { + schedule.nextDate = schedule.nextDate.add(schedule.vestingFrequency); + } } } } function _revokeVestingSchedules(address _beneficiary) private { if (_canBeRemoved(_beneficiary)) { - uint256 index = schedules[_beneficiary].index; + uint256 index = vestingData[_beneficiary].index; beneficiaries[index] = beneficiaries[beneficiaries.length - 1]; beneficiaries.length--; if (index != beneficiaries.length) { - schedules[beneficiaries[index]].index = index; + vestingData[beneficiaries[index]].index = index; } - delete schedules[_beneficiary]; + delete vestingData[_beneficiary]; } } function _canBeRemoved(address _beneficiary) private returns(bool) { - return (schedules[_beneficiary].availableTokens == 0); + return (vestingData[_beneficiary].availableTokens == 0); } } From 2b717850bd9bdb01db0aaffa69465d33a5b57427 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 14 Nov 2018 20:56:24 +0200 Subject: [PATCH 06/93] added deposit/withdrawal functions --- contracts/wallet/VestingEscrowWallet.sol | 49 ++++++++++++++++++++---- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index a222210c0..4fed0fc4d 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -2,8 +2,7 @@ pragma solidity ^0.4.24; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; -//TODO ? -import "../interfaces/IERC20.sol"; +import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol"; /** @@ -11,7 +10,7 @@ import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol"; */ contract VestingEscrowWallet is Ownable { using SafeMath for uint256; - using SafeERC20 for ERC20Basic; + using SafeERC20 for ERC20; struct VestingSchedule { uint256 numberOfTokens; @@ -32,7 +31,7 @@ contract VestingEscrowWallet is Ownable { enum State {STARTED, COMPLETED} - IERC20 public token; + ERC20 public token; address public treasury; uint256 public unassignedTokens; @@ -51,11 +50,35 @@ contract VestingEscrowWallet is Ownable { event RevokeVestingSchedules(address _beneficiary, uint256 _timestamp); event RevokeVestingSchedule(address _beneficiary, uint256 index, uint256 _timestamp); + //TODO add events + constructor(address _tokenAddress, address _treasury) public { - token = IERC20(_tokenAddress); + token = ERC20(_tokenAddress); treasury = _treasury; } + function depositTokens(uint256 _numberOfTokens) external onlyOwner { + require(_numberOfTokens > 0, "Number of tokens should be greater than zero"); + token.safeTransferFrom(treasury, this, _numberOfTokens); + unassignedTokens = unassignedTokens.add(_numberOfTokens); + } + + function sendToTreasury() external onlyOwner { + uint256 amount = unassignedTokens; + unassignedTokens = 0; + token.safeTransfer(treasury, amount); + } + + function sendAvailableTokens(address _beneficiary) external onlyOwner { + _update(_beneficiary); + _sendTokens(_beneficiary); + } + + function withdrawAvailableTokens() external { + _update(msg.sender); + _sendTokens(msg.sender); + } + function addVestingSchedule( address _beneficiary, uint256 _numberOfTokens, @@ -153,7 +176,14 @@ contract VestingEscrowWallet is Ownable { } - + function _sendTokens(address _beneficiary) private { + VestingData data = vestingData[_beneficiary]; + uint256 amount = data.availableTokens; + require(amount > 0, "Beneficiary doesn't have available tokens"); + data.availableTokens = 0; + data.claimedTokens = data.claimedTokens.add(amount); + token.safeTransfer(_beneficiary, amount); + } function _update(address _beneficiary) internal { VestingData data = vestingData[_beneficiary]; @@ -165,7 +195,6 @@ contract VestingEscrowWallet is Ownable { uint256 numberOfTokens = schedule.numberOfTokens.div(periodCount); data.availableTokens = data.availableTokens.add(numberOfTokens); schedule.lockedTokens = schedule.lockedTokens.sub(numberOfTokens); - if (schedule.nextDate == schedule.startDate.add(schedule.vestingDuration)) { schedule.state = State.COMPLETED; } else { @@ -175,6 +204,12 @@ contract VestingEscrowWallet is Ownable { } } + function _updateAll() internal { + for (uint256 i = 0; i < beneficiaries.length; i++) { + _update(beneficiaries[i]); + } + } + function _revokeVestingSchedules(address _beneficiary) private { if (_canBeRemoved(_beneficiary)) { uint256 index = vestingData[_beneficiary].index; From 1e6e7ca02c50331b005f7330d0629344281176bb Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 14 Nov 2018 23:08:35 +0200 Subject: [PATCH 07/93] added batch operations, events --- contracts/wallet/VestingEscrowWallet.sol | 114 +++++++++++++++++++---- 1 file changed, 94 insertions(+), 20 deletions(-) diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index 4fed0fc4d..1d9451613 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -47,10 +47,20 @@ contract VestingEscrowWallet is Ownable { uint256 _startDate, uint256 _timestamp ); + event EditVestingSchedule( + address _beneficiary, + uint256 _index, + uint256 _numberOfTokens, + uint256 _vestingDuration, + uint256 _vestingFrequency, + uint256 _startDate, + uint256 _timestamp + ); event RevokeVestingSchedules(address _beneficiary, uint256 _timestamp); - event RevokeVestingSchedule(address _beneficiary, uint256 index, uint256 _timestamp); - - //TODO add events + event RevokeVestingSchedule(address _beneficiary, uint256 _index, uint256 _timestamp); + event DepositTokens(uint256 _numberOfTokens, uint256 _timestamp); + event SendToTreasury(uint256 _numberOfTokens, uint256 _timestamp); + event SendTokens(address _beneficiary, uint256 _numberOfTokens, uint256 _timestamp); constructor(address _tokenAddress, address _treasury) public { token = ERC20(_tokenAddress); @@ -61,15 +71,19 @@ contract VestingEscrowWallet is Ownable { require(_numberOfTokens > 0, "Number of tokens should be greater than zero"); token.safeTransferFrom(treasury, this, _numberOfTokens); unassignedTokens = unassignedTokens.add(_numberOfTokens); + /*solium-disable-next-line security/no-block-members*/ + emit DepositTokens(_numberOfTokens, now); } function sendToTreasury() external onlyOwner { uint256 amount = unassignedTokens; unassignedTokens = 0; token.safeTransfer(treasury, amount); + /*solium-disable-next-line security/no-block-members*/ + emit SendToTreasury(amount, now); } - function sendAvailableTokens(address _beneficiary) external onlyOwner { + function sendAvailableTokens(address _beneficiary) public onlyOwner { _update(_beneficiary); _sendTokens(_beneficiary); } @@ -86,14 +100,10 @@ contract VestingEscrowWallet is Ownable { uint256 _vestingFrequency, uint256 _startDate ) - external + public onlyOwner { - require(_beneficiary != address(0), "Invalid beneficiary address"); - require(_numberOfTokens > 0, "Number of tokens should be greater than zero"); - require(_vestingDuration % _vestingFrequency == 0, "Duration should be divided entirely by frequency"); - uint256 periodCount = _vestingDuration.div(_vestingFrequency); - require(_numberOfTokens % periodCount == 0, "Number of tokens should be divided entirely by period count"); + _validateSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate); require(_numberOfTokens <= unassignedTokens, "Wallet doesn't contain enough unassigned tokens"); VestingSchedule memory schedule; @@ -115,21 +125,43 @@ contract VestingEscrowWallet is Ownable { emit AddVestingSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate, now); } - function revokeVestingSchedule(address _beneficiary, uint256 index) external onlyOwner { + function editVestingSchedule( + address _beneficiary, + uint256 _index, + uint256 _numberOfTokens, + uint256 _vestingDuration, + uint256 _vestingFrequency, + uint256 _startDate + ) + external + onlyOwner + { + _validateSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate); + require(_index < vestingData[_beneficiary].schedules.length, "Schedule not found"); +// require(_numberOfTokens <= unassignedTokens, "Wallet doesn't contain enough unassigned tokens"); + + VestingSchedule storage schedule = vestingData[_beneficiary].schedules[_index]; + + //TODO implement + + emit EditVestingSchedule(_beneficiary, _index, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate, now); + } + + function revokeVestingSchedule(address _beneficiary, uint256 _index) external onlyOwner { require(_beneficiary != address(0), "Invalid beneficiary address"); - require(index < vestingData[_beneficiary].schedules.length, "Schedule not found"); + require(_index < vestingData[_beneficiary].schedules.length, "Schedule not found"); VestingSchedule[] storage schedules = vestingData[_beneficiary].schedules; - unassignedTokens = unassignedTokens.add(schedules[index].lockedTokens); - schedules[index] = schedules[schedules.length - 1]; + unassignedTokens = unassignedTokens.add(schedules[_index].lockedTokens); + schedules[_index] = schedules[schedules.length - 1]; schedules.length--; if (schedules.length == 0) { _revokeVestingSchedules(_beneficiary); } /*solium-disable-next-line security/no-block-members*/ - emit RevokeVestingSchedule(_beneficiary, index, now); + emit RevokeVestingSchedule(_beneficiary, _index, now); } - function revokeVestingSchedules(address _beneficiary) external onlyOwner { + function revokeVestingSchedules(address _beneficiary) public onlyOwner { require(_beneficiary != address(0), "Invalid beneficiary address"); VestingData data = vestingData[_beneficiary]; for (uint256 i = 0; i < data.schedules.length; i++) { @@ -161,8 +193,35 @@ contract VestingEscrowWallet is Ownable { return vestingData[_beneficiary].schedules.length; } - function editVestingSchedule( - address _beneficiary, + function batchSendAvailableTokens(address[] _beneficiaries) external onlyOwner { + for (uint256 i = 0; i < _beneficiaries.length; i++) { + sendAvailableTokens(_beneficiaries[i]); + } + } + + function batchAddVestingSchedule( + address[] _beneficiaries, + uint256 _numberOfTokens, + uint256 _vestingDuration, + uint256 _vestingFrequency, + uint256 _startDate + ) + external + onlyOwner + { + for (uint256 i = 0; i < _beneficiaries.length; i++) { + addVestingSchedule(_beneficiaries[i], _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate); + } + } + + function batchRevokeVestingSchedules(address[] _beneficiaries) external onlyOwner { + for (uint256 i = 0; i < _beneficiaries.length; i++) { + revokeVestingSchedules(_beneficiaries[i]); + } + } + + function batchEditVestingSchedule( + address[] _beneficiaries, uint256 _index, uint256 _numberOfTokens, uint256 _vestingDuration, @@ -175,6 +234,19 @@ contract VestingEscrowWallet is Ownable { //TODO implement } + function _validateSchedule( + address _beneficiary, + uint256 _numberOfTokens, + uint256 _vestingDuration, + uint256 _vestingFrequency, + uint256 _startDate) + { + require(_beneficiary != address(0), "Invalid beneficiary address"); + require(_numberOfTokens > 0, "Number of tokens should be greater than zero"); + require(_vestingDuration % _vestingFrequency == 0, "Duration should be divided entirely by frequency"); + uint256 periodCount = _vestingDuration.div(_vestingFrequency); + require(_numberOfTokens % periodCount == 0, "Number of tokens should be divided entirely by period count"); + } function _sendTokens(address _beneficiary) private { VestingData data = vestingData[_beneficiary]; @@ -183,9 +255,11 @@ contract VestingEscrowWallet is Ownable { data.availableTokens = 0; data.claimedTokens = data.claimedTokens.add(amount); token.safeTransfer(_beneficiary, amount); + /*solium-disable-next-line security/no-block-members*/ + emit SendTokens(_beneficiary, amount, now); } - function _update(address _beneficiary) internal { + function _update(address _beneficiary) private { VestingData data = vestingData[_beneficiary]; for (uint256 i = 0; i < data.schedules.length; i++) { VestingSchedule schedule = data.schedules[i]; @@ -204,7 +278,7 @@ contract VestingEscrowWallet is Ownable { } } - function _updateAll() internal { + function _updateAll() private { for (uint256 i = 0; i < beneficiaries.length; i++) { _update(beneficiaries[i]); } From fa7c049a923bda18c23473070d4dd6a375f8bb93 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 14 Nov 2018 23:50:31 +0200 Subject: [PATCH 08/93] added template --- contracts/wallet/VestingEscrowWallet.sol | 68 ++++++++++++++++-------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index 1d9451613..a81c7b04c 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -8,6 +8,7 @@ import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol"; /** * @title Wallet for core vesting escrow functionality */ +//TODO remove vesting from methods, events, variables contract VestingEscrowWallet is Ownable { using SafeMath for uint256; using SafeERC20 for ERC20; @@ -29,16 +30,23 @@ contract VestingEscrowWallet is Ownable { uint256 claimedTokens; } + struct VestingTemplate { + uint256 numberOfTokens; + uint256 vestingDuration; + uint256 vestingFrequency; + } + enum State {STARTED, COMPLETED} ERC20 public token; address public treasury; - uint256 public unassignedTokens; mapping (address => VestingData) public vestingData; address[] public beneficiaries; + VestingTemplate[] public templates; + event AddVestingSchedule( address _beneficiary, uint256 _numberOfTokens, @@ -61,6 +69,8 @@ contract VestingEscrowWallet is Ownable { event DepositTokens(uint256 _numberOfTokens, uint256 _timestamp); event SendToTreasury(uint256 _numberOfTokens, uint256 _timestamp); event SendTokens(address _beneficiary, uint256 _numberOfTokens, uint256 _timestamp); + event AddVestingTemplate(uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, uint256 _timestamp); + event RemoveVestingTemplate(uint256 _index, uint256 _timestamp); constructor(address _tokenAddress, address _treasury) public { token = ERC20(_tokenAddress); @@ -93,6 +103,25 @@ contract VestingEscrowWallet is Ownable { _sendTokens(msg.sender); } + function addVestingTemplate(uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency) external onlyOwner { + _validateTemplate(_numberOfTokens, _vestingDuration, _vestingFrequency); + VestingTemplate memory template; + template.numberOfTokens = _numberOfTokens; + template.vestingDuration = _vestingDuration; + template.vestingFrequency = _vestingFrequency; + templates.push(template); + /*solium-disable-next-line security/no-block-members*/ + emit AddVestingTemplate(_numberOfTokens, _vestingDuration, _vestingFrequency, now); + } + + function removeVestingTemplate(uint256 _index) external onlyOwner { + require(_index < templates.length, "Template not found"); + templates[_index] = templates[templates.length - 1]; + templates.length--; + /*solium-disable-next-line security/no-block-members*/ + emit RemoveVestingTemplate(_index, now); + } + function addVestingSchedule( address _beneficiary, uint256 _numberOfTokens, @@ -125,6 +154,12 @@ contract VestingEscrowWallet is Ownable { emit AddVestingSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate, now); } + function addVestingScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startDate) public onlyOwner { + require(_index < templates.length, "Template not found"); + VestingTemplate template = templates[_index]; + addVestingSchedule(_beneficiary, template.numberOfTokens, template.vestingDuration, template.vestingFrequency, _startDate); + } + function editVestingSchedule( address _beneficiary, uint256 _index, @@ -214,34 +249,25 @@ contract VestingEscrowWallet is Ownable { } } + function batchAddVestingScheduleFromTemplate(address[] _beneficiaries, uint256 _index, uint256 _startDate) public onlyOwner { + for (uint256 i = 0; i < _beneficiaries.length; i++) { + addVestingScheduleFromTemplate(_beneficiaries[i], _index, _startDate); + } + } + function batchRevokeVestingSchedules(address[] _beneficiaries) external onlyOwner { for (uint256 i = 0; i < _beneficiaries.length; i++) { revokeVestingSchedules(_beneficiaries[i]); } } - function batchEditVestingSchedule( - address[] _beneficiaries, - uint256 _index, - uint256 _numberOfTokens, - uint256 _vestingDuration, - uint256 _vestingFrequency, - uint256 _startDate - ) - external - onlyOwner - { - //TODO implement + function _validateSchedule(address _beneficiary, uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, uint256 _startDate) { + require(_beneficiary != address(0), "Invalid beneficiary address"); + _validateTemplate(_numberOfTokens, _vestingDuration, _vestingFrequency); + require(_startDate < now, "Start date shouldn't be in the past"); } - function _validateSchedule( - address _beneficiary, - uint256 _numberOfTokens, - uint256 _vestingDuration, - uint256 _vestingFrequency, - uint256 _startDate) - { - require(_beneficiary != address(0), "Invalid beneficiary address"); + function _validateTemplate(uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency) { require(_numberOfTokens > 0, "Number of tokens should be greater than zero"); require(_vestingDuration % _vestingFrequency == 0, "Duration should be divided entirely by frequency"); uint256 periodCount = _vestingDuration.div(_vestingFrequency); From a13bdacb6721b87c2906ec0835e69e2839a5cf25 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Thu, 15 Nov 2018 11:04:06 +0200 Subject: [PATCH 09/93] renamed startDate, nextDate to startTime, nextTime --- contracts/wallet/VestingEscrowWallet.sol | 51 ++++++++++++------------ 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index a81c7b04c..db1184ca4 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -8,6 +8,7 @@ import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol"; /** * @title Wallet for core vesting escrow functionality */ +//TODO add docs for public, external methods //TODO remove vesting from methods, events, variables contract VestingEscrowWallet is Ownable { using SafeMath for uint256; @@ -18,8 +19,8 @@ contract VestingEscrowWallet is Ownable { uint256 lockedTokens; uint256 vestingDuration; uint256 vestingFrequency; - uint256 startDate; - uint256 nextDate; + uint256 startTime; + uint256 nextTime; State state; } @@ -52,7 +53,7 @@ contract VestingEscrowWallet is Ownable { uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, - uint256 _startDate, + uint256 _startTime, uint256 _timestamp ); event EditVestingSchedule( @@ -61,7 +62,7 @@ contract VestingEscrowWallet is Ownable { uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, - uint256 _startDate, + uint256 _startTime, uint256 _timestamp ); event RevokeVestingSchedules(address _beneficiary, uint256 _timestamp); @@ -127,12 +128,12 @@ contract VestingEscrowWallet is Ownable { uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, - uint256 _startDate + uint256 _startTime ) public onlyOwner { - _validateSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate); + _validateSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime); require(_numberOfTokens <= unassignedTokens, "Wallet doesn't contain enough unassigned tokens"); VestingSchedule memory schedule; @@ -141,8 +142,8 @@ contract VestingEscrowWallet is Ownable { schedule.lockedTokens = _numberOfTokens; schedule.vestingDuration = _vestingDuration; schedule.vestingFrequency = _vestingFrequency; - schedule.startDate = _startDate; - schedule.nextDate = _startDate.add(schedule.vestingFrequency); + schedule.startTime = _startTime; + schedule.nextTime = _startTime.add(schedule.vestingFrequency); schedule.state = State.STARTED; //add beneficiary to the schedule list only if adding first schedule if (vestingData[_beneficiary].schedules.length == 0) { @@ -151,13 +152,13 @@ contract VestingEscrowWallet is Ownable { } vestingData[_beneficiary].schedules.push(schedule); /*solium-disable-next-line security/no-block-members*/ - emit AddVestingSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate, now); + emit AddVestingSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime, now); } - function addVestingScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startDate) public onlyOwner { + function addVestingScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startTime) public onlyOwner { require(_index < templates.length, "Template not found"); VestingTemplate template = templates[_index]; - addVestingSchedule(_beneficiary, template.numberOfTokens, template.vestingDuration, template.vestingFrequency, _startDate); + addVestingSchedule(_beneficiary, template.numberOfTokens, template.vestingDuration, template.vestingFrequency, _startTime); } function editVestingSchedule( @@ -166,12 +167,12 @@ contract VestingEscrowWallet is Ownable { uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, - uint256 _startDate + uint256 _startTime ) external onlyOwner { - _validateSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate); + _validateSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime); require(_index < vestingData[_beneficiary].schedules.length, "Schedule not found"); // require(_numberOfTokens <= unassignedTokens, "Wallet doesn't contain enough unassigned tokens"); @@ -179,7 +180,7 @@ contract VestingEscrowWallet is Ownable { //TODO implement - emit EditVestingSchedule(_beneficiary, _index, _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate, now); + emit EditVestingSchedule(_beneficiary, _index, _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime, now); } function revokeVestingSchedule(address _beneficiary, uint256 _index) external onlyOwner { @@ -217,8 +218,8 @@ contract VestingEscrowWallet is Ownable { schedule.lockedTokens, schedule.vestingDuration, schedule.vestingFrequency, - schedule.startDate, - schedule.nextDate, + schedule.startTime, + schedule.nextTime, schedule.state ); } @@ -239,19 +240,19 @@ contract VestingEscrowWallet is Ownable { uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, - uint256 _startDate + uint256 _startTime ) external onlyOwner { for (uint256 i = 0; i < _beneficiaries.length; i++) { - addVestingSchedule(_beneficiaries[i], _numberOfTokens, _vestingDuration, _vestingFrequency, _startDate); + addVestingSchedule(_beneficiaries[i], _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime); } } - function batchAddVestingScheduleFromTemplate(address[] _beneficiaries, uint256 _index, uint256 _startDate) public onlyOwner { + function batchAddVestingScheduleFromTemplate(address[] _beneficiaries, uint256 _index, uint256 _startTime) public onlyOwner { for (uint256 i = 0; i < _beneficiaries.length; i++) { - addVestingScheduleFromTemplate(_beneficiaries[i], _index, _startDate); + addVestingScheduleFromTemplate(_beneficiaries[i], _index, _startTime); } } @@ -261,10 +262,10 @@ contract VestingEscrowWallet is Ownable { } } - function _validateSchedule(address _beneficiary, uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, uint256 _startDate) { + function _validateSchedule(address _beneficiary, uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, uint256 _startTime) { require(_beneficiary != address(0), "Invalid beneficiary address"); _validateTemplate(_numberOfTokens, _vestingDuration, _vestingFrequency); - require(_startDate < now, "Start date shouldn't be in the past"); + require(_startTime < now, "Start date shouldn't be in the past"); } function _validateTemplate(uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency) { @@ -290,15 +291,15 @@ contract VestingEscrowWallet is Ownable { for (uint256 i = 0; i < data.schedules.length; i++) { VestingSchedule schedule = data.schedules[i]; /*solium-disable-next-line security/no-block-members*/ - if (schedule.state == State.STARTED && schedule.nextDate <= now) { + if (schedule.state == State.STARTED && schedule.nextTime <= now) { uint256 periodCount = schedule.vestingDuration.div(schedule.vestingFrequency); uint256 numberOfTokens = schedule.numberOfTokens.div(periodCount); data.availableTokens = data.availableTokens.add(numberOfTokens); schedule.lockedTokens = schedule.lockedTokens.sub(numberOfTokens); - if (schedule.nextDate == schedule.startDate.add(schedule.vestingDuration)) { + if (schedule.nextTime == schedule.startTime.add(schedule.vestingDuration)) { schedule.state = State.COMPLETED; } else { - schedule.nextDate = schedule.nextDate.add(schedule.vestingFrequency); + schedule.nextTime = schedule.nextTime.add(schedule.vestingFrequency); } } } From ae3c85bdc862bbf5430ad21191835252e8cc6cbc Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Thu, 15 Nov 2018 12:00:51 +0200 Subject: [PATCH 10/93] added edit and batchEdit --- contracts/wallet/VestingEscrowWallet.sol | 45 +++++++++++++++++++----- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index db1184ca4..08ee8775c 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -37,7 +37,7 @@ contract VestingEscrowWallet is Ownable { uint256 vestingFrequency; } - enum State {STARTED, COMPLETED} + enum State {CREATED, STARTED, COMPLETED} ERC20 public token; address public treasury; @@ -144,7 +144,7 @@ contract VestingEscrowWallet is Ownable { schedule.vestingFrequency = _vestingFrequency; schedule.startTime = _startTime; schedule.nextTime = _startTime.add(schedule.vestingFrequency); - schedule.state = State.STARTED; + schedule.state = State.CREATED; //add beneficiary to the schedule list only if adding first schedule if (vestingData[_beneficiary].schedules.length == 0) { vestingData[_beneficiary].index = beneficiaries.length; @@ -169,17 +169,26 @@ contract VestingEscrowWallet is Ownable { uint256 _vestingFrequency, uint256 _startTime ) - external + public onlyOwner { _validateSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime); require(_index < vestingData[_beneficiary].schedules.length, "Schedule not found"); -// require(_numberOfTokens <= unassignedTokens, "Wallet doesn't contain enough unassigned tokens"); - VestingSchedule storage schedule = vestingData[_beneficiary].schedules[_index]; - - //TODO implement - + /*solium-disable-next-line security/no-block-members*/ + require(schedule.startTime < now, "It's not possible to edit the started schedule"); + if (_numberOfTokens <= schedule.lockedTokens) { + unassignedTokens = unassignedTokens.add(schedule.lockedTokens - _numberOfTokens); + } else { + require((_numberOfTokens - schedule.lockedTokens) <= unassignedTokens, "Wallet doesn't contain enough unassigned tokens"); + unassignedTokens = unassignedTokens.sub(_numberOfTokens - schedule.lockedTokens); + } + schedule.numberOfTokens = _numberOfTokens; + schedule.lockedTokens = _numberOfTokens; + schedule.vestingDuration = _vestingDuration; + schedule.vestingFrequency = _vestingFrequency; + schedule.startTime = _startTime; + schedule.nextTime = _startTime.add(schedule.vestingFrequency); emit EditVestingSchedule(_beneficiary, _index, _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime, now); } @@ -262,6 +271,23 @@ contract VestingEscrowWallet is Ownable { } } + function batchEditVestingSchedule( + address[] _beneficiaries, + uint256[] _indexes, + uint256 _numberOfTokens, + uint256 _vestingDuration, + uint256 _vestingFrequency, + uint256 _startTime + ) + external + onlyOwner + { + require(_beneficiaries.length == _indexes.length, "Beneficiaries array and indexes array should have the same length"); + for (uint256 i = 0; i < _beneficiaries.length; i++) { + editVestingSchedule(_beneficiaries[i], _indexes[i], _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime); + } + } + function _validateSchedule(address _beneficiary, uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, uint256 _startTime) { require(_beneficiary != address(0), "Invalid beneficiary address"); _validateTemplate(_numberOfTokens, _vestingDuration, _vestingFrequency); @@ -291,7 +317,7 @@ contract VestingEscrowWallet is Ownable { for (uint256 i = 0; i < data.schedules.length; i++) { VestingSchedule schedule = data.schedules[i]; /*solium-disable-next-line security/no-block-members*/ - if (schedule.state == State.STARTED && schedule.nextTime <= now) { + if (schedule.state != State.COMPLETED && schedule.nextTime <= now) { uint256 periodCount = schedule.vestingDuration.div(schedule.vestingFrequency); uint256 numberOfTokens = schedule.numberOfTokens.div(periodCount); data.availableTokens = data.availableTokens.add(numberOfTokens); @@ -299,6 +325,7 @@ contract VestingEscrowWallet is Ownable { if (schedule.nextTime == schedule.startTime.add(schedule.vestingDuration)) { schedule.state = State.COMPLETED; } else { + schedule.state = State.STARTED; schedule.nextTime = schedule.nextTime.add(schedule.vestingFrequency); } } From 21377cdd8da1952a11606e69600ff279a307548b Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Thu, 15 Nov 2018 13:07:00 +0200 Subject: [PATCH 11/93] removed redundant "vesting" from names --- contracts/wallet/VestingEscrowWallet.sol | 201 +++++++++++------------ test/z_vesting_escrow_wallet.js | 23 +-- 2 files changed, 108 insertions(+), 116 deletions(-) diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index 08ee8775c..2d8ca803f 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -9,32 +9,31 @@ import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol"; * @title Wallet for core vesting escrow functionality */ //TODO add docs for public, external methods -//TODO remove vesting from methods, events, variables contract VestingEscrowWallet is Ownable { using SafeMath for uint256; using SafeERC20 for ERC20; - struct VestingSchedule { + struct Schedule { uint256 numberOfTokens; uint256 lockedTokens; - uint256 vestingDuration; - uint256 vestingFrequency; + uint256 duration; + uint256 frequency; uint256 startTime; uint256 nextTime; State state; } - struct VestingData { + struct Data { uint256 index; - VestingSchedule[] schedules; + Schedule[] schedules; uint256 availableTokens; uint256 claimedTokens; } - struct VestingTemplate { + struct Template { uint256 numberOfTokens; - uint256 vestingDuration; - uint256 vestingFrequency; + uint256 duration; + uint256 frequency; } enum State {CREATED, STARTED, COMPLETED} @@ -43,35 +42,35 @@ contract VestingEscrowWallet is Ownable { address public treasury; uint256 public unassignedTokens; - mapping (address => VestingData) public vestingData; + mapping (address => Data) public dataMap; address[] public beneficiaries; - VestingTemplate[] public templates; + Template[] public templates; - event AddVestingSchedule( + event AddSchedule( address _beneficiary, uint256 _numberOfTokens, - uint256 _vestingDuration, - uint256 _vestingFrequency, + uint256 _duration, + uint256 _frequency, uint256 _startTime, uint256 _timestamp ); - event EditVestingSchedule( + event EditSchedule( address _beneficiary, uint256 _index, uint256 _numberOfTokens, - uint256 _vestingDuration, - uint256 _vestingFrequency, + uint256 _duration, + uint256 _frequency, uint256 _startTime, uint256 _timestamp ); - event RevokeVestingSchedules(address _beneficiary, uint256 _timestamp); - event RevokeVestingSchedule(address _beneficiary, uint256 _index, uint256 _timestamp); + event RevokeSchedules(address _beneficiary, uint256 _timestamp); + event RevokeSchedule(address _beneficiary, uint256 _index, uint256 _timestamp); event DepositTokens(uint256 _numberOfTokens, uint256 _timestamp); event SendToTreasury(uint256 _numberOfTokens, uint256 _timestamp); event SendTokens(address _beneficiary, uint256 _numberOfTokens, uint256 _timestamp); - event AddVestingTemplate(uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, uint256 _timestamp); - event RemoveVestingTemplate(uint256 _index, uint256 _timestamp); + event AddTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, uint256 _timestamp); + event RemoveTemplate(uint256 _index, uint256 _timestamp); constructor(address _tokenAddress, address _treasury) public { token = ERC20(_tokenAddress); @@ -104,77 +103,77 @@ contract VestingEscrowWallet is Ownable { _sendTokens(msg.sender); } - function addVestingTemplate(uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency) external onlyOwner { - _validateTemplate(_numberOfTokens, _vestingDuration, _vestingFrequency); - VestingTemplate memory template; + function addTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) external onlyOwner { + _validateTemplate(_numberOfTokens, _duration, _frequency); + Template memory template; template.numberOfTokens = _numberOfTokens; - template.vestingDuration = _vestingDuration; - template.vestingFrequency = _vestingFrequency; + template.duration = _duration; + template.frequency = _frequency; templates.push(template); /*solium-disable-next-line security/no-block-members*/ - emit AddVestingTemplate(_numberOfTokens, _vestingDuration, _vestingFrequency, now); + emit AddTemplate(_numberOfTokens, _duration, _frequency, now); } - function removeVestingTemplate(uint256 _index) external onlyOwner { + function removeTemplate(uint256 _index) external onlyOwner { require(_index < templates.length, "Template not found"); templates[_index] = templates[templates.length - 1]; templates.length--; /*solium-disable-next-line security/no-block-members*/ - emit RemoveVestingTemplate(_index, now); + emit RemoveTemplate(_index, now); } - function addVestingSchedule( + function addSchedule( address _beneficiary, uint256 _numberOfTokens, - uint256 _vestingDuration, - uint256 _vestingFrequency, + uint256 _duration, + uint256 _frequency, uint256 _startTime ) public onlyOwner { - _validateSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime); + _validateSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); require(_numberOfTokens <= unassignedTokens, "Wallet doesn't contain enough unassigned tokens"); - VestingSchedule memory schedule; + Schedule memory schedule; unassignedTokens = unassignedTokens.sub(_numberOfTokens); schedule.numberOfTokens = _numberOfTokens; schedule.lockedTokens = _numberOfTokens; - schedule.vestingDuration = _vestingDuration; - schedule.vestingFrequency = _vestingFrequency; + schedule.duration = _duration; + schedule.frequency = _frequency; schedule.startTime = _startTime; - schedule.nextTime = _startTime.add(schedule.vestingFrequency); + schedule.nextTime = _startTime.add(schedule.frequency); schedule.state = State.CREATED; //add beneficiary to the schedule list only if adding first schedule - if (vestingData[_beneficiary].schedules.length == 0) { - vestingData[_beneficiary].index = beneficiaries.length; + if (dataMap[_beneficiary].schedules.length == 0) { + dataMap[_beneficiary].index = beneficiaries.length; beneficiaries.push(_beneficiary); } - vestingData[_beneficiary].schedules.push(schedule); + dataMap[_beneficiary].schedules.push(schedule); /*solium-disable-next-line security/no-block-members*/ - emit AddVestingSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime, now); + emit AddSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime, now); } - function addVestingScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startTime) public onlyOwner { + function addScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startTime) public onlyOwner { require(_index < templates.length, "Template not found"); - VestingTemplate template = templates[_index]; - addVestingSchedule(_beneficiary, template.numberOfTokens, template.vestingDuration, template.vestingFrequency, _startTime); + Template storage template = templates[_index]; + addSchedule(_beneficiary, template.numberOfTokens, template.duration, template.frequency, _startTime); } - function editVestingSchedule( + function editSchedule( address _beneficiary, uint256 _index, uint256 _numberOfTokens, - uint256 _vestingDuration, - uint256 _vestingFrequency, + uint256 _duration, + uint256 _frequency, uint256 _startTime ) public onlyOwner { - _validateSchedule(_beneficiary, _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime); - require(_index < vestingData[_beneficiary].schedules.length, "Schedule not found"); - VestingSchedule storage schedule = vestingData[_beneficiary].schedules[_index]; + _validateSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); + require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); + Schedule storage schedule = dataMap[_beneficiary].schedules[_index]; /*solium-disable-next-line security/no-block-members*/ require(schedule.startTime < now, "It's not possible to edit the started schedule"); if (_numberOfTokens <= schedule.lockedTokens) { @@ -185,57 +184,57 @@ contract VestingEscrowWallet is Ownable { } schedule.numberOfTokens = _numberOfTokens; schedule.lockedTokens = _numberOfTokens; - schedule.vestingDuration = _vestingDuration; - schedule.vestingFrequency = _vestingFrequency; + schedule.duration = _duration; + schedule.frequency = _frequency; schedule.startTime = _startTime; - schedule.nextTime = _startTime.add(schedule.vestingFrequency); - emit EditVestingSchedule(_beneficiary, _index, _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime, now); + schedule.nextTime = _startTime.add(schedule.frequency); + emit EditSchedule(_beneficiary, _index, _numberOfTokens, _duration, _frequency, _startTime, now); } - function revokeVestingSchedule(address _beneficiary, uint256 _index) external onlyOwner { + function revokeSchedule(address _beneficiary, uint256 _index) external onlyOwner { require(_beneficiary != address(0), "Invalid beneficiary address"); - require(_index < vestingData[_beneficiary].schedules.length, "Schedule not found"); - VestingSchedule[] storage schedules = vestingData[_beneficiary].schedules; + require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); + Schedule[] storage schedules = dataMap[_beneficiary].schedules; unassignedTokens = unassignedTokens.add(schedules[_index].lockedTokens); schedules[_index] = schedules[schedules.length - 1]; schedules.length--; if (schedules.length == 0) { - _revokeVestingSchedules(_beneficiary); + _revokeSchedules(_beneficiary); } /*solium-disable-next-line security/no-block-members*/ - emit RevokeVestingSchedule(_beneficiary, _index, now); + emit RevokeSchedule(_beneficiary, _index, now); } - function revokeVestingSchedules(address _beneficiary) public onlyOwner { + function revokeSchedules(address _beneficiary) public onlyOwner { require(_beneficiary != address(0), "Invalid beneficiary address"); - VestingData data = vestingData[_beneficiary]; + Data storage data = dataMap[_beneficiary]; for (uint256 i = 0; i < data.schedules.length; i++) { unassignedTokens = unassignedTokens.add(data.schedules[i].lockedTokens); } - delete vestingData[_beneficiary].schedules; - _revokeVestingSchedules(_beneficiary); + delete dataMap[_beneficiary].schedules; + _revokeSchedules(_beneficiary); /*solium-disable-next-line security/no-block-members*/ - emit RevokeVestingSchedules(_beneficiary, now); + emit RevokeSchedules(_beneficiary, now); } - function getVestingSchedule(address _beneficiary, uint256 _index) external onlyOwner returns(uint256, uint256, uint256, uint256, uint256, uint256, State) { + function getSchedule(address _beneficiary, uint256 _index) external view onlyOwner returns(uint256, uint256, uint256, uint256, uint256, uint256, State) { require(_beneficiary != address(0), "Invalid beneficiary address"); - require(_index < vestingData[_beneficiary].schedules.length, "Schedule not found"); - VestingSchedule schedule = vestingData[_beneficiary].schedules[_index]; + require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); + Schedule storage schedule = dataMap[_beneficiary].schedules[_index]; return ( schedule.numberOfTokens, schedule.lockedTokens, - schedule.vestingDuration, - schedule.vestingFrequency, + schedule.duration, + schedule.frequency, schedule.startTime, schedule.nextTime, schedule.state ); } - function getVestingScheduleCount(address _beneficiary) external onlyOwner returns(uint256) { + function getScheduleCount(address _beneficiary) external view onlyOwner returns(uint256) { require(_beneficiary != address(0), "Invalid beneficiary address"); - return vestingData[_beneficiary].schedules.length; + return dataMap[_beneficiary].schedules.length; } function batchSendAvailableTokens(address[] _beneficiaries) external onlyOwner { @@ -244,39 +243,39 @@ contract VestingEscrowWallet is Ownable { } } - function batchAddVestingSchedule( + function batchAddSchedule( address[] _beneficiaries, uint256 _numberOfTokens, - uint256 _vestingDuration, - uint256 _vestingFrequency, + uint256 _duration, + uint256 _frequency, uint256 _startTime ) external onlyOwner { for (uint256 i = 0; i < _beneficiaries.length; i++) { - addVestingSchedule(_beneficiaries[i], _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime); + addSchedule(_beneficiaries[i], _numberOfTokens, _duration, _frequency, _startTime); } } - function batchAddVestingScheduleFromTemplate(address[] _beneficiaries, uint256 _index, uint256 _startTime) public onlyOwner { + function batchAddScheduleFromTemplate(address[] _beneficiaries, uint256 _index, uint256 _startTime) public onlyOwner { for (uint256 i = 0; i < _beneficiaries.length; i++) { - addVestingScheduleFromTemplate(_beneficiaries[i], _index, _startTime); + addScheduleFromTemplate(_beneficiaries[i], _index, _startTime); } } - function batchRevokeVestingSchedules(address[] _beneficiaries) external onlyOwner { + function batchRevokeSchedules(address[] _beneficiaries) external onlyOwner { for (uint256 i = 0; i < _beneficiaries.length; i++) { - revokeVestingSchedules(_beneficiaries[i]); + revokeSchedules(_beneficiaries[i]); } } - function batchEditVestingSchedule( + function batchEditSchedule( address[] _beneficiaries, uint256[] _indexes, uint256 _numberOfTokens, - uint256 _vestingDuration, - uint256 _vestingFrequency, + uint256 _duration, + uint256 _frequency, uint256 _startTime ) external @@ -284,25 +283,25 @@ contract VestingEscrowWallet is Ownable { { require(_beneficiaries.length == _indexes.length, "Beneficiaries array and indexes array should have the same length"); for (uint256 i = 0; i < _beneficiaries.length; i++) { - editVestingSchedule(_beneficiaries[i], _indexes[i], _numberOfTokens, _vestingDuration, _vestingFrequency, _startTime); + editSchedule(_beneficiaries[i], _indexes[i], _numberOfTokens, _duration, _frequency, _startTime); } } - function _validateSchedule(address _beneficiary, uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency, uint256 _startTime) { + function _validateSchedule(address _beneficiary, uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, uint256 _startTime) private view { require(_beneficiary != address(0), "Invalid beneficiary address"); - _validateTemplate(_numberOfTokens, _vestingDuration, _vestingFrequency); - require(_startTime < now, "Start date shouldn't be in the past"); + _validateTemplate(_numberOfTokens, _duration, _frequency); + require(_startTime > now, "Start date shouldn't be in the past"); } - function _validateTemplate(uint256 _numberOfTokens, uint256 _vestingDuration, uint256 _vestingFrequency) { + function _validateTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) private pure { require(_numberOfTokens > 0, "Number of tokens should be greater than zero"); - require(_vestingDuration % _vestingFrequency == 0, "Duration should be divided entirely by frequency"); - uint256 periodCount = _vestingDuration.div(_vestingFrequency); + require(_duration % _frequency == 0, "Duration should be divided entirely by frequency"); + uint256 periodCount = _duration.div(_frequency); require(_numberOfTokens % periodCount == 0, "Number of tokens should be divided entirely by period count"); } function _sendTokens(address _beneficiary) private { - VestingData data = vestingData[_beneficiary]; + Data storage data = dataMap[_beneficiary]; uint256 amount = data.availableTokens; require(amount > 0, "Beneficiary doesn't have available tokens"); data.availableTokens = 0; @@ -313,20 +312,20 @@ contract VestingEscrowWallet is Ownable { } function _update(address _beneficiary) private { - VestingData data = vestingData[_beneficiary]; + Data storage data = dataMap[_beneficiary]; for (uint256 i = 0; i < data.schedules.length; i++) { - VestingSchedule schedule = data.schedules[i]; + Schedule storage schedule = data.schedules[i]; /*solium-disable-next-line security/no-block-members*/ if (schedule.state != State.COMPLETED && schedule.nextTime <= now) { - uint256 periodCount = schedule.vestingDuration.div(schedule.vestingFrequency); + uint256 periodCount = schedule.duration.div(schedule.frequency); uint256 numberOfTokens = schedule.numberOfTokens.div(periodCount); data.availableTokens = data.availableTokens.add(numberOfTokens); schedule.lockedTokens = schedule.lockedTokens.sub(numberOfTokens); - if (schedule.nextTime == schedule.startTime.add(schedule.vestingDuration)) { + if (schedule.nextTime == schedule.startTime.add(schedule.duration)) { schedule.state = State.COMPLETED; } else { schedule.state = State.STARTED; - schedule.nextTime = schedule.nextTime.add(schedule.vestingFrequency); + schedule.nextTime = schedule.nextTime.add(schedule.frequency); } } } @@ -338,20 +337,20 @@ contract VestingEscrowWallet is Ownable { } } - function _revokeVestingSchedules(address _beneficiary) private { + function _revokeSchedules(address _beneficiary) private { if (_canBeRemoved(_beneficiary)) { - uint256 index = vestingData[_beneficiary].index; + uint256 index = dataMap[_beneficiary].index; beneficiaries[index] = beneficiaries[beneficiaries.length - 1]; beneficiaries.length--; if (index != beneficiaries.length) { - vestingData[beneficiaries[index]].index = index; + dataMap[beneficiaries[index]].index = index; } - delete vestingData[_beneficiary]; + delete dataMap[_beneficiary]; } } - function _canBeRemoved(address _beneficiary) private returns(bool) { - return (vestingData[_beneficiary].availableTokens == 0); + function _canBeRemoved(address _beneficiary) private view returns(bool) { + return (dataMap[_beneficiary].availableTokens == 0); } } diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 4b4b8adbb..9b4f0cd45 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -1,6 +1,6 @@ import {deployPolyRegistryAndPolyToken, deployVestingEscrowWallet} from "./helpers/createInstances"; import latestTime from "./helpers/latestTime"; -import {duration} from "./helpers/utils"; +import {duration as durationUtil} from "./helpers/utils"; const VestingEscrowWallet = artifacts.require('./VestingEscrowWallet.sol'); @@ -57,24 +57,17 @@ contract('VestingEscrowWallet', accounts => { it("Should add Vesting Schedule to the beneficiary address", async () => { let numberOfTokens = 100000; - let vestingDuration = duration.years(4); - let vestingFrequency = duration.years(1); - let startDate = latestTime(); - const tx = await I_VestingEscrowWallet.addVestingSchedule( - account_beneficiary1, - numberOfTokens, - vestingDuration, - vestingFrequency, - startDate, - {from: account_polymath} - ); + let duration = durationUtil.years(4); + let frequency = durationUtil.years(1); + let startTime = latestTime() + durationUtil.days(1); + const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: account_polymath}); let log = tx.logs[0]; assert.equal(log.args._beneficiary, account_beneficiary1); assert.equal(log.args._numberOfTokens, numberOfTokens); - assert.equal(log.args._vestingDuration, vestingDuration); - assert.equal(log.args._vestingFrequency, vestingFrequency); - assert.equal(log.args._startDate, startDate); + assert.equal(log.args._duration, duration); + assert.equal(log.args._frequency, frequency); + assert.equal(log.args._startTime, startTime); }); From d600f9752b828dd8f10a28c3fdcffd62278a4a4b Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Thu, 15 Nov 2018 17:22:27 +0200 Subject: [PATCH 12/93] updated test addVestingSchedule --- test/helpers/createInstances.js | 4 ++-- test/z_vesting_escrow_wallet.js | 24 ++++++++++++++++-------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/test/helpers/createInstances.js b/test/helpers/createInstances.js index 319c61f51..966602ba2 100644 --- a/test/helpers/createInstances.js +++ b/test/helpers/createInstances.js @@ -424,8 +424,8 @@ export async function deployMockWrongTypeRedemptionAndVerifyed(accountPolymath, return new Array(I_MockWrongTypeBurnFactory); } -export async function deployVestingEscrowWallet(accountPolymath, polyToken, treasury) { - I_VestingEscrowWallet = await VestingEscrowWallet.new(polyToken, treasury, { from: accountPolymath }); +export async function deployVestingEscrowWallet(accountOwner, polyToken, treasury) { + I_VestingEscrowWallet = await VestingEscrowWallet.new(polyToken, treasury, { from: accountOwner }); assert.notEqual( I_VestingEscrowWallet.address.valueOf(), "0x0000000000000000000000000000000000000000", diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 9b4f0cd45..c37a9eb29 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -12,8 +12,8 @@ contract('VestingEscrowWallet', accounts => { // Accounts Variable declaration let account_polymath; - let account_issuer; - let token_owner; + let wallet_owner; + let account_treasury; let account_beneficiary1; let account_beneficiary2; let account_beneficiary3; @@ -28,19 +28,18 @@ contract('VestingEscrowWallet', accounts => { before(async () => { // Accounts setup account_polymath = accounts[0]; - account_issuer = accounts[1]; - - token_owner = account_issuer; + wallet_owner = accounts[1]; + account_treasury = accounts[2]; account_beneficiary1 = accounts[7]; account_beneficiary2 = accounts[8]; account_beneficiary3 = accounts[9]; // Step 1: Deploy the PolyToken - [I_PolymathRegistry, I_PolyToken] = await deployPolyRegistryAndPolyToken(account_polymath, token_owner); + [I_PolymathRegistry, I_PolyToken] = await deployPolyRegistryAndPolyToken(account_polymath, account_treasury); // STEP 2: Deploy the VestingEscrowWallet - [I_VestingEscrowWallet] = await deployVestingEscrowWallet(account_polymath, I_PolyToken.address, token_owner); + [I_VestingEscrowWallet] = await deployVestingEscrowWallet(wallet_owner, I_PolyToken.address, account_treasury); // Printing all the contract addresses console.log(` @@ -60,7 +59,9 @@ contract('VestingEscrowWallet', accounts => { let duration = durationUtil.years(4); let frequency = durationUtil.years(1); let startTime = latestTime() + durationUtil.days(1); - const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: account_polymath}); + await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); + const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); let log = tx.logs[0]; assert.equal(log.args._beneficiary, account_beneficiary1); @@ -68,6 +69,13 @@ contract('VestingEscrowWallet', accounts => { assert.equal(log.args._duration, duration); assert.equal(log.args._frequency, frequency); assert.equal(log.args._startTime, startTime); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1, {from: wallet_owner}); + assert.equal(scheduleCount, 1); + + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0, {from: wallet_owner}); + console.log("=========================================="); + console.log(schedule); }); From bafb54029ebd4dc3b454b097a1101ff748d93923 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Thu, 15 Nov 2018 19:58:07 +0200 Subject: [PATCH 13/93] tests for adding and revoking schedules --- test/z_vesting_escrow_wallet.js | 125 +++++++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 12 deletions(-) diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index c37a9eb29..231441a80 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -10,6 +10,10 @@ const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); contract('VestingEscrowWallet', accounts => { + const CREATED = 0; + const STARTED = 1; + const COMPLETED = 2; + // Accounts Variable declaration let account_polymath; let wallet_owner; @@ -52,9 +56,30 @@ contract('VestingEscrowWallet', accounts => { `); }); - describe("Adding Vesting Schedule", async () => { - - it("Should add Vesting Schedule to the beneficiary address", async () => { + describe("Adding and Revoking Vesting Schedule", async () => { + + let schedules = [ + { + numberOfTokens: 100000, + duration: durationUtil.years(4), + frequency: durationUtil.years(1), + startTime: latestTime() + durationUtil.days(1) + }, + { + numberOfTokens: 30000, + duration: durationUtil.weeks(6), + frequency: durationUtil.weeks(1), + startTime: latestTime() + durationUtil.days(2) + }, + { + numberOfTokens: 2000, + duration: durationUtil.days(10), + frequency: durationUtil.days(2), + startTime: latestTime() + durationUtil.days(3) + } + ]; + + it("Should add Vesting Schedule to the first beneficiary address", async () => { let numberOfTokens = 100000; let duration = durationUtil.years(4); let frequency = durationUtil.years(1); @@ -64,21 +89,97 @@ contract('VestingEscrowWallet', accounts => { const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); let log = tx.logs[0]; - assert.equal(log.args._beneficiary, account_beneficiary1); - assert.equal(log.args._numberOfTokens, numberOfTokens); - assert.equal(log.args._duration, duration); - assert.equal(log.args._frequency, frequency); - assert.equal(log.args._startTime, startTime); + checkScheduleLog(log, account_beneficiary1, numberOfTokens, duration, frequency, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1, {from: wallet_owner}); - assert.equal(scheduleCount, 1); + assert.equal(scheduleCount.toNumber(), 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0, {from: wallet_owner}); - console.log("=========================================="); - console.log(schedule); + checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + }); + + it("Should revoke Vesting Schedule from the first beneficiary address", async () => { + const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_owner}); + + assert.equal(tx.logs[0].args._beneficiary, account_beneficiary1); + assert.equal(tx.logs[0].args._index, 0); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1, {from: wallet_owner}); + assert.equal(scheduleCount.toNumber(), 0); + }); + + it("Should add 3 Vesting Schedules to the second beneficiary address", async () => { + let totalNumberOfTokens = getTotalNumberOfTokens(schedules); + await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: account_treasury}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_owner}); + for (let i = 0; i < schedules.length; i++) { + let numberOfTokens = schedules[i].numberOfTokens; + let duration = schedules[i].duration; + let frequency = schedules[i].frequency; + let startTime = schedules[i].startTime; + const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary2, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + + let log = tx.logs[0]; + checkScheduleLog(log, account_beneficiary2, numberOfTokens, duration, frequency, startTime); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2, {from: wallet_owner}); + assert.equal(scheduleCount.toNumber(), i + 1); + + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, i, {from: wallet_owner}); + checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + } + }); + + it("Should revoke Vesting Schedule from the second beneficiary address", async () => { + const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary2, 1, {from: wallet_owner}); + + assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); + assert.equal(tx.logs[0].args._index, 1); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2, {from: wallet_owner}); + assert.equal(scheduleCount.toNumber(), 2); + + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, 1, {from: wallet_owner}); + checkSchedule(schedule, schedules[2].numberOfTokens, schedules[2].numberOfTokens, schedules[2].duration, schedules[2].frequency, + schedules[2].startTime, schedules[2].startTime + schedules[2].frequency, CREATED); + }); + + it("Should revoke 2 Vesting Schedules from the second beneficiary address", async () => { + const tx = await I_VestingEscrowWallet.revokeSchedules(account_beneficiary2, {from: wallet_owner}); + + assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2, {from: wallet_owner}); + assert.equal(scheduleCount.toNumber(), 0); }); }); -}); \ No newline at end of file +}); + +function checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTime) { + assert.equal(log.args._beneficiary, beneficiary); + assert.equal(log.args._numberOfTokens, numberOfTokens); + assert.equal(log.args._duration, duration); + assert.equal(log.args._frequency, frequency); + assert.equal(log.args._startTime, startTime); +} + +function checkSchedule(schedule, numberOfTokens, lockedTokens, duration, frequency, startTime, nextTime, state) { + assert.equal(schedule[0].toNumber(), numberOfTokens); + assert.equal(schedule[1].toNumber(), lockedTokens); + assert.equal(schedule[2].toNumber(), duration); + assert.equal(schedule[3].toNumber(), frequency); + assert.equal(schedule[4].toNumber(), startTime); + assert.equal(schedule[5].toNumber(), nextTime); + assert.equal(schedule[6].toNumber(), state); +} + +function getTotalNumberOfTokens(schedules) { + let numberOfTokens = 0; + for (let i = 0; i < schedules.length; i++) { + numberOfTokens += schedules[i].numberOfTokens; + } + return numberOfTokens; +} From ecc03aad940aee0cc416e56960f8eb1159b4f4ca Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Thu, 15 Nov 2018 21:56:31 +0200 Subject: [PATCH 14/93] tests for templates --- contracts/wallet/VestingEscrowWallet.sol | 17 +++- test/z_vesting_escrow_wallet.js | 124 ++++++++++++++++++----- 2 files changed, 114 insertions(+), 27 deletions(-) diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index 2d8ca803f..14fd8e272 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -122,6 +122,10 @@ contract VestingEscrowWallet is Ownable { emit RemoveTemplate(_index, now); } + function getTemplateCount() external onlyOwner returns(uint256) { + return templates.length; + } + function addSchedule( address _beneficiary, uint256 _numberOfTokens, @@ -175,7 +179,7 @@ contract VestingEscrowWallet is Ownable { require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); Schedule storage schedule = dataMap[_beneficiary].schedules[_index]; /*solium-disable-next-line security/no-block-members*/ - require(schedule.startTime < now, "It's not possible to edit the started schedule"); + require(now < schedule.startTime, "It's not possible to edit the started schedule"); if (_numberOfTokens <= schedule.lockedTokens) { unassignedTokens = unassignedTokens.add(schedule.lockedTokens - _numberOfTokens); } else { @@ -217,7 +221,7 @@ contract VestingEscrowWallet is Ownable { emit RevokeSchedules(_beneficiary, now); } - function getSchedule(address _beneficiary, uint256 _index) external view onlyOwner returns(uint256, uint256, uint256, uint256, uint256, uint256, State) { + function getSchedule(address _beneficiary, uint256 _index) external view returns(uint256, uint256, uint256, uint256, uint256, uint256, State) { require(_beneficiary != address(0), "Invalid beneficiary address"); require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); Schedule storage schedule = dataMap[_beneficiary].schedules[_index]; @@ -232,11 +236,16 @@ contract VestingEscrowWallet is Ownable { ); } - function getScheduleCount(address _beneficiary) external view onlyOwner returns(uint256) { + function getScheduleCount(address _beneficiary) external view returns(uint256) { require(_beneficiary != address(0), "Invalid beneficiary address"); return dataMap[_beneficiary].schedules.length; } + function getAvailableTokens(address _beneficiary) external view returns(uint256) { + require(_beneficiary != address(0), "Invalid beneficiary address"); + return dataMap[_beneficiary].availableTokens; + } + function batchSendAvailableTokens(address[] _beneficiaries) external onlyOwner { for (uint256 i = 0; i < _beneficiaries.length; i++) { sendAvailableTokens(_beneficiaries[i]); @@ -290,7 +299,7 @@ contract VestingEscrowWallet is Ownable { function _validateSchedule(address _beneficiary, uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, uint256 _startTime) private view { require(_beneficiary != address(0), "Invalid beneficiary address"); _validateTemplate(_numberOfTokens, _duration, _frequency); - require(_startTime > now, "Start date shouldn't be in the past"); + require(now < _startTime, "Start date shouldn't be in the past"); } function _validateTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) private pure { diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 231441a80..281b9b9b2 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -1,6 +1,7 @@ import {deployPolyRegistryAndPolyToken, deployVestingEscrowWallet} from "./helpers/createInstances"; import latestTime from "./helpers/latestTime"; import {duration as durationUtil} from "./helpers/utils"; +import {catchRevert} from "./helpers/exceptions"; const VestingEscrowWallet = artifacts.require('./VestingEscrowWallet.sol'); @@ -56,7 +57,7 @@ contract('VestingEscrowWallet', accounts => { `); }); - describe("Adding and Revoking Vesting Schedule", async () => { + describe("Adding, Editing and Revoking Vesting Schedule", async () => { let schedules = [ { @@ -80,10 +81,10 @@ contract('VestingEscrowWallet', accounts => { ]; it("Should add Vesting Schedule to the first beneficiary address", async () => { - let numberOfTokens = 100000; - let duration = durationUtil.years(4); - let frequency = durationUtil.years(1); - let startTime = latestTime() + durationUtil.days(1); + let numberOfTokens = schedules[0].numberOfTokens; + let duration = schedules[0].duration; + let frequency = schedules[0].frequency; + let startTime = schedules[0].startTime; await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); @@ -91,21 +92,51 @@ contract('VestingEscrowWallet', accounts => { let log = tx.logs[0]; checkScheduleLog(log, account_beneficiary1, numberOfTokens, duration, frequency, startTime); - let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1, {from: wallet_owner}); - assert.equal(scheduleCount.toNumber(), 1); + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); + assert.equal(scheduleCount, 1); - let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0, {from: wallet_owner}); + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); }); + it("Should edit Vesting Schedule to the first beneficiary address", async () => { + let numberOfTokens = schedules[1].numberOfTokens; + let duration = schedules[1].duration; + let frequency = schedules[1].frequency; + let startTime = schedules[1].startTime; + const tx = await I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + + let log = tx.logs[0]; + checkScheduleLog(log, account_beneficiary1, numberOfTokens, duration, frequency, startTime); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); + assert.equal(scheduleCount, 1); + + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); + checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + assert.equal(unassignedTokens, schedules[0].numberOfTokens - schedules[1].numberOfTokens); + }); + + it("Should fail edit Vesting Schedule to the first beneficiary address", async () => { + let numberOfTokens = schedules[0].numberOfTokens + schedules[1].numberOfTokens; + let duration = schedules[0].duration; + let frequency = schedules[0].frequency; + let startTime = schedules[0].startTime; + await catchRevert( + I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}) + ); + }); + it("Should revoke Vesting Schedule from the first beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_owner}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary1); assert.equal(tx.logs[0].args._index, 0); - let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1, {from: wallet_owner}); - assert.equal(scheduleCount.toNumber(), 0); + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); + assert.equal(scheduleCount, 0); }); it("Should add 3 Vesting Schedules to the second beneficiary address", async () => { @@ -122,10 +153,10 @@ contract('VestingEscrowWallet', accounts => { let log = tx.logs[0]; checkScheduleLog(log, account_beneficiary2, numberOfTokens, duration, frequency, startTime); - let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2, {from: wallet_owner}); - assert.equal(scheduleCount.toNumber(), i + 1); + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2); + assert.equal(scheduleCount, i + 1); - let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, i, {from: wallet_owner}); + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, i); checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); } }); @@ -136,10 +167,10 @@ contract('VestingEscrowWallet', accounts => { assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); assert.equal(tx.logs[0].args._index, 1); - let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2, {from: wallet_owner}); - assert.equal(scheduleCount.toNumber(), 2); + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2); + assert.equal(scheduleCount, 2); - let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, 1, {from: wallet_owner}); + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, 1); checkSchedule(schedule, schedules[2].numberOfTokens, schedules[2].numberOfTokens, schedules[2].duration, schedules[2].frequency, schedules[2].startTime, schedules[2].startTime + schedules[2].frequency, CREATED); }); @@ -149,10 +180,57 @@ contract('VestingEscrowWallet', accounts => { assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); - let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2, {from: wallet_owner}); - assert.equal(scheduleCount.toNumber(), 0); + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2); + assert.equal(scheduleCount, 0); + }); + + it("Should add 3 Templates", async () => { + for (let i = 0; i < schedules.length; i++) { + let numberOfTokens = schedules[i].numberOfTokens; + let duration = schedules[i].duration; + let frequency = schedules[i].frequency; + const tx = await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_owner}); + + assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); + assert.equal(tx.logs[0].args._duration.toNumber(), duration); + assert.equal(tx.logs[0].args._frequency.toNumber(), frequency); + } + }); + + it("Should remove first Template", async () => { + const tx = await I_VestingEscrowWallet.removeTemplate(1, {from: wallet_owner}); + + assert.equal(tx.logs[0].args._index, 1); + }); + + it("Should add Vesting Schedule from Template", async () => { + let numberOfTokens = schedules[2].numberOfTokens; + let duration = schedules[2].duration; + let frequency = schedules[2].frequency; + let startTime = schedules[2].startTime; + await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); + const tx = await I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 1, startTime, {from: wallet_owner}); + + let log = tx.logs[0]; + checkScheduleLog(log, account_beneficiary1, numberOfTokens, duration, frequency, startTime); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); + assert.equal(scheduleCount, 1); + + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); + checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + + await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_owner}); }); + it("Should remove 2 Templates", async () => { + await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_owner}); + await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_owner}); + + let templateCount = await I_VestingEscrowWallet.getTemplateCount.call({from: wallet_owner}); + assert.equal(templateCount, 0); + }); }); @@ -160,10 +238,10 @@ contract('VestingEscrowWallet', accounts => { function checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTime) { assert.equal(log.args._beneficiary, beneficiary); - assert.equal(log.args._numberOfTokens, numberOfTokens); - assert.equal(log.args._duration, duration); - assert.equal(log.args._frequency, frequency); - assert.equal(log.args._startTime, startTime); + assert.equal(log.args._numberOfTokens.toNumber(), numberOfTokens); + assert.equal(log.args._duration.toNumber(), duration); + assert.equal(log.args._frequency.toNumber(), frequency); + assert.equal(log.args._startTime.toNumber(), startTime); } function checkSchedule(schedule, numberOfTokens, lockedTokens, duration, frequency, startTime, nextTime, state) { @@ -173,7 +251,7 @@ function checkSchedule(schedule, numberOfTokens, lockedTokens, duration, frequen assert.equal(schedule[3].toNumber(), frequency); assert.equal(schedule[4].toNumber(), startTime); assert.equal(schedule[5].toNumber(), nextTime); - assert.equal(schedule[6].toNumber(), state); + assert.equal(schedule[6], state); } function getTotalNumberOfTokens(schedules) { From 59c422650c1765f8472a1a5047a1481bb7128c57 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Fri, 16 Nov 2018 15:28:46 +0200 Subject: [PATCH 15/93] tests for depositing and withdrawing tokens --- contracts/wallet/VestingEscrowWallet.sol | 2 +- test/z_vesting_escrow_wallet.js | 50 +++++++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index 14fd8e272..a88aa9dab 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -122,7 +122,7 @@ contract VestingEscrowWallet is Ownable { emit RemoveTemplate(_index, now); } - function getTemplateCount() external onlyOwner returns(uint256) { + function getTemplateCount() external view onlyOwner returns(uint256) { return templates.length; } diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 281b9b9b2..1f94b63c4 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -57,6 +57,54 @@ contract('VestingEscrowWallet', accounts => { `); }); + describe("Depositing and withdrawing tokens", async () => { + + it("Should deposit tokens for new Vesting Schedules", async () => { + let numberOfTokens = 25000; + await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); + const tx = await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); + + assert.equal(tx.logs[0].args._numberOfTokens, numberOfTokens); + + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + assert.equal(unassignedTokens, numberOfTokens); + + let balance = await I_PolyToken.balanceOf.call(I_VestingEscrowWallet.address); + assert.equal(balance.toNumber(), numberOfTokens); + }); + + it("Should withdraw tokens to a treasury", async () => { + let numberOfTokens = 25000; + const tx = await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + + assert.equal(tx.logs[0].args._numberOfTokens, numberOfTokens); + + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + assert.equal(unassignedTokens, 0); + + let balance = await I_PolyToken.balanceOf.call(I_VestingEscrowWallet.address); + assert.equal(balance.toNumber(), 0); + }); + + it("Should send tokens to the third beneficiary address", async () => { + let numberOfTokens = 75000; + let duration = durationUtil.seconds(3); + let frequency = durationUtil.seconds(1); + let startTime = latestTime() + durationUtil.seconds(10); + await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); + await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + + const tx = await I_VestingEscrowWallet.sendAvailableTokens(account_beneficiary3, {from: wallet_owner}); + assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); + assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens / 3); + + let balance = await I_PolyToken.balanceOf.call(account_beneficiary3); + assert.equal(balance.toNumber(), numberOfTokens / 3); + }); + + }); + describe("Adding, Editing and Revoking Vesting Schedule", async () => { let schedules = [ @@ -116,7 +164,7 @@ contract('VestingEscrowWallet', accounts => { checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); - assert.equal(unassignedTokens, schedules[0].numberOfTokens - schedules[1].numberOfTokens); + assert.equal(unassignedTokens.toNumber(), schedules[0].numberOfTokens - schedules[1].numberOfTokens); }); it("Should fail edit Vesting Schedule to the first beneficiary address", async () => { From fb9b15ee5046d13dee9e8f677c5a2ad7af6a1668 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Fri, 16 Nov 2018 19:38:53 +0200 Subject: [PATCH 16/93] fixed depositing/withdrawing tests --- contracts/wallet/VestingEscrowWallet.sol | 10 +++- test/z_vesting_escrow_wallet.js | 62 +++++++++++++++++++----- 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index a88aa9dab..0603fa600 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -94,12 +94,10 @@ contract VestingEscrowWallet is Ownable { } function sendAvailableTokens(address _beneficiary) public onlyOwner { - _update(_beneficiary); _sendTokens(_beneficiary); } function withdrawAvailableTokens() external { - _update(msg.sender); _sendTokens(msg.sender); } @@ -320,6 +318,10 @@ contract VestingEscrowWallet is Ownable { emit SendTokens(_beneficiary, amount, now); } + function update(address _beneficiary) external onlyOwner { + _update(_beneficiary); + } + function _update(address _beneficiary) private { Data storage data = dataMap[_beneficiary]; for (uint256 i = 0; i < data.schedules.length; i++) { @@ -340,6 +342,10 @@ contract VestingEscrowWallet is Ownable { } } + function updateAll() external onlyOwner { + _updateAll(); + } + function _updateAll() private { for (uint256 i = 0; i < beneficiaries.length; i++) { _update(beneficiaries[i]); diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 1f94b63c4..741d06a92 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -2,6 +2,7 @@ import {deployPolyRegistryAndPolyToken, deployVestingEscrowWallet} from "./helpe import latestTime from "./helpers/latestTime"; import {duration as durationUtil} from "./helpers/utils"; import {catchRevert} from "./helpers/exceptions"; +import {increaseTime} from "./helpers/time"; const VestingEscrowWallet = artifacts.require('./VestingEscrowWallet.sol'); @@ -9,6 +10,9 @@ const Web3 = require('web3'); const BigNumber = require('bignumber.js'); const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));// Hardcoded development port +//TODO check withdraw with 3 schedules and few passed steps for beneficiary +//TODO tests for batch operations +//TODO negative cases contract('VestingEscrowWallet', accounts => { const CREATED = 0; @@ -86,14 +90,17 @@ contract('VestingEscrowWallet', accounts => { assert.equal(balance.toNumber(), 0); }); - it("Should send tokens to the third beneficiary address", async () => { + it("Should send available tokens to the beneficiary address", async () => { let numberOfTokens = 75000; - let duration = durationUtil.seconds(3); - let frequency = durationUtil.seconds(1); - let startTime = latestTime() + durationUtil.seconds(10); + let duration = durationUtil.seconds(30); + let frequency = durationUtil.seconds(10); + let timeShift = durationUtil.seconds(100); + let startTime = latestTime() + timeShift; await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + await increaseTime(timeShift + frequency); + await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); const tx = await I_VestingEscrowWallet.sendAvailableTokens(account_beneficiary3, {from: wallet_owner}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); @@ -101,6 +108,37 @@ contract('VestingEscrowWallet', accounts => { let balance = await I_PolyToken.balanceOf.call(account_beneficiary3); assert.equal(balance.toNumber(), numberOfTokens / 3); + + await I_PolyToken.transfer(account_treasury, balance, {from: account_beneficiary3}); + await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_owner}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + }); + + it("Should withdraw available tokens to the beneficiary address", async () => { + let numberOfTokens = 33000; + let duration = durationUtil.seconds(30); + let frequency = durationUtil.seconds(10); + let timeShift = durationUtil.seconds(100); + let startTime = latestTime() + timeShift; + await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); + await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + await increaseTime(timeShift + frequency * 3); + await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); + await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); + await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); + await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); + + const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); + assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); + assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); + + let balance = await I_PolyToken.balanceOf.call(account_beneficiary3); + assert.equal(balance.toNumber(), numberOfTokens); + + await I_PolyToken.transfer(account_treasury, balance, {from: account_beneficiary3}); + await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_owner}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); }); }); @@ -128,7 +166,7 @@ contract('VestingEscrowWallet', accounts => { } ]; - it("Should add Vesting Schedule to the first beneficiary address", async () => { + it("Should add Vesting Schedule to the beneficiary address", async () => { let numberOfTokens = schedules[0].numberOfTokens; let duration = schedules[0].duration; let frequency = schedules[0].frequency; @@ -147,7 +185,7 @@ contract('VestingEscrowWallet', accounts => { checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); }); - it("Should edit Vesting Schedule to the first beneficiary address", async () => { + it("Should edit Vesting Schedule to the beneficiary address", async () => { let numberOfTokens = schedules[1].numberOfTokens; let duration = schedules[1].duration; let frequency = schedules[1].frequency; @@ -167,7 +205,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(unassignedTokens.toNumber(), schedules[0].numberOfTokens - schedules[1].numberOfTokens); }); - it("Should fail edit Vesting Schedule to the first beneficiary address", async () => { + it("Should fail edit Vesting Schedule to the beneficiary address", async () => { let numberOfTokens = schedules[0].numberOfTokens + schedules[1].numberOfTokens; let duration = schedules[0].duration; let frequency = schedules[0].frequency; @@ -177,7 +215,7 @@ contract('VestingEscrowWallet', accounts => { ); }); - it("Should revoke Vesting Schedule from the first beneficiary address", async () => { + it("Should revoke Vesting Schedule from the beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_owner}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary1); @@ -187,7 +225,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 0); }); - it("Should add 3 Vesting Schedules to the second beneficiary address", async () => { + it("Should add 3 Vesting Schedules to the beneficiary address", async () => { let totalNumberOfTokens = getTotalNumberOfTokens(schedules); await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: account_treasury}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_owner}); @@ -209,7 +247,7 @@ contract('VestingEscrowWallet', accounts => { } }); - it("Should revoke Vesting Schedule from the second beneficiary address", async () => { + it("Should revoke Vesting Schedule from the beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary2, 1, {from: wallet_owner}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); @@ -223,7 +261,7 @@ contract('VestingEscrowWallet', accounts => { schedules[2].startTime, schedules[2].startTime + schedules[2].frequency, CREATED); }); - it("Should revoke 2 Vesting Schedules from the second beneficiary address", async () => { + it("Should revoke 2 Vesting Schedules from the beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeSchedules(account_beneficiary2, {from: wallet_owner}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); @@ -245,7 +283,7 @@ contract('VestingEscrowWallet', accounts => { } }); - it("Should remove first Template", async () => { + it("Should remove template", async () => { const tx = await I_VestingEscrowWallet.removeTemplate(1, {from: wallet_owner}); assert.equal(tx.logs[0].args._index, 1); From e3b9bb3871191c31c98da2b4d336d9defb690ee5 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Mon, 19 Nov 2018 10:42:58 +0200 Subject: [PATCH 17/93] docs for public, external functions --- contracts/wallet/VestingEscrowWallet.sol | 115 ++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/wallet/VestingEscrowWallet.sol index 0603fa600..8c5d025e2 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/wallet/VestingEscrowWallet.sol @@ -8,7 +8,6 @@ import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol"; /** * @title Wallet for core vesting escrow functionality */ -//TODO add docs for public, external methods contract VestingEscrowWallet is Ownable { using SafeMath for uint256; using SafeERC20 for ERC20; @@ -77,6 +76,9 @@ contract VestingEscrowWallet is Ownable { treasury = _treasury; } + /** + * @notice Used to deposit tokens from treasury + */ function depositTokens(uint256 _numberOfTokens) external onlyOwner { require(_numberOfTokens > 0, "Number of tokens should be greater than zero"); token.safeTransferFrom(treasury, this, _numberOfTokens); @@ -85,6 +87,9 @@ contract VestingEscrowWallet is Ownable { emit DepositTokens(_numberOfTokens, now); } + /** + * @notice Sends unassigned tokens to treasury + */ function sendToTreasury() external onlyOwner { uint256 amount = unassignedTokens; unassignedTokens = 0; @@ -93,14 +98,27 @@ contract VestingEscrowWallet is Ownable { emit SendToTreasury(amount, now); } + /** + * @notice Sends available tokens to beneficiary + * @param _beneficiary beneficiary's address + */ function sendAvailableTokens(address _beneficiary) public onlyOwner { _sendTokens(_beneficiary); } + /** + * @notice Used to withdraw available tokens by beneficiary + */ function withdrawAvailableTokens() external { _sendTokens(msg.sender); } + /** + * @notice Add template + * @param _numberOfTokens number of tokens + * @param _duration vesting duration + * @param _frequency vesting frequency + */ function addTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) external onlyOwner { _validateTemplate(_numberOfTokens, _duration, _frequency); Template memory template; @@ -112,6 +130,10 @@ contract VestingEscrowWallet is Ownable { emit AddTemplate(_numberOfTokens, _duration, _frequency, now); } + /** + * @notice Removes template + * @param _index index of the template + */ function removeTemplate(uint256 _index) external onlyOwner { require(_index < templates.length, "Template not found"); templates[_index] = templates[templates.length - 1]; @@ -120,10 +142,22 @@ contract VestingEscrowWallet is Ownable { emit RemoveTemplate(_index, now); } + /** + * @notice Returns count of templates + * @return count of templates + */ function getTemplateCount() external view onlyOwner returns(uint256) { return templates.length; } + /** + * @notice Adds vesting schedules for each of beneficiary + * @param _beneficiary beneficiary's addresses + * @param _numberOfTokens number of tokens + * @param _duration vesting duration + * @param _frequency vesting frequency + * @param _startTime vesting start time + */ function addSchedule( address _beneficiary, uint256 _numberOfTokens, @@ -156,12 +190,27 @@ contract VestingEscrowWallet is Ownable { emit AddSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime, now); } + /** + * @notice Adds vesting schedules from template for each of beneficiary + * @param _beneficiary beneficiary's addresses + * @param _index index of the template + * @param _startTime vesting start time + */ function addScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startTime) public onlyOwner { require(_index < templates.length, "Template not found"); Template storage template = templates[_index]; addSchedule(_beneficiary, template.numberOfTokens, template.duration, template.frequency, _startTime); } + /** + * @notice Edits vesting schedules for each of beneficiary + * @param _beneficiary beneficiary's addresses + * @param _index index of schedule + * @param _numberOfTokens number of tokens + * @param _duration vesting duration + * @param _frequency vesting frequency + * @param _startTime vesting start time + */ function editSchedule( address _beneficiary, uint256 _index, @@ -193,6 +242,11 @@ contract VestingEscrowWallet is Ownable { emit EditSchedule(_beneficiary, _index, _numberOfTokens, _duration, _frequency, _startTime, now); } + /** + * @notice Revokes beneficiary's schedule + * @param _beneficiary beneficiary's address + * @param _index index of the schedule + */ function revokeSchedule(address _beneficiary, uint256 _index) external onlyOwner { require(_beneficiary != address(0), "Invalid beneficiary address"); require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); @@ -207,6 +261,11 @@ contract VestingEscrowWallet is Ownable { emit RevokeSchedule(_beneficiary, _index, now); } + + /** + * @notice Revokes all beneficiary's schedules + * @param _beneficiary beneficiary's address + */ function revokeSchedules(address _beneficiary) public onlyOwner { require(_beneficiary != address(0), "Invalid beneficiary address"); Data storage data = dataMap[_beneficiary]; @@ -219,6 +278,12 @@ contract VestingEscrowWallet is Ownable { emit RevokeSchedules(_beneficiary, now); } + /** + * @notice Returns beneficiary's schedule + * @param _beneficiary beneficiary's address + * @param _index index of the schedule + * @return beneficiary's schedule + */ function getSchedule(address _beneficiary, uint256 _index) external view returns(uint256, uint256, uint256, uint256, uint256, uint256, State) { require(_beneficiary != address(0), "Invalid beneficiary address"); require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); @@ -234,22 +299,44 @@ contract VestingEscrowWallet is Ownable { ); } + /** + * @notice Returns count of beneficiary's schedules + * @param _beneficiary beneficiary's address + * @return count of beneficiary's schedules + */ function getScheduleCount(address _beneficiary) external view returns(uint256) { require(_beneficiary != address(0), "Invalid beneficiary address"); return dataMap[_beneficiary].schedules.length; } + /** + * @notice Returns available tokens for beneficiary + * @param _beneficiary beneficiary's address + * @return available tokens for beneficiary + */ function getAvailableTokens(address _beneficiary) external view returns(uint256) { require(_beneficiary != address(0), "Invalid beneficiary address"); return dataMap[_beneficiary].availableTokens; } + /** + * @notice Used to bulk send available tokens for each of beneficiaries + * @param _beneficiaries array of beneficiary's addresses + */ function batchSendAvailableTokens(address[] _beneficiaries) external onlyOwner { for (uint256 i = 0; i < _beneficiaries.length; i++) { sendAvailableTokens(_beneficiaries[i]); } } + /** + * @notice Used to bulk add vesting schedules for each of beneficiaries + * @param _beneficiaries array of beneficiary's addresses + * @param _numberOfTokens number of tokens + * @param _duration vesting duration + * @param _frequency vesting frequency + * @param _startTime vesting start time + */ function batchAddSchedule( address[] _beneficiaries, uint256 _numberOfTokens, @@ -265,18 +352,37 @@ contract VestingEscrowWallet is Ownable { } } + /** + * @notice Used to bulk add vesting schedules from template for each of beneficiaries + * @param _beneficiaries array of beneficiary's addresses + * @param _index index of the template + * @param _startTime vesting start time + */ function batchAddScheduleFromTemplate(address[] _beneficiaries, uint256 _index, uint256 _startTime) public onlyOwner { for (uint256 i = 0; i < _beneficiaries.length; i++) { addScheduleFromTemplate(_beneficiaries[i], _index, _startTime); } } + /** + * @notice Used to bulk revoke vesting schedules for each of beneficiaries + * @param _beneficiaries array of beneficiary's addresses + */ function batchRevokeSchedules(address[] _beneficiaries) external onlyOwner { for (uint256 i = 0; i < _beneficiaries.length; i++) { revokeSchedules(_beneficiaries[i]); } } + /** + * @notice Used to bulk edit vesting schedules for each of beneficiaries + * @param _beneficiaries array of beneficiary's addresses + * @param _indexes array of beneficiary's indexes of schedule + * @param _numberOfTokens number of tokens + * @param _duration vesting duration + * @param _frequency vesting frequency + * @param _startTime vesting start time + */ function batchEditSchedule( address[] _beneficiaries, uint256[] _indexes, @@ -318,6 +424,10 @@ contract VestingEscrowWallet is Ownable { emit SendTokens(_beneficiary, amount, now); } + /** + * @notice manually triggers update outside for beneficiary's schedule (can be used to reduce user gas costs) + * @param _beneficiary beneficiary's address of the schedule + */ function update(address _beneficiary) external onlyOwner { _update(_beneficiary); } @@ -342,6 +452,9 @@ contract VestingEscrowWallet is Ownable { } } + /** + * @notice manually triggers update outside for all schedules (can be used to reduce user gas costs) + */ function updateAll() external onlyOwner { _updateAll(); } From af8297bd700cd65f178b22e692fdc16f99e894e9 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Mon, 19 Nov 2018 11:42:40 +0200 Subject: [PATCH 18/93] check withdraw with 3 schedules --- test/z_vesting_escrow_wallet.js | 55 ++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 741d06a92..ea0c88b45 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -10,7 +10,6 @@ const Web3 = require('web3'); const BigNumber = require('bignumber.js'); const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));// Hardcoded development port -//TODO check withdraw with 3 schedules and few passed steps for beneficiary //TODO tests for batch operations //TODO negative cases contract('VestingEscrowWallet', accounts => { @@ -124,11 +123,57 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); await increaseTime(timeShift + frequency * 3); - await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); - await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); - await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); - await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); + for (let i = 0; i < 4; i++) { + await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); + } + + const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); + assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); + assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); + let balance = await I_PolyToken.balanceOf.call(account_beneficiary3); + assert.equal(balance.toNumber(), numberOfTokens); + + await I_PolyToken.transfer(account_treasury, balance, {from: account_beneficiary3}); + await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_owner}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + }); + + it("Should withdraw available tokens by 3 schedules to the beneficiary address", async () => { + let schedules = [ + { + numberOfTokens: 100000, + duration: durationUtil.seconds(4), + frequency: durationUtil.seconds(1) + }, + { + numberOfTokens: 30000, + duration: durationUtil.seconds(6), + frequency: durationUtil.seconds(1) + }, + { + numberOfTokens: 2000, + duration: durationUtil.seconds(10), + frequency: durationUtil.seconds(1) + } + ]; + + let totalNumberOfTokens = getTotalNumberOfTokens(schedules); + await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: account_treasury}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_owner}); + for (let i = 0; i < schedules.length; i++) { + let numberOfTokens = schedules[i].numberOfTokens; + let duration = schedules[i].duration; + let frequency = schedules[i].frequency; + let startTime = latestTime() + durationUtil.seconds(100); + await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + } + await increaseTime(durationUtil.minutes(5)); + let stepCount = 4; + for (let i = 0; i < stepCount; i++) { + await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); + } + let numberOfTokens = 100000 + (30000 / 6 * stepCount) + (2000 / 10 * stepCount); const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); From e9b0566697963fcd17b5f92ab79473906f67c40e Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Mon, 19 Nov 2018 14:49:06 +0200 Subject: [PATCH 19/93] Tests for batch operations --- test/z_vesting_escrow_wallet.js | 146 ++++++++++++++++++++++++++++++-- 1 file changed, 141 insertions(+), 5 deletions(-) diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index ea0c88b45..64eae8ce2 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -25,6 +25,9 @@ contract('VestingEscrowWallet', accounts => { let account_beneficiary1; let account_beneficiary2; let account_beneficiary3; + let account_beneficiary4; + + let beneficiaries; let message = "Transaction Should Fail!"; @@ -39,9 +42,16 @@ contract('VestingEscrowWallet', accounts => { wallet_owner = accounts[1]; account_treasury = accounts[2]; - account_beneficiary1 = accounts[7]; - account_beneficiary2 = accounts[8]; - account_beneficiary3 = accounts[9]; + account_beneficiary1 = accounts[6]; + account_beneficiary2 = accounts[7]; + account_beneficiary3 = accounts[8]; + account_beneficiary4 = accounts[9]; + + beneficiaries = [ + account_beneficiary1, + account_beneficiary2, + account_beneficiary3 + ]; // Step 1: Deploy the PolyToken [I_PolymathRegistry, I_PolyToken] = await deployPolyRegistryAndPolyToken(account_polymath, account_treasury); @@ -230,7 +240,7 @@ contract('VestingEscrowWallet', accounts => { checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); }); - it("Should edit Vesting Schedule to the beneficiary address", async () => { + it("Should edit Vesting Schedule for the beneficiary's address", async () => { let numberOfTokens = schedules[1].numberOfTokens; let duration = schedules[1].duration; let frequency = schedules[1].frequency; @@ -262,6 +272,7 @@ contract('VestingEscrowWallet', accounts => { it("Should revoke Vesting Schedule from the beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_owner}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary1); assert.equal(tx.logs[0].args._index, 0); @@ -294,6 +305,7 @@ contract('VestingEscrowWallet', accounts => { it("Should revoke Vesting Schedule from the beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary2, 1, {from: wallet_owner}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); assert.equal(tx.logs[0].args._index, 1); @@ -308,6 +320,7 @@ contract('VestingEscrowWallet', accounts => { it("Should revoke 2 Vesting Schedules from the beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeSchedules(account_beneficiary2, {from: wallet_owner}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); @@ -334,7 +347,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(tx.logs[0].args._index, 1); }); - it("Should add Vesting Schedule from Template", async () => { + it("Should add Vesting Schedule from template", async () => { let numberOfTokens = schedules[2].numberOfTokens; let duration = schedules[2].duration; let frequency = schedules[2].frequency; @@ -353,6 +366,7 @@ contract('VestingEscrowWallet', accounts => { checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_owner}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); }); it("Should remove 2 Templates", async () => { @@ -365,6 +379,128 @@ contract('VestingEscrowWallet', accounts => { }); + describe("Tests for batch operations", async () => { + + it("Should add schedules for 3 beneficiaries", async () => { + let numberOfTokens = 30000; + let duration = durationUtil.weeks(4); + let frequency = durationUtil.weeks(1); + let startTime = latestTime() + durationUtil.seconds(100); + + let totalNumberOfTokens = numberOfTokens * 3; + await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: account_treasury}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_owner}); + + let tx = await I_VestingEscrowWallet.batchAddSchedule(beneficiaries, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + + for (let i = 0; i < beneficiaries.length; i++) { + let log = tx.logs[i]; + let beneficiary = beneficiaries[i]; + checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTime); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(beneficiary); + assert.equal(scheduleCount, 1); + + let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); + checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + } + }); + + it("Should edit Vesting Schedule for 3 beneficiary's addresses", async () => { + let numberOfTokens = 25000; + let duration = durationUtil.seconds(50); + let frequency = durationUtil.seconds(10); + let timeShift = durationUtil.seconds(100); + let startTime = latestTime() + timeShift; + + let indexes = [0, 0, 0]; + const tx = await I_VestingEscrowWallet.batchEditSchedule(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + await increaseTime(timeShift + frequency); + + for (let i = 0; i < beneficiaries.length; i++) { + let log = tx.logs[i]; + let beneficiary = beneficiaries[i]; + checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTime); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(beneficiary); + assert.equal(scheduleCount, 1); + + let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); + checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + } + + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + assert.equal(unassignedTokens.toNumber(), 5000 * beneficiaries.length); + }); + + it("Should send available tokens to the beneficiaries addresses", async () => { + for (let i = 0; i < beneficiaries.length; i++) { + let beneficiary = beneficiaries[i]; + await I_VestingEscrowWallet.update(beneficiary, {from: wallet_owner}); + } + + const tx = await I_VestingEscrowWallet.batchSendAvailableTokens(beneficiaries, {from: wallet_owner}); + + for (let i = 0; i < beneficiaries.length; i++) { + let log = tx.logs[i]; + let beneficiary = beneficiaries[i]; + assert.equal(log.args._beneficiary, beneficiary); + assert.equal(log.args._numberOfTokens.toNumber(), 5000); + + let balance = await I_PolyToken.balanceOf.call(beneficiary); + assert.equal(balance.toNumber(), 5000); + + await I_PolyToken.transfer(account_treasury, balance, {from: beneficiary}); + await I_VestingEscrowWallet.revokeSchedules(beneficiary, {from: wallet_owner}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + } + }); + + it("Should add schedules from template for 3 beneficiaries", async () => { + let numberOfTokens = 18000; + let duration = durationUtil.weeks(3); + let frequency = durationUtil.weeks(1); + let startTime = latestTime() + durationUtil.seconds(100); + + let totalNumberOfTokens = numberOfTokens * 3; + await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: account_treasury}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_owner}); + await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_owner}); + + let tx = await I_VestingEscrowWallet.batchAddScheduleFromTemplate(beneficiaries, 0, startTime, {from: wallet_owner}); + await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_owner}); + + for (let i = 0; i < beneficiaries.length; i++) { + let log = tx.logs[i]; + let beneficiary = beneficiaries[i]; + checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTime); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(beneficiary); + assert.equal(scheduleCount, 1); + + let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); + checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + } + + }); + + it("Should revoke Vesting Schedule from the 3 beneficiary's addresses", async () => { + const tx = await I_VestingEscrowWallet.batchRevokeSchedules(beneficiaries, {from: wallet_owner}); + + for (let i = 0; i < beneficiaries.length; i++) { + let log = tx.logs[i]; + let beneficiary = beneficiaries[i]; + assert.equal(log.args._beneficiary, beneficiary); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(beneficiary); + assert.equal(scheduleCount, 0); + } + + await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + }); + + }); + }); function checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTime) { From 3b6fd8911f1c031f6e958864e46c425f9f0d1ac8 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Mon, 19 Nov 2018 16:56:14 +0200 Subject: [PATCH 20/93] tests for negative cases --- test/z_vesting_escrow_wallet.js | 149 +++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 1 deletion(-) diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 64eae8ce2..b7eef2742 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -10,7 +10,6 @@ const Web3 = require('web3'); const BigNumber = require('bignumber.js'); const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));// Hardcoded development port -//TODO tests for batch operations //TODO negative cases contract('VestingEscrowWallet', accounts => { @@ -72,6 +71,12 @@ contract('VestingEscrowWallet', accounts => { describe("Depositing and withdrawing tokens", async () => { + it("Should fail to deposit zero amount of tokens", async () => { + await catchRevert( + I_VestingEscrowWallet.depositTokens(0, {from: wallet_owner}) + ); + }); + it("Should deposit tokens for new Vesting Schedules", async () => { let numberOfTokens = 25000; await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); @@ -99,6 +104,12 @@ contract('VestingEscrowWallet', accounts => { assert.equal(balance.toNumber(), 0); }); + it("Should fail to send available tokens -- fail because beneficiary doesn't have available tokens", async () => { + catchRevert( + I_VestingEscrowWallet.sendAvailableTokens(account_beneficiary3, {from: wallet_owner}) + ); + }); + it("Should send available tokens to the beneficiary address", async () => { let numberOfTokens = 75000; let duration = durationUtil.seconds(30); @@ -119,6 +130,18 @@ contract('VestingEscrowWallet', accounts => { assert.equal(balance.toNumber(), numberOfTokens / 3); await I_PolyToken.transfer(account_treasury, balance, {from: account_beneficiary3}); + }); + + it("Should fail to edit Vesting Schedule -- fail because schedule already started", async () => { + let numberOfTokens = 75000; + let duration = durationUtil.seconds(30); + let frequency = durationUtil.seconds(10); + let timeShift = durationUtil.seconds(100); + let startTime = latestTime() + timeShift; + await catchRevert( + I_VestingEscrowWallet.editSchedule(account_beneficiary3, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}) + ); + await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_owner}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); }); @@ -221,6 +244,66 @@ contract('VestingEscrowWallet', accounts => { } ]; + it("Should fail to add Vesting Schedule to the beneficiary address -- fail because not enough unassigned tokens", async () => { + await catchRevert( + I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_owner}) + ); + }); + + it("Should fail to add Vesting Schedule to the beneficiary address -- fail because address in invalid", async () => { + await catchRevert( + I_VestingEscrowWallet.addSchedule(0, 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_owner}) + ); + }); + + it("Should fail to add Vesting Schedule to the beneficiary address -- fail because start date in the past", async () => { + await catchRevert( + I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 1, latestTime() - durationUtil.days(1), {from: wallet_owner}) + ); + }); + + it("Should fail to add Vesting Schedule to the beneficiary address -- fail because number of tokens is 0", async () => { + await catchRevert( + I_VestingEscrowWallet.addSchedule(account_beneficiary1, 0, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_owner}) + ); + }); + + it("Should fail to add Vesting Schedule to the beneficiary address -- fail because duration can't be divided entirely by frequency", async () => { + await catchRevert( + I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 3, latestTime() + durationUtil.days(1), {from: wallet_owner}) + ); + }); + + it("Should fail to add Vesting Schedule to the beneficiary address -- fail because number of tokens can't be divided entirely by period count", async () => { + await catchRevert( + I_VestingEscrowWallet.addSchedule(account_beneficiary1, 5, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_owner}) + ); + }); + + it("Should fail to get Vesting Schedule -- fail because address is invalid", async () => { + await catchRevert( + I_VestingEscrowWallet.getSchedule(0, 0) + ); + }); + + it("Should fail to get Vesting Schedule -- fail because schedule not found", async () => { + await catchRevert( + I_VestingEscrowWallet.getSchedule(account_beneficiary1, 0) + ); + }); + + it("Should fail to get count of Vesting Schedule -- fail because address is invalid", async () => { + await catchRevert( + I_VestingEscrowWallet.getScheduleCount(0) + ); + }); + + it("Should fail to get available tokens -- fail because address is invalid", async () => { + await catchRevert( + I_VestingEscrowWallet.getAvailableTokens(0) + ); + }); + it("Should add Vesting Schedule to the beneficiary address", async () => { let numberOfTokens = schedules[0].numberOfTokens; let duration = schedules[0].duration; @@ -240,6 +323,26 @@ contract('VestingEscrowWallet', accounts => { checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); }); + it("Should fail to edit Vesting Schedule -- fail because schedule not found", async () => { + let numberOfTokens = schedules[0].numberOfTokens; + let duration = schedules[0].duration; + let frequency = schedules[0].frequency; + let startTime = schedules[0].startTime; + await catchRevert( + I_VestingEscrowWallet.editSchedule(account_beneficiary1, 1, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}) + ); + }); + + it("Should fail to edit Vesting Schedule -- fail because not enough unassigned tokens", async () => { + let numberOfTokens = schedules[0].numberOfTokens * 2; + let duration = schedules[0].duration; + let frequency = schedules[0].frequency; + let startTime = schedules[0].startTime; + await catchRevert( + I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}) + ); + }); + it("Should edit Vesting Schedule for the beneficiary's address", async () => { let numberOfTokens = schedules[1].numberOfTokens; let duration = schedules[1].duration; @@ -270,6 +373,18 @@ contract('VestingEscrowWallet', accounts => { ); }); + it("Should fail to revoke Vesting Schedule -- fail because address is invalid", async () => { + await catchRevert( + I_VestingEscrowWallet.revokeSchedule(0, 0, {from: wallet_owner}) + ); + }); + + it("Should fail to revoke Vesting Schedule -- fail because schedule not found", async () => { + await catchRevert( + I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 1, {from: wallet_owner}) + ); + }); + it("Should revoke Vesting Schedule from the beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_owner}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); @@ -281,6 +396,12 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 0); }); + it("Should fail to revoke Vesting Schedules -- fail because address is invalid", async () => { + await catchRevert( + I_VestingEscrowWallet.revokeSchedules(0, {from: wallet_owner}) + ); + }); + it("Should add 3 Vesting Schedules to the beneficiary address", async () => { let totalNumberOfTokens = getTotalNumberOfTokens(schedules); await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: account_treasury}); @@ -347,6 +468,13 @@ contract('VestingEscrowWallet', accounts => { assert.equal(tx.logs[0].args._index, 1); }); + it("Should fail to add Vesting Schedule from template -- fail because template not found", async () => { + let startTime = schedules[2].startTime; + await catchRevert( + I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 1, startTime, {from: wallet_owner}) + ); + }); + it("Should add Vesting Schedule from template", async () => { let numberOfTokens = schedules[2].numberOfTokens; let duration = schedules[2].duration; @@ -369,6 +497,12 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); }); + it("Should fail to remove template", async () => { + await catchRevert( + I_VestingEscrowWallet.removeTemplate(2, {from: wallet_owner}) + ); + }); + it("Should remove 2 Templates", async () => { await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_owner}); await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_owner}); @@ -406,6 +540,19 @@ contract('VestingEscrowWallet', accounts => { } }); + it("Should edit Vesting Schedule for 3 beneficiary's addresses", async () => { + let numberOfTokens = 25000; + let duration = durationUtil.seconds(50); + let frequency = durationUtil.seconds(10); + let timeShift = durationUtil.seconds(100); + let startTime = latestTime() + timeShift; + + let indexes = [0, 0, 0, 0]; + await catchRevert( + I_VestingEscrowWallet.batchEditSchedule(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}) + ); + }); + it("Should edit Vesting Schedule for 3 beneficiary's addresses", async () => { let numberOfTokens = 25000; let duration = durationUtil.seconds(50); From 99750f6f9f131d1b4ee4be0ca5061cb343a8ea2a Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Tue, 20 Nov 2018 00:19:21 +0200 Subject: [PATCH 21/93] disabled tests: depositing and withdrawing tokens --- test/z_vesting_escrow_wallet.js | 92 +++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 34 deletions(-) diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index b7eef2742..a5351321d 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -10,7 +10,6 @@ const Web3 = require('web3'); const BigNumber = require('bignumber.js'); const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));// Hardcoded development port -//TODO negative cases contract('VestingEscrowWallet', accounts => { const CREATED = 0; @@ -68,7 +67,7 @@ contract('VestingEscrowWallet', accounts => { ----------------------------------------------------------------------------- `); }); - +/* describe("Depositing and withdrawing tokens", async () => { it("Should fail to deposit zero amount of tokens", async () => { @@ -77,7 +76,7 @@ contract('VestingEscrowWallet', accounts => { ); }); - it("Should deposit tokens for new Vesting Schedules", async () => { + it("Should deposit tokens for new vesting schedules", async () => { let numberOfTokens = 25000; await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); const tx = await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); @@ -132,7 +131,7 @@ contract('VestingEscrowWallet', accounts => { await I_PolyToken.transfer(account_treasury, balance, {from: account_beneficiary3}); }); - it("Should fail to edit Vesting Schedule -- fail because schedule already started", async () => { + it("Should fail to edit vesting schedule -- fail because schedule already started", async () => { let numberOfTokens = 75000; let duration = durationUtil.seconds(30); let frequency = durationUtil.seconds(10); @@ -220,8 +219,8 @@ contract('VestingEscrowWallet', accounts => { }); }); - - describe("Adding, Editing and Revoking Vesting Schedule", async () => { +*/ + describe("Adding, editing and revoking vesting schedule", async () => { let schedules = [ { @@ -244,55 +243,55 @@ contract('VestingEscrowWallet', accounts => { } ]; - it("Should fail to add Vesting Schedule to the beneficiary address -- fail because not enough unassigned tokens", async () => { + it("Should fail to add vesting schedule to the beneficiary address -- fail because not enough unassigned tokens", async () => { await catchRevert( I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_owner}) ); }); - it("Should fail to add Vesting Schedule to the beneficiary address -- fail because address in invalid", async () => { + it("Should fail to add vesting schedule to the beneficiary address -- fail because address in invalid", async () => { await catchRevert( I_VestingEscrowWallet.addSchedule(0, 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_owner}) ); }); - it("Should fail to add Vesting Schedule to the beneficiary address -- fail because start date in the past", async () => { + it("Should fail to add vesting schedule to the beneficiary address -- fail because start date in the past", async () => { await catchRevert( I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 1, latestTime() - durationUtil.days(1), {from: wallet_owner}) ); }); - it("Should fail to add Vesting Schedule to the beneficiary address -- fail because number of tokens is 0", async () => { + it("Should fail to add vesting schedule to the beneficiary address -- fail because number of tokens is 0", async () => { await catchRevert( I_VestingEscrowWallet.addSchedule(account_beneficiary1, 0, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_owner}) ); }); - it("Should fail to add Vesting Schedule to the beneficiary address -- fail because duration can't be divided entirely by frequency", async () => { + it("Should fail to add vesting schedule to the beneficiary address -- fail because duration can't be divided entirely by frequency", async () => { await catchRevert( I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 3, latestTime() + durationUtil.days(1), {from: wallet_owner}) ); }); - it("Should fail to add Vesting Schedule to the beneficiary address -- fail because number of tokens can't be divided entirely by period count", async () => { + it("Should fail to add vesting schedule to the beneficiary address -- fail because number of tokens can't be divided entirely by period count", async () => { await catchRevert( I_VestingEscrowWallet.addSchedule(account_beneficiary1, 5, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_owner}) ); }); - it("Should fail to get Vesting Schedule -- fail because address is invalid", async () => { + it("Should fail to get vesting schedule -- fail because address is invalid", async () => { await catchRevert( I_VestingEscrowWallet.getSchedule(0, 0) ); }); - it("Should fail to get Vesting Schedule -- fail because schedule not found", async () => { + it("Should fail to get vesting schedule -- fail because schedule not found", async () => { await catchRevert( I_VestingEscrowWallet.getSchedule(account_beneficiary1, 0) ); }); - it("Should fail to get count of Vesting Schedule -- fail because address is invalid", async () => { + it("Should fail to get count of vesting schedule -- fail because address is invalid", async () => { await catchRevert( I_VestingEscrowWallet.getScheduleCount(0) ); @@ -304,12 +303,12 @@ contract('VestingEscrowWallet', accounts => { ); }); - it("Should add Vesting Schedule to the beneficiary address", async () => { + it("Should add vesting schedule to the beneficiary address", async () => { let numberOfTokens = schedules[0].numberOfTokens; let duration = schedules[0].duration; let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; - await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); + await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: account_treasury}); await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); @@ -323,7 +322,7 @@ contract('VestingEscrowWallet', accounts => { checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); }); - it("Should fail to edit Vesting Schedule -- fail because schedule not found", async () => { + it("Should fail to edit vesting schedule -- fail because schedule not found", async () => { let numberOfTokens = schedules[0].numberOfTokens; let duration = schedules[0].duration; let frequency = schedules[0].frequency; @@ -333,7 +332,7 @@ contract('VestingEscrowWallet', accounts => { ); }); - it("Should fail to edit Vesting Schedule -- fail because not enough unassigned tokens", async () => { + it("Should fail to edit vesting schedule -- fail because not enough unassigned tokens", async () => { let numberOfTokens = schedules[0].numberOfTokens * 2; let duration = schedules[0].duration; let frequency = schedules[0].frequency; @@ -343,7 +342,7 @@ contract('VestingEscrowWallet', accounts => { ); }); - it("Should edit Vesting Schedule for the beneficiary's address", async () => { + it("Should edit vesting schedule for the beneficiary's address", async () => { let numberOfTokens = schedules[1].numberOfTokens; let duration = schedules[1].duration; let frequency = schedules[1].frequency; @@ -363,7 +362,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(unassignedTokens.toNumber(), schedules[0].numberOfTokens - schedules[1].numberOfTokens); }); - it("Should fail edit Vesting Schedule to the beneficiary address", async () => { + it("Should fail edit vesting schedule to the beneficiary address", async () => { let numberOfTokens = schedules[0].numberOfTokens + schedules[1].numberOfTokens; let duration = schedules[0].duration; let frequency = schedules[0].frequency; @@ -373,19 +372,19 @@ contract('VestingEscrowWallet', accounts => { ); }); - it("Should fail to revoke Vesting Schedule -- fail because address is invalid", async () => { + it("Should fail to revoke vesting schedule -- fail because address is invalid", async () => { await catchRevert( I_VestingEscrowWallet.revokeSchedule(0, 0, {from: wallet_owner}) ); }); - it("Should fail to revoke Vesting Schedule -- fail because schedule not found", async () => { + it("Should fail to revoke vesting schedule -- fail because schedule not found", async () => { await catchRevert( I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 1, {from: wallet_owner}) ); }); - it("Should revoke Vesting Schedule from the beneficiary address", async () => { + it("Should revoke vesting schedule from the beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_owner}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); @@ -396,13 +395,13 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 0); }); - it("Should fail to revoke Vesting Schedules -- fail because address is invalid", async () => { + it("Should fail to revoke vesting schedules -- fail because address is invalid", async () => { await catchRevert( I_VestingEscrowWallet.revokeSchedules(0, {from: wallet_owner}) ); }); - it("Should add 3 Vesting Schedules to the beneficiary address", async () => { + it("Should add 3 vesting schedules to the beneficiary address", async () => { let totalNumberOfTokens = getTotalNumberOfTokens(schedules); await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: account_treasury}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_owner}); @@ -424,7 +423,7 @@ contract('VestingEscrowWallet', accounts => { } }); - it("Should revoke Vesting Schedule from the beneficiary address", async () => { + it("Should revoke vesting schedule from the beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary2, 1, {from: wallet_owner}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); @@ -436,10 +435,10 @@ contract('VestingEscrowWallet', accounts => { let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, 1); checkSchedule(schedule, schedules[2].numberOfTokens, schedules[2].numberOfTokens, schedules[2].duration, schedules[2].frequency, - schedules[2].startTime, schedules[2].startTime + schedules[2].frequency, CREATED); + schedules[2].startTime, schedules[2].startTime + schedules[2].frequency, CREATED); }); - it("Should revoke 2 Vesting Schedules from the beneficiary address", async () => { + it("Should revoke 2 vesting schedules from the beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeSchedules(account_beneficiary2, {from: wallet_owner}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); @@ -449,6 +448,31 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 0); }); + }); + + describe("Adding, using and removing templates", async () => { + + let schedules = [ + { + numberOfTokens: 100000, + duration: durationUtil.years(4), + frequency: durationUtil.years(1), + startTime: latestTime() + durationUtil.days(1) + }, + { + numberOfTokens: 30000, + duration: durationUtil.weeks(6), + frequency: durationUtil.weeks(1), + startTime: latestTime() + durationUtil.days(2) + }, + { + numberOfTokens: 2000, + duration: durationUtil.days(10), + frequency: durationUtil.days(2), + startTime: latestTime() + durationUtil.days(3) + } + ]; + it("Should add 3 Templates", async () => { for (let i = 0; i < schedules.length; i++) { let numberOfTokens = schedules[i].numberOfTokens; @@ -468,14 +492,14 @@ contract('VestingEscrowWallet', accounts => { assert.equal(tx.logs[0].args._index, 1); }); - it("Should fail to add Vesting Schedule from template -- fail because template not found", async () => { + it("Should fail to add vesting schedule from template -- fail because template not found", async () => { let startTime = schedules[2].startTime; await catchRevert( I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 1, startTime, {from: wallet_owner}) ); }); - it("Should add Vesting Schedule from template", async () => { + it("Should add vesting schedule from template", async () => { let numberOfTokens = schedules[2].numberOfTokens; let duration = schedules[2].duration; let frequency = schedules[2].frequency; @@ -540,7 +564,7 @@ contract('VestingEscrowWallet', accounts => { } }); - it("Should edit Vesting Schedule for 3 beneficiary's addresses", async () => { + it("Should edit vesting schedule for 3 beneficiary's addresses", async () => { let numberOfTokens = 25000; let duration = durationUtil.seconds(50); let frequency = durationUtil.seconds(10); @@ -553,7 +577,7 @@ contract('VestingEscrowWallet', accounts => { ); }); - it("Should edit Vesting Schedule for 3 beneficiary's addresses", async () => { + it("Should edit vesting schedule for 3 beneficiary's addresses", async () => { let numberOfTokens = 25000; let duration = durationUtil.seconds(50); let frequency = durationUtil.seconds(10); @@ -631,7 +655,7 @@ contract('VestingEscrowWallet', accounts => { }); - it("Should revoke Vesting Schedule from the 3 beneficiary's addresses", async () => { + it("Should revoke vesting schedule from the 3 beneficiary's addresses", async () => { const tx = await I_VestingEscrowWallet.batchRevokeSchedules(beneficiaries, {from: wallet_owner}); for (let i = 0; i < beneficiaries.length; i++) { From 313c7d0b55494796563c409df52cc2daf4d413e1 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Tue, 20 Nov 2018 08:50:17 +0200 Subject: [PATCH 22/93] fixed "Error: Exceeds block gas limit" --- test/z_vesting_escrow_wallet.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index a5351321d..32fbfb058 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -67,7 +67,7 @@ contract('VestingEscrowWallet', accounts => { ----------------------------------------------------------------------------- `); }); -/* + describe("Depositing and withdrawing tokens", async () => { it("Should fail to deposit zero amount of tokens", async () => { @@ -173,11 +173,6 @@ contract('VestingEscrowWallet', accounts => { it("Should withdraw available tokens by 3 schedules to the beneficiary address", async () => { let schedules = [ - { - numberOfTokens: 100000, - duration: durationUtil.seconds(4), - frequency: durationUtil.seconds(1) - }, { numberOfTokens: 30000, duration: durationUtil.seconds(6), @@ -205,7 +200,7 @@ contract('VestingEscrowWallet', accounts => { for (let i = 0; i < stepCount; i++) { await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); } - let numberOfTokens = 100000 + (30000 / 6 * stepCount) + (2000 / 10 * stepCount); + let numberOfTokens = (30000 / 6 * stepCount) + (2000 / 10 * stepCount); const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); @@ -219,7 +214,7 @@ contract('VestingEscrowWallet', accounts => { }); }); -*/ + describe("Adding, editing and revoking vesting schedule", async () => { let schedules = [ From bfa6a5c5d841d15bfa19a4197299d11f29c7e7da Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Tue, 20 Nov 2018 13:05:16 +0200 Subject: [PATCH 23/93] updated VestingEscrowWallet to use it as a module --- contracts/modules/Wallet/IWallet.sol | 19 ++++ .../Wallet}/VestingEscrowWallet.sol | 88 ++++++++++++++----- .../Wallet/VestingEscrowWalletFactory.sol | 72 +++++++++++++++ 3 files changed, 157 insertions(+), 22 deletions(-) create mode 100644 contracts/modules/Wallet/IWallet.sol rename contracts/{wallet => modules/Wallet}/VestingEscrowWallet.sol (88%) create mode 100644 contracts/modules/Wallet/VestingEscrowWalletFactory.sol diff --git a/contracts/modules/Wallet/IWallet.sol b/contracts/modules/Wallet/IWallet.sol new file mode 100644 index 000000000..ea5c918d8 --- /dev/null +++ b/contracts/modules/Wallet/IWallet.sol @@ -0,0 +1,19 @@ +pragma solidity ^0.4.24; + +import "../../Pausable.sol"; +import "../Module.sol"; + +/** + * @title Interface to be implemented by all Wallet modules + * @dev abstract contract + */ +contract IWallet is Module, Pausable { + + function unpause() public onlyOwner { + super._unpause(); + } + + function pause() public onlyOwner { + super._pause(); + } +} diff --git a/contracts/wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol similarity index 88% rename from contracts/wallet/VestingEscrowWallet.sol rename to contracts/modules/Wallet/VestingEscrowWallet.sol index 8c5d025e2..4c1e757f5 100644 --- a/contracts/wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -4,14 +4,17 @@ import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol"; +import "./IWallet.sol"; /** * @title Wallet for core vesting escrow functionality */ -contract VestingEscrowWallet is Ownable { +contract VestingEscrowWallet is IWallet { using SafeMath for uint256; using SafeERC20 for ERC20; + bytes32 public constant ADMIN = "ADMIN"; + struct Schedule { uint256 numberOfTokens; uint256 lockedTokens; @@ -71,15 +74,38 @@ contract VestingEscrowWallet is Ownable { event AddTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, uint256 _timestamp); event RemoveTemplate(uint256 _index, uint256 _timestamp); - constructor(address _tokenAddress, address _treasury) public { - token = ERC20(_tokenAddress); + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + */ + constructor (address _securityToken, address _polyAddress) + public + Module(_securityToken, _polyAddress) + { + token = ERC20(_polyAddress); + } + + /** + * @notice Function used to initialize the different variables + * @param _treasury Address of the treasury + */ + function configure(address _treasury) public onlyFactory { + require(_treasury != address(0), "Invalid address"); treasury = _treasury; } + /** + * @notice This function returns the signature of the configure function + */ + function getInitFunction() public pure returns (bytes4) { + return bytes4(keccak256("configure(address)")); + } + /** * @notice Used to deposit tokens from treasury */ - function depositTokens(uint256 _numberOfTokens) external onlyOwner { + function depositTokens(uint256 _numberOfTokens) external withPerm(ADMIN) { require(_numberOfTokens > 0, "Number of tokens should be greater than zero"); token.safeTransferFrom(treasury, this, _numberOfTokens); unassignedTokens = unassignedTokens.add(_numberOfTokens); @@ -90,7 +116,7 @@ contract VestingEscrowWallet is Ownable { /** * @notice Sends unassigned tokens to treasury */ - function sendToTreasury() external onlyOwner { + function sendToTreasury() external withPerm(ADMIN) { uint256 amount = unassignedTokens; unassignedTokens = 0; token.safeTransfer(treasury, amount); @@ -102,7 +128,7 @@ contract VestingEscrowWallet is Ownable { * @notice Sends available tokens to beneficiary * @param _beneficiary beneficiary's address */ - function sendAvailableTokens(address _beneficiary) public onlyOwner { + function sendAvailableTokens(address _beneficiary) public withPerm(ADMIN) { _sendTokens(_beneficiary); } @@ -119,7 +145,7 @@ contract VestingEscrowWallet is Ownable { * @param _duration vesting duration * @param _frequency vesting frequency */ - function addTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) external onlyOwner { + function addTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) external withPerm(ADMIN) { _validateTemplate(_numberOfTokens, _duration, _frequency); Template memory template; template.numberOfTokens = _numberOfTokens; @@ -134,7 +160,7 @@ contract VestingEscrowWallet is Ownable { * @notice Removes template * @param _index index of the template */ - function removeTemplate(uint256 _index) external onlyOwner { + function removeTemplate(uint256 _index) external withPerm(ADMIN) { require(_index < templates.length, "Template not found"); templates[_index] = templates[templates.length - 1]; templates.length--; @@ -146,7 +172,7 @@ contract VestingEscrowWallet is Ownable { * @notice Returns count of templates * @return count of templates */ - function getTemplateCount() external view onlyOwner returns(uint256) { + function getTemplateCount() external view withPerm(ADMIN) returns(uint256) { return templates.length; } @@ -166,7 +192,7 @@ contract VestingEscrowWallet is Ownable { uint256 _startTime ) public - onlyOwner + withPerm(ADMIN) { _validateSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); require(_numberOfTokens <= unassignedTokens, "Wallet doesn't contain enough unassigned tokens"); @@ -196,7 +222,7 @@ contract VestingEscrowWallet is Ownable { * @param _index index of the template * @param _startTime vesting start time */ - function addScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startTime) public onlyOwner { + function addScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startTime) public withPerm(ADMIN) { require(_index < templates.length, "Template not found"); Template storage template = templates[_index]; addSchedule(_beneficiary, template.numberOfTokens, template.duration, template.frequency, _startTime); @@ -220,7 +246,7 @@ contract VestingEscrowWallet is Ownable { uint256 _startTime ) public - onlyOwner + withPerm(ADMIN) { _validateSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); @@ -247,7 +273,7 @@ contract VestingEscrowWallet is Ownable { * @param _beneficiary beneficiary's address * @param _index index of the schedule */ - function revokeSchedule(address _beneficiary, uint256 _index) external onlyOwner { + function revokeSchedule(address _beneficiary, uint256 _index) external withPerm(ADMIN) { require(_beneficiary != address(0), "Invalid beneficiary address"); require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); Schedule[] storage schedules = dataMap[_beneficiary].schedules; @@ -266,7 +292,7 @@ contract VestingEscrowWallet is Ownable { * @notice Revokes all beneficiary's schedules * @param _beneficiary beneficiary's address */ - function revokeSchedules(address _beneficiary) public onlyOwner { + function revokeSchedules(address _beneficiary) public withPerm(ADMIN) { require(_beneficiary != address(0), "Invalid beneficiary address"); Data storage data = dataMap[_beneficiary]; for (uint256 i = 0; i < data.schedules.length; i++) { @@ -323,7 +349,7 @@ contract VestingEscrowWallet is Ownable { * @notice Used to bulk send available tokens for each of beneficiaries * @param _beneficiaries array of beneficiary's addresses */ - function batchSendAvailableTokens(address[] _beneficiaries) external onlyOwner { + function batchSendAvailableTokens(address[] _beneficiaries) external withPerm(ADMIN) { for (uint256 i = 0; i < _beneficiaries.length; i++) { sendAvailableTokens(_beneficiaries[i]); } @@ -345,7 +371,7 @@ contract VestingEscrowWallet is Ownable { uint256 _startTime ) external - onlyOwner + withPerm(ADMIN) { for (uint256 i = 0; i < _beneficiaries.length; i++) { addSchedule(_beneficiaries[i], _numberOfTokens, _duration, _frequency, _startTime); @@ -358,7 +384,7 @@ contract VestingEscrowWallet is Ownable { * @param _index index of the template * @param _startTime vesting start time */ - function batchAddScheduleFromTemplate(address[] _beneficiaries, uint256 _index, uint256 _startTime) public onlyOwner { + function batchAddScheduleFromTemplate(address[] _beneficiaries, uint256 _index, uint256 _startTime) public withPerm(ADMIN) { for (uint256 i = 0; i < _beneficiaries.length; i++) { addScheduleFromTemplate(_beneficiaries[i], _index, _startTime); } @@ -368,7 +394,7 @@ contract VestingEscrowWallet is Ownable { * @notice Used to bulk revoke vesting schedules for each of beneficiaries * @param _beneficiaries array of beneficiary's addresses */ - function batchRevokeSchedules(address[] _beneficiaries) external onlyOwner { + function batchRevokeSchedules(address[] _beneficiaries) external withPerm(ADMIN) { for (uint256 i = 0; i < _beneficiaries.length; i++) { revokeSchedules(_beneficiaries[i]); } @@ -392,7 +418,7 @@ contract VestingEscrowWallet is Ownable { uint256 _startTime ) external - onlyOwner + withPerm(ADMIN) { require(_beneficiaries.length == _indexes.length, "Beneficiaries array and indexes array should have the same length"); for (uint256 i = 0; i < _beneficiaries.length; i++) { @@ -400,7 +426,16 @@ contract VestingEscrowWallet is Ownable { } } - function _validateSchedule(address _beneficiary, uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, uint256 _startTime) private view { + function _validateSchedule( + address _beneficiary, + uint256 _numberOfTokens, + uint256 _duration, + uint256 _frequency, + uint256 _startTime + ) + private + view + { require(_beneficiary != address(0), "Invalid beneficiary address"); _validateTemplate(_numberOfTokens, _duration, _frequency); require(now < _startTime, "Start date shouldn't be in the past"); @@ -428,7 +463,7 @@ contract VestingEscrowWallet is Ownable { * @notice manually triggers update outside for beneficiary's schedule (can be used to reduce user gas costs) * @param _beneficiary beneficiary's address of the schedule */ - function update(address _beneficiary) external onlyOwner { + function update(address _beneficiary) external withPerm(ADMIN) { _update(_beneficiary); } @@ -455,7 +490,7 @@ contract VestingEscrowWallet is Ownable { /** * @notice manually triggers update outside for all schedules (can be used to reduce user gas costs) */ - function updateAll() external onlyOwner { + function updateAll() external withPerm(ADMIN) { _updateAll(); } @@ -481,4 +516,13 @@ contract VestingEscrowWallet is Ownable { return (dataMap[_beneficiary].availableTokens == 0); } + /** + * @notice Return the permissions flag that are associated with VestingEscrowWallet + */ + function getPermissions() public view returns(bytes32[]) { + bytes32[] memory allPermissions = new bytes32[](1); + allPermissions[0] = ADMIN; + return allPermissions; + } + } diff --git a/contracts/modules/Wallet/VestingEscrowWalletFactory.sol b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol new file mode 100644 index 000000000..8f187251c --- /dev/null +++ b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol @@ -0,0 +1,72 @@ +pragma solidity ^0.4.24; + +import "./VestingEscrowWallet.sol"; +import "../ModuleFactory.sol"; +import "../../libraries/Util.sol"; + +/** + * @title Factory for deploying VestingEscrowWallet module + */ +contract VestingEscrowWalletFactory is ModuleFactory { + + /** + * @notice Constructor + * @param _polyAddress Address of the polytoken + */ + constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public + ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) + { + version = "1.0.0"; + name = "VestingEscrowWallet"; + title = "Vesting Escrow Wallet"; + description = "Manage vesting schedules to employees / affiliates"; + compatibleSTVersionRange["lowerBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); + compatibleSTVersionRange["upperBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); + } + + /** + * @notice Used to launch the Module with the help of factory + * _data Data used for the intialization of the module factory variables + * @return address Contract address of the Module + */ + function deploy(bytes _data) external returns(address) { + if (setupCost > 0) { + require(polyToken.transferFrom(msg.sender, owner, setupCost), "Failed transferFrom due to insufficent Allowance provided"); + } + VestingEscrowWallet vestingEscrowWallet = new VestingEscrowWallet(msg.sender, address(polyToken)); + //Checks that _data is valid (not calling anything it shouldn't) + require(Util.getSig(_data) == vestingEscrowWallet.getInitFunction(), "Invalid data"); + /*solium-disable-next-line security/no-low-level-calls*/ + require(address(vestingEscrowWallet).call(_data), "Unsuccessfull call"); + /*solium-disable-next-line security/no-block-members*/ + emit GenerateModuleFromFactory(address(vestingEscrowWallet), getName(), address(this), msg.sender, setupCost, now); + return address(vestingEscrowWallet); + } + + /** + * @notice Type of the Module factory + */ + function getTypes() external view returns(uint8[]) { + uint8[] memory res = new uint8[](1); + res[0] = 6; + return res; + } + + /** + * @notice Returns the instructions associated with the module + */ + function getInstructions() external view returns(string) { + /*solium-disable-next-line max-len*/ + return "Issuer can send tokens to and then select the address that would be able to withdraw them according to their specific vesting schedule."; + } + + /** + * @notice Get the tags related to the module factory + */ + function getTags() external view returns(bytes32[]) { + bytes32[] memory availableTags = new bytes32[](2); + availableTags[0] = "Vested Wallet"; + availableTags[1] = "Escrow"; + return availableTags; + } +} From 0e357eba06e6673b76c7297018ee9ce3edc60674 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Tue, 20 Nov 2018 14:19:08 +0200 Subject: [PATCH 24/93] updated tests for VestingEscrowWallet --- test/helpers/createInstances.js | 28 +++++++-------- test/z_vesting_escrow_wallet.js | 64 ++++++++++++++++++++++++++++----- 2 files changed, 69 insertions(+), 23 deletions(-) diff --git a/test/helpers/createInstances.js b/test/helpers/createInstances.js index 966602ba2..d31737346 100644 --- a/test/helpers/createInstances.js +++ b/test/helpers/createInstances.js @@ -30,7 +30,7 @@ const PolyTokenFaucet = artifacts.require("./PolyTokenFaucet.sol"); const DummySTOFactory = artifacts.require("./DummySTOFactory.sol"); const MockBurnFactory = artifacts.require("./MockBurnFactory.sol"); const MockWrongTypeFactory = artifacts.require("./MockWrongTypeFactory.sol"); -const VestingEscrowWallet = artifacts.require("./VestingEscrowWallet.sol"); +const VestingEscrowWalletFactory = artifacts.require("./VestingEscrowWalletFactory.sol"); const Web3 = require("web3"); const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); // Hardcoded development port @@ -51,6 +51,7 @@ let I_CountTransferManagerFactory; let I_ERC20DividendCheckpointFactory; let I_GeneralPermissionManagerFactory; let I_GeneralTransferManagerFactory; +let I_VestingEscrowWalletFactory; let I_GeneralTransferManager; let I_ModuleRegistryProxy; let I_PreSaleSTOFactory; @@ -66,7 +67,6 @@ let I_PolymathRegistry; let I_SecurityTokenRegistryProxy; let I_STRProxied; let I_MRProxied; -let I_VestingEscrowWallet; // Initial fee for ticker registry and security token registry const initRegFee = web3.utils.toWei("250"); @@ -397,6 +397,18 @@ export async function deployRedemptionAndVerifyed(accountPolymath, MRProxyInstan return new Array(I_TrackedRedemptionFactory); } +export async function deployVestingEscrowWalletAndVerifyed(accountPolymath, MRProxyInstance, polyToken, setupCost) { + I_VestingEscrowWalletFactory = await VestingEscrowWalletFactory.new(polyToken, setupCost, 0, 0, { from: accountPolymath }); + + assert.notEqual( + I_VestingEscrowWalletFactory.address.valueOf(), + "0x0000000000000000000000000000000000000000", + "VestingEscrowWalletFactory contract was not deployed" + ); + + await registerAndVerifyByMR(I_VestingEscrowWalletFactory.address, accountPolymath, MRProxyInstance); + return new Array(I_VestingEscrowWalletFactory); +} export async function deployMockRedemptionAndVerifyed(accountPolymath, MRProxyInstance, polyToken, setupCost) { I_MockBurnFactory = await MockBurnFactory.new(polyToken, setupCost, 0, 0, { from: accountPolymath }); @@ -424,18 +436,6 @@ export async function deployMockWrongTypeRedemptionAndVerifyed(accountPolymath, return new Array(I_MockWrongTypeBurnFactory); } -export async function deployVestingEscrowWallet(accountOwner, polyToken, treasury) { - I_VestingEscrowWallet = await VestingEscrowWallet.new(polyToken, treasury, { from: accountOwner }); - assert.notEqual( - I_VestingEscrowWallet.address.valueOf(), - "0x0000000000000000000000000000000000000000", - "VestingEscrowWallet contract was not deployed" - ); - - return new Array(I_VestingEscrowWallet); -} - - /// Helper function function mergeReturn(returnData) { let returnArray = new Array(); diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 32fbfb058..c3951b874 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -1,4 +1,4 @@ -import {deployPolyRegistryAndPolyToken, deployVestingEscrowWallet} from "./helpers/createInstances"; +import {deployVestingEscrowWalletAndVerifyed, setUpPolymathNetwork} from "./helpers/createInstances"; import latestTime from "./helpers/latestTime"; import {duration as durationUtil} from "./helpers/utils"; import {catchRevert} from "./helpers/exceptions"; @@ -13,8 +13,6 @@ const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); contract('VestingEscrowWallet', accounts => { const CREATED = 0; - const STARTED = 1; - const COMPLETED = 2; // Accounts Variable declaration let account_polymath; @@ -30,10 +28,39 @@ contract('VestingEscrowWallet', accounts => { let message = "Transaction Should Fail!"; // Contract Instance Declaration + let I_SecurityTokenRegistryProxy; + let I_GeneralTransferManagerFactory; + let I_ScheduledCheckpointFactory; + let I_GeneralPermissionManager; + let I_ScheduledCheckpoint; + let I_GeneralTransferManager; + let I_ModuleRegistryProxy; + let I_ModuleRegistry; + let I_FeatureRegistry; + let I_SecurityTokenRegistry; + let I_STRProxied; + let I_MRProxied; + let I_STFactory; + let I_SecurityToken; let I_VestingEscrowWallet; let I_PolyToken; let I_PolymathRegistry; + // SecurityToken Details + const name = "Team"; + const symbol = "sap"; + const tokenDetails = "This is equity type of issuance"; + const decimals = 18; + const contact = "team@polymath.network"; + + // Module key + const delegateManagerKey = 1; + const transferManagerKey = 2; + const stoKey = 3; + + // Initial fee for ticker registry and security token registry + const initRegFee = web3.utils.toWei("250"); + before(async () => { // Accounts setup account_polymath = accounts[0]; @@ -51,19 +78,38 @@ contract('VestingEscrowWallet', accounts => { account_beneficiary3 ]; - // Step 1: Deploy the PolyToken - [I_PolymathRegistry, I_PolyToken] = await deployPolyRegistryAndPolyToken(account_polymath, account_treasury); + // Step 1: Deploy the genral PM ecosystem + let instances = await setUpPolymathNetwork(account_polymath, wallet_owner); + + [ + I_PolymathRegistry, + I_PolyToken, + I_FeatureRegistry, + I_ModuleRegistry, + I_ModuleRegistryProxy, + I_MRProxied, + I_GeneralTransferManagerFactory, + I_STFactory, + I_SecurityTokenRegistry, + I_SecurityTokenRegistryProxy, + I_STRProxied + ] = instances; // STEP 2: Deploy the VestingEscrowWallet - [I_VestingEscrowWallet] = await deployVestingEscrowWallet(wallet_owner, I_PolyToken.address, account_treasury); + [I_VestingEscrowWalletFactory] = await deployVestingEscrowWalletAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- PolymathRegistry: ${I_PolymathRegistry.address} - PolyToken: ${I_PolyToken.address} - - VestingEscrowWalle: ${I_VestingEscrowWallet.address} + SecurityTokenRegistryProxy: ${I_SecurityTokenRegistryProxy.address} + SecurityTokenRegistry: ${I_SecurityTokenRegistry.address} + ModuleRegistry: ${I_ModuleRegistry.address} + ModuleRegistryProxy: ${I_ModuleRegistryProxy.address} + FeatureRegistry: ${I_FeatureRegistry.address} + + STFactory: ${I_STFactory.address} + GeneralTransferManagerFactory: ${I_GeneralTransferManagerFactory.address} ----------------------------------------------------------------------------- `); }); From 99eeaf37068abc0bee375a0ce56995ee25314022 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Tue, 20 Nov 2018 15:27:27 +0200 Subject: [PATCH 25/93] changed error messages --- .../modules/Wallet/VestingEscrowWallet.sol | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 4c1e757f5..a1b8ee07b 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -106,7 +106,7 @@ contract VestingEscrowWallet is IWallet { * @notice Used to deposit tokens from treasury */ function depositTokens(uint256 _numberOfTokens) external withPerm(ADMIN) { - require(_numberOfTokens > 0, "Number of tokens should be greater than zero"); + require(_numberOfTokens > 0, "Should be greater than zero"); token.safeTransferFrom(treasury, this, _numberOfTokens); unassignedTokens = unassignedTokens.add(_numberOfTokens); /*solium-disable-next-line security/no-block-members*/ @@ -195,7 +195,7 @@ contract VestingEscrowWallet is IWallet { withPerm(ADMIN) { _validateSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); - require(_numberOfTokens <= unassignedTokens, "Wallet doesn't contain enough unassigned tokens"); + require(_numberOfTokens <= unassignedTokens, "Not enough tokens"); Schedule memory schedule; unassignedTokens = unassignedTokens.sub(_numberOfTokens); @@ -252,11 +252,11 @@ contract VestingEscrowWallet is IWallet { require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); Schedule storage schedule = dataMap[_beneficiary].schedules[_index]; /*solium-disable-next-line security/no-block-members*/ - require(now < schedule.startTime, "It's not possible to edit the started schedule"); + require(now < schedule.startTime, "Schedule started"); if (_numberOfTokens <= schedule.lockedTokens) { unassignedTokens = unassignedTokens.add(schedule.lockedTokens - _numberOfTokens); } else { - require((_numberOfTokens - schedule.lockedTokens) <= unassignedTokens, "Wallet doesn't contain enough unassigned tokens"); + require((_numberOfTokens - schedule.lockedTokens) <= unassignedTokens, "Not enough tokens"); unassignedTokens = unassignedTokens.sub(_numberOfTokens - schedule.lockedTokens); } schedule.numberOfTokens = _numberOfTokens; @@ -293,7 +293,7 @@ contract VestingEscrowWallet is IWallet { * @param _beneficiary beneficiary's address */ function revokeSchedules(address _beneficiary) public withPerm(ADMIN) { - require(_beneficiary != address(0), "Invalid beneficiary address"); + require(_beneficiary != address(0), "Invalid address"); Data storage data = dataMap[_beneficiary]; for (uint256 i = 0; i < data.schedules.length; i++) { unassignedTokens = unassignedTokens.add(data.schedules[i].lockedTokens); @@ -311,7 +311,7 @@ contract VestingEscrowWallet is IWallet { * @return beneficiary's schedule */ function getSchedule(address _beneficiary, uint256 _index) external view returns(uint256, uint256, uint256, uint256, uint256, uint256, State) { - require(_beneficiary != address(0), "Invalid beneficiary address"); + require(_beneficiary != address(0), "Invalid address"); require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); Schedule storage schedule = dataMap[_beneficiary].schedules[_index]; return ( @@ -331,7 +331,7 @@ contract VestingEscrowWallet is IWallet { * @return count of beneficiary's schedules */ function getScheduleCount(address _beneficiary) external view returns(uint256) { - require(_beneficiary != address(0), "Invalid beneficiary address"); + require(_beneficiary != address(0), "Invalid address"); return dataMap[_beneficiary].schedules.length; } @@ -341,7 +341,7 @@ contract VestingEscrowWallet is IWallet { * @return available tokens for beneficiary */ function getAvailableTokens(address _beneficiary) external view returns(uint256) { - require(_beneficiary != address(0), "Invalid beneficiary address"); + require(_beneficiary != address(0), "Invalid address"); return dataMap[_beneficiary].availableTokens; } @@ -420,7 +420,7 @@ contract VestingEscrowWallet is IWallet { external withPerm(ADMIN) { - require(_beneficiaries.length == _indexes.length, "Beneficiaries array and indexes array should have the same length"); + require(_beneficiaries.length == _indexes.length, "Arrays sizes mismatch"); for (uint256 i = 0; i < _beneficiaries.length; i++) { editSchedule(_beneficiaries[i], _indexes[i], _numberOfTokens, _duration, _frequency, _startTime); } @@ -436,22 +436,22 @@ contract VestingEscrowWallet is IWallet { private view { - require(_beneficiary != address(0), "Invalid beneficiary address"); + require(_beneficiary != address(0), "Invalid address"); _validateTemplate(_numberOfTokens, _duration, _frequency); - require(now < _startTime, "Start date shouldn't be in the past"); + require(now < _startTime, "Date in the past"); } function _validateTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) private pure { - require(_numberOfTokens > 0, "Number of tokens should be greater than zero"); - require(_duration % _frequency == 0, "Duration should be divided entirely by frequency"); + require(_numberOfTokens > 0, "Zero amount"); + require(_duration % _frequency == 0, "Duration and frequency mismatch"); uint256 periodCount = _duration.div(_frequency); - require(_numberOfTokens % periodCount == 0, "Number of tokens should be divided entirely by period count"); + require(_numberOfTokens % periodCount == 0, "Tokens and periods mismatch"); } function _sendTokens(address _beneficiary) private { Data storage data = dataMap[_beneficiary]; uint256 amount = data.availableTokens; - require(amount > 0, "Beneficiary doesn't have available tokens"); + require(amount > 0, "No tokens"); data.availableTokens = 0; data.claimedTokens = data.claimedTokens.add(amount); token.safeTransfer(_beneficiary, amount); From a6c7b5502aedafd10b5e816ac599afdb4aaada4d Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Tue, 20 Nov 2018 17:52:00 +0200 Subject: [PATCH 26/93] Initialization of VestingEscrowWallet module in tests --- .../modules/Wallet/VestingEscrowWallet.sol | 25 +++---- .../Wallet/VestingEscrowWalletFactory.sol | 2 +- test/z_vesting_escrow_wallet.js | 69 +++++++++++++++++-- 3 files changed, 79 insertions(+), 17 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index a1b8ee07b..d20db9c6b 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -487,18 +487,19 @@ contract VestingEscrowWallet is IWallet { } } - /** - * @notice manually triggers update outside for all schedules (can be used to reduce user gas costs) - */ - function updateAll() external withPerm(ADMIN) { - _updateAll(); - } - - function _updateAll() private { - for (uint256 i = 0; i < beneficiaries.length; i++) { - _update(beneficiaries[i]); - } - } + //TODO temporally for decreasing contract size +// /** +// * @notice manually triggers update outside for all schedules (can be used to reduce user gas costs) +// */ +// function updateAll() external withPerm(ADMIN) { +// _updateAll(); +// } +// +// function _updateAll() private { +// for (uint256 i = 0; i < beneficiaries.length; i++) { +// _update(beneficiaries[i]); +// } +// } function _revokeSchedules(address _beneficiary) private { if (_canBeRemoved(_beneficiary)) { diff --git a/contracts/modules/Wallet/VestingEscrowWalletFactory.sol b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol index 8f187251c..88db1919d 100644 --- a/contracts/modules/Wallet/VestingEscrowWalletFactory.sol +++ b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol @@ -29,7 +29,7 @@ contract VestingEscrowWalletFactory is ModuleFactory { * _data Data used for the intialization of the module factory variables * @return address Contract address of the Module */ - function deploy(bytes _data) external returns(address) { + function deploy(bytes _data) external returns(address) { if (setupCost > 0) { require(polyToken.transferFrom(msg.sender, owner, setupCost), "Failed transferFrom due to insufficent Allowance provided"); } diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index c3951b874..e228dd3f2 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -1,9 +1,12 @@ import {deployVestingEscrowWalletAndVerifyed, setUpPolymathNetwork} from "./helpers/createInstances"; import latestTime from "./helpers/latestTime"; -import {duration as durationUtil} from "./helpers/utils"; +import {duration as durationUtil, latestBlock, promisifyLogWatch} from "./helpers/utils"; import {catchRevert} from "./helpers/exceptions"; import {increaseTime} from "./helpers/time"; +import {encodeModuleCall} from "./helpers/encodeCall"; +const SecurityToken = artifacts.require('./SecurityToken.sol'); +const GeneralTransferManager = artifacts.require('./GeneralTransferManager'); const VestingEscrowWallet = artifacts.require('./VestingEscrowWallet.sol'); const Web3 = require('web3'); @@ -17,6 +20,7 @@ contract('VestingEscrowWallet', accounts => { // Accounts Variable declaration let account_polymath; let wallet_owner; + let token_owner; let account_treasury; let account_beneficiary1; let account_beneficiary2; @@ -30,9 +34,9 @@ contract('VestingEscrowWallet', accounts => { // Contract Instance Declaration let I_SecurityTokenRegistryProxy; let I_GeneralTransferManagerFactory; - let I_ScheduledCheckpointFactory; + let I_VestingEscrowWalletFactory; let I_GeneralPermissionManager; - let I_ScheduledCheckpoint; + let I_VestingEscrowWallet; let I_GeneralTransferManager; let I_ModuleRegistryProxy; let I_ModuleRegistry; @@ -42,7 +46,6 @@ contract('VestingEscrowWallet', accounts => { let I_MRProxied; let I_STFactory; let I_SecurityToken; - let I_VestingEscrowWallet; let I_PolyToken; let I_PolymathRegistry; @@ -65,6 +68,7 @@ contract('VestingEscrowWallet', accounts => { // Accounts setup account_polymath = accounts[0]; wallet_owner = accounts[1]; + token_owner = wallet_owner; account_treasury = accounts[2]; account_beneficiary1 = accounts[6]; @@ -114,6 +118,63 @@ contract('VestingEscrowWallet', accounts => { `); }); + describe("Generate the SecurityToken", async() => { + + it("Should register the ticker before the generation of the security token", async () => { + await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); + let tx = await I_STRProxied.registerTicker(token_owner, symbol, contact, { from : token_owner }); + assert.equal(tx.logs[0].args._owner, token_owner); + assert.equal(tx.logs[0].args._ticker, symbol.toUpperCase()); + }); + + it("Should generate the new security token with the same symbol as registered above", async () => { + await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); + let _blockNo = latestBlock(); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); + + // Verify the successful generation of the security token + assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); + + I_SecurityToken = SecurityToken.at(tx.logs[1].args._securityTokenAddress); + + const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); + + // Verify that GeneralTransferManager module get added successfully or not + assert.equal(log.args._types[0].toNumber(), 2); + assert.equal( + web3.utils.toAscii(log.args._name) + .replace(/\u0000/g, ''), + "GeneralTransferManager" + ); + }); + + it("Should intialize the auto attached modules", async () => { + let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; + I_GeneralTransferManager = GeneralTransferManager.at(moduleData); + + }); + + it("Should successfully attach the VestingEscrowWallet with the security token", async () => { + let bytesData = encodeModuleCall( + ["address"], + [account_treasury] + ); + + await I_SecurityToken.changeGranularity(1, {from: token_owner}); + const tx = await I_SecurityToken.addModule(I_VestingEscrowWalletFactory.address, bytesData, 0, 0, { from: token_owner }); + + assert.equal(tx.logs[2].args._types[0].toNumber(), 6, "VestingEscrowWallet doesn't get deployed"); + assert.equal( + web3.utils.toAscii(tx.logs[2].args._name) + .replace(/\u0000/g, ''), + "VestingEscrowWallet", + "VestingEscrowWallet module was not added" + ); + I_VestingEscrowWallet = VestingEscrowWallet.at(tx.logs[2].args._module); + }); + + }); + describe("Depositing and withdrawing tokens", async () => { it("Should fail to deposit zero amount of tokens", async () => { From d28da6f2ba768390098f678e0a7bb9fc225bcb74 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 21 Nov 2018 10:51:35 +0200 Subject: [PATCH 27/93] fixed tests --- test/z_vesting_escrow_wallet.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index e228dd3f2..776e48bec 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -68,8 +68,8 @@ contract('VestingEscrowWallet', accounts => { // Accounts setup account_polymath = accounts[0]; wallet_owner = accounts[1]; - token_owner = wallet_owner; - account_treasury = accounts[2]; + token_owner = accounts[1]; + account_treasury = accounts[1]; account_beneficiary1 = accounts[6]; account_beneficiary2 = accounts[7]; @@ -83,7 +83,7 @@ contract('VestingEscrowWallet', accounts => { ]; // Step 1: Deploy the genral PM ecosystem - let instances = await setUpPolymathNetwork(account_polymath, wallet_owner); + let instances = await setUpPolymathNetwork(account_polymath, token_owner); [ I_PolymathRegistry, @@ -114,6 +114,8 @@ contract('VestingEscrowWallet', accounts => { STFactory: ${I_STFactory.address} GeneralTransferManagerFactory: ${I_GeneralTransferManagerFactory.address} + + I_VestingEscrowWalletFactory: ${I_VestingEscrowWalletFactory.address} ----------------------------------------------------------------------------- `); }); From a361ffec7566fcb94cb2bafd974c0767595a0a41 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 21 Nov 2018 11:24:33 +0200 Subject: [PATCH 28/93] use delegate instead of owner in tests --- test/z_vesting_escrow_wallet.js | 210 ++++++++++++++++++-------------- 1 file changed, 121 insertions(+), 89 deletions(-) diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 776e48bec..e53d4a40a 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -1,4 +1,4 @@ -import {deployVestingEscrowWalletAndVerifyed, setUpPolymathNetwork} from "./helpers/createInstances"; +import {setUpPolymathNetwork, deployGPMAndVerifyed, deployVestingEscrowWalletAndVerifyed} from "./helpers/createInstances"; import latestTime from "./helpers/latestTime"; import {duration as durationUtil, latestBlock, promisifyLogWatch} from "./helpers/utils"; import {catchRevert} from "./helpers/exceptions"; @@ -7,6 +7,7 @@ import {encodeModuleCall} from "./helpers/encodeCall"; const SecurityToken = artifacts.require('./SecurityToken.sol'); const GeneralTransferManager = artifacts.require('./GeneralTransferManager'); +const GeneralPermissionManager = artifacts.require("./GeneralPermissionManager"); const VestingEscrowWallet = artifacts.require('./VestingEscrowWallet.sol'); const Web3 = require('web3'); @@ -19,9 +20,8 @@ contract('VestingEscrowWallet', accounts => { // Accounts Variable declaration let account_polymath; - let wallet_owner; let token_owner; - let account_treasury; + let wallet_admin; let account_beneficiary1; let account_beneficiary2; let account_beneficiary3; @@ -33,6 +33,7 @@ contract('VestingEscrowWallet', accounts => { // Contract Instance Declaration let I_SecurityTokenRegistryProxy; + let I_GeneralPermissionManagerFactory; let I_GeneralTransferManagerFactory; let I_VestingEscrowWalletFactory; let I_GeneralPermissionManager; @@ -55,6 +56,7 @@ contract('VestingEscrowWallet', accounts => { const tokenDetails = "This is equity type of issuance"; const decimals = 18; const contact = "team@polymath.network"; + const delegateDetails = "Hello I am legit delegate"; // Module key const delegateManagerKey = 1; @@ -67,9 +69,8 @@ contract('VestingEscrowWallet', accounts => { before(async () => { // Accounts setup account_polymath = accounts[0]; - wallet_owner = accounts[1]; token_owner = accounts[1]; - account_treasury = accounts[1]; + wallet_admin = accounts[2]; account_beneficiary1 = accounts[6]; account_beneficiary2 = accounts[7]; @@ -99,7 +100,10 @@ contract('VestingEscrowWallet', accounts => { I_STRProxied ] = instances; - // STEP 2: Deploy the VestingEscrowWallet + // STEP 2: Deploy the GeneralDelegateManagerFactory + [I_GeneralPermissionManagerFactory] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); + + // STEP 3: Deploy the VestingEscrowWallet [I_VestingEscrowWalletFactory] = await deployVestingEscrowWalletAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); // Printing all the contract addresses @@ -114,6 +118,7 @@ contract('VestingEscrowWallet', accounts => { STFactory: ${I_STFactory.address} GeneralTransferManagerFactory: ${I_GeneralTransferManagerFactory.address} + GeneralPermissionManagerFactory: ${I_GeneralPermissionManagerFactory.address} I_VestingEscrowWalletFactory: ${I_VestingEscrowWalletFactory.address} ----------------------------------------------------------------------------- @@ -156,10 +161,21 @@ contract('VestingEscrowWallet', accounts => { }); + it("Should successfully attach the General permission manager factory with the security token", async () => { + const tx = await I_SecurityToken.addModule(I_GeneralPermissionManagerFactory.address, "0x", 0, 0, { from: token_owner }); + assert.equal(tx.logs[2].args._types[0].toNumber(), delegateManagerKey, "General Permission Manager doesn't get deployed"); + assert.equal( + web3.utils.toAscii(tx.logs[2].args._name).replace(/\u0000/g, ""), + "GeneralPermissionManager", + "GeneralPermissionManagerFactory module was not added" + ); + I_GeneralPermissionManager = GeneralPermissionManager.at(tx.logs[2].args._module); + }); + it("Should successfully attach the VestingEscrowWallet with the security token", async () => { let bytesData = encodeModuleCall( ["address"], - [account_treasury] + [token_owner] ); await I_SecurityToken.changeGranularity(1, {from: token_owner}); @@ -175,20 +191,36 @@ contract('VestingEscrowWallet', accounts => { I_VestingEscrowWallet = VestingEscrowWallet.at(tx.logs[2].args._module); }); + it("Should successfully add the delegate", async() => { + let tx = await I_GeneralPermissionManager.addDelegate(wallet_admin, delegateDetails, { from: token_owner}); + assert.equal(tx.logs[0].args._delegate, wallet_admin); + }); + + it("Should provide the permission", async() => { + let tx = await I_GeneralPermissionManager.changePermission( + wallet_admin, + I_VestingEscrowWallet.address, + "ADMIN", + true, + {from: token_owner} + ); + assert.equal(tx.logs[0].args._delegate, wallet_admin); + }); + }); describe("Depositing and withdrawing tokens", async () => { it("Should fail to deposit zero amount of tokens", async () => { await catchRevert( - I_VestingEscrowWallet.depositTokens(0, {from: wallet_owner}) + I_VestingEscrowWallet.depositTokens(0, {from: wallet_admin}) ); }); it("Should deposit tokens for new vesting schedules", async () => { let numberOfTokens = 25000; - await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); - const tx = await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); + await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); + const tx = await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); assert.equal(tx.logs[0].args._numberOfTokens, numberOfTokens); @@ -201,7 +233,7 @@ contract('VestingEscrowWallet', accounts => { it("Should withdraw tokens to a treasury", async () => { let numberOfTokens = 25000; - const tx = await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + const tx = await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); assert.equal(tx.logs[0].args._numberOfTokens, numberOfTokens); @@ -214,7 +246,7 @@ contract('VestingEscrowWallet', accounts => { it("Should fail to send available tokens -- fail because beneficiary doesn't have available tokens", async () => { catchRevert( - I_VestingEscrowWallet.sendAvailableTokens(account_beneficiary3, {from: wallet_owner}) + I_VestingEscrowWallet.sendAvailableTokens(account_beneficiary3, {from: wallet_admin}) ); }); @@ -224,20 +256,20 @@ contract('VestingEscrowWallet', accounts => { let frequency = durationUtil.seconds(10); let timeShift = durationUtil.seconds(100); let startTime = latestTime() + timeShift; - await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); - await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); - await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency); - await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); + await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_admin}); - const tx = await I_VestingEscrowWallet.sendAvailableTokens(account_beneficiary3, {from: wallet_owner}); + const tx = await I_VestingEscrowWallet.sendAvailableTokens(account_beneficiary3, {from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens / 3); let balance = await I_PolyToken.balanceOf.call(account_beneficiary3); assert.equal(balance.toNumber(), numberOfTokens / 3); - await I_PolyToken.transfer(account_treasury, balance, {from: account_beneficiary3}); + await I_PolyToken.transfer(token_owner, balance, {from: account_beneficiary3}); }); it("Should fail to edit vesting schedule -- fail because schedule already started", async () => { @@ -247,11 +279,11 @@ contract('VestingEscrowWallet', accounts => { let timeShift = durationUtil.seconds(100); let startTime = latestTime() + timeShift; await catchRevert( - I_VestingEscrowWallet.editSchedule(account_beneficiary3, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}) + I_VestingEscrowWallet.editSchedule(account_beneficiary3, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) ); - await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_owner}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_admin}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); it("Should withdraw available tokens to the beneficiary address", async () => { @@ -260,12 +292,12 @@ contract('VestingEscrowWallet', accounts => { let frequency = durationUtil.seconds(10); let timeShift = durationUtil.seconds(100); let startTime = latestTime() + timeShift; - await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); - await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); - await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency * 3); for (let i = 0; i < 4; i++) { - await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); + await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_admin}); } const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); @@ -275,9 +307,9 @@ contract('VestingEscrowWallet', accounts => { let balance = await I_PolyToken.balanceOf.call(account_beneficiary3); assert.equal(balance.toNumber(), numberOfTokens); - await I_PolyToken.transfer(account_treasury, balance, {from: account_beneficiary3}); - await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_owner}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + await I_PolyToken.transfer(token_owner, balance, {from: account_beneficiary3}); + await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_admin}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); it("Should withdraw available tokens by 3 schedules to the beneficiary address", async () => { @@ -295,19 +327,19 @@ contract('VestingEscrowWallet', accounts => { ]; let totalNumberOfTokens = getTotalNumberOfTokens(schedules); - await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: account_treasury}); - await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_owner}); + await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); for (let i = 0; i < schedules.length; i++) { let numberOfTokens = schedules[i].numberOfTokens; let duration = schedules[i].duration; let frequency = schedules[i].frequency; let startTime = latestTime() + durationUtil.seconds(100); - await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); } await increaseTime(durationUtil.minutes(5)); let stepCount = 4; for (let i = 0; i < stepCount; i++) { - await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_owner}); + await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_admin}); } let numberOfTokens = (30000 / 6 * stepCount) + (2000 / 10 * stepCount); const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); @@ -317,9 +349,9 @@ contract('VestingEscrowWallet', accounts => { let balance = await I_PolyToken.balanceOf.call(account_beneficiary3); assert.equal(balance.toNumber(), numberOfTokens); - await I_PolyToken.transfer(account_treasury, balance, {from: account_beneficiary3}); - await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_owner}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + await I_PolyToken.transfer(token_owner, balance, {from: account_beneficiary3}); + await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_admin}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); }); @@ -349,37 +381,37 @@ contract('VestingEscrowWallet', accounts => { it("Should fail to add vesting schedule to the beneficiary address -- fail because not enough unassigned tokens", async () => { await catchRevert( - I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_owner}) + I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) ); }); it("Should fail to add vesting schedule to the beneficiary address -- fail because address in invalid", async () => { await catchRevert( - I_VestingEscrowWallet.addSchedule(0, 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_owner}) + I_VestingEscrowWallet.addSchedule(0, 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) ); }); it("Should fail to add vesting schedule to the beneficiary address -- fail because start date in the past", async () => { await catchRevert( - I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 1, latestTime() - durationUtil.days(1), {from: wallet_owner}) + I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 1, latestTime() - durationUtil.days(1), {from: wallet_admin}) ); }); it("Should fail to add vesting schedule to the beneficiary address -- fail because number of tokens is 0", async () => { await catchRevert( - I_VestingEscrowWallet.addSchedule(account_beneficiary1, 0, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_owner}) + I_VestingEscrowWallet.addSchedule(account_beneficiary1, 0, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) ); }); it("Should fail to add vesting schedule to the beneficiary address -- fail because duration can't be divided entirely by frequency", async () => { await catchRevert( - I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 3, latestTime() + durationUtil.days(1), {from: wallet_owner}) + I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 3, latestTime() + durationUtil.days(1), {from: wallet_admin}) ); }); it("Should fail to add vesting schedule to the beneficiary address -- fail because number of tokens can't be divided entirely by period count", async () => { await catchRevert( - I_VestingEscrowWallet.addSchedule(account_beneficiary1, 5, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_owner}) + I_VestingEscrowWallet.addSchedule(account_beneficiary1, 5, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) ); }); @@ -412,9 +444,9 @@ contract('VestingEscrowWallet', accounts => { let duration = schedules[0].duration; let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; - await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: account_treasury}); - await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); - const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); let log = tx.logs[0]; checkScheduleLog(log, account_beneficiary1, numberOfTokens, duration, frequency, startTime); @@ -432,7 +464,7 @@ contract('VestingEscrowWallet', accounts => { let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; await catchRevert( - I_VestingEscrowWallet.editSchedule(account_beneficiary1, 1, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}) + I_VestingEscrowWallet.editSchedule(account_beneficiary1, 1, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) ); }); @@ -442,7 +474,7 @@ contract('VestingEscrowWallet', accounts => { let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; await catchRevert( - I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}) + I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) ); }); @@ -451,7 +483,7 @@ contract('VestingEscrowWallet', accounts => { let duration = schedules[1].duration; let frequency = schedules[1].frequency; let startTime = schedules[1].startTime; - const tx = await I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + const tx = await I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); let log = tx.logs[0]; checkScheduleLog(log, account_beneficiary1, numberOfTokens, duration, frequency, startTime); @@ -472,25 +504,25 @@ contract('VestingEscrowWallet', accounts => { let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; await catchRevert( - I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}) + I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) ); }); it("Should fail to revoke vesting schedule -- fail because address is invalid", async () => { await catchRevert( - I_VestingEscrowWallet.revokeSchedule(0, 0, {from: wallet_owner}) + I_VestingEscrowWallet.revokeSchedule(0, 0, {from: wallet_admin}) ); }); it("Should fail to revoke vesting schedule -- fail because schedule not found", async () => { await catchRevert( - I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 1, {from: wallet_owner}) + I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 1, {from: wallet_admin}) ); }); it("Should revoke vesting schedule from the beneficiary address", async () => { - const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_owner}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_admin}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary1); assert.equal(tx.logs[0].args._index, 0); @@ -501,20 +533,20 @@ contract('VestingEscrowWallet', accounts => { it("Should fail to revoke vesting schedules -- fail because address is invalid", async () => { await catchRevert( - I_VestingEscrowWallet.revokeSchedules(0, {from: wallet_owner}) + I_VestingEscrowWallet.revokeSchedules(0, {from: wallet_admin}) ); }); it("Should add 3 vesting schedules to the beneficiary address", async () => { let totalNumberOfTokens = getTotalNumberOfTokens(schedules); - await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: account_treasury}); - await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_owner}); + await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); for (let i = 0; i < schedules.length; i++) { let numberOfTokens = schedules[i].numberOfTokens; let duration = schedules[i].duration; let frequency = schedules[i].frequency; let startTime = schedules[i].startTime; - const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary2, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary2, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); let log = tx.logs[0]; checkScheduleLog(log, account_beneficiary2, numberOfTokens, duration, frequency, startTime); @@ -528,8 +560,8 @@ contract('VestingEscrowWallet', accounts => { }); it("Should revoke vesting schedule from the beneficiary address", async () => { - const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary2, 1, {from: wallet_owner}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary2, 1, {from: wallet_admin}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); assert.equal(tx.logs[0].args._index, 1); @@ -543,8 +575,8 @@ contract('VestingEscrowWallet', accounts => { }); it("Should revoke 2 vesting schedules from the beneficiary address", async () => { - const tx = await I_VestingEscrowWallet.revokeSchedules(account_beneficiary2, {from: wallet_owner}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + const tx = await I_VestingEscrowWallet.revokeSchedules(account_beneficiary2, {from: wallet_admin}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); @@ -582,7 +614,7 @@ contract('VestingEscrowWallet', accounts => { let numberOfTokens = schedules[i].numberOfTokens; let duration = schedules[i].duration; let frequency = schedules[i].frequency; - const tx = await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_owner}); + const tx = await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_admin}); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); assert.equal(tx.logs[0].args._duration.toNumber(), duration); @@ -591,7 +623,7 @@ contract('VestingEscrowWallet', accounts => { }); it("Should remove template", async () => { - const tx = await I_VestingEscrowWallet.removeTemplate(1, {from: wallet_owner}); + const tx = await I_VestingEscrowWallet.removeTemplate(1, {from: wallet_admin}); assert.equal(tx.logs[0].args._index, 1); }); @@ -599,7 +631,7 @@ contract('VestingEscrowWallet', accounts => { it("Should fail to add vesting schedule from template -- fail because template not found", async () => { let startTime = schedules[2].startTime; await catchRevert( - I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 1, startTime, {from: wallet_owner}) + I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 1, startTime, {from: wallet_admin}) ); }); @@ -608,9 +640,9 @@ contract('VestingEscrowWallet', accounts => { let duration = schedules[2].duration; let frequency = schedules[2].frequency; let startTime = schedules[2].startTime; - await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: account_treasury }); - await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_owner}); - const tx = await I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 1, startTime, {from: wallet_owner}); + await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 1, startTime, {from: wallet_admin}); let log = tx.logs[0]; checkScheduleLog(log, account_beneficiary1, numberOfTokens, duration, frequency, startTime); @@ -621,21 +653,21 @@ contract('VestingEscrowWallet', accounts => { let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); - await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_owner}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_admin}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); it("Should fail to remove template", async () => { await catchRevert( - I_VestingEscrowWallet.removeTemplate(2, {from: wallet_owner}) + I_VestingEscrowWallet.removeTemplate(2, {from: wallet_admin}) ); }); it("Should remove 2 Templates", async () => { - await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_owner}); - await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_owner}); + await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_admin}); + await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_admin}); - let templateCount = await I_VestingEscrowWallet.getTemplateCount.call({from: wallet_owner}); + let templateCount = await I_VestingEscrowWallet.getTemplateCount.call({from: wallet_admin}); assert.equal(templateCount, 0); }); @@ -650,10 +682,10 @@ contract('VestingEscrowWallet', accounts => { let startTime = latestTime() + durationUtil.seconds(100); let totalNumberOfTokens = numberOfTokens * 3; - await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: account_treasury}); - await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_owner}); + await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); - let tx = await I_VestingEscrowWallet.batchAddSchedule(beneficiaries, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + let tx = await I_VestingEscrowWallet.batchAddSchedule(beneficiaries, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; @@ -677,7 +709,7 @@ contract('VestingEscrowWallet', accounts => { let indexes = [0, 0, 0, 0]; await catchRevert( - I_VestingEscrowWallet.batchEditSchedule(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}) + I_VestingEscrowWallet.batchEditSchedule(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) ); }); @@ -689,7 +721,7 @@ contract('VestingEscrowWallet', accounts => { let startTime = latestTime() + timeShift; let indexes = [0, 0, 0]; - const tx = await I_VestingEscrowWallet.batchEditSchedule(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: wallet_owner}); + const tx = await I_VestingEscrowWallet.batchEditSchedule(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency); for (let i = 0; i < beneficiaries.length; i++) { @@ -711,10 +743,10 @@ contract('VestingEscrowWallet', accounts => { it("Should send available tokens to the beneficiaries addresses", async () => { for (let i = 0; i < beneficiaries.length; i++) { let beneficiary = beneficiaries[i]; - await I_VestingEscrowWallet.update(beneficiary, {from: wallet_owner}); + await I_VestingEscrowWallet.update(beneficiary, {from: wallet_admin}); } - const tx = await I_VestingEscrowWallet.batchSendAvailableTokens(beneficiaries, {from: wallet_owner}); + const tx = await I_VestingEscrowWallet.batchSendAvailableTokens(beneficiaries, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; @@ -725,9 +757,9 @@ contract('VestingEscrowWallet', accounts => { let balance = await I_PolyToken.balanceOf.call(beneficiary); assert.equal(balance.toNumber(), 5000); - await I_PolyToken.transfer(account_treasury, balance, {from: beneficiary}); - await I_VestingEscrowWallet.revokeSchedules(beneficiary, {from: wallet_owner}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + await I_PolyToken.transfer(token_owner, balance, {from: beneficiary}); + await I_VestingEscrowWallet.revokeSchedules(beneficiary, {from: wallet_admin}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); } }); @@ -738,12 +770,12 @@ contract('VestingEscrowWallet', accounts => { let startTime = latestTime() + durationUtil.seconds(100); let totalNumberOfTokens = numberOfTokens * 3; - await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: account_treasury}); - await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_owner}); - await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_owner}); + await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_admin}); - let tx = await I_VestingEscrowWallet.batchAddScheduleFromTemplate(beneficiaries, 0, startTime, {from: wallet_owner}); - await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_owner}); + let tx = await I_VestingEscrowWallet.batchAddScheduleFromTemplate(beneficiaries, 0, startTime, {from: wallet_admin}); + await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; @@ -760,7 +792,7 @@ contract('VestingEscrowWallet', accounts => { }); it("Should revoke vesting schedule from the 3 beneficiary's addresses", async () => { - const tx = await I_VestingEscrowWallet.batchRevokeSchedules(beneficiaries, {from: wallet_owner}); + const tx = await I_VestingEscrowWallet.batchRevokeSchedules(beneficiaries, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; @@ -771,7 +803,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 0); } - await I_VestingEscrowWallet.sendToTreasury({from: wallet_owner}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); }); From 45fddfef5c3f0872e677ba7324d066ac3578ef5a Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 21 Nov 2018 12:20:13 +0200 Subject: [PATCH 29/93] optimized VestingEscrowWallet --- .../modules/Wallet/VestingEscrowWallet.sol | 38 +++++++++---------- test/z_vesting_escrow_wallet.js | 7 +--- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index d20db9c6b..082eb3b00 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -274,7 +274,7 @@ contract VestingEscrowWallet is IWallet { * @param _index index of the schedule */ function revokeSchedule(address _beneficiary, uint256 _index) external withPerm(ADMIN) { - require(_beneficiary != address(0), "Invalid beneficiary address"); + require(_beneficiary != address(0), "Invalid address"); require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); Schedule[] storage schedules = dataMap[_beneficiary].schedules; unassignedTokens = unassignedTokens.add(schedules[_index].lockedTokens); @@ -341,7 +341,7 @@ contract VestingEscrowWallet is IWallet { * @return available tokens for beneficiary */ function getAvailableTokens(address _beneficiary) external view returns(uint256) { - require(_beneficiary != address(0), "Invalid address"); + require(_beneficiary != address(0)); return dataMap[_beneficiary].availableTokens; } @@ -451,7 +451,7 @@ contract VestingEscrowWallet is IWallet { function _sendTokens(address _beneficiary) private { Data storage data = dataMap[_beneficiary]; uint256 amount = data.availableTokens; - require(amount > 0, "No tokens"); + require(amount > 0, "No available tokens"); data.availableTokens = 0; data.claimedTokens = data.claimedTokens.add(amount); token.safeTransfer(_beneficiary, amount); @@ -487,22 +487,22 @@ contract VestingEscrowWallet is IWallet { } } - //TODO temporally for decreasing contract size -// /** -// * @notice manually triggers update outside for all schedules (can be used to reduce user gas costs) -// */ -// function updateAll() external withPerm(ADMIN) { -// _updateAll(); -// } -// -// function _updateAll() private { -// for (uint256 i = 0; i < beneficiaries.length; i++) { -// _update(beneficiaries[i]); -// } -// } + /** + * @notice manually triggers update outside for all schedules (can be used to reduce user gas costs) + */ + function updateAll() external withPerm(ADMIN) { + _updateAll(); + } + + function _updateAll() private { + for (uint256 i = 0; i < beneficiaries.length; i++) { + _update(beneficiaries[i]); + } + } function _revokeSchedules(address _beneficiary) private { - if (_canBeRemoved(_beneficiary)) { + //can be removed + if (dataMap[_beneficiary].availableTokens == 0) { uint256 index = dataMap[_beneficiary].index; beneficiaries[index] = beneficiaries[beneficiaries.length - 1]; beneficiaries.length--; @@ -513,10 +513,6 @@ contract VestingEscrowWallet is IWallet { } } - function _canBeRemoved(address _beneficiary) private view returns(bool) { - return (dataMap[_beneficiary].availableTokens == 0); - } - /** * @notice Return the permissions flag that are associated with VestingEscrowWallet */ diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index e53d4a40a..5c92d2fe0 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -741,10 +741,7 @@ contract('VestingEscrowWallet', accounts => { }); it("Should send available tokens to the beneficiaries addresses", async () => { - for (let i = 0; i < beneficiaries.length; i++) { - let beneficiary = beneficiaries[i]; - await I_VestingEscrowWallet.update(beneficiary, {from: wallet_admin}); - } + await I_VestingEscrowWallet.updateAll({from: wallet_admin}); const tx = await I_VestingEscrowWallet.batchSendAvailableTokens(beneficiaries, {from: wallet_admin}); @@ -783,7 +780,7 @@ contract('VestingEscrowWallet', accounts => { checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(beneficiary); - assert.equal(scheduleCount, 1); + assert.equal(scheduleCount.toNumber(), 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); From b26f12a652205bd714f1bd109976b74907dddad6 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 21 Nov 2018 13:44:47 +0200 Subject: [PATCH 30/93] added tests for checking permission --- .../modules/Wallet/VestingEscrowWallet.sol | 6 +- test/helpers/exceptions.js | 3 + test/z_vesting_escrow_wallet.js | 118 +++++++++++++++++- 3 files changed, 121 insertions(+), 6 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 082eb3b00..abd5fea9e 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -83,23 +83,23 @@ contract VestingEscrowWallet is IWallet { public Module(_securityToken, _polyAddress) { - token = ERC20(_polyAddress); } /** * @notice Function used to initialize the different variables * @param _treasury Address of the treasury */ - function configure(address _treasury) public onlyFactory { + function configure(address _treasury, address _token) public onlyFactory { require(_treasury != address(0), "Invalid address"); treasury = _treasury; + token = ERC20(_token); } /** * @notice This function returns the signature of the configure function */ function getInitFunction() public pure returns (bytes4) { - return bytes4(keccak256("configure(address)")); + return bytes4(keccak256("configure(address,address)")); } /** diff --git a/test/helpers/exceptions.js b/test/helpers/exceptions.js index 22c05be07..ea0327af8 100644 --- a/test/helpers/exceptions.js +++ b/test/helpers/exceptions.js @@ -25,6 +25,9 @@ module.exports = { catchRevert: async function(promise) { await tryCatch(promise, "revert"); }, + catchPermission: async function(promise) { + await tryCatch(promise, "revert Permission check failed"); + }, catchOutOfGas: async function(promise) { await tryCatch(promise, "out of gas"); }, diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 5c92d2fe0..421a56acc 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -1,7 +1,7 @@ import {setUpPolymathNetwork, deployGPMAndVerifyed, deployVestingEscrowWalletAndVerifyed} from "./helpers/createInstances"; import latestTime from "./helpers/latestTime"; import {duration as durationUtil, latestBlock, promisifyLogWatch} from "./helpers/utils"; -import {catchRevert} from "./helpers/exceptions"; +import {catchRevert, catchPermission} from "./helpers/exceptions"; import {increaseTime} from "./helpers/time"; import {encodeModuleCall} from "./helpers/encodeCall"; @@ -174,8 +174,8 @@ contract('VestingEscrowWallet', accounts => { it("Should successfully attach the VestingEscrowWallet with the security token", async () => { let bytesData = encodeModuleCall( - ["address"], - [token_owner] + ["address", "address"], + [token_owner, I_PolyToken.address] ); await I_SecurityToken.changeGranularity(1, {from: token_owner}); @@ -805,6 +805,118 @@ contract('VestingEscrowWallet', accounts => { }); + describe("Check permissions", async () => { + + it("Should not be able to deposit", async () => { + await catchPermission( + I_VestingEscrowWallet.depositTokens(25000, {from: account_beneficiary1}) + ); + }); + + it("Should not be able to withdraw tokens to a treasury", async () => { + await catchPermission( + I_VestingEscrowWallet.sendToTreasury({from: account_beneficiary1}) + ); + }); + + it("Should not be able to send available tokens", async () => { + await catchPermission( + I_VestingEscrowWallet.sendAvailableTokens(account_beneficiary3, {from: account_beneficiary1}) + ); + }); + + it("Should not be able to add template", async () => { + await catchPermission( + I_VestingEscrowWallet.addTemplate(25000, 4, 1, {from: account_beneficiary1}) + ); + }); + + it("Should not be able to remove template", async () => { + await catchPermission( + I_VestingEscrowWallet.removeTemplate(0, {from: account_beneficiary1}) + ); + }); + + it("Should not be able to get template count", async () => { + await catchPermission( + I_VestingEscrowWallet.getTemplateCount({from: account_beneficiary1}) + ); + }); + + it("Should not be able to add schedule", async () => { + await catchPermission( + I_VestingEscrowWallet.addSchedule(account_beneficiary1, 10000, 4, 1, latestTime(), {from: account_beneficiary1}) + ); + }); + + it("Should not be able to add schedule from template", async () => { + await catchPermission( + I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 0, latestTime(), {from: account_beneficiary1}) + ); + }); + + it("Should not be able to edit schedule", async () => { + await catchPermission( + I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, 10000, 4, 1, latestTime(), {from: account_beneficiary1}) + ); + }); + + it("Should not be able to revoke schedule", async () => { + await catchPermission( + I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: account_beneficiary1}) + ); + }); + + it("Should not be able to revoke schedules", async () => { + await catchPermission( + I_VestingEscrowWallet.revokeSchedules(account_beneficiary1, {from: account_beneficiary1}) + ); + }); + + it("Should not be able to send available tokens to the beneficiaries", async () => { + await catchPermission( + I_VestingEscrowWallet.batchSendAvailableTokens([account_beneficiary1], {from: account_beneficiary1}) + ); + }); + + it("Should not be able to add schedules to the beneficiaries", async () => { + await catchPermission( + I_VestingEscrowWallet.batchAddSchedule([account_beneficiary1], 10000, 4, 1, latestTime(), {from: account_beneficiary1}) + ); + }); + + it("Should not be able to add schedules from template to the beneficiaries", async () => { + await catchPermission( + I_VestingEscrowWallet.batchAddScheduleFromTemplate([account_beneficiary1], 0, latestTime(), {from: account_beneficiary1}) + ); + }); + + it("Should not be able to revoke schedules of the beneficiaries", async () => { + await catchPermission( + I_VestingEscrowWallet.batchRevokeSchedules([account_beneficiary1], {from: account_beneficiary1}) + ); + }); + + it("Should not be able to edit schedules for the beneficiaries", async () => { + await catchPermission( + I_VestingEscrowWallet.batchEditSchedule([account_beneficiary1], [0], 10000, 4, 1, latestTime(), {from: account_beneficiary1}) + ); + }); + + it("Should not be able update schedule", async () => { + await catchPermission( + I_VestingEscrowWallet.update(account_beneficiary1, {from: account_beneficiary1}) + ); + }); + + it("Should not be able update all schedules", async () => { + await catchPermission( + I_VestingEscrowWallet.updateAll({from: account_beneficiary1}) + ); + }); + + }); + }); function checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTime) { From 92fb53a16ec44e4970720142bf032b7819f6f1c2 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 21 Nov 2018 22:04:12 +0200 Subject: [PATCH 31/93] added test for factory, applied review comments --- .../modules/Wallet/VestingEscrowWallet.sol | 60 ++++++++----------- test/z_vesting_escrow_wallet.js | 18 ++++-- 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index abd5fea9e..6b2aa584f 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -50,29 +50,27 @@ contract VestingEscrowWallet is IWallet { Template[] public templates; event AddSchedule( - address _beneficiary, + address indexed _beneficiary, uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, - uint256 _startTime, - uint256 _timestamp + uint256 _startTime ); event EditSchedule( - address _beneficiary, + address indexed _beneficiary, uint256 _index, uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, - uint256 _startTime, - uint256 _timestamp + uint256 _startTime ); - event RevokeSchedules(address _beneficiary, uint256 _timestamp); - event RevokeSchedule(address _beneficiary, uint256 _index, uint256 _timestamp); - event DepositTokens(uint256 _numberOfTokens, uint256 _timestamp); - event SendToTreasury(uint256 _numberOfTokens, uint256 _timestamp); - event SendTokens(address _beneficiary, uint256 _numberOfTokens, uint256 _timestamp); - event AddTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, uint256 _timestamp); - event RemoveTemplate(uint256 _index, uint256 _timestamp); + event RevokeSchedules(address indexed _beneficiary); + event RevokeSchedule(address indexed _beneficiary, uint256 _index); + event DepositTokens(uint256 _numberOfTokens); + event SendToTreasury(uint256 _numberOfTokens); + event SendTokens(address indexed _beneficiary, uint256 _numberOfTokens); + event AddTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, uint256 _index); + event RemoveTemplate(uint256 _index); /** * @notice Constructor @@ -109,8 +107,7 @@ contract VestingEscrowWallet is IWallet { require(_numberOfTokens > 0, "Should be greater than zero"); token.safeTransferFrom(treasury, this, _numberOfTokens); unassignedTokens = unassignedTokens.add(_numberOfTokens); - /*solium-disable-next-line security/no-block-members*/ - emit DepositTokens(_numberOfTokens, now); + emit DepositTokens(_numberOfTokens); } /** @@ -120,8 +117,7 @@ contract VestingEscrowWallet is IWallet { uint256 amount = unassignedTokens; unassignedTokens = 0; token.safeTransfer(treasury, amount); - /*solium-disable-next-line security/no-block-members*/ - emit SendToTreasury(amount, now); + emit SendToTreasury(amount); } /** @@ -152,8 +148,7 @@ contract VestingEscrowWallet is IWallet { template.duration = _duration; template.frequency = _frequency; templates.push(template); - /*solium-disable-next-line security/no-block-members*/ - emit AddTemplate(_numberOfTokens, _duration, _frequency, now); + emit AddTemplate(_numberOfTokens, _duration, _frequency, templates.length - 1); } /** @@ -162,17 +157,18 @@ contract VestingEscrowWallet is IWallet { */ function removeTemplate(uint256 _index) external withPerm(ADMIN) { require(_index < templates.length, "Template not found"); - templates[_index] = templates[templates.length - 1]; + if (_index != templates.length - 1) { + templates[_index] = templates[templates.length - 1]; + } templates.length--; - /*solium-disable-next-line security/no-block-members*/ - emit RemoveTemplate(_index, now); + emit RemoveTemplate(_index); } /** * @notice Returns count of templates * @return count of templates */ - function getTemplateCount() external view withPerm(ADMIN) returns(uint256) { + function getTemplateCount() external view returns(uint256) { return templates.length; } @@ -212,8 +208,7 @@ contract VestingEscrowWallet is IWallet { beneficiaries.push(_beneficiary); } dataMap[_beneficiary].schedules.push(schedule); - /*solium-disable-next-line security/no-block-members*/ - emit AddSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime, now); + emit AddSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); } /** @@ -224,7 +219,7 @@ contract VestingEscrowWallet is IWallet { */ function addScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startTime) public withPerm(ADMIN) { require(_index < templates.length, "Template not found"); - Template storage template = templates[_index]; + Template memory template = templates[_index]; addSchedule(_beneficiary, template.numberOfTokens, template.duration, template.frequency, _startTime); } @@ -265,7 +260,7 @@ contract VestingEscrowWallet is IWallet { schedule.frequency = _frequency; schedule.startTime = _startTime; schedule.nextTime = _startTime.add(schedule.frequency); - emit EditSchedule(_beneficiary, _index, _numberOfTokens, _duration, _frequency, _startTime, now); + emit EditSchedule(_beneficiary, _index, _numberOfTokens, _duration, _frequency, _startTime); } /** @@ -283,8 +278,7 @@ contract VestingEscrowWallet is IWallet { if (schedules.length == 0) { _revokeSchedules(_beneficiary); } - /*solium-disable-next-line security/no-block-members*/ - emit RevokeSchedule(_beneficiary, _index, now); + emit RevokeSchedule(_beneficiary, _index); } @@ -300,8 +294,7 @@ contract VestingEscrowWallet is IWallet { } delete dataMap[_beneficiary].schedules; _revokeSchedules(_beneficiary); - /*solium-disable-next-line security/no-block-members*/ - emit RevokeSchedules(_beneficiary, now); + emit RevokeSchedules(_beneficiary); } /** @@ -384,7 +377,7 @@ contract VestingEscrowWallet is IWallet { * @param _index index of the template * @param _startTime vesting start time */ - function batchAddScheduleFromTemplate(address[] _beneficiaries, uint256 _index, uint256 _startTime) public withPerm(ADMIN) { + function batchAddScheduleFromTemplate(address[] _beneficiaries, uint256 _index, uint256 _startTime) external withPerm(ADMIN) { for (uint256 i = 0; i < _beneficiaries.length; i++) { addScheduleFromTemplate(_beneficiaries[i], _index, _startTime); } @@ -455,8 +448,7 @@ contract VestingEscrowWallet is IWallet { data.availableTokens = 0; data.claimedTokens = data.claimedTokens.add(amount); token.safeTransfer(_beneficiary, amount); - /*solium-disable-next-line security/no-block-members*/ - emit SendTokens(_beneficiary, amount, now); + emit SendTokens(_beneficiary, amount); } /** diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 421a56acc..20cac61b6 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -207,6 +207,18 @@ contract('VestingEscrowWallet', accounts => { assert.equal(tx.logs[0].args._delegate, wallet_admin); }); + it("Should get the permission", async () => { + let perm = await I_VestingEscrowWallet.getPermissions.call(); + assert.equal(web3.utils.toAscii(perm[0]).replace(/\u0000/g, ""), "ADMIN"); + }); + + it("Should get the tags of the factory", async () => { + let tags = await I_VestingEscrowWalletFactory.getTags.call(); + assert.equal(tags.length, 2); + assert.equal(web3.utils.toAscii(tags[0]).replace(/\u0000/g, ""), "Vested Wallet"); + assert.equal(web3.utils.toAscii(tags[1]).replace(/\u0000/g, ""), "Escrow"); + }); + }); describe("Depositing and withdrawing tokens", async () => { @@ -837,12 +849,6 @@ contract('VestingEscrowWallet', accounts => { ); }); - it("Should not be able to get template count", async () => { - await catchPermission( - I_VestingEscrowWallet.getTemplateCount({from: account_beneficiary1}) - ); - }); - it("Should not be able to add schedule", async () => { await catchPermission( I_VestingEscrowWallet.addSchedule(account_beneficiary1, 10000, 4, 1, latestTime(), {from: account_beneficiary1}) From 3de498b5a172de909d1ce72185e72fe6adba18ab Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Thu, 22 Nov 2018 17:47:48 +0200 Subject: [PATCH 32/93] review comments: renaming, redundant operations --- .../modules/Wallet/VestingEscrowWallet.sol | 89 ++++++------- test/z_vesting_escrow_wallet.js | 126 ++++++++++-------- 2 files changed, 117 insertions(+), 98 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 6b2aa584f..7cf9b8aea 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -56,7 +56,7 @@ contract VestingEscrowWallet is IWallet { uint256 _frequency, uint256 _startTime ); - event EditSchedule( + event ModifySchedule( address indexed _beneficiary, uint256 _index, uint256 _numberOfTokens, @@ -104,6 +104,10 @@ contract VestingEscrowWallet is IWallet { * @notice Used to deposit tokens from treasury */ function depositTokens(uint256 _numberOfTokens) external withPerm(ADMIN) { + _depositTokens(_numberOfTokens); + } + + function _depositTokens(uint256 _numberOfTokens) internal { require(_numberOfTokens > 0, "Should be greater than zero"); token.safeTransferFrom(treasury, this, _numberOfTokens); unassignedTokens = unassignedTokens.add(_numberOfTokens); @@ -121,10 +125,10 @@ contract VestingEscrowWallet is IWallet { } /** - * @notice Sends available tokens to beneficiary + * @notice Pushes available tokens to beneficiary * @param _beneficiary beneficiary's address */ - function sendAvailableTokens(address _beneficiary) public withPerm(ADMIN) { + function pushAvailableTokens(address _beneficiary) public withPerm(ADMIN) { _sendTokens(_beneficiary); } @@ -143,11 +147,7 @@ contract VestingEscrowWallet is IWallet { */ function addTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) external withPerm(ADMIN) { _validateTemplate(_numberOfTokens, _duration, _frequency); - Template memory template; - template.numberOfTokens = _numberOfTokens; - template.duration = _duration; - template.frequency = _frequency; - templates.push(template); + templates.push(Template(_numberOfTokens, _duration, _frequency)); emit AddTemplate(_numberOfTokens, _duration, _frequency, templates.length - 1); } @@ -191,23 +191,20 @@ contract VestingEscrowWallet is IWallet { withPerm(ADMIN) { _validateSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); - require(_numberOfTokens <= unassignedTokens, "Not enough tokens"); - - Schedule memory schedule; + if (_numberOfTokens > unassignedTokens) { + _depositTokens(_numberOfTokens.sub(unassignedTokens)); + } unassignedTokens = unassignedTokens.sub(_numberOfTokens); - schedule.numberOfTokens = _numberOfTokens; - schedule.lockedTokens = _numberOfTokens; - schedule.duration = _duration; - schedule.frequency = _frequency; - schedule.startTime = _startTime; - schedule.nextTime = _startTime.add(schedule.frequency); - schedule.state = State.CREATED; //add beneficiary to the schedule list only if adding first schedule if (dataMap[_beneficiary].schedules.length == 0) { dataMap[_beneficiary].index = beneficiaries.length; beneficiaries.push(_beneficiary); } - dataMap[_beneficiary].schedules.push(schedule); + dataMap[_beneficiary].schedules.push( + Schedule( + _numberOfTokens, _numberOfTokens, _duration, _frequency, _startTime, _startTime.add(_frequency), State.CREATED + ) + ); emit AddSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); } @@ -217,14 +214,18 @@ contract VestingEscrowWallet is IWallet { * @param _index index of the template * @param _startTime vesting start time */ - function addScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startTime) public withPerm(ADMIN) { + function addScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startTime) external withPerm(ADMIN) { + _addScheduleFromTemplate(_beneficiary, _index, _startTime); + } + + function _addScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startTime) internal { require(_index < templates.length, "Template not found"); Template memory template = templates[_index]; addSchedule(_beneficiary, template.numberOfTokens, template.duration, template.frequency, _startTime); } /** - * @notice Edits vesting schedules for each of beneficiary + * @notice Modifies vesting schedules for each of beneficiary * @param _beneficiary beneficiary's addresses * @param _index index of schedule * @param _numberOfTokens number of tokens @@ -232,7 +233,7 @@ contract VestingEscrowWallet is IWallet { * @param _frequency vesting frequency * @param _startTime vesting start time */ - function editSchedule( + function modifySchedule( address _beneficiary, uint256 _index, uint256 _numberOfTokens, @@ -251,16 +252,13 @@ contract VestingEscrowWallet is IWallet { if (_numberOfTokens <= schedule.lockedTokens) { unassignedTokens = unassignedTokens.add(schedule.lockedTokens - _numberOfTokens); } else { - require((_numberOfTokens - schedule.lockedTokens) <= unassignedTokens, "Not enough tokens"); + if (_numberOfTokens - schedule.lockedTokens > unassignedTokens) { + _depositTokens(_numberOfTokens - schedule.lockedTokens - unassignedTokens); + } unassignedTokens = unassignedTokens.sub(_numberOfTokens - schedule.lockedTokens); } - schedule.numberOfTokens = _numberOfTokens; - schedule.lockedTokens = _numberOfTokens; - schedule.duration = _duration; - schedule.frequency = _frequency; - schedule.startTime = _startTime; - schedule.nextTime = _startTime.add(schedule.frequency); - emit EditSchedule(_beneficiary, _index, _numberOfTokens, _duration, _frequency, _startTime); + dataMap[_beneficiary].schedules[_index] = Schedule(_numberOfTokens, _numberOfTokens, _duration, _frequency, _startTime, _startTime.add(_frequency), State.CREATED); + emit ModifySchedule(_beneficiary, _index, _numberOfTokens, _duration, _frequency, _startTime); } /** @@ -342,9 +340,10 @@ contract VestingEscrowWallet is IWallet { * @notice Used to bulk send available tokens for each of beneficiaries * @param _beneficiaries array of beneficiary's addresses */ - function batchSendAvailableTokens(address[] _beneficiaries) external withPerm(ADMIN) { + function pushAvailableTokensMulti(address[] _beneficiaries) external withPerm(ADMIN) { + require(_beneficiaries.length > 1, "Array size should be greater than one"); for (uint256 i = 0; i < _beneficiaries.length; i++) { - sendAvailableTokens(_beneficiaries[i]); + pushAvailableTokens(_beneficiaries[i]); } } @@ -356,7 +355,7 @@ contract VestingEscrowWallet is IWallet { * @param _frequency vesting frequency * @param _startTime vesting start time */ - function batchAddSchedule( + function addScheduleMulti( address[] _beneficiaries, uint256 _numberOfTokens, uint256 _duration, @@ -377,9 +376,9 @@ contract VestingEscrowWallet is IWallet { * @param _index index of the template * @param _startTime vesting start time */ - function batchAddScheduleFromTemplate(address[] _beneficiaries, uint256 _index, uint256 _startTime) external withPerm(ADMIN) { + function addScheduleFromTemplateMulti(address[] _beneficiaries, uint256 _index, uint256 _startTime) external withPerm(ADMIN) { for (uint256 i = 0; i < _beneficiaries.length; i++) { - addScheduleFromTemplate(_beneficiaries[i], _index, _startTime); + _addScheduleFromTemplate(_beneficiaries[i], _index, _startTime); } } @@ -387,14 +386,14 @@ contract VestingEscrowWallet is IWallet { * @notice Used to bulk revoke vesting schedules for each of beneficiaries * @param _beneficiaries array of beneficiary's addresses */ - function batchRevokeSchedules(address[] _beneficiaries) external withPerm(ADMIN) { + function revokeSchedulesMulti(address[] _beneficiaries) external withPerm(ADMIN) { for (uint256 i = 0; i < _beneficiaries.length; i++) { revokeSchedules(_beneficiaries[i]); } } /** - * @notice Used to bulk edit vesting schedules for each of beneficiaries + * @notice Used to bulk modify vesting schedules for each of beneficiaries * @param _beneficiaries array of beneficiary's addresses * @param _indexes array of beneficiary's indexes of schedule * @param _numberOfTokens number of tokens @@ -402,7 +401,7 @@ contract VestingEscrowWallet is IWallet { * @param _frequency vesting frequency * @param _startTime vesting start time */ - function batchEditSchedule( + function modifyScheduleMulti( address[] _beneficiaries, uint256[] _indexes, uint256 _numberOfTokens, @@ -415,7 +414,7 @@ contract VestingEscrowWallet is IWallet { { require(_beneficiaries.length == _indexes.length, "Arrays sizes mismatch"); for (uint256 i = 0; i < _beneficiaries.length; i++) { - editSchedule(_beneficiaries[i], _indexes[i], _numberOfTokens, _duration, _frequency, _startTime); + modifySchedule(_beneficiaries[i], _indexes[i], _numberOfTokens, _duration, _frequency, _startTime); } } @@ -426,7 +425,7 @@ contract VestingEscrowWallet is IWallet { uint256 _frequency, uint256 _startTime ) - private + internal view { require(_beneficiary != address(0), "Invalid address"); @@ -434,14 +433,14 @@ contract VestingEscrowWallet is IWallet { require(now < _startTime, "Date in the past"); } - function _validateTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) private pure { + function _validateTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) internal pure { require(_numberOfTokens > 0, "Zero amount"); require(_duration % _frequency == 0, "Duration and frequency mismatch"); uint256 periodCount = _duration.div(_frequency); require(_numberOfTokens % periodCount == 0, "Tokens and periods mismatch"); } - function _sendTokens(address _beneficiary) private { + function _sendTokens(address _beneficiary) internal { Data storage data = dataMap[_beneficiary]; uint256 amount = data.availableTokens; require(amount > 0, "No available tokens"); @@ -459,7 +458,7 @@ contract VestingEscrowWallet is IWallet { _update(_beneficiary); } - function _update(address _beneficiary) private { + function _update(address _beneficiary) internal { Data storage data = dataMap[_beneficiary]; for (uint256 i = 0; i < data.schedules.length; i++) { Schedule storage schedule = data.schedules[i]; @@ -486,13 +485,13 @@ contract VestingEscrowWallet is IWallet { _updateAll(); } - function _updateAll() private { + function _updateAll() internal { for (uint256 i = 0; i < beneficiaries.length; i++) { _update(beneficiaries[i]); } } - function _revokeSchedules(address _beneficiary) private { + function _revokeSchedules(address _beneficiary) internal { //can be removed if (dataMap[_beneficiary].availableTokens == 0) { uint256 index = dataMap[_beneficiary].index; diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 20cac61b6..3565e5b29 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -1,7 +1,7 @@ -import {setUpPolymathNetwork, deployGPMAndVerifyed, deployVestingEscrowWalletAndVerifyed} from "./helpers/createInstances"; +import {deployGPMAndVerifyed, deployVestingEscrowWalletAndVerifyed, setUpPolymathNetwork} from "./helpers/createInstances"; import latestTime from "./helpers/latestTime"; import {duration as durationUtil, latestBlock, promisifyLogWatch} from "./helpers/utils"; -import {catchRevert, catchPermission} from "./helpers/exceptions"; +import {catchPermission, catchRevert} from "./helpers/exceptions"; import {increaseTime} from "./helpers/time"; import {encodeModuleCall} from "./helpers/encodeCall"; @@ -256,9 +256,9 @@ contract('VestingEscrowWallet', accounts => { assert.equal(balance.toNumber(), 0); }); - it("Should fail to send available tokens -- fail because beneficiary doesn't have available tokens", async () => { + it("Should fail to push available tokens -- fail because beneficiary doesn't have available tokens", async () => { catchRevert( - I_VestingEscrowWallet.sendAvailableTokens(account_beneficiary3, {from: wallet_admin}) + I_VestingEscrowWallet.pushAvailableTokens(account_beneficiary3, {from: wallet_admin}) ); }); @@ -274,7 +274,7 @@ contract('VestingEscrowWallet', accounts => { await increaseTime(timeShift + frequency); await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_admin}); - const tx = await I_VestingEscrowWallet.sendAvailableTokens(account_beneficiary3, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.pushAvailableTokens(account_beneficiary3, {from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens / 3); @@ -284,14 +284,14 @@ contract('VestingEscrowWallet', accounts => { await I_PolyToken.transfer(token_owner, balance, {from: account_beneficiary3}); }); - it("Should fail to edit vesting schedule -- fail because schedule already started", async () => { + it("Should fail to modify vesting schedule -- fail because schedule already started", async () => { let numberOfTokens = 75000; let duration = durationUtil.seconds(30); let frequency = durationUtil.seconds(10); let timeShift = durationUtil.seconds(100); let startTime = latestTime() + timeShift; await catchRevert( - I_VestingEscrowWallet.editSchedule(account_beneficiary3, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) + I_VestingEscrowWallet.modifySchedule(account_beneficiary3, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) ); await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_admin}); @@ -368,7 +368,7 @@ contract('VestingEscrowWallet', accounts => { }); - describe("Adding, editing and revoking vesting schedule", async () => { + describe("Adding, modifying and revoking vesting schedule", async () => { let schedules = [ { @@ -391,12 +391,6 @@ contract('VestingEscrowWallet', accounts => { } ]; - it("Should fail to add vesting schedule to the beneficiary address -- fail because not enough unassigned tokens", async () => { - await catchRevert( - I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) - ); - }); - it("Should fail to add vesting schedule to the beneficiary address -- fail because address in invalid", async () => { await catchRevert( I_VestingEscrowWallet.addSchedule(0, 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) @@ -460,8 +454,7 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); - let log = tx.logs[0]; - checkScheduleLog(log, account_beneficiary1, numberOfTokens, duration, frequency, startTime); + checkScheduleLog(tx.logs[0], account_beneficiary1, numberOfTokens, duration, frequency, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); assert.equal(scheduleCount, 1); @@ -470,35 +463,45 @@ contract('VestingEscrowWallet', accounts => { checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); }); - it("Should fail to edit vesting schedule -- fail because schedule not found", async () => { + it("Should add vesting schedule without depositing to the beneficiary address", async () => { let numberOfTokens = schedules[0].numberOfTokens; let duration = schedules[0].duration; let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; - await catchRevert( - I_VestingEscrowWallet.editSchedule(account_beneficiary1, 1, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) - ); + await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); + const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + + assert.equal(tx.logs[0].args._numberOfTokens, numberOfTokens); + checkScheduleLog(tx.logs[1], account_beneficiary1, numberOfTokens, duration, frequency, startTime); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); + assert.equal(scheduleCount, 2); + + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 1); + checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + + await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 1, {from: wallet_admin}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); - it("Should fail to edit vesting schedule -- fail because not enough unassigned tokens", async () => { - let numberOfTokens = schedules[0].numberOfTokens * 2; + it("Should fail to modify vesting schedule -- fail because schedule not found", async () => { + let numberOfTokens = schedules[0].numberOfTokens; let duration = schedules[0].duration; let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; await catchRevert( - I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) + I_VestingEscrowWallet.modifySchedule(account_beneficiary1, 2, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) ); }); - it("Should edit vesting schedule for the beneficiary's address", async () => { + it("Should modify vesting schedule for the beneficiary's address", async () => { let numberOfTokens = schedules[1].numberOfTokens; let duration = schedules[1].duration; let frequency = schedules[1].frequency; let startTime = schedules[1].startTime; - const tx = await I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.modifySchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); - let log = tx.logs[0]; - checkScheduleLog(log, account_beneficiary1, numberOfTokens, duration, frequency, startTime); + checkScheduleLog(tx.logs[0], account_beneficiary1, numberOfTokens, duration, frequency, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); assert.equal(scheduleCount, 1); @@ -508,16 +511,29 @@ contract('VestingEscrowWallet', accounts => { let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); assert.equal(unassignedTokens.toNumber(), schedules[0].numberOfTokens - schedules[1].numberOfTokens); + + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); - it("Should fail edit vesting schedule to the beneficiary address", async () => { + it("Should modify vesting schedule without depositing for the beneficiary's address", async () => { let numberOfTokens = schedules[0].numberOfTokens + schedules[1].numberOfTokens; let duration = schedules[0].duration; let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; - await catchRevert( - I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) - ); + await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); + const tx = await I_VestingEscrowWallet.modifySchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + + assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), schedules[0].numberOfTokens); + checkScheduleLog(tx.logs[1], account_beneficiary1, numberOfTokens, duration, frequency, startTime); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); + assert.equal(scheduleCount, 1); + + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); + checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + assert.equal(unassignedTokens.toNumber(), 0); }); it("Should fail to revoke vesting schedule -- fail because address is invalid", async () => { @@ -560,8 +576,7 @@ contract('VestingEscrowWallet', accounts => { let startTime = schedules[i].startTime; const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary2, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); - let log = tx.logs[0]; - checkScheduleLog(log, account_beneficiary2, numberOfTokens, duration, frequency, startTime); + checkScheduleLog(tx.logs[0], account_beneficiary2, numberOfTokens, duration, frequency, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2); assert.equal(scheduleCount, i + 1); @@ -656,8 +671,7 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); const tx = await I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 1, startTime, {from: wallet_admin}); - let log = tx.logs[0]; - checkScheduleLog(log, account_beneficiary1, numberOfTokens, duration, frequency, startTime); + checkScheduleLog(tx.logs[0], account_beneficiary1, numberOfTokens, duration, frequency, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); assert.equal(scheduleCount, 1); @@ -685,7 +699,7 @@ contract('VestingEscrowWallet', accounts => { }); - describe("Tests for batch operations", async () => { + describe("Tests for multi operations", async () => { it("Should add schedules for 3 beneficiaries", async () => { let numberOfTokens = 30000; @@ -697,7 +711,7 @@ contract('VestingEscrowWallet', accounts => { await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); - let tx = await I_VestingEscrowWallet.batchAddSchedule(beneficiaries, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + let tx = await I_VestingEscrowWallet.addScheduleMulti(beneficiaries, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; @@ -712,7 +726,7 @@ contract('VestingEscrowWallet', accounts => { } }); - it("Should edit vesting schedule for 3 beneficiary's addresses", async () => { + it("Should modify vesting schedule for 3 beneficiary's addresses", async () => { let numberOfTokens = 25000; let duration = durationUtil.seconds(50); let frequency = durationUtil.seconds(10); @@ -721,11 +735,11 @@ contract('VestingEscrowWallet', accounts => { let indexes = [0, 0, 0, 0]; await catchRevert( - I_VestingEscrowWallet.batchEditSchedule(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) + I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) ); }); - it("Should edit vesting schedule for 3 beneficiary's addresses", async () => { + it("Should modify vesting schedule for 3 beneficiary's addresses", async () => { let numberOfTokens = 25000; let duration = durationUtil.seconds(50); let frequency = durationUtil.seconds(10); @@ -733,7 +747,7 @@ contract('VestingEscrowWallet', accounts => { let startTime = latestTime() + timeShift; let indexes = [0, 0, 0]; - const tx = await I_VestingEscrowWallet.batchEditSchedule(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency); for (let i = 0; i < beneficiaries.length; i++) { @@ -752,10 +766,16 @@ contract('VestingEscrowWallet', accounts => { assert.equal(unassignedTokens.toNumber(), 5000 * beneficiaries.length); }); + it("Should not be able to send available tokens to the beneficiaries addresses -- fail because of array size", async () => { + await catchRevert( + I_VestingEscrowWallet.pushAvailableTokensMulti([account_beneficiary1], {from: wallet_admin}) + ); + }); + it("Should send available tokens to the beneficiaries addresses", async () => { await I_VestingEscrowWallet.updateAll({from: wallet_admin}); - const tx = await I_VestingEscrowWallet.batchSendAvailableTokens(beneficiaries, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.pushAvailableTokensMulti(beneficiaries, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; @@ -783,7 +803,7 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_admin}); - let tx = await I_VestingEscrowWallet.batchAddScheduleFromTemplate(beneficiaries, 0, startTime, {from: wallet_admin}); + let tx = await I_VestingEscrowWallet.addScheduleFromTemplateMulti(beneficiaries, 0, startTime, {from: wallet_admin}); await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { @@ -801,7 +821,7 @@ contract('VestingEscrowWallet', accounts => { }); it("Should revoke vesting schedule from the 3 beneficiary's addresses", async () => { - const tx = await I_VestingEscrowWallet.batchRevokeSchedules(beneficiaries, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.revokeSchedulesMulti(beneficiaries, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; @@ -833,7 +853,7 @@ contract('VestingEscrowWallet', accounts => { it("Should not be able to send available tokens", async () => { await catchPermission( - I_VestingEscrowWallet.sendAvailableTokens(account_beneficiary3, {from: account_beneficiary1}) + I_VestingEscrowWallet.pushAvailableTokens(account_beneficiary3, {from: account_beneficiary1}) ); }); @@ -861,9 +881,9 @@ contract('VestingEscrowWallet', accounts => { ); }); - it("Should not be able to edit schedule", async () => { + it("Should not be able to modify schedule", async () => { await catchPermission( - I_VestingEscrowWallet.editSchedule(account_beneficiary1, 0, 10000, 4, 1, latestTime(), {from: account_beneficiary1}) + I_VestingEscrowWallet.modifySchedule(account_beneficiary1, 0, 10000, 4, 1, latestTime(), {from: account_beneficiary1}) ); }); @@ -881,31 +901,31 @@ contract('VestingEscrowWallet', accounts => { it("Should not be able to send available tokens to the beneficiaries", async () => { await catchPermission( - I_VestingEscrowWallet.batchSendAvailableTokens([account_beneficiary1], {from: account_beneficiary1}) + I_VestingEscrowWallet.pushAvailableTokensMulti([account_beneficiary1], {from: account_beneficiary1}) ); }); it("Should not be able to add schedules to the beneficiaries", async () => { await catchPermission( - I_VestingEscrowWallet.batchAddSchedule([account_beneficiary1], 10000, 4, 1, latestTime(), {from: account_beneficiary1}) + I_VestingEscrowWallet.addScheduleMulti([account_beneficiary1], 10000, 4, 1, latestTime(), {from: account_beneficiary1}) ); }); it("Should not be able to add schedules from template to the beneficiaries", async () => { await catchPermission( - I_VestingEscrowWallet.batchAddScheduleFromTemplate([account_beneficiary1], 0, latestTime(), {from: account_beneficiary1}) + I_VestingEscrowWallet.addScheduleFromTemplateMulti([account_beneficiary1], 0, latestTime(), {from: account_beneficiary1}) ); }); it("Should not be able to revoke schedules of the beneficiaries", async () => { await catchPermission( - I_VestingEscrowWallet.batchRevokeSchedules([account_beneficiary1], {from: account_beneficiary1}) + I_VestingEscrowWallet.revokeSchedulesMulti([account_beneficiary1], {from: account_beneficiary1}) ); }); - it("Should not be able to edit schedules for the beneficiaries", async () => { + it("Should not be able to modify schedules for the beneficiaries", async () => { await catchPermission( - I_VestingEscrowWallet.batchEditSchedule([account_beneficiary1], [0], 10000, 4, 1, latestTime(), {from: account_beneficiary1}) + I_VestingEscrowWallet.modifyScheduleMulti([account_beneficiary1], [0], 10000, 4, 1, latestTime(), {from: account_beneficiary1}) ); }); From 6f10ec0ea61503aeaa445b5d53113fd712bbd4f1 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Thu, 22 Nov 2018 19:59:10 +0200 Subject: [PATCH 33/93] review comments: use ST instead of configuring by tokens --- .../modules/Wallet/VestingEscrowWallet.sol | 13 +-- test/z_vesting_escrow_wallet.js | 92 ++++++++++++++----- 2 files changed, 72 insertions(+), 33 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 7cf9b8aea..85d51ad8c 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -11,7 +11,6 @@ import "./IWallet.sol"; */ contract VestingEscrowWallet is IWallet { using SafeMath for uint256; - using SafeERC20 for ERC20; bytes32 public constant ADMIN = "ADMIN"; @@ -40,7 +39,6 @@ contract VestingEscrowWallet is IWallet { enum State {CREATED, STARTED, COMPLETED} - ERC20 public token; address public treasury; uint256 public unassignedTokens; @@ -87,17 +85,16 @@ contract VestingEscrowWallet is IWallet { * @notice Function used to initialize the different variables * @param _treasury Address of the treasury */ - function configure(address _treasury, address _token) public onlyFactory { + function configure(address _treasury) public onlyFactory { require(_treasury != address(0), "Invalid address"); treasury = _treasury; - token = ERC20(_token); } /** * @notice This function returns the signature of the configure function */ function getInitFunction() public pure returns (bytes4) { - return bytes4(keccak256("configure(address,address)")); + return bytes4(keccak256("configure(address)")); } /** @@ -109,7 +106,7 @@ contract VestingEscrowWallet is IWallet { function _depositTokens(uint256 _numberOfTokens) internal { require(_numberOfTokens > 0, "Should be greater than zero"); - token.safeTransferFrom(treasury, this, _numberOfTokens); + ISecurityToken(securityToken).transferFrom(treasury, this, _numberOfTokens); unassignedTokens = unassignedTokens.add(_numberOfTokens); emit DepositTokens(_numberOfTokens); } @@ -120,7 +117,7 @@ contract VestingEscrowWallet is IWallet { function sendToTreasury() external withPerm(ADMIN) { uint256 amount = unassignedTokens; unassignedTokens = 0; - token.safeTransfer(treasury, amount); + ISecurityToken(securityToken).transfer(treasury, amount); emit SendToTreasury(amount); } @@ -446,7 +443,7 @@ contract VestingEscrowWallet is IWallet { require(amount > 0, "No available tokens"); data.availableTokens = 0; data.claimedTokens = data.claimedTokens.add(amount); - token.safeTransfer(_beneficiary, amount); + ISecurityToken(securityToken).transfer(_beneficiary, amount); emit SendTokens(_beneficiary, amount); } diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 3565e5b29..4b8146395 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -25,7 +25,6 @@ contract('VestingEscrowWallet', accounts => { let account_beneficiary1; let account_beneficiary2; let account_beneficiary3; - let account_beneficiary4; let beneficiaries; @@ -75,7 +74,6 @@ contract('VestingEscrowWallet', accounts => { account_beneficiary1 = accounts[6]; account_beneficiary2 = accounts[7]; account_beneficiary3 = accounts[8]; - account_beneficiary4 = accounts[9]; beneficiaries = [ account_beneficiary1, @@ -174,8 +172,8 @@ contract('VestingEscrowWallet', accounts => { it("Should successfully attach the VestingEscrowWallet with the security token", async () => { let bytesData = encodeModuleCall( - ["address", "address"], - [token_owner, I_PolyToken.address] + ["address"], + [token_owner] ); await I_SecurityToken.changeGranularity(1, {from: token_owner}); @@ -191,6 +189,50 @@ contract('VestingEscrowWallet', accounts => { I_VestingEscrowWallet = VestingEscrowWallet.at(tx.logs[2].args._module); }); + it("Should Buy the tokens for token_owner", async() => { + // Add the Investor in to the whitelist + let tx = await I_GeneralTransferManager.modifyWhitelist( + token_owner, + latestTime(), + latestTime(), + latestTime() + durationUtil.days(10), + true, + { + from: token_owner, + gas: 6000000 + }); + + assert.equal(tx.logs[0].args._investor.toLowerCase(), token_owner.toLowerCase(), "Failed in adding the token_owner in whitelist"); + + // Mint some tokens + await I_SecurityToken.mint(token_owner, web3.utils.toWei('1', 'ether'), { from: token_owner }); + + assert.equal( + (await I_SecurityToken.balanceOf(token_owner)).toNumber(), + web3.utils.toWei('1', 'ether') + ); + + }); + + it("Should whitelist investors", async() => { + // Add the Investor in to the whitelist + let tx = await I_GeneralTransferManager.modifyWhitelistMulti( + [I_VestingEscrowWallet.address, account_beneficiary1, account_beneficiary2, account_beneficiary3], + [latestTime(), latestTime(), latestTime(), latestTime()], + [latestTime(), latestTime(), latestTime(), latestTime()], + [latestTime() + durationUtil.days(10), latestTime() + durationUtil.days(10), latestTime() + durationUtil.days(10), latestTime() + durationUtil.days(10)], + [true, true, true, true], + { + from: token_owner, + gas: 6000000 + }); + + assert.equal(tx.logs[0].args._investor, I_VestingEscrowWallet.address); + assert.equal(tx.logs[1].args._investor, account_beneficiary1); + assert.equal(tx.logs[2].args._investor, account_beneficiary2); + assert.equal(tx.logs[3].args._investor, account_beneficiary3); + }); + it("Should successfully add the delegate", async() => { let tx = await I_GeneralPermissionManager.addDelegate(wallet_admin, delegateDetails, { from: token_owner}); assert.equal(tx.logs[0].args._delegate, wallet_admin); @@ -231,7 +273,7 @@ contract('VestingEscrowWallet', accounts => { it("Should deposit tokens for new vesting schedules", async () => { let numberOfTokens = 25000; - await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); + await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); const tx = await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); assert.equal(tx.logs[0].args._numberOfTokens, numberOfTokens); @@ -239,7 +281,7 @@ contract('VestingEscrowWallet', accounts => { let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); assert.equal(unassignedTokens, numberOfTokens); - let balance = await I_PolyToken.balanceOf.call(I_VestingEscrowWallet.address); + let balance = await I_SecurityToken.balanceOf.call(I_VestingEscrowWallet.address); assert.equal(balance.toNumber(), numberOfTokens); }); @@ -252,7 +294,7 @@ contract('VestingEscrowWallet', accounts => { let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); assert.equal(unassignedTokens, 0); - let balance = await I_PolyToken.balanceOf.call(I_VestingEscrowWallet.address); + let balance = await I_SecurityToken.balanceOf.call(I_VestingEscrowWallet.address); assert.equal(balance.toNumber(), 0); }); @@ -268,7 +310,7 @@ contract('VestingEscrowWallet', accounts => { let frequency = durationUtil.seconds(10); let timeShift = durationUtil.seconds(100); let startTime = latestTime() + timeShift; - await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); + await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency); @@ -278,10 +320,10 @@ contract('VestingEscrowWallet', accounts => { assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens / 3); - let balance = await I_PolyToken.balanceOf.call(account_beneficiary3); + let balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); assert.equal(balance.toNumber(), numberOfTokens / 3); - await I_PolyToken.transfer(token_owner, balance, {from: account_beneficiary3}); + await I_SecurityToken.transfer(token_owner, balance, {from: account_beneficiary3}); }); it("Should fail to modify vesting schedule -- fail because schedule already started", async () => { @@ -304,7 +346,7 @@ contract('VestingEscrowWallet', accounts => { let frequency = durationUtil.seconds(10); let timeShift = durationUtil.seconds(100); let startTime = latestTime() + timeShift; - await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); + await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency * 3); @@ -316,10 +358,10 @@ contract('VestingEscrowWallet', accounts => { assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); - let balance = await I_PolyToken.balanceOf.call(account_beneficiary3); + let balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); assert.equal(balance.toNumber(), numberOfTokens); - await I_PolyToken.transfer(token_owner, balance, {from: account_beneficiary3}); + await I_SecurityToken.transfer(token_owner, balance, {from: account_beneficiary3}); await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); @@ -339,7 +381,7 @@ contract('VestingEscrowWallet', accounts => { ]; let totalNumberOfTokens = getTotalNumberOfTokens(schedules); - await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); + await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); for (let i = 0; i < schedules.length; i++) { let numberOfTokens = schedules[i].numberOfTokens; @@ -358,10 +400,10 @@ contract('VestingEscrowWallet', accounts => { assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); - let balance = await I_PolyToken.balanceOf.call(account_beneficiary3); + let balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); assert.equal(balance.toNumber(), numberOfTokens); - await I_PolyToken.transfer(token_owner, balance, {from: account_beneficiary3}); + await I_SecurityToken.transfer(token_owner, balance, {from: account_beneficiary3}); await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); @@ -450,7 +492,7 @@ contract('VestingEscrowWallet', accounts => { let duration = schedules[0].duration; let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; - await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); + await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); @@ -468,7 +510,7 @@ contract('VestingEscrowWallet', accounts => { let duration = schedules[0].duration; let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; - await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); + await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); assert.equal(tx.logs[0].args._numberOfTokens, numberOfTokens); @@ -520,7 +562,7 @@ contract('VestingEscrowWallet', accounts => { let duration = schedules[0].duration; let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; - await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); + await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); const tx = await I_VestingEscrowWallet.modifySchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), schedules[0].numberOfTokens); @@ -567,7 +609,7 @@ contract('VestingEscrowWallet', accounts => { it("Should add 3 vesting schedules to the beneficiary address", async () => { let totalNumberOfTokens = getTotalNumberOfTokens(schedules); - await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); + await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); for (let i = 0; i < schedules.length; i++) { let numberOfTokens = schedules[i].numberOfTokens; @@ -667,7 +709,7 @@ contract('VestingEscrowWallet', accounts => { let duration = schedules[2].duration; let frequency = schedules[2].frequency; let startTime = schedules[2].startTime; - await I_PolyToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); + await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); const tx = await I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 1, startTime, {from: wallet_admin}); @@ -708,7 +750,7 @@ contract('VestingEscrowWallet', accounts => { let startTime = latestTime() + durationUtil.seconds(100); let totalNumberOfTokens = numberOfTokens * 3; - await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); + await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); let tx = await I_VestingEscrowWallet.addScheduleMulti(beneficiaries, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); @@ -783,10 +825,10 @@ contract('VestingEscrowWallet', accounts => { assert.equal(log.args._beneficiary, beneficiary); assert.equal(log.args._numberOfTokens.toNumber(), 5000); - let balance = await I_PolyToken.balanceOf.call(beneficiary); + let balance = await I_SecurityToken.balanceOf.call(beneficiary); assert.equal(balance.toNumber(), 5000); - await I_PolyToken.transfer(token_owner, balance, {from: beneficiary}); + await I_SecurityToken.transfer(token_owner, balance, {from: beneficiary}); await I_VestingEscrowWallet.revokeSchedules(beneficiary, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); } @@ -799,7 +841,7 @@ contract('VestingEscrowWallet', accounts => { let startTime = latestTime() + durationUtil.seconds(100); let totalNumberOfTokens = numberOfTokens * 3; - await I_PolyToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); + await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_admin}); From c26a8caaaea74654fe3d35042a9ae6b835172e71 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Fri, 23 Nov 2018 00:41:12 +0200 Subject: [PATCH 34/93] review comments: simplified data structure --- .../modules/Wallet/VestingEscrowWallet.sol | 77 +++++++++---------- test/z_vesting_escrow_wallet.js | 62 ++++++++------- 2 files changed, 71 insertions(+), 68 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 85d51ad8c..ed5b41fae 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -16,19 +16,16 @@ contract VestingEscrowWallet is IWallet { struct Schedule { uint256 numberOfTokens; - uint256 lockedTokens; + uint256 releasedTokens; + uint256 availableTokens; uint256 duration; uint256 frequency; uint256 startTime; - uint256 nextTime; - State state; } struct Data { uint256 index; Schedule[] schedules; - uint256 availableTokens; - uint256 claimedTokens; } struct Template { @@ -38,6 +35,7 @@ contract VestingEscrowWallet is IWallet { } enum State {CREATED, STARTED, COMPLETED} + //TODO add method for getting state address public treasury; uint256 public unassignedTokens; @@ -197,11 +195,7 @@ contract VestingEscrowWallet is IWallet { dataMap[_beneficiary].index = beneficiaries.length; beneficiaries.push(_beneficiary); } - dataMap[_beneficiary].schedules.push( - Schedule( - _numberOfTokens, _numberOfTokens, _duration, _frequency, _startTime, _startTime.add(_frequency), State.CREATED - ) - ); + dataMap[_beneficiary].schedules.push(Schedule(_numberOfTokens, 0, 0, _duration, _frequency, _startTime)); emit AddSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); } @@ -246,15 +240,15 @@ contract VestingEscrowWallet is IWallet { Schedule storage schedule = dataMap[_beneficiary].schedules[_index]; /*solium-disable-next-line security/no-block-members*/ require(now < schedule.startTime, "Schedule started"); - if (_numberOfTokens <= schedule.lockedTokens) { - unassignedTokens = unassignedTokens.add(schedule.lockedTokens - _numberOfTokens); + if (_numberOfTokens <= schedule.numberOfTokens) { + unassignedTokens = unassignedTokens.add(schedule.numberOfTokens - _numberOfTokens); } else { - if (_numberOfTokens - schedule.lockedTokens > unassignedTokens) { - _depositTokens(_numberOfTokens - schedule.lockedTokens - unassignedTokens); + if (_numberOfTokens - schedule.numberOfTokens > unassignedTokens) { + _depositTokens(_numberOfTokens - schedule.numberOfTokens - unassignedTokens); } - unassignedTokens = unassignedTokens.sub(_numberOfTokens - schedule.lockedTokens); + unassignedTokens = unassignedTokens.sub(_numberOfTokens - schedule.numberOfTokens); } - dataMap[_beneficiary].schedules[_index] = Schedule(_numberOfTokens, _numberOfTokens, _duration, _frequency, _startTime, _startTime.add(_frequency), State.CREATED); + dataMap[_beneficiary].schedules[_index] = Schedule(_numberOfTokens, 0, 0, _duration, _frequency, _startTime); emit ModifySchedule(_beneficiary, _index, _numberOfTokens, _duration, _frequency, _startTime); } @@ -267,7 +261,7 @@ contract VestingEscrowWallet is IWallet { require(_beneficiary != address(0), "Invalid address"); require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); Schedule[] storage schedules = dataMap[_beneficiary].schedules; - unassignedTokens = unassignedTokens.add(schedules[_index].lockedTokens); + unassignedTokens = unassignedTokens.add(schedules[_index].numberOfTokens - schedules[_index].releasedTokens); schedules[_index] = schedules[schedules.length - 1]; schedules.length--; if (schedules.length == 0) { @@ -285,7 +279,7 @@ contract VestingEscrowWallet is IWallet { require(_beneficiary != address(0), "Invalid address"); Data storage data = dataMap[_beneficiary]; for (uint256 i = 0; i < data.schedules.length; i++) { - unassignedTokens = unassignedTokens.add(data.schedules[i].lockedTokens); + unassignedTokens = unassignedTokens.add(data.schedules[i].numberOfTokens - data.schedules[i].releasedTokens); } delete dataMap[_beneficiary].schedules; _revokeSchedules(_beneficiary); @@ -298,18 +292,15 @@ contract VestingEscrowWallet is IWallet { * @param _index index of the schedule * @return beneficiary's schedule */ - function getSchedule(address _beneficiary, uint256 _index) external view returns(uint256, uint256, uint256, uint256, uint256, uint256, State) { + function getSchedule(address _beneficiary, uint256 _index) external view returns(uint256, uint256, uint256, uint256) { require(_beneficiary != address(0), "Invalid address"); require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); Schedule storage schedule = dataMap[_beneficiary].schedules[_index]; return ( schedule.numberOfTokens, - schedule.lockedTokens, schedule.duration, schedule.frequency, - schedule.startTime, - schedule.nextTime, - schedule.state + schedule.startTime ); } @@ -329,8 +320,16 @@ contract VestingEscrowWallet is IWallet { * @return available tokens for beneficiary */ function getAvailableTokens(address _beneficiary) external view returns(uint256) { + return _getAvailableTokens(_beneficiary); + } + + function _getAvailableTokens(address _beneficiary) internal view returns(uint256) { require(_beneficiary != address(0)); - return dataMap[_beneficiary].availableTokens; + uint256 availableTokens; + for (uint256 i = 0; i < dataMap[_beneficiary].schedules.length; i++) { + availableTokens = availableTokens.add(dataMap[_beneficiary].schedules[i].availableTokens); + } + return availableTokens; } /** @@ -438,11 +437,11 @@ contract VestingEscrowWallet is IWallet { } function _sendTokens(address _beneficiary) internal { - Data storage data = dataMap[_beneficiary]; - uint256 amount = data.availableTokens; + uint256 amount = _getAvailableTokens(_beneficiary); require(amount > 0, "No available tokens"); - data.availableTokens = 0; - data.claimedTokens = data.claimedTokens.add(amount); + for (uint256 i = 0; i < dataMap[_beneficiary].schedules.length; i++) { + dataMap[_beneficiary].schedules[i].availableTokens = 0; + } ISecurityToken(securityToken).transfer(_beneficiary, amount); emit SendTokens(_beneficiary, amount); } @@ -459,17 +458,17 @@ contract VestingEscrowWallet is IWallet { Data storage data = dataMap[_beneficiary]; for (uint256 i = 0; i < data.schedules.length; i++) { Schedule storage schedule = data.schedules[i]; - /*solium-disable-next-line security/no-block-members*/ - if (schedule.state != State.COMPLETED && schedule.nextTime <= now) { + if (schedule.releasedTokens < schedule.numberOfTokens) { uint256 periodCount = schedule.duration.div(schedule.frequency); - uint256 numberOfTokens = schedule.numberOfTokens.div(periodCount); - data.availableTokens = data.availableTokens.add(numberOfTokens); - schedule.lockedTokens = schedule.lockedTokens.sub(numberOfTokens); - if (schedule.nextTime == schedule.startTime.add(schedule.duration)) { - schedule.state = State.COMPLETED; - } else { - schedule.state = State.STARTED; - schedule.nextTime = schedule.nextTime.add(schedule.frequency); + /*solium-disable-next-line security/no-block-members*/ + uint256 periodNumber = (now.sub(schedule.startTime)).div(schedule.frequency); + if (periodNumber > periodCount) { + periodNumber = periodCount; + } + uint256 releasedTokens = schedule.numberOfTokens.mul(periodNumber).div(periodCount); + if (schedule.releasedTokens < releasedTokens) { + schedule.availableTokens = schedule.availableTokens.add(releasedTokens - schedule.releasedTokens); + schedule.releasedTokens = releasedTokens; } } } @@ -490,7 +489,7 @@ contract VestingEscrowWallet is IWallet { function _revokeSchedules(address _beneficiary) internal { //can be removed - if (dataMap[_beneficiary].availableTokens == 0) { + if (_getAvailableTokens(_beneficiary) == 0) { uint256 index = dataMap[_beneficiary].index; beneficiaries[index] = beneficiaries[beneficiaries.length - 1]; beneficiaries.length--; diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 4b8146395..ee274a50d 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -366,17 +366,22 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); - it("Should withdraw available tokens by 3 schedules to the beneficiary address", async () => { + it("Should withdraw available tokens by 2 schedules to the beneficiary address", async () => { let schedules = [ + { + numberOfTokens: 100000, + duration: durationUtil.minutes(4), + frequency: durationUtil.minutes(1) + }, { numberOfTokens: 30000, - duration: durationUtil.seconds(6), - frequency: durationUtil.seconds(1) + duration: durationUtil.minutes(6), + frequency: durationUtil.minutes(1) }, { numberOfTokens: 2000, - duration: durationUtil.seconds(10), - frequency: durationUtil.seconds(1) + duration: durationUtil.minutes(10), + frequency: durationUtil.minutes(1) } ]; @@ -390,12 +395,11 @@ contract('VestingEscrowWallet', accounts => { let startTime = latestTime() + durationUtil.seconds(100); await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); } - await increaseTime(durationUtil.minutes(5)); - let stepCount = 4; - for (let i = 0; i < stepCount; i++) { - await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_admin}); - } - let numberOfTokens = (30000 / 6 * stepCount) + (2000 / 10 * stepCount); + let stepCount = 6; + await increaseTime(durationUtil.minutes(stepCount) + durationUtil.seconds(100)); + await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_admin}); + + let numberOfTokens = 100000 + (30000 / 6 * stepCount) + (2000 / 10 * stepCount); const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); @@ -408,6 +412,8 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); + //TODO add test like previous one, but with withdrawing tokens + }); describe("Adding, modifying and revoking vesting schedule", async () => { @@ -433,6 +439,8 @@ contract('VestingEscrowWallet', accounts => { } ]; + //TODO add test for checking pushing during revoking + it("Should fail to add vesting schedule to the beneficiary address -- fail because address in invalid", async () => { await catchRevert( I_VestingEscrowWallet.addSchedule(0, 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) @@ -502,7 +510,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); - checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); }); it("Should add vesting schedule without depositing to the beneficiary address", async () => { @@ -520,7 +528,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 2); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 1); - checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 1, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); @@ -549,7 +557,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); - checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); assert.equal(unassignedTokens.toNumber(), schedules[0].numberOfTokens - schedules[1].numberOfTokens); @@ -572,7 +580,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); - checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); assert.equal(unassignedTokens.toNumber(), 0); @@ -624,7 +632,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, i + 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, i); - checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); } }); @@ -639,8 +647,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 2); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, 1); - checkSchedule(schedule, schedules[2].numberOfTokens, schedules[2].numberOfTokens, schedules[2].duration, schedules[2].frequency, - schedules[2].startTime, schedules[2].startTime + schedules[2].frequency, CREATED); + checkSchedule(schedule, schedules[2].numberOfTokens, schedules[2].duration, schedules[2].frequency, schedules[2].startTime); }); it("Should revoke 2 vesting schedules from the beneficiary address", async () => { @@ -719,7 +726,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); - checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); @@ -764,7 +771,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); - checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); } }); @@ -801,7 +808,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); - checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); } let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); @@ -857,7 +864,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount.toNumber(), 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); - checkSchedule(schedule, numberOfTokens, numberOfTokens, duration, frequency, startTime, startTime + frequency, CREATED); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); } }); @@ -995,14 +1002,11 @@ function checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, assert.equal(log.args._startTime.toNumber(), startTime); } -function checkSchedule(schedule, numberOfTokens, lockedTokens, duration, frequency, startTime, nextTime, state) { +function checkSchedule(schedule, numberOfTokens, duration, frequency, startTime) { assert.equal(schedule[0].toNumber(), numberOfTokens); - assert.equal(schedule[1].toNumber(), lockedTokens); - assert.equal(schedule[2].toNumber(), duration); - assert.equal(schedule[3].toNumber(), frequency); - assert.equal(schedule[4].toNumber(), startTime); - assert.equal(schedule[5].toNumber(), nextTime); - assert.equal(schedule[6], state); + assert.equal(schedule[1].toNumber(), duration); + assert.equal(schedule[2].toNumber(), frequency); + assert.equal(schedule[3].toNumber(), startTime); } function getTotalNumberOfTokens(schedules) { From 03437b8654968f6e79b664cb81bc986e4453809a Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Fri, 23 Nov 2018 10:14:09 +0200 Subject: [PATCH 35/93] review comments: removed redundant functions --- .../modules/Wallet/VestingEscrowWallet.sol | 50 +++++++------------ test/z_vesting_escrow_wallet.js | 14 ++---- 2 files changed, 20 insertions(+), 44 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index ed5b41fae..29400e895 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -446,44 +446,28 @@ contract VestingEscrowWallet is IWallet { emit SendTokens(_beneficiary, amount); } - /** - * @notice manually triggers update outside for beneficiary's schedule (can be used to reduce user gas costs) - * @param _beneficiary beneficiary's address of the schedule - */ - function update(address _beneficiary) external withPerm(ADMIN) { - _update(_beneficiary); - } - - function _update(address _beneficiary) internal { - Data storage data = dataMap[_beneficiary]; - for (uint256 i = 0; i < data.schedules.length; i++) { - Schedule storage schedule = data.schedules[i]; - if (schedule.releasedTokens < schedule.numberOfTokens) { - uint256 periodCount = schedule.duration.div(schedule.frequency); - /*solium-disable-next-line security/no-block-members*/ - uint256 periodNumber = (now.sub(schedule.startTime)).div(schedule.frequency); - if (periodNumber > periodCount) { - periodNumber = periodCount; - } - uint256 releasedTokens = schedule.numberOfTokens.mul(periodNumber).div(periodCount); - if (schedule.releasedTokens < releasedTokens) { - schedule.availableTokens = schedule.availableTokens.add(releasedTokens - schedule.releasedTokens); - schedule.releasedTokens = releasedTokens; - } - } - } - } - /** * @notice manually triggers update outside for all schedules (can be used to reduce user gas costs) */ function updateAll() external withPerm(ADMIN) { - _updateAll(); - } - - function _updateAll() internal { for (uint256 i = 0; i < beneficiaries.length; i++) { - _update(beneficiaries[i]); + Data storage data = dataMap[beneficiaries[i]]; + for (uint256 j = 0; j < data.schedules.length; j++) { + Schedule storage schedule = data.schedules[j]; + if (schedule.releasedTokens < schedule.numberOfTokens) { + uint256 periodCount = schedule.duration.div(schedule.frequency); + /*solium-disable-next-line security/no-block-members*/ + uint256 periodNumber = (now.sub(schedule.startTime)).div(schedule.frequency); + if (periodNumber > periodCount) { + periodNumber = periodCount; + } + uint256 releasedTokens = schedule.numberOfTokens.mul(periodNumber).div(periodCount); + if (schedule.releasedTokens < releasedTokens) { + schedule.availableTokens = schedule.availableTokens.add(releasedTokens - schedule.releasedTokens); + schedule.releasedTokens = releasedTokens; + } + } + } } } diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index ee274a50d..318600a9c 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -314,7 +314,7 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency); - await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_admin}); + await I_VestingEscrowWallet.updateAll({from: wallet_admin}); const tx = await I_VestingEscrowWallet.pushAvailableTokens(account_beneficiary3, {from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); @@ -350,9 +350,7 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency * 3); - for (let i = 0; i < 4; i++) { - await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_admin}); - } + await I_VestingEscrowWallet.updateAll({from: wallet_admin}); const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); @@ -397,7 +395,7 @@ contract('VestingEscrowWallet', accounts => { } let stepCount = 6; await increaseTime(durationUtil.minutes(stepCount) + durationUtil.seconds(100)); - await I_VestingEscrowWallet.update(account_beneficiary3, {from: wallet_admin}); + await I_VestingEscrowWallet.updateAll({from: wallet_admin}); let numberOfTokens = 100000 + (30000 / 6 * stepCount) + (2000 / 10 * stepCount); const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); @@ -978,12 +976,6 @@ contract('VestingEscrowWallet', accounts => { ); }); - it("Should not be able update schedule", async () => { - await catchPermission( - I_VestingEscrowWallet.update(account_beneficiary1, {from: account_beneficiary1}) - ); - }); - it("Should not be able update all schedules", async () => { await catchPermission( I_VestingEscrowWallet.updateAll({from: account_beneficiary1}) From 4add551c8585f7f94179fab848a64bf0491d7476 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Fri, 23 Nov 2018 11:25:53 +0200 Subject: [PATCH 36/93] removed dataMap --- .../modules/Wallet/VestingEscrowWallet.sol | 70 +++++++++---------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 29400e895..a5a6973d1 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -23,11 +23,6 @@ contract VestingEscrowWallet is IWallet { uint256 startTime; } - struct Data { - uint256 index; - Schedule[] schedules; - } - struct Template { uint256 numberOfTokens; uint256 duration; @@ -40,7 +35,7 @@ contract VestingEscrowWallet is IWallet { address public treasury; uint256 public unassignedTokens; - mapping (address => Data) public dataMap; + mapping (address => Schedule[]) public schedules; address[] public beneficiaries; Template[] public templates; @@ -191,11 +186,10 @@ contract VestingEscrowWallet is IWallet { } unassignedTokens = unassignedTokens.sub(_numberOfTokens); //add beneficiary to the schedule list only if adding first schedule - if (dataMap[_beneficiary].schedules.length == 0) { - dataMap[_beneficiary].index = beneficiaries.length; + if (schedules[_beneficiary].length == 0) { beneficiaries.push(_beneficiary); } - dataMap[_beneficiary].schedules.push(Schedule(_numberOfTokens, 0, 0, _duration, _frequency, _startTime)); + schedules[_beneficiary].push(Schedule(_numberOfTokens, 0, 0, _duration, _frequency, _startTime)); emit AddSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); } @@ -236,8 +230,8 @@ contract VestingEscrowWallet is IWallet { withPerm(ADMIN) { _validateSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); - require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); - Schedule storage schedule = dataMap[_beneficiary].schedules[_index]; + require(_index < schedules[_beneficiary].length, "Schedule not found"); + Schedule storage schedule = schedules[_beneficiary][_index]; /*solium-disable-next-line security/no-block-members*/ require(now < schedule.startTime, "Schedule started"); if (_numberOfTokens <= schedule.numberOfTokens) { @@ -248,7 +242,7 @@ contract VestingEscrowWallet is IWallet { } unassignedTokens = unassignedTokens.sub(_numberOfTokens - schedule.numberOfTokens); } - dataMap[_beneficiary].schedules[_index] = Schedule(_numberOfTokens, 0, 0, _duration, _frequency, _startTime); + schedules[_beneficiary][_index] = Schedule(_numberOfTokens, 0, 0, _duration, _frequency, _startTime); emit ModifySchedule(_beneficiary, _index, _numberOfTokens, _duration, _frequency, _startTime); } @@ -259,12 +253,12 @@ contract VestingEscrowWallet is IWallet { */ function revokeSchedule(address _beneficiary, uint256 _index) external withPerm(ADMIN) { require(_beneficiary != address(0), "Invalid address"); - require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); - Schedule[] storage schedules = dataMap[_beneficiary].schedules; - unassignedTokens = unassignedTokens.add(schedules[_index].numberOfTokens - schedules[_index].releasedTokens); - schedules[_index] = schedules[schedules.length - 1]; - schedules.length--; - if (schedules.length == 0) { + require(_index < schedules[_beneficiary].length, "Schedule not found"); + Schedule[] storage userSchedules = schedules[_beneficiary]; + unassignedTokens = unassignedTokens.add(userSchedules[_index].numberOfTokens - userSchedules[_index].releasedTokens); + userSchedules[_index] = userSchedules[userSchedules.length - 1]; + userSchedules.length--; + if (userSchedules.length == 0) { _revokeSchedules(_beneficiary); } emit RevokeSchedule(_beneficiary, _index); @@ -277,11 +271,11 @@ contract VestingEscrowWallet is IWallet { */ function revokeSchedules(address _beneficiary) public withPerm(ADMIN) { require(_beneficiary != address(0), "Invalid address"); - Data storage data = dataMap[_beneficiary]; - for (uint256 i = 0; i < data.schedules.length; i++) { - unassignedTokens = unassignedTokens.add(data.schedules[i].numberOfTokens - data.schedules[i].releasedTokens); + Schedule[] storage data = schedules[_beneficiary]; + for (uint256 i = 0; i < data.length; i++) { + unassignedTokens = unassignedTokens.add(data[i].numberOfTokens - data[i].releasedTokens); } - delete dataMap[_beneficiary].schedules; + delete schedules[_beneficiary]; _revokeSchedules(_beneficiary); emit RevokeSchedules(_beneficiary); } @@ -294,8 +288,8 @@ contract VestingEscrowWallet is IWallet { */ function getSchedule(address _beneficiary, uint256 _index) external view returns(uint256, uint256, uint256, uint256) { require(_beneficiary != address(0), "Invalid address"); - require(_index < dataMap[_beneficiary].schedules.length, "Schedule not found"); - Schedule storage schedule = dataMap[_beneficiary].schedules[_index]; + require(_index < schedules[_beneficiary].length, "Schedule not found"); + Schedule storage schedule = schedules[_beneficiary][_index]; return ( schedule.numberOfTokens, schedule.duration, @@ -311,7 +305,7 @@ contract VestingEscrowWallet is IWallet { */ function getScheduleCount(address _beneficiary) external view returns(uint256) { require(_beneficiary != address(0), "Invalid address"); - return dataMap[_beneficiary].schedules.length; + return schedules[_beneficiary].length; } /** @@ -326,8 +320,8 @@ contract VestingEscrowWallet is IWallet { function _getAvailableTokens(address _beneficiary) internal view returns(uint256) { require(_beneficiary != address(0)); uint256 availableTokens; - for (uint256 i = 0; i < dataMap[_beneficiary].schedules.length; i++) { - availableTokens = availableTokens.add(dataMap[_beneficiary].schedules[i].availableTokens); + for (uint256 i = 0; i < schedules[_beneficiary].length; i++) { + availableTokens = availableTokens.add(schedules[_beneficiary][i].availableTokens); } return availableTokens; } @@ -439,8 +433,8 @@ contract VestingEscrowWallet is IWallet { function _sendTokens(address _beneficiary) internal { uint256 amount = _getAvailableTokens(_beneficiary); require(amount > 0, "No available tokens"); - for (uint256 i = 0; i < dataMap[_beneficiary].schedules.length; i++) { - dataMap[_beneficiary].schedules[i].availableTokens = 0; + for (uint256 i = 0; i < schedules[_beneficiary].length; i++) { + schedules[_beneficiary][i].availableTokens = 0; } ISecurityToken(securityToken).transfer(_beneficiary, amount); emit SendTokens(_beneficiary, amount); @@ -451,9 +445,9 @@ contract VestingEscrowWallet is IWallet { */ function updateAll() external withPerm(ADMIN) { for (uint256 i = 0; i < beneficiaries.length; i++) { - Data storage data = dataMap[beneficiaries[i]]; - for (uint256 j = 0; j < data.schedules.length; j++) { - Schedule storage schedule = data.schedules[j]; + Schedule[] storage data = schedules[beneficiaries[i]]; + for (uint256 j = 0; j < data.length; j++) { + Schedule storage schedule = data[j]; if (schedule.releasedTokens < schedule.numberOfTokens) { uint256 periodCount = schedule.duration.div(schedule.frequency); /*solium-disable-next-line security/no-block-members*/ @@ -474,13 +468,15 @@ contract VestingEscrowWallet is IWallet { function _revokeSchedules(address _beneficiary) internal { //can be removed if (_getAvailableTokens(_beneficiary) == 0) { - uint256 index = dataMap[_beneficiary].index; + uint256 index; + for (uint256 i = 0; i < beneficiaries.length; i++) { + if (_beneficiary == beneficiaries[i]) { + index = i; + } + } beneficiaries[index] = beneficiaries[beneficiaries.length - 1]; beneficiaries.length--; - if (index != beneficiaries.length) { - dataMap[beneficiaries[index]].index = index; - } - delete dataMap[_beneficiary]; + delete schedules[_beneficiary]; } } From 42e6817b9b8dc5de79e3bbbbfd497b98aec46ae7 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Fri, 23 Nov 2018 12:41:47 +0200 Subject: [PATCH 37/93] refactored revoke methods --- .../modules/Wallet/VestingEscrowWallet.sol | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index a5a6973d1..0a0e463aa 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -254,29 +254,31 @@ contract VestingEscrowWallet is IWallet { function revokeSchedule(address _beneficiary, uint256 _index) external withPerm(ADMIN) { require(_beneficiary != address(0), "Invalid address"); require(_index < schedules[_beneficiary].length, "Schedule not found"); +// _sendTokens(_beneficiary); Schedule[] storage userSchedules = schedules[_beneficiary]; unassignedTokens = unassignedTokens.add(userSchedules[_index].numberOfTokens - userSchedules[_index].releasedTokens); - userSchedules[_index] = userSchedules[userSchedules.length - 1]; + if (_index != userSchedules.length - 1) { + userSchedules[_index] = userSchedules[userSchedules.length - 1]; + } userSchedules.length--; if (userSchedules.length == 0) { - _revokeSchedules(_beneficiary); + _removeBeneficiary(_beneficiary); } emit RevokeSchedule(_beneficiary, _index); } - /** * @notice Revokes all beneficiary's schedules * @param _beneficiary beneficiary's address */ function revokeSchedules(address _beneficiary) public withPerm(ADMIN) { require(_beneficiary != address(0), "Invalid address"); +// _sendTokens(_beneficiary); Schedule[] storage data = schedules[_beneficiary]; for (uint256 i = 0; i < data.length; i++) { unassignedTokens = unassignedTokens.add(data[i].numberOfTokens - data[i].releasedTokens); } - delete schedules[_beneficiary]; - _revokeSchedules(_beneficiary); + _removeBeneficiary(_beneficiary); emit RevokeSchedules(_beneficiary); } @@ -465,19 +467,20 @@ contract VestingEscrowWallet is IWallet { } } - function _revokeSchedules(address _beneficiary) internal { - //can be removed - if (_getAvailableTokens(_beneficiary) == 0) { - uint256 index; - for (uint256 i = 0; i < beneficiaries.length; i++) { - if (_beneficiary == beneficiaries[i]) { - index = i; - } + function _removeBeneficiary(address _beneficiary) internal { + bool isFound = false; + uint256 index; + for (uint256 i = 0; i < beneficiaries.length; i++) { + if (_beneficiary == beneficiaries[i]) { + isFound = true; + index = i; } + } + if (isFound && index != beneficiaries.length - 1) { beneficiaries[index] = beneficiaries[beneficiaries.length - 1]; - beneficiaries.length--; - delete schedules[_beneficiary]; } + beneficiaries.length--; + delete schedules[_beneficiary]; } /** From 210fbb92bd6446c024cf4178115af5b3f2ab2f67 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Fri, 23 Nov 2018 14:39:27 +0200 Subject: [PATCH 38/93] test for pushing during revoking, getState method --- .../modules/Wallet/VestingEscrowWallet.sol | 32 +++-- test/z_vesting_escrow_wallet.js | 131 +++++++++++++----- 2 files changed, 121 insertions(+), 42 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 0a0e463aa..a1d98c7e0 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -30,7 +30,6 @@ contract VestingEscrowWallet is IWallet { } enum State {CREATED, STARTED, COMPLETED} - //TODO add method for getting state address public treasury; uint256 public unassignedTokens; @@ -254,7 +253,7 @@ contract VestingEscrowWallet is IWallet { function revokeSchedule(address _beneficiary, uint256 _index) external withPerm(ADMIN) { require(_beneficiary != address(0), "Invalid address"); require(_index < schedules[_beneficiary].length, "Schedule not found"); -// _sendTokens(_beneficiary); + _sendTokens(_beneficiary); Schedule[] storage userSchedules = schedules[_beneficiary]; unassignedTokens = unassignedTokens.add(userSchedules[_index].numberOfTokens - userSchedules[_index].releasedTokens); if (_index != userSchedules.length - 1) { @@ -273,7 +272,7 @@ contract VestingEscrowWallet is IWallet { */ function revokeSchedules(address _beneficiary) public withPerm(ADMIN) { require(_beneficiary != address(0), "Invalid address"); -// _sendTokens(_beneficiary); + _sendTokens(_beneficiary); Schedule[] storage data = schedules[_beneficiary]; for (uint256 i = 0; i < data.length; i++) { unassignedTokens = unassignedTokens.add(data[i].numberOfTokens - data[i].releasedTokens); @@ -288,7 +287,7 @@ contract VestingEscrowWallet is IWallet { * @param _index index of the schedule * @return beneficiary's schedule */ - function getSchedule(address _beneficiary, uint256 _index) external view returns(uint256, uint256, uint256, uint256) { + function getSchedule(address _beneficiary, uint256 _index) external view returns(uint256, uint256, uint256, uint256, State) { require(_beneficiary != address(0), "Invalid address"); require(_index < schedules[_beneficiary].length, "Schedule not found"); Schedule storage schedule = schedules[_beneficiary][_index]; @@ -296,10 +295,22 @@ contract VestingEscrowWallet is IWallet { schedule.numberOfTokens, schedule.duration, schedule.frequency, - schedule.startTime + schedule.startTime, + _getScheduleState(_beneficiary, _index) ); } + function _getScheduleState(address _beneficiary, uint256 _index) internal view returns(State) { + Schedule memory schedule = schedules[_beneficiary][_index]; + if (now < schedule.startTime) { + return State.CREATED; + } else if (now > schedule.startTime && now < schedule.startTime.add(schedule.duration)) { + return State.STARTED; + } else { + return State.COMPLETED; + } + } + /** * @notice Returns count of beneficiary's schedules * @param _beneficiary beneficiary's address @@ -434,12 +445,13 @@ contract VestingEscrowWallet is IWallet { function _sendTokens(address _beneficiary) internal { uint256 amount = _getAvailableTokens(_beneficiary); - require(amount > 0, "No available tokens"); - for (uint256 i = 0; i < schedules[_beneficiary].length; i++) { - schedules[_beneficiary][i].availableTokens = 0; + if (amount > 0) { + for (uint256 i = 0; i < schedules[_beneficiary].length; i++) { + schedules[_beneficiary][i].availableTokens = 0; + } + ISecurityToken(securityToken).transfer(_beneficiary, amount); + emit SendTokens(_beneficiary, amount); } - ISecurityToken(securityToken).transfer(_beneficiary, amount); - emit SendTokens(_beneficiary, amount); } /** diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 318600a9c..ae2866075 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -17,6 +17,8 @@ const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); contract('VestingEscrowWallet', accounts => { const CREATED = 0; + const STARTED = 1; + const COMPLETED = 2; // Accounts Variable declaration let account_polymath; @@ -298,12 +300,6 @@ contract('VestingEscrowWallet', accounts => { assert.equal(balance.toNumber(), 0); }); - it("Should fail to push available tokens -- fail because beneficiary doesn't have available tokens", async () => { - catchRevert( - I_VestingEscrowWallet.pushAvailableTokens(account_beneficiary3, {from: wallet_admin}) - ); - }); - it("Should send available tokens to the beneficiary address", async () => { let numberOfTokens = 75000; let duration = durationUtil.seconds(30); @@ -359,12 +355,15 @@ contract('VestingEscrowWallet', accounts => { let balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); assert.equal(balance.toNumber(), numberOfTokens); + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary3, 0); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, COMPLETED); + await I_SecurityToken.transfer(token_owner, balance, {from: account_beneficiary3}); await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); - it("Should withdraw available tokens by 2 schedules to the beneficiary address", async () => { + it("Should withdraw available tokens 2 times by 3 schedules to the beneficiary address", async () => { let schedules = [ { numberOfTokens: 100000, @@ -405,13 +404,23 @@ contract('VestingEscrowWallet', accounts => { let balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); assert.equal(balance.toNumber(), numberOfTokens); + stepCount = 4; + await increaseTime(durationUtil.minutes(stepCount) + durationUtil.seconds(100)); + await I_VestingEscrowWallet.updateAll({from: wallet_admin}); + + numberOfTokens = (2000 / 10 * stepCount); + const tx2 = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); + assert.equal(tx2.logs[0].args._beneficiary, account_beneficiary3); + assert.equal(tx2.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); + + balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); + assert.equal(balance.toNumber(), totalNumberOfTokens); + await I_SecurityToken.transfer(token_owner, balance, {from: account_beneficiary3}); await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); - //TODO add test like previous one, but with withdrawing tokens - }); describe("Adding, modifying and revoking vesting schedule", async () => { @@ -508,7 +517,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); - checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); }); it("Should add vesting schedule without depositing to the beneficiary address", async () => { @@ -526,7 +535,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 2); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 1); - checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 1, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); @@ -555,7 +564,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); - checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); assert.equal(unassignedTokens.toNumber(), schedules[0].numberOfTokens - schedules[1].numberOfTokens); @@ -578,12 +587,23 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); - checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); assert.equal(unassignedTokens.toNumber(), 0); }); + it("Should revoke vesting schedule from the beneficiary address", async () => { + const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_admin}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + + assert.equal(tx.logs[0].args._beneficiary, account_beneficiary1); + assert.equal(tx.logs[0].args._index, 0); + + let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); + assert.equal(scheduleCount, 0); + }); + it("Should fail to revoke vesting schedule -- fail because address is invalid", async () => { await catchRevert( I_VestingEscrowWallet.revokeSchedule(0, 0, {from: wallet_admin}) @@ -596,17 +616,6 @@ contract('VestingEscrowWallet', accounts => { ); }); - it("Should revoke vesting schedule from the beneficiary address", async () => { - const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_admin}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); - - assert.equal(tx.logs[0].args._beneficiary, account_beneficiary1); - assert.equal(tx.logs[0].args._index, 0); - - let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); - assert.equal(scheduleCount, 0); - }); - it("Should fail to revoke vesting schedules -- fail because address is invalid", async () => { await catchRevert( I_VestingEscrowWallet.revokeSchedules(0, {from: wallet_admin}) @@ -630,7 +639,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, i + 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, i); - checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); } }); @@ -645,7 +654,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 2); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, 1); - checkSchedule(schedule, schedules[2].numberOfTokens, schedules[2].duration, schedules[2].frequency, schedules[2].startTime); + checkSchedule(schedule, schedules[2].numberOfTokens, schedules[2].duration, schedules[2].frequency, schedules[2].startTime, CREATED); }); it("Should revoke 2 vesting schedules from the beneficiary address", async () => { @@ -658,6 +667,63 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 0); }); + it("Should push available tokens during revoking vesting schedule", async () => { + let schedules = [ + { + numberOfTokens: 100000, + duration: durationUtil.minutes(4), + frequency: durationUtil.minutes(1) + }, + { + numberOfTokens: 30000, + duration: durationUtil.minutes(6), + frequency: durationUtil.minutes(1) + }, + { + numberOfTokens: 2000, + duration: durationUtil.minutes(10), + frequency: durationUtil.minutes(1) + } + ]; + + let totalNumberOfTokens = getTotalNumberOfTokens(schedules); + await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); + for (let i = 0; i < schedules.length; i++) { + let numberOfTokens = schedules[i].numberOfTokens; + let duration = schedules[i].duration; + let frequency = schedules[i].frequency; + let startTime = latestTime() + durationUtil.seconds(100); + await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + } + let stepCount = 6; + await increaseTime(durationUtil.minutes(stepCount) + durationUtil.seconds(100)); + await I_VestingEscrowWallet.updateAll({from: wallet_admin}); + + let numberOfTokens = 100000 + (30000 / 6 * stepCount) + (2000 / 10 * stepCount); + const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary3, 0, {from: wallet_admin}); + assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); + assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); + + let balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); + assert.equal(balance.toNumber(), numberOfTokens); + + stepCount = 4; + await increaseTime(durationUtil.minutes(stepCount) + durationUtil.seconds(100)); + await I_VestingEscrowWallet.updateAll({from: wallet_admin}); + + numberOfTokens = (2000 / 10 * stepCount); + const tx2 = await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_admin}); + assert.equal(tx2.logs[0].args._beneficiary, account_beneficiary3); + assert.equal(tx2.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); + + balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); + assert.equal(balance.toNumber(), totalNumberOfTokens); + + await I_SecurityToken.transfer(token_owner, balance, {from: account_beneficiary3}); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + }); + }); describe("Adding, using and removing templates", async () => { @@ -724,7 +790,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); - checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); @@ -769,11 +835,11 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); - checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); } }); - it("Should modify vesting schedule for 3 beneficiary's addresses", async () => { + it("Should not be able modify vesting schedule for 3 beneficiary's addresses", async () => { let numberOfTokens = 25000; let duration = durationUtil.seconds(50); let frequency = durationUtil.seconds(10); @@ -806,7 +872,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); - checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, STARTED); } let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); @@ -862,7 +928,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount.toNumber(), 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); - checkSchedule(schedule, numberOfTokens, duration, frequency, startTime); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); } }); @@ -994,11 +1060,12 @@ function checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, assert.equal(log.args._startTime.toNumber(), startTime); } -function checkSchedule(schedule, numberOfTokens, duration, frequency, startTime) { +function checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, state) { assert.equal(schedule[0].toNumber(), numberOfTokens); assert.equal(schedule[1].toNumber(), duration); assert.equal(schedule[2].toNumber(), frequency); assert.equal(schedule[3].toNumber(), startTime); + assert.equal(schedule[4].toNumber(), state); } function getTotalNumberOfTokens(schedules) { From baf0ec962bc64cc2a6b352ece2890dd795f7ee67 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Fri, 23 Nov 2018 16:52:04 +0200 Subject: [PATCH 39/93] fixed coverage failure --- test/z_vesting_escrow_wallet.js | 229 +++++++++++++++++--------------- 1 file changed, 125 insertions(+), 104 deletions(-) diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index ae2866075..ed5998751 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -1,7 +1,7 @@ import {deployGPMAndVerifyed, deployVestingEscrowWalletAndVerifyed, setUpPolymathNetwork} from "./helpers/createInstances"; import latestTime from "./helpers/latestTime"; import {duration as durationUtil, latestBlock, promisifyLogWatch} from "./helpers/utils"; -import {catchPermission, catchRevert} from "./helpers/exceptions"; +import {catchRevert} from "./helpers/exceptions"; import {increaseTime} from "./helpers/time"; import {encodeModuleCall} from "./helpers/encodeCall"; @@ -273,6 +273,14 @@ contract('VestingEscrowWallet', accounts => { ); }); + it("Should not be able to deposit -- fail because of permissions check", async () => { + let numberOfTokens = 25000; + await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); + await catchRevert( + I_VestingEscrowWallet.depositTokens(25000, {from: account_beneficiary1}) + ); + }); + it("Should deposit tokens for new vesting schedules", async () => { let numberOfTokens = 25000; await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); @@ -287,6 +295,12 @@ contract('VestingEscrowWallet', accounts => { assert.equal(balance.toNumber(), numberOfTokens); }); + it("Should not be able to withdraw tokens to a treasury -- fail because of permissions check", async () => { + await catchRevert( + I_VestingEscrowWallet.sendToTreasury({from: account_beneficiary1}) + ); + }); + it("Should withdraw tokens to a treasury", async () => { let numberOfTokens = 25000; const tx = await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); @@ -300,7 +314,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(balance.toNumber(), 0); }); - it("Should send available tokens to the beneficiary address", async () => { + it("Should not be able to push available tokens -- fail because of permissions check", async () => { let numberOfTokens = 75000; let duration = durationUtil.seconds(30); let frequency = durationUtil.seconds(10); @@ -312,6 +326,19 @@ contract('VestingEscrowWallet', accounts => { await increaseTime(timeShift + frequency); await I_VestingEscrowWallet.updateAll({from: wallet_admin}); + await catchRevert( + I_VestingEscrowWallet.pushAvailableTokens(account_beneficiary3, {from: account_beneficiary1}) + ); + }); + + it("Should not be able update all schedules -- fail because of permissions check", async () => { + await catchRevert( + I_VestingEscrowWallet.updateAll({from: account_beneficiary1}) + ); + }); + + it("Should push available tokens to the beneficiary address", async () => { + let numberOfTokens = 75000; const tx = await I_VestingEscrowWallet.pushAvailableTokens(account_beneficiary3, {from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens / 3); @@ -446,8 +473,6 @@ contract('VestingEscrowWallet', accounts => { } ]; - //TODO add test for checking pushing during revoking - it("Should fail to add vesting schedule to the beneficiary address -- fail because address in invalid", async () => { await catchRevert( I_VestingEscrowWallet.addSchedule(0, 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) @@ -502,6 +527,19 @@ contract('VestingEscrowWallet', accounts => { ); }); + it("Should not be able to add schedule -- fail because of permissions check", async () => { + let numberOfTokens = schedules[0].numberOfTokens; + let duration = schedules[0].duration; + let frequency = schedules[0].frequency; + let startTime = schedules[0].startTime; + await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); + await catchRevert( + I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: account_beneficiary1}) + ); + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + }); + it("Should add vesting schedule to the beneficiary address", async () => { let numberOfTokens = schedules[0].numberOfTokens; let duration = schedules[0].duration; @@ -551,6 +589,12 @@ contract('VestingEscrowWallet', accounts => { ); }); + it("Should not be able to modify schedule -- fail because of permissions check", async () => { + await catchRevert( + I_VestingEscrowWallet.modifySchedule(account_beneficiary1, 0, 10000, 4, 1, latestTime() + 100, {from: account_beneficiary1}) + ); + }); + it("Should modify vesting schedule for the beneficiary's address", async () => { let numberOfTokens = schedules[1].numberOfTokens; let duration = schedules[1].duration; @@ -593,6 +637,12 @@ contract('VestingEscrowWallet', accounts => { assert.equal(unassignedTokens.toNumber(), 0); }); + it("Should not be able to revoke schedule -- fail because of permissions check", async () => { + await catchRevert( + I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: account_beneficiary1}) + ); + }); + it("Should revoke vesting schedule from the beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); @@ -643,6 +693,12 @@ contract('VestingEscrowWallet', accounts => { } }); + it("Should not be able to revoke schedules -- fail because of permissions check", async () => { + await catchRevert( + I_VestingEscrowWallet.revokeSchedules(account_beneficiary1, {from: account_beneficiary1}) + ); + }); + it("Should revoke vesting schedule from the beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary2, 1, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); @@ -749,6 +805,12 @@ contract('VestingEscrowWallet', accounts => { } ]; + it("Should not be able to add template -- fail because of permissions check", async () => { + await catchRevert( + I_VestingEscrowWallet.addTemplate(25000, 4, 1, {from: account_beneficiary1}) + ); + }); + it("Should add 3 Templates", async () => { for (let i = 0; i < schedules.length; i++) { let numberOfTokens = schedules[i].numberOfTokens; @@ -762,6 +824,12 @@ contract('VestingEscrowWallet', accounts => { } }); + it("Should not be able to remove template -- fail because of permissions check", async () => { + await catchRevert( + I_VestingEscrowWallet.removeTemplate(1, {from: account_beneficiary1}) + ); + }); + it("Should remove template", async () => { const tx = await I_VestingEscrowWallet.removeTemplate(1, {from: wallet_admin}); @@ -775,6 +843,12 @@ contract('VestingEscrowWallet', accounts => { ); }); + it("Should not be able to add schedule from template -- fail because of permissions check", async () => { + await catchRevert( + I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 0, latestTime(), {from: account_beneficiary1}) + ); + }); + it("Should add vesting schedule from template", async () => { let numberOfTokens = schedules[2].numberOfTokens; let duration = schedules[2].duration; @@ -814,6 +888,12 @@ contract('VestingEscrowWallet', accounts => { describe("Tests for multi operations", async () => { + it("Should not be able to add schedules to the beneficiaries -- fail because of permissions check", async () => { + await catchRevert( + I_VestingEscrowWallet.addScheduleMulti([account_beneficiary1], 10000, 4, 1, latestTime() + 100, {from: account_beneficiary1}) + ); + }); + it("Should add schedules for 3 beneficiaries", async () => { let numberOfTokens = 30000; let duration = durationUtil.weeks(4); @@ -852,6 +932,19 @@ contract('VestingEscrowWallet', accounts => { ); }); + it("Should not be able to modify schedules for the beneficiaries -- fail because of permissions check", async () => { + let numberOfTokens = 25000; + let duration = durationUtil.seconds(50); + let frequency = durationUtil.seconds(10); + let timeShift = durationUtil.seconds(100); + let startTime = latestTime() + timeShift; + + let indexes = [0, 0, 0]; + await catchRevert( + I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: account_beneficiary1}) + ); + }); + it("Should modify vesting schedule for 3 beneficiary's addresses", async () => { let numberOfTokens = 25000; let duration = durationUtil.seconds(50); @@ -885,6 +978,12 @@ contract('VestingEscrowWallet', accounts => { ); }); + it("Should not be able to send available tokens to the beneficiaries -- fail because of permissions check", async () => { + await catchRevert( + I_VestingEscrowWallet.pushAvailableTokensMulti([account_beneficiary1], {from: account_beneficiary1}) + ); + }); + it("Should send available tokens to the beneficiaries addresses", async () => { await I_VestingEscrowWallet.updateAll({from: wallet_admin}); @@ -905,6 +1004,22 @@ contract('VestingEscrowWallet', accounts => { } }); + it("Should not be able to add schedules from template to the beneficiaries -- fail because of permissions check", async () => { + let numberOfTokens = 18000; + let duration = durationUtil.weeks(3); + let frequency = durationUtil.weeks(1); + let startTime = latestTime() + durationUtil.seconds(100); + + let totalNumberOfTokens = numberOfTokens * 3; + await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_admin}); + + await catchRevert( + I_VestingEscrowWallet.addScheduleFromTemplateMulti([account_beneficiary1, account_beneficiary2], 0, startTime, {from: account_beneficiary1}) + ); + }); + it("Should add schedules from template for 3 beneficiaries", async () => { let numberOfTokens = 18000; let duration = durationUtil.weeks(3); @@ -933,6 +1048,12 @@ contract('VestingEscrowWallet', accounts => { }); + it("Should not be able to revoke schedules of the beneficiaries -- fail because of permissions check", async () => { + await catchRevert( + I_VestingEscrowWallet.revokeSchedulesMulti([account_beneficiary1], {from: account_beneficiary1}) + ); + }); + it("Should revoke vesting schedule from the 3 beneficiary's addresses", async () => { const tx = await I_VestingEscrowWallet.revokeSchedulesMulti(beneficiaries, {from: wallet_admin}); @@ -950,106 +1071,6 @@ contract('VestingEscrowWallet', accounts => { }); - describe("Check permissions", async () => { - - it("Should not be able to deposit", async () => { - await catchPermission( - I_VestingEscrowWallet.depositTokens(25000, {from: account_beneficiary1}) - ); - }); - - it("Should not be able to withdraw tokens to a treasury", async () => { - await catchPermission( - I_VestingEscrowWallet.sendToTreasury({from: account_beneficiary1}) - ); - }); - - it("Should not be able to send available tokens", async () => { - await catchPermission( - I_VestingEscrowWallet.pushAvailableTokens(account_beneficiary3, {from: account_beneficiary1}) - ); - }); - - it("Should not be able to add template", async () => { - await catchPermission( - I_VestingEscrowWallet.addTemplate(25000, 4, 1, {from: account_beneficiary1}) - ); - }); - - it("Should not be able to remove template", async () => { - await catchPermission( - I_VestingEscrowWallet.removeTemplate(0, {from: account_beneficiary1}) - ); - }); - - it("Should not be able to add schedule", async () => { - await catchPermission( - I_VestingEscrowWallet.addSchedule(account_beneficiary1, 10000, 4, 1, latestTime(), {from: account_beneficiary1}) - ); - }); - - it("Should not be able to add schedule from template", async () => { - await catchPermission( - I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 0, latestTime(), {from: account_beneficiary1}) - ); - }); - - it("Should not be able to modify schedule", async () => { - await catchPermission( - I_VestingEscrowWallet.modifySchedule(account_beneficiary1, 0, 10000, 4, 1, latestTime(), {from: account_beneficiary1}) - ); - }); - - it("Should not be able to revoke schedule", async () => { - await catchPermission( - I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: account_beneficiary1}) - ); - }); - - it("Should not be able to revoke schedules", async () => { - await catchPermission( - I_VestingEscrowWallet.revokeSchedules(account_beneficiary1, {from: account_beneficiary1}) - ); - }); - - it("Should not be able to send available tokens to the beneficiaries", async () => { - await catchPermission( - I_VestingEscrowWallet.pushAvailableTokensMulti([account_beneficiary1], {from: account_beneficiary1}) - ); - }); - - it("Should not be able to add schedules to the beneficiaries", async () => { - await catchPermission( - I_VestingEscrowWallet.addScheduleMulti([account_beneficiary1], 10000, 4, 1, latestTime(), {from: account_beneficiary1}) - ); - }); - - it("Should not be able to add schedules from template to the beneficiaries", async () => { - await catchPermission( - I_VestingEscrowWallet.addScheduleFromTemplateMulti([account_beneficiary1], 0, latestTime(), {from: account_beneficiary1}) - ); - }); - - it("Should not be able to revoke schedules of the beneficiaries", async () => { - await catchPermission( - I_VestingEscrowWallet.revokeSchedulesMulti([account_beneficiary1], {from: account_beneficiary1}) - ); - }); - - it("Should not be able to modify schedules for the beneficiaries", async () => { - await catchPermission( - I_VestingEscrowWallet.modifyScheduleMulti([account_beneficiary1], [0], 10000, 4, 1, latestTime(), {from: account_beneficiary1}) - ); - }); - - it("Should not be able update all schedules", async () => { - await catchPermission( - I_VestingEscrowWallet.updateAll({from: account_beneficiary1}) - ); - }); - - }); - }); function checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTime) { From bd0f693f4aa271ecf5379ea839bba7fbab5305d5 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Fri, 23 Nov 2018 20:53:16 +0200 Subject: [PATCH 40/93] test for factory --- test/z_vesting_escrow_wallet.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index ed5998751..9728f0140 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -263,6 +263,13 @@ contract('VestingEscrowWallet', accounts => { assert.equal(web3.utils.toAscii(tags[1]).replace(/\u0000/g, ""), "Escrow"); }); + it("Should get the instructions of the factory", async () => { + assert.equal( + (await I_VestingEscrowWalletFactory.getInstructions.call()).replace(/\u0000/g, ""), + "Issuer can send tokens to and then select the address that would be able to withdraw them according to their specific vesting schedule." + + ""); + }); + }); describe("Depositing and withdrawing tokens", async () => { From 4c0f8de9c3fafd8f5ed6e580dc903ff99ebee95d Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sat, 24 Nov 2018 17:11:10 +0000 Subject: [PATCH 41/93] WIP --- .../GeneralTransferManager.sol | 83 +++++++++++-------- test/h_general_transfer_manager.js | 38 ++++----- test/helpers/signData.js | 2 +- truffle-config.js | 2 +- 4 files changed, 71 insertions(+), 54 deletions(-) diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index 814d54d7b..eea89494d 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -21,17 +21,30 @@ contract GeneralTransferManager is ITransferManager { //from and to timestamps that an investor can send / receive tokens respectively struct TimeRestriction { - uint256 fromTime; - uint256 toTime; - uint256 expiryTime; - bool canBuyFromSTO; + uint64 fromTime; + uint64 toTime; + uint64 expiryTime; + uint8 canBuyFromSTO; + uint8 added; } + // Allows all TimeRestrictions to be offset + struct Offset { + uint64 offset; + uint8 isForward; + } + + // Offset to be applied to all timings (except KYC expiry) + Offset public offset; + + // List of all addresses that have been added to the GTM at some point + address[] public investors; + // An address can only send / receive tokens once their corresponding uint256 > block.number // (unless allowAllTransfers == true or allowAllWhitelistTransfers == true) mapping (address => TimeRestriction) public whitelist; // Map of used nonces by customer - mapping(address => mapping(uint256 => bool)) public nonceMap; + mapping(address => mapping(uint256 => bool)) public nonceMap; //If true, there are no transfer restrictions, for any addresses bool public allowAllTransfers = false; @@ -59,10 +72,10 @@ contract GeneralTransferManager is ITransferManager { address _investor, uint256 _dateAdded, address _addedBy, - uint256 _fromTime, - uint256 _toTime, - uint256 _expiryTime, - bool _canBuyFromSTO + uint64 _fromTime, + uint64 _toTime, + uint64 _expiryTime, + uint8 _canBuyFromSTO ); /** @@ -169,15 +182,15 @@ contract GeneralTransferManager is ITransferManager { return (_onWhitelist(_to) && _onWhitelist(_from)) ? Result.VALID : Result.NA; } if (allowAllWhitelistIssuances && _from == issuanceAddress) { - if (!whitelist[_to].canBuyFromSTO && _isSTOAttached()) { + if ((whitelist[_to].canBuyFromSTO == 0) && _isSTOAttached()) { return Result.NA; } return _onWhitelist(_to) ? Result.VALID : Result.NA; } //Anyone on the whitelist can transfer provided the blocknumber is large enough /*solium-disable-next-line security/no-block-members*/ - return ((_onWhitelist(_from) && whitelist[_from].fromTime <= now) && - (_onWhitelist(_to) && whitelist[_to].toTime <= now)) ? Result.VALID : Result.NA; /*solium-disable-line security/no-block-members*/ + return ((_onWhitelist(_from) && whitelist[_from].fromTime <= uint64(now)) && + (_onWhitelist(_to) && whitelist[_to].toTime <= uint64(now))) ? Result.VALID : Result.NA; /*solium-disable-line security/no-block-members*/ } return Result.NA; } @@ -192,16 +205,18 @@ contract GeneralTransferManager is ITransferManager { */ function modifyWhitelist( address _investor, - uint256 _fromTime, - uint256 _toTime, - uint256 _expiryTime, - bool _canBuyFromSTO + uint64 _fromTime, + uint64 _toTime, + uint64 _expiryTime, + uint8 _canBuyFromSTO ) public withPerm(WHITELIST) { - //Passing a _time == 0 into this function, is equivalent to removing the _investor from the whitelist - whitelist[_investor] = TimeRestriction(_fromTime, _toTime, _expiryTime, _canBuyFromSTO); + if (whitelist[_investor].added == uint8(0)) { + investors.push(_investor); + } + whitelist[_investor] = TimeRestriction(_fromTime, _toTime, _expiryTime, _canBuyFromSTO, uint8(1)); /*solium-disable-next-line security/no-block-members*/ emit ModifyWhitelist(_investor, now, msg.sender, _fromTime, _toTime, _expiryTime, _canBuyFromSTO); } @@ -216,10 +231,10 @@ contract GeneralTransferManager is ITransferManager { */ function modifyWhitelistMulti( address[] _investors, - uint256[] _fromTimes, - uint256[] _toTimes, - uint256[] _expiryTimes, - bool[] _canBuyFromSTO + uint64[] _fromTimes, + uint64[] _toTimes, + uint64[] _expiryTimes, + uint8[] _canBuyFromSTO ) public withPerm(WHITELIST) { require(_investors.length == _fromTimes.length, "Mismatched input lengths"); require(_fromTimes.length == _toTimes.length, "Mismatched input lengths"); @@ -246,29 +261,31 @@ contract GeneralTransferManager is ITransferManager { */ function modifyWhitelistSigned( address _investor, - uint256 _fromTime, - uint256 _toTime, - uint256 _expiryTime, - bool _canBuyFromSTO, - uint256 _validFrom, - uint256 _validTo, + uint64 _fromTime, + uint64 _toTime, + uint64 _expiryTime, + uint8 _canBuyFromSTO, + uint64 _validFrom, + uint64 _validTo, uint256 _nonce, uint8 _v, bytes32 _r, bytes32 _s ) public { /*solium-disable-next-line security/no-block-members*/ - require(_validFrom <= now, "ValidFrom is too early"); + require(_validFrom <= uint64(now), "ValidFrom is too early"); /*solium-disable-next-line security/no-block-members*/ - require(_validTo >= now, "ValidTo is too late"); + require(_validTo >= uint64(now), "ValidTo is too late"); require(!nonceMap[_investor][_nonce], "Already used signature"); nonceMap[_investor][_nonce] = true; bytes32 hash = keccak256( abi.encodePacked(this, _investor, _fromTime, _toTime, _expiryTime, _canBuyFromSTO, _validFrom, _validTo, _nonce) ); _checkSig(hash, _v, _r, _s); - //Passing a _time == 0 into this function, is equivalent to removing the _investor from the whitelist - whitelist[_investor] = TimeRestriction(_fromTime, _toTime, _expiryTime, _canBuyFromSTO); + if (whitelist[_investor].added == uint8(0)) { + investors.push(_investor); + } + whitelist[_investor] = TimeRestriction(_fromTime, _toTime, _expiryTime, _canBuyFromSTO, uint8(1)); /*solium-disable-next-line security/no-block-members*/ emit ModifyWhitelist(_investor, now, msg.sender, _fromTime, _toTime, _expiryTime, _canBuyFromSTO); } @@ -290,7 +307,7 @@ contract GeneralTransferManager is ITransferManager { */ function _onWhitelist(address _investor) internal view returns(bool) { return (((whitelist[_investor].fromTime != 0) || (whitelist[_investor].toTime != 0)) && - (whitelist[_investor].expiryTime >= now)); /*solium-disable-line security/no-block-members*/ + (whitelist[_investor].expiryTime >= uint64(now))); /*solium-disable-line security/no-block-members*/ } /** diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 3e060c288..b7f14ed31 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -150,7 +150,7 @@ contract("GeneralTransferManager", accounts => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); - + console.log(JSON.stringify(tx)); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); @@ -187,7 +187,7 @@ contract("GeneralTransferManager", accounts => { [latestTime() + duration.days(30), latestTime() + duration.days(30)], [latestTime() + duration.days(90), latestTime() + duration.days(90)], [latestTime() + duration.years(1), latestTime() + duration.years(1)], - [false, false], + [0, 0], { from: account_issuer, gas: 6000000 @@ -291,7 +291,7 @@ contract("GeneralTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 6000000 @@ -320,7 +320,7 @@ contract("GeneralTransferManager", accounts => { it("Should fail in buying the tokens from the STO -- because amount is 0", async() => { await catchRevert( I_DummySTO.generateTokens(account_investor1, 0, { from: token_owner }) - ); + ); }); it("Should fail in buying the tokens from the STO -- because STO is paused", async() => { @@ -359,7 +359,7 @@ contract("GeneralTransferManager", accounts => { fromTime, toTime, expiryTime, - true, + 1, validFrom, validTo, nonce, @@ -376,7 +376,7 @@ contract("GeneralTransferManager", accounts => { fromTime, toTime, expiryTime, - true, + 1, validFrom, validTo, nonce, @@ -403,7 +403,7 @@ contract("GeneralTransferManager", accounts => { fromTime, toTime, expiryTime, - true, + 1, validFrom, validTo, nonce, @@ -420,7 +420,7 @@ contract("GeneralTransferManager", accounts => { fromTime, toTime, expiryTime, - true, + 1, validFrom, validTo, nonce, @@ -447,7 +447,7 @@ contract("GeneralTransferManager", accounts => { fromTime, toTime, expiryTime, - true, + 1, validFrom, validTo, nonce, @@ -464,7 +464,7 @@ contract("GeneralTransferManager", accounts => { fromTime, toTime, expiryTime, - true, + 1, validFrom, validTo, nonce, @@ -491,7 +491,7 @@ contract("GeneralTransferManager", accounts => { latestTime(), latestTime() + duration.days(80), expiryTime + duration.days(200), - true, + 1, validFrom, validTo, nonce, @@ -507,7 +507,7 @@ contract("GeneralTransferManager", accounts => { latestTime(), latestTime() + duration.days(80), expiryTime + duration.days(200), - true, + 1, validFrom, validTo, nonce, @@ -547,7 +547,7 @@ contract("GeneralTransferManager", accounts => { latestTime(), latestTime() + duration.days(80), expiryTime + duration.days(200), - true, + 1, validFrom, validTo, nonce, @@ -563,7 +563,7 @@ contract("GeneralTransferManager", accounts => { latestTime(), latestTime() + duration.days(80), expiryTime + duration.days(200), - true, + 1, validFrom, validTo, nonce, @@ -670,7 +670,7 @@ contract("GeneralTransferManager", accounts => { [fromTime, fromTime], [toTime, toTime], [expiryTime, expiryTime], - [true, true], + [1, 1], { from: account_delegate, gas: 6000000 @@ -690,7 +690,7 @@ contract("GeneralTransferManager", accounts => { [fromTime], [toTime, toTime], [expiryTime, expiryTime], - [true, true], + [1, 1], { from: account_delegate, gas: 6000000 @@ -710,7 +710,7 @@ contract("GeneralTransferManager", accounts => { [fromTime, fromTime], [toTime], [expiryTime, expiryTime], - [true, true], + [1, 1], { from: account_delegate, gas: 6000000 @@ -730,7 +730,7 @@ contract("GeneralTransferManager", accounts => { [fromTime, fromTime], [toTime, toTime], [expiryTime], - [true, true], + [1, 1], { from: account_delegate, gas: 6000000 @@ -749,7 +749,7 @@ contract("GeneralTransferManager", accounts => { [fromTime, fromTime], [toTime, toTime], [expiryTime, expiryTime], - [true, true], + [1, 1], { from: token_owner, gas: 6000000 diff --git a/test/helpers/signData.js b/test/helpers/signData.js index ea7476cc3..2e5c1ad61 100644 --- a/test/helpers/signData.js +++ b/test/helpers/signData.js @@ -6,7 +6,7 @@ const ethUtil = require("ethereumjs-util"); function signData(tmAddress, investorAddress, fromTime, toTime, expiryTime, restricted, validFrom, validTo, nonce, pk) { let packedData = utils .solidityKeccak256( - ["address", "address", "uint256", "uint256", "uint256", "bool", "uint256", "uint256", "uint256"], + ["address", "address", "uint64", "uint64", "uint64", "uint8", "uint64", "uint64", "uint256"], [tmAddress, investorAddress, fromTime, toTime, expiryTime, restricted, validFrom, validTo, nonce] ) .slice(2); diff --git a/truffle-config.js b/truffle-config.js index c993327ea..2a84351bd 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -11,7 +11,7 @@ module.exports = { host: 'localhost', port: 8545, network_id: '*', // Match any network id - gas: 7900000, + gas: 9000000, }, mainnet: { host: 'localhost', From 191b788617ae16719267cd0d2dd557bacdb7b29f Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sat, 24 Nov 2018 21:07:49 +0000 Subject: [PATCH 42/93] WIP --- contracts/modules/Module.sol | 19 ++---- contracts/modules/ModuleStorage.sol | 30 ++++++++++ .../GeneralTransferManager.sol | 59 +------------------ .../GeneralTransferManagerFactory.sol | 9 ++- .../GeneralTransferManagerStorage.sol | 55 +++++++++++++++++ .../proxy/GeneralTransferManagerProxy.sol | 47 +++++++++++++++ migrations/2_deploy_contracts.js | 8 ++- test/helpers/createInstances.js | 20 ++++++- 8 files changed, 169 insertions(+), 78 deletions(-) create mode 100644 contracts/modules/ModuleStorage.sol create mode 100644 contracts/modules/TransferManager/GeneralTransferManagerStorage.sol create mode 100644 contracts/proxy/GeneralTransferManagerProxy.sol diff --git a/contracts/modules/Module.sol b/contracts/modules/Module.sol index aa3e6d865..1566a3428 100644 --- a/contracts/modules/Module.sol +++ b/contracts/modules/Module.sol @@ -2,32 +2,23 @@ pragma solidity ^0.4.24; import "../interfaces/IModule.sol"; import "../interfaces/ISecurityToken.sol"; -import "../interfaces/IERC20.sol"; +import "./ModuleStorage.sol"; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; /** * @title Interface that any module contract should implement * @notice Contract is abstract */ -contract Module is IModule { - - address public factory; - - address public securityToken; - - bytes32 public constant FEE_ADMIN = "FEE_ADMIN"; - - IERC20 public polyToken; +contract Module is IModule, ModuleStorage { /** * @notice Constructor * @param _securityToken Address of the security token * @param _polyAddress Address of the polytoken */ - constructor (address _securityToken, address _polyAddress) public { - securityToken = _securityToken; - factory = msg.sender; - polyToken = IERC20(_polyAddress); + constructor (address _securityToken, address _polyAddress) public + ModuleStorage(_securityToken, _polyAddress) + { } //Allows owner, factory or permissioned delegate diff --git a/contracts/modules/ModuleStorage.sol b/contracts/modules/ModuleStorage.sol new file mode 100644 index 000000000..cd52c9de2 --- /dev/null +++ b/contracts/modules/ModuleStorage.sol @@ -0,0 +1,30 @@ +pragma solidity ^0.4.24; + +import "../interfaces/IERC20.sol"; + +/** + * @title Storage for Module contract + * @notice Contract is abstract + */ +contract ModuleStorage { + + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + */ + constructor (address _securityToken, address _polyAddress) public { + securityToken = _securityToken; + factory = msg.sender; + polyToken = IERC20(_polyAddress); + } + + address public factory; + + address public securityToken; + + bytes32 public constant FEE_ADMIN = "FEE_ADMIN"; + + IERC20 public polyToken; + +} diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index eea89494d..247ac8374 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -1,60 +1,16 @@ pragma solidity ^0.4.24; import "./ITransferManager.sol"; +import "./GeneralTransferManagerStorage.sol"; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; /** * @title Transfer Manager module for core transfer validation functionality */ -contract GeneralTransferManager is ITransferManager { +contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManager { using SafeMath for uint256; - //Address from which issuances come - address public issuanceAddress = address(0); - - //Address which can sign whitelist changes - address public signingAddress = address(0); - - bytes32 public constant WHITELIST = "WHITELIST"; - bytes32 public constant FLAGS = "FLAGS"; - - //from and to timestamps that an investor can send / receive tokens respectively - struct TimeRestriction { - uint64 fromTime; - uint64 toTime; - uint64 expiryTime; - uint8 canBuyFromSTO; - uint8 added; - } - - // Allows all TimeRestrictions to be offset - struct Offset { - uint64 offset; - uint8 isForward; - } - - // Offset to be applied to all timings (except KYC expiry) - Offset public offset; - - // List of all addresses that have been added to the GTM at some point - address[] public investors; - - // An address can only send / receive tokens once their corresponding uint256 > block.number - // (unless allowAllTransfers == true or allowAllWhitelistTransfers == true) - mapping (address => TimeRestriction) public whitelist; - // Map of used nonces by customer - mapping(address => mapping(uint256 => bool)) public nonceMap; - - //If true, there are no transfer restrictions, for any addresses - bool public allowAllTransfers = false; - //If true, time lock is ignored for transfers (address must still be on whitelist) - bool public allowAllWhitelistTransfers = false; - //If true, time lock is ignored for issuances (address must still be on whitelist) - bool public allowAllWhitelistIssuances = true; - //If true, time lock is ignored for burn transactions - bool public allowAllBurnTransfers = false; - // Emit when Issuance address get changed event ChangeIssuanceAddress(address _issuanceAddress); // Emit when there is change in the flag variable called allowAllTransfers @@ -78,17 +34,6 @@ contract GeneralTransferManager is ITransferManager { uint8 _canBuyFromSTO ); - /** - * @notice Constructor - * @param _securityToken Address of the security token - * @param _polyAddress Address of the polytoken - */ - constructor (address _securityToken, address _polyAddress) - public - Module(_securityToken, _polyAddress) - { - } - /** * @notice This function returns the signature of configure function */ diff --git a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol index c15eb52aa..c37ab8b4b 100644 --- a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "./GeneralTransferManager.sol"; +import "../../proxy/GeneralTransferManagerProxy.sol"; import "../ModuleFactory.sol"; /** @@ -8,11 +8,13 @@ import "../ModuleFactory.sol"; */ contract GeneralTransferManagerFactory is ModuleFactory { + address public logicContract; + /** * @notice Constructor * @param _polyAddress Address of the polytoken */ - constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public + constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost, address _logicContract) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { version = "1.0.0"; @@ -21,6 +23,7 @@ contract GeneralTransferManagerFactory is ModuleFactory { description = "Manage transfers using a time based whitelist"; compatibleSTVersionRange["lowerBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); compatibleSTVersionRange["upperBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); + logicContract = _logicContract; } @@ -31,7 +34,7 @@ contract GeneralTransferManagerFactory is ModuleFactory { function deploy(bytes /* _data */) external returns(address) { if (setupCost > 0) require(polyToken.transferFrom(msg.sender, owner, setupCost), "Failed transferFrom because of sufficent Allowance is not provided"); - address generalTransferManager = new GeneralTransferManager(msg.sender, address(polyToken)); + address generalTransferManager = new GeneralTransferManagerProxy(msg.sender, address(polyToken), logicContract); /*solium-disable-next-line security/no-block-members*/ emit GenerateModuleFromFactory(address(generalTransferManager), getName(), address(this), msg.sender, setupCost, now); return address(generalTransferManager); diff --git a/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol b/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol new file mode 100644 index 000000000..7dae02ebb --- /dev/null +++ b/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol @@ -0,0 +1,55 @@ +pragma solidity ^0.4.24; + +import "./ITransferManager.sol"; + +/** + * @title Transfer Manager module for core transfer validation functionality + */ +contract GeneralTransferManagerStorage { + + //Address from which issuances come + address public issuanceAddress = address(0); + + //Address which can sign whitelist changes + address public signingAddress = address(0); + + bytes32 public constant WHITELIST = "WHITELIST"; + bytes32 public constant FLAGS = "FLAGS"; + + //from and to timestamps that an investor can send / receive tokens respectively + struct TimeRestriction { + uint64 fromTime; + uint64 toTime; + uint64 expiryTime; + uint8 canBuyFromSTO; + uint8 added; + } + + // Allows all TimeRestrictions to be offset + struct Offset { + uint64 offset; + uint8 isForward; + } + + // Offset to be applied to all timings (except KYC expiry) + Offset public offset; + + // List of all addresses that have been added to the GTM at some point + address[] public investors; + + // An address can only send / receive tokens once their corresponding uint256 > block.number + // (unless allowAllTransfers == true or allowAllWhitelistTransfers == true) + mapping (address => TimeRestriction) public whitelist; + // Map of used nonces by customer + mapping(address => mapping(uint256 => bool)) public nonceMap; + + //If true, there are no transfer restrictions, for any addresses + bool public allowAllTransfers = false; + //If true, time lock is ignored for transfers (address must still be on whitelist) + bool public allowAllWhitelistTransfers = false; + //If true, time lock is ignored for issuances (address must still be on whitelist) + bool public allowAllWhitelistIssuances = true; + //If true, time lock is ignored for burn transactions + bool public allowAllBurnTransfers = false; + +} diff --git a/contracts/proxy/GeneralTransferManagerProxy.sol b/contracts/proxy/GeneralTransferManagerProxy.sol new file mode 100644 index 000000000..cc5999bad --- /dev/null +++ b/contracts/proxy/GeneralTransferManagerProxy.sol @@ -0,0 +1,47 @@ +pragma solidity ^0.4.24; + +import "../modules/TransferManager/GeneralTransferManagerStorage.sol"; +import "./Proxy.sol"; +import "../Pausable.sol"; +import "../modules/ModuleStorage.sol"; + +/** + * @title Transfer Manager module for core transfer validation functionality + */ +contract GeneralTransferManagerProxy is ModuleStorage, Pausable, GeneralTransferManagerStorage, Proxy { + + // Address of the current implementation + address internal __implementation; + + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + * @param _implementation representing the address of the new implementation to be set + */ + constructor (address _securityToken, address _polyAddress, address _implementation) + public + ModuleStorage(_securityToken, _polyAddress) + { + require( + _implementation != address(0), + "Implementation address should not be 0x" + ); + __implementation = _implementation; + } + + /** + * @notice Internal function to provide the address of the implementation contract + */ + function _implementation() internal view returns (address) { + return __implementation; + } + + /** + * @dev Tells the address of the current implementation + * @return address of the current implementation + */ + function implementation() external view returns (address) { + return _implementation(); + } +} diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index 694fdf03e..e903789b2 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -1,5 +1,6 @@ const PolymathRegistry = artifacts.require('./PolymathRegistry.sol') const GeneralTransferManagerFactory = artifacts.require('./GeneralTransferManagerFactory.sol') +const GeneralTransferManagerLogic = artifacts.require('./GeneralTransferManager.sol') const GeneralPermissionManagerFactory = artifacts.require('./GeneralPermissionManagerFactory.sol') const PercentageTransferManagerFactory = artifacts.require('./PercentageTransferManagerFactory.sol') const USDTieredSTOProxyFactory = artifacts.require('./USDTieredSTOProxyFactory.sol'); @@ -145,10 +146,15 @@ module.exports = function (deployer, network, accounts) { moduleRegistry = ModuleRegistry.at(ModuleRegistryProxy.address); // Add module registry to polymath registry return polymathRegistry.changeAddress("ModuleRegistry", ModuleRegistryProxy.address, {from: PolymathAccount}); + }).then(() => { + console.log("deployinglogic") + // B) Deploy the GeneralTransferManagerLogic Contract (Factory used to generate the GeneralTransferManager contract and this + // manager attach with the securityToken contract at the time of deployment) + return deployer.deploy(GeneralTransferManagerLogic, {from: PolymathAccount}); }).then(() => { // B) Deploy the GeneralTransferManagerFactory Contract (Factory used to generate the GeneralTransferManager contract and this // manager attach with the securityToken contract at the time of deployment) - return deployer.deploy(GeneralTransferManagerFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); + return deployer.deploy(GeneralTransferManagerFactory, PolyToken, 0, 0, 0, GeneralTransferManagerLogic.address, {from: PolymathAccount}); }).then(() => { // C) Deploy the GeneralPermissionManagerFactory Contract (Factory used to generate the GeneralPermissionManager contract and // this manager attach with the securityToken contract at the time of deployment) diff --git a/test/helpers/createInstances.js b/test/helpers/createInstances.js index 2021d350e..c2201ec12 100644 --- a/test/helpers/createInstances.js +++ b/test/helpers/createInstances.js @@ -82,7 +82,9 @@ export async function setUpPolymathNetwork(account_polymath, token_owner) { let b = await deployFeatureRegistry(account_polymath); // STEP 3: Deploy the ModuleRegistry let c = await deployModuleRegistry(account_polymath); - // STEP 4: Deploy the GeneralTransferManagerFactory + // STEP 4a: Deploy the GeneralTransferManagerFactory + let logic = await deployGTMLogic(account_polymath); + // STEP 4b: Deploy the GeneralTransferManagerFactory let d = await deployGTM(account_polymath); // Step 6: Deploy the STversionProxy contract let e = await deploySTFactory(account_polymath); @@ -127,8 +129,20 @@ async function deployModuleRegistry(account_polymath) { return new Array(I_ModuleRegistry, I_ModuleRegistryProxy, I_MRProxied); } +async function deployGTMLogic(account_polymath) { + I_GeneralTransferManagerLogic = await GeneralTransferManager.new({ from: account_polymath }); + + assert.notEqual( + I_GeneralTransferManagerLogic.address.valueOf(), + "0x0000000000000000000000000000000000000000", + "GeneralTransferManagerLogic contract was not deployed" + ); + + return new Array(I_GeneralTransferManagerLogic); +} + async function deployGTM(account_polymath) { - I_GeneralTransferManagerFactory = await GeneralTransferManagerFactory.new(I_PolyToken.address, 0, 0, 0, { from: account_polymath }); + I_GeneralTransferManagerFactory = await GeneralTransferManagerFactory.new(I_PolyToken.address, 0, 0, 0, I_GeneralTransferManagerLogic.address, { from: account_polymath }); assert.notEqual( I_GeneralTransferManagerFactory.address.valueOf(), @@ -193,7 +207,7 @@ async function registerAndVerifyByMR(factoryAdrress, owner, mr) { /// Deploy the TransferManagers export async function deployGTMAndVerifyed(accountPolymath, MRProxyInstance, polyToken, setupCost) { - I_GeneralTransferManagerFactory = await GeneralTransferManagerFactory.new(polyToken, setupCost, 0, 0, { from: accountPolymath }); + I_GeneralTransferManagerFactory = await GeneralTransferManagerFactory.new(polyToken, setupCost, 0, 0, I_GeneralTransferManagerLogic.address, { from: accountPolymath }); assert.notEqual( I_GeneralPermissionManagerFactory.address.valueOf(), From 9f0e2efe8c28223b63a62369388f5f6734b6adff Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sat, 24 Nov 2018 21:57:34 +0000 Subject: [PATCH 43/93] Fixes --- .../TransferManager/GeneralTransferManager.sol | 11 +++++++++++ contracts/proxy/GeneralTransferManagerProxy.sol | 2 +- migrations/2_deploy_contracts.js | 4 ++-- test/h_general_transfer_manager.js | 2 +- test/helpers/createInstances.js | 4 +++- test/u_module_registry_proxy.js | 5 ++++- 6 files changed, 22 insertions(+), 6 deletions(-) diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index 247ac8374..f15a522da 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -34,6 +34,17 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag uint8 _canBuyFromSTO ); + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + */ + constructor (address _securityToken, address _polyAddress) + public + Module(_securityToken, _polyAddress) + { + } + /** * @notice This function returns the signature of configure function */ diff --git a/contracts/proxy/GeneralTransferManagerProxy.sol b/contracts/proxy/GeneralTransferManagerProxy.sol index cc5999bad..9732b76db 100644 --- a/contracts/proxy/GeneralTransferManagerProxy.sol +++ b/contracts/proxy/GeneralTransferManagerProxy.sol @@ -8,7 +8,7 @@ import "../modules/ModuleStorage.sol"; /** * @title Transfer Manager module for core transfer validation functionality */ -contract GeneralTransferManagerProxy is ModuleStorage, Pausable, GeneralTransferManagerStorage, Proxy { +contract GeneralTransferManagerProxy is GeneralTransferManagerStorage, ModuleStorage, Pausable, Proxy { // Address of the current implementation address internal __implementation; diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index e903789b2..63b2a8231 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -147,10 +147,9 @@ module.exports = function (deployer, network, accounts) { // Add module registry to polymath registry return polymathRegistry.changeAddress("ModuleRegistry", ModuleRegistryProxy.address, {from: PolymathAccount}); }).then(() => { - console.log("deployinglogic") // B) Deploy the GeneralTransferManagerLogic Contract (Factory used to generate the GeneralTransferManager contract and this // manager attach with the securityToken contract at the time of deployment) - return deployer.deploy(GeneralTransferManagerLogic, {from: PolymathAccount}); + return deployer.deploy(GeneralTransferManagerLogic, "0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000", {from: PolymathAccount}); }).then(() => { // B) Deploy the GeneralTransferManagerFactory Contract (Factory used to generate the GeneralTransferManager contract and this // manager attach with the securityToken contract at the time of deployment) @@ -309,6 +308,7 @@ module.exports = function (deployer, network, accounts) { POLYOracle: ${POLYOracle} STFactory: ${STFactory.address} + GeneralTransferManagerLogic: ${GeneralTransferManagerLogic.address} GeneralTransferManagerFactory: ${GeneralTransferManagerFactory.address} GeneralPermissionManagerFactory: ${GeneralPermissionManagerFactory.address} diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index b7f14ed31..5137d8e9e 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -150,7 +150,7 @@ contract("GeneralTransferManager", accounts => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); - console.log(JSON.stringify(tx)); + // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/helpers/createInstances.js b/test/helpers/createInstances.js index c2201ec12..35be83d95 100644 --- a/test/helpers/createInstances.js +++ b/test/helpers/createInstances.js @@ -20,6 +20,7 @@ const USDTieredSTOProxyFactory = artifacts.require("./USDTieredSTOProxyFactory") const ManualApprovalTransferManager = artifacts.require("./ManualApprovalTransferManager"); const FeatureRegistry = artifacts.require("./FeatureRegistry.sol"); const STFactory = artifacts.require("./STFactory.sol"); +const GeneralTransferManager = artifacts.require("./GeneralTransferManager.sol"); const GeneralTransferManagerFactory = artifacts.require("./GeneralTransferManagerFactory.sol"); const GeneralPermissionManagerFactory = artifacts.require("./GeneralPermissionManagerFactory.sol"); const CountTransferManagerFactory = artifacts.require("./CountTransferManagerFactory.sol"); @@ -49,6 +50,7 @@ let I_EtherDividendCheckpointFactory; let I_CountTransferManagerFactory; let I_ERC20DividendCheckpointFactory; let I_GeneralPermissionManagerFactory; +let I_GeneralTransferManagerLogic; let I_GeneralTransferManagerFactory; let I_GeneralTransferManager; let I_ModuleRegistryProxy; @@ -130,7 +132,7 @@ async function deployModuleRegistry(account_polymath) { } async function deployGTMLogic(account_polymath) { - I_GeneralTransferManagerLogic = await GeneralTransferManager.new({ from: account_polymath }); + I_GeneralTransferManagerLogic = await GeneralTransferManager.new("0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000", { from: account_polymath }); assert.notEqual( I_GeneralTransferManagerLogic.address.valueOf(), diff --git a/test/u_module_registry_proxy.js b/test/u_module_registry_proxy.js index 6d00b8fe2..877d173d4 100644 --- a/test/u_module_registry_proxy.js +++ b/test/u_module_registry_proxy.js @@ -9,6 +9,7 @@ const ModuleRegistryProxy = artifacts.require("./ModuleRegistryProxy.sol"); const ModuleRegistry = artifacts.require("./ModuleRegistry.sol"); const STFactory = artifacts.require("./STFactory.sol"); const SecurityToken = artifacts.require("./SecurityToken.sol"); +const GeneralTransferManagerLogic = artifacts.require("./GeneralTransferManager.sol"); const GeneralTransferManagerFactory = artifacts.require("./GeneralTransferManagerFactory.sol"); const GeneralPermissionManagerFactory = artifacts.require("./GeneralPermissionManagerFactory.sol"); @@ -122,7 +123,9 @@ contract("ModuleRegistryProxy", accounts => { await I_MRProxied.updateFromRegistry({ from: account_polymath }); // STEP 4: Deploy the GeneralTransferManagerFactory - I_GeneralTransferManagerFactory = await GeneralTransferManagerFactory.new(I_PolyToken.address, 0, 0, 0, { + let I_GeneralTransferManagerLogic = await GeneralTransferManagerLogic.new("0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000", { from: account_polymath }); + + I_GeneralTransferManagerFactory = await GeneralTransferManagerFactory.new(I_PolyToken.address, 0, 0, 0, I_GeneralTransferManagerLogic.address, { from: account_polymath }); From 3234d152f1e492ec6652e65e32dbd8e0c4c825f4 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sat, 24 Nov 2018 22:01:58 +0000 Subject: [PATCH 44/93] Update config --- truffle-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/truffle-config.js b/truffle-config.js index 2a84351bd..c993327ea 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -11,7 +11,7 @@ module.exports = { host: 'localhost', port: 8545, network_id: '*', // Match any network id - gas: 9000000, + gas: 7900000, }, mainnet: { host: 'localhost', From 14d5890a2f68b42d6d1d9132fad9c18e53e7009e Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sat, 24 Nov 2018 22:23:09 +0000 Subject: [PATCH 45/93] Log gas for 50 txs --- test/h_general_transfer_manager.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 5137d8e9e..9871f5e3c 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -197,6 +197,28 @@ contract("GeneralTransferManager", accounts => { assert.equal(tx.logs[1].args._investor, account_affiliates2); }); + it("Should whitelist lots of addresses and check gas", async () => { + let mockInvestors = []; + for (let i = 0; i < 50; i++) { + mockInvestors.push("0x0000000000000000000000000000000000000000".substring(0,42-i.toString().length) + i.toString()); + } + + let times = range1(50); + let bools = rangeB(50); + let tx = await I_GeneralTransferManager.modifyWhitelistMulti( + mockInvestors, + times, + times, + times, + bools, + { + from: account_issuer, + gas: 7900000 + } + ); + console.log("Multi Whitelist x 50: " + tx.receipt.gasUsed); + }); + it("Should mint the tokens to the affiliates", async () => { await I_SecurityToken.mintMulti([account_affiliates1, account_affiliates2], [100 * Math.pow(10, 18), 100 * Math.pow(10, 18)], { from: account_issuer, @@ -836,3 +858,6 @@ contract("GeneralTransferManager", accounts => { }) }); }); + +function range1(i) {return i?range1(i-1).concat(i):[]} +function rangeB(i) {return i?rangeB(i-1).concat(0):[]} From a2784768745db24552c694737c109c0cbf2e58c8 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sat, 24 Nov 2018 23:40:53 +0000 Subject: [PATCH 46/93] WIP --- .../GeneralTransferManager.sol | 36 ++++++- .../GeneralTransferManagerStorage.sol | 2 +- test/h_general_transfer_manager.js | 97 ++++++++++++++++++- 3 files changed, 129 insertions(+), 6 deletions(-) diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index f15a522da..c64c99c34 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -24,6 +24,8 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag // Emit when there is change in the flag variable called signingAddress event ChangeSigningAddress(address _signingAddress); // Emit when investor details get modified related to their whitelisting + event OffsetModified(uint64 _time, uint8 _isForward); + event ModifyWhitelist( address _investor, uint256 _dateAdded, @@ -45,6 +47,12 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag { } + function modifyOffset(uint64 _time, uint8 _isForward) public withPerm(FLAGS) { + offset.time = _time; + offset.isForward = _isForward; + emit OffsetModified(_time, _isForward); + } + /** * @notice This function returns the signature of configure function */ @@ -137,16 +145,21 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag //Anyone on the whitelist can transfer, regardless of time return (_onWhitelist(_to) && _onWhitelist(_from)) ? Result.VALID : Result.NA; } - if (allowAllWhitelistIssuances && _from == issuanceAddress) { + if (_from == issuanceAddress && (whitelist[_to].canBuyFromSTO == 0) && _isSTOAttached()) { if ((whitelist[_to].canBuyFromSTO == 0) && _isSTOAttached()) { return Result.NA; } + } + if (allowAllWhitelistIssuances && _from == issuanceAddress) { return _onWhitelist(_to) ? Result.VALID : Result.NA; } + if (_from == issuanceAddress) { + return (_onWhitelist(_to) && _adjustTimes(whitelist[_to].toTime) <= uint64(now)) ? Result.VALID : Result.NA; + } //Anyone on the whitelist can transfer provided the blocknumber is large enough /*solium-disable-next-line security/no-block-members*/ - return ((_onWhitelist(_from) && whitelist[_from].fromTime <= uint64(now)) && - (_onWhitelist(_to) && whitelist[_to].toTime <= uint64(now))) ? Result.VALID : Result.NA; /*solium-disable-line security/no-block-members*/ + return ((_onWhitelist(_from) && _adjustTimes(whitelist[_from].fromTime) <= uint64(now)) && + (_onWhitelist(_to) && _adjustTimes(whitelist[_to].toTime) <= uint64(now))) ? Result.VALID : Result.NA; /*solium-disable-line security/no-block-members*/ } return Result.NA; } @@ -274,6 +287,23 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag return attached; } + function _adjustTimes(uint64 _time) internal view returns(uint64) { + if (offset.isForward != 0) { + require(_time + offset.time > _time); + return _time + offset.time; + } else { + require(_time >= offset.time); + return _time - offset.time; + } + } + + /** + * @dev Returns list of all investors + */ + function getInvestors() external view returns(address[]) { + return investors; + } + /** * @notice Return the permissions flag that are associated with general trnasfer manager */ diff --git a/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol b/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol index 7dae02ebb..6cfb29e21 100644 --- a/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol +++ b/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol @@ -27,7 +27,7 @@ contract GeneralTransferManagerStorage { // Allows all TimeRestrictions to be offset struct Offset { - uint64 offset; + uint64 time; uint8 isForward; } diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 9871f5e3c..b5f2b3d91 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -172,14 +172,14 @@ contract("GeneralTransferManager", accounts => { await catchRevert( I_SecurityToken.addModule(P_GeneralTransferManagerFactory.address, "", web3.utils.toWei("500"), 0, {from: account_issuer}) ); - }) + }); it("Should attach the paid GTM", async() => { let snap_id = await takeSnapshot(); await I_PolyToken.getTokens(web3.utils.toWei("500"), I_SecurityToken.address); await I_SecurityToken.addModule(P_GeneralTransferManagerFactory.address, "", web3.utils.toWei("500"), 0, {from: account_issuer}); await revertToSnapshot(snap_id); - }) + }); it("Should whitelist the affiliates before the STO attached", async () => { let tx = await I_GeneralTransferManager.modifyWhitelistMulti( @@ -195,6 +195,7 @@ contract("GeneralTransferManager", accounts => { ); assert.equal(tx.logs[0].args._investor, account_affiliates1); assert.equal(tx.logs[1].args._investor, account_affiliates2); + assert.deepEqual(await I_GeneralTransferManager.getInvestors.call(), [account_affiliates1, account_affiliates2]); }); it("Should whitelist lots of addresses and check gas", async () => { @@ -217,6 +218,7 @@ contract("GeneralTransferManager", accounts => { } ); console.log("Multi Whitelist x 50: " + tx.receipt.gasUsed); + assert.deepEqual(await I_GeneralTransferManager.getInvestors.call(), [account_affiliates1, account_affiliates2].concat(mockInvestors)); }); it("Should mint the tokens to the affiliates", async () => { @@ -364,6 +366,97 @@ contract("GeneralTransferManager", accounts => { }); }); + describe("Buy tokens using on-chain whitelist and negative offset", async () => { + // let snap_id; + + it("Should Buy the tokens", async () => { + // Add the Investor in to the whitelist + // snap_id = await takeSnapshot(); + let tx = await I_GeneralTransferManager.modifyWhitelist( + account_investor1, + latestTime() + duration.days(10), + latestTime() + duration.days(10), + latestTime() + duration.days(20), + 1, + { + from: account_issuer, + gas: 6000000 + } + ); + + assert.equal( + tx.logs[0].args._investor.toLowerCase(), + account_investor1.toLowerCase(), + "Failed in adding the investor in whitelist" + ); + + // Jump time + await increaseTime(5000); + + // Mint some tokens + await I_DummySTO.generateTokens(account_investor1, web3.utils.toWei("1", "ether"), { from: token_owner }); + + await catchRevert(I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1})); + assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toNumber(), web3.utils.toWei("3", "ether")); + }); + + it("Add an offset and check transfers are disabled", async () => { + let tx = await I_GeneralTransferManager.modifyOffset(duration.days(10), 0, {from: token_owner}); + await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); + assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toNumber(), web3.utils.toWei("3", "ether")); + tx = await I_GeneralTransferManager.modifyOffset(0, 0, {from: token_owner}); + // await revertToSnapshot(snap_id); + }); + + }); + + + describe("Buy tokens using on-chain whitelist and positive offset", async () => { + // let snap_id; + + it("Should Buy the tokens", async () => { + // Add the Investor in to the whitelist + // snap_id = await takeSnapshot(); + let tx = await I_GeneralTransferManager.modifyWhitelist( + account_investor1, + latestTime(), + latestTime(), + latestTime(), + 1, + { + from: account_issuer, + gas: 6000000 + } + ); + + assert.equal( + tx.logs[0].args._investor.toLowerCase(), + account_investor1.toLowerCase(), + "Failed in adding the investor in whitelist" + ); + + // Jump time + await increaseTime(5000); + + // Mint some tokens + console.log(await I_GeneralTransferManager.offset.call()); + await I_DummySTO.generateTokens(account_investor1, web3.utils.toWei("1", "ether"), { from: token_owner }); + + assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toNumber(), web3.utils.toWei("4", "ether")); + await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); + }); + + it("Add an offset and check transfers are disabled", async () => { + let tx = await I_GeneralTransferManager.modifyOffset(duration.days(10), 1, {from: token_owner}); + await catchRevert(I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1})); + await increaseTime(duration.days(10)); + I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); + tx = await I_GeneralTransferManager.modifyOffset(0, 0, {from: token_owner}); + // await revertToSnapshot(snap_id); + }); + + }); + describe("Buy tokens using off-chain whitelist", async () => { it("Should buy the tokens -- Failed due to investor is not in the whitelist", async () => { await catchRevert(I_DummySTO.generateTokens(account_investor2, web3.utils.toWei("1", "ether"), { from: token_owner })); From 165f6c7e4c02010f3c5743ad5d0b37c334c690fc Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sat, 24 Nov 2018 23:49:38 +0000 Subject: [PATCH 47/93] update --- test/h_general_transfer_manager.js | 91 +++++++++++++++--------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index b5f2b3d91..9105c63e6 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -411,51 +411,52 @@ contract("GeneralTransferManager", accounts => { }); - describe("Buy tokens using on-chain whitelist and positive offset", async () => { - // let snap_id; - - it("Should Buy the tokens", async () => { - // Add the Investor in to the whitelist - // snap_id = await takeSnapshot(); - let tx = await I_GeneralTransferManager.modifyWhitelist( - account_investor1, - latestTime(), - latestTime(), - latestTime(), - 1, - { - from: account_issuer, - gas: 6000000 - } - ); - - assert.equal( - tx.logs[0].args._investor.toLowerCase(), - account_investor1.toLowerCase(), - "Failed in adding the investor in whitelist" - ); - - // Jump time - await increaseTime(5000); - - // Mint some tokens - console.log(await I_GeneralTransferManager.offset.call()); - await I_DummySTO.generateTokens(account_investor1, web3.utils.toWei("1", "ether"), { from: token_owner }); - - assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toNumber(), web3.utils.toWei("4", "ether")); - await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); - }); - - it("Add an offset and check transfers are disabled", async () => { - let tx = await I_GeneralTransferManager.modifyOffset(duration.days(10), 1, {from: token_owner}); - await catchRevert(I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1})); - await increaseTime(duration.days(10)); - I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); - tx = await I_GeneralTransferManager.modifyOffset(0, 0, {from: token_owner}); - // await revertToSnapshot(snap_id); - }); - - }); + // describe("Buy tokens using on-chain whitelist and positive offset", async () => { + // // let snap_id; + // + // it("Should Buy the tokens", async () => { + // + // // Add the Investor in to the whitelist + // // snap_id = await takeSnapshot(); + // let tx = await I_GeneralTransferManager.modifyWhitelist( + // account_investor1, + // latestTime(), + // latestTime(), + // latestTime(), + // 1, + // { + // from: account_issuer, + // gas: 6000000 + // } + // ); + // + // assert.equal( + // tx.logs[0].args._investor.toLowerCase(), + // account_investor1.toLowerCase(), + // "Failed in adding the investor in whitelist" + // ); + // + // // Jump time + // await increaseTime(5000); + // + // // Mint some tokens + // console.log(await I_GeneralTransferManager.offset.call()); + // await I_DummySTO.generateTokens(account_investor1, web3.utils.toWei("1", "ether"), { from: token_owner }); + // + // assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toNumber(), web3.utils.toWei("4", "ether")); + // await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); + // }); + // + // it("Add an offset and check transfers are disabled", async () => { + // let tx = await I_GeneralTransferManager.modifyOffset(duration.days(10), 1, {from: token_owner}); + // await catchRevert(I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1})); + // await increaseTime(duration.days(10)); + // await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); + // tx = await I_GeneralTransferManager.modifyOffset(0, 0, {from: token_owner}); + // // await revertToSnapshot(snap_id); + // }); + // + // }); describe("Buy tokens using off-chain whitelist", async () => { it("Should buy the tokens -- Failed due to investor is not in the whitelist", async () => { From f1216963784eb6bd66f5ba8bbabbcbc66d54930b Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sun, 25 Nov 2018 17:52:56 +0000 Subject: [PATCH 48/93] Fix tests --- test/h_general_transfer_manager.js | 100 ++++++++++++++++------------- 1 file changed, 54 insertions(+), 46 deletions(-) diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 9105c63e6..750a4cfbc 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -411,52 +411,60 @@ contract("GeneralTransferManager", accounts => { }); - // describe("Buy tokens using on-chain whitelist and positive offset", async () => { - // // let snap_id; - // - // it("Should Buy the tokens", async () => { - // - // // Add the Investor in to the whitelist - // // snap_id = await takeSnapshot(); - // let tx = await I_GeneralTransferManager.modifyWhitelist( - // account_investor1, - // latestTime(), - // latestTime(), - // latestTime(), - // 1, - // { - // from: account_issuer, - // gas: 6000000 - // } - // ); - // - // assert.equal( - // tx.logs[0].args._investor.toLowerCase(), - // account_investor1.toLowerCase(), - // "Failed in adding the investor in whitelist" - // ); - // - // // Jump time - // await increaseTime(5000); - // - // // Mint some tokens - // console.log(await I_GeneralTransferManager.offset.call()); - // await I_DummySTO.generateTokens(account_investor1, web3.utils.toWei("1", "ether"), { from: token_owner }); - // - // assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toNumber(), web3.utils.toWei("4", "ether")); - // await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); - // }); - // - // it("Add an offset and check transfers are disabled", async () => { - // let tx = await I_GeneralTransferManager.modifyOffset(duration.days(10), 1, {from: token_owner}); - // await catchRevert(I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1})); - // await increaseTime(duration.days(10)); - // await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); - // tx = await I_GeneralTransferManager.modifyOffset(0, 0, {from: token_owner}); - // // await revertToSnapshot(snap_id); - // }); - // - // }); + describe("Buy tokens using on-chain whitelist and positive offset", async () => { + // let snap_id; + + it("Should Buy the tokens", async () => { + + // Add the Investor in to the whitelist + // snap_id = await takeSnapshot(); + let tx = await I_GeneralTransferManager.modifyWhitelist( + account_investor1, + latestTime(), + latestTime(), + latestTime() + duration.days(20), + 1, + { + from: account_issuer, + gas: 6000000 + } + ); + + assert.equal( + tx.logs[0].args._investor.toLowerCase(), + account_investor1.toLowerCase(), + "Failed in adding the investor in whitelist" + ); + + // Jump time + await increaseTime(5000); + // console.log("vT1: " + JSON.stringify(await I_GeneralTransferManager.verifyTransfer.call(account_investor1, account_investor1, web3.utils.toWei("1", "ether"), "", false))); + // console.log("vT2: " + JSON.stringify(await I_GeneralTransferManager.verifyTransfer.call("0x0000000000000000000000000000000000000000", account_investor1, web3.utils.toWei("1", "ether"), "", false))); + + // Mint some tokens + console.log(await I_GeneralTransferManager.offset.call()); + await I_DummySTO.generateTokens(account_investor1, web3.utils.toWei("1", "ether"), { from: token_owner }); + + assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toNumber(), web3.utils.toWei("4", "ether")); + await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); + }); + + it("Add an offset and check transfers are disabled", async () => { + let tx = await I_GeneralTransferManager.modifyOffset(duration.days(10), 1, {from: token_owner}); + // console.log("vT1: " + JSON.stringify(await I_GeneralTransferManager.verifyTransfer.call(account_investor1, account_investor1, web3.utils.toWei("1", "ether"), "", false))); + // console.log("vT2: " + JSON.stringify(await I_GeneralTransferManager.verifyTransfer.call("0x0000000000000000000000000000000000000000", account_investor1, web3.utils.toWei("1", "ether"), "", false))); + + await catchRevert(I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1})); + await increaseTime(duration.days(10)); + // console.log("vT1: " + JSON.stringify(await I_GeneralTransferManager.verifyTransfer.call(account_investor1, account_investor1, web3.utils.toWei("1", "ether"), "", false))); + // console.log("vT2: " + JSON.stringify(await I_GeneralTransferManager.verifyTransfer.call("0x0000000000000000000000000000000000000000", account_investor1, web3.utils.toWei("1", "ether"), "", false))); + + await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); + tx = await I_GeneralTransferManager.modifyOffset(0, 0, {from: token_owner}); + // await revertToSnapshot(snap_id); + }); + + }); describe("Buy tokens using off-chain whitelist", async () => { it("Should buy the tokens -- Failed due to investor is not in the whitelist", async () => { From 094769752bdf0c8f238388c5de56c6de25db22f5 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sun, 25 Nov 2018 18:05:30 +0000 Subject: [PATCH 49/93] Fix typo --- contracts/modules/TransferManager/GeneralTransferManager.sol | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index c64c99c34..d9b7857ac 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -146,9 +146,7 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag return (_onWhitelist(_to) && _onWhitelist(_from)) ? Result.VALID : Result.NA; } if (_from == issuanceAddress && (whitelist[_to].canBuyFromSTO == 0) && _isSTOAttached()) { - if ((whitelist[_to].canBuyFromSTO == 0) && _isSTOAttached()) { - return Result.NA; - } + return Result.NA; } if (allowAllWhitelistIssuances && _from == issuanceAddress) { return _onWhitelist(_to) ? Result.VALID : Result.NA; From af1a97e3dabfc8574d3714f2e88ba2850c4d8a4f Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sun, 25 Nov 2018 18:12:55 +0000 Subject: [PATCH 50/93] Change onWhitelist logic --- contracts/modules/TransferManager/GeneralTransferManager.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index d9b7857ac..a7029caa1 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -273,8 +273,7 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag * @param _investor Address of the investor */ function _onWhitelist(address _investor) internal view returns(bool) { - return (((whitelist[_investor].fromTime != 0) || (whitelist[_investor].toTime != 0)) && - (whitelist[_investor].expiryTime >= uint64(now))); /*solium-disable-line security/no-block-members*/ + return (whitelist[_investor].expiryTime >= uint64(now)); /*solium-disable-line security/no-block-members*/ } /** From 67037aa0dccbfcb0d22bb410ad87ddcd75d6dfda Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sun, 25 Nov 2018 18:20:27 +0000 Subject: [PATCH 51/93] Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index db3d8dcde..0e19e93ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,12 @@ All notable changes to this project will be documented in this file. * Added `getTokensSoldByTier` to return sold (not minted during finalisation) tokens in each tier to USDTSTO. * Removed individual mappings for tier data removed in UDSTSTO. +# GeneralTransferManager +* Add an Offset that can be used to move all from & to dates forwards or backwards by a fixed offset. +* Add `address[] public investors` to record a list of all addresses that have been added to the whitelist (`getInvestors`) +* Fix for when `allowAllWhitelistIssuances` is FALSE +* Make GTM a Proxy based implementation to reduce deployment gas costs + ##Changed * `getAllModulesAndPermsFromTypes()` does not take securityToken address as a parameter anymore. From 492127f8366f1ad955bf6e450f2bd7e8b113c446 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sun, 25 Nov 2018 18:30:57 +0000 Subject: [PATCH 52/93] Update all test cases --- test/b_capped_sto.js | 14 +++++------ test/c_checkpoints.js | 6 ++--- test/d_count_transfer_manager.js | 8 +++---- test/e_erc20_dividends.js | 12 +++++----- test/f_ether_dividends.js | 12 +++++----- test/i_Issuance.js | 4 ++-- test/j_manual_approval_transfer_manager.js | 6 ++--- test/l_percentage_transfer_manager.js | 8 +++---- test/m_presale_sto.js | 6 ++--- test/o_security_token.js | 20 ++++++++-------- test/p_usd_tiered_sto.js | 18 +++++++------- test/q_usd_tiered_sto_sim.js | 6 ++--- test/r_concurrent_STO.js | 6 ++--- test/v_tracked_redemptions.js | 6 ++--- ...kup_volume_restriction_transfer_manager.js | 14 +++++------ test/x_single_trade_volume_restriction.js | 24 +++++++++---------- test/y_scheduled_checkpoints.js | 6 ++--- 17 files changed, 88 insertions(+), 88 deletions(-) diff --git a/test/b_capped_sto.js b/test/b_capped_sto.js index d89fe6eba..fe59d9c03 100644 --- a/test/b_capped_sto.js +++ b/test/b_capped_sto.js @@ -130,7 +130,7 @@ contract("CappedSTO", accounts => { // STEP 5: Deploy the GeneralDelegateManagerFactory [I_GeneralPermissionManagerFactory] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); - + // STEP 6: Deploy the CappedSTOFactory I_CappedSTOFactory = await CappedSTOFactory.new(I_PolyToken.address, cappedSTOSetupCost, 0, 0, { from: token_owner }); @@ -360,7 +360,7 @@ contract("CappedSTO", accounts => { balanceOfReceiver = await web3.eth.getBalance(account_fundsReceiver); // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, 1, { from: account_issuer }); @@ -443,7 +443,7 @@ contract("CappedSTO", accounts => { fromTime, toTime + duration.days(20), expiryTime, - true, + 1, { from: account_issuer } @@ -565,7 +565,7 @@ contract("CappedSTO", accounts => { it("Should successfully whitelist investor 3", async () => { balanceOfReceiver = await web3.eth.getBalance(account_fundsReceiver); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, 1, { from: account_issuer, gas: 500000 }); @@ -733,7 +733,7 @@ contract("CappedSTO", accounts => { "Tokens are not transfered properly" ); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, P_fromTime, P_toTime, P_expiryTime, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, P_fromTime, P_toTime, P_expiryTime, 1, { from: account_issuer, gas: 500000 }); @@ -800,7 +800,7 @@ contract("CappedSTO", accounts => { P_fromTime, P_toTime + duration.days(20), P_expiryTime, - true, + 1, { from: account_issuer, gas: 500000 @@ -997,7 +997,7 @@ contract("CappedSTO", accounts => { await I_PolyToken.getTokens(polyToInvest * Math.pow(10, 18), account_investor3); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, P_fromTime, P_toTime, P_expiryTime, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, P_fromTime, P_toTime, P_expiryTime, 1, { from: account_issuer, gas: 500000 }); diff --git a/test/c_checkpoints.js b/test/c_checkpoints.js index 6a08b6dea..2ba198f83 100644 --- a/test/c_checkpoints.js +++ b/test/c_checkpoints.js @@ -149,7 +149,7 @@ contract("Checkpoints", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - false, + 0, { from: account_issuer, gas: 6000000 @@ -176,7 +176,7 @@ contract("Checkpoints", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - false, + 0, { from: account_issuer, gas: 6000000 @@ -201,7 +201,7 @@ contract("Checkpoints", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - false, + 0, { from: account_issuer, gas: 6000000 diff --git a/test/d_count_transfer_manager.js b/test/d_count_transfer_manager.js index 1a1e7717a..4e86bdbb6 100644 --- a/test/d_count_transfer_manager.js +++ b/test/d_count_transfer_manager.js @@ -200,7 +200,7 @@ contract("CountTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 500000 @@ -230,7 +230,7 @@ contract("CountTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 500000 @@ -257,7 +257,7 @@ contract("CountTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 500000 @@ -282,7 +282,7 @@ contract("CountTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 500000 diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index b832bcee2..6a4baeab6 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -89,7 +89,7 @@ contract("ERC20DividendCheckpoint", accounts => { account_investor4 = accounts[9]; account_temp = accounts[2]; account_manager = accounts[5]; - + // Step 1: Deploy the genral PM ecosystem let instances = await setUpPolymathNetwork(account_polymath, token_owner); @@ -202,7 +202,7 @@ contract("ERC20DividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(30), - true, + 1, { from: account_issuer, gas: 500000 @@ -232,7 +232,7 @@ contract("ERC20DividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(30), - true, + 1, { from: account_issuer, gas: 500000 @@ -372,7 +372,7 @@ contract("ERC20DividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(20), - true, + 1, { from: account_issuer, gas: 500000 @@ -434,7 +434,7 @@ contract("ERC20DividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 500000 @@ -970,7 +970,7 @@ contract("ERC20DividendCheckpoint", accounts => { let expiry = latestTime() + duration.days(10); let exclusions = [1]; let checkpointID = await I_SecurityToken.createCheckpoint.call({ from: token_owner }); - await I_SecurityToken.createCheckpoint({ from: token_owner }); + await I_SecurityToken.createCheckpoint({ from: token_owner }); await catchRevert(I_ERC20DividendCheckpoint.createDividendWithCheckpointAndExclusions( maturity, expiry, diff --git a/test/f_ether_dividends.js b/test/f_ether_dividends.js index b4e5bbf2b..68c11f72f 100644 --- a/test/f_ether_dividends.js +++ b/test/f_ether_dividends.js @@ -200,7 +200,7 @@ contract("EtherDividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(30), - true, + 1, { from: account_issuer, gas: 500000 @@ -230,7 +230,7 @@ contract("EtherDividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(30), - true, + 1, { from: account_issuer, gas: 500000 @@ -364,7 +364,7 @@ contract("EtherDividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(20), - true, + 1, { from: account_issuer, gas: 500000 @@ -415,7 +415,7 @@ contract("EtherDividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 500000 @@ -719,7 +719,7 @@ contract("EtherDividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 500000 @@ -851,7 +851,7 @@ contract("EtherDividendCheckpoint", accounts => { let expiry = latestTime() + duration.days(10); let exclusions = [1]; let checkpointID = await I_SecurityToken.createCheckpoint.call({ from: token_owner }); - await I_SecurityToken.createCheckpoint({ from: token_owner }); + await I_SecurityToken.createCheckpoint({ from: token_owner }); await catchRevert(I_EtherDividendCheckpoint.createDividendWithCheckpointAndExclusions( maturity, expiry, diff --git a/test/i_Issuance.js b/test/i_Issuance.js index ac1fcdd37..efcf0db96 100644 --- a/test/i_Issuance.js +++ b/test/i_Issuance.js @@ -215,7 +215,7 @@ contract("Issuance", accounts => { fromTime + duration.days(70), toTime + duration.days(90), expiryTime + duration.days(50), - true, + 1, { from: account_polymath } @@ -271,7 +271,7 @@ contract("Issuance", accounts => { }); it("should add the investor into the whitelist by the delegate", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor2, fromTime, toTime, expiryTime, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor2, fromTime, toTime, expiryTime, 1, { from: account_delegate, gas: 7000000 }); diff --git a/test/j_manual_approval_transfer_manager.js b/test/j_manual_approval_transfer_manager.js index 0461f287a..c817f5c44 100644 --- a/test/j_manual_approval_transfer_manager.js +++ b/test/j_manual_approval_transfer_manager.js @@ -171,7 +171,7 @@ contract("ManualApprovalTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 6000000 @@ -201,7 +201,7 @@ contract("ManualApprovalTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 6000000 @@ -290,7 +290,7 @@ contract("ManualApprovalTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 6000000 diff --git a/test/l_percentage_transfer_manager.js b/test/l_percentage_transfer_manager.js index b15ee41a0..530b202c8 100644 --- a/test/l_percentage_transfer_manager.js +++ b/test/l_percentage_transfer_manager.js @@ -120,7 +120,7 @@ contract("PercentageTransferManager", accounts => { // STEP 4(b): Deploy the PercentageTransferManager [P_PercentageTransferManagerFactory] = await deployPercentageTMAndVerified(account_polymath, I_MRProxied, I_PolyToken.address, web3.utils.toWei("500", "ether")); - + // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- @@ -192,7 +192,7 @@ contract("PercentageTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 6000000 @@ -222,7 +222,7 @@ contract("PercentageTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 6000000 @@ -287,7 +287,7 @@ contract("PercentageTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 6000000 diff --git a/test/m_presale_sto.js b/test/m_presale_sto.js index a89932dc4..35a348c30 100644 --- a/test/m_presale_sto.js +++ b/test/m_presale_sto.js @@ -236,7 +236,7 @@ contract("PreSaleSTO", accounts => { expiryTime = toTime + duration.days(100); // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, 1, { from: account_issuer, gas: 6000000 }); @@ -277,7 +277,7 @@ contract("PreSaleSTO", accounts => { expiryTime = toTime + duration.days(100); // Add the Investor in to the whitelist - let tx1 = await I_GeneralTransferManager.modifyWhitelist(account_investor2, fromTime, toTime, expiryTime, true, { + let tx1 = await I_GeneralTransferManager.modifyWhitelist(account_investor2, fromTime, toTime, expiryTime, 1, { from: account_issuer, gas: 6000000 }); @@ -285,7 +285,7 @@ contract("PreSaleSTO", accounts => { assert.equal(tx1.logs[0].args._investor, account_investor2, "Failed in adding the investor in whitelist"); // Add the Investor in to the whitelist - let tx2 = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, true, { + let tx2 = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, 1, { from: account_issuer, gas: 6000000 }); diff --git a/test/o_security_token.js b/test/o_security_token.js index 52521181e..7d2722a20 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -193,7 +193,7 @@ contract("SecurityToken", accounts => { let toTime = fromTime + duration.days(100); let expiryTime = toTime + duration.days(100); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_affiliate1, fromTime, toTime, expiryTime, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_affiliate1, fromTime, toTime, expiryTime, 1, { from: token_owner, gas: 6000000 }); @@ -212,7 +212,7 @@ contract("SecurityToken", accounts => { let toTime = fromTime + duration.days(100); let expiryTime = toTime + duration.days(100); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_affiliate2, fromTime, toTime, expiryTime, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_affiliate2, fromTime, toTime, expiryTime, 1, { from: token_owner, gas: 6000000 }); @@ -517,7 +517,7 @@ contract("SecurityToken", accounts => { toTime = fromTime + duration.days(100); expiryTime = toTime + duration.days(100); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, 1, { from: token_owner, gas: 6000000 }); @@ -614,7 +614,7 @@ contract("SecurityToken", accounts => { }); it("Should transfer from whitelist investor1 to whitelist investor 2", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor2, fromTime, toTime, expiryTime, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor2, fromTime, toTime, expiryTime, 1, { from: token_owner, gas: 500000 }); @@ -636,7 +636,7 @@ contract("SecurityToken", accounts => { it("Should transferFrom from one investor to other", async () => { await I_SecurityToken.approve(account_investor1, 2 * Math.pow(10, 18), { from: account_investor2 }); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, 1, { from: token_owner, gas: 500000 }); @@ -682,7 +682,7 @@ contract("SecurityToken", accounts => { }); it("Should add the investor in the whitelist by the delegate", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, fromTime, toTime, expiryTime, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, fromTime, toTime, expiryTime, 1, { from: account_delegate, gas: 6000000 }); @@ -722,7 +722,7 @@ contract("SecurityToken", accounts => { }); it("Should remove investor from the whitelist by the delegate", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, 0, 0, 0, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, 0, 0, 0, 1, { from: account_delegate, gas: 6000000 }); @@ -751,7 +751,7 @@ contract("SecurityToken", accounts => { }); it("Should fail in buying to tokens", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, fromTime, toTime, expiryTime, true, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, fromTime, toTime, expiryTime, 1, { from: account_delegate, gas: 6000000 }); @@ -939,7 +939,7 @@ contract("SecurityToken", accounts => { latestTime(), latestTime() + duration.seconds(2), latestTime() + duration.days(50), - true, + 1, { from: account_delegate, gas: 6000000 @@ -982,7 +982,7 @@ contract("SecurityToken", accounts => { latestTime(), latestTime() + duration.seconds(2), latestTime() + duration.days(50), - true, + 1, { from: account_delegate, gas: 6000000 diff --git a/test/p_usd_tiered_sto.js b/test/p_usd_tiered_sto.js index 604eb1aaf..8a274942a 100644 --- a/test/p_usd_tiered_sto.js +++ b/test/p_usd_tiered_sto.js @@ -222,7 +222,7 @@ contract("USDTieredSTO", accounts => { I_SecurityTokenRegistryProxy, I_STRProxied ] = instances; - + I_DaiToken = await PolyTokenFaucet.new({from: POLYMATH}); // STEP 4: Deploy the GeneralDelegateManagerFactory [I_GeneralPermissionManagerFactory] = await deployGPMAndVerifyed(POLYMATH, I_MRProxied, I_PolyToken.address, 0); @@ -1005,7 +1005,7 @@ contract("USDTieredSTO", accounts => { let fromTime = latestTime(); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let whitelisted = true; + let whitelisted = 1; await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); @@ -1105,7 +1105,7 @@ contract("USDTieredSTO", accounts => { let fromTime = latestTime(); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let whitelisted = true; + let whitelisted = 1; await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); @@ -1160,7 +1160,7 @@ contract("USDTieredSTO", accounts => { let fromTime = latestTime(); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let whitelisted = true; + let whitelisted = 1; await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); @@ -1230,7 +1230,7 @@ contract("USDTieredSTO", accounts => { let fromTime = latestTime(); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let whitelisted = true; + let whitelisted = 1; await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); @@ -1285,7 +1285,7 @@ contract("USDTieredSTO", accounts => { let fromTime = latestTime(); let toTime = latestTime(); let expiryTime = toTime + duration.days(100); - let whitelisted = true; + let whitelisted = 1; await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); @@ -1353,7 +1353,7 @@ contract("USDTieredSTO", accounts => { let fromTime = latestTime(); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let whitelisted = true; + let whitelisted = 1; const tx1 = await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER @@ -4482,7 +4482,7 @@ contract("USDTieredSTO", accounts => { "fundsRaisedUSD not changed as expected" ); }); - + it("should return minted tokens in a tier", async () => { let totalMinted = (await I_USDTieredSTO_Array[0].getTokensSoldByTier.call(0)).toNumber(); let individualMinted = await I_USDTieredSTO_Array[0].getTokensMintedByTier.call(0); @@ -4564,7 +4564,7 @@ contract("USDTieredSTO", accounts => { assert.equal((await I_USDTieredSTOFactory.getSetupCost.call()).toNumber(), STOSetupCost); assert.equal((await I_USDTieredSTOFactory.getTypes.call())[0], 3); assert.equal(web3.utils.hexToString(await I_USDTieredSTOFactory.getName.call()), "USDTieredSTO", "Wrong Module added"); - assert.equal(await I_USDTieredSTOFactory.description.call(), + assert.equal(await I_USDTieredSTOFactory.description.call(), "It allows both accredited and non-accredited investors to contribute into the STO. Non-accredited investors will be capped at a maximum investment limit (as a default or specific to their jurisdiction). Tokens will be sold according to tiers sequentially & each tier has its own price and volume of tokens to sell. Upon receipt of funds (ETH, POLY or DAI), security tokens will automatically transfer to investor’s wallet address", "Wrong Module added"); assert.equal(await I_USDTieredSTOFactory.title.call(), "USD Tiered STO", "Wrong Module added"); diff --git a/test/q_usd_tiered_sto_sim.js b/test/q_usd_tiered_sto_sim.js index 55f84f2b3..31929ade5 100644 --- a/test/q_usd_tiered_sto_sim.js +++ b/test/q_usd_tiered_sto_sim.js @@ -195,7 +195,7 @@ contract("USDTieredSTO Sim", accounts => { I_SecurityTokenRegistryProxy, I_STRProxied ] = instances; - + I_DaiToken = await PolyTokenFaucet.new({from: POLYMATH}); // STEP 5: Deploy the USDTieredSTOFactory @@ -353,13 +353,13 @@ contract("USDTieredSTO Sim", accounts => { let fromTime = latestTime() + duration.days(15); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let canBuyFromSTO = true; + let canBuyFromSTO = 1; await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, canBuyFromSTO, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(ACCREDITED2, fromTime, toTime, expiryTime, canBuyFromSTO, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, canBuyFromSTO, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED2, fromTime, toTime, expiryTime, canBuyFromSTO, { from: ISSUER }); - await I_GeneralTransferManager.modifyWhitelist(NOTAPPROVED, fromTime, toTime, expiryTime, false, { from: ISSUER }); + await I_GeneralTransferManager.modifyWhitelist(NOTAPPROVED, fromTime, toTime, expiryTime, 0, { from: ISSUER }); await increaseTime(duration.days(3)); diff --git a/test/r_concurrent_STO.js b/test/r_concurrent_STO.js index 7912658a4..36761308e 100644 --- a/test/r_concurrent_STO.js +++ b/test/r_concurrent_STO.js @@ -2,7 +2,7 @@ import latestTime from "./helpers/latestTime"; import { duration, promisifyLogWatch, latestBlock } from "./helpers/utils"; import { takeSnapshot, increaseTime, revertToSnapshot } from "./helpers/time"; import { encodeProxyCall, encodeModuleCall } from "./helpers/encodeCall"; -import { +import { setUpPolymathNetwork, deployDummySTOAndVerifyed, deployCappedSTOAndVerifyed, @@ -94,7 +94,7 @@ contract("Concurrent STO", accounts => { I_SecurityTokenRegistryProxy, I_STRProxied ] = instances; - + // STEP 2: Deploy the STO Factories [I_CappedSTOFactory] = await deployCappedSTOAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, STOSetupCost); @@ -159,7 +159,7 @@ contract("Concurrent STO", accounts => { let fromTime = latestTime(); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let canBuyFromSTO = true; + let canBuyFromSTO = 1; let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, canBuyFromSTO, { from: account_issuer, diff --git a/test/v_tracked_redemptions.js b/test/v_tracked_redemptions.js index 159564651..eacddd87e 100644 --- a/test/v_tracked_redemptions.js +++ b/test/v_tracked_redemptions.js @@ -102,7 +102,7 @@ contract("TrackedRedemption", accounts => { I_STRProxied ] = instances; - + // STEP 4: Deploy the TrackedRedemption [I_TrackedRedemptionFactory] = await deployRedemptionAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); [P_TrackedRedemptionFactory] = await deployRedemptionAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, web3.utils.toWei("500")); @@ -190,7 +190,7 @@ contract("TrackedRedemption", accounts => { latestTime(), latestTime(), latestTime() + duration.days(30), - true, + 1, { from: account_issuer, gas: 500000 @@ -220,7 +220,7 @@ contract("TrackedRedemption", accounts => { latestTime(), latestTime(), latestTime() + duration.days(30), - true, + 1, { from: account_issuer, gas: 500000 diff --git a/test/w_lockup_volume_restriction_transfer_manager.js b/test/w_lockup_volume_restriction_transfer_manager.js index fe06f3f5c..7646fb031 100644 --- a/test/w_lockup_volume_restriction_transfer_manager.js +++ b/test/w_lockup_volume_restriction_transfer_manager.js @@ -112,7 +112,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { STFactory: ${I_STFactory.address} GeneralTransferManagerFactory: ${I_GeneralTransferManagerFactory.address} - LockupVolumeRestrictionTransferManagerFactory: + LockupVolumeRestrictionTransferManagerFactory: ${I_VolumeRestrictionTransferManagerFactory.address} ----------------------------------------------------------------------------- `); @@ -165,7 +165,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer }); @@ -192,7 +192,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer }); @@ -249,7 +249,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer }); @@ -346,14 +346,14 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { // balance should be 9000000000000000000 here (9 eth) let balance = await I_SecurityToken.balanceOf(account_investor2) - + // create a lockup for their entire balance // over 16 seconds total, with 4 periods of 4 seconds each. // this will generate an exception because 9000000000000000000 / 4 = 2250000000000000000 but the token granularity is 1000000000000000000 await catchRevert( I_VolumeRestrictionTransferManager.addLockUp(account_investor2, 16, 4, 0, balance, { from: token_owner }) ); - + }); it("Should prevent the transfer of tokens in a lockup", async() => { @@ -572,7 +572,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { }); it("Should revert if the parameters are bad when creating multiple lockups", async() => { - + await catchRevert( // pass in the wrong number of params. txn should revert I_VolumeRestrictionTransferManager.addLockUpMulti( diff --git a/test/x_single_trade_volume_restriction.js b/test/x_single_trade_volume_restriction.js index 15c01e68c..25243a638 100644 --- a/test/x_single_trade_volume_restriction.js +++ b/test/x_single_trade_volume_restriction.js @@ -107,7 +107,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { // STEP 4: Deploy the SingleTradeVolumeRestrictionManagerFactory [I_SingleTradeVolumeRestrictionManagerFactory] = await deploySingleTradeVolumeRMAndVerified(account_polymath, I_MRProxied, I_PolyToken.address, 0); [P_SingleTradeVolumeRestrictionManagerFactory] = await deploySingleTradeVolumeRMAndVerified(account_polymath, I_MRProxied, I_PolyToken.address, web3.utils.toWei("500")); - + }); describe("Generate the SecurityToken", async () => { @@ -165,7 +165,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, { + 1, { from: account_issuer }); @@ -193,7 +193,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, { + 1, { from: account_issuer }); @@ -212,7 +212,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { // it("Fails to attach the SingleTradeVolumeRestrictionManager with the security token due to fees not paid", async () => { let managerArgs = encodeModuleCall(STVRParameters, [true, 90, false]); - + await I_PolyToken.getTokens(web3.utils.toWei("500", "ether"), token_owner); await catchRevert( I_SecurityToken.addModule(P_SingleTradeVolumeRestrictionManagerFactory.address, managerArgs, web3.utils.toWei("500", "ether"), 0, { from: token_owner}) @@ -222,7 +222,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { it("Should successfully attach the Paid SingleTradeVolumeRestrictionManager with the security token", async () => { let managerArgs = encodeModuleCall(STVRParameters, [false, 90, false]); await I_PolyToken.transfer(I_SecurityToken.address, web3.utils.toWei("500", "ether"), { from: token_owner }); - + let tx = await I_SecurityToken.addModule(P_SingleTradeVolumeRestrictionManagerFactory.address, managerArgs, web3.utils.toWei("500", "ether"), 0, { from: token_owner }); @@ -291,7 +291,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { I_SingleTradeVolumeRestrictionManager.addExemptWallet(accounts[5]) ); - await catchRevert( + await catchRevert( I_SingleTradeVolumeRestrictionManager.addExemptWallet(zero_address, { from: token_owner }) ); @@ -342,7 +342,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { await catchRevert ( I_SingleTradeVolumeRestrictionPercentageManager.setTransferLimitInPercentage(accounts[4], 101 * 10 ** 16, { from: token_owner }) ); - // Transfer limit in tokens can not be set for a manager that has transfer limit set as percentage + // Transfer limit in tokens can not be set for a manager that has transfer limit set as percentage await catchRevert ( I_SingleTradeVolumeRestrictionPercentageManager.setTransferLimitInTokens(accounts[4], 1, { from: token_owner }) ); @@ -393,7 +393,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { from: token_owner }); assert.equal(tx.logs[0].args._amount, 10, "Global Limit not set"); - + //Global limit can be set by non-admins await catchRevert( I_SingleTradeVolumeRestrictionPercentageManager.changeGlobalLimitInTokens(89) @@ -542,7 +542,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, { + 1, { from: account_issuer } ); @@ -552,7 +552,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, { + 1, { from: account_issuer } ); @@ -562,7 +562,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, { + 1, { from: account_issuer } ); @@ -667,7 +667,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { }); it('should change transfer limits to tokens', async () => { - // Should not change to percentage again + // Should not change to percentage again await catchRevert( I_SingleTradeVolumeRestrictionPercentageManager.changeTransferLimitToPercentage(1, { from: token_owner }) ); diff --git a/test/y_scheduled_checkpoints.js b/test/y_scheduled_checkpoints.js index 5fcc03a74..864c6b9a1 100644 --- a/test/y_scheduled_checkpoints.js +++ b/test/y_scheduled_checkpoints.js @@ -192,7 +192,7 @@ contract('ScheduledCheckpoint', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 6000000 @@ -235,7 +235,7 @@ contract('ScheduledCheckpoint', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 6000000 @@ -270,7 +270,7 @@ contract('ScheduledCheckpoint', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - true, + 1, { from: account_issuer, gas: 6000000 From 704751d3ed72e06605e29e460fe4148efb3bd582 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Mon, 26 Nov 2018 10:42:33 +0530 Subject: [PATCH 53/93] Add whitelist optimization --- .../GeneralTransferManager.sol | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index a7029caa1..566ee19d1 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -179,6 +179,26 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag ) public withPerm(WHITELIST) + { + _modifyWhitelist(_investor, _fromTime, _toTime, _expiryTime, _canBuyFromSTO); + } + + /** + * @notice Adds or removes addresses from the whitelist. + * @param _investor is the address to whitelist + * @param _fromTime is the moment when the sale lockup period ends and the investor can freely sell his tokens + * @param _toTime is the moment when the purchase lockup period ends and the investor can freely purchase tokens from others + * @param _expiryTime is the moment till investors KYC will be validated. After that investor need to do re-KYC + * @param _canBuyFromSTO is used to know whether the investor is restricted investor or not. + */ + function _modifyWhitelist( + address _investor, + uint64 _fromTime, + uint64 _toTime, + uint64 _expiryTime, + uint8 _canBuyFromSTO + ) + internal { if (whitelist[_investor].added == uint8(0)) { investors.push(_investor); @@ -208,7 +228,7 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag require(_toTimes.length == _expiryTimes.length, "Mismatched input lengths"); require(_canBuyFromSTO.length == _toTimes.length, "Mismatched input length"); for (uint256 i = 0; i < _investors.length; i++) { - modifyWhitelist(_investors[i], _fromTimes[i], _toTimes[i], _expiryTimes[i], _canBuyFromSTO[i]); + _modifyWhitelist(_investors[i], _fromTimes[i], _toTimes[i], _expiryTimes[i], _canBuyFromSTO[i]); } } From babb4cb4a04fd11131618e489f4fbb65e8ced97a Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 26 Nov 2018 14:31:10 +0000 Subject: [PATCH 54/93] Make Dividend modules proxies --- .../modules/Checkpoint/DividendCheckpoint.sol | 37 +--------- .../Checkpoint/DividendCheckpointStorage.sol | 50 +++++++++++++ .../Checkpoint/ERC20DividendCheckpoint.sol | 39 +++++----- .../ERC20DividendCheckpointFactory.sol | 9 ++- .../ERC20DividendCheckpointStorage.sol | 11 +++ .../Checkpoint/EtherDividendCheckpoint.sol | 25 +++---- .../EtherDividendCheckpointFactory.sol | 9 ++- .../GeneralTransferManager.sol | 6 ++ .../GeneralTransferManagerFactory.sol | 1 + .../GeneralTransferManagerStorage.sol | 2 - .../proxy/ERC20DividendCheckpointProxy.sol | 48 +++++++++++++ .../proxy/EtherDividendCheckpointProxy.sol | 47 ++++++++++++ scripts/compareStorageLayout.js | 71 +++++++++++++++++++ 13 files changed, 280 insertions(+), 75 deletions(-) create mode 100644 contracts/modules/Checkpoint/DividendCheckpointStorage.sol create mode 100644 contracts/modules/Checkpoint/ERC20DividendCheckpointStorage.sol create mode 100644 contracts/proxy/ERC20DividendCheckpointProxy.sol create mode 100644 contracts/proxy/EtherDividendCheckpointProxy.sol create mode 100644 scripts/compareStorageLayout.js diff --git a/contracts/modules/Checkpoint/DividendCheckpoint.sol b/contracts/modules/Checkpoint/DividendCheckpoint.sol index 452a48b13..3a345af25 100644 --- a/contracts/modules/Checkpoint/DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/DividendCheckpoint.sol @@ -8,6 +8,7 @@ pragma solidity ^0.4.24; import "./ICheckpoint.sol"; +import "./DividendCheckpointStorage.sol"; import "../Module.sol"; import "../../interfaces/ISecurityToken.sol"; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; @@ -17,43 +18,9 @@ import "openzeppelin-solidity/contracts/math/Math.sol"; * @title Checkpoint module for issuing ether dividends * @dev abstract contract */ -contract DividendCheckpoint is ICheckpoint, Module { +contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module { using SafeMath for uint256; - uint256 public EXCLUDED_ADDRESS_LIMIT = 50; - bytes32 public constant DISTRIBUTE = "DISTRIBUTE"; - bytes32 public constant MANAGE = "MANAGE"; - bytes32 public constant CHECKPOINT = "CHECKPOINT"; - - struct Dividend { - uint256 checkpointId; - uint256 created; // Time at which the dividend was created - uint256 maturity; // Time after which dividend can be claimed - set to 0 to bypass - uint256 expiry; // Time until which dividend can be claimed - after this time any remaining amount can be withdrawn by issuer - - // set to very high value to bypass - uint256 amount; // Dividend amount in WEI - uint256 claimedAmount; // Amount of dividend claimed so far - uint256 totalSupply; // Total supply at the associated checkpoint (avoids recalculating this) - bool reclaimed; // True if expiry has passed and issuer has reclaimed remaining dividend - uint256 dividendWithheld; - uint256 dividendWithheldReclaimed; - mapping (address => bool) claimed; // List of addresses which have claimed dividend - mapping (address => bool) dividendExcluded; // List of addresses which cannot claim dividends - bytes32 name; // Name/title - used for identification - } - - // List of all dividends - Dividend[] public dividends; - - // List of addresses which cannot claim dividends - address[] public excluded; - - // Mapping from address to withholding tax as a percentage * 10**16 - mapping (address => uint256) public withholdingTax; - - // Total amount of ETH withheld per investor - mapping (address => uint256) public investorWithheld; - event SetDefaultExcludedAddresses(address[] _excluded, uint256 _timestamp); event SetWithholding(address[] _investors, uint256[] _withholding, uint256 _timestamp); event SetWithholdingFixed(address[] _investors, uint256 _withholding, uint256 _timestamp); diff --git a/contracts/modules/Checkpoint/DividendCheckpointStorage.sol b/contracts/modules/Checkpoint/DividendCheckpointStorage.sol new file mode 100644 index 000000000..bf86191e6 --- /dev/null +++ b/contracts/modules/Checkpoint/DividendCheckpointStorage.sol @@ -0,0 +1,50 @@ +/** + * DISCLAIMER: Under certain conditions, the function pushDividendPayment + * may fail due to block gas limits. + * If the total number of investors that ever held tokens is greater than ~15,000 then + * the function may fail. If this happens investors can pull their dividends, or the Issuer + * can use pushDividendPaymentToAddresses to provide an explict address list in batches + */ +pragma solidity ^0.4.24; + +/** + * @title Checkpoint module for issuing ether dividends + * @dev abstract contract + */ +contract DividendCheckpointStorage { + + uint256 public EXCLUDED_ADDRESS_LIMIT = 50; + bytes32 public constant DISTRIBUTE = "DISTRIBUTE"; + bytes32 public constant MANAGE = "MANAGE"; + bytes32 public constant CHECKPOINT = "CHECKPOINT"; + + struct Dividend { + uint256 checkpointId; + uint256 created; // Time at which the dividend was created + uint256 maturity; // Time after which dividend can be claimed - set to 0 to bypass + uint256 expiry; // Time until which dividend can be claimed - after this time any remaining amount can be withdrawn by issuer - + // set to very high value to bypass + uint256 amount; // Dividend amount in WEI + uint256 claimedAmount; // Amount of dividend claimed so far + uint256 totalSupply; // Total supply at the associated checkpoint (avoids recalculating this) + bool reclaimed; // True if expiry has passed and issuer has reclaimed remaining dividend + uint256 dividendWithheld; + uint256 dividendWithheldReclaimed; + mapping (address => bool) claimed; // List of addresses which have claimed dividend + mapping (address => bool) dividendExcluded; // List of addresses which cannot claim dividends + bytes32 name; // Name/title - used for identification + } + + // List of all dividends + Dividend[] public dividends; + + // List of addresses which cannot claim dividends + address[] public excluded; + + // Mapping from address to withholding tax as a percentage * 10**16 + mapping (address => uint256) public withholdingTax; + + // Total amount of ETH withheld per investor + mapping (address => uint256) public investorWithheld; + +} diff --git a/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol b/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol index 1f7f25cd5..b779088f7 100644 --- a/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol @@ -1,17 +1,16 @@ pragma solidity ^0.4.24; import "./DividendCheckpoint.sol"; +import "./ERC20DividendCheckpointStorage.sol"; import "../../interfaces/IOwnable.sol"; import "../../interfaces/IERC20.sol"; /** * @title Checkpoint module for issuing ERC20 dividends */ -contract ERC20DividendCheckpoint is DividendCheckpoint { +contract ERC20DividendCheckpoint is ERC20DividendCheckpointStorage, DividendCheckpoint { using SafeMath for uint256; - // Mapping to token address for each dividend - mapping (uint256 => address) public dividendTokens; event ERC20DividendDeposited( address indexed _depositor, uint256 _checkpointId, @@ -68,8 +67,8 @@ contract ERC20DividendCheckpoint is DividendCheckpoint { address _token, uint256 _amount, bytes32 _name - ) - external + ) + external withPerm(MANAGE) { createDividendWithExclusions(_maturity, _expiry, _token, _amount, excluded, _name); @@ -133,16 +132,16 @@ contract ERC20DividendCheckpoint is DividendCheckpoint { * @param _name Name/Title for identification */ function createDividendWithCheckpointAndExclusions( - uint256 _maturity, - uint256 _expiry, - address _token, - uint256 _amount, - uint256 _checkpointId, + uint256 _maturity, + uint256 _expiry, + address _token, + uint256 _amount, + uint256 _checkpointId, address[] _excluded, bytes32 _name - ) + ) public - withPerm(MANAGE) + withPerm(MANAGE) { _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, _excluded, _name); } @@ -158,15 +157,15 @@ contract ERC20DividendCheckpoint is DividendCheckpoint { * @param _name Name/Title for identification */ function _createDividendWithCheckpointAndExclusions( - uint256 _maturity, - uint256 _expiry, - address _token, - uint256 _amount, - uint256 _checkpointId, + uint256 _maturity, + uint256 _expiry, + address _token, + uint256 _amount, + uint256 _checkpointId, address[] _excluded, bytes32 _name - ) - internal + ) + internal { ISecurityToken securityTokenInstance = ISecurityToken(securityToken); require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many addresses excluded"); @@ -210,7 +209,7 @@ contract ERC20DividendCheckpoint is DividendCheckpoint { } /** - * @notice Emits the ERC20DividendDeposited event. + * @notice Emits the ERC20DividendDeposited event. * Seperated into a different function as a workaround for stack too deep error */ function _emitERC20DividendDepositedEvent( diff --git a/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol b/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol index 5fd158c26..a684e553b 100644 --- a/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol +++ b/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "./ERC20DividendCheckpoint.sol"; +import "../../proxy/ERC20DividendCheckpointProxy.sol"; import "../ModuleFactory.sol"; /** @@ -8,6 +8,8 @@ import "../ModuleFactory.sol"; */ contract ERC20DividendCheckpointFactory is ModuleFactory { + address public logicContract; + /** * @notice Constructor * @param _polyAddress Address of the polytoken @@ -15,7 +17,7 @@ contract ERC20DividendCheckpointFactory is ModuleFactory { * @param _usageCost Usage cost of the module * @param _subscriptionCost Subscription cost of the module */ - constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public + constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost, address _logicContract) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { version = "1.0.0"; @@ -24,6 +26,7 @@ contract ERC20DividendCheckpointFactory is ModuleFactory { description = "Create ERC20 dividends for token holders at a specific checkpoint"; compatibleSTVersionRange["lowerBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); compatibleSTVersionRange["upperBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); + logicContract = _logicContract; } /** @@ -33,7 +36,7 @@ contract ERC20DividendCheckpointFactory is ModuleFactory { function deploy(bytes /* _data */) external returns(address) { if (setupCost > 0) require(polyToken.transferFrom(msg.sender, owner, setupCost), "insufficent allowance"); - address erc20DividendCheckpoint = new ERC20DividendCheckpoint(msg.sender, address(polyToken)); + address erc20DividendCheckpoint = new ERC20DividendCheckpointProxy(msg.sender, address(polyToken), logicContract); /*solium-disable-next-line security/no-block-members*/ emit GenerateModuleFromFactory(erc20DividendCheckpoint, getName(), address(this), msg.sender, setupCost, now); return erc20DividendCheckpoint; diff --git a/contracts/modules/Checkpoint/ERC20DividendCheckpointStorage.sol b/contracts/modules/Checkpoint/ERC20DividendCheckpointStorage.sol new file mode 100644 index 000000000..8bbd13bb6 --- /dev/null +++ b/contracts/modules/Checkpoint/ERC20DividendCheckpointStorage.sol @@ -0,0 +1,11 @@ +pragma solidity ^0.4.24; + +/** + * @title Checkpoint module for issuing ERC20 dividends + */ +contract ERC20DividendCheckpointStorage { + + // Mapping to token address for each dividend + mapping (uint256 => address) public dividendTokens; + +} diff --git a/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol b/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol index 4def51468..f5a916818 100644 --- a/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol @@ -8,6 +8,7 @@ import "../../interfaces/IOwnable.sol"; */ contract EtherDividendCheckpoint is DividendCheckpoint { using SafeMath for uint256; + event EtherDividendDeposited( address indexed _depositor, uint256 _checkpointId, @@ -56,7 +57,7 @@ contract EtherDividendCheckpoint is DividendCheckpoint { uint256 _expiry, uint256 _checkpointId, bytes32 _name - ) + ) external payable withPerm(MANAGE) @@ -76,7 +77,7 @@ contract EtherDividendCheckpoint is DividendCheckpoint { uint256 _expiry, address[] _excluded, bytes32 _name - ) + ) public payable withPerm(MANAGE) @@ -94,10 +95,10 @@ contract EtherDividendCheckpoint is DividendCheckpoint { * @param _name Name/title for identification */ function createDividendWithCheckpointAndExclusions( - uint256 _maturity, - uint256 _expiry, - uint256 _checkpointId, - address[] _excluded, + uint256 _maturity, + uint256 _expiry, + uint256 _checkpointId, + address[] _excluded, bytes32 _name ) public @@ -116,12 +117,12 @@ contract EtherDividendCheckpoint is DividendCheckpoint { * @param _name Name/title for identification */ function _createDividendWithCheckpointAndExclusions( - uint256 _maturity, - uint256 _expiry, - uint256 _checkpointId, - address[] _excluded, + uint256 _maturity, + uint256 _expiry, + uint256 _checkpointId, + address[] _excluded, bytes32 _name - ) + ) internal { require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many addresses excluded"); @@ -169,7 +170,7 @@ contract EtherDividendCheckpoint is DividendCheckpoint { */ function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal { (uint256 claim, uint256 withheld) = calculateDividend(_dividendIndex, _payee); - _dividend.claimed[_payee] = true; + _dividend.claimed[_payee] = true; uint256 claimAfterWithheld = claim.sub(withheld); if (claimAfterWithheld > 0) { /*solium-disable-next-line security/no-send*/ diff --git a/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol b/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol index 315760be1..3129fba42 100644 --- a/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol +++ b/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "./EtherDividendCheckpoint.sol"; +import "../../proxy/EtherDividendCheckpointProxy.sol"; import "../ModuleFactory.sol"; /** @@ -8,6 +8,8 @@ import "../ModuleFactory.sol"; */ contract EtherDividendCheckpointFactory is ModuleFactory { + address public logicContract; + /** * @notice Constructor * @param _polyAddress Address of the polytoken @@ -15,7 +17,7 @@ contract EtherDividendCheckpointFactory is ModuleFactory { * @param _usageCost Usage cost of the module * @param _subscriptionCost Subscription cost of the module */ - constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public + constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost, address _logicContract) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { version = "1.0.0"; @@ -24,6 +26,7 @@ contract EtherDividendCheckpointFactory is ModuleFactory { description = "Create ETH dividends for token holders at a specific checkpoint"; compatibleSTVersionRange["lowerBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); compatibleSTVersionRange["upperBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); + logicContract = _logicContract; } /** @@ -33,7 +36,7 @@ contract EtherDividendCheckpointFactory is ModuleFactory { function deploy(bytes /* _data */) external returns(address) { if(setupCost > 0) require(polyToken.transferFrom(msg.sender, owner, setupCost), "Insufficent allowance or balance"); - address ethDividendCheckpoint = new EtherDividendCheckpoint(msg.sender, address(polyToken)); + address ethDividendCheckpoint = new EtherDividendCheckpointProxy(msg.sender, address(polyToken), logicContract); /*solium-disable-next-line security/no-block-members*/ emit GenerateModuleFromFactory(ethDividendCheckpoint, getName(), address(this), msg.sender, setupCost, now); return ethDividendCheckpoint; diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index 566ee19d1..04028fead 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -26,6 +26,11 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag // Emit when investor details get modified related to their whitelisting event OffsetModified(uint64 _time, uint8 _isForward); + // _fromTime is the time from which the _investor can send tokens + // _toTime is the time from which the _investor can receive tokens + // if allowAllWhitelistIssuances is TRUE, then _toTime is ignored when receiving tokens from the issuance address + // if allowAllWhitelistTransfers is TRUE, then _toTime and _fromTime is ignored when sending or receiving tokens + // in any case, any investor sending or receiving tokens, must have a _expiryTime in the future event ModifyWhitelist( address _investor, uint256 _dateAdded, @@ -200,6 +205,7 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag ) internal { + require(_investor != address(0), "Invalid investor"); if (whitelist[_investor].added == uint8(0)) { investors.push(_investor); } diff --git a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol index c37ab8b4b..4c81be20a 100644 --- a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol @@ -17,6 +17,7 @@ contract GeneralTransferManagerFactory is ModuleFactory { constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost, address _logicContract) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { + require(_logicContract != address(0), "Invalid logic contract"); version = "1.0.0"; name = "GeneralTransferManager"; title = "General Transfer Manager"; diff --git a/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol b/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol index 6cfb29e21..f5c162080 100644 --- a/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol +++ b/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol @@ -1,7 +1,5 @@ pragma solidity ^0.4.24; -import "./ITransferManager.sol"; - /** * @title Transfer Manager module for core transfer validation functionality */ diff --git a/contracts/proxy/ERC20DividendCheckpointProxy.sol b/contracts/proxy/ERC20DividendCheckpointProxy.sol new file mode 100644 index 000000000..33c27fd4e --- /dev/null +++ b/contracts/proxy/ERC20DividendCheckpointProxy.sol @@ -0,0 +1,48 @@ +pragma solidity ^0.4.24; + +import "../modules/Checkpoint/ERC20DividendCheckpointStorage.sol"; +import "../modules/Checkpoint/DividendCheckpointStorage.sol"; +import "./Proxy.sol"; +import "../Pausable.sol"; +import "../modules/ModuleStorage.sol"; + +/** + * @title Transfer Manager module for core transfer validation functionality + */ +contract ERC20DividendCheckpointProxy is ERC20DividendCheckpointStorage, DividendCheckpointStorage, ModuleStorage, Pausable, Proxy { + + // Address of the current implementation + address internal __implementation; + + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + * @param _implementation representing the address of the new implementation to be set + */ + constructor (address _securityToken, address _polyAddress, address _implementation) + public + ModuleStorage(_securityToken, _polyAddress) + { + require( + _implementation != address(0), + "Implementation address should not be 0x" + ); + __implementation = _implementation; + } + + /** + * @notice Internal function to provide the address of the implementation contract + */ + function _implementation() internal view returns (address) { + return __implementation; + } + + /** + * @dev Tells the address of the current implementation + * @return address of the current implementation + */ + function implementation() external view returns (address) { + return _implementation(); + } +} diff --git a/contracts/proxy/EtherDividendCheckpointProxy.sol b/contracts/proxy/EtherDividendCheckpointProxy.sol new file mode 100644 index 000000000..4786736ea --- /dev/null +++ b/contracts/proxy/EtherDividendCheckpointProxy.sol @@ -0,0 +1,47 @@ +pragma solidity ^0.4.24; + +import "../modules/Checkpoint/DividendCheckpointStorage.sol"; +import "./Proxy.sol"; +import "../Pausable.sol"; +import "../modules/ModuleStorage.sol"; + +/** + * @title Transfer Manager module for core transfer validation functionality + */ +contract EtherDividendCheckpointProxy is DividendCheckpointStorage, ModuleStorage, Pausable, Proxy { + + // Address of the current implementation + address internal __implementation; + + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + * @param _implementation representing the address of the new implementation to be set + */ + constructor (address _securityToken, address _polyAddress, address _implementation) + public + ModuleStorage(_securityToken, _polyAddress) + { + require( + _implementation != address(0), + "Implementation address should not be 0x" + ); + __implementation = _implementation; + } + + /** + * @notice Internal function to provide the address of the implementation contract + */ + function _implementation() internal view returns (address) { + return __implementation; + } + + /** + * @dev Tells the address of the current implementation + * @return address of the current implementation + */ + function implementation() external view returns (address) { + return _implementation(); + } +} diff --git a/scripts/compareStorageLayout.js b/scripts/compareStorageLayout.js new file mode 100644 index 000000000..5bf50a985 --- /dev/null +++ b/scripts/compareStorageLayout.js @@ -0,0 +1,71 @@ +const fs = require('fs'); +const logicContract = fs.readFileSync('./logic.sol', 'utf8'); +const proxyContract = fs.readFileSync('./proxy.sol', 'utf8'); +const _ = require('underscore'); +const solc = require('solc'); + +let logicInput = { + 'contracts': logicContract +} +let proxyInput = { + 'contracts': proxyContract +} + +function traverseAST(_input, _elements) { + if(_input.children) { + for(var i=0;i<_input.children.length;i++) { + traverseAST(_input.children[i], _elements); + } + } + _elements.push(_input); +} + +function compareStorageLayouts(oldLayout, newLayout) { + function makeComp(x) { + return [x.constant, x.name, x.scope, x.stateVariable, x.storageLocation, x.type, x.value, x.visibility].join(':'); + } + // if(newLayout.length < oldLayout.length) return false; + for(var i=0;i e.name == 'ContractDefinition'); + + // filter out all linearizedBaseContracts + // pick the last one as the last contract always has the full inheritance + const linearizedBaseContracts = _.last(_.map(contractDefinitions, e => e.attributes.linearizedBaseContracts)); + + // get all stateVariables + const stateVariables = _.filter(elements, e => e.attributes && e.attributes.stateVariable ) + + // group them by scope + const stateVariableMap = _.groupBy(stateVariables, e => e.attributes.scope); + + orderedStateVariables = _.reduceRight(linearizedBaseContracts, (a, b) => { + return a.concat(stateVariableMap[b] || []) + }, []); + return orderedStateVariables; +} + +// console.log(orderedStateVariables); +console.log(compareStorageLayouts(parseContract(logicInput), parseContract(proxyInput))); From 0c19bf2acf8ebc06cebe8ebb21c82e6d06a63569 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 26 Nov 2018 17:17:58 +0000 Subject: [PATCH 55/93] Updates --- .../proxy/ERC20DividendCheckpointProxy.sol | 21 +- .../proxy/EtherDividendCheckpointProxy.sol | 21 +- .../proxy/GeneralTransferManagerProxy.sol | 21 +- contracts/proxy/OwnedProxy.sol | 91 ++ migrations/2_deploy_contracts.js | 16 +- scripts/compareStorageLayout.js | 14 +- scripts/logic.sol | 1188 +++++++++++++++++ scripts/proxy.sol | 332 +++++ test/h_general_transfer_manager.js | 3 +- test/helpers/createInstances.js | 10 +- 10 files changed, 1648 insertions(+), 69 deletions(-) create mode 100644 contracts/proxy/OwnedProxy.sol create mode 100644 scripts/logic.sol create mode 100644 scripts/proxy.sol diff --git a/contracts/proxy/ERC20DividendCheckpointProxy.sol b/contracts/proxy/ERC20DividendCheckpointProxy.sol index 33c27fd4e..8839d30e1 100644 --- a/contracts/proxy/ERC20DividendCheckpointProxy.sol +++ b/contracts/proxy/ERC20DividendCheckpointProxy.sol @@ -2,17 +2,14 @@ pragma solidity ^0.4.24; import "../modules/Checkpoint/ERC20DividendCheckpointStorage.sol"; import "../modules/Checkpoint/DividendCheckpointStorage.sol"; -import "./Proxy.sol"; +import "./OwnedProxy.sol"; import "../Pausable.sol"; import "../modules/ModuleStorage.sol"; /** * @title Transfer Manager module for core transfer validation functionality */ -contract ERC20DividendCheckpointProxy is ERC20DividendCheckpointStorage, DividendCheckpointStorage, ModuleStorage, Pausable, Proxy { - - // Address of the current implementation - address internal __implementation; +contract ERC20DividendCheckpointProxy is ERC20DividendCheckpointStorage, DividendCheckpointStorage, ModuleStorage, Pausable, OwnedProxy { /** * @notice Constructor @@ -31,18 +28,4 @@ contract ERC20DividendCheckpointProxy is ERC20DividendCheckpointStorage, Dividen __implementation = _implementation; } - /** - * @notice Internal function to provide the address of the implementation contract - */ - function _implementation() internal view returns (address) { - return __implementation; - } - - /** - * @dev Tells the address of the current implementation - * @return address of the current implementation - */ - function implementation() external view returns (address) { - return _implementation(); - } } diff --git a/contracts/proxy/EtherDividendCheckpointProxy.sol b/contracts/proxy/EtherDividendCheckpointProxy.sol index 4786736ea..40b1c1332 100644 --- a/contracts/proxy/EtherDividendCheckpointProxy.sol +++ b/contracts/proxy/EtherDividendCheckpointProxy.sol @@ -1,17 +1,14 @@ pragma solidity ^0.4.24; import "../modules/Checkpoint/DividendCheckpointStorage.sol"; -import "./Proxy.sol"; +import "./OwnedProxy.sol"; import "../Pausable.sol"; import "../modules/ModuleStorage.sol"; /** * @title Transfer Manager module for core transfer validation functionality */ -contract EtherDividendCheckpointProxy is DividendCheckpointStorage, ModuleStorage, Pausable, Proxy { - - // Address of the current implementation - address internal __implementation; +contract EtherDividendCheckpointProxy is DividendCheckpointStorage, ModuleStorage, Pausable, OwnedProxy { /** * @notice Constructor @@ -30,18 +27,4 @@ contract EtherDividendCheckpointProxy is DividendCheckpointStorage, ModuleStorag __implementation = _implementation; } - /** - * @notice Internal function to provide the address of the implementation contract - */ - function _implementation() internal view returns (address) { - return __implementation; - } - - /** - * @dev Tells the address of the current implementation - * @return address of the current implementation - */ - function implementation() external view returns (address) { - return _implementation(); - } } diff --git a/contracts/proxy/GeneralTransferManagerProxy.sol b/contracts/proxy/GeneralTransferManagerProxy.sol index 9732b76db..cb9b69070 100644 --- a/contracts/proxy/GeneralTransferManagerProxy.sol +++ b/contracts/proxy/GeneralTransferManagerProxy.sol @@ -1,17 +1,14 @@ pragma solidity ^0.4.24; import "../modules/TransferManager/GeneralTransferManagerStorage.sol"; -import "./Proxy.sol"; +import "./OwnedProxy.sol"; import "../Pausable.sol"; import "../modules/ModuleStorage.sol"; /** * @title Transfer Manager module for core transfer validation functionality */ -contract GeneralTransferManagerProxy is GeneralTransferManagerStorage, ModuleStorage, Pausable, Proxy { - - // Address of the current implementation - address internal __implementation; +contract GeneralTransferManagerProxy is GeneralTransferManagerStorage, ModuleStorage, Pausable, OwnedProxy { /** * @notice Constructor @@ -30,18 +27,4 @@ contract GeneralTransferManagerProxy is GeneralTransferManagerStorage, ModuleSto __implementation = _implementation; } - /** - * @notice Internal function to provide the address of the implementation contract - */ - function _implementation() internal view returns (address) { - return __implementation; - } - - /** - * @dev Tells the address of the current implementation - * @return address of the current implementation - */ - function implementation() external view returns (address) { - return _implementation(); - } } diff --git a/contracts/proxy/OwnedProxy.sol b/contracts/proxy/OwnedProxy.sol new file mode 100644 index 000000000..67d3822bc --- /dev/null +++ b/contracts/proxy/OwnedProxy.sol @@ -0,0 +1,91 @@ +pragma solidity ^0.4.18; + +import "./Proxy.sol"; + +/** + * @title OwnedUpgradeabilityProxy + * @dev This contract combines an upgradeability proxy with basic authorization control functionalities + */ +contract OwnedProxy is Proxy { + + // Owner of the contract + address private __owner; + + // Address of the current implementation + address internal __implementation; + + /** + * @dev Event to show ownership has been transferred + * @param _previousOwner representing the address of the previous owner + * @param _newOwner representing the address of the new owner + */ + event ProxyOwnershipTransferred(address _previousOwner, address _newOwner); + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier ifOwner() { + if (msg.sender == _owner()) { + _; + } else { + _fallback(); + } + } + + /** + * @dev the constructor sets the original owner of the contract to the sender account. + */ + constructor() public { + _setOwner(msg.sender); + } + + /** + * @dev Tells the address of the owner + * @return the address of the owner + */ + function _owner() internal view returns (address) { + return __owner; + } + + /** + * @dev Sets the address of the owner + */ + function _setOwner(address _newOwner) internal { + require(_newOwner != address(0), "Address should not be 0x"); + __owner = _newOwner; + } + + /** + * @notice Internal function to provide the address of the implementation contract + */ + function _implementation() internal view returns (address) { + return __implementation; + } + + /** + * @dev Tells the address of the proxy owner + * @return the address of the proxy owner + */ + function proxyOwner() external ifOwner returns (address) { + return _owner(); + } + + /** + * @dev Tells the address of the current implementation + * @return address of the current implementation + */ + function implementation() external ifOwner returns (address) { + return _implementation(); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param _newOwner The address to transfer ownership to. + */ + function transferProxyOwnership(address _newOwner) external ifOwner { + require(_newOwner != address(0), "Address should not be 0x"); + emit ProxyOwnershipTransferred(_owner(), _newOwner); + _setOwner(_newOwner); + } + +} diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index 63b2a8231..f25cfab35 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -5,6 +5,8 @@ const GeneralPermissionManagerFactory = artifacts.require('./GeneralPermissionMa const PercentageTransferManagerFactory = artifacts.require('./PercentageTransferManagerFactory.sol') const USDTieredSTOProxyFactory = artifacts.require('./USDTieredSTOProxyFactory.sol'); const CountTransferManagerFactory = artifacts.require('./CountTransferManagerFactory.sol') +const EtherDividendCheckpointLogic = artifacts.require('./EtherDividendCheckpoint.sol') +const ERC20DividendCheckpointLogic = artifacts.require('./ERC20DividendCheckpoint.sol') const EtherDividendCheckpointFactory = artifacts.require('./EtherDividendCheckpointFactory.sol') const ERC20DividendCheckpointFactory = artifacts.require('./ERC20DividendCheckpointFactory.sol') const ModuleRegistry = artifacts.require('./ModuleRegistry.sol'); @@ -150,6 +152,14 @@ module.exports = function (deployer, network, accounts) { // B) Deploy the GeneralTransferManagerLogic Contract (Factory used to generate the GeneralTransferManager contract and this // manager attach with the securityToken contract at the time of deployment) return deployer.deploy(GeneralTransferManagerLogic, "0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000", {from: PolymathAccount}); + }).then(() => { + // B) Deploy the GeneralTransferManagerLogic Contract (Factory used to generate the GeneralTransferManager contract and this + // manager attach with the securityToken contract at the time of deployment) + return deployer.deploy(ERC20DividendCheckpointLogic, "0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000", {from: PolymathAccount}); + }).then(() => { + // B) Deploy the GeneralTransferManagerLogic Contract (Factory used to generate the GeneralTransferManager contract and this + // manager attach with the securityToken contract at the time of deployment) + return deployer.deploy(EtherDividendCheckpointLogic, "0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000", {from: PolymathAccount}); }).then(() => { // B) Deploy the GeneralTransferManagerFactory Contract (Factory used to generate the GeneralTransferManager contract and this // manager attach with the securityToken contract at the time of deployment) @@ -169,11 +179,11 @@ module.exports = function (deployer, network, accounts) { }).then(() => { // D) Deploy the EtherDividendCheckpointFactory Contract (Factory used to generate the EtherDividendCheckpoint contract use // to provide the functionality of the dividend in terms of ETH) - return deployer.deploy(EtherDividendCheckpointFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); + return deployer.deploy(EtherDividendCheckpointFactory, PolyToken, 0, 0, 0, EtherDividendCheckpointLogic.address, {from: PolymathAccount}); }).then(() => { // D) Deploy the ERC20DividendCheckpointFactory Contract (Factory used to generate the ERC20DividendCheckpoint contract use // to provide the functionality of the dividend in terms of ERC20 token) - return deployer.deploy(ERC20DividendCheckpointFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); + return deployer.deploy(ERC20DividendCheckpointFactory, PolyToken, 0, 0, 0, ERC20DividendCheckpointLogic.address, {from: PolymathAccount}); }).then(() => { // D) Deploy the ManualApprovalTransferManagerFactory Contract (Factory used to generate the ManualApprovalTransferManager contract use // to manual approve the transfer that will overcome the other transfer restrictions) @@ -319,6 +329,8 @@ module.exports = function (deployer, network, accounts) { CountTransferManagerFactory: ${CountTransferManagerFactory.address} PercentageTransferManagerFactory: ${PercentageTransferManagerFactory.address} ManualApprovalTransferManagerFactory: ${ManualApprovalTransferManagerFactory.address} + EtherDividendCheckpointLogic: ${EtherDividendCheckpointLogic.address} + ERC20DividendCheckpointLogic: ${ERC20DividendCheckpointLogic.address} EtherDividendCheckpointFactory: ${EtherDividendCheckpointFactory.address} ERC20DividendCheckpointFactory: ${ERC20DividendCheckpointFactory.address} --------------------------------------------------------------------------------- diff --git a/scripts/compareStorageLayout.js b/scripts/compareStorageLayout.js index 5bf50a985..502f27872 100644 --- a/scripts/compareStorageLayout.js +++ b/scripts/compareStorageLayout.js @@ -20,27 +20,27 @@ function traverseAST(_input, _elements) { _elements.push(_input); } -function compareStorageLayouts(oldLayout, newLayout) { +function compareStorageLayouts(logicLayout, proxyLayout) { function makeComp(x) { - return [x.constant, x.name, x.scope, x.stateVariable, x.storageLocation, x.type, x.value, x.visibility].join(':'); + return [x.constant, x.name, x.stateVariable, x.storageLocation, x.type, x.value, x.visibility].join(':'); } // if(newLayout.length < oldLayout.length) return false; - for(var i=0;i bool) claimed; // List of addresses which have claimed dividend + mapping (address => bool) dividendExcluded; // List of addresses which cannot claim dividends + bytes32 name; // Name/title - used for identification + } + + // List of all dividends + Dividend[] public dividends; + + // List of addresses which cannot claim dividends + address[] public excluded; + + // Mapping from address to withholding tax as a percentage * 10**16 + mapping (address => uint256) public withholdingTax; + + // Total amount of ETH withheld per investor + mapping (address => uint256) public investorWithheld; + +} + +// File: contracts/modules/Checkpoint/ICheckpoint.sol + +/** + * @title Interface to be implemented by all checkpoint modules + */ +/*solium-disable-next-line no-empty-blocks*/ +interface ICheckpoint { + +} + +// File: openzeppelin-solidity/contracts/math/Math.sol + +/** + * @title Math + * @dev Assorted math operations + */ +library Math { + function max64(uint64 a, uint64 b) internal pure returns (uint64) { + return a >= b ? a : b; + } + + function min64(uint64 a, uint64 b) internal pure returns (uint64) { + return a < b ? a : b; + } + + function max256(uint256 a, uint256 b) internal pure returns (uint256) { + return a >= b ? a : b; + } + + function min256(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } +} + +// File: openzeppelin-solidity/contracts/math/SafeMath.sol + +/** + * @title SafeMath + * @dev Math operations with safety checks that throw on error + */ +library SafeMath { + + /** + * @dev Multiplies two numbers, throws on overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { + // Gas optimization: this is cheaper than asserting 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 + if (a == 0) { + return 0; + } + + c = a * b; + assert(c / a == b); + return c; + } + + /** + * @dev Integer division of two numbers, truncating the quotient. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + // uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return a / b; + } + + /** + * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + assert(b <= a); + return a - b; + } + + /** + * @dev Adds two numbers, throws on overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256 c) { + c = a + b; + assert(c >= a); + return c; + } +} + +// File: contracts/modules/Checkpoint/DividendCheckpoint.sol + +/** + * DISCLAIMER: Under certain conditions, the function pushDividendPayment + * may fail due to block gas limits. + * If the total number of investors that ever held tokens is greater than ~15,000 then + * the function may fail. If this happens investors can pull their dividends, or the Issuer + * can use pushDividendPaymentToAddresses to provide an explict address list in batches + */ +pragma solidity ^0.4.24; + +/** + * @title Checkpoint module for issuing ether dividends + * @dev abstract contract + */ +contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module { + using SafeMath for uint256; + + event SetDefaultExcludedAddresses(address[] _excluded, uint256 _timestamp); + event SetWithholding(address[] _investors, uint256[] _withholding, uint256 _timestamp); + event SetWithholdingFixed(address[] _investors, uint256 _withholding, uint256 _timestamp); + + modifier validDividendIndex(uint256 _dividendIndex) { + require(_dividendIndex < dividends.length, "Invalid dividend"); + require(!dividends[_dividendIndex].reclaimed, "Dividend reclaimed"); + /*solium-disable-next-line security/no-block-members*/ + require(now >= dividends[_dividendIndex].maturity, "Dividend maturity in future"); + /*solium-disable-next-line security/no-block-members*/ + require(now < dividends[_dividendIndex].expiry, "Dividend expiry in past"); + _; + } + + /** + * @notice Init function i.e generalise function to maintain the structure of the module contract + * @return bytes4 + */ + function getInitFunction() public pure returns (bytes4) { + return bytes4(0); + } + + /** + * @notice Return the default excluded addresses + * @return List of excluded addresses + */ + function getDefaultExcluded() external view returns (address[]) { + return excluded; + } + + /** + * @notice Creates a checkpoint on the security token + * @return Checkpoint ID + */ + function createCheckpoint() public withPerm(CHECKPOINT) returns (uint256) { + return ISecurityToken(securityToken).createCheckpoint(); + } + + /** + * @notice Function to clear and set list of excluded addresses used for future dividends + * @param _excluded Addresses of investors + */ + function setDefaultExcluded(address[] _excluded) public withPerm(MANAGE) { + require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many excluded addresses"); + for (uint256 j = 0; j < _excluded.length; j++) { + require (_excluded[j] != address(0), "Invalid address"); + for (uint256 i = j + 1; i < _excluded.length; i++) { + require (_excluded[j] != _excluded[i], "Duplicate exclude address"); + } + } + excluded = _excluded; + /*solium-disable-next-line security/no-block-members*/ + emit SetDefaultExcludedAddresses(excluded, now); + } + + /** + * @notice Function to set withholding tax rates for investors + * @param _investors Addresses of investors + * @param _withholding Withholding tax for individual investors (multiplied by 10**16) + */ + function setWithholding(address[] _investors, uint256[] _withholding) public withPerm(MANAGE) { + require(_investors.length == _withholding.length, "Mismatched input lengths"); + /*solium-disable-next-line security/no-block-members*/ + emit SetWithholding(_investors, _withholding, now); + for (uint256 i = 0; i < _investors.length; i++) { + require(_withholding[i] <= 10**18, "Incorrect withholding tax"); + withholdingTax[_investors[i]] = _withholding[i]; + } + } + + /** + * @notice Function to set withholding tax rates for investors + * @param _investors Addresses of investor + * @param _withholding Withholding tax for all investors (multiplied by 10**16) + */ + function setWithholdingFixed(address[] _investors, uint256 _withholding) public withPerm(MANAGE) { + require(_withholding <= 10**18, "Incorrect withholding tax"); + /*solium-disable-next-line security/no-block-members*/ + emit SetWithholdingFixed(_investors, _withholding, now); + for (uint256 i = 0; i < _investors.length; i++) { + withholdingTax[_investors[i]] = _withholding; + } + } + + /** + * @notice Issuer can push dividends to provided addresses + * @param _dividendIndex Dividend to push + * @param _payees Addresses to which to push the dividend + */ + function pushDividendPaymentToAddresses( + uint256 _dividendIndex, + address[] _payees + ) + public + withPerm(DISTRIBUTE) + validDividendIndex(_dividendIndex) + { + Dividend storage dividend = dividends[_dividendIndex]; + for (uint256 i = 0; i < _payees.length; i++) { + if ((!dividend.claimed[_payees[i]]) && (!dividend.dividendExcluded[_payees[i]])) { + _payDividend(_payees[i], dividend, _dividendIndex); + } + } + } + + /** + * @notice Issuer can push dividends using the investor list from the security token + * @param _dividendIndex Dividend to push + * @param _start Index in investor list at which to start pushing dividends + * @param _iterations Number of addresses to push dividends for + */ + function pushDividendPayment( + uint256 _dividendIndex, + uint256 _start, + uint256 _iterations + ) + public + withPerm(DISTRIBUTE) + validDividendIndex(_dividendIndex) + { + Dividend storage dividend = dividends[_dividendIndex]; + address[] memory investors = ISecurityToken(securityToken).getInvestors(); + uint256 numberInvestors = Math.min256(investors.length, _start.add(_iterations)); + for (uint256 i = _start; i < numberInvestors; i++) { + address payee = investors[i]; + if ((!dividend.claimed[payee]) && (!dividend.dividendExcluded[payee])) { + _payDividend(payee, dividend, _dividendIndex); + } + } + } + + /** + * @notice Investors can pull their own dividends + * @param _dividendIndex Dividend to pull + */ + function pullDividendPayment(uint256 _dividendIndex) public validDividendIndex(_dividendIndex) + { + Dividend storage dividend = dividends[_dividendIndex]; + require(!dividend.claimed[msg.sender], "Dividend already claimed"); + require(!dividend.dividendExcluded[msg.sender], "msg.sender excluded from Dividend"); + _payDividend(msg.sender, dividend, _dividendIndex); + } + + /** + * @notice Internal function for paying dividends + * @param _payee Address of investor + * @param _dividend Storage with previously issued dividends + * @param _dividendIndex Dividend to pay + */ + function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal; + + /** + * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends + * @param _dividendIndex Dividend to reclaim + */ + function reclaimDividend(uint256 _dividendIndex) external; + + /** + * @notice Calculate amount of dividends claimable + * @param _dividendIndex Dividend to calculate + * @param _payee Affected investor address + * @return claim, withheld amounts + */ + function calculateDividend(uint256 _dividendIndex, address _payee) public view returns(uint256, uint256) { + require(_dividendIndex < dividends.length, "Invalid dividend"); + Dividend storage dividend = dividends[_dividendIndex]; + if (dividend.claimed[_payee] || dividend.dividendExcluded[_payee]) { + return (0, 0); + } + uint256 balance = ISecurityToken(securityToken).balanceOfAt(_payee, dividend.checkpointId); + uint256 claim = balance.mul(dividend.amount).div(dividend.totalSupply); + uint256 withheld = claim.mul(withholdingTax[_payee]).div(uint256(10**18)); + return (claim, withheld); + } + + /** + * @notice Get the index according to the checkpoint id + * @param _checkpointId Checkpoint id to query + * @return uint256[] + */ + function getDividendIndex(uint256 _checkpointId) public view returns(uint256[]) { + uint256 counter = 0; + for(uint256 i = 0; i < dividends.length; i++) { + if (dividends[i].checkpointId == _checkpointId) { + counter++; + } + } + + uint256[] memory index = new uint256[](counter); + counter = 0; + for(uint256 j = 0; j < dividends.length; j++) { + if (dividends[j].checkpointId == _checkpointId) { + index[counter] = j; + counter++; + } + } + return index; + } + + /** + * @notice Allows issuer to withdraw withheld tax + * @param _dividendIndex Dividend to withdraw from + */ + function withdrawWithholding(uint256 _dividendIndex) external; + + /** + * @notice Return the permissions flag that are associated with this module + * @return bytes32 array + */ + function getPermissions() public view returns(bytes32[]) { + bytes32[] memory allPermissions = new bytes32[](2); + allPermissions[0] = DISTRIBUTE; + allPermissions[1] = MANAGE; + return allPermissions; + } + +} + +// File: contracts/modules/Checkpoint/ERC20DividendCheckpointStorage.sol + +/** + * @title Checkpoint module for issuing ERC20 dividends + */ +contract ERC20DividendCheckpointStorage { + + // Mapping to token address for each dividend + mapping (uint256 => address) public dividendTokens; + +} + +// File: contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol + +/** + * @title Checkpoint module for issuing ERC20 dividends + */ +contract ERC20DividendCheckpoint is ERC20DividendCheckpointStorage, DividendCheckpoint { + using SafeMath for uint256; + + event ERC20DividendDeposited( + address indexed _depositor, + uint256 _checkpointId, + uint256 _created, + uint256 _maturity, + uint256 _expiry, + address indexed _token, + uint256 _amount, + uint256 _totalSupply, + uint256 _dividendIndex, + bytes32 indexed _name + ); + event ERC20DividendClaimed( + address indexed _payee, + uint256 _dividendIndex, + address indexed _token, + uint256 _amount, + uint256 _withheld + ); + event ERC20DividendReclaimed( + address indexed _claimer, + uint256 _dividendIndex, + address indexed _token, + uint256 _claimedAmount + ); + event ERC20DividendWithholdingWithdrawn( + address indexed _claimer, + uint256 _dividendIndex, + address indexed _token, + uint256 _withheldAmount + ); + + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + */ + constructor (address _securityToken, address _polyAddress) public + Module(_securityToken, _polyAddress) + { + } + + /** + * @notice Creates a dividend and checkpoint for the dividend + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _name Name/Title for identification + */ + function createDividend( + uint256 _maturity, + uint256 _expiry, + address _token, + uint256 _amount, + bytes32 _name + ) + external + withPerm(MANAGE) + { + createDividendWithExclusions(_maturity, _expiry, _token, _amount, excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _checkpointId Checkpoint id from which to create dividends + * @param _name Name/Title for identification + */ + function createDividendWithCheckpoint( + uint256 _maturity, + uint256 _expiry, + address _token, + uint256 _amount, + uint256 _checkpointId, + bytes32 _name + ) + external + withPerm(MANAGE) + { + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, excluded, _name); + } + + /** + * @notice Creates a dividend and checkpoint for the dividend + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _excluded List of addresses to exclude + * @param _name Name/Title for identification + */ + function createDividendWithExclusions( + uint256 _maturity, + uint256 _expiry, + address _token, + uint256 _amount, + address[] _excluded, + bytes32 _name + ) + public + withPerm(MANAGE) + { + uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint(); + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, checkpointId, _excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _checkpointId Checkpoint id from which to create dividends + * @param _excluded List of addresses to exclude + * @param _name Name/Title for identification + */ + function createDividendWithCheckpointAndExclusions( + uint256 _maturity, + uint256 _expiry, + address _token, + uint256 _amount, + uint256 _checkpointId, + address[] _excluded, + bytes32 _name + ) + public + withPerm(MANAGE) + { + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, _excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _checkpointId Checkpoint id from which to create dividends + * @param _excluded List of addresses to exclude + * @param _name Name/Title for identification + */ + function _createDividendWithCheckpointAndExclusions( + uint256 _maturity, + uint256 _expiry, + address _token, + uint256 _amount, + uint256 _checkpointId, + address[] _excluded, + bytes32 _name + ) + internal + { + ISecurityToken securityTokenInstance = ISecurityToken(securityToken); + require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many addresses excluded"); + require(_expiry > _maturity, "Expiry before maturity"); + /*solium-disable-next-line security/no-block-members*/ + require(_expiry > now, "Expiry in past"); + require(_amount > 0, "No dividend sent"); + require(_token != address(0), "Invalid token"); + require(_checkpointId <= securityTokenInstance.currentCheckpointId(), "Invalid checkpoint"); + require(IERC20(_token).transferFrom(msg.sender, address(this), _amount), "insufficent allowance"); + require(_name[0] != 0); + uint256 dividendIndex = dividends.length; + uint256 currentSupply = securityTokenInstance.totalSupplyAt(_checkpointId); + uint256 excludedSupply = 0; + dividends.push( + Dividend( + _checkpointId, + now, /*solium-disable-line security/no-block-members*/ + _maturity, + _expiry, + _amount, + 0, + 0, + false, + 0, + 0, + _name + ) + ); + + for (uint256 j = 0; j < _excluded.length; j++) { + require (_excluded[j] != address(0), "Invalid address"); + require(!dividends[dividendIndex].dividendExcluded[_excluded[j]], "duped exclude address"); + excludedSupply = excludedSupply.add(securityTokenInstance.balanceOfAt(_excluded[j], _checkpointId)); + dividends[dividendIndex].dividendExcluded[_excluded[j]] = true; + } + + dividends[dividendIndex].totalSupply = currentSupply.sub(excludedSupply); + dividendTokens[dividendIndex] = _token; + _emitERC20DividendDepositedEvent(_checkpointId, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex, _name); + } + + /** + * @notice Emits the ERC20DividendDeposited event. + * Seperated into a different function as a workaround for stack too deep error + */ + function _emitERC20DividendDepositedEvent( + uint256 _checkpointId, + uint256 _maturity, + uint256 _expiry, + address _token, + uint256 _amount, + uint256 currentSupply, + uint256 dividendIndex, + bytes32 _name + ) + internal + { + /*solium-disable-next-line security/no-block-members*/ + emit ERC20DividendDeposited(msg.sender, _checkpointId, now, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex, _name); + } + + /** + * @notice Internal function for paying dividends + * @param _payee Address of investor + * @param _dividend Storage with previously issued dividends + * @param _dividendIndex Dividend to pay + */ + function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal { + (uint256 claim, uint256 withheld) = calculateDividend(_dividendIndex, _payee); + _dividend.claimed[_payee] = true; + _dividend.claimedAmount = claim.add(_dividend.claimedAmount); + uint256 claimAfterWithheld = claim.sub(withheld); + if (claimAfterWithheld > 0) { + require(IERC20(dividendTokens[_dividendIndex]).transfer(_payee, claimAfterWithheld), "transfer failed"); + _dividend.dividendWithheld = _dividend.dividendWithheld.add(withheld); + investorWithheld[_payee] = investorWithheld[_payee].add(withheld); + emit ERC20DividendClaimed(_payee, _dividendIndex, dividendTokens[_dividendIndex], claim, withheld); + } + } + + /** + * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends + * @param _dividendIndex Dividend to reclaim + */ + function reclaimDividend(uint256 _dividendIndex) external withPerm(MANAGE) { + require(_dividendIndex < dividends.length, "Invalid dividend"); + /*solium-disable-next-line security/no-block-members*/ + require(now >= dividends[_dividendIndex].expiry, "Dividend expiry in future"); + require(!dividends[_dividendIndex].reclaimed, "already claimed"); + dividends[_dividendIndex].reclaimed = true; + Dividend storage dividend = dividends[_dividendIndex]; + uint256 remainingAmount = dividend.amount.sub(dividend.claimedAmount); + address owner = IOwnable(securityToken).owner(); + require(IERC20(dividendTokens[_dividendIndex]).transfer(owner, remainingAmount), "transfer failed"); + emit ERC20DividendReclaimed(owner, _dividendIndex, dividendTokens[_dividendIndex], remainingAmount); + } + + /** + * @notice Allows issuer to withdraw withheld tax + * @param _dividendIndex Dividend to withdraw from + */ + function withdrawWithholding(uint256 _dividendIndex) external withPerm(MANAGE) { + require(_dividendIndex < dividends.length, "Invalid dividend"); + Dividend storage dividend = dividends[_dividendIndex]; + uint256 remainingWithheld = dividend.dividendWithheld.sub(dividend.dividendWithheldReclaimed); + dividend.dividendWithheldReclaimed = dividend.dividendWithheld; + address owner = IOwnable(securityToken).owner(); + require(IERC20(dividendTokens[_dividendIndex]).transfer(owner, remainingWithheld), "transfer failed"); + emit ERC20DividendWithholdingWithdrawn(owner, _dividendIndex, dividendTokens[_dividendIndex], remainingWithheld); + } + +} diff --git a/scripts/proxy.sol b/scripts/proxy.sol new file mode 100644 index 000000000..ed315955f --- /dev/null +++ b/scripts/proxy.sol @@ -0,0 +1,332 @@ +pragma solidity ^0.4.24; + +// File: contracts/Pausable.sol + +/** + * @title Utility contract to allow pausing and unpausing of certain functions + */ +contract Pausable { + + event Pause(uint256 _timestammp); + event Unpause(uint256 _timestamp); + + bool public paused = false; + + /** + * @notice Modifier to make a function callable only when the contract is not paused. + */ + modifier whenNotPaused() { + require(!paused, "Contract is paused"); + _; + } + + /** + * @notice Modifier to make a function callable only when the contract is paused. + */ + modifier whenPaused() { + require(paused, "Contract is not paused"); + _; + } + + /** + * @notice Called by the owner to pause, triggers stopped state + */ + function _pause() internal whenNotPaused { + paused = true; + /*solium-disable-next-line security/no-block-members*/ + emit Pause(now); + } + + /** + * @notice Called by the owner to unpause, returns to normal state + */ + function _unpause() internal whenPaused { + paused = false; + /*solium-disable-next-line security/no-block-members*/ + emit Unpause(now); + } + +} + +// File: contracts/modules/Checkpoint/DividendCheckpointStorage.sol + +/** + * DISCLAIMER: Under certain conditions, the function pushDividendPayment + * may fail due to block gas limits. + * If the total number of investors that ever held tokens is greater than ~15,000 then + * the function may fail. If this happens investors can pull their dividends, or the Issuer + * can use pushDividendPaymentToAddresses to provide an explict address list in batches + */ +pragma solidity ^0.4.24; + +/** + * @title Checkpoint module for issuing ether dividends + * @dev abstract contract + */ +contract DividendCheckpointStorage { + + uint256 public EXCLUDED_ADDRESS_LIMIT = 50; + bytes32 public constant DISTRIBUTE = "DISTRIBUTE"; + bytes32 public constant MANAGE = "MANAGE"; + bytes32 public constant CHECKPOINT = "CHECKPOINT"; + + struct Dividend { + uint256 checkpointId; + uint256 created; // Time at which the dividend was created + uint256 maturity; // Time after which dividend can be claimed - set to 0 to bypass + uint256 expiry; // Time until which dividend can be claimed - after this time any remaining amount can be withdrawn by issuer - + // set to very high value to bypass + uint256 amount; // Dividend amount in WEI + uint256 claimedAmount; // Amount of dividend claimed so far + uint256 totalSupply; // Total supply at the associated checkpoint (avoids recalculating this) + bool reclaimed; // True if expiry has passed and issuer has reclaimed remaining dividend + uint256 dividendWithheld; + uint256 dividendWithheldReclaimed; + mapping (address => bool) claimed; // List of addresses which have claimed dividend + mapping (address => bool) dividendExcluded; // List of addresses which cannot claim dividends + bytes32 name; // Name/title - used for identification + } + + // List of all dividends + Dividend[] public dividends; + + // List of addresses which cannot claim dividends + address[] public excluded; + + // Mapping from address to withholding tax as a percentage * 10**16 + mapping (address => uint256) public withholdingTax; + + // Total amount of ETH withheld per investor + mapping (address => uint256) public investorWithheld; + +} + +// File: contracts/modules/Checkpoint/ERC20DividendCheckpointStorage.sol + +/** + * @title Checkpoint module for issuing ERC20 dividends + */ +contract ERC20DividendCheckpointStorage { + + // Mapping to token address for each dividend + mapping (uint256 => address) public dividendTokens; + +} + +// File: contracts/interfaces/IERC20.sol + +/** + * @title ERC20 interface + * @dev see https://github.com/ethereum/EIPs/issues/20 + */ +interface IERC20 { + function decimals() external view returns (uint8); + function totalSupply() external view returns (uint256); + function balanceOf(address _owner) external view returns (uint256); + function allowance(address _owner, address _spender) external view returns (uint256); + function transfer(address _to, uint256 _value) external returns (bool); + function transferFrom(address _from, address _to, uint256 _value) external returns (bool); + function approve(address _spender, uint256 _value) external returns (bool); + function decreaseApproval(address _spender, uint _subtractedValue) external returns (bool); + function increaseApproval(address _spender, uint _addedValue) external returns (bool); + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); +} + +// File: contracts/modules/ModuleStorage.sol + +/** + * @title Storage for Module contract + * @notice Contract is abstract + */ +contract ModuleStorage { + + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + */ + constructor (address _securityToken, address _polyAddress) public { + securityToken = _securityToken; + factory = msg.sender; + polyToken = IERC20(_polyAddress); + } + + address public factory; + + address public securityToken; + + bytes32 public constant FEE_ADMIN = "FEE_ADMIN"; + + IERC20 public polyToken; + +} + +// File: contracts/proxy/Proxy.sol + +/** + * @title Proxy + * @dev Gives the possibility to delegate any call to a foreign implementation. + */ +contract Proxy { + + /** + * @dev Tells the address of the implementation where every call will be delegated. + * @return address of the implementation to which it will be delegated + */ + function _implementation() internal view returns (address); + + /** + * @dev Fallback function. + * Implemented entirely in `_fallback`. + */ + function _fallback() internal { + _delegate(_implementation()); + } + + /** + * @dev Fallback function allowing to perform a delegatecall to the given implementation. + * This function will return whatever the implementation call returns + */ + function _delegate(address implementation) internal { + /*solium-disable-next-line security/no-inline-assembly*/ + assembly { + // Copy msg.data. We take full control of memory in this inline assembly + // block because it will not return to Solidity code. We overwrite the + // Solidity scratch pad at memory position 0. + calldatacopy(0, 0, calldatasize) + + // Call the implementation. + // out and outsize are 0 because we don't know the size yet. + let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0) + + // Copy the returned data. + returndatacopy(0, 0, returndatasize) + + switch result + // delegatecall returns 0 on error. + case 0 { revert(0, returndatasize) } + default { return(0, returndatasize) } + } + } + + function () public payable { + _fallback(); + } +} + +// File: contracts/proxy/OwnedProxy.sol + +/** + * @title OwnedUpgradeabilityProxy + * @dev This contract combines an upgradeability proxy with basic authorization control functionalities + */ +contract OwnedProxy is Proxy { + + // Owner of the contract + address private __owner; + + // Address of the current implementation + address internal __implementation; + + /** + * @dev Event to show ownership has been transferred + * @param _previousOwner representing the address of the previous owner + * @param _newOwner representing the address of the new owner + */ + event ProxyOwnershipTransferred(address _previousOwner, address _newOwner); + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier ifOwner() { + if (msg.sender == _owner()) { + _; + } else { + _fallback(); + } + } + + /** + * @dev the constructor sets the original owner of the contract to the sender account. + */ + constructor() public { + _setOwner(msg.sender); + } + + /** + * @dev Tells the address of the owner + * @return the address of the owner + */ + function _owner() internal view returns (address) { + return __owner; + } + + /** + * @dev Sets the address of the owner + */ + function _setOwner(address _newOwner) internal { + require(_newOwner != address(0), "Address should not be 0x"); + __owner = _newOwner; + } + + /** + * @notice Internal function to provide the address of the implementation contract + */ + function _implementation() internal view returns (address) { + return __implementation; + } + + /** + * @dev Tells the address of the proxy owner + * @return the address of the proxy owner + */ + function proxyOwner() external ifOwner returns (address) { + return _owner(); + } + + /** + * @dev Tells the address of the current implementation + * @return address of the current implementation + */ + function implementation() external ifOwner returns (address) { + return _implementation(); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param _newOwner The address to transfer ownership to. + */ + function transferProxyOwnership(address _newOwner) external ifOwner { + require(_newOwner != address(0), "Address should not be 0x"); + emit ProxyOwnershipTransferred(_owner(), _newOwner); + _setOwner(_newOwner); + } + +} + +// File: contracts/proxy/ERC20DividendCheckpointProxy.sol + +/** + * @title Transfer Manager module for core transfer validation functionality + */ +contract ERC20DividendCheckpointProxy is ERC20DividendCheckpointStorage, DividendCheckpointStorage, ModuleStorage, Pausable, OwnedProxy { + + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + * @param _implementation representing the address of the new implementation to be set + */ + constructor (address _securityToken, address _polyAddress, address _implementation) + public + ModuleStorage(_securityToken, _polyAddress) + { + require( + _implementation != address(0), + "Implementation address should not be 0x" + ); + __implementation = _implementation; + } + +} diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 750a4cfbc..5dbcf5a6c 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -92,6 +92,7 @@ contract("GeneralTransferManager", accounts => { account_investor1 = accounts[8]; account_investor2 = accounts[9]; account_delegate = accounts[7]; + account_investor3 = accounts[5]; account_investor4 = accounts[6]; account_affiliates1 = accounts[3]; @@ -201,7 +202,7 @@ contract("GeneralTransferManager", accounts => { it("Should whitelist lots of addresses and check gas", async () => { let mockInvestors = []; for (let i = 0; i < 50; i++) { - mockInvestors.push("0x0000000000000000000000000000000000000000".substring(0,42-i.toString().length) + i.toString()); + mockInvestors.push("0x1000000000000000000000000000000000000000".substring(0,42-i.toString().length) + i.toString()); } let times = range1(50); diff --git a/test/helpers/createInstances.js b/test/helpers/createInstances.js index 35be83d95..a6118741f 100644 --- a/test/helpers/createInstances.js +++ b/test/helpers/createInstances.js @@ -8,6 +8,8 @@ const CappedSTOFactory = artifacts.require("./CappedSTOFactory.sol"); const SecurityTokenRegistryProxy = artifacts.require("./SecurityTokenRegistryProxy.sol"); const SecurityTokenRegistry = artifacts.require("./SecurityTokenRegistry.sol"); const SecurityTokenRegistryMock = artifacts.require("./SecurityTokenRegistryMock.sol"); +const ERC20DividendCheckpoint = artifacts.require("./ERC20DividendCheckpoint.sol"); +const EtherDividendCheckpoint = artifacts.require("./EtherDividendCheckpoint.sol"); const ERC20DividendCheckpointFactory = artifacts.require("./ERC20DividendCheckpointFactory.sol"); const EtherDividendCheckpointFactory = artifacts.require("./EtherDividendCheckpointFactory.sol"); const ManualApprovalTransferManagerFactory = artifacts.require("./ManualApprovalTransferManagerFactory.sol"); @@ -46,8 +48,10 @@ let I_SingleTradeVolumeRestrictionManagerFactory; let I_ManualApprovalTransferManagerFactory; let I_VolumeRestrictionTransferManagerFactory; let I_PercentageTransferManagerFactory; +let I_EtherDividendCheckpointLogic; let I_EtherDividendCheckpointFactory; let I_CountTransferManagerFactory; +let I_ERC20DividendCheckpointLogic; let I_ERC20DividendCheckpointFactory; let I_GeneralPermissionManagerFactory; let I_GeneralTransferManagerLogic; @@ -371,7 +375,8 @@ export async function deployUSDTieredSTOAndVerified(accountPolymath, MRProxyInst /// Deploy the Dividend Modules export async function deployERC20DividendAndVerifyed(accountPolymath, MRProxyInstance, polyToken, setupCost) { - I_ERC20DividendCheckpointFactory = await ERC20DividendCheckpointFactory.new(polyToken, setupCost, 0, 0, { from: accountPolymath }); + I_ERC20DividendCheckpointLogic = await ERC20DividendCheckpoint.new("0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000", { from: accountPolymath }); + I_ERC20DividendCheckpointFactory = await ERC20DividendCheckpointFactory.new(polyToken, setupCost, 0, 0, I_ERC20DividendCheckpointLogic.address, { from: accountPolymath }); assert.notEqual( I_ERC20DividendCheckpointFactory.address.valueOf(), @@ -383,7 +388,8 @@ export async function deployERC20DividendAndVerifyed(accountPolymath, MRProxyIns } export async function deployEtherDividendAndVerifyed(accountPolymath, MRProxyInstance, polyToken, setupCost) { - I_EtherDividendCheckpointFactory = await EtherDividendCheckpointFactory.new(polyToken, setupCost, 0, 0, { from: accountPolymath }); + I_EtherDividendCheckpointLogic = await EtherDividendCheckpoint.new("0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000", { from: accountPolymath }); + I_EtherDividendCheckpointFactory = await EtherDividendCheckpointFactory.new(polyToken, setupCost, 0, 0, I_EtherDividendCheckpointLogic.address, { from: accountPolymath }); assert.notEqual( I_EtherDividendCheckpointFactory.address.valueOf(), From 3f60f88fab2093df8e52ececaa0e56369893121a Mon Sep 17 00:00:00 2001 From: satyam Date: Tue, 27 Nov 2018 10:40:34 +0530 Subject: [PATCH 56/93] minor cleanup --- .../modules/Checkpoint/DividendCheckpointStorage.sol | 9 +-------- .../Checkpoint/ERC20DividendCheckpointStorage.sol | 2 +- contracts/proxy/OwnedProxy.sol | 2 +- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/contracts/modules/Checkpoint/DividendCheckpointStorage.sol b/contracts/modules/Checkpoint/DividendCheckpointStorage.sol index bf86191e6..4cf1f2838 100644 --- a/contracts/modules/Checkpoint/DividendCheckpointStorage.sol +++ b/contracts/modules/Checkpoint/DividendCheckpointStorage.sol @@ -1,14 +1,7 @@ -/** - * DISCLAIMER: Under certain conditions, the function pushDividendPayment - * may fail due to block gas limits. - * If the total number of investors that ever held tokens is greater than ~15,000 then - * the function may fail. If this happens investors can pull their dividends, or the Issuer - * can use pushDividendPaymentToAddresses to provide an explict address list in batches - */ pragma solidity ^0.4.24; /** - * @title Checkpoint module for issuing ether dividends + * @title Holds the storage variable for the DividendCheckpoint modules (i.e ERC20, Ether) * @dev abstract contract */ contract DividendCheckpointStorage { diff --git a/contracts/modules/Checkpoint/ERC20DividendCheckpointStorage.sol b/contracts/modules/Checkpoint/ERC20DividendCheckpointStorage.sol index 8bbd13bb6..29401f8d9 100644 --- a/contracts/modules/Checkpoint/ERC20DividendCheckpointStorage.sol +++ b/contracts/modules/Checkpoint/ERC20DividendCheckpointStorage.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.24; /** - * @title Checkpoint module for issuing ERC20 dividends + * @title It holds the storage variables related to ERC20DividendCheckpoint module */ contract ERC20DividendCheckpointStorage { diff --git a/contracts/proxy/OwnedProxy.sol b/contracts/proxy/OwnedProxy.sol index 67d3822bc..b75142fbe 100644 --- a/contracts/proxy/OwnedProxy.sol +++ b/contracts/proxy/OwnedProxy.sol @@ -3,7 +3,7 @@ pragma solidity ^0.4.18; import "./Proxy.sol"; /** - * @title OwnedUpgradeabilityProxy + * @title OwnedProxy * @dev This contract combines an upgradeability proxy with basic authorization control functionalities */ contract OwnedProxy is Proxy { From d473a2d30285c61e6c59bb7c7ebe767a71482cbf Mon Sep 17 00:00:00 2001 From: satyam Date: Tue, 27 Nov 2018 14:02:33 +0530 Subject: [PATCH 57/93] make script dynamic --- package.json | 1 + scripts/compareStorageLayout.js | 88 ++- scripts/logic.sol | 1188 ----------------------------- scripts/proxy.sol | 332 -------- yarn.lock | 1247 ++----------------------------- 5 files changed, 151 insertions(+), 2705 deletions(-) delete mode 100644 scripts/logic.sol delete mode 100644 scripts/proxy.sol diff --git a/package.json b/package.json index ef2d76c38..58104d99b 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "ethers": "^3.0.15", "fs": "0.0.1-security", "openzeppelin-solidity": "1.10.0", + "prompt": "^1.0.0", "readline-sync": "^1.4.9", "request": "^2.88.0", "request-promise": "^4.2.2", diff --git a/scripts/compareStorageLayout.js b/scripts/compareStorageLayout.js index 502f27872..c339bf095 100644 --- a/scripts/compareStorageLayout.js +++ b/scripts/compareStorageLayout.js @@ -1,15 +1,52 @@ const fs = require('fs'); -const logicContract = fs.readFileSync('./logic.sol', 'utf8'); -const proxyContract = fs.readFileSync('./proxy.sol', 'utf8'); const _ = require('underscore'); const solc = require('solc'); +const prompt = require('prompt'); +const path = require('path'); +const util = require('util'); +const exec = util.promisify(require('child_process').exec); -let logicInput = { - 'contracts': logicContract -} -let proxyInput = { - 'contracts': proxyContract -} +prompt.start(); + +prompt.get(['LogicContract', 'ProxyContract'], async(err, result) => { + + let logicContract; + let proxyContract; + + const fileList = walkSync('./contracts', []); + + let paths = findPath(result.LogicContract, result.ProxyContract, fileList); + + if (paths.length == 2) { + + console.log("Contracts exists \n"); + + await flatContracts(paths); + + if (path.basename(paths[0]) === result.LogicContract) { + logicContract = fs.readFileSync(`./flat/${path.basename(paths[0])}`, 'utf8'); + } else { + logicContract = fs.readFileSync(`./flat/${path.basename(paths[1])}`, 'utf8'); + } + if (path.basename(paths[0]) === result.ProxyContract) { + proxyContract = fs.readFileSync(`./flat/${path.basename(paths[0])}`, 'utf8'); + } else { + proxyContract = fs.readFileSync(`./flat/${path.basename(paths[1])}`, 'utf8'); + } + + let logicInput = { + 'contracts': logicContract + } + let proxyInput = { + 'contracts': proxyContract + } + + console.log(compareStorageLayouts(parseContract(logicInput), parseContract(proxyInput))); + + } else { + console.log("Contracts doesn't exists"); + } +}); function traverseAST(_input, _elements) { if(_input.children) { @@ -67,5 +104,36 @@ function parseContract(input) { return orderedStateVariables; } -// console.log(orderedStateVariables); -console.log(compareStorageLayouts(parseContract(logicInput), parseContract(proxyInput))); +var walkSync = function(dir, filelist) { + files = fs.readdirSync(dir); + filelist = filelist || []; + files.forEach(function(file) { + if (fs.statSync(path.join(dir, file)).isDirectory()) { + filelist = walkSync(path.join(dir, file), filelist); + } + else { + filelist.push(path.join(dir, file)); + } + }); + return filelist; +}; + +var findPath = function(logicContractName, proxyContractName, fileList) { + let paths = new Array(); + for (let i =0; i < fileList.length; i++) { + if ((logicContractName === path.basename(fileList[i]) || logicContractName === (path.basename(fileList[i])).split(".")[0]) || + (proxyContractName === path.basename(fileList[i]) || proxyContractName === (path.basename(fileList[i])).split(".")[0])) { + paths.push(fileList[i]); + } + } + return paths; +} + +async function flatContracts(_paths, _logic) { + let promises = new Array(); + for (let i = 0; i< _paths.length; i++) { + promises.push(await exec(`./node_modules/.bin/sol-merger ${_paths[i]} ./flat`)); + } + await Promise.all(promises); +} + diff --git a/scripts/logic.sol b/scripts/logic.sol deleted file mode 100644 index 828bc7213..000000000 --- a/scripts/logic.sol +++ /dev/null @@ -1,1188 +0,0 @@ -pragma solidity ^0.4.24; - -// File: contracts/interfaces/IERC20.sol - -/** - * @title ERC20 interface - * @dev see https://github.com/ethereum/EIPs/issues/20 - */ -interface IERC20 { - function decimals() external view returns (uint8); - function totalSupply() external view returns (uint256); - function balanceOf(address _owner) external view returns (uint256); - function allowance(address _owner, address _spender) external view returns (uint256); - function transfer(address _to, uint256 _value) external returns (bool); - function transferFrom(address _from, address _to, uint256 _value) external returns (bool); - function approve(address _spender, uint256 _value) external returns (bool); - function decreaseApproval(address _spender, uint _subtractedValue) external returns (bool); - function increaseApproval(address _spender, uint _addedValue) external returns (bool); - event Transfer(address indexed from, address indexed to, uint256 value); - event Approval(address indexed owner, address indexed spender, uint256 value); -} - -// File: contracts/interfaces/IOwnable.sol - -/** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ -interface IOwnable { - /** - * @dev Returns owner - */ - function owner() external view returns (address); - - /** - * @dev Allows the current owner to relinquish control of the contract. - */ - function renounceOwnership() external; - - /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param _newOwner The address to transfer ownership to. - */ - function transferOwnership(address _newOwner) external; - -} - -// File: contracts/interfaces/ISecurityToken.sol - -/** - * @title Interface for all security tokens - */ -interface ISecurityToken { - - // Standard ERC20 interface - function decimals() external view returns (uint8); - function totalSupply() external view returns (uint256); - function balanceOf(address _owner) external view returns (uint256); - function allowance(address _owner, address _spender) external view returns (uint256); - function transfer(address _to, uint256 _value) external returns (bool); - function transferFrom(address _from, address _to, uint256 _value) external returns (bool); - function approve(address _spender, uint256 _value) external returns (bool); - function decreaseApproval(address _spender, uint _subtractedValue) external returns (bool); - function increaseApproval(address _spender, uint _addedValue) external returns (bool); - event Transfer(address indexed from, address indexed to, uint256 value); - event Approval(address indexed owner, address indexed spender, uint256 value); - - //transfer, transferFrom must respect the result of verifyTransfer - function verifyTransfer(address _from, address _to, uint256 _value) external returns (bool success); - - /** - * @notice Mints new tokens and assigns them to the target _investor. - * Can only be called by the STO attached to the token (Or by the ST owner if there's no STO attached yet) - * @param _investor Address the tokens will be minted to - * @param _value is the amount of tokens that will be minted to the investor - */ - function mint(address _investor, uint256 _value) external returns (bool success); - - /** - * @notice Mints new tokens and assigns them to the target _investor. - * Can only be called by the STO attached to the token (Or by the ST owner if there's no STO attached yet) - * @param _investor Address the tokens will be minted to - * @param _value is The amount of tokens that will be minted to the investor - * @param _data Data to indicate validation - */ - function mintWithData(address _investor, uint256 _value, bytes _data) external returns (bool success); - - /** - * @notice Used to burn the securityToken on behalf of someone else - * @param _from Address for whom to burn tokens - * @param _value No. of tokens to be burned - * @param _data Data to indicate validation - */ - function burnFromWithData(address _from, uint256 _value, bytes _data) external; - - /** - * @notice Used to burn the securityToken - * @param _value No. of tokens to be burned - * @param _data Data to indicate validation - */ - function burnWithData(uint256 _value, bytes _data) external; - - event Minted(address indexed _to, uint256 _value); - event Burnt(address indexed _burner, uint256 _value); - - // Permissions this to a Permission module, which has a key of 1 - // If no Permission return false - note that IModule withPerm will allow ST owner all permissions anyway - // this allows individual modules to override this logic if needed (to not allow ST owner all permissions) - function checkPermission(address _delegate, address _module, bytes32 _perm) external view returns (bool); - - /** - * @notice Returns module list for a module type - * @param _module Address of the module - * @return bytes32 Name - * @return address Module address - * @return address Module factory address - * @return bool Module archived - * @return uint8 Module type - * @return uint256 Module index - * @return uint256 Name index - - */ - function getModule(address _module) external view returns(bytes32, address, address, bool, uint8, uint256, uint256); - - /** - * @notice Returns module list for a module name - * @param _name Name of the module - * @return address[] List of modules with this name - */ - function getModulesByName(bytes32 _name) external view returns (address[]); - - /** - * @notice Returns module list for a module type - * @param _type Type of the module - * @return address[] List of modules with this type - */ - function getModulesByType(uint8 _type) external view returns (address[]); - - /** - * @notice Queries totalSupply at a specified checkpoint - * @param _checkpointId Checkpoint ID to query as of - */ - function totalSupplyAt(uint256 _checkpointId) external view returns (uint256); - - /** - * @notice Queries balance at a specified checkpoint - * @param _investor Investor to query balance for - * @param _checkpointId Checkpoint ID to query as of - */ - function balanceOfAt(address _investor, uint256 _checkpointId) external view returns (uint256); - - /** - * @notice Creates a checkpoint that can be used to query historical balances / totalSuppy - */ - function createCheckpoint() external returns (uint256); - - /** - * @notice Gets length of investors array - * NB - this length may differ from investorCount if the list has not been pruned of zero-balance investors - * @return Length - */ - function getInvestors() external view returns (address[]); - - /** - * @notice returns an array of investors at a given checkpoint - * NB - this length may differ from investorCount as it contains all investors that ever held tokens - * @param _checkpointId Checkpoint id at which investor list is to be populated - * @return list of investors - */ - function getInvestorsAt(uint256 _checkpointId) external view returns(address[]); - - /** - * @notice generates subset of investors - * NB - can be used in batches if investor list is large - * @param _start Position of investor to start iteration from - * @param _end Position of investor to stop iteration at - * @return list of investors - */ - function iterateInvestors(uint256 _start, uint256 _end) external view returns(address[]); - - /** - * @notice Gets current checkpoint ID - * @return Id - */ - function currentCheckpointId() external view returns (uint256); - - /** - * @notice Gets an investor at a particular index - * @param _index Index to return address from - * @return Investor address - */ - function investors(uint256 _index) external view returns (address); - - /** - * @notice Allows the owner to withdraw unspent POLY stored by them on the ST or any ERC20 token. - * @dev Owner can transfer POLY to the ST which will be used to pay for modules that require a POLY fee. - * @param _tokenContract Address of the ERC20Basic compliance token - * @param _value Amount of POLY to withdraw - */ - function withdrawERC20(address _tokenContract, uint256 _value) external; - - /** - * @notice Allows owner to approve more POLY to one of the modules - * @param _module Module address - * @param _budget New budget - */ - function changeModuleBudget(address _module, uint256 _budget) external; - - /** - * @notice Changes the tokenDetails - * @param _newTokenDetails New token details - */ - function updateTokenDetails(string _newTokenDetails) external; - - /** - * @notice Allows the owner to change token granularity - * @param _granularity Granularity level of the token - */ - function changeGranularity(uint256 _granularity) external; - - /** - * @notice Removes addresses with zero balances from the investors list - * @param _start Index in investors list at which to start removing zero balances - * @param _iters Max number of iterations of the for loop - * NB - pruning this list will mean you may not be able to iterate over investors on-chain as of a historical checkpoint - */ - function pruneInvestors(uint256 _start, uint256 _iters) external; - - /** - * @notice Freezes all the transfers - */ - function freezeTransfers() external; - - /** - * @notice Un-freezes all the transfers - */ - function unfreezeTransfers() external; - - /** - * @notice Ends token minting period permanently - */ - function freezeMinting() external; - - /** - * @notice Mints new tokens and assigns them to the target investors. - * Can only be called by the STO attached to the token or by the Issuer (Security Token contract owner) - * @param _investors A list of addresses to whom the minted tokens will be delivered - * @param _values A list of the amount of tokens to mint to corresponding addresses from _investor[] list - * @return Success - */ - function mintMulti(address[] _investors, uint256[] _values) external returns (bool success); - - /** - * @notice Function used to attach a module to the security token - * @dev E.G.: On deployment (through the STR) ST gets a TransferManager module attached to it - * @dev to control restrictions on transfers. - * @dev You are allowed to add a new moduleType if: - * @dev - there is no existing module of that type yet added - * @dev - the last member of the module list is replacable - * @param _moduleFactory is the address of the module factory to be added - * @param _data is data packed into bytes used to further configure the module (See STO usage) - * @param _maxCost max amount of POLY willing to pay to module. (WIP) - */ - function addModule( - address _moduleFactory, - bytes _data, - uint256 _maxCost, - uint256 _budget - ) external; - - /** - * @notice Archives a module attached to the SecurityToken - * @param _module address of module to archive - */ - function archiveModule(address _module) external; - - /** - * @notice Unarchives a module attached to the SecurityToken - * @param _module address of module to unarchive - */ - function unarchiveModule(address _module) external; - - /** - * @notice Removes a module attached to the SecurityToken - * @param _module address of module to archive - */ - function removeModule(address _module) external; - - /** - * @notice Used by the issuer to set the controller addresses - * @param _controller address of the controller - */ - function setController(address _controller) external; - - /** - * @notice Used by a controller to execute a forced transfer - * @param _from address from which to take tokens - * @param _to address where to send tokens - * @param _value amount of tokens to transfer - * @param _data data to indicate validation - * @param _log data attached to the transfer by controller to emit in event - */ - function forceTransfer(address _from, address _to, uint256 _value, bytes _data, bytes _log) external; - - /** - * @notice Used by a controller to execute a foced burn - * @param _from address from which to take tokens - * @param _value amount of tokens to transfer - * @param _data data to indicate validation - * @param _log data attached to the transfer by controller to emit in event - */ - function forceBurn(address _from, uint256 _value, bytes _data, bytes _log) external; - - /** - * @notice Used by the issuer to permanently disable controller functionality - * @dev enabled via feature switch "disableControllerAllowed" - */ - function disableController() external; - - /** - * @notice Used to get the version of the securityToken - */ - function getVersion() external view returns(uint8[]); - - /** - * @notice Gets the investor count - */ - function getInvestorCount() external view returns(uint256); - - /** - * @notice Overloaded version of the transfer function - * @param _to receiver of transfer - * @param _value value of transfer - * @param _data data to indicate validation - * @return bool success - */ - function transferWithData(address _to, uint256 _value, bytes _data) external returns (bool success); - - /** - * @notice Overloaded version of the transferFrom function - * @param _from sender of transfer - * @param _to receiver of transfer - * @param _value value of transfer - * @param _data data to indicate validation - * @return bool success - */ - function transferFromWithData(address _from, address _to, uint256 _value, bytes _data) external returns(bool); - - /** - * @notice Provides the granularity of the token - * @return uint256 - */ - function granularity() external view returns(uint256); -} - -// File: contracts/interfaces/IModule.sol - -/** - * @title Interface that every module contract should implement - */ -interface IModule { - - /** - * @notice This function returns the signature of configure function - */ - function getInitFunction() external pure returns (bytes4); - - /** - * @notice Return the permission flags that are associated with a module - */ - function getPermissions() external view returns(bytes32[]); - - /** - * @notice Used to withdraw the fee by the factory owner - */ - function takeFee(uint256 _amount) external returns(bool); - -} - -// File: contracts/modules/ModuleStorage.sol - -/** - * @title Storage for Module contract - * @notice Contract is abstract - */ -contract ModuleStorage { - - /** - * @notice Constructor - * @param _securityToken Address of the security token - * @param _polyAddress Address of the polytoken - */ - constructor (address _securityToken, address _polyAddress) public { - securityToken = _securityToken; - factory = msg.sender; - polyToken = IERC20(_polyAddress); - } - - address public factory; - - address public securityToken; - - bytes32 public constant FEE_ADMIN = "FEE_ADMIN"; - - IERC20 public polyToken; - -} - -// File: openzeppelin-solidity/contracts/ownership/Ownable.sol - -/** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ -contract Ownable { - address public owner; - - - event OwnershipRenounced(address indexed previousOwner); - event OwnershipTransferred( - address indexed previousOwner, - address indexed newOwner - ); - - - /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - constructor() public { - owner = msg.sender; - } - - /** - * @dev Throws if called by any account other than the owner. - */ - modifier onlyOwner() { - require(msg.sender == owner); - _; - } - - /** - * @dev Allows the current owner to relinquish control of the contract. - */ - function renounceOwnership() public onlyOwner { - emit OwnershipRenounced(owner); - owner = address(0); - } - - /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param _newOwner The address to transfer ownership to. - */ - function transferOwnership(address _newOwner) public onlyOwner { - _transferOwnership(_newOwner); - } - - /** - * @dev Transfers control of the contract to a newOwner. - * @param _newOwner The address to transfer ownership to. - */ - function _transferOwnership(address _newOwner) internal { - require(_newOwner != address(0)); - emit OwnershipTransferred(owner, _newOwner); - owner = _newOwner; - } -} - -// File: contracts/modules/Module.sol - -/** - * @title Interface that any module contract should implement - * @notice Contract is abstract - */ -contract Module is IModule, ModuleStorage { - - /** - * @notice Constructor - * @param _securityToken Address of the security token - * @param _polyAddress Address of the polytoken - */ - constructor (address _securityToken, address _polyAddress) public - ModuleStorage(_securityToken, _polyAddress) - { - } - - //Allows owner, factory or permissioned delegate - modifier withPerm(bytes32 _perm) { - bool isOwner = msg.sender == Ownable(securityToken).owner(); - bool isFactory = msg.sender == factory; - require(isOwner||isFactory||ISecurityToken(securityToken).checkPermission(msg.sender, address(this), _perm), "Permission check failed"); - _; - } - - modifier onlyOwner { - require(msg.sender == Ownable(securityToken).owner(), "Sender is not owner"); - _; - } - - modifier onlyFactory { - require(msg.sender == factory, "Sender is not factory"); - _; - } - - modifier onlyFactoryOwner { - require(msg.sender == Ownable(factory).owner(), "Sender is not factory owner"); - _; - } - - modifier onlyFactoryOrOwner { - require((msg.sender == Ownable(securityToken).owner()) || (msg.sender == factory), "Sender is not factory or owner"); - _; - } - - /** - * @notice used to withdraw the fee by the factory owner - */ - function takeFee(uint256 _amount) public withPerm(FEE_ADMIN) returns(bool) { - require(polyToken.transferFrom(securityToken, Ownable(factory).owner(), _amount), "Unable to take fee"); - return true; - } -} - -// File: contracts/modules/Checkpoint/DividendCheckpointStorage.sol - -/** - * DISCLAIMER: Under certain conditions, the function pushDividendPayment - * may fail due to block gas limits. - * If the total number of investors that ever held tokens is greater than ~15,000 then - * the function may fail. If this happens investors can pull their dividends, or the Issuer - * can use pushDividendPaymentToAddresses to provide an explict address list in batches - */ -pragma solidity ^0.4.24; - -/** - * @title Checkpoint module for issuing ether dividends - * @dev abstract contract - */ -contract DividendCheckpointStorage { - - uint256 public EXCLUDED_ADDRESS_LIMIT = 50; - bytes32 public constant DISTRIBUTE = "DISTRIBUTE"; - bytes32 public constant MANAGE = "MANAGE"; - bytes32 public constant CHECKPOINT = "CHECKPOINT"; - - struct Dividend { - uint256 checkpointId; - uint256 created; // Time at which the dividend was created - uint256 maturity; // Time after which dividend can be claimed - set to 0 to bypass - uint256 expiry; // Time until which dividend can be claimed - after this time any remaining amount can be withdrawn by issuer - - // set to very high value to bypass - uint256 amount; // Dividend amount in WEI - uint256 claimedAmount; // Amount of dividend claimed so far - uint256 totalSupply; // Total supply at the associated checkpoint (avoids recalculating this) - bool reclaimed; // True if expiry has passed and issuer has reclaimed remaining dividend - uint256 dividendWithheld; - uint256 dividendWithheldReclaimed; - mapping (address => bool) claimed; // List of addresses which have claimed dividend - mapping (address => bool) dividendExcluded; // List of addresses which cannot claim dividends - bytes32 name; // Name/title - used for identification - } - - // List of all dividends - Dividend[] public dividends; - - // List of addresses which cannot claim dividends - address[] public excluded; - - // Mapping from address to withholding tax as a percentage * 10**16 - mapping (address => uint256) public withholdingTax; - - // Total amount of ETH withheld per investor - mapping (address => uint256) public investorWithheld; - -} - -// File: contracts/modules/Checkpoint/ICheckpoint.sol - -/** - * @title Interface to be implemented by all checkpoint modules - */ -/*solium-disable-next-line no-empty-blocks*/ -interface ICheckpoint { - -} - -// File: openzeppelin-solidity/contracts/math/Math.sol - -/** - * @title Math - * @dev Assorted math operations - */ -library Math { - function max64(uint64 a, uint64 b) internal pure returns (uint64) { - return a >= b ? a : b; - } - - function min64(uint64 a, uint64 b) internal pure returns (uint64) { - return a < b ? a : b; - } - - function max256(uint256 a, uint256 b) internal pure returns (uint256) { - return a >= b ? a : b; - } - - function min256(uint256 a, uint256 b) internal pure returns (uint256) { - return a < b ? a : b; - } -} - -// File: openzeppelin-solidity/contracts/math/SafeMath.sol - -/** - * @title SafeMath - * @dev Math operations with safety checks that throw on error - */ -library SafeMath { - - /** - * @dev Multiplies two numbers, throws on overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { - // Gas optimization: this is cheaper than asserting 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 - if (a == 0) { - return 0; - } - - c = a * b; - assert(c / a == b); - return c; - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - // assert(b > 0); // Solidity automatically throws when dividing by 0 - // uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - return a / b; - } - - /** - * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - assert(b <= a); - return a - b; - } - - /** - * @dev Adds two numbers, throws on overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256 c) { - c = a + b; - assert(c >= a); - return c; - } -} - -// File: contracts/modules/Checkpoint/DividendCheckpoint.sol - -/** - * DISCLAIMER: Under certain conditions, the function pushDividendPayment - * may fail due to block gas limits. - * If the total number of investors that ever held tokens is greater than ~15,000 then - * the function may fail. If this happens investors can pull their dividends, or the Issuer - * can use pushDividendPaymentToAddresses to provide an explict address list in batches - */ -pragma solidity ^0.4.24; - -/** - * @title Checkpoint module for issuing ether dividends - * @dev abstract contract - */ -contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module { - using SafeMath for uint256; - - event SetDefaultExcludedAddresses(address[] _excluded, uint256 _timestamp); - event SetWithholding(address[] _investors, uint256[] _withholding, uint256 _timestamp); - event SetWithholdingFixed(address[] _investors, uint256 _withholding, uint256 _timestamp); - - modifier validDividendIndex(uint256 _dividendIndex) { - require(_dividendIndex < dividends.length, "Invalid dividend"); - require(!dividends[_dividendIndex].reclaimed, "Dividend reclaimed"); - /*solium-disable-next-line security/no-block-members*/ - require(now >= dividends[_dividendIndex].maturity, "Dividend maturity in future"); - /*solium-disable-next-line security/no-block-members*/ - require(now < dividends[_dividendIndex].expiry, "Dividend expiry in past"); - _; - } - - /** - * @notice Init function i.e generalise function to maintain the structure of the module contract - * @return bytes4 - */ - function getInitFunction() public pure returns (bytes4) { - return bytes4(0); - } - - /** - * @notice Return the default excluded addresses - * @return List of excluded addresses - */ - function getDefaultExcluded() external view returns (address[]) { - return excluded; - } - - /** - * @notice Creates a checkpoint on the security token - * @return Checkpoint ID - */ - function createCheckpoint() public withPerm(CHECKPOINT) returns (uint256) { - return ISecurityToken(securityToken).createCheckpoint(); - } - - /** - * @notice Function to clear and set list of excluded addresses used for future dividends - * @param _excluded Addresses of investors - */ - function setDefaultExcluded(address[] _excluded) public withPerm(MANAGE) { - require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many excluded addresses"); - for (uint256 j = 0; j < _excluded.length; j++) { - require (_excluded[j] != address(0), "Invalid address"); - for (uint256 i = j + 1; i < _excluded.length; i++) { - require (_excluded[j] != _excluded[i], "Duplicate exclude address"); - } - } - excluded = _excluded; - /*solium-disable-next-line security/no-block-members*/ - emit SetDefaultExcludedAddresses(excluded, now); - } - - /** - * @notice Function to set withholding tax rates for investors - * @param _investors Addresses of investors - * @param _withholding Withholding tax for individual investors (multiplied by 10**16) - */ - function setWithholding(address[] _investors, uint256[] _withholding) public withPerm(MANAGE) { - require(_investors.length == _withholding.length, "Mismatched input lengths"); - /*solium-disable-next-line security/no-block-members*/ - emit SetWithholding(_investors, _withholding, now); - for (uint256 i = 0; i < _investors.length; i++) { - require(_withholding[i] <= 10**18, "Incorrect withholding tax"); - withholdingTax[_investors[i]] = _withholding[i]; - } - } - - /** - * @notice Function to set withholding tax rates for investors - * @param _investors Addresses of investor - * @param _withholding Withholding tax for all investors (multiplied by 10**16) - */ - function setWithholdingFixed(address[] _investors, uint256 _withholding) public withPerm(MANAGE) { - require(_withholding <= 10**18, "Incorrect withholding tax"); - /*solium-disable-next-line security/no-block-members*/ - emit SetWithholdingFixed(_investors, _withholding, now); - for (uint256 i = 0; i < _investors.length; i++) { - withholdingTax[_investors[i]] = _withholding; - } - } - - /** - * @notice Issuer can push dividends to provided addresses - * @param _dividendIndex Dividend to push - * @param _payees Addresses to which to push the dividend - */ - function pushDividendPaymentToAddresses( - uint256 _dividendIndex, - address[] _payees - ) - public - withPerm(DISTRIBUTE) - validDividendIndex(_dividendIndex) - { - Dividend storage dividend = dividends[_dividendIndex]; - for (uint256 i = 0; i < _payees.length; i++) { - if ((!dividend.claimed[_payees[i]]) && (!dividend.dividendExcluded[_payees[i]])) { - _payDividend(_payees[i], dividend, _dividendIndex); - } - } - } - - /** - * @notice Issuer can push dividends using the investor list from the security token - * @param _dividendIndex Dividend to push - * @param _start Index in investor list at which to start pushing dividends - * @param _iterations Number of addresses to push dividends for - */ - function pushDividendPayment( - uint256 _dividendIndex, - uint256 _start, - uint256 _iterations - ) - public - withPerm(DISTRIBUTE) - validDividendIndex(_dividendIndex) - { - Dividend storage dividend = dividends[_dividendIndex]; - address[] memory investors = ISecurityToken(securityToken).getInvestors(); - uint256 numberInvestors = Math.min256(investors.length, _start.add(_iterations)); - for (uint256 i = _start; i < numberInvestors; i++) { - address payee = investors[i]; - if ((!dividend.claimed[payee]) && (!dividend.dividendExcluded[payee])) { - _payDividend(payee, dividend, _dividendIndex); - } - } - } - - /** - * @notice Investors can pull their own dividends - * @param _dividendIndex Dividend to pull - */ - function pullDividendPayment(uint256 _dividendIndex) public validDividendIndex(_dividendIndex) - { - Dividend storage dividend = dividends[_dividendIndex]; - require(!dividend.claimed[msg.sender], "Dividend already claimed"); - require(!dividend.dividendExcluded[msg.sender], "msg.sender excluded from Dividend"); - _payDividend(msg.sender, dividend, _dividendIndex); - } - - /** - * @notice Internal function for paying dividends - * @param _payee Address of investor - * @param _dividend Storage with previously issued dividends - * @param _dividendIndex Dividend to pay - */ - function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal; - - /** - * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends - * @param _dividendIndex Dividend to reclaim - */ - function reclaimDividend(uint256 _dividendIndex) external; - - /** - * @notice Calculate amount of dividends claimable - * @param _dividendIndex Dividend to calculate - * @param _payee Affected investor address - * @return claim, withheld amounts - */ - function calculateDividend(uint256 _dividendIndex, address _payee) public view returns(uint256, uint256) { - require(_dividendIndex < dividends.length, "Invalid dividend"); - Dividend storage dividend = dividends[_dividendIndex]; - if (dividend.claimed[_payee] || dividend.dividendExcluded[_payee]) { - return (0, 0); - } - uint256 balance = ISecurityToken(securityToken).balanceOfAt(_payee, dividend.checkpointId); - uint256 claim = balance.mul(dividend.amount).div(dividend.totalSupply); - uint256 withheld = claim.mul(withholdingTax[_payee]).div(uint256(10**18)); - return (claim, withheld); - } - - /** - * @notice Get the index according to the checkpoint id - * @param _checkpointId Checkpoint id to query - * @return uint256[] - */ - function getDividendIndex(uint256 _checkpointId) public view returns(uint256[]) { - uint256 counter = 0; - for(uint256 i = 0; i < dividends.length; i++) { - if (dividends[i].checkpointId == _checkpointId) { - counter++; - } - } - - uint256[] memory index = new uint256[](counter); - counter = 0; - for(uint256 j = 0; j < dividends.length; j++) { - if (dividends[j].checkpointId == _checkpointId) { - index[counter] = j; - counter++; - } - } - return index; - } - - /** - * @notice Allows issuer to withdraw withheld tax - * @param _dividendIndex Dividend to withdraw from - */ - function withdrawWithholding(uint256 _dividendIndex) external; - - /** - * @notice Return the permissions flag that are associated with this module - * @return bytes32 array - */ - function getPermissions() public view returns(bytes32[]) { - bytes32[] memory allPermissions = new bytes32[](2); - allPermissions[0] = DISTRIBUTE; - allPermissions[1] = MANAGE; - return allPermissions; - } - -} - -// File: contracts/modules/Checkpoint/ERC20DividendCheckpointStorage.sol - -/** - * @title Checkpoint module for issuing ERC20 dividends - */ -contract ERC20DividendCheckpointStorage { - - // Mapping to token address for each dividend - mapping (uint256 => address) public dividendTokens; - -} - -// File: contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol - -/** - * @title Checkpoint module for issuing ERC20 dividends - */ -contract ERC20DividendCheckpoint is ERC20DividendCheckpointStorage, DividendCheckpoint { - using SafeMath for uint256; - - event ERC20DividendDeposited( - address indexed _depositor, - uint256 _checkpointId, - uint256 _created, - uint256 _maturity, - uint256 _expiry, - address indexed _token, - uint256 _amount, - uint256 _totalSupply, - uint256 _dividendIndex, - bytes32 indexed _name - ); - event ERC20DividendClaimed( - address indexed _payee, - uint256 _dividendIndex, - address indexed _token, - uint256 _amount, - uint256 _withheld - ); - event ERC20DividendReclaimed( - address indexed _claimer, - uint256 _dividendIndex, - address indexed _token, - uint256 _claimedAmount - ); - event ERC20DividendWithholdingWithdrawn( - address indexed _claimer, - uint256 _dividendIndex, - address indexed _token, - uint256 _withheldAmount - ); - - /** - * @notice Constructor - * @param _securityToken Address of the security token - * @param _polyAddress Address of the polytoken - */ - constructor (address _securityToken, address _polyAddress) public - Module(_securityToken, _polyAddress) - { - } - - /** - * @notice Creates a dividend and checkpoint for the dividend - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _token Address of ERC20 token in which dividend is to be denominated - * @param _amount Amount of specified token for dividend - * @param _name Name/Title for identification - */ - function createDividend( - uint256 _maturity, - uint256 _expiry, - address _token, - uint256 _amount, - bytes32 _name - ) - external - withPerm(MANAGE) - { - createDividendWithExclusions(_maturity, _expiry, _token, _amount, excluded, _name); - } - - /** - * @notice Creates a dividend with a provided checkpoint - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _token Address of ERC20 token in which dividend is to be denominated - * @param _amount Amount of specified token for dividend - * @param _checkpointId Checkpoint id from which to create dividends - * @param _name Name/Title for identification - */ - function createDividendWithCheckpoint( - uint256 _maturity, - uint256 _expiry, - address _token, - uint256 _amount, - uint256 _checkpointId, - bytes32 _name - ) - external - withPerm(MANAGE) - { - _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, excluded, _name); - } - - /** - * @notice Creates a dividend and checkpoint for the dividend - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _token Address of ERC20 token in which dividend is to be denominated - * @param _amount Amount of specified token for dividend - * @param _excluded List of addresses to exclude - * @param _name Name/Title for identification - */ - function createDividendWithExclusions( - uint256 _maturity, - uint256 _expiry, - address _token, - uint256 _amount, - address[] _excluded, - bytes32 _name - ) - public - withPerm(MANAGE) - { - uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint(); - _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, checkpointId, _excluded, _name); - } - - /** - * @notice Creates a dividend with a provided checkpoint - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _token Address of ERC20 token in which dividend is to be denominated - * @param _amount Amount of specified token for dividend - * @param _checkpointId Checkpoint id from which to create dividends - * @param _excluded List of addresses to exclude - * @param _name Name/Title for identification - */ - function createDividendWithCheckpointAndExclusions( - uint256 _maturity, - uint256 _expiry, - address _token, - uint256 _amount, - uint256 _checkpointId, - address[] _excluded, - bytes32 _name - ) - public - withPerm(MANAGE) - { - _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, _excluded, _name); - } - - /** - * @notice Creates a dividend with a provided checkpoint - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _token Address of ERC20 token in which dividend is to be denominated - * @param _amount Amount of specified token for dividend - * @param _checkpointId Checkpoint id from which to create dividends - * @param _excluded List of addresses to exclude - * @param _name Name/Title for identification - */ - function _createDividendWithCheckpointAndExclusions( - uint256 _maturity, - uint256 _expiry, - address _token, - uint256 _amount, - uint256 _checkpointId, - address[] _excluded, - bytes32 _name - ) - internal - { - ISecurityToken securityTokenInstance = ISecurityToken(securityToken); - require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many addresses excluded"); - require(_expiry > _maturity, "Expiry before maturity"); - /*solium-disable-next-line security/no-block-members*/ - require(_expiry > now, "Expiry in past"); - require(_amount > 0, "No dividend sent"); - require(_token != address(0), "Invalid token"); - require(_checkpointId <= securityTokenInstance.currentCheckpointId(), "Invalid checkpoint"); - require(IERC20(_token).transferFrom(msg.sender, address(this), _amount), "insufficent allowance"); - require(_name[0] != 0); - uint256 dividendIndex = dividends.length; - uint256 currentSupply = securityTokenInstance.totalSupplyAt(_checkpointId); - uint256 excludedSupply = 0; - dividends.push( - Dividend( - _checkpointId, - now, /*solium-disable-line security/no-block-members*/ - _maturity, - _expiry, - _amount, - 0, - 0, - false, - 0, - 0, - _name - ) - ); - - for (uint256 j = 0; j < _excluded.length; j++) { - require (_excluded[j] != address(0), "Invalid address"); - require(!dividends[dividendIndex].dividendExcluded[_excluded[j]], "duped exclude address"); - excludedSupply = excludedSupply.add(securityTokenInstance.balanceOfAt(_excluded[j], _checkpointId)); - dividends[dividendIndex].dividendExcluded[_excluded[j]] = true; - } - - dividends[dividendIndex].totalSupply = currentSupply.sub(excludedSupply); - dividendTokens[dividendIndex] = _token; - _emitERC20DividendDepositedEvent(_checkpointId, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex, _name); - } - - /** - * @notice Emits the ERC20DividendDeposited event. - * Seperated into a different function as a workaround for stack too deep error - */ - function _emitERC20DividendDepositedEvent( - uint256 _checkpointId, - uint256 _maturity, - uint256 _expiry, - address _token, - uint256 _amount, - uint256 currentSupply, - uint256 dividendIndex, - bytes32 _name - ) - internal - { - /*solium-disable-next-line security/no-block-members*/ - emit ERC20DividendDeposited(msg.sender, _checkpointId, now, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex, _name); - } - - /** - * @notice Internal function for paying dividends - * @param _payee Address of investor - * @param _dividend Storage with previously issued dividends - * @param _dividendIndex Dividend to pay - */ - function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal { - (uint256 claim, uint256 withheld) = calculateDividend(_dividendIndex, _payee); - _dividend.claimed[_payee] = true; - _dividend.claimedAmount = claim.add(_dividend.claimedAmount); - uint256 claimAfterWithheld = claim.sub(withheld); - if (claimAfterWithheld > 0) { - require(IERC20(dividendTokens[_dividendIndex]).transfer(_payee, claimAfterWithheld), "transfer failed"); - _dividend.dividendWithheld = _dividend.dividendWithheld.add(withheld); - investorWithheld[_payee] = investorWithheld[_payee].add(withheld); - emit ERC20DividendClaimed(_payee, _dividendIndex, dividendTokens[_dividendIndex], claim, withheld); - } - } - - /** - * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends - * @param _dividendIndex Dividend to reclaim - */ - function reclaimDividend(uint256 _dividendIndex) external withPerm(MANAGE) { - require(_dividendIndex < dividends.length, "Invalid dividend"); - /*solium-disable-next-line security/no-block-members*/ - require(now >= dividends[_dividendIndex].expiry, "Dividend expiry in future"); - require(!dividends[_dividendIndex].reclaimed, "already claimed"); - dividends[_dividendIndex].reclaimed = true; - Dividend storage dividend = dividends[_dividendIndex]; - uint256 remainingAmount = dividend.amount.sub(dividend.claimedAmount); - address owner = IOwnable(securityToken).owner(); - require(IERC20(dividendTokens[_dividendIndex]).transfer(owner, remainingAmount), "transfer failed"); - emit ERC20DividendReclaimed(owner, _dividendIndex, dividendTokens[_dividendIndex], remainingAmount); - } - - /** - * @notice Allows issuer to withdraw withheld tax - * @param _dividendIndex Dividend to withdraw from - */ - function withdrawWithholding(uint256 _dividendIndex) external withPerm(MANAGE) { - require(_dividendIndex < dividends.length, "Invalid dividend"); - Dividend storage dividend = dividends[_dividendIndex]; - uint256 remainingWithheld = dividend.dividendWithheld.sub(dividend.dividendWithheldReclaimed); - dividend.dividendWithheldReclaimed = dividend.dividendWithheld; - address owner = IOwnable(securityToken).owner(); - require(IERC20(dividendTokens[_dividendIndex]).transfer(owner, remainingWithheld), "transfer failed"); - emit ERC20DividendWithholdingWithdrawn(owner, _dividendIndex, dividendTokens[_dividendIndex], remainingWithheld); - } - -} diff --git a/scripts/proxy.sol b/scripts/proxy.sol deleted file mode 100644 index ed315955f..000000000 --- a/scripts/proxy.sol +++ /dev/null @@ -1,332 +0,0 @@ -pragma solidity ^0.4.24; - -// File: contracts/Pausable.sol - -/** - * @title Utility contract to allow pausing and unpausing of certain functions - */ -contract Pausable { - - event Pause(uint256 _timestammp); - event Unpause(uint256 _timestamp); - - bool public paused = false; - - /** - * @notice Modifier to make a function callable only when the contract is not paused. - */ - modifier whenNotPaused() { - require(!paused, "Contract is paused"); - _; - } - - /** - * @notice Modifier to make a function callable only when the contract is paused. - */ - modifier whenPaused() { - require(paused, "Contract is not paused"); - _; - } - - /** - * @notice Called by the owner to pause, triggers stopped state - */ - function _pause() internal whenNotPaused { - paused = true; - /*solium-disable-next-line security/no-block-members*/ - emit Pause(now); - } - - /** - * @notice Called by the owner to unpause, returns to normal state - */ - function _unpause() internal whenPaused { - paused = false; - /*solium-disable-next-line security/no-block-members*/ - emit Unpause(now); - } - -} - -// File: contracts/modules/Checkpoint/DividendCheckpointStorage.sol - -/** - * DISCLAIMER: Under certain conditions, the function pushDividendPayment - * may fail due to block gas limits. - * If the total number of investors that ever held tokens is greater than ~15,000 then - * the function may fail. If this happens investors can pull their dividends, or the Issuer - * can use pushDividendPaymentToAddresses to provide an explict address list in batches - */ -pragma solidity ^0.4.24; - -/** - * @title Checkpoint module for issuing ether dividends - * @dev abstract contract - */ -contract DividendCheckpointStorage { - - uint256 public EXCLUDED_ADDRESS_LIMIT = 50; - bytes32 public constant DISTRIBUTE = "DISTRIBUTE"; - bytes32 public constant MANAGE = "MANAGE"; - bytes32 public constant CHECKPOINT = "CHECKPOINT"; - - struct Dividend { - uint256 checkpointId; - uint256 created; // Time at which the dividend was created - uint256 maturity; // Time after which dividend can be claimed - set to 0 to bypass - uint256 expiry; // Time until which dividend can be claimed - after this time any remaining amount can be withdrawn by issuer - - // set to very high value to bypass - uint256 amount; // Dividend amount in WEI - uint256 claimedAmount; // Amount of dividend claimed so far - uint256 totalSupply; // Total supply at the associated checkpoint (avoids recalculating this) - bool reclaimed; // True if expiry has passed and issuer has reclaimed remaining dividend - uint256 dividendWithheld; - uint256 dividendWithheldReclaimed; - mapping (address => bool) claimed; // List of addresses which have claimed dividend - mapping (address => bool) dividendExcluded; // List of addresses which cannot claim dividends - bytes32 name; // Name/title - used for identification - } - - // List of all dividends - Dividend[] public dividends; - - // List of addresses which cannot claim dividends - address[] public excluded; - - // Mapping from address to withholding tax as a percentage * 10**16 - mapping (address => uint256) public withholdingTax; - - // Total amount of ETH withheld per investor - mapping (address => uint256) public investorWithheld; - -} - -// File: contracts/modules/Checkpoint/ERC20DividendCheckpointStorage.sol - -/** - * @title Checkpoint module for issuing ERC20 dividends - */ -contract ERC20DividendCheckpointStorage { - - // Mapping to token address for each dividend - mapping (uint256 => address) public dividendTokens; - -} - -// File: contracts/interfaces/IERC20.sol - -/** - * @title ERC20 interface - * @dev see https://github.com/ethereum/EIPs/issues/20 - */ -interface IERC20 { - function decimals() external view returns (uint8); - function totalSupply() external view returns (uint256); - function balanceOf(address _owner) external view returns (uint256); - function allowance(address _owner, address _spender) external view returns (uint256); - function transfer(address _to, uint256 _value) external returns (bool); - function transferFrom(address _from, address _to, uint256 _value) external returns (bool); - function approve(address _spender, uint256 _value) external returns (bool); - function decreaseApproval(address _spender, uint _subtractedValue) external returns (bool); - function increaseApproval(address _spender, uint _addedValue) external returns (bool); - event Transfer(address indexed from, address indexed to, uint256 value); - event Approval(address indexed owner, address indexed spender, uint256 value); -} - -// File: contracts/modules/ModuleStorage.sol - -/** - * @title Storage for Module contract - * @notice Contract is abstract - */ -contract ModuleStorage { - - /** - * @notice Constructor - * @param _securityToken Address of the security token - * @param _polyAddress Address of the polytoken - */ - constructor (address _securityToken, address _polyAddress) public { - securityToken = _securityToken; - factory = msg.sender; - polyToken = IERC20(_polyAddress); - } - - address public factory; - - address public securityToken; - - bytes32 public constant FEE_ADMIN = "FEE_ADMIN"; - - IERC20 public polyToken; - -} - -// File: contracts/proxy/Proxy.sol - -/** - * @title Proxy - * @dev Gives the possibility to delegate any call to a foreign implementation. - */ -contract Proxy { - - /** - * @dev Tells the address of the implementation where every call will be delegated. - * @return address of the implementation to which it will be delegated - */ - function _implementation() internal view returns (address); - - /** - * @dev Fallback function. - * Implemented entirely in `_fallback`. - */ - function _fallback() internal { - _delegate(_implementation()); - } - - /** - * @dev Fallback function allowing to perform a delegatecall to the given implementation. - * This function will return whatever the implementation call returns - */ - function _delegate(address implementation) internal { - /*solium-disable-next-line security/no-inline-assembly*/ - assembly { - // Copy msg.data. We take full control of memory in this inline assembly - // block because it will not return to Solidity code. We overwrite the - // Solidity scratch pad at memory position 0. - calldatacopy(0, 0, calldatasize) - - // Call the implementation. - // out and outsize are 0 because we don't know the size yet. - let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0) - - // Copy the returned data. - returndatacopy(0, 0, returndatasize) - - switch result - // delegatecall returns 0 on error. - case 0 { revert(0, returndatasize) } - default { return(0, returndatasize) } - } - } - - function () public payable { - _fallback(); - } -} - -// File: contracts/proxy/OwnedProxy.sol - -/** - * @title OwnedUpgradeabilityProxy - * @dev This contract combines an upgradeability proxy with basic authorization control functionalities - */ -contract OwnedProxy is Proxy { - - // Owner of the contract - address private __owner; - - // Address of the current implementation - address internal __implementation; - - /** - * @dev Event to show ownership has been transferred - * @param _previousOwner representing the address of the previous owner - * @param _newOwner representing the address of the new owner - */ - event ProxyOwnershipTransferred(address _previousOwner, address _newOwner); - - /** - * @dev Throws if called by any account other than the owner. - */ - modifier ifOwner() { - if (msg.sender == _owner()) { - _; - } else { - _fallback(); - } - } - - /** - * @dev the constructor sets the original owner of the contract to the sender account. - */ - constructor() public { - _setOwner(msg.sender); - } - - /** - * @dev Tells the address of the owner - * @return the address of the owner - */ - function _owner() internal view returns (address) { - return __owner; - } - - /** - * @dev Sets the address of the owner - */ - function _setOwner(address _newOwner) internal { - require(_newOwner != address(0), "Address should not be 0x"); - __owner = _newOwner; - } - - /** - * @notice Internal function to provide the address of the implementation contract - */ - function _implementation() internal view returns (address) { - return __implementation; - } - - /** - * @dev Tells the address of the proxy owner - * @return the address of the proxy owner - */ - function proxyOwner() external ifOwner returns (address) { - return _owner(); - } - - /** - * @dev Tells the address of the current implementation - * @return address of the current implementation - */ - function implementation() external ifOwner returns (address) { - return _implementation(); - } - - /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param _newOwner The address to transfer ownership to. - */ - function transferProxyOwnership(address _newOwner) external ifOwner { - require(_newOwner != address(0), "Address should not be 0x"); - emit ProxyOwnershipTransferred(_owner(), _newOwner); - _setOwner(_newOwner); - } - -} - -// File: contracts/proxy/ERC20DividendCheckpointProxy.sol - -/** - * @title Transfer Manager module for core transfer validation functionality - */ -contract ERC20DividendCheckpointProxy is ERC20DividendCheckpointStorage, DividendCheckpointStorage, ModuleStorage, Pausable, OwnedProxy { - - /** - * @notice Constructor - * @param _securityToken Address of the security token - * @param _polyAddress Address of the polytoken - * @param _implementation representing the address of the new implementation to be set - */ - constructor (address _securityToken, address _polyAddress, address _implementation) - public - ModuleStorage(_securityToken, _polyAddress) - { - require( - _implementation != address(0), - "Implementation address should not be 0x" - ); - __implementation = _implementation; - } - -} diff --git a/yarn.lock b/yarn.lock index 27308427c..31973936e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,12 +5,10 @@ "@soldoc/markdown@^0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@soldoc/markdown/-/markdown-0.1.0.tgz#9f85be75049af9721b5129f133d52dafbf5f671e" - integrity sha512-V0UnvVVJ1qDzpuKLMuh7oHG94puwi8BI3t99Vrr7dQgIHuJdfZJ4SbGuWuFV/fSthyH++WY4ePO3d6gxfZ2//w== "@soldoc/soldoc@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@soldoc/soldoc/-/soldoc-0.4.3.tgz#24ffee9264228e1c3edd61fd3162d63587954933" - integrity sha1-JP/ukmQijhw+3WH9MWLWNYeVSTM= dependencies: "@soldoc/markdown" "^0.1.0" chalk "^2.3.1" @@ -24,31 +22,26 @@ abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== abbrev@1.0.x: version "1.0.9" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" - integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= abstract-leveldown@~2.6.0: version "2.6.3" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz#1c5e8c6a5ef965ae8c35dfb3a8770c476b82c4b8" - integrity sha512-2++wDf/DYqkPR3o5tbfdhF96EfMApo1GpPfzOsR/ZYXdkSmELlvOOEAl9iKkRsktMPHdGjO4rtkBpf2I7TiTeA== dependencies: xtend "~4.0.0" abstract-leveldown@~2.7.1: version "2.7.2" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz#87a44d7ebebc341d59665204834c8b7e0932cc93" - integrity sha512-+OVvxH2rHVEhWLdbudP6p0+dNMXu8JA1CbhP19T8paTYAcX7oJ4OVjT+ZUVpv7mITxXHqDMej+GdqXBmXkw09w== dependencies: xtend "~4.0.0" accepts@~1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" - integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= dependencies: mime-types "~2.1.18" negotiator "0.6.1" @@ -56,56 +49,46 @@ accepts@~1.3.5: acorn-dynamic-import@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" - integrity sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ= dependencies: acorn "^4.0.3" acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" - integrity sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s= dependencies: acorn "^3.0.4" acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - integrity sha1-ReN/s56No/JbruP/U2niu18iAXo= acorn@^4.0.3: version "4.0.13" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" - integrity sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c= acorn@^5.0.0, acorn@^5.5.0: version "5.7.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" - integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== aes-js@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" - integrity sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0= aes-js@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.1.tgz#89fd1f94ae51b4c72d62466adc1a7323ff52f072" - integrity sha512-cEA0gBelItZZV7iBiL8ApCiNgc+gBWJJ4uoORhbu6vOqAJ0UL9wIlxr4RI7ij9SSVzy6AnPwiu37kVYiHCl3nw== ajv-keywords@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" - integrity sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I= ajv-keywords@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" - integrity sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo= ajv@^5.1.1, ajv@^5.2.2, ajv@^5.2.3, ajv@^5.3.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= dependencies: co "^4.6.0" fast-deep-equal "^1.0.0" @@ -115,7 +98,6 @@ ajv@^5.1.1, ajv@^5.2.2, ajv@^5.2.3, ajv@^5.3.0: ajv@^6.1.0: version "6.5.4" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.4.tgz#247d5274110db653706b550fcc2b797ca28cfc59" - integrity sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg== dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" @@ -125,7 +107,6 @@ ajv@^6.1.0: align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc= dependencies: kind-of "^3.0.2" longest "^1.0.1" @@ -134,7 +115,6 @@ align-text@^0.1.1, align-text@^0.1.3: ambi@^2.2.0: version "2.5.0" resolved "https://registry.yarnpkg.com/ambi/-/ambi-2.5.0.tgz#7c8e372be48891157e7cea01cb6f9143d1f74220" - integrity sha1-fI43K+SIkRV+fOoBy2+RQ9H3QiA= dependencies: editions "^1.1.1" typechecker "^4.3.0" @@ -142,44 +122,36 @@ ambi@^2.2.0: amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= ansi-escapes@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" - integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw== ansi-regex@^2.0.0, ansi-regex@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" any-promise@1.3.0, any-promise@^1.0.0, any-promise@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= anymatch@^1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" - integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA== dependencies: micromatch "^2.1.5" normalize-path "^2.0.0" @@ -187,7 +159,6 @@ anymatch@^1.3.0: anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== dependencies: micromatch "^3.1.4" normalize-path "^2.1.1" @@ -195,12 +166,10 @@ anymatch@^2.0.0: aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== are-we-there-yet@~1.1.2: version "1.1.5" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== dependencies: delegates "^1.0.0" readable-stream "^2.0.6" @@ -208,85 +177,56 @@ are-we-there-yet@~1.1.2: argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" -arguments-extended@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/arguments-extended/-/arguments-extended-0.0.3.tgz#6107e4917d0eb6f0a4dd66320fc15afc72ef4946" - integrity sha1-YQfkkX0OtvCk3WYyD8Fa/HLvSUY= - dependencies: - extended "~0.0.3" - is-extended "~0.0.8" - arr-diff@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= dependencies: arr-flatten "^1.0.1" arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== arr-union@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-extended@~0.0.3, array-extended@~0.0.4, array-extended@~0.0.5: - version "0.0.11" - resolved "https://registry.yarnpkg.com/array-extended/-/array-extended-0.0.11.tgz#d7144ae748de93ca726f121009dbff1626d164bd" - integrity sha1-1xRK50jek8pybxIQCdv/FibRZL0= - dependencies: - arguments-extended "~0.0.3" - extended "~0.0.3" - is-extended "~0.0.3" array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= dependencies: array-uniq "^1.0.1" array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= asn1.js@^4.0.0: version "4.10.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" - integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== dependencies: bn.js "^4.0.0" inherits "^2.0.1" @@ -295,36 +235,30 @@ asn1.js@^4.0.0: asn1@~0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== dependencies: safer-buffer "~2.1.0" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= assert@^1.1.1: version "1.4.1" resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" - integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= dependencies: util "0.10.3" assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - integrity sha1-GdOGodntxufByF04iu28xW0zYC0= async-eventemitter@^0.2.2: version "0.2.4" resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" - integrity sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw== dependencies: async "^2.4.0" @@ -337,49 +271,44 @@ async-eventemitter@ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" - integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== async@1.x, async@^1.4.2, async@~1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.4.1, async@^2.5.0: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" - integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== dependencies: lodash "^4.17.10" +async@~0.9.0: + version "0.9.2" + resolved "http://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + async@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9" - integrity sha1-+PwEyjoTeErenhZBr5hXjPvWR6k= asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= atob@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= dependencies: chalk "^1.1.3" esutils "^2.0.2" @@ -388,7 +317,6 @@ babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: babel-core@^6.0.14, babel-core@^6.26.0: version "6.26.3" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" - integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== dependencies: babel-code-frame "^6.26.0" babel-generator "^6.26.0" @@ -413,7 +341,6 @@ babel-core@^6.0.14, babel-core@^6.26.0: babel-generator@^6.26.0: version "6.26.1" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" - integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== dependencies: babel-messages "^6.23.0" babel-runtime "^6.26.0" @@ -427,7 +354,6 @@ babel-generator@^6.26.0: babel-helper-bindify-decorators@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" - integrity sha1-FMGeXxQte0fxmlJDHlKxzLxAozA= dependencies: babel-runtime "^6.22.0" babel-traverse "^6.24.1" @@ -436,7 +362,6 @@ babel-helper-bindify-decorators@^6.24.1: babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - integrity sha1-zORReto1b0IgvK6KAsKzRvmlZmQ= dependencies: babel-helper-explode-assignable-expression "^6.24.1" babel-runtime "^6.22.0" @@ -445,7 +370,6 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: babel-helper-call-delegate@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - integrity sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340= dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -455,7 +379,6 @@ babel-helper-call-delegate@^6.24.1: babel-helper-define-map@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" - integrity sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8= dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.26.0" @@ -465,7 +388,6 @@ babel-helper-define-map@^6.24.1: babel-helper-explode-assignable-expression@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - integrity sha1-8luCz33BBDPFX3BZLVdGQArCLKo= dependencies: babel-runtime "^6.22.0" babel-traverse "^6.24.1" @@ -474,7 +396,6 @@ babel-helper-explode-assignable-expression@^6.24.1: babel-helper-explode-class@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" - integrity sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes= dependencies: babel-helper-bindify-decorators "^6.24.1" babel-runtime "^6.22.0" @@ -484,7 +405,6 @@ babel-helper-explode-class@^6.24.1: babel-helper-function-name@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - integrity sha1-00dbjAPtmCQqJbSDUasYOZ01gKk= dependencies: babel-helper-get-function-arity "^6.24.1" babel-runtime "^6.22.0" @@ -495,7 +415,6 @@ babel-helper-function-name@^6.24.1: babel-helper-get-function-arity@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - integrity sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -503,7 +422,6 @@ babel-helper-get-function-arity@^6.24.1: babel-helper-hoist-variables@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" - integrity sha1-HssnaJydJVE+rbyZFKc/VAi+enY= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -511,7 +429,6 @@ babel-helper-hoist-variables@^6.24.1: babel-helper-optimise-call-expression@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" - integrity sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -519,7 +436,6 @@ babel-helper-optimise-call-expression@^6.24.1: babel-helper-regex@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" - integrity sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI= dependencies: babel-runtime "^6.26.0" babel-types "^6.26.0" @@ -528,7 +444,6 @@ babel-helper-regex@^6.24.1: babel-helper-remap-async-to-generator@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" - integrity sha1-XsWBgnrXI/7N04HxySg5BnbkVRs= dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -539,7 +454,6 @@ babel-helper-remap-async-to-generator@^6.24.1: babel-helper-replace-supers@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" - integrity sha1-v22/5Dk40XNpohPKiov3S2qQqxo= dependencies: babel-helper-optimise-call-expression "^6.24.1" babel-messages "^6.23.0" @@ -551,7 +465,6 @@ babel-helper-replace-supers@^6.24.1: babel-helpers@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - integrity sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI= dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" @@ -559,61 +472,50 @@ babel-helpers@^6.24.1: babel-messages@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= dependencies: babel-runtime "^6.22.0" babel-plugin-check-es2015-constants@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" - integrity sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o= dependencies: babel-runtime "^6.22.0" babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - integrity sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU= babel-plugin-syntax-async-generators@^6.5.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" - integrity sha1-a8lj67FuzLrmuStZbrfzXDQqi5o= babel-plugin-syntax-class-properties@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" - integrity sha1-1+sjt5oxf4VDlixQW4J8fWysJ94= babel-plugin-syntax-decorators@^6.13.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" - integrity sha1-MSVjtNvePMgGzuPkFszurd0RrAs= babel-plugin-syntax-dynamic-import@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" - integrity sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo= babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - integrity sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4= babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" - integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U= babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - integrity sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM= babel-plugin-transform-async-generator-functions@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" - integrity sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds= dependencies: babel-helper-remap-async-to-generator "^6.24.1" babel-plugin-syntax-async-generators "^6.5.0" @@ -622,7 +524,6 @@ babel-plugin-transform-async-generator-functions@^6.24.1: babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" - integrity sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E= dependencies: babel-helper-remap-async-to-generator "^6.24.1" babel-plugin-syntax-async-functions "^6.8.0" @@ -631,7 +532,6 @@ babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async- babel-plugin-transform-class-properties@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" - integrity sha1-anl2PqYdM9NvN7YRqp3vgagbRqw= dependencies: babel-helper-function-name "^6.24.1" babel-plugin-syntax-class-properties "^6.8.0" @@ -641,7 +541,6 @@ babel-plugin-transform-class-properties@^6.24.1: babel-plugin-transform-decorators@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" - integrity sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0= dependencies: babel-helper-explode-class "^6.24.1" babel-plugin-syntax-decorators "^6.13.0" @@ -652,21 +551,18 @@ babel-plugin-transform-decorators@^6.24.1: babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" - integrity sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" - integrity sha1-u8UbSflk1wy42OC5ToICRs46YUE= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" - integrity sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8= dependencies: babel-runtime "^6.26.0" babel-template "^6.26.0" @@ -677,7 +573,6 @@ babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es20 babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-classes@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" - integrity sha1-WkxYpQyclGHlZLSyo7+ryXolhNs= dependencies: babel-helper-define-map "^6.24.1" babel-helper-function-name "^6.24.1" @@ -692,7 +587,6 @@ babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-cla babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" - integrity sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM= dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" @@ -700,14 +594,12 @@ babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transfor babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" - integrity sha1-mXux8auWf2gtKwh2/jWNYOdlxW0= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" - integrity sha1-c+s9MQypaePvnskcU3QabxV2Qj4= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -715,14 +607,12 @@ babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2 babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" - integrity sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" - integrity sha1-g0yJhTvDaxrw86TF26qU/Y6sqos= dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -731,14 +621,12 @@ babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es20 babel-plugin-transform-es2015-literals@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" - integrity sha1-T1SgLWzWbPkVKAAZox0xklN3yi4= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" - integrity sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ= dependencies: babel-plugin-transform-es2015-modules-commonjs "^6.24.1" babel-runtime "^6.22.0" @@ -747,7 +635,6 @@ babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015 babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: version "6.26.2" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" - integrity sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q== dependencies: babel-plugin-transform-strict-mode "^6.24.1" babel-runtime "^6.26.0" @@ -757,7 +644,6 @@ babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-e babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" - integrity sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM= dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -766,7 +652,6 @@ babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-e babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015-modules-umd@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" - integrity sha1-rJl+YoXNGO1hdq22B9YCNErThGg= dependencies: babel-plugin-transform-es2015-modules-amd "^6.24.1" babel-runtime "^6.22.0" @@ -775,7 +660,6 @@ babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015 babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" - integrity sha1-JM72muIcuDp/hgPa0CH1cusnj40= dependencies: babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" @@ -783,7 +667,6 @@ babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es201 babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-parameters@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" - integrity sha1-V6w1GrScrxSpfNE7CfZv3wpiXys= dependencies: babel-helper-call-delegate "^6.24.1" babel-helper-get-function-arity "^6.24.1" @@ -795,7 +678,6 @@ babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015- babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" - integrity sha1-JPh11nIch2YbvZmkYi5R8U3jiqA= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -803,14 +685,12 @@ babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transfo babel-plugin-transform-es2015-spread@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" - integrity sha1-1taKmfia7cRTbIGlQujdnxdG+NE= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" - integrity sha1-AMHNsaynERLN8M9hJsLta0V8zbw= dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -819,21 +699,18 @@ babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es201 babel-plugin-transform-es2015-template-literals@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" - integrity sha1-qEs0UPfp+PH2g51taH2oS7EjbY0= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" - integrity sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" - integrity sha1-04sS9C6nMj9yk4fxinxa4frrNek= dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -842,7 +719,6 @@ babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es20 babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" - integrity sha1-KrDJx/MJj6SJB3cruBP+QejeOg4= dependencies: babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" babel-plugin-syntax-exponentiation-operator "^6.8.0" @@ -851,7 +727,6 @@ babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-e babel-plugin-transform-object-rest-spread@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" - integrity sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY= dependencies: babel-plugin-syntax-object-rest-spread "^6.8.0" babel-runtime "^6.26.0" @@ -859,14 +734,12 @@ babel-plugin-transform-object-rest-spread@^6.22.0: babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" - integrity sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8= dependencies: regenerator-transform "^0.10.0" babel-plugin-transform-strict-mode@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" - integrity sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -874,7 +747,6 @@ babel-plugin-transform-strict-mode@^6.24.1: babel-polyfill@6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" - integrity sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM= dependencies: babel-runtime "^6.26.0" core-js "^2.5.0" @@ -883,7 +755,6 @@ babel-polyfill@6.26.0: babel-preset-env@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" - integrity sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg== dependencies: babel-plugin-check-es2015-constants "^6.22.0" babel-plugin-syntax-trailing-function-commas "^6.22.0" @@ -919,7 +790,6 @@ babel-preset-env@^1.7.0: babel-preset-es2015@6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" - integrity sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk= dependencies: babel-plugin-check-es2015-constants "^6.22.0" babel-plugin-transform-es2015-arrow-functions "^6.22.0" @@ -949,7 +819,6 @@ babel-preset-es2015@6.24.1: babel-preset-stage-2@6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" - integrity sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE= dependencies: babel-plugin-syntax-dynamic-import "^6.18.0" babel-plugin-transform-class-properties "^6.24.1" @@ -959,7 +828,6 @@ babel-preset-stage-2@6.24.1: babel-preset-stage-3@6.24.1, babel-preset-stage-3@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" - integrity sha1-g2raCp56f6N8sTj7kyb4eTSkg5U= dependencies: babel-plugin-syntax-trailing-function-commas "^6.22.0" babel-plugin-transform-async-generator-functions "^6.24.1" @@ -970,7 +838,6 @@ babel-preset-stage-3@6.24.1, babel-preset-stage-3@^6.24.1: babel-register@6.26.0, babel-register@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" - integrity sha1-btAhFz4vy0htestFxgCahW9kcHE= dependencies: babel-core "^6.26.0" babel-runtime "^6.26.0" @@ -983,7 +850,6 @@ babel-register@6.26.0, babel-register@^6.26.0: babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= dependencies: core-js "^2.4.0" regenerator-runtime "^0.11.0" @@ -991,7 +857,6 @@ babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: babel-template@^6.24.1, babel-template@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" - integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= dependencies: babel-runtime "^6.26.0" babel-traverse "^6.26.0" @@ -1002,7 +867,6 @@ babel-template@^6.24.1, babel-template@^6.26.0: babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= dependencies: babel-code-frame "^6.26.0" babel-messages "^6.23.0" @@ -1017,7 +881,6 @@ babel-traverse@^6.24.1, babel-traverse@^6.26.0: babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= dependencies: babel-runtime "^6.26.0" esutils "^2.0.2" @@ -1027,7 +890,6 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: babelify@^7.3.0: version "7.3.0" resolved "https://registry.yarnpkg.com/babelify/-/babelify-7.3.0.tgz#aa56aede7067fd7bd549666ee16dc285087e88e5" - integrity sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU= dependencies: babel-core "^6.0.14" object-assign "^4.0.0" @@ -1035,34 +897,28 @@ babelify@^7.3.0: babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= base-x@^3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.4.tgz#94c1788736da065edb1d68808869e357c977fa77" - integrity sha512-UYOadoSIkEI/VrRGSG6qp93rp2WdokiAiNYDfGW5qURAY8GiAQkvMbwNNSDYiVJopqv4gCna7xqf4rrNGp+5AA== dependencies: safe-buffer "^5.0.1" base64-js@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978" - integrity sha1-EQHpVE9KdrG8OybUUsqW16NeeXg= base64-js@^1.0.2: version "1.3.0" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" - integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== dependencies: cache-base "^1.0.1" class-utils "^0.3.5" @@ -1075,29 +931,24 @@ base@^0.11.1: bcrypt-pbkdf@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= dependencies: tweetnacl "^0.14.3" big.js@^3.1.3: version "3.2.0" resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" - integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== bignumber.js@^4.0.2: version "4.1.0" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-4.1.0.tgz#db6f14067c140bd46624815a7916c92d9b6c24b1" - integrity sha512-eJzYkFYy9L4JzXsbymsFn3p54D+llV27oTQ+ziJG7WFRheJcNZilgVXMG0LoZtlQSKBsJdWtLFqOD0u+U0jZKA== bignumber.js@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-5.0.0.tgz#fbce63f09776b3000a83185badcde525daf34833" - integrity sha512-KWTu6ZMVk9sxlDJQh2YH1UOnfDP8O8TpxUxgQG/vKASoSnEjK9aVuOueFaPcQEYQ5fyNXNTOYwYw3099RYebWg== bignumber.js@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-6.0.0.tgz#bbfa047644609a5af093e9cbd83b0461fa3f6002" - integrity sha512-x247jIuy60/+FtMRvscqfxtVHQf8AGx2hm9c6btkgC0x/hp9yt+teISNhvF8WlwRkCc5yF2fDECH8SIMe8j+GA== "bignumber.js@git+https://github.com/debris/bignumber.js#master": version "2.0.7" @@ -1114,24 +965,20 @@ bignumber.js@^6.0.0: binary-extensions@^1.0.0: version "1.12.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14" - integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg== bindings@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7" - integrity sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw== bip66@^1.1.3: version "1.1.5" resolved "https://registry.yarnpkg.com/bip66/-/bip66-1.1.5.tgz#01fa8748785ca70955d5011217d1b3139969ca22" - integrity sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI= dependencies: safe-buffer "^5.0.1" bitcore-lib@^0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/bitcore-lib/-/bitcore-lib-0.15.0.tgz#f924be13869f2aab7e04aeec5642ad3359b6cec2" - integrity sha512-AeXLWhiivF6CDFzrABZHT4jJrflyylDWTi32o30rF92HW9msfuKpjzrHtFKYGa9w0kNVv5HABQjCB3OEav4PhQ== dependencies: bn.js "=4.11.8" bs58 "=4.0.1" @@ -1143,7 +990,6 @@ bitcore-lib@^0.15.0: bitcore-mnemonic@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/bitcore-mnemonic/-/bitcore-mnemonic-1.5.0.tgz#c7e785beb6bf0616ed4992785dc3658670425a39" - integrity sha512-sbeP4xwkindLMfIQhVxj6rZSDMwtiKmfc1DqvwpR6Yg+Qo4I4WHO5pvzb12Y04uDh1N3zgD45esHhfH0HHmE4g== dependencies: bitcore-lib "^0.15.0" unorm "^1.3.3" @@ -1151,7 +997,6 @@ bitcore-mnemonic@^1.5.0: bl@^1.0.0: version "1.2.2" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" - integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== dependencies: readable-stream "^2.3.5" safe-buffer "^5.1.1" @@ -1159,39 +1004,32 @@ bl@^1.0.0: block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= dependencies: inherits "~2.0.0" bluebird@^2.9.34: version "2.11.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" - integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE= bluebird@^3.4.6, bluebird@^3.5.0: version "3.5.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.2.tgz#1be0908e054a751754549c270489c1505d4ab15a" - integrity sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg== bn.js@4.11.6: version "4.11.6" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" - integrity sha1-UzRK2xRhehP26N0s4okF0cC6MhU= bn.js@=4.11.8, bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.3, bn.js@^4.11.6, bn.js@^4.4.0, bn.js@^4.8.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== bn.js@^2.0.3: version "2.2.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-2.2.0.tgz#12162bc2ae71fc40a5626c33438f3a875cd37625" - integrity sha1-EhYrwq5x/EClYmwzQ486h1zTdiU= body-parser@1.18.3, body-parser@^1.16.0: version "1.18.3" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" - integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= dependencies: bytes "3.0.0" content-type "~1.0.4" @@ -1207,7 +1045,6 @@ body-parser@1.18.3, body-parser@^1.16.0: borc@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/borc/-/borc-2.0.3.tgz#08845ea73a6d3211120928ee3929f8dc2de9f52e" - integrity sha512-2mfipKUXn7yLgwn8D5jZkJqd2ZyzqmYZQX/9d4On33oGNDLwxj5qQMst+nkKyEdaujQRFfrZCId+k8wehQVANg== dependencies: bignumber.js "^6.0.0" commander "^2.15.0" @@ -1217,7 +1054,6 @@ borc@^2.0.2: brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -1225,7 +1061,6 @@ brace-expansion@^1.1.7: braces@^1.8.2: version "1.8.5" resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= dependencies: expand-range "^1.8.1" preserve "^0.2.0" @@ -1234,7 +1069,6 @@ braces@^1.8.2: braces@^2.3.0, braces@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: arr-flatten "^1.1.0" array-unique "^0.3.2" @@ -1250,22 +1084,18 @@ braces@^2.3.0, braces@^2.3.1: brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= browser-stdout@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" - integrity sha1-81HTKWnTL6XXpVZxVCY9korjvR8= browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.0.6: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== dependencies: buffer-xor "^1.0.3" cipher-base "^1.0.0" @@ -1277,7 +1107,6 @@ browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.0.6: browserify-cipher@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== dependencies: browserify-aes "^1.0.4" browserify-des "^1.0.0" @@ -1286,7 +1115,6 @@ browserify-cipher@^1.0.0: browserify-des@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== dependencies: cipher-base "^1.0.1" des.js "^1.0.0" @@ -1296,7 +1124,6 @@ browserify-des@^1.0.0: browserify-rsa@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" - integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= dependencies: bn.js "^4.1.0" randombytes "^2.0.1" @@ -1304,14 +1131,12 @@ browserify-rsa@^4.0.0: browserify-sha3@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/browserify-sha3/-/browserify-sha3-0.0.1.tgz#3ff34a3006ef15c0fb3567e541b91a2340123d11" - integrity sha1-P/NKMAbvFcD7NWflQbkaI0ASPRE= dependencies: js-sha3 "^0.3.1" browserify-sign@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" - integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= dependencies: bn.js "^4.1.1" browserify-rsa "^4.0.0" @@ -1324,14 +1149,12 @@ browserify-sign@^4.0.0: browserify-zlib@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== dependencies: pako "~1.0.5" browserslist@^3.2.6: version "3.2.8" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" - integrity sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ== dependencies: caniuse-lite "^1.0.30000844" electron-to-chromium "^1.3.47" @@ -1339,19 +1162,16 @@ browserslist@^3.2.6: bs58@=4.0.1, bs58@^4.0.0, bs58@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" - integrity sha1-vhYedsNU9veIrkBx9j806MTwpCo= dependencies: base-x "^3.0.2" bs58@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-2.0.1.tgz#55908d58f1982aba2008fa1bed8f91998a29bf8d" - integrity sha1-VZCNWPGYKrogCPob7Y+RmYopv40= bs58check@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" - integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== dependencies: bs58 "^4.0.0" create-hash "^1.1.0" @@ -1360,17 +1180,14 @@ bs58check@^2.1.2: bson@^1.0.4: version "1.1.0" resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.0.tgz#bee57d1fb6a87713471af4e32bcae36de814b5b0" - integrity sha512-9Aeai9TacfNtWXOYarkFJRW2CWo+dRon+fuLZYJmvLV3+MiUp0bEI6IAZfXEIg7/Pl/7IWlLaDnhzTsD81etQA== buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== buffer-alloc@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== dependencies: buffer-alloc-unsafe "^1.1.0" buffer-fill "^1.0.0" @@ -1378,37 +1195,30 @@ buffer-alloc@^1.2.0: buffer-compare@=1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-compare/-/buffer-compare-1.1.1.tgz#5be7be853af89198d1f4ddc090d1d66a48aef596" - integrity sha1-W+e+hTr4kZjR9N3AkNHWakiu9ZY= buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= buffer-fill@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== buffer-to-arraybuffer@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" - integrity sha1-YGSkD6dutDxyOrqe+PbhIW0QURo= buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= buffer@^3.0.1: version "3.6.0" resolved "https://registry.yarnpkg.com/buffer/-/buffer-3.6.0.tgz#a72c936f77b96bf52f5f7e7b467180628551defb" - integrity sha1-pyyTb3e5a/UvX357RnGAYoVR3vs= dependencies: base64-js "0.0.8" ieee754 "^1.1.4" @@ -1417,7 +1227,6 @@ buffer@^3.0.1: buffer@^4.3.0, buffer@^4.9.0: version "4.9.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" - integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -1426,7 +1235,6 @@ buffer@^4.3.0, buffer@^4.9.0: buffer@^5.0.5: version "5.2.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.1.tgz#dd57fa0f109ac59c602479044dca7b8b3d0b71d6" - integrity sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg== dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -1434,22 +1242,18 @@ buffer@^5.0.5: builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== dependencies: collection-visit "^1.0.0" component-emitter "^1.2.1" @@ -1464,34 +1268,28 @@ cache-base@^1.0.1: caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8= dependencies: callsites "^0.2.0" callsites@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= camelcase@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" - integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk= camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" - integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= caminte@0.3.7: version "0.3.7" resolved "https://registry.yarnpkg.com/caminte/-/caminte-0.3.7.tgz#ec1ec0457664a0f092643b7c646c457d5cd6f693" - integrity sha1-7B7ARXZkoPCSZDt8ZGxFfVzW9pM= dependencies: bluebird "^3.4.6" uuid "^3.0.1" @@ -1499,17 +1297,14 @@ caminte@0.3.7: caniuse-lite@^1.0.30000844: version "1.0.30000890" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000890.tgz#86a18ffcc65d79ec6a437e985761b8bf1c4efeaf" - integrity sha512-4NI3s4Y6ROm+SgZN5sLUG4k7nVWQnedis3c/RWkynV5G6cHSY7+a8fwFyn2yoBDE3E6VswhTNNwR3PvzGqlTkg== caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= center-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60= dependencies: align-text "^0.1.3" lazy-cache "^1.0.3" @@ -1517,7 +1312,6 @@ center-align@^0.1.1: chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -1528,7 +1322,6 @@ chalk@^1.1.3: chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.1, chalk@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" - integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" @@ -1537,19 +1330,16 @@ chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.1, chalk@^2.4.1: chardet@^0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" - integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= checkpoint-store@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/checkpoint-store/-/checkpoint-store-1.1.0.tgz#04e4cb516b91433893581e6d4601a78e9552ea06" - integrity sha1-BOTLUWuRQziTWB5tRgGnjpVS6gY= dependencies: functional-red-black-tree "^1.0.1" chokidar@^1.6.0: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" - integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg= dependencies: anymatch "^1.3.0" async-each "^1.0.0" @@ -1565,7 +1355,6 @@ chokidar@^1.6.0: chokidar@^2.0.2: version "2.0.4" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" - integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ== dependencies: anymatch "^2.0.0" async-each "^1.0.0" @@ -1585,12 +1374,10 @@ chokidar@^2.0.2: chownr@^1.0.1: version "1.1.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" - integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== dependencies: inherits "^2.0.1" safe-buffer "^5.0.1" @@ -1598,12 +1385,10 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" - integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== dependencies: arr-union "^3.1.0" define-property "^0.2.5" @@ -1613,7 +1398,6 @@ class-utils@^0.3.5: cli-color@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-1.3.0.tgz#cd2ec212efbd1a0eeb5b017f17d4e2d15e91420f" - integrity sha512-XmbLr8MzgOup/sPHF4nOZerCOcL7rD7vKWpEl0axUsMAY+AEimOhYva1ksskWqkLGY/bjR9h7Cfbr+RrJRfmTQ== dependencies: ansi-regex "^2.1.1" d "1" @@ -1625,19 +1409,16 @@ cli-color@^1.2.0: cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= dependencies: restore-cursor "^2.0.0" cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= cliui@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE= dependencies: center-align "^0.1.1" right-align "^0.1.1" @@ -1646,7 +1427,6 @@ cliui@^2.1.0: cliui@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -1655,7 +1435,6 @@ cliui@^3.2.0: cliui@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== dependencies: string-width "^2.1.1" strip-ansi "^4.0.0" @@ -1664,22 +1443,18 @@ cliui@^4.0.0: clone@2.x, clone@^2.0.0: version "2.1.2" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= coinstring@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/coinstring/-/coinstring-2.3.0.tgz#cdb63363a961502404a25afb82c2e26d5ff627a4" - integrity sha1-zbYzY6lhUCQEolr7gsLibV/2J6Q= dependencies: bs58 "^2.0.1" create-hash "^1.1.1" @@ -1687,7 +1462,6 @@ coinstring@^2.0.0: collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= dependencies: map-visit "^1.0.0" object-visit "^1.0.0" @@ -1695,85 +1469,70 @@ collection-visit@^1.0.0: color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= colors@1.0.x: version "1.0.3" resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= colors@^1.1.2: version "1.3.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.2.tgz#2df8ff573dfbf255af562f8ce7181d6b971a359b" - integrity sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ== combined-stream@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" - integrity sha1-cj599ugBrFYTETp+RFqbactjKBg= dependencies: delayed-stream "~1.0.0" combined-stream@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" - integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== dependencies: delayed-stream "~1.0.0" commander@2.11.0: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" - integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== commander@2.15.1: version "2.15.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" - integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== commander@^2.11.0, commander@^2.14.1, commander@^2.15.0, commander@^2.8.1, commander@^2.9.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" - integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== commander@~2.17.1: version "2.17.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" - integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== commander@~2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" - integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ= dependencies: graceful-readlink ">= 1.0.0" compare-versions@^3.0.1: version "3.4.0" resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.4.0.tgz#e0747df5c9cb7f054d6d3dc3e1dbc444f9e92b26" - integrity sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg== component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" - integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= concat-stream@^1.6.0: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== dependencies: buffer-from "^1.0.0" inherits "^2.0.3" @@ -1783,76 +1542,62 @@ concat-stream@^1.6.0: console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" - integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= dependencies: date-now "^0.1.4" console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" - integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== convert-source-map@^1.5.1: version "1.6.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" - integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== dependencies: safe-buffer "~5.1.1" cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" - integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= cookiejar@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" - integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= core-js@^2.4.0, core-js@^2.5.0: version "2.5.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" - integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= cors@^2.8.1: version "2.8.4" resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.4.tgz#2bd381f2eb201020105cd50ea59da63090694686" - integrity sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY= dependencies: object-assign "^4" vary "^1" @@ -1860,7 +1605,6 @@ cors@^2.8.1: coveralls@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.0.2.tgz#f5a0bcd90ca4e64e088b710fa8dda640aea4884f" - integrity sha512-Tv0LKe/MkBOilH2v7WBiTBdudg2ChfGbdXafc/s330djpF3zKOmuehTeRwjXWc7pzfj9FrDUTA7tEx6Div8NFw== dependencies: growl "~> 1.10.0" js-yaml "^3.11.0" @@ -1872,7 +1616,6 @@ coveralls@^3.0.1: create-ecdh@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" - integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== dependencies: bn.js "^4.1.0" elliptic "^6.0.0" @@ -1880,7 +1623,6 @@ create-ecdh@^4.0.0: create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== dependencies: cipher-base "^1.0.1" inherits "^2.0.1" @@ -1891,7 +1633,6 @@ create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2: create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: version "1.1.7" resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== dependencies: cipher-base "^1.0.3" create-hash "^1.1.0" @@ -1903,7 +1644,6 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: cron-parser@^2.4.0: version "2.6.0" resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.6.0.tgz#ae2514ceda9ccb540256e201bdd23ae814e03674" - integrity sha512-KGfDDTjBIx85MnVYcdhLccoJH/7jcYW+5Z/t3Wsg2QlJhmmjf+97z+9sQftS71lopOYYapjEKEvmWaCsym5Z4g== dependencies: is-nan "^1.2.1" moment-timezone "^0.5.0" @@ -1911,7 +1651,6 @@ cron-parser@^2.4.0: cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= dependencies: lru-cache "^4.0.1" shebang-command "^1.2.0" @@ -1920,7 +1659,6 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0: crypto-browserify@3.12.0, crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== dependencies: browserify-cipher "^1.0.0" browserify-sign "^4.0.0" @@ -1937,115 +1675,84 @@ crypto-browserify@3.12.0, crypto-browserify@^3.11.0: crypto-js@^3.1.4, crypto-js@^3.1.5: version "3.1.8" resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.1.8.tgz#715f070bf6014f2ae992a98b3929258b713f08d5" - integrity sha1-cV8HC/YBTyrpkqmLOSkli3E/CNU= crypto-js@^3.1.9-1: version "3.1.9-1" resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.1.9-1.tgz#fda19e761fc077e01ffbfdc6e9fdfc59e8806cd8" - integrity sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg= crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" - integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= csextends@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/csextends/-/csextends-1.2.0.tgz#6374b210984b54d4495f29c99d3dd069b80543e5" - integrity sha512-S/8k1bDTJIwuGgQYmsRoE+8P+ohV32WhQ0l4zqrc0XDdxOhjQQD7/wTZwCzoZX53jSX3V/qwjT+OkPTxWQcmjg== cycle@1.0.x: version "1.0.3" resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" - integrity sha1-IegLK+hYD5i0aPN5QwZisEbDStI= d@1: version "1.0.0" resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" - integrity sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8= dependencies: es5-ext "^0.10.9" dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= dependencies: assert-plus "^1.0.0" -date-extended@~0.0.3: - version "0.0.6" - resolved "https://registry.yarnpkg.com/date-extended/-/date-extended-0.0.6.tgz#23802d57dd1bf7818813fe0c32e851a86da267c9" - integrity sha1-I4AtV90b94GIE/4MMuhRqG2iZ8k= - dependencies: - array-extended "~0.0.3" - extended "~0.0.3" - is-extended "~0.0.3" - date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" - integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= death@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/death/-/death-1.1.0.tgz#01aa9c401edd92750514470b8266390c66c67318" - integrity sha1-AaqcQB7dknUFFEcLgmY5DGbGcxg= debug@*: version "4.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" - integrity sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg== dependencies: ms "^2.1.1" debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" debug@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== dependencies: ms "2.0.0" debug@^3.0.1, debug@^3.1.0: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== dependencies: ms "^2.1.1" decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -declare.js@~0.0.4: - version "0.0.8" - resolved "https://registry.yarnpkg.com/declare.js/-/declare.js-0.0.8.tgz#0478adff9564c004f51df73d8bc134019d28dcde" - integrity sha1-BHit/5VkwAT1Hfc9i8E0AZ0o3N4= decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= decompress-response@^3.2.0, decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= dependencies: mimic-response "^1.0.0" decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" - integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== dependencies: file-type "^5.2.0" is-stream "^1.1.0" @@ -2054,7 +1761,6 @@ decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: decompress-tarbz2@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" - integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== dependencies: decompress-tar "^4.1.0" file-type "^6.1.0" @@ -2065,7 +1771,6 @@ decompress-tarbz2@^4.0.0: decompress-targz@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" - integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== dependencies: decompress-tar "^4.1.1" file-type "^5.2.0" @@ -2074,7 +1779,6 @@ decompress-targz@^4.0.0: decompress-unzip@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" - integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= dependencies: file-type "^3.8.0" get-stream "^2.2.0" @@ -2084,7 +1788,6 @@ decompress-unzip@^4.0.1: decompress@^4.0.0: version "4.2.0" resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.0.tgz#7aedd85427e5a92dacfe55674a7c505e96d01f9d" - integrity sha1-eu3YVCflqS2s/lVnSnxQXpbQH50= dependencies: decompress-tar "^4.0.0" decompress-tarbz2 "^4.0.0" @@ -2098,57 +1801,52 @@ decompress@^4.0.0: deep-assign@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-2.0.0.tgz#ebe06b1f07f08dae597620e3dd1622f371a1c572" - integrity sha1-6+BrHwfwja5ZdiDj3RYi83GhxXI= dependencies: is-obj "^1.0.0" +deep-equal@~0.2.1: + version "0.2.2" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-0.2.2.tgz#84b745896f34c684e98f2ce0e42abaf43bba017d" + deep-equal@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" - integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= deferred-leveldown@~1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz#3acd2e0b75d1669924bc0a4b642851131173e1eb" - integrity sha512-uukrWD2bguRtXilKt6cAWKyoXrTSMo5m7crUdLfWQmu8kIm88w3QZoUL+6nhpfKVmhHANER6Re3sKoNoZ3IKMA== dependencies: abstract-leveldown "~2.6.0" define-properties@^1.1.1, define-properties@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== dependencies: object-keys "^1.0.12" define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= dependencies: is-descriptor "^1.0.0" define-property@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== dependencies: is-descriptor "^1.0.2" isobject "^3.0.1" @@ -2156,12 +1854,10 @@ define-property@^2.0.2: defined@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= del@^2.0.2: version "2.2.2" resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" - integrity sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag= dependencies: globby "^5.0.0" is-path-cwd "^1.0.0" @@ -2174,27 +1870,22 @@ del@^2.0.2: delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= delimit-stream@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/delimit-stream/-/delimit-stream-0.1.0.tgz#9b8319477c0e5f8aeb3ce357ae305fc25ea1cd2b" - integrity sha1-m4MZR3wOX4rrPONXrjBfwl6hzSs= depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= des.js@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" - integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= dependencies: inherits "^2.0.1" minimalistic-assert "^1.0.0" @@ -2202,34 +1893,28 @@ des.js@^1.0.0: destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= dependencies: repeating "^2.0.0" detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= diff@3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" - integrity sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww== diff@3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== dependencies: bn.js "^4.1.0" miller-rabin "^4.0.0" @@ -2238,7 +1923,6 @@ diffie-hellman@^5.0.0: doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= dependencies: esutils "^2.0.2" isarray "^1.0.0" @@ -2246,24 +1930,20 @@ doctrine@1.5.0: doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== dependencies: esutils "^2.0.2" dom-walk@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" - integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg= domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== drbg.js@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/drbg.js/-/drbg.js-1.0.1.tgz#3e36b6c42b37043823cdbc332d58f31e2445480b" - integrity sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs= dependencies: browserify-aes "^1.0.6" create-hash "^1.1.2" @@ -2272,19 +1952,16 @@ drbg.js@^1.0.1: duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= eachr@^2.0.2: version "2.0.4" resolved "https://registry.yarnpkg.com/eachr/-/eachr-2.0.4.tgz#466f7caa10708f610509e32c807aafe57fc122bf" - integrity sha1-Rm98qhBwj2EFCeMsgHqv5X/BIr8= dependencies: typechecker "^2.0.8" ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= dependencies: jsbn "~0.1.0" safer-buffer "^2.1.0" @@ -2292,12 +1969,10 @@ ecc-jsbn@~0.1.1: editions@^1.1.1, editions@^1.3.3, editions@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" - integrity sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg== editions@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/editions/-/editions-2.0.2.tgz#54fdac6fb24b0a1a72ffc1ba0126c10602c3e0bd" - integrity sha512-0B8aSTWUu9+JW99zHoeogavCi+lkE5l35FK0OKe0pCobixJYoeof3ZujtqYzSsU2MskhRadY5V9oWUuyG4aJ3A== dependencies: errlop "^1.0.2" semver "^5.5.0" @@ -2305,17 +1980,14 @@ editions@^2.0.2: ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.47: version "1.3.78" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.78.tgz#ecb72b5b166ba6598efb384461d63cad74678ebf" - integrity sha512-p4D/5iX08c3LNep5bWn/X3dFmec1K9le6O43lgRsO/vYKBTH2smWDMDfkGlPtERFcLVkI8xdKW5EokBZODh1xg== elliptic@6.3.3: version "6.3.3" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.3.tgz#5482d9646d54bcb89fd7d994fc9e2e9568876e3f" - integrity sha1-VILZZG1UvLif19mU/J4ulWiHbj8= dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -2325,7 +1997,6 @@ elliptic@6.3.3: elliptic@=6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" - integrity sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8= dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -2338,7 +2009,6 @@ elliptic@=6.4.0: elliptic@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-3.1.0.tgz#c21682ef762769b56a74201609105da11d5f60cc" - integrity sha1-whaC73YnabVqdCAWCRBdoR1fYMw= dependencies: bn.js "^2.0.3" brorand "^1.0.1" @@ -2348,7 +2018,6 @@ elliptic@^3.1.0: elliptic@^6.0.0, elliptic@^6.2.3, elliptic@^6.4.0: version "6.4.1" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" - integrity sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ== dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -2361,31 +2030,26 @@ elliptic@^6.0.0, elliptic@^6.2.3, elliptic@^6.4.0: emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= encoding@^0.1.11: version "0.1.12" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" - integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= dependencies: iconv-lite "~0.4.13" end-of-stream@^1.0.0: version "1.4.1" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" - integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== dependencies: once "^1.4.0" enhanced-resolve@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" - integrity sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24= dependencies: graceful-fs "^4.1.2" memory-fs "^0.4.0" @@ -2395,33 +2059,28 @@ enhanced-resolve@^3.4.0: eol@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/eol/-/eol-0.9.1.tgz#f701912f504074be35c6117a5c4ade49cd547acd" - integrity sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg== errlop@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/errlop/-/errlop-1.0.3.tgz#dba29c90cf832c3d2ce469fe515d7e5eef2c6676" - integrity sha512-5VTnt0yikY4LlQEfCXVSqfE6oLj1HVM4zVSvAKMnoYjL/zrb6nqiLowZS4XlG7xENfyj7lpYWvT+wfSCr6dtlA== dependencies: editions "^1.3.4" errno@^0.1.3, errno@~0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" - integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== dependencies: prr "~1.0.1" error-ex@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" es-abstract@^1.5.0: version "1.12.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" - integrity sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA== dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.1" @@ -2432,7 +2091,6 @@ es-abstract@^1.5.0: es-to-primitive@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" - integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== dependencies: is-callable "^1.1.4" is-date-object "^1.0.1" @@ -2441,7 +2099,6 @@ es-to-primitive@^1.1.1: es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.46, es5-ext@^0.10.9, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: version "0.10.46" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.46.tgz#efd99f67c5a7ec789baa3daa7f79870388f7f572" - integrity sha512-24XxRvJXNFwEMpJb3nOkiRJKRoupmjYmOPVlI65Qy2SrtxwOTB+g6ODjBKOtwEHbYrhWRty9xxOWLNdClT2djw== dependencies: es6-iterator "~2.0.3" es6-symbol "~3.1.1" @@ -2450,7 +2107,6 @@ es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.46, es5-ext@ es6-iterator@^2.0.1, es6-iterator@^2.0.3, es6-iterator@~2.0.1, es6-iterator@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= dependencies: d "1" es5-ext "^0.10.35" @@ -2459,7 +2115,6 @@ es6-iterator@^2.0.1, es6-iterator@^2.0.3, es6-iterator@~2.0.1, es6-iterator@~2.0 es6-map@^0.1.3: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - integrity sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA= dependencies: d "1" es5-ext "~0.10.14" @@ -2471,7 +2126,6 @@ es6-map@^0.1.3: es6-set@~0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - integrity sha1-0rPsXU2ADO2BjbU40ol02wpzzLE= dependencies: d "1" es5-ext "~0.10.14" @@ -2482,7 +2136,6 @@ es6-set@~0.1.5: es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" - integrity sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc= dependencies: d "1" es5-ext "~0.10.14" @@ -2490,7 +2143,6 @@ es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: es6-weak-map@^2.0.1, es6-weak-map@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" - integrity sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8= dependencies: d "1" es5-ext "^0.10.14" @@ -2500,17 +2152,14 @@ es6-weak-map@^2.0.1, es6-weak-map@^2.0.2: escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= escodegen@1.8.x: version "1.8.1" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" - integrity sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg= dependencies: esprima "^2.7.1" estraverse "^1.9.1" @@ -2522,7 +2171,6 @@ escodegen@1.8.x: escope@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" - integrity sha1-4Bl16BJ4GhY6ba392AOY3GTIicM= dependencies: es6-map "^0.1.3" es6-weak-map "^2.0.1" @@ -2532,12 +2180,10 @@ escope@^3.6.0: eslint-config-standard@^11.0.0: version "11.0.0" resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-11.0.0.tgz#87ee0d3c9d95382dc761958cbb23da9eea31e0ba" - integrity sha512-oDdENzpViEe5fwuRCWla7AXQd++/oyIp8zP+iP9jiUPG6NBj3SHgdgtl/kTn00AjeN+1HNvavTKmYbMo+xMOlw== eslint-import-resolver-node@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" - integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q== dependencies: debug "^2.6.9" resolve "^1.5.0" @@ -2545,7 +2191,6 @@ eslint-import-resolver-node@^0.3.1: eslint-module-utils@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz#b270362cd88b1a48ad308976ce7fa54e98411746" - integrity sha1-snA2LNiLGkitMIl2zn+lTphBF0Y= dependencies: debug "^2.6.8" pkg-dir "^1.0.0" @@ -2553,7 +2198,6 @@ eslint-module-utils@^2.2.0: eslint-plugin-import@^2.10.0: version "2.14.0" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz#6b17626d2e3e6ad52cfce8807a845d15e22111a8" - integrity sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g== dependencies: contains-path "^0.1.0" debug "^2.6.8" @@ -2569,7 +2213,6 @@ eslint-plugin-import@^2.10.0: eslint-plugin-node@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz#bf19642298064379315d7a4b2a75937376fa05e4" - integrity sha512-Q/Cc2sW1OAISDS+Ji6lZS2KV4b7ueA/WydVWd1BECTQwVvfQy5JAi3glhINoKzoMnfnuRgNP+ZWKrGAbp3QDxw== dependencies: ignore "^3.3.6" minimatch "^3.0.4" @@ -2579,17 +2222,14 @@ eslint-plugin-node@^6.0.1: eslint-plugin-promise@^3.7.0: version "3.8.0" resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.8.0.tgz#65ebf27a845e3c1e9d6f6a5622ddd3801694b621" - integrity sha512-JiFL9UFR15NKpHyGii1ZcvmtIqa3UTwiDAGb8atSffe43qJ3+1czVGN6UtkklpcJ2DVnqvTMzEKRaJdBkAL2aQ== eslint-plugin-standard@^3.0.1: version "3.1.0" resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.1.0.tgz#2a9e21259ba4c47c02d53b2d0c9135d4b1022d47" - integrity sha512-fVcdyuKRr0EZ4fjWl3c+gp1BANFJD1+RaWa2UPYfMZ6jCtp5RG00kSaXnK/dE5sYzt4kaWJ9qdxqUfc0d9kX0w== eslint-scope@^3.7.1: version "3.7.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" - integrity sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA== dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" @@ -2597,12 +2237,10 @@ eslint-scope@^3.7.1: eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" - integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== eslint@^4.19.1: version "4.19.1" resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" - integrity sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ== dependencies: ajv "^5.3.0" babel-code-frame "^6.22.0" @@ -2646,7 +2284,6 @@ eslint@^4.19.1: espree@^3.5.4: version "3.5.4" resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" - integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A== dependencies: acorn "^5.5.0" acorn-jsx "^3.0.0" @@ -2654,51 +2291,42 @@ espree@^3.5.4: esprima@2.7.x, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" - integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esquery@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" - integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== dependencies: estraverse "^4.0.0" esrecurse@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== dependencies: estraverse "^4.1.0" estraverse@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" - integrity sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q= estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= eth-block-tracker@^2.2.2: version "2.3.1" resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-2.3.1.tgz#ab6d177e5b50128fa06d7ae9e0489c7484bac95e" - integrity sha512-NamWuMBIl8kmkJFVj8WzGatySTzQPQag4Xr677yFxdVtIxACFbL/dQowk0MzEqIKk93U1TwY3MjVU6mOcwZnKA== dependencies: async-eventemitter ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c eth-query "^2.1.0" @@ -2712,7 +2340,6 @@ eth-block-tracker@^2.2.2: eth-lib@0.1.27, eth-lib@^0.1.26: version "0.1.27" resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.27.tgz#f0b0fd144f865d2d6bf8257a40004f2e75ca1dd6" - integrity sha512-B8czsfkJYzn2UIEMwjc7Mbj+Cy72V+/OXH/tb44LV8jhrjizQJJ325xMOMyk3+ETa6r6oi0jsUY14+om8mQMWA== dependencies: bn.js "^4.11.6" elliptic "^6.4.0" @@ -2725,7 +2352,6 @@ eth-lib@0.1.27, eth-lib@^0.1.26: eth-lib@0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.7.tgz#2f93f17b1e23aec3759cd4a3fe20c1286a3fc1ca" - integrity sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco= dependencies: bn.js "^4.11.6" elliptic "^6.4.0" @@ -2734,7 +2360,6 @@ eth-lib@0.2.7: eth-lightwallet@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/eth-lightwallet/-/eth-lightwallet-3.0.1.tgz#297022932aa568f4e4eb0873bff257f5e5b78709" - integrity sha512-79vVCETy+4l1b6wuOWwjqPW3Bom5ZK46BgkUNwaXhiMG1rrMRHjpjYEWMqH0JHeCzOzB4HBIFz7eK1/4s6w5nA== dependencies: bitcore-lib "^0.15.0" bitcore-mnemonic "^1.5.0" @@ -2751,7 +2376,6 @@ eth-lightwallet@^3.0.1: eth-query@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e" - integrity sha1-1nQdkAAQa1FRDHLbktY2VFam2l4= dependencies: json-rpc-random-id "^1.0.0" xtend "^4.0.1" @@ -2759,7 +2383,6 @@ eth-query@^2.1.0: eth-sig-util@^1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-1.4.2.tgz#8d958202c7edbaae839707fba6f09ff327606210" - integrity sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA= dependencies: ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" ethereumjs-util "^5.1.1" @@ -2767,7 +2390,6 @@ eth-sig-util@^1.4.2: ethereum-bridge@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/ethereum-bridge/-/ethereum-bridge-0.6.1.tgz#53c93ed7c0e21752a91e5f089a5997e1d6fea228" - integrity sha512-yDTivI85618BoLI71yNRzW6iVcVN2rjnviCIzs0QOCOENj4XpYQhMDGhdqDi8XWDdzTd0Ja/Canuuh3vfE2IcA== dependencies: async "^2.4.1" borc "^2.0.2" @@ -2798,17 +2420,14 @@ ethereum-bridge@^0.6.1: ethereum-common@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.2.0.tgz#13bf966131cce1eeade62a1b434249bb4cb120ca" - integrity sha512-XOnAR/3rntJgbCdGhqdaLIxDLWKLmsZOGhHdBKadEr6gEnJLH52k93Ou+TUdFaPN3hJc3isBZBal3U/XZ15abA== ethereum-common@^0.0.18: version "0.0.18" resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" - integrity sha1-L9w1dvIykDNYl26znaeDIT/5Uj8= ethereumjs-abi@0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.4.tgz#9ba1bb056492d00c27279f6eccd4d58275912c1a" - integrity sha1-m6G7BWSS0AwnJ59uzNTVgnWRLBo= dependencies: bn.js "^4.10.0" ethereumjs-util "^4.3.0" @@ -2823,7 +2442,6 @@ ethereumjs-abi@^0.6.5, "ethereumjs-abi@git+https://github.com/ethereumjs/ethereu ethereumjs-account@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/ethereumjs-account/-/ethereumjs-account-2.0.5.tgz#eeafc62de544cb07b0ee44b10f572c9c49e00a84" - integrity sha512-bgDojnXGjhMwo6eXQC0bY6UK2liSFUSMwwylOmQvZbSl/D7NXQ3+vrGO46ZeOgjGfxXmgIeVNDIiHw7fNZM4VA== dependencies: ethereumjs-util "^5.0.0" rlp "^2.0.0" @@ -2832,7 +2450,6 @@ ethereumjs-account@^2.0.3: ethereumjs-block@^1.2.2, ethereumjs-block@~1.7.0: version "1.7.1" resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz#78b88e6cc56de29a6b4884ee75379b6860333c3f" - integrity sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg== dependencies: async "^2.0.1" ethereum-common "0.2.0" @@ -2843,26 +2460,22 @@ ethereumjs-block@^1.2.2, ethereumjs-block@~1.7.0: ethereumjs-common@~0.4.0: version "0.4.1" resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-0.4.1.tgz#27690a24a817b058cc3a2aedef9392e8d7d63984" - integrity sha512-ywYGsOeGCsMNWso5Y4GhjWI24FJv9FK7+VyVKiQgXg8ZRDPXJ7F/kJ1CnjtkjTvDF4e0yqU+FWswlqR3bmZQ9Q== ethereumjs-testrpc-sc@6.1.6: version "6.1.6" resolved "https://registry.yarnpkg.com/ethereumjs-testrpc-sc/-/ethereumjs-testrpc-sc-6.1.6.tgz#290595380b5182814564d4aa38f35b7788aab070" - integrity sha512-iv2qiGBFgk9mn5Nq2enX8dG5WQ7Lk+FCqpnxfPfH4Ns8KLPwttmNOy264nh3SXDJJvcQwz/XnlLteDQVILotbg== dependencies: source-map-support "^0.5.3" ethereumjs-testrpc@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/ethereumjs-testrpc/-/ethereumjs-testrpc-6.0.3.tgz#7a0b87bf3670f92f607f98fa6a78801d9741b124" - integrity sha512-lAxxsxDKK69Wuwqym2K49VpXtBvLEsXr1sryNG4AkvL5DomMdeCBbu3D87UEevKenLHBiT8GTjARwN6Yj039gA== dependencies: webpack "^3.0.0" ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.1, ethereumjs-tx@^1.3.3: version "1.3.7" resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz#88323a2d875b10549b8347e09f4862b546f3d89a" - integrity sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA== dependencies: ethereum-common "^0.0.18" ethereumjs-util "^5.0.0" @@ -2870,7 +2483,6 @@ ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.1, ethereumjs-tx@ ethereumjs-util@^4.3.0: version "4.5.0" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz#3e9428b317eebda3d7260d854fddda954b1f1bc6" - integrity sha1-PpQosxfuvaPXJg2FT93alUsfG8Y= dependencies: bn.js "^4.8.0" create-hash "^1.1.2" @@ -2881,7 +2493,6 @@ ethereumjs-util@^4.3.0: ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.3, ethereumjs-util@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz#3e0c0d1741471acf1036052d048623dee54ad642" - integrity sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA== dependencies: bn.js "^4.11.0" create-hash "^1.1.2" @@ -2894,7 +2505,6 @@ ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereum ethereumjs-vm@^2.0.2: version "2.4.0" resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-2.4.0.tgz#244f1e35f2755e537a13546111d1a4c159d34b13" - integrity sha512-MJ4lCWa5c6LhahhhvoDKW+YGjK00ZQn0RHHLh4L+WaH1k6Qv7/q3uTluew6sJGNCZdlO0yYMDXYW9qyxLHKlgQ== dependencies: async "^2.1.2" async-eventemitter "^0.2.2" @@ -2911,7 +2521,6 @@ ethereumjs-vm@^2.0.2: ethereumjs-wallet@^0.6.0: version "0.6.2" resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-0.6.2.tgz#67244b6af3e8113b53d709124b25477b64aeccda" - integrity sha512-DHEKPV9lYORM7dL8602dkb+AgdfzCYz2lxpdYQoD3OwG355LLDuivW9rGuLpDMCry/ORyBYV6n+QCo/71SwACg== dependencies: aes-js "^3.1.1" bs58check "^2.1.2" @@ -2925,7 +2534,6 @@ ethereumjs-wallet@^0.6.0: ethers@^3.0.15: version "3.0.29" resolved "https://registry.yarnpkg.com/ethers/-/ethers-3.0.29.tgz#ce8139955b4ed44456eb6764b089bb117c86775d" - integrity sha512-OGyA5pW5xFC5o/ZV5MfIoVp/EdA1QMg2bMJFf7Kznsz8m7IzzbgsPHTCjzSfKQDs/XDphGyRcA7A6bkIeJL4gw== dependencies: aes-js "3.0.0" bn.js "^4.4.0" @@ -2941,7 +2549,6 @@ ethers@^3.0.15: ethjs-abi@0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/ethjs-abi/-/ethjs-abi-0.1.8.tgz#cd288583ed628cdfadaf8adefa3ba1dbcbca6c18" - integrity sha1-zSiFg+1ijN+tr4re+juh28vKbBg= dependencies: bn.js "4.11.6" js-sha3 "0.5.5" @@ -2950,7 +2557,6 @@ ethjs-abi@0.1.8: ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" - integrity sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk= dependencies: bn.js "4.11.6" number-to-bn "1.7.0" @@ -2958,7 +2564,6 @@ ethjs-unit@0.1.6: ethjs-util@^0.1.3: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" - integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== dependencies: is-hex-prefixed "1.0.0" strip-hex-prefix "1.0.0" @@ -2966,7 +2571,6 @@ ethjs-util@^0.1.3: event-emitter@^0.3.5, event-emitter@~0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= dependencies: d "1" es5-ext "~0.10.14" @@ -2974,22 +2578,18 @@ event-emitter@^0.3.5, event-emitter@~0.3.5: eventemitter3@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.1.1.tgz#47786bdaa087caf7b1b75e73abc5c7d540158cd0" - integrity sha1-R3hr2qCHyvext15zq8XH1UAVjNA= events@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= events@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" - integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== dependencies: md5.js "^1.3.4" safe-buffer "^5.1.1" @@ -2997,7 +2597,6 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: execa@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= dependencies: cross-spawn "^5.0.1" get-stream "^3.0.0" @@ -3010,14 +2609,12 @@ execa@^0.7.0: expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= dependencies: is-posix-bracket "^0.1.0" expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= dependencies: debug "^2.3.3" define-property "^0.2.5" @@ -3030,14 +2627,12 @@ expand-brackets@^2.1.4: expand-range@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= dependencies: fill-range "^2.1.0" express@^4.14.0: version "4.16.4" resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" - integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== dependencies: accepts "~1.3.5" array-flatten "1.1.1" @@ -3073,14 +2668,12 @@ express@^4.14.0: extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" @@ -3088,33 +2681,16 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -extended@0.0.6, extended@~0.0.3: - version "0.0.6" - resolved "https://registry.yarnpkg.com/extended/-/extended-0.0.6.tgz#7fb8bf7b9dae397586e48570acfd642c78e50669" - integrity sha1-f7i/e52uOXWG5IVwrP1kLHjlBmk= - dependencies: - extender "~0.0.5" - -extender@~0.0.5: - version "0.0.10" - resolved "https://registry.yarnpkg.com/extender/-/extender-0.0.10.tgz#589c07482be61a1460b6d81f9c24aa67e8f324cd" - integrity sha1-WJwHSCvmGhRgttgfnCSqZ+jzJM0= - dependencies: - declare.js "~0.0.4" extendr@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/extendr/-/extendr-2.1.0.tgz#301aa0bbea565f4d2dc8f570f2a22611a8527b56" - integrity sha1-MBqgu+pWX00tyPVw8qImEahSe1Y= dependencies: typechecker "~2.0.1" external-editor@^2.0.4: version "2.2.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" - integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== dependencies: chardet "^0.4.0" iconv-lite "^0.4.17" @@ -3123,14 +2699,12 @@ external-editor@^2.0.4: extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= dependencies: is-extglob "^1.0.0" extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== dependencies: array-unique "^0.3.2" define-property "^1.0.0" @@ -3144,87 +2718,64 @@ extglob@^2.0.4: extract-opts@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/extract-opts/-/extract-opts-2.2.0.tgz#1fa28eba7352c6db480f885ceb71a46810be6d7d" - integrity sha1-H6KOunNSxttID4hc63GkaBC+bX0= dependencies: typechecker "~2.0.1" extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= eyes@0.1.x: version "0.1.8" resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" - integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= fake-merkle-patricia-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz#4b8c3acfb520afadf9860b1f14cd8ce3402cddd3" - integrity sha1-S4w6z7Ugr635hgsfFM2M40As3dM= dependencies: checkpoint-store "^1.1.0" -fast-csv@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/fast-csv/-/fast-csv-2.4.1.tgz#bd7dd268391f729367b59445b8dd0ad026881b26" - integrity sha1-vX3SaDkfcpNntZRFuN0K0CaIGyY= - dependencies: - extended "0.0.6" - is-extended "0.0.10" - object-extended "0.0.7" - string-extended "0.0.8" - fast-deep-equal@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" - integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= dependencies: pend "~1.2.0" fetch-ponyfill@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893" - integrity sha1-rjzl9zLGReq4fkroeTQUcJsjmJM= dependencies: node-fetch "~1.7.1" figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= dependencies: escape-string-regexp "^1.0.5" file-entry-cache@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" - integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E= dependencies: flat-cache "^1.2.1" object-assign "^4.0.1" @@ -3232,27 +2783,22 @@ file-entry-cache@^2.0.0: file-type@^3.8.0: version "3.9.0" resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" - integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= file-type@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" - integrity sha1-LdvqfHP/42No365J3DOMBYwritY= file-type@^6.1.0: version "6.2.0" resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" - integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= fill-range@^2.1.0: version "2.2.4" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" - integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== dependencies: is-number "^2.1.0" isobject "^2.0.0" @@ -3263,7 +2809,6 @@ fill-range@^2.1.0: fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" @@ -3273,7 +2818,6 @@ fill-range@^4.0.0: finalhandler@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" - integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== dependencies: debug "2.6.9" encodeurl "~1.0.2" @@ -3286,7 +2830,6 @@ finalhandler@1.1.1: find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" @@ -3294,14 +2837,12 @@ find-up@^1.0.0: find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= dependencies: locate-path "^2.0.0" flat-cache@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" - integrity sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE= dependencies: circular-json "^0.3.1" del "^2.0.2" @@ -3311,31 +2852,26 @@ flat-cache@^1.2.1: for-each@^0.3.2, for-each@~0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== dependencies: is-callable "^1.1.3" for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= for-own@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= dependencies: for-in "^1.0.1" forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= form-data@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" - integrity sha1-SXBJi+YEwgwAXU9cI67NIda0kJk= dependencies: asynckit "^0.4.0" combined-stream "1.0.6" @@ -3344,29 +2880,24 @@ form-data@~2.3.2: forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= dependencies: map-cache "^0.2.2" fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== fs-extra@^0.30.0: version "0.30.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" - integrity sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A= dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -3377,7 +2908,6 @@ fs-extra@^0.30.0: fs-extra@^2.0.0, fs-extra@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" - integrity sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU= dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -3385,7 +2915,6 @@ fs-extra@^2.0.0, fs-extra@^2.1.2: fs-extra@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" - integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -3394,7 +2923,6 @@ fs-extra@^4.0.2: fs-extra@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" - integrity sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ== dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -3403,14 +2931,12 @@ fs-extra@^5.0.0: fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" - integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== dependencies: minipass "^2.2.1" fs-promise@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/fs-promise/-/fs-promise-2.0.3.tgz#f64e4f854bcf689aa8bddcba268916db3db46854" - integrity sha1-9k5PhUvPaJqovdy6JokW2z20aFQ= dependencies: any-promise "^1.3.0" fs-extra "^2.0.0" @@ -3420,17 +2946,14 @@ fs-promise@^2.0.0: fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fs@0.0.1-security: version "0.0.1-security" resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4" - integrity sha1-invTcYa23d84E/I4WLV+yq9eQdQ= fsevents@^1.0.0, fsevents@^1.2.2: version "1.2.4" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" - integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== dependencies: nan "^2.9.2" node-pre-gyp "^0.10.0" @@ -3438,7 +2961,6 @@ fsevents@^1.0.0, fsevents@^1.2.2: fstream@^1.0.2, fstream@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" @@ -3448,24 +2970,20 @@ fstream@^1.0.2, fstream@^1.0.8: function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= ganache-cli@^6.1.8: version "6.1.8" resolved "https://registry.yarnpkg.com/ganache-cli/-/ganache-cli-6.1.8.tgz#49a8a331683a9652183f82ef1378d17e1814fcd3" - integrity sha512-yXzteu4SIgUL31mnpm9j+x6dpHUw0p/nsRVkcySKq0w+1vDxH9jMErP1QhZAJuTVE6ni4nfvGSNkaQx5cD3jfg== dependencies: source-map-support "^0.5.3" gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -3479,12 +2997,10 @@ gauge@~2.7.3: get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== get-stream@^2.2.0: version "2.3.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" - integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= dependencies: object-assign "^4.0.1" pinkie-promise "^2.0.0" @@ -3492,24 +3008,20 @@ get-stream@^2.2.0: get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= dependencies: assert-plus "^1.0.0" glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= dependencies: glob-parent "^2.0.0" is-glob "^2.0.0" @@ -3517,14 +3029,12 @@ glob-base@^0.3.0: glob-parent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= dependencies: is-glob "^2.0.0" glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= dependencies: is-glob "^3.1.0" path-dirname "^1.0.0" @@ -3532,7 +3042,6 @@ glob-parent@^3.1.0: glob@7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -3544,7 +3053,6 @@ glob@7.1.2: glob@^5.0.15: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= dependencies: inflight "^1.0.4" inherits "2" @@ -3555,7 +3063,6 @@ glob@^5.0.15: glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2, glob@~7.1.2: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -3567,7 +3074,6 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2, glob@~7.1.2: glob@~6.0.4: version "6.0.4" resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" - integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI= dependencies: inflight "^1.0.4" inherits "2" @@ -3578,7 +3084,6 @@ glob@~6.0.4: global@~4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" - integrity sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8= dependencies: min-document "^2.19.0" process "~0.5.1" @@ -3586,17 +3091,14 @@ global@~4.3.0: globals@^11.0.1: version "11.8.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.8.0.tgz#c1ef45ee9bed6badf0663c5cb90e8d1adec1321d" - integrity sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA== globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== globby@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" - integrity sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0= dependencies: array-union "^1.0.1" arrify "^1.0.0" @@ -3608,7 +3110,6 @@ globby@^5.0.0: got@7.1.0, got@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" - integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== dependencies: decompress-response "^3.2.0" duplexer3 "^0.1.4" @@ -3628,27 +3129,22 @@ got@7.1.0, got@^7.1.0: graceful-fs@*, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= "graceful-readlink@>= 1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= growl@1.10.3: version "1.10.3" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" - integrity sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q== growl@1.10.5, "growl@~> 1.10.0": version "1.10.5" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== handlebars@^4.0.1: version "4.0.12" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" - integrity sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA== dependencies: async "^2.5.0" optimist "^0.6.1" @@ -3659,12 +3155,10 @@ handlebars@^4.0.1: har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= har-validator@~5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29" - integrity sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA== dependencies: ajv "^5.3.0" har-schema "^2.0.0" @@ -3672,51 +3166,42 @@ har-validator@~5.1.0: has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= dependencies: ansi-regex "^2.0.0" has-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" - integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= has-flag@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" - integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE= has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= has-symbol-support-x@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" - integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== has-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= has-to-string-tag-x@^1.2.0: version "1.4.1" resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" - integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== dependencies: has-symbol-support-x "^1.4.1" has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= dependencies: get-value "^2.0.3" has-values "^0.1.4" @@ -3725,7 +3210,6 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= dependencies: get-value "^2.0.6" has-values "^1.0.0" @@ -3734,12 +3218,10 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= has-values@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= dependencies: is-number "^3.0.0" kind-of "^4.0.0" @@ -3747,14 +3229,12 @@ has-values@^1.0.0: has@^1.0.1, has@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: function-bind "^1.1.1" hash-base@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" - integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= dependencies: inherits "^2.0.1" safe-buffer "^5.0.1" @@ -3762,7 +3242,6 @@ hash-base@^3.0.0: hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.5" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.5.tgz#e38ab4b85dfb1e0c40fe9265c0e9b54854c23812" - integrity sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA== dependencies: inherits "^2.0.3" minimalistic-assert "^1.0.1" @@ -3770,7 +3249,6 @@ hash.js@^1.0.0, hash.js@^1.0.3: hdkey@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/hdkey/-/hdkey-1.1.0.tgz#e74e7b01d2c47f797fa65d1d839adb7a44639f29" - integrity sha512-E7aU8pNlWUJbXGjTz/+lKf1LkMcA3hUrC5ZleeizrmLSd++kvf8mSOe3q8CmBDA9j4hdfXO5iY6hGiTUCOV2jQ== dependencies: coinstring "^2.0.0" safe-buffer "^5.1.1" @@ -3779,12 +3257,10 @@ hdkey@^1.0.0: he@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" - integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= dependencies: hash.js "^1.0.3" minimalistic-assert "^1.0.0" @@ -3793,7 +3269,6 @@ hmac-drbg@^1.0.0: home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - integrity sha1-42w/LSyufXRqhX440Y1fMqeILbg= dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.1" @@ -3801,12 +3276,10 @@ home-or-tmp@^2.0.0: hosted-git-info@^2.1.4: version "2.7.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" - integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= dependencies: depd "~1.1.2" inherits "2.0.3" @@ -3816,12 +3289,10 @@ http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: http-https@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" - integrity sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs= http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= dependencies: assert-plus "^1.0.0" jsprim "^1.2.2" @@ -3830,12 +3301,10 @@ http-signature@~1.2.0: https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= i18n@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/i18n/-/i18n-0.8.3.tgz#2d8cf1c24722602c2041d01ba6ae5eaa51388f0e" - integrity sha1-LYzxwkciYCwgQdAbpq5eqlE4jw4= dependencies: debug "*" make-plural "^3.0.3" @@ -3844,41 +3313,39 @@ i18n@^0.8.3: mustache "*" sprintf-js ">=1.0.3" +i@0.3.x: + version "0.3.6" + resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" + iconv-lite@0.4.23: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" - integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== dependencies: safer-buffer ">= 2.1.2 < 3" iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" ieee754@^1.1.4, ieee754@^1.1.8: version "1.1.12" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" - integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA== ignore-walk@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" - integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== dependencies: minimatch "^3.0.4" ignore@^3.3.3, ignore@^3.3.6: version "3.3.10" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== ignorefs@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/ignorefs/-/ignorefs-1.2.0.tgz#da59fb858976e4a5e43702ccd1f282fdbc9e5756" - integrity sha1-2ln7hYl25KXkNwLM0fKC/byeV1Y= dependencies: editions "^1.3.3" ignorepatterns "^1.1.0" @@ -3886,27 +3353,22 @@ ignorefs@^1.0.0: ignorepatterns@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ignorepatterns/-/ignorepatterns-1.1.0.tgz#ac8f436f2239b5dfb66d5f0d3a904a87ac67cc5e" - integrity sha1-rI9DbyI5td+2bV8NOpBKh6xnzF4= immediate@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" - integrity sha1-0UD6j2FGWb1lQSMwl92qwlzdmRw= imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" wrappy "1" @@ -3914,22 +3376,18 @@ inflight@^1.0.4: inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= inherits@2.0.1, inherits@=2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== inquirer@^3.0.6: version "3.3.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" - integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" @@ -3949,91 +3407,76 @@ inquirer@^3.0.6: interpret@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" - integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ= invariant@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== dependencies: loose-envify "^1.0.0" invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= ipaddr.js@1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" - integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4= is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= dependencies: kind-of "^3.0.2" is-accessor-descriptor@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== dependencies: kind-of "^6.0.0" is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= dependencies: binary-extensions "^1.0.0" is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== is-builtin-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= dependencies: builtin-modules "^1.0.0" is-callable@^1.1.3, is-callable@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= dependencies: kind-of "^3.0.2" is-data-descriptor@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== dependencies: kind-of "^6.0.0" is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== dependencies: is-accessor-descriptor "^0.1.6" is-data-descriptor "^0.1.4" @@ -4042,7 +3485,6 @@ is-descriptor@^0.1.0: is-descriptor@^1.0.0, is-descriptor@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== dependencies: is-accessor-descriptor "^1.0.0" is-data-descriptor "^1.0.0" @@ -4051,261 +3493,210 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= is-equal-shallow@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= dependencies: is-primitive "^2.0.0" is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= is-extendable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== dependencies: is-plain-object "^2.0.4" -is-extended@0.0.10, is-extended@~0.0.3, is-extended@~0.0.8: - version "0.0.10" - resolved "https://registry.yarnpkg.com/is-extended/-/is-extended-0.0.10.tgz#244e140df75bb1c9a3106f412ff182fb534a6d62" - integrity sha1-JE4UDfdbscmjEG9BL/GC+1NKbWI= - dependencies: - extended "~0.0.3" - is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= is-finite@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= dependencies: number-is-nan "^1.0.0" is-fn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fn/-/is-fn-1.0.0.tgz#9543d5de7bcf5b08a22ec8a20bae6e286d510d8c" - integrity sha1-lUPV3nvPWwiiLsiiC65uKG1RDYw= is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= is-function@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" - integrity sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU= is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= dependencies: is-extglob "^1.0.0" is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= dependencies: is-extglob "^2.1.0" is-glob@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" - integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= dependencies: is-extglob "^2.1.1" is-hex-prefixed@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" - integrity sha1-fY035q135dEnFIkTxXPggtd39VQ= is-nan@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.2.1.tgz#9faf65b6fb6db24b7f5c0628475ea71f988401e2" - integrity sha1-n69ltvttskt/XAYoR16nH5iEAeI= dependencies: define-properties "^1.1.1" is-natural-number@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" - integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= dependencies: kind-of "^3.0.2" is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= dependencies: kind-of "^3.0.2" is-number@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= is-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" - integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" - integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0= is-path-in-cwd@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" - integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ== dependencies: is-path-inside "^1.0.0" is-path-inside@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" - integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= dependencies: path-is-inside "^1.0.1" is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: isobject "^3.0.1" is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= is-promise@^2.1, is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= is-regex@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= dependencies: has "^1.0.1" is-resolvable@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== is-retry-allowed@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" - integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ= is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= is-symbol@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" - integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== dependencies: has-symbols "^1.0.0" is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= isomorphic-fetch@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" - integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk= dependencies: node-fetch "^1.0.1" whatwg-fetch ">=0.10.0" @@ -4313,12 +3704,10 @@ isomorphic-fetch@^2.2.0: isstream@0.1.x, isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= istanbul@^0.4.5: version "0.4.5" resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" - integrity sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs= dependencies: abbrev "1.0.x" async "1.x" @@ -4338,7 +3727,6 @@ istanbul@^0.4.5: isurl@^1.0.0-alpha5: version "1.0.0" resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" - integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== dependencies: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" @@ -4346,37 +3734,30 @@ isurl@^1.0.0-alpha5: js-sha3@0.5.5: version "0.5.5" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.5.tgz#baf0c0e8c54ad5903447df96ade7a4a1bca79a4a" - integrity sha1-uvDA6MVK1ZA0R9+Wreekobynmko= js-sha3@0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" - integrity sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc= js-sha3@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.3.1.tgz#86122802142f0828502a0d1dee1d95e253bb0243" - integrity sha1-hhIoAhQvCChQKg0d7h2V4lO7AkM= js-string-escape@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" - integrity sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8= "js-tokens@^3.0.0 || ^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= js-yaml@3.x, js-yaml@^3.11.0, js-yaml@^3.9.1: version "3.12.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" - integrity sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A== dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -4384,27 +3765,22 @@ js-yaml@3.x, js-yaml@^3.11.0, js-yaml@^3.9.1: jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= json-loader@^0.5.4: version "0.5.7" resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d" - integrity sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w== json-rpc-engine@^3.6.0: version "3.8.0" resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.8.0.tgz#9d4ff447241792e1d0a232f6ef927302bb0c62a9" - integrity sha512-6QNcvm2gFuuK4TKU1uwfH0Qd/cOSb9c1lls0gbnIhciktIUQJwz6NQNAW4B1KiGPenv7IKu97V222Yo1bNhGuA== dependencies: async "^2.0.1" babel-preset-env "^1.7.0" @@ -4416,82 +3792,68 @@ json-rpc-engine@^3.6.0: json-rpc-error@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/json-rpc-error/-/json-rpc-error-2.0.0.tgz#a7af9c202838b5e905c7250e547f1aff77258a02" - integrity sha1-p6+cICg4tekFxyUOVH8a/3cligI= dependencies: inherits "^2.0.1" json-rpc-random-id@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz#ba49d96aded1444dbb8da3d203748acbbcdec8c8" - integrity sha1-uknZat7RRE27jaPSA3SKy7zeyMg= json-schema-traverse@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= dependencies: jsonify "~0.0.0" json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= json-text-sequence@^0.1: version "0.1.1" resolved "https://registry.yarnpkg.com/json-text-sequence/-/json-text-sequence-0.1.1.tgz#a72f217dc4afc4629fff5feb304dc1bd51a2f3d2" - integrity sha1-py8hfcSvxGKf/1/rME3BvVGi89I= dependencies: delimit-stream "0.1.0" json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - integrity sha1-NzaitCi4e72gzIO1P6PWM6NcKug= optionalDependencies: graceful-fs "^4.1.6" jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= optionalDependencies: graceful-fs "^4.1.6" jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= dependencies: assert-plus "1.0.0" extsprintf "1.3.0" @@ -4501,7 +3863,6 @@ jsprim@^1.2.2: keccak@^1.0.2: version "1.4.0" resolved "https://registry.yarnpkg.com/keccak/-/keccak-1.4.0.tgz#572f8a6dbee8e7b3aa421550f9e6408ca2186f80" - integrity sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw== dependencies: bindings "^1.2.1" inherits "^2.0.3" @@ -4511,7 +3872,6 @@ keccak@^1.0.2: keccakjs@^0.2.0, keccakjs@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/keccakjs/-/keccakjs-0.2.1.tgz#1d633af907ef305bbf9f2fa616d56c44561dfa4d" - integrity sha1-HWM6+QfvMFu/ny+mFtVsRFYd+k0= dependencies: browserify-sha3 "^0.0.1" sha3 "^1.1.0" @@ -4519,74 +3879,62 @@ keccakjs@^0.2.0, keccakjs@^0.2.1: kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= dependencies: is-buffer "^1.1.5" kind-of@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== klaw@^1.0.0: version "1.3.1" resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - integrity sha1-QIhDO0azsbolnXh4XY6W9zugJDk= optionalDependencies: graceful-fs "^4.1.9" lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= dependencies: invert-kv "^1.0.0" lcov-parse@^0.0.10: version "0.0.10" resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3" - integrity sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM= level-codec@~7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7" - integrity sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ== level-errors@^1.0.3: version "1.1.2" resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.1.2.tgz#4399c2f3d3ab87d0625f7e3676e2d807deff404d" - integrity sha512-Sw/IJwWbPKF5Ai4Wz60B52yj0zYeqzObLh8k1Tk88jVmD51cJSKWSYpRyhVIvFzZdvsPqlH5wfhp/yxdsaQH4w== dependencies: errno "~0.1.1" level-errors@~1.0.3: version "1.0.5" resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.0.5.tgz#83dbfb12f0b8a2516bdc9a31c4876038e227b859" - integrity sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig== dependencies: errno "~0.1.1" level-iterator-stream@~1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz#e43b78b1a8143e6fa97a4f485eb8ea530352f2ed" - integrity sha1-5Dt4sagUPm+pek9IXrjqUwNS8u0= dependencies: inherits "^2.0.1" level-errors "^1.0.3" @@ -4596,7 +3944,6 @@ level-iterator-stream@~1.3.0: level-ws@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-0.0.0.tgz#372e512177924a00424b0b43aef2bb42496d228b" - integrity sha1-Ny5RIXeSSgBCSwtDrvK7QkltIos= dependencies: readable-stream "~1.0.15" xtend "~2.1.1" @@ -4604,7 +3951,6 @@ level-ws@0.0.0: levelup@^1.2.1: version "1.3.9" resolved "https://registry.yarnpkg.com/levelup/-/levelup-1.3.9.tgz#2dbcae845b2bb2b6bea84df334c475533bbd82ab" - integrity sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ== dependencies: deferred-leveldown "~1.2.1" level-codec "~7.0.0" @@ -4617,7 +3963,6 @@ levelup@^1.2.1: levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" @@ -4625,7 +3970,6 @@ levn@^0.3.0, levn@~0.3.0: load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -4636,7 +3980,6 @@ load-json-file@^1.0.0: load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -4646,12 +3989,10 @@ load-json-file@^2.0.0: loader-runner@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.1.tgz#026f12fe7c3115992896ac02ba022ba92971b979" - integrity sha512-By6ZFY7ETWOc9RFaAIb23IjJVcM4dvJC/N57nmdz9RSkMXvAXGI7SyVlAw3v8vjtDRlqThgVDVmTnr9fqMlxkw== loader-utils@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" - integrity sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0= dependencies: big.js "^3.1.3" emojis-list "^2.0.0" @@ -4660,7 +4001,6 @@ loader-utils@^1.1.0: locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= dependencies: p-locate "^2.0.0" path-exists "^3.0.0" @@ -4668,54 +4008,44 @@ locate-path@^2.0.0: lodash.assign@^4.0.3, lodash.assign@^4.0.6: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" - integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= lodash@4.x, lodash@^4.13.1, lodash@^4.14.2, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" - integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== lodash@=4.17.4: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" - integrity sha1-eCA6TRwyiuHYbcpkYONptX9AVa4= log-driver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" - integrity sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg== long-timeout@0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/long-timeout/-/long-timeout-0.1.1.tgz#9721d788b47e0bcb5a24c2e2bee1a0da55dab514" - integrity sha1-lyHXiLR+C8taJMLivuGg2lXatRQ= longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" - integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: js-tokens "^3.0.0 || ^4.0.0" lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== lru-cache@^4.0.1: version "4.1.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" - integrity sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA== dependencies: pseudomap "^1.0.2" yallist "^2.1.2" @@ -4723,57 +4053,48 @@ lru-cache@^4.0.1: lru-queue@0.1: version "0.1.0" resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" - integrity sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM= dependencies: es5-ext "~0.10.2" ltgt@~2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" - integrity sha1-81ypHEk/e3PaDgdJUwTxezH4fuU= make-dir@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== dependencies: pify "^3.0.0" make-plural@^3.0.3, make-plural@~3.0.3: version "3.0.6" resolved "https://registry.yarnpkg.com/make-plural/-/make-plural-3.0.6.tgz#2033a03bac290b8f3bb91258f65b9df7e8b01ca7" - integrity sha1-IDOgO6wpC487uRJY9lud9+iwHKc= optionalDependencies: minimist "^1.2.0" map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= dependencies: object-visit "^1.0.0" math-interval-parser@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/math-interval-parser/-/math-interval-parser-1.1.0.tgz#dbeda5b06b3249973c6df6170fde2386f0afd893" - integrity sha1-2+2lsGsySZc8bfYXD94jhvCv2JM= dependencies: xregexp "^2.0.0" math-random@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" - integrity sha1-izqsWIuKZuSXXjzepn97sylgH6w= md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== dependencies: hash-base "^3.0.0" inherits "^2.0.1" @@ -4782,19 +4103,16 @@ md5.js@^1.3.4: media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= mem@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= dependencies: mimic-fn "^1.0.0" memdown@^1.0.0: version "1.4.1" resolved "https://registry.yarnpkg.com/memdown/-/memdown-1.4.1.tgz#b4e4e192174664ffbae41361aa500f3119efe215" - integrity sha1-tOThkhdGZP+65BNhqlAPMRnv4hU= dependencies: abstract-leveldown "~2.7.1" functional-red-black-tree "^1.0.1" @@ -4806,7 +4124,6 @@ memdown@^1.0.0: memoizee@^0.4.14: version "0.4.14" resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.14.tgz#07a00f204699f9a95c2d9e77218271c7cd610d57" - integrity sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg== dependencies: d "1" es5-ext "^0.10.45" @@ -4820,7 +4137,6 @@ memoizee@^0.4.14: memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" - integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= dependencies: errno "^0.1.3" readable-stream "^2.0.1" @@ -4828,17 +4144,14 @@ memory-fs@^0.4.0, memory-fs@~0.4.1: memorystream@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" - integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= merkle-patricia-tree@^2.1.2: version "2.3.2" resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz#982ca1b5a0fde00eed2f6aeed1f9152860b8208a" - integrity sha512-81PW5m8oz/pz3GvsAwbauj7Y00rqm81Tzad77tHBwU7pIAtN+TJnMSOJhxBKflSVYhptMMb9RskhqHqrSm1V+g== dependencies: async "^1.4.2" ethereumjs-util "^5.0.0" @@ -4852,7 +4165,6 @@ merkle-patricia-tree@^2.1.2: messageformat@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/messageformat/-/messageformat-0.3.1.tgz#e58fff8245e9b3971799e5b43db58b3e9417f5a2" - integrity sha1-5Y//gkXps5cXmeW0PbWLPpQX9aI= dependencies: async "~1.5.2" glob "~6.0.4" @@ -4863,12 +4175,10 @@ messageformat@^0.3.1: methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= micromatch@^2.1.5: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= dependencies: arr-diff "^2.0.0" array-unique "^0.2.1" @@ -4887,7 +4197,6 @@ micromatch@^2.1.5: micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -4906,7 +4215,6 @@ micromatch@^3.1.10, micromatch@^3.1.4: miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== dependencies: bn.js "^4.0.0" brorand "^1.0.1" @@ -4914,73 +4222,60 @@ miller-rabin@^4.0.0: mime-db@~1.36.0: version "1.36.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397" - integrity sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw== mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.18, mime-types@~2.1.19: version "2.1.20" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19" - integrity sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A== dependencies: mime-db "~1.36.0" mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" - integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== min-document@^2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= dependencies: dom-walk "^0.1.0" minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= "minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= minimist@^1.2.0, minimist@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= minipass@^2.2.1, minipass@^2.3.3: version "2.3.4" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.4.tgz#4768d7605ed6194d6d576169b9e12ef71e9d9957" - integrity sha512-mlouk1OHlaUE8Odt1drMtG1bAJA4ZA6B/ehysgV0LUIrDHdKgo1KorZq3pK0b/7Z7LJIQ12MNM6aC+Tn6lUZ5w== dependencies: safe-buffer "^5.1.2" yallist "^3.0.0" @@ -4988,14 +4283,12 @@ minipass@^2.2.1, minipass@^2.3.3: minizlib@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.1.tgz#6734acc045a46e61d596a43bb9d9cd326e19cc42" - integrity sha512-TrfjCjk4jLhcJyGMYymBH6oTXcWjYbUAXTHDbtnWHjZC25h0cdajHuPE1zxb4DVmu8crfh+HwH/WMuyLG0nHBg== dependencies: minipass "^2.2.1" mixin-deep@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" - integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" @@ -5003,21 +4296,18 @@ mixin-deep@^1.2.0: mkdirp-promise@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" - integrity sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE= dependencies: mkdirp "*" -mkdirp@*, mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: +mkdirp@*, mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@0.x.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= dependencies: minimist "0.0.8" mocha@^4.0.1, mocha@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794" - integrity sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA== dependencies: browser-stdout "1.3.0" commander "2.11.0" @@ -5033,7 +4323,6 @@ mocha@^4.0.1, mocha@^4.1.0: mocha@^5.0.1: version "5.2.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" - integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== dependencies: browser-stdout "1.3.1" commander "2.15.1" @@ -5050,39 +4339,32 @@ mocha@^5.0.1: mock-fs@^4.1.0: version "4.7.0" resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.7.0.tgz#9f17e219cacb8094f4010e0a8c38589e2b33c299" - integrity sha512-WlQNtUlzMRpvLHf8dqeUmNqfdPjGY29KrJF50Ldb4AcL+vQeR8QH3wQcFMgrhTwb1gHjZn9xggho+84tBskLgA== moment-timezone@^0.5.0: version "0.5.21" resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.21.tgz#3cba247d84492174dbf71de2a9848fa13207b845" - integrity sha512-j96bAh4otsgj3lKydm3K7kdtA3iKf2m6MY2iSYCzCm5a1zmHo1g+aK3068dDEeocLZQIS9kU8bsdQHLqEvgW0A== dependencies: moment ">= 2.9.0" "moment@>= 2.9.0", moment@^2.22.2: version "2.22.2" resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" - integrity sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y= mout@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/mout/-/mout-0.11.1.tgz#ba3611df5f0e5b1ffbfd01166b8f02d1f5fa2b99" - integrity sha1-ujYR318OWx/7/QEWa48C0fX6K5k= ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= ms@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== multihashes@^0.4.5: version "0.4.14" resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.14.tgz#774db9a161f81a8a27dc60788f91248e020f5244" - integrity sha512-V/g/EIN6nALXfS/xHUAgtfPP3mn3sPIF/i9beuGKf25QXS2QZYCpeVJbDPEannkz32B2fihzCe2D/KMrbcmefg== dependencies: bs58 "^4.0.1" varint "^5.0.0" @@ -5090,22 +4372,18 @@ multihashes@^0.4.5: mustache@*: version "3.0.0" resolved "https://registry.yarnpkg.com/mustache/-/mustache-3.0.0.tgz#3de22dd9ba38152f7355399a953dd4528c403338" - integrity sha512-bhBDkK/PioIbtQzRIbGUGypvc3MC4c389QnJt8KDIEJ666OidRPoXAQAHPivikfS3JkMEaWoPvcDL7YrQxtSwg== mustache@^2.3.0: version "2.3.2" resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.2.tgz#a6d4d9c3f91d13359ab889a812954f9230a3d0c5" - integrity sha512-KpMNwdQsYz3O/SBS1qJ/o3sqUJ5wSb8gb0pul8CO0S56b9Y2ALm8zCfsjPXsqGFfoNBkDwZuZIAjhsZI03gYVQ== -mute-stream@0.0.7: +mute-stream@0.0.7, mute-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= mz@^2.6.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== dependencies: any-promise "^1.0.0" object-assign "^4.0.1" @@ -5114,22 +4392,18 @@ mz@^2.6.0: nan@2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" - integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA== nan@^2.0.8, nan@^2.2.1, nan@^2.3.3, nan@^2.9.2: version "2.11.1" resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.1.tgz#90e22bccb8ca57ea4cd37cc83d3819b52eea6766" - integrity sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA== nano-json-stream-parser@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" - integrity sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18= nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -5146,12 +4420,14 @@ nanomatch@^1.2.9: natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +ncp@1.0.x: + version "1.0.1" + resolved "http://registry.npmjs.org/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246" needle@^2.2.1: version "2.2.4" resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" - integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA== dependencies: debug "^2.1.2" iconv-lite "^0.4.4" @@ -5160,27 +4436,22 @@ needle@^2.2.1: negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" - integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= neo-async@^2.5.0: version "2.5.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.2.tgz#489105ce7bc54e709d736b195f82135048c50fcc" - integrity sha512-vdqTKI9GBIYcAEbFAcpKPErKINfPF5zIuz3/niBfq8WUZjpT2tytLlFVrBgWdOtqI4uaA/Rb6No0hux39XXDuw== next-tick@1: version "1.0.0" resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" - integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= node-async-loop@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/node-async-loop/-/node-async-loop-1.2.2.tgz#c5870299bf6477b780c88b431aa5b37733f55a3d" - integrity sha1-xYcCmb9kd7eAyItDGqWzdzP1Wj0= node-cache@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-4.2.0.tgz#48ac796a874e762582692004a376d26dfa875811" - integrity sha512-obRu6/f7S024ysheAjoYFEEBqqDWv4LOMNJEuO8vMeEw2AT4z+NCzO4hlc2lhI4vATzbCQv6kke9FVdx0RbCOw== dependencies: clone "2.x" lodash "4.x" @@ -5188,7 +4459,6 @@ node-cache@^4.1.1: node-fetch@^1.0.1, node-fetch@~1.7.1: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== dependencies: encoding "^0.1.11" is-stream "^1.0.1" @@ -5196,7 +4466,6 @@ node-fetch@^1.0.1, node-fetch@~1.7.1: node-libs-browser@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" - integrity sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg== dependencies: assert "^1.1.1" browserify-zlib "^0.2.0" @@ -5225,7 +4494,6 @@ node-libs-browser@^2.0.0: node-pre-gyp@^0.10.0: version "0.10.3" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" - integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== dependencies: detect-libc "^1.0.2" mkdirp "^0.5.1" @@ -5241,7 +4509,6 @@ node-pre-gyp@^0.10.0: node-schedule@^1.2.3: version "1.3.0" resolved "https://registry.yarnpkg.com/node-schedule/-/node-schedule-1.3.0.tgz#e7a7e816a7f2550d5b170bd106e765db28bdf030" - integrity sha512-NNwO9SUPjBwFmPh3vXiPVEhJLn4uqYmZYvJV358SRGM06BR4UoIqxJpeJwDDXB6atULsgQA97MfD1zMd5xsu+A== dependencies: cron-parser "^2.4.0" long-timeout "0.1.1" @@ -5250,14 +4517,12 @@ node-schedule@^1.2.3: nopt@3.x, nopt@~3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= dependencies: abbrev "1" nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= dependencies: abbrev "1" osenv "^0.1.4" @@ -5265,7 +4530,6 @@ nopt@^4.0.1: normalize-package-data@^2.3.2: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" - integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw== dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -5275,19 +4539,16 @@ normalize-package-data@^2.3.2: normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" npm-bundled@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" - integrity sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g== npm-packlist@^1.1.6: version "1.1.12" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.12.tgz#22bde2ebc12e72ca482abd67afc51eb49377243a" - integrity sha512-WJKFOVMeAlsU/pjXuqVdzU0WfgtIBCupkEVwn+1Y0ERAbUfWw8R4GjgVbaKnUjRoD2FoQbHOCbOyT5Mbs9Lw4g== dependencies: ignore-walk "^3.0.1" npm-bundled "^1.0.1" @@ -5295,14 +4556,12 @@ npm-packlist@^1.1.6: npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= dependencies: path-key "^2.0.0" npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -5312,12 +4571,10 @@ npmlog@^4.0.2: number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= number-to-bn@1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" - integrity sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA= dependencies: bn.js "4.11.6" strip-hex-prefix "1.0.0" @@ -5325,57 +4582,40 @@ number-to-bn@1.7.0: oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== object-assign@^4, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" kind-of "^3.0.3" -object-extended@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/object-extended/-/object-extended-0.0.7.tgz#84fd23f56b15582aeb3e88b05cb55d2432d68a33" - integrity sha1-hP0j9WsVWCrrPoiwXLVdJDLWijM= - dependencies: - array-extended "~0.0.4" - extended "~0.0.3" - is-extended "~0.0.3" - object-inspect@~1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" - integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== object-keys@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" - integrity sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag== object-keys@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" - integrity sha1-KKaq50KN0sOpLz2V8hM13SBOAzY= object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= dependencies: isobject "^3.0.0" object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= dependencies: for-own "^0.1.4" is-extendable "^0.1.1" @@ -5383,47 +4623,40 @@ object.omit@^2.0.0: object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= dependencies: isobject "^3.0.1" oboe@2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.3.tgz#2b4865dbd46be81225713f4e9bfe4bcf4f680a4f" - integrity sha1-K0hl29Rr6BIlcT9Om/5Lz09oCk8= dependencies: http-https "^1.0.0" on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= dependencies: ee-first "1.1.1" once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= dependencies: mimic-fn "^1.0.0" openzeppelin-solidity@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/openzeppelin-solidity/-/openzeppelin-solidity-1.10.0.tgz#d77eee6653f5958d051318a61ba0b436f92216c0" - integrity sha512-igkrumQQ2lrN2zjeQV4Dnb0GpTBj1fzMcd8HPyBUqwI0hhuscX/HzXiqKT6gFQl1j9Wy/ppVVs9fqL/foF7Gmg== optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= dependencies: minimist "~0.0.1" wordwrap "~0.0.2" @@ -5431,7 +4664,6 @@ optimist@^0.6.1: optionator@^0.8.1, optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.4" @@ -5443,29 +4675,24 @@ optionator@^0.8.1, optionator@^0.8.2: original-require@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/original-require/-/original-require-1.0.1.tgz#0f130471584cd33511c5ec38c8d59213f9ac5e20" - integrity sha1-DxMEcVhM0zURxew4yNWSE/msXiA= os-browserify@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= os-locale@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= dependencies: lcid "^1.0.0" os-locale@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== dependencies: execa "^0.7.0" lcid "^1.0.0" @@ -5474,12 +4701,10 @@ os-locale@^2.0.0: os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= osenv@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" @@ -5487,48 +4712,40 @@ osenv@^0.1.4: p-cancelable@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" - integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== dependencies: p-try "^1.0.0" p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= dependencies: p-limit "^1.1.0" p-timeout@^1.1.1: version "1.2.1" resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" - integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= dependencies: p-finally "^1.0.0" p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= pako@~1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" - integrity sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg== parse-asn1@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" - integrity sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw== dependencies: asn1.js "^4.0.0" browserify-aes "^1.0.0" @@ -5539,7 +4756,6 @@ parse-asn1@^5.0.0: parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= dependencies: glob-base "^0.3.0" is-dotfile "^1.0.0" @@ -5549,7 +4765,6 @@ parse-glob@^3.0.4: parse-headers@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.1.tgz#6ae83a7aa25a9d9b700acc28698cd1f1ed7e9536" - integrity sha1-aug6eqJanZtwCswoaYzR8e1+lTY= dependencies: for-each "^0.3.2" trim "0.0.1" @@ -5557,71 +4772,58 @@ parse-headers@^2.0.0: parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= dependencies: error-ex "^1.2.0" parseurl@~1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" - integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= path-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" - integrity sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo= path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= dependencies: pinkie-promise "^2.0.0" path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= path-key@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= path-parse@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -5630,14 +4832,12 @@ path-type@^1.0.0: path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= dependencies: pify "^2.0.0" pbkdf2@^3.0.3: version "3.0.17" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" - integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== dependencies: create-hash "^1.1.2" create-hmac "^1.1.4" @@ -5648,119 +4848,116 @@ pbkdf2@^3.0.3: pegjs@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/pegjs/-/pegjs-0.10.0.tgz#cf8bafae6eddff4b5a7efb185269eaaf4610ddbd" - integrity sha1-z4uvrm7d/0tafvsYUmnqr0YQ3b0= pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= pkg-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" - integrity sha1-ektQio1bstYp1EcFb/TpyTFM89Q= dependencies: find-up "^1.0.0" +pkginfo@0.3.x: + version "0.3.1" + resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" + +pkginfo@0.x.x: + version "0.4.1" + resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff" + pluralize@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" - integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= pragma-singleton@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/pragma-singleton/-/pragma-singleton-1.0.3.tgz#6894317bb8d47157e59de2a4a009db7e6f63e30e" - integrity sha1-aJQxe7jUcVflneKkoAnbfm9j4w4= prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= prepend-http@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= prettier@^1.14.3: version "1.14.3" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.14.3.tgz#90238dd4c0684b7edce5f83b0fb7328e48bd0895" - integrity sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg== private@^0.1.6, private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== process-nextick-args@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= process@~0.5.1: version "0.5.2" resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" - integrity sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8= progress@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" - integrity sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8= promise-to-callback@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/promise-to-callback/-/promise-to-callback-1.0.0.tgz#5d2a749010bfb67d963598fcd3960746a68feef7" - integrity sha1-XSp0kBC/tn2WNZj805YHRqaP7vc= dependencies: is-fn "^1.0.0" set-immediate-shim "^1.0.1" +prompt@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prompt/-/prompt-1.0.0.tgz#8e57123c396ab988897fb327fd3aedc3e735e4fe" + dependencies: + colors "^1.1.2" + pkginfo "0.x.x" + read "1.0.x" + revalidator "0.1.x" + utile "0.3.x" + winston "2.1.x" + prop-types@^15.6.2: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" - integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ== dependencies: loose-envify "^1.3.1" object-assign "^4.1.1" @@ -5768,7 +4965,6 @@ prop-types@^15.6.2: proxy-addr@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" - integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== dependencies: forwarded "~0.1.2" ipaddr.js "1.8.0" @@ -5776,22 +4972,18 @@ proxy-addr@~2.0.4: prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= psl@^1.1.24: version "1.1.29" resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67" - integrity sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ== public-encrypt@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== dependencies: bn.js "^4.1.0" browserify-rsa "^4.0.0" @@ -5803,27 +4995,22 @@ public-encrypt@^4.0.0: punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= punycode@^1.2.4, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== qs@6.5.2, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== query-string@^5.0.1: version "5.1.1" resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" - integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== dependencies: decode-uri-component "^0.2.0" object-assign "^4.1.0" @@ -5832,17 +5019,14 @@ query-string@^5.0.1: querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= randomatic@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.0.tgz#36f2ca708e9e567f5ed2ec01949026d50aa10116" - integrity sha512-KnGPVE0lo2WoXxIZ7cPR8YBpiol4gsSuOwDSg410oHh80ZMp5EiypNqL2K4Z77vJn6lB5rap7IkAmcUlalcnBQ== dependencies: is-number "^4.0.0" kind-of "^6.0.0" @@ -5851,14 +5035,12 @@ randomatic@^3.0.0: randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" - integrity sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A== dependencies: safe-buffer "^5.1.0" randomfill@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== dependencies: randombytes "^2.0.5" safe-buffer "^5.1.0" @@ -5866,17 +5048,14 @@ randomfill@^1.0.3: randomhex@0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/randomhex/-/randomhex-0.1.5.tgz#baceef982329091400f2a2912c6cd02f1094f585" - integrity sha1-us7vmCMpCRQA8qKRLGzQLxCU9YU= range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= raw-body@2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" - integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== dependencies: bytes "3.0.0" http-errors "1.6.3" @@ -5886,7 +5065,6 @@ raw-body@2.3.3: rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: deep-extend "^0.6.0" ini "~1.3.0" @@ -5896,7 +5074,6 @@ rc@^1.2.7: react-dom@^16.2.0: version "16.5.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.5.2.tgz#b69ee47aa20bab5327b2b9d7c1fe2a30f2cfa9d7" - integrity sha512-RC8LDw8feuZOHVgzEf7f+cxBr/DnKdqp56VU0lAs1f4UfKc4cU8wU4fTq/mgnvynLQo8OtlPC19NUFh/zjZPuA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -5906,7 +5083,6 @@ react-dom@^16.2.0: react@^16.2.0: version "16.5.2" resolved "https://registry.yarnpkg.com/react/-/react-16.5.2.tgz#19f6b444ed139baa45609eee6dc3d318b3895d42" - integrity sha512-FDCSVd3DjVTmbEAjUNX6FgfAmQ+ypJfHUsqUJOYNCBUp1h8lqmtC+0mXJ+JjsWx4KAVTkk1vKd1hLQPvEviSuw== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -5916,7 +5092,6 @@ react@^16.2.0: read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= dependencies: find-up "^1.0.0" read-pkg "^1.0.0" @@ -5924,7 +5099,6 @@ read-pkg-up@^1.0.1: read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= dependencies: find-up "^2.0.0" read-pkg "^2.0.0" @@ -5932,7 +5106,6 @@ read-pkg-up@^2.0.0: read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" @@ -5941,16 +5114,20 @@ read-pkg@^1.0.0: read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= dependencies: load-json-file "^2.0.0" normalize-package-data "^2.3.2" path-type "^2.0.0" +read@1.0.x: + version "1.0.7" + resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" + dependencies: + mute-stream "~0.0.4" + readable-stream@^1.0.33: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -5960,7 +5137,6 @@ readable-stream@^1.0.33: readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -5973,7 +5149,6 @@ readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable readable-stream@~1.0.15: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -5983,7 +5158,6 @@ readable-stream@~1.0.15: readdirp@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== dependencies: graceful-fs "^4.1.11" micromatch "^3.1.10" @@ -5992,34 +5166,28 @@ readdirp@^2.0.0: readline-sync@^1.4.9: version "1.4.9" resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.9.tgz#3eda8e65f23cd2a17e61301b1f0003396af5ecda" - integrity sha1-PtqOZfI80qF+YTAbHwADOWr17No= rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= dependencies: resolve "^1.1.6" regenerate@^1.2.1: version "1.4.0" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" - integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== regenerator-runtime@^0.10.5: version "0.10.5" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" - integrity sha1-M2w+/BIgrc7dosn6tntaeVWjNlg= regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" - integrity sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q== dependencies: babel-runtime "^6.18.0" babel-types "^6.19.0" @@ -6028,14 +5196,12 @@ regenerator-transform@^0.10.0: regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== dependencies: is-equal-shallow "^0.1.3" regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== dependencies: extend-shallow "^3.0.2" safe-regex "^1.1.0" @@ -6043,12 +5209,10 @@ regex-not@^1.0.0, regex-not@^1.0.2: regexpp@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" - integrity sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw== regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" - integrity sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA= dependencies: regenerate "^1.2.1" regjsgen "^0.2.0" @@ -6057,62 +5221,52 @@ regexpu-core@^2.0.0: regjsgen@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= regjsparser@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw= dependencies: jsesc "~0.5.0" remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= repeating@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= dependencies: is-finite "^1.0.0" req-cwd@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/req-cwd/-/req-cwd-1.0.1.tgz#0d73aeae9266e697a78f7976019677e76acf0fff" - integrity sha1-DXOurpJm5penj3l2AZZ352rPD/8= dependencies: req-from "^1.0.1" req-from@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/req-from/-/req-from-1.0.1.tgz#bf81da5147947d32d13b947dc12a58ad4587350e" - integrity sha1-v4HaUUeUfTLRO5R9wSpYrUWHNQ4= dependencies: resolve-from "^2.0.0" request-promise-core@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" - integrity sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY= dependencies: lodash "^4.13.1" request-promise@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-4.2.2.tgz#d1ea46d654a6ee4f8ee6a4fea1018c22911904b4" - integrity sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ= dependencies: bluebird "^3.5.0" request-promise-core "1.1.1" @@ -6122,7 +5276,6 @@ request-promise@^4.2.2: request@^2.67.0, request@^2.79.0, request@^2.81.0, request@^2.85.0, request@^2.88.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" - integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -6148,22 +5301,18 @@ request@^2.67.0, request@^2.79.0, request@^2.81.0, request@^2.85.0, request@^2.8 require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= require-from-string@^1.1.0: version "1.2.1" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418" - integrity sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg= require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM= dependencies: caller-path "^0.1.0" resolve-from "^1.0.0" @@ -6171,41 +5320,34 @@ require-uncached@^1.0.3: resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY= resolve-from@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" - integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= resolve@1.1.x: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= resolve@^1.1.6, resolve@^1.3.3, resolve@^1.5.0, resolve@^1.6.0: version "1.8.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" - integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== dependencies: path-parse "^1.0.5" resolve@~1.7.1: version "1.7.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3" - integrity sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw== dependencies: path-parse "^1.0.5" restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= dependencies: onetime "^2.0.0" signal-exit "^3.0.2" @@ -6213,33 +5355,32 @@ restore-cursor@^2.0.0: resumer@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" - integrity sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k= dependencies: through "~2.3.4" ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +revalidator@0.1.x: + version "0.1.8" + resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" - integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8= dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.2.8, rimraf@^2.6.1: +rimraf@2, rimraf@2.x.x, rimraf@^2.2.8, rimraf@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== dependencies: glob "^7.0.5" ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== dependencies: hash-base "^3.0.0" inherits "^2.0.1" @@ -6247,79 +5388,66 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: rlp@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.1.0.tgz#e4f9886d5a982174f314543831e36e1a658460f9" - integrity sha512-93U7IKH5j7nmXFVg19MeNBGzQW5uXW1pmCuKY8veeKIhYTE32C2d0mOegfiIAfXcHOKJjjPlJisn8iHDF5AezA== dependencies: safe-buffer "^5.1.1" run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= dependencies: is-promise "^2.1.0" rustbn.js@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" - integrity sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA== rx-lite-aggregates@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" - integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= dependencies: rx-lite "*" rx-lite@*, rx-lite@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" - integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== safe-event-emitter@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz#5b692ef22329ed8f69fdce607e50ca734f6f20af" - integrity sha512-e1wFe99A91XYYxoQbcq2ZJUWurxEyP8vfz7A7vuUe1s95q8r5ebraVaA1BukYJcpM6V16ugWoD9vngi8Ccu5fg== dependencies: events "^3.0.0" safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= dependencies: ret "~0.1.10" safe@^0.4.5: version "0.4.6" resolved "https://registry.yarnpkg.com/safe/-/safe-0.4.6.tgz#1d5580cf2635c5cb940ea48fb5081ae3c25b1be1" - integrity sha1-HVWAzyY1xcuUDqSPtQga48JbG+E= safefs@^3.1.2: version "3.2.2" resolved "https://registry.yarnpkg.com/safefs/-/safefs-3.2.2.tgz#8170c1444d7038e08caea05a374fae2fa349e15c" - integrity sha1-gXDBRE1wOOCMrqBaN0+uL6NJ4Vw= dependencies: graceful-fs "*" "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== scandirectory@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/scandirectory/-/scandirectory-2.5.0.tgz#6ce03f54a090b668e3cbedbf20edf9e310593e72" - integrity sha1-bOA/VKCQtmjjy+2/IO354xBZPnI= dependencies: ignorefs "^1.0.0" safefs "^3.1.2" @@ -6328,24 +5456,20 @@ scandirectory@^2.5.0: schedule@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/schedule/-/schedule-0.5.0.tgz#c128fffa0b402488b08b55ae74bb9df55cc29cc8" - integrity sha512-HUcJicG5Ou8xfR//c2rPT0lPIRR09vVvN81T9fqfVgBmhERUbDEQoYKjpBxbueJnCPpSu2ujXzOnRQt6x9o/jw== dependencies: object-assign "^4.1.1" scrypt-async@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/scrypt-async/-/scrypt-async-1.3.1.tgz#a11fd6fac981b4b823ee01dee0221169500ddae9" - integrity sha1-oR/W+smBtLgj7gHe4CIRaVAN2uk= scrypt-js@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.3.tgz#bb0040be03043da9a012a2cea9fc9f852cfc87d4" - integrity sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q= scrypt.js@0.2.0, scrypt.js@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/scrypt.js/-/scrypt.js-0.2.0.tgz#af8d1465b71e9990110bedfc593b9479e03a8ada" - integrity sha1-r40UZbcemZARC+38WTuUeeA6ito= dependencies: scrypt "^6.0.2" scryptsy "^1.2.1" @@ -6353,21 +5477,18 @@ scrypt.js@0.2.0, scrypt.js@^0.2.0: scrypt@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/scrypt/-/scrypt-6.0.3.tgz#04e014a5682b53fa50c2d5cce167d719c06d870d" - integrity sha1-BOAUpWgrU/pQwtXM4WfXGcBthw0= dependencies: nan "^2.0.8" scryptsy@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" - integrity sha1-oyJfpLJST4AnAHYeKFW987LZIWM= dependencies: pbkdf2 "^3.0.3" secp256k1@^3.0.1: version "3.5.2" resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.5.2.tgz#f95f952057310722184fe9c914e6b71281f2f2ae" - integrity sha512-iin3kojdybY6NArd+UFsoTuapOF7bnJNf2UbcWXaY3z+E1sJDipl60vtzB5hbO/uquBu7z0fd4VC4Irp+xoFVQ== dependencies: bindings "^1.2.1" bip66 "^1.1.3" @@ -6381,29 +5502,24 @@ secp256k1@^3.0.1: seek-bzip@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc" - integrity sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w= dependencies: commander "~2.8.1" semaphore@>=1.0.1, semaphore@^1.0.3: version "1.1.0" resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" - integrity sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA== "semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" - integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== semver@~5.4.1: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - integrity sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg== send@0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" - integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== dependencies: debug "2.6.9" depd "~1.1.2" @@ -6422,7 +5538,6 @@ send@0.16.2: serve-static@1.13.2: version "1.13.2" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" - integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" @@ -6432,7 +5547,6 @@ serve-static@1.13.2: servify@^0.1.12: version "0.1.12" resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" - integrity sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw== dependencies: body-parser "^1.16.0" cors "^2.8.1" @@ -6443,17 +5557,14 @@ servify@^0.1.12: set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= set-immediate-shim@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= set-value@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" - integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -6463,7 +5574,6 @@ set-value@^0.4.3: set-value@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" - integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -6473,22 +5583,18 @@ set-value@^2.0.0: setimmediate@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f" - integrity sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48= setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" - integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== sha.js@^2.4.0, sha.js@^2.4.8: version "2.4.11" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== dependencies: inherits "^2.0.1" safe-buffer "^5.0.1" @@ -6496,35 +5602,30 @@ sha.js@^2.4.0, sha.js@^2.4.8: sha3@^1.1.0: version "1.2.2" resolved "https://registry.yarnpkg.com/sha3/-/sha3-1.2.2.tgz#a66c5098de4c25bc88336ec8b4817d005bca7ba9" - integrity sha1-pmxQmN5MJbyIM27ItIF9AFvKe6k= dependencies: nan "2.10.0" shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= shelljs@^0.7.4: version "0.7.8" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" - integrity sha1-3svPh0sNHl+3LhSxZKloMEjprLM= dependencies: glob "^7.0.0" interpret "^1.0.0" rechoir "^0.6.2" -shelljs@^0.8.1, shelljs@^0.8.2: +shelljs@^0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.2.tgz#345b7df7763f4c2340d584abb532c5f752ca9e35" - integrity sha512-pRXeNrCA2Wd9itwhvLp5LZQvPJ0wU6bcjaTMywHHGX5XWhVN2nzSu7WV0q+oUY7mGK3mgSkDDzP3MgjqdyIgbQ== dependencies: glob "^7.0.0" interpret "^1.0.0" @@ -6533,17 +5634,14 @@ shelljs@^0.8.1, shelljs@^0.8.2: signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= simple-concat@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" - integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY= simple-get@^2.7.0: version "2.8.1" resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" - integrity sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw== dependencies: decompress-response "^3.3.0" once "^1.3.1" @@ -6552,19 +5650,16 @@ simple-get@^2.7.0: slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= slice-ansi@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" - integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== dependencies: is-fullwidth-code-point "^2.0.0" snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== dependencies: define-property "^1.0.0" isobject "^3.0.0" @@ -6573,14 +5668,12 @@ snapdragon-node@^2.0.1: snapdragon-util@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== dependencies: kind-of "^3.2.0" snapdragon@^0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== dependencies: base "^0.11.1" debug "^2.2.0" @@ -6594,22 +5687,18 @@ snapdragon@^0.8.1: sol-digger@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/sol-digger/-/sol-digger-0.0.2.tgz#406c4a9d31e269e7f88eb1c2ea101318e5e09025" - integrity sha1-QGxKnTHiaef4jrHC6hATGOXgkCU= sol-explore@1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/sol-explore/-/sol-explore-1.6.1.tgz#b59f073c69fe332560d5a10c32ba8ca7f2986cfb" - integrity sha1-tZ8HPGn+MyVg1aEMMrqMp/KYbPs= sol-explore@^1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/sol-explore/-/sol-explore-1.6.2.tgz#43ae8c419fd3ac056a05f8a9d1fb1022cd41ecc2" - integrity sha1-Q66MQZ/TrAVqBfip0fsQIs1B7MI= sol-merger@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/sol-merger/-/sol-merger-0.1.2.tgz#1f12500f42d427dc0ec8e4c113392acd8a6f62d9" - integrity sha512-12Z84jxeb5VFlQOGS38HOiTrHYohU07oQ5wHOcFJmcRRbaL5kWN7IcldMO1QdW8kONyKdj0xhukzLlN5m5ix4w== dependencies: bluebird "^3.5.0" cli-color "^1.2.0" @@ -6621,7 +5710,6 @@ sol-merger@^0.1.2: solc@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/solc/-/solc-0.4.24.tgz#354f14b269b38cbaa82a47d1ff151723502b954e" - integrity sha512-2xd7Cf1HeVwrIb6Bu1cwY2/TaLRodrppCq3l7rhLimFQgmxptXhTC3+/wesVLpB09F1A2kZgvbMOgH7wvhFnBQ== dependencies: fs-extra "^0.30.0" memorystream "^0.3.1" @@ -6632,7 +5720,6 @@ solc@0.4.24: solc@^0.4.19, solc@^0.4.2, solc@^0.4.24: version "0.4.25" resolved "https://registry.yarnpkg.com/solc/-/solc-0.4.25.tgz#06b8321f7112d95b4b903639b1138a4d292f5faa" - integrity sha512-jU1YygRVy6zatgXrLY2rRm7HW1d7a8CkkEgNJwvH2VLpWhMFsMdWcJn6kUqZwcSz/Vm+w89dy7Z/aB5p6AFTrg== dependencies: fs-extra "^0.30.0" memorystream "^0.3.1" @@ -6643,7 +5730,6 @@ solc@^0.4.19, solc@^0.4.2, solc@^0.4.24: solidity-coverage@^0.5.11: version "0.5.11" resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.5.11.tgz#1ee45f6d98b75a615aadb8f9aa7db4a2b32258e7" - integrity sha512-qikdsSi6+9XbfvwA0aI7HUVpF9fIFNqRWTw23M89GMDY+b6Gj0wWU9IngJS0fimoZIAdEp3bfChxvpfVcrUesg== dependencies: death "^1.1.0" ethereumjs-testrpc-sc "6.1.6" @@ -6659,7 +5745,6 @@ solidity-coverage@^0.5.11: solidity-docgen@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/solidity-docgen/-/solidity-docgen-0.1.0.tgz#f3a56ff074e8c7d832af3a3d462c3b5abf0f64cb" - integrity sha512-F7ufNWmlP5c5hIi66Ijv9tc+HNosyO7ijWq6pRtyBR1WqyJBH/0DJkD6QZI8HkE8p6LEXiPKxGBWbAeVT9Nu9g== dependencies: commander "^2.14.1" lodash "^4.17.5" @@ -6672,7 +5757,6 @@ solidity-docgen@^0.1.0: solidity-parser-sc@0.4.11: version "0.4.11" resolved "https://registry.yarnpkg.com/solidity-parser-sc/-/solidity-parser-sc-0.4.11.tgz#86734c9205537007f4d6201b57176e41696ee607" - integrity sha512-1kV5iC7m3CtMDfmHaVNwz2saSGQVIuF16rIxU417Al38MVCWHMQQ5vT6cmLsNwDe60S74auobWij9vNawSeOyw== dependencies: mocha "^4.1.0" pegjs "^0.10.0" @@ -6681,12 +5765,10 @@ solidity-parser-sc@0.4.11: solium-plugin-security@0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/solium-plugin-security/-/solium-plugin-security-0.1.1.tgz#2a87bcf8f8c3abf7d198e292e4ac080284e3f3f6" - integrity sha512-kpLirBwIq4mhxk0Y/nn5cQ6qdJTI+U1LO3gpoNIcqNaW+sI058moXBe2UiHs+9wvF9IzYD49jcKhFTxcR9u9SQ== solium@^1.1.6: version "1.1.8" resolved "https://registry.yarnpkg.com/solium/-/solium-1.1.8.tgz#35d30a15c572a233ce8a90226d6cfccb762fadb7" - integrity sha512-fn0lusM6of14CytIDDHK73SGjn6NsVTaCVJjaKCKJyqKhT00rH/hDtvnIeZ2ZTD9z/xaXd4Js2brW3az6AV9RA== dependencies: ajv "^5.2.2" chokidar "^1.6.0" @@ -6704,7 +5786,6 @@ solium@^1.1.6: solparse@2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/solparse/-/solparse-2.2.5.tgz#72709c867cd6bfc50ec2325f4b81d2b3ea365d99" - integrity sha512-t7tvtR6KU6QfPYLMv1nlCh9DA8HYIu5tbjHpKu0fhGFZ1NuSp0KKDHfFHv07g6v1xgcuUY3rVqNFjZt5b9+5qA== dependencies: mocha "^4.0.1" pegjs "^0.10.0" @@ -6713,17 +5794,14 @@ solparse@2.2.5: sorted-array-functions@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/sorted-array-functions/-/sorted-array-functions-1.2.0.tgz#43265b21d6e985b7df31621b1c11cc68d8efc7c3" - integrity sha512-sWpjPhIZJtqO77GN+LD8dDsDKcWZ9GCOJNqKzi1tvtjGIzwfoyuRH8S0psunmc6Z5P+qfDqztSbwYR5X/e1UTg== source-list-map@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" - integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== source-map-resolve@^0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== dependencies: atob "^2.1.1" decode-uri-component "^0.2.0" @@ -6734,14 +5812,12 @@ source-map-resolve@^0.5.0: source-map-support@^0.4.15: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== dependencies: source-map "^0.5.6" source-map-support@^0.5.3: version "0.5.9" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" - integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -6749,29 +5825,24 @@ source-map-support@^0.5.3: source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== source-map@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" - integrity sha1-2rc/vPwrqBm03gO9b26qSBZLP50= dependencies: amdefine ">=0.0.4" spdx-correct@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.2.tgz#19bb409e91b47b1ad54159243f7312a858db3c2e" - integrity sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" @@ -6779,12 +5850,10 @@ spdx-correct@^3.0.0: spdx-exceptions@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" - integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== spdx-expression-parse@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" @@ -6792,29 +5861,24 @@ spdx-expression-parse@^3.0.0: spdx-license-ids@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz#e2a303236cac54b04031fa7a5a79c7e701df852f" - integrity sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w== split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== dependencies: extend-shallow "^3.0.0" sprintf-js@>=1.0.3: version "1.1.1" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" - integrity sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw= sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sshpk@^1.7.0: version "1.15.1" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.15.1.tgz#b79a089a732e346c6e0714830f36285cd38191a2" - integrity sha512-mSdgNUaidk+dRU5MhYtN9zebdzF2iG0cNPWy8HG+W8y+fT1JnSkh0fzzpjOa0L7P8i1Rscz38t0h4gPcKz43xA== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -6829,12 +5893,10 @@ sshpk@^1.7.0: stack-trace@0.0.x: version "0.0.10" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" - integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= dependencies: define-property "^0.2.5" object-copy "^0.1.0" @@ -6842,27 +5904,22 @@ static-extend@^0.1.1: "statuses@>= 1.4.0 < 2": version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= statuses@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" - integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== stdio@^0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/stdio/-/stdio-0.2.7.tgz#a1c57da10fe1cfaa0c3bf683c9d0743d1b660839" - integrity sha1-ocV9oQ/hz6oMO/aDydB0PRtmCDk= stealthy-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" - integrity sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds= dependencies: inherits "~2.0.1" readable-stream "^2.0.2" @@ -6870,7 +5927,6 @@ stream-browserify@^2.0.1: stream-http@^2.7.2: version "2.8.3" resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" - integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== dependencies: builtin-status-codes "^3.0.0" inherits "^2.0.1" @@ -6881,22 +5937,10 @@ stream-http@^2.7.2: strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= - -string-extended@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/string-extended/-/string-extended-0.0.8.tgz#741957dff487b0272a79eec5a44f239ee6f17ccd" - integrity sha1-dBlX3/SHsCcqee7FpE8jnubxfM0= - dependencies: - array-extended "~0.0.5" - date-extended "~0.0.3" - extended "~0.0.3" - is-extended "~0.0.3" string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -6905,7 +5949,6 @@ string-width@^1.0.1: "string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" @@ -6913,7 +5956,6 @@ string-width@^1.0.1: string.prototype.trim@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea" - integrity sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo= dependencies: define-properties "^1.1.2" es-abstract "^1.5.0" @@ -6922,109 +5964,92 @@ string.prototype.trim@~1.1.2: string_decoder@^1.0.0, string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= dependencies: ansi-regex "^2.0.0" strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= dependencies: ansi-regex "^3.0.0" strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= dependencies: is-utf8 "^0.2.0" strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= strip-dirs@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" - integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== dependencies: is-natural-number "^4.0.1" strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= strip-hex-prefix@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" - integrity sha1-DF8VX+8RUTczd96du1iNoFUA428= dependencies: is-hex-prefixed "1.0.0" strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= supports-color@4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" - integrity sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ== dependencies: has-flag "^2.0.0" supports-color@5.4.0: version "5.4.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" - integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== dependencies: has-flag "^3.0.0" supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= supports-color@^3.1.0: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" - integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= dependencies: has-flag "^1.0.0" supports-color@^4.2.1: version "4.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" - integrity sha1-vnoN5ITexcXN34s9WRJQRJEvY1s= dependencies: has-flag "^2.0.0" supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" swarm-js@0.1.37: version "0.1.37" resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.37.tgz#27d485317a340bbeec40292af783cc10acfa4663" - integrity sha512-G8gi5fcXP/2upwiuOShJ258sIufBVztekgobr3cVgYXObZwJ5AXLqZn52AI+/ffft29pJexF9WNdUxjlkVehoQ== dependencies: bluebird "^3.5.0" buffer "^5.0.5" @@ -7043,7 +6068,6 @@ swarm-js@0.1.37: table@4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" - integrity sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA== dependencies: ajv "^5.2.3" ajv-keywords "^2.1.0" @@ -7055,12 +6079,10 @@ table@4.0.2: tapable@^0.2.7: version "0.2.8" resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22" - integrity sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI= tape@^4.4.0, tape@^4.6.3: version "4.9.1" resolved "https://registry.yarnpkg.com/tape/-/tape-4.9.1.tgz#1173d7337e040c76fbf42ec86fcabedc9b3805c9" - integrity sha512-6fKIXknLpoe/Jp4rzHKFPpJUHDHDqn8jus99IfPnHIjyz78HYlefTGD3b5EkbQzuLfaEvmfPK3IolLgq2xT3kw== dependencies: deep-equal "~1.0.1" defined "~1.0.0" @@ -7079,7 +6101,6 @@ tape@^4.4.0, tape@^4.6.3: tar-stream@^1.5.2: version "1.6.2" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" - integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== dependencies: bl "^1.0.0" buffer-alloc "^1.2.0" @@ -7092,7 +6113,6 @@ tar-stream@^1.5.2: tar.gz@^1.0.5: version "1.0.7" resolved "https://registry.yarnpkg.com/tar.gz/-/tar.gz-1.0.7.tgz#577ef2c595faaa73452ef0415fed41113212257b" - integrity sha512-uhGatJvds/3diZrETqMj4RxBR779LKlIE74SsMcn5JProZsfs9j0QBwWO1RW+IWNJxS2x8Zzra1+AW6OQHWphg== dependencies: bluebird "^2.9.34" commander "^2.8.1" @@ -7103,7 +6123,6 @@ tar.gz@^1.0.5: tar@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= dependencies: block-stream "*" fstream "^1.0.2" @@ -7112,7 +6131,6 @@ tar@^2.1.1: tar@^4: version "4.4.6" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" - integrity sha512-tMkTnh9EdzxyfW+6GK6fCahagXsnYk6kE6S9Gr9pjVdys769+laCTbodXDhPAjzVtEBazRgP0gYqOjnk9dQzLg== dependencies: chownr "^1.0.1" fs-minipass "^1.2.5" @@ -7125,7 +6143,6 @@ tar@^4: taskgroup@^4.0.5, taskgroup@^4.2.0: version "4.3.1" resolved "https://registry.yarnpkg.com/taskgroup/-/taskgroup-4.3.1.tgz#7de193febd768273c457730497024d512c27915a" - integrity sha1-feGT/r12gnPEV3MElwJNUSwnkVo= dependencies: ambi "^2.2.0" csextends "^1.0.3" @@ -7133,43 +6150,36 @@ taskgroup@^4.0.5, taskgroup@^4.2.0: text-table@^0.2.0, text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= thenify-all@^1.0.0, thenify-all@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= dependencies: thenify ">= 3.1.0 < 4" "thenify@>= 3.1.0 < 4": version "3.3.0" resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839" - integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk= dependencies: any-promise "^1.0.0" through@^2.3.6, through@~2.3.4, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= timed-out@^4.0.0, timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= timers-browserify@^2.0.4: version "2.0.10" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" - integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg== dependencies: setimmediate "^1.0.4" timers-ext@^0.1.5: version "0.1.7" resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" - integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ== dependencies: es5-ext "~0.10.46" next-tick "1" @@ -7177,7 +6187,6 @@ timers-ext@^0.1.5: tingodb@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/tingodb/-/tingodb-0.6.1.tgz#f63336259af7dfa6c90dfe2556a0dfb0d4eede59" - integrity sha1-9jM2JZr336bJDf4lVqDfsNTu3lk= dependencies: lodash "^4.17.5" safe "^0.4.5" @@ -7188,36 +6197,30 @@ tingodb@^0.6.1: tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== dependencies: os-tmpdir "~1.0.2" to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= to-buffer@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" - integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= dependencies: is-number "^3.0.0" repeat-string "^1.6.1" @@ -7225,7 +6228,6 @@ to-regex-range@^2.1.0: to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== dependencies: define-property "^2.0.2" extend-shallow "^3.0.2" @@ -7235,7 +6237,6 @@ to-regex@^3.0.1, to-regex@^3.0.2: tough-cookie@>=2.3.3, tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" - integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== dependencies: psl "^1.1.24" punycode "^1.4.1" @@ -7243,27 +6244,22 @@ tough-cookie@>=2.3.3, tough-cookie@~2.4.3: tree-kill@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36" - integrity sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg== trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= trim@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" - integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= truffle-blockchain-utils@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/truffle-blockchain-utils/-/truffle-blockchain-utils-0.0.5.tgz#a4e5c064dadd69f782a137f3d276d21095da7a47" - integrity sha1-pOXAZNrdafeCoTfz0nbSEJXaekc= truffle-contract-schema@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/truffle-contract-schema/-/truffle-contract-schema-2.0.1.tgz#9bf821d32e26e674ba15eb5d40f96b10b1c9d568" - integrity sha1-m/gh0y4m5nS6FetdQPlrELHJ1Wg= dependencies: ajv "^5.1.1" crypto-js "^3.1.9-1" @@ -7272,7 +6268,6 @@ truffle-contract-schema@^2.0.1: truffle-contract@^3.0.4: version "3.0.6" resolved "https://registry.yarnpkg.com/truffle-contract/-/truffle-contract-3.0.6.tgz#2ef6fc32d7faafa9f4aed8e50001a9fdea342192" - integrity sha1-Lvb8Mtf6r6n0rtjlAAGp/eo0IZI= dependencies: ethjs-abi "0.1.8" truffle-blockchain-utils "^0.0.5" @@ -7283,12 +6278,10 @@ truffle-contract@^3.0.4: truffle-error@^0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/truffle-error/-/truffle-error-0.0.3.tgz#4bf55242e14deee1c7194932709182deff2c97ca" - integrity sha1-S/VSQuFN7uHHGUkycJGC3v8sl8o= truffle-hdwallet-provider-privkey@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/truffle-hdwallet-provider-privkey/-/truffle-hdwallet-provider-privkey-0.1.0.tgz#9417047a74ad37d923df926154b6486ffb57f6c9" - integrity sha512-Vj04yr2d9qLRZspoHztbE/YQnVaoFb90JNZHtggRUm+JFm/NOiSJHLVI63+3mtUIuQ04EuKZ7Df8JQw0Ni7IeA== dependencies: ethereumjs-tx "^1.3.3" ethereumjs-wallet "^0.6.0" @@ -7298,7 +6291,6 @@ truffle-hdwallet-provider-privkey@^0.1.0: truffle-wallet-provider@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/truffle-wallet-provider/-/truffle-wallet-provider-0.0.5.tgz#db59ce6fa1c558766011137509a94dfca8d1408e" - integrity sha1-21nOb6HFWHZgERN1CalN/KjRQI4= dependencies: ethereumjs-wallet "^0.6.0" web3 "^0.18.2" @@ -7307,7 +6299,6 @@ truffle-wallet-provider@0.0.5: truffle@^4.1.13: version "4.1.14" resolved "https://registry.yarnpkg.com/truffle/-/truffle-4.1.14.tgz#8d2c298e29abf9b1e486e44ff9faca6d34bb9030" - integrity sha512-e7tTLvKP3bN9dE7MagfWyFjy4ZgoEGbeujECy1me1ENBzbj/aO/+45gs72qsL3+3IkCNNcWNOJjjrm8BYZZNNg== dependencies: mocha "^4.1.0" original-require "1.0.1" @@ -7316,36 +6307,30 @@ truffle@^4.1.13: tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= dependencies: safe-buffer "^5.0.1" tweetnacl@0.13.2: version "0.13.2" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.13.2.tgz#453161770469d45cd266c36404e2bc99a8fa9944" - integrity sha1-RTFhdwRp1FzSZsNkBOK8maj6mUQ= tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= dependencies: prelude-ls "~1.1.2" type-is@~1.6.16: version "1.6.16" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" - integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== dependencies: media-typer "0.3.0" mime-types "~2.1.18" @@ -7353,36 +6338,30 @@ type-is@~1.6.16: typechecker@^2.0.8: version "2.1.0" resolved "https://registry.yarnpkg.com/typechecker/-/typechecker-2.1.0.tgz#d1c2093a54ff8a19f58cff877eeaa54f2242d383" - integrity sha1-0cIJOlT/ihn1jP+HfuqlTyJC04M= typechecker@^4.3.0: version "4.6.0" resolved "https://registry.yarnpkg.com/typechecker/-/typechecker-4.6.0.tgz#d245d9c2df21147d5e2a942fff170b68ece73c87" - integrity sha512-83OrXpyP3LNr7aRbLkt2nkjE/d7q8su8/uRvrKxCpswqVCVGOgyaKpaz8/MTjQqBYe4eLNuJ44pNakFZKqyPMA== dependencies: editions "^2.0.2" typechecker@~2.0.1: version "2.0.8" resolved "https://registry.yarnpkg.com/typechecker/-/typechecker-2.0.8.tgz#e83da84bb64c584ccb345838576c40b0337db82e" - integrity sha1-6D2oS7ZMWEzLNFg4V2xAsDN9uC4= typedarray-to-buffer@^3.1.2: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== dependencies: is-typedarray "^1.0.0" typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= uglify-js@^2.8.29: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" - integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0= dependencies: source-map "~0.5.1" yargs "~3.10.0" @@ -7392,7 +6371,6 @@ uglify-js@^2.8.29: uglify-js@^3.1.4: version "3.4.9" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" - integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q== dependencies: commander "~2.17.1" source-map "~0.6.1" @@ -7400,12 +6378,10 @@ uglify-js@^3.1.4: uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc= uglifyjs-webpack-plugin@^0.4.6: version "0.4.6" resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309" - integrity sha1-uVH0q7a9YX5m9j64kUmOORdj4wk= dependencies: source-map "^0.5.6" uglify-js "^2.8.29" @@ -7414,12 +6390,10 @@ uglifyjs-webpack-plugin@^0.4.6: ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== unbzip2-stream@^1.0.9: version "1.3.1" resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz#7854da51622a7e63624221196357803b552966a1" - integrity sha512-fIZnvdjblYs7Cru/xC6tCPVhz7JkYcVQQkePwMLyQELzYTds2Xn8QefPVnvdVhhZqubxNA1cASXEH5wcK0Bucw== dependencies: buffer "^3.0.1" through "^2.3.6" @@ -7427,17 +6401,14 @@ unbzip2-stream@^1.0.9: underscore@1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" - integrity sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI= underscore@^1.8.3: version "1.9.1" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" - integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" - integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= dependencies: arr-union "^3.1.0" get-value "^2.0.6" @@ -7447,22 +6418,18 @@ union-value@^1.0.0: universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== unorm@^1.3.3: version "1.4.1" resolved "https://registry.yarnpkg.com/unorm/-/unorm-1.4.1.tgz#364200d5f13646ca8bcd44490271335614792300" - integrity sha1-NkIA1fE2RsqLzURJAnEzVhR5IwA= unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= dependencies: has-value "^0.3.1" isobject "^3.0.0" @@ -7470,41 +6437,34 @@ unset-value@^1.0.0: upath@^1.0.5: version "1.1.0" resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" - integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== dependencies: punycode "^2.1.0" urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= url-parse-lax@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= dependencies: prepend-http "^1.0.1" url-set-query@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" - integrity sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk= url-to-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" - integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= dependencies: punycode "1.3.2" querystring "0.2.0" @@ -7512,66 +6472,65 @@ url@^0.11.0: use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== utf8@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.1.tgz#2e01db02f7d8d0944f77104f1609eb0c304cf768" - integrity sha1-LgHbAvfY0JRPdxBPFgnrDDBM92g= utf8@^2.1.1, utf8@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96" - integrity sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY= utf8@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" - integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= util@0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= dependencies: inherits "2.0.1" util@^0.10.3: version "0.10.4" resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" - integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== dependencies: inherits "2.0.3" +utile@0.3.x: + version "0.3.0" + resolved "https://registry.yarnpkg.com/utile/-/utile-0.3.0.tgz#1352c340eb820e4d8ddba039a4fbfaa32ed4ef3a" + dependencies: + async "~0.9.0" + deep-equal "~0.2.1" + i "0.3.x" + mkdirp "0.x.x" + ncp "1.0.x" + rimraf "2.x.x" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= uuid@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac" - integrity sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w= uuid@^3.0.1, uuid@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== valid-url@^1.0.9: version "1.0.9" resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200" - integrity sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA= validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" @@ -7579,17 +6538,14 @@ validate-npm-package-license@^3.0.1: varint@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.0.tgz#d826b89f7490732fabc0c0ed693ed475dcb29ebf" - integrity sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8= vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= dependencies: assert-plus "^1.0.0" core-util-is "1.0.2" @@ -7598,14 +6554,12 @@ verror@1.10.0: vm-browserify@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" - integrity sha1-XX6kW7755Kb/ZflUOOCofDV9WnM= dependencies: indexof "0.0.1" watchpack@^1.4.0: version "1.6.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" - integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== dependencies: chokidar "^2.0.2" graceful-fs "^4.1.2" @@ -7614,7 +6568,6 @@ watchpack@^1.4.0: watchr@~2.4.13: version "2.4.13" resolved "https://registry.yarnpkg.com/watchr/-/watchr-2.4.13.tgz#d74847bb4d6f90f61fe2c74f9f68662aa0e07601" - integrity sha1-10hHu01vkPYf4sdPn2hmKqDgdgE= dependencies: eachr "^2.0.2" extendr "^2.1.0" @@ -7628,7 +6581,6 @@ watchr@~2.4.13: web3-bzz@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.0.0-beta.34.tgz#068d37777ab65e5c60f8ec8b9a50cfe45277929c" - integrity sha1-Bo03d3q2Xlxg+OyLmlDP5FJ3kpw= dependencies: got "7.1.0" swarm-js "0.1.37" @@ -7637,7 +6589,6 @@ web3-bzz@1.0.0-beta.34: web3-core-helpers@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.34.tgz#b168da00d3e19e156bc15ae203203dd4dfee2d03" - integrity sha1-sWjaANPhnhVrwVriAyA91N/uLQM= dependencies: underscore "1.8.3" web3-eth-iban "1.0.0-beta.34" @@ -7646,7 +6597,6 @@ web3-core-helpers@1.0.0-beta.34: web3-core-method@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.0.0-beta.34.tgz#ec163c8a2c490fa02a7ec15559fa7307fc7cc6dd" - integrity sha1-7BY8iixJD6AqfsFVWfpzB/x8xt0= dependencies: underscore "1.8.3" web3-core-helpers "1.0.0-beta.34" @@ -7657,7 +6607,6 @@ web3-core-method@1.0.0-beta.34: web3-core-promievent@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.0.0-beta.34.tgz#a4f4fa6784bb293e82c60960ae5b56a94cd03edc" - integrity sha1-pPT6Z4S7KT6CxglgrltWqUzQPtw= dependencies: any-promise "1.3.0" eventemitter3 "1.1.1" @@ -7665,7 +6614,6 @@ web3-core-promievent@1.0.0-beta.34: web3-core-requestmanager@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.0.0-beta.34.tgz#01f8f6cf2ae6b6f0b70c38bae1ef741b5bab215c" - integrity sha1-Afj2zyrmtvC3DDi64e90G1urIVw= dependencies: underscore "1.8.3" web3-core-helpers "1.0.0-beta.34" @@ -7676,7 +6624,6 @@ web3-core-requestmanager@1.0.0-beta.34: web3-core-subscriptions@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.34.tgz#9fed144033f221c3cf21060302ffdaf5ef2de2de" - integrity sha1-n+0UQDPyIcPPIQYDAv/a9e8t4t4= dependencies: eventemitter3 "1.1.1" underscore "1.8.3" @@ -7685,7 +6632,6 @@ web3-core-subscriptions@1.0.0-beta.34: web3-core@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.0.0-beta.34.tgz#121be8555e9fb00d2c5d05ddd3381d0c9e46987e" - integrity sha1-EhvoVV6fsA0sXQXd0zgdDJ5GmH4= dependencies: web3-core-helpers "1.0.0-beta.34" web3-core-method "1.0.0-beta.34" @@ -7695,7 +6641,6 @@ web3-core@1.0.0-beta.34: web3-eth-abi@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.34.tgz#034533e3aa2f7e59ff31793eaea685c0ed5af67a" - integrity sha1-A0Uz46ovfln/MXk+rqaFwO1a9no= dependencies: bn.js "4.11.6" underscore "1.8.3" @@ -7705,7 +6650,6 @@ web3-eth-abi@1.0.0-beta.34: web3-eth-accounts@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.34.tgz#e09142eeecc797ac3459b75e9b23946d3695f333" - integrity sha1-4JFC7uzHl6w0WbdemyOUbTaV8zM= dependencies: any-promise "1.3.0" crypto-browserify "3.12.0" @@ -7721,7 +6665,6 @@ web3-eth-accounts@1.0.0-beta.34: web3-eth-contract@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.34.tgz#9dbb38fae7643a808427a20180470ec7415c91e6" - integrity sha1-nbs4+udkOoCEJ6IBgEcOx0FckeY= dependencies: underscore "1.8.3" web3-core "1.0.0-beta.34" @@ -7735,7 +6678,6 @@ web3-eth-contract@1.0.0-beta.34: web3-eth-iban@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.34.tgz#9af458605867ccf74ea979aaf326b38ba6a5ba0c" - integrity sha1-mvRYYFhnzPdOqXmq8yazi6alugw= dependencies: bn.js "4.11.6" web3-utils "1.0.0-beta.34" @@ -7743,7 +6685,6 @@ web3-eth-iban@1.0.0-beta.34: web3-eth-personal@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.34.tgz#9afba167342ebde5420bcd5895c3f6c34388f205" - integrity sha1-mvuhZzQuveVCC81YlcP2w0OI8gU= dependencies: web3-core "1.0.0-beta.34" web3-core-helpers "1.0.0-beta.34" @@ -7754,7 +6695,6 @@ web3-eth-personal@1.0.0-beta.34: web3-eth@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.0.0-beta.34.tgz#74086000850c6fe6f535ef49837d6d4bb6113268" - integrity sha1-dAhgAIUMb+b1Ne9Jg31tS7YRMmg= dependencies: underscore "1.8.3" web3-core "1.0.0-beta.34" @@ -7772,7 +6712,6 @@ web3-eth@1.0.0-beta.34: web3-net@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.0.0-beta.34.tgz#427cea2f431881449c8e38d523290f173f9ff63d" - integrity sha1-QnzqL0MYgUScjjjVIykPFz+f9j0= dependencies: web3-core "1.0.0-beta.34" web3-core-method "1.0.0-beta.34" @@ -7781,7 +6720,6 @@ web3-net@1.0.0-beta.34: web3-provider-engine@^13.6.4: version "13.8.0" resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz#4c7c1ad2af5f1fe10343b8a65495879a2f9c00df" - integrity sha512-fZXhX5VWwWpoFfrfocslyg6P7cN3YWPG/ASaevNfeO80R+nzgoPUBXcWQekSGSsNDkeRTis4aMmpmofYf1TNtQ== dependencies: async "^2.5.0" clone "^2.0.0" @@ -7806,7 +6744,6 @@ web3-provider-engine@^13.6.4: web3-provider-engine@^8.4.0: version "8.6.1" resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-8.6.1.tgz#4d86e19e30caaf97df351511ec0f60136e5b30eb" - integrity sha1-TYbhnjDKr5ffNRUR7A9gE25bMOs= dependencies: async "^2.1.2" clone "^2.0.0" @@ -7826,7 +6763,6 @@ web3-provider-engine@^8.4.0: web3-providers-http@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.0.0-beta.34.tgz#e561b52bbb43766282007d40285bfe3550c27e7a" - integrity sha1-5WG1K7tDdmKCAH1AKFv+NVDCfno= dependencies: web3-core-helpers "1.0.0-beta.34" xhr2 "0.1.4" @@ -7834,7 +6770,6 @@ web3-providers-http@1.0.0-beta.34: web3-providers-ipc@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.0.0-beta.34.tgz#a1b77f1a306d73649a9c039052e40cb71328d00a" - integrity sha1-obd/GjBtc2SanAOQUuQMtxMo0Ao= dependencies: oboe "2.1.3" underscore "1.8.3" @@ -7843,7 +6778,6 @@ web3-providers-ipc@1.0.0-beta.34: web3-providers-ws@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.0.0-beta.34.tgz#7de70f1b83f2de36476772156becfef6e3516eb3" - integrity sha1-fecPG4Py3jZHZ3IVa+z+9uNRbrM= dependencies: underscore "1.8.3" web3-core-helpers "1.0.0-beta.34" @@ -7852,7 +6786,6 @@ web3-providers-ws@1.0.0-beta.34: web3-shh@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.0.0-beta.34.tgz#975061d71eaec42ccee576f7bd8f70f03844afe0" - integrity sha1-l1Bh1x6uxCzO5Xb3vY9w8DhEr+A= dependencies: web3-core "1.0.0-beta.34" web3-core-method "1.0.0-beta.34" @@ -7862,7 +6795,6 @@ web3-shh@1.0.0-beta.34: web3-utils@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.0.0-beta.34.tgz#9411fc39aaef39ca4e06169f762297d9ff020970" - integrity sha1-lBH8OarvOcpOBhafdiKX2f8CCXA= dependencies: bn.js "4.11.6" eth-lib "0.1.27" @@ -7875,7 +6807,6 @@ web3-utils@1.0.0-beta.34: web3@0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/web3/-/web3-0.19.1.tgz#e763d5b1107c4bc24abd4f8cbee1ba3659e6eb31" - integrity sha1-52PVsRB8S8JKvU+MvuG6Nlnm6zE= dependencies: bignumber.js "^4.0.2" crypto-js "^3.1.4" @@ -7886,7 +6817,6 @@ web3@0.19.1: web3@0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/web3/-/web3-0.20.2.tgz#c54dac5fc0e377399c04c1a6ecbb12e4513278d6" - integrity sha1-xU2sX8DjdzmcBMGm7LsS5FEyeNY= dependencies: bignumber.js "git+https://github.com/frozeman/bignumber.js-nolookahead.git" crypto-js "^3.1.4" @@ -7897,7 +6827,6 @@ web3@0.20.2: web3@0.20.6: version "0.20.6" resolved "https://registry.yarnpkg.com/web3/-/web3-0.20.6.tgz#3e97306ae024fb24e10a3d75c884302562215120" - integrity sha1-PpcwauAk+yThCj11yIQwJWIhUSA= dependencies: bignumber.js "git+https://github.com/frozeman/bignumber.js-nolookahead.git" crypto-js "^3.1.4" @@ -7908,7 +6837,6 @@ web3@0.20.6: web3@1.0.0-beta.34: version "1.0.0-beta.34" resolved "https://registry.yarnpkg.com/web3/-/web3-1.0.0-beta.34.tgz#347e561b784098cb5563315f490479a1d91f2ab1" - integrity sha1-NH5WG3hAmMtVYzFfSQR5odkfKrE= dependencies: web3-bzz "1.0.0-beta.34" web3-core "1.0.0-beta.34" @@ -7921,7 +6849,6 @@ web3@1.0.0-beta.34: web3@^0.16.0: version "0.16.0" resolved "https://registry.yarnpkg.com/web3/-/web3-0.16.0.tgz#a4554175cd462943035b1f1d39432f741c6b6019" - integrity sha1-pFVBdc1GKUMDWx8dOUMvdBxrYBk= dependencies: bignumber.js "git+https://github.com/debris/bignumber.js#master" crypto-js "^3.1.4" @@ -7931,7 +6858,6 @@ web3@^0.16.0: web3@^0.18.2, web3@^0.18.4: version "0.18.4" resolved "https://registry.yarnpkg.com/web3/-/web3-0.18.4.tgz#81ec1784145491f2eaa8955b31c06049e07c5e7d" - integrity sha1-gewXhBRUkfLqqJVbMcBgSeB8Xn0= dependencies: bignumber.js "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" crypto-js "^3.1.4" @@ -7942,7 +6868,6 @@ web3@^0.18.2, web3@^0.18.4: web3@^0.20.5: version "0.20.7" resolved "https://registry.yarnpkg.com/web3/-/web3-0.20.7.tgz#1605e6d81399ed6f85a471a4f3da0c8be57df2f7" - integrity sha512-VU6/DSUX93d1fCzBz7WP/SGCQizO1rKZi4Px9j/3yRyfssHyFcZamMw2/sj4E8TlfMXONvZLoforR8B4bRoyTQ== dependencies: bignumber.js "git+https://github.com/frozeman/bignumber.js-nolookahead.git" crypto-js "^3.1.4" @@ -7953,7 +6878,6 @@ web3@^0.20.5: webpack-sources@^1.0.1: version "1.3.0" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" - integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== dependencies: source-list-map "^2.0.0" source-map "~0.6.1" @@ -7961,7 +6885,6 @@ webpack-sources@^1.0.1: webpack@^3.0.0: version "3.12.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.12.0.tgz#3f9e34360370602fcf639e97939db486f4ec0d74" - integrity sha512-Sw7MdIIOv/nkzPzee4o0EdvCuPmxT98+vVpIvwtcwcF1Q4SDSNp92vwcKc4REe7NItH9f1S4ra9FuQ7yuYZ8bQ== dependencies: acorn "^5.0.0" acorn-dynamic-import "^2.0.0" @@ -7998,46 +6921,50 @@ webpack@^3.0.0: whatwg-fetch@>=0.10.0: version "3.0.0" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" - integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" - integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= which@^1.1.1, which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: string-width "^1.0.2 || 2" window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0= window-size@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" - integrity sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU= + +winston@2.1.x: + version "2.1.1" + resolved "http://registry.npmjs.org/winston/-/winston-2.1.1.tgz#3c9349d196207fd1bdff9d4bc43ef72510e3a12e" + dependencies: + async "~1.0.0" + colors "1.0.x" + cycle "1.0.x" + eyes "0.1.x" + isstream "0.1.x" + pkginfo "0.3.x" + stack-trace "0.0.x" winston@^2.3.1: version "2.4.4" resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.4.tgz#a01e4d1d0a103cf4eada6fc1f886b3110d71c34b" - integrity sha512-NBo2Pepn4hK4V01UfcWcDlmiVTs7VTB1h7bgnB0rgP146bYhMxX0ypCz3lBOfNxCO4Zuek7yeT+y/zM1OfMw4Q== dependencies: async "~1.0.0" colors "1.0.x" @@ -8049,22 +6976,18 @@ winston@^2.3.1: wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8= wordwrap@^1.0.0, wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -8072,19 +6995,16 @@ wrap-ansi@^2.0.0: wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= write@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c= dependencies: mkdirp "^0.5.1" ws@^3.0.0: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" - integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== dependencies: async-limiter "~1.0.0" safe-buffer "~5.1.0" @@ -8093,14 +7013,12 @@ ws@^3.0.0: xhr-request-promise@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.2.tgz#343c44d1ee7726b8648069682d0f840c83b4261d" - integrity sha1-NDxE0e53JrhkgGloLQ+EDIO0Jh0= dependencies: xhr-request "^1.0.1" xhr-request@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" - integrity sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA== dependencies: buffer-to-arraybuffer "^0.0.5" object-assign "^4.1.1" @@ -8113,19 +7031,16 @@ xhr-request@^1.0.1: xhr2-cookies@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" - integrity sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg= dependencies: cookiejar "^2.1.1" xhr2@*, xhr2@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" - integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8= xhr@^2.0.4, xhr@^2.2.0, xhr@^2.3.3: version "2.5.0" resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.5.0.tgz#bed8d1676d5ca36108667692b74b316c496e49dd" - integrity sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ== dependencies: global "~4.3.0" is-function "^1.0.1" @@ -8135,49 +7050,40 @@ xhr@^2.0.4, xhr@^2.2.0, xhr@^2.3.3: xmlhttprequest@*, xmlhttprequest@1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" - integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw= xregexp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" - integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM= xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= xtend@~2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" - integrity sha1-bv7MKk2tjmlixJAbM3znuoe10os= dependencies: object-keys "~0.4.0" y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= yaeti@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" - integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc= yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= yallist@^3.0.0, yallist@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" - integrity sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k= yargs-parser@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" - integrity sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ= dependencies: camelcase "^3.0.0" lodash.assign "^4.0.6" @@ -8185,28 +7091,24 @@ yargs-parser@^2.4.1: yargs-parser@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" - integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k= dependencies: camelcase "^4.1.0" yargs-parser@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" - integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ== dependencies: camelcase "^4.1.0" yargs-parser@^9.0.2: version "9.0.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" - integrity sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc= dependencies: camelcase "^4.1.0" yargs@^10.0.3: version "10.1.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5" - integrity sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig== dependencies: cliui "^4.0.0" decamelize "^1.1.1" @@ -8224,7 +7126,6 @@ yargs@^10.0.3: yargs@^11.0.0: version "11.1.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" - integrity sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A== dependencies: cliui "^4.0.0" decamelize "^1.1.1" @@ -8242,7 +7143,6 @@ yargs@^11.0.0: yargs@^4.6.0, yargs@^4.7.1: version "4.8.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" - integrity sha1-wMQpJMpKqmsObaFznfshZDn53cA= dependencies: cliui "^3.2.0" decamelize "^1.1.1" @@ -8262,7 +7162,6 @@ yargs@^4.6.0, yargs@^4.7.1: yargs@^8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" - integrity sha1-YpmpBVsc78lp/355wdkY3Osiw2A= dependencies: camelcase "^4.1.0" cliui "^3.2.0" @@ -8281,7 +7180,6 @@ yargs@^8.0.2: yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E= dependencies: camelcase "^1.0.2" cliui "^2.1.0" @@ -8291,7 +7189,6 @@ yargs@~3.10.0: yauzl@^2.4.2: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= dependencies: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" From b172ce6fb95dfe6f2733b960bcea0e5f18302988 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Tue, 27 Nov 2018 17:51:11 +0200 Subject: [PATCH 58/93] Applied review comments (not finished) --- .../modules/Wallet/VestingEscrowWallet.sol | 117 +++++++++++------- test/z_vesting_escrow_wallet.js | 17 +-- 2 files changed, 79 insertions(+), 55 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index a1d98c7e0..e5226dda0 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -3,7 +3,6 @@ pragma solidity ^0.4.24; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; -import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol"; import "./IWallet.sol"; /** @@ -44,7 +43,8 @@ contract VestingEscrowWallet is IWallet { uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, - uint256 _startTime + uint256 _startTime, + uint256 _index ); event ModifySchedule( address indexed _beneficiary, @@ -54,7 +54,7 @@ contract VestingEscrowWallet is IWallet { uint256 _frequency, uint256 _startTime ); - event RevokeSchedules(address indexed _beneficiary); + event RevokeAllSchedules(address indexed _beneficiary); event RevokeSchedule(address indexed _beneficiary, uint256 _index); event DepositTokens(uint256 _numberOfTokens); event SendToTreasury(uint256 _numberOfTokens); @@ -178,6 +178,18 @@ contract VestingEscrowWallet is IWallet { ) public withPerm(ADMIN) + { + _addSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); + } + + function _addSchedule( + address _beneficiary, + uint256 _numberOfTokens, + uint256 _duration, + uint256 _frequency, + uint256 _startTime + ) + internal { _validateSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); if (_numberOfTokens > unassignedTokens) { @@ -189,7 +201,8 @@ contract VestingEscrowWallet is IWallet { beneficiaries.push(_beneficiary); } schedules[_beneficiary].push(Schedule(_numberOfTokens, 0, 0, _duration, _frequency, _startTime)); - emit AddSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); + uint256 index = schedules[_beneficiary].length - 1; + emit AddSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime, index); } /** @@ -205,7 +218,7 @@ contract VestingEscrowWallet is IWallet { function _addScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startTime) internal { require(_index < templates.length, "Template not found"); Template memory template = templates[_index]; - addSchedule(_beneficiary, template.numberOfTokens, template.duration, template.frequency, _startTime); + _addSchedule(_beneficiary, template.numberOfTokens, template.duration, template.frequency, _startTime); } /** @@ -227,6 +240,19 @@ contract VestingEscrowWallet is IWallet { ) public withPerm(ADMIN) + { + _modifySchedule(_beneficiary, _index, _numberOfTokens, _duration, _frequency, _startTime); + } + + function _modifySchedule( + address _beneficiary, + uint256 _index, + uint256 _numberOfTokens, + uint256 _duration, + uint256 _frequency, + uint256 _startTime + ) + internal { _validateSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); require(_index < schedules[_beneficiary].length, "Schedule not found"); @@ -234,12 +260,12 @@ contract VestingEscrowWallet is IWallet { /*solium-disable-next-line security/no-block-members*/ require(now < schedule.startTime, "Schedule started"); if (_numberOfTokens <= schedule.numberOfTokens) { - unassignedTokens = unassignedTokens.add(schedule.numberOfTokens - _numberOfTokens); + unassignedTokens = unassignedTokens.add(schedule.numberOfTokens.sub(_numberOfTokens)); } else { - if (_numberOfTokens - schedule.numberOfTokens > unassignedTokens) { - _depositTokens(_numberOfTokens - schedule.numberOfTokens - unassignedTokens); + if (_numberOfTokens.sub(schedule.numberOfTokens) > unassignedTokens) { + _depositTokens(_numberOfTokens.sub(schedule.numberOfTokens).sub(unassignedTokens)); } - unassignedTokens = unassignedTokens.sub(_numberOfTokens - schedule.numberOfTokens); + unassignedTokens = unassignedTokens.sub(_numberOfTokens.sub(schedule.numberOfTokens)); } schedules[_beneficiary][_index] = Schedule(_numberOfTokens, 0, 0, _duration, _frequency, _startTime); emit ModifySchedule(_beneficiary, _index, _numberOfTokens, _duration, _frequency, _startTime); @@ -255,14 +281,11 @@ contract VestingEscrowWallet is IWallet { require(_index < schedules[_beneficiary].length, "Schedule not found"); _sendTokens(_beneficiary); Schedule[] storage userSchedules = schedules[_beneficiary]; - unassignedTokens = unassignedTokens.add(userSchedules[_index].numberOfTokens - userSchedules[_index].releasedTokens); + unassignedTokens = unassignedTokens.add(userSchedules[_index].numberOfTokens.sub(userSchedules[_index].releasedTokens)); if (_index != userSchedules.length - 1) { userSchedules[_index] = userSchedules[userSchedules.length - 1]; } userSchedules.length--; - if (userSchedules.length == 0) { - _removeBeneficiary(_beneficiary); - } emit RevokeSchedule(_beneficiary, _index); } @@ -270,15 +293,19 @@ contract VestingEscrowWallet is IWallet { * @notice Revokes all beneficiary's schedules * @param _beneficiary beneficiary's address */ - function revokeSchedules(address _beneficiary) public withPerm(ADMIN) { + function revokeAllSchedules(address _beneficiary) public withPerm(ADMIN) { + _revokeAllSchedules(_beneficiary); + } + + function _revokeAllSchedules(address _beneficiary) internal { require(_beneficiary != address(0), "Invalid address"); _sendTokens(_beneficiary); - Schedule[] storage data = schedules[_beneficiary]; - for (uint256 i = 0; i < data.length; i++) { - unassignedTokens = unassignedTokens.add(data[i].numberOfTokens - data[i].releasedTokens); + Schedule[] storage userSchedules = schedules[_beneficiary]; + for (uint256 i = 0; i < userSchedules.length; i++) { + unassignedTokens = unassignedTokens.add(userSchedules[i].numberOfTokens.sub(userSchedules[i].releasedTokens)); } - _removeBeneficiary(_beneficiary); - emit RevokeSchedules(_beneficiary); + userSchedules.length = 0; + emit RevokeAllSchedules(_beneficiary); } /** @@ -296,11 +323,11 @@ contract VestingEscrowWallet is IWallet { schedule.duration, schedule.frequency, schedule.startTime, - _getScheduleState(_beneficiary, _index) + getScheduleState(_beneficiary, _index) ); } - function _getScheduleState(address _beneficiary, uint256 _index) internal view returns(State) { + function getScheduleState(address _beneficiary, uint256 _index) public view returns(State) { Schedule memory schedule = schedules[_beneficiary][_index]; if (now < schedule.startTime) { return State.CREATED; @@ -326,11 +353,7 @@ contract VestingEscrowWallet is IWallet { * @param _beneficiary beneficiary's address * @return available tokens for beneficiary */ - function getAvailableTokens(address _beneficiary) external view returns(uint256) { - return _getAvailableTokens(_beneficiary); - } - - function _getAvailableTokens(address _beneficiary) internal view returns(uint256) { + function getAvailableTokens(address _beneficiary) public view returns(uint256) { require(_beneficiary != address(0)); uint256 availableTokens; for (uint256 i = 0; i < schedules[_beneficiary].length; i++) { @@ -350,6 +373,22 @@ contract VestingEscrowWallet is IWallet { } } + /** + * @notice Used to remove beneficiaries without schedules + */ + function trimBeneficiaries() external withPerm(ADMIN) { + //TODO commented because of contract size +// for (uint256 i = 0; i < beneficiaries.length; i++) { +// if (schedules[beneficiaries[i]].length == 0) { +// delete schedules[beneficiaries[i]]; +// if (i != beneficiaries.length - 1) { +// beneficiaries[i] = beneficiaries[beneficiaries.length - 1]; +// } +// beneficiaries.length--; +// } +// } + } + /** * @notice Used to bulk add vesting schedules for each of beneficiaries * @param _beneficiaries array of beneficiary's addresses @@ -369,7 +408,7 @@ contract VestingEscrowWallet is IWallet { withPerm(ADMIN) { for (uint256 i = 0; i < _beneficiaries.length; i++) { - addSchedule(_beneficiaries[i], _numberOfTokens, _duration, _frequency, _startTime); + _addSchedule(_beneficiaries[i], _numberOfTokens, _duration, _frequency, _startTime); } } @@ -391,7 +430,7 @@ contract VestingEscrowWallet is IWallet { */ function revokeSchedulesMulti(address[] _beneficiaries) external withPerm(ADMIN) { for (uint256 i = 0; i < _beneficiaries.length; i++) { - revokeSchedules(_beneficiaries[i]); + _revokeAllSchedules(_beneficiaries[i]); } } @@ -417,7 +456,7 @@ contract VestingEscrowWallet is IWallet { { require(_beneficiaries.length == _indexes.length, "Arrays sizes mismatch"); for (uint256 i = 0; i < _beneficiaries.length; i++) { - modifySchedule(_beneficiaries[i], _indexes[i], _numberOfTokens, _duration, _frequency, _startTime); + _modifySchedule(_beneficiaries[i], _indexes[i], _numberOfTokens, _duration, _frequency, _startTime); } } @@ -444,7 +483,7 @@ contract VestingEscrowWallet is IWallet { } function _sendTokens(address _beneficiary) internal { - uint256 amount = _getAvailableTokens(_beneficiary); + uint256 amount = getAvailableTokens(_beneficiary); if (amount > 0) { for (uint256 i = 0; i < schedules[_beneficiary].length; i++) { schedules[_beneficiary][i].availableTokens = 0; @@ -471,7 +510,7 @@ contract VestingEscrowWallet is IWallet { } uint256 releasedTokens = schedule.numberOfTokens.mul(periodNumber).div(periodCount); if (schedule.releasedTokens < releasedTokens) { - schedule.availableTokens = schedule.availableTokens.add(releasedTokens - schedule.releasedTokens); + schedule.availableTokens = schedule.availableTokens.add(releasedTokens.sub(schedule.releasedTokens)); schedule.releasedTokens = releasedTokens; } } @@ -479,22 +518,6 @@ contract VestingEscrowWallet is IWallet { } } - function _removeBeneficiary(address _beneficiary) internal { - bool isFound = false; - uint256 index; - for (uint256 i = 0; i < beneficiaries.length; i++) { - if (_beneficiary == beneficiaries[i]) { - isFound = true; - index = i; - } - } - if (isFound && index != beneficiaries.length - 1) { - beneficiaries[index] = beneficiaries[beneficiaries.length - 1]; - } - beneficiaries.length--; - delete schedules[_beneficiary]; - } - /** * @notice Return the permissions flag that are associated with VestingEscrowWallet */ diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 9728f0140..6bebcff8e 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -366,7 +366,7 @@ contract('VestingEscrowWallet', accounts => { I_VestingEscrowWallet.modifySchedule(account_beneficiary3, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) ); - await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_admin}); + await I_VestingEscrowWallet.revokeAllSchedules(account_beneficiary3, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); @@ -393,7 +393,7 @@ contract('VestingEscrowWallet', accounts => { checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, COMPLETED); await I_SecurityToken.transfer(token_owner, balance, {from: account_beneficiary3}); - await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_admin}); + await I_VestingEscrowWallet.revokeAllSchedules(account_beneficiary3, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); @@ -451,7 +451,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(balance.toNumber(), totalNumberOfTokens); await I_SecurityToken.transfer(token_owner, balance, {from: account_beneficiary3}); - await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_admin}); + await I_VestingEscrowWallet.revokeAllSchedules(account_beneficiary3, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); @@ -675,7 +675,7 @@ contract('VestingEscrowWallet', accounts => { it("Should fail to revoke vesting schedules -- fail because address is invalid", async () => { await catchRevert( - I_VestingEscrowWallet.revokeSchedules(0, {from: wallet_admin}) + I_VestingEscrowWallet.revokeAllSchedules(0, {from: wallet_admin}) ); }); @@ -702,7 +702,7 @@ contract('VestingEscrowWallet', accounts => { it("Should not be able to revoke schedules -- fail because of permissions check", async () => { await catchRevert( - I_VestingEscrowWallet.revokeSchedules(account_beneficiary1, {from: account_beneficiary1}) + I_VestingEscrowWallet.revokeAllSchedules(account_beneficiary1, {from: account_beneficiary1}) ); }); @@ -721,7 +721,7 @@ contract('VestingEscrowWallet', accounts => { }); it("Should revoke 2 vesting schedules from the beneficiary address", async () => { - const tx = await I_VestingEscrowWallet.revokeSchedules(account_beneficiary2, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.revokeAllSchedules(account_beneficiary2, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); @@ -776,7 +776,7 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.updateAll({from: wallet_admin}); numberOfTokens = (2000 / 10 * stepCount); - const tx2 = await I_VestingEscrowWallet.revokeSchedules(account_beneficiary3, {from: wallet_admin}); + const tx2 = await I_VestingEscrowWallet.revokeAllSchedules(account_beneficiary3, {from: wallet_admin}); assert.equal(tx2.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx2.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); @@ -1006,7 +1006,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(balance.toNumber(), 5000); await I_SecurityToken.transfer(token_owner, balance, {from: beneficiary}); - await I_VestingEscrowWallet.revokeSchedules(beneficiary, {from: wallet_admin}); + await I_VestingEscrowWallet.revokeAllSchedules(beneficiary, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); } }); @@ -1073,6 +1073,7 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 0); } + await I_VestingEscrowWallet.trimBeneficiaries({from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); From 8c2b1408be7f22a258dba8f247be9a614fe4ca52 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Tue, 27 Nov 2018 22:03:25 +0200 Subject: [PATCH 59/93] get rid of updateAll function --- .../modules/Wallet/VestingEscrowWallet.sol | 101 ++++++++---------- test/z_vesting_escrow_wallet.js | 54 ++++------ 2 files changed, 65 insertions(+), 90 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index e5226dda0..275d12e96 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -15,8 +15,7 @@ contract VestingEscrowWallet is IWallet { struct Schedule { uint256 numberOfTokens; - uint256 releasedTokens; - uint256 availableTokens; + uint256 claimedTokens; uint256 duration; uint256 frequency; uint256 startTime; @@ -200,7 +199,7 @@ contract VestingEscrowWallet is IWallet { if (schedules[_beneficiary].length == 0) { beneficiaries.push(_beneficiary); } - schedules[_beneficiary].push(Schedule(_numberOfTokens, 0, 0, _duration, _frequency, _startTime)); + schedules[_beneficiary].push(Schedule(_numberOfTokens, 0, _duration, _frequency, _startTime)); uint256 index = schedules[_beneficiary].length - 1; emit AddSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime, index); } @@ -267,7 +266,7 @@ contract VestingEscrowWallet is IWallet { } unassignedTokens = unassignedTokens.sub(_numberOfTokens.sub(schedule.numberOfTokens)); } - schedules[_beneficiary][_index] = Schedule(_numberOfTokens, 0, 0, _duration, _frequency, _startTime); + schedules[_beneficiary][_index] = Schedule(_numberOfTokens, 0, _duration, _frequency, _startTime); emit ModifySchedule(_beneficiary, _index, _numberOfTokens, _duration, _frequency, _startTime); } @@ -279,9 +278,10 @@ contract VestingEscrowWallet is IWallet { function revokeSchedule(address _beneficiary, uint256 _index) external withPerm(ADMIN) { require(_beneficiary != address(0), "Invalid address"); require(_index < schedules[_beneficiary].length, "Schedule not found"); - _sendTokens(_beneficiary); + _sendTokens(_beneficiary, _index); Schedule[] storage userSchedules = schedules[_beneficiary]; - unassignedTokens = unassignedTokens.add(userSchedules[_index].numberOfTokens.sub(userSchedules[_index].releasedTokens)); + uint256 releasedTokens = _getReleasedTokens(_beneficiary, _index); + unassignedTokens = unassignedTokens.add(userSchedules[_index].numberOfTokens.sub(releasedTokens)); if (_index != userSchedules.length - 1) { userSchedules[_index] = userSchedules[userSchedules.length - 1]; } @@ -302,7 +302,8 @@ contract VestingEscrowWallet is IWallet { _sendTokens(_beneficiary); Schedule[] storage userSchedules = schedules[_beneficiary]; for (uint256 i = 0; i < userSchedules.length; i++) { - unassignedTokens = unassignedTokens.add(userSchedules[i].numberOfTokens.sub(userSchedules[i].releasedTokens)); + uint256 releasedTokens = _getReleasedTokens(_beneficiary, i); + unassignedTokens = unassignedTokens.add(userSchedules[i].numberOfTokens.sub(releasedTokens)); } userSchedules.length = 0; emit RevokeAllSchedules(_beneficiary); @@ -348,18 +349,26 @@ contract VestingEscrowWallet is IWallet { return schedules[_beneficiary].length; } - /** - * @notice Returns available tokens for beneficiary - * @param _beneficiary beneficiary's address - * @return available tokens for beneficiary - */ - function getAvailableTokens(address _beneficiary) public view returns(uint256) { - require(_beneficiary != address(0)); - uint256 availableTokens; - for (uint256 i = 0; i < schedules[_beneficiary].length; i++) { - availableTokens = availableTokens.add(schedules[_beneficiary][i].availableTokens); + function _getAvailableTokens(address _beneficiary, uint256 _index) internal view returns(uint256) { + Schedule storage schedule = schedules[_beneficiary][_index]; + uint256 releasedTokens = _getReleasedTokens(_beneficiary, _index); + return releasedTokens.sub(schedule.claimedTokens); + } + + function _getReleasedTokens(address _beneficiary, uint256 _index) internal view returns(uint256) { + Schedule storage schedule = schedules[_beneficiary][_index]; + /*solium-disable-next-line security/no-block-members*/ + if (now > schedule.startTime) { + uint256 periodCount = schedule.duration.div(schedule.frequency); + /*solium-disable-next-line security/no-block-members*/ + uint256 periodNumber = (now.sub(schedule.startTime)).div(schedule.frequency); + if (periodNumber > periodCount) { + periodNumber = periodCount; + } + return schedule.numberOfTokens.mul(periodNumber).div(periodCount); + } else { + return 0; } - return availableTokens; } /** @@ -377,16 +386,15 @@ contract VestingEscrowWallet is IWallet { * @notice Used to remove beneficiaries without schedules */ function trimBeneficiaries() external withPerm(ADMIN) { - //TODO commented because of contract size -// for (uint256 i = 0; i < beneficiaries.length; i++) { -// if (schedules[beneficiaries[i]].length == 0) { -// delete schedules[beneficiaries[i]]; -// if (i != beneficiaries.length - 1) { -// beneficiaries[i] = beneficiaries[beneficiaries.length - 1]; -// } -// beneficiaries.length--; -// } -// } + for (uint256 i = 0; i < beneficiaries.length; i++) { + if (schedules[beneficiaries[i]].length == 0) { + delete schedules[beneficiaries[i]]; + if (i != beneficiaries.length - 1) { + beneficiaries[i] = beneficiaries[beneficiaries.length - 1]; + } + beneficiaries.length--; + } + } } /** @@ -483,38 +491,17 @@ contract VestingEscrowWallet is IWallet { } function _sendTokens(address _beneficiary) internal { - uint256 amount = getAvailableTokens(_beneficiary); - if (amount > 0) { - for (uint256 i = 0; i < schedules[_beneficiary].length; i++) { - schedules[_beneficiary][i].availableTokens = 0; - } - ISecurityToken(securityToken).transfer(_beneficiary, amount); - emit SendTokens(_beneficiary, amount); + for (uint256 i = 0; i < schedules[_beneficiary].length; i++) { + _sendTokens(_beneficiary, i); } } - /** - * @notice manually triggers update outside for all schedules (can be used to reduce user gas costs) - */ - function updateAll() external withPerm(ADMIN) { - for (uint256 i = 0; i < beneficiaries.length; i++) { - Schedule[] storage data = schedules[beneficiaries[i]]; - for (uint256 j = 0; j < data.length; j++) { - Schedule storage schedule = data[j]; - if (schedule.releasedTokens < schedule.numberOfTokens) { - uint256 periodCount = schedule.duration.div(schedule.frequency); - /*solium-disable-next-line security/no-block-members*/ - uint256 periodNumber = (now.sub(schedule.startTime)).div(schedule.frequency); - if (periodNumber > periodCount) { - periodNumber = periodCount; - } - uint256 releasedTokens = schedule.numberOfTokens.mul(periodNumber).div(periodCount); - if (schedule.releasedTokens < releasedTokens) { - schedule.availableTokens = schedule.availableTokens.add(releasedTokens.sub(schedule.releasedTokens)); - schedule.releasedTokens = releasedTokens; - } - } - } + function _sendTokens(address _beneficiary, uint256 _index) internal { + uint256 amount = _getAvailableTokens(_beneficiary, _index); + if (amount > 0) { + schedules[_beneficiary][_index].claimedTokens = schedules[_beneficiary][_index].claimedTokens.add(amount); + ISecurityToken(securityToken).transfer(_beneficiary, amount); + emit SendTokens(_beneficiary, amount); } } diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 6bebcff8e..6c629628e 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -331,19 +331,12 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency); - await I_VestingEscrowWallet.updateAll({from: wallet_admin}); await catchRevert( I_VestingEscrowWallet.pushAvailableTokens(account_beneficiary3, {from: account_beneficiary1}) ); }); - it("Should not be able update all schedules -- fail because of permissions check", async () => { - await catchRevert( - I_VestingEscrowWallet.updateAll({from: account_beneficiary1}) - ); - }); - it("Should push available tokens to the beneficiary address", async () => { let numberOfTokens = 75000; const tx = await I_VestingEscrowWallet.pushAvailableTokens(account_beneficiary3, {from: wallet_admin}); @@ -380,7 +373,6 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency * 3); - await I_VestingEscrowWallet.updateAll({from: wallet_admin}); const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); @@ -428,24 +420,26 @@ contract('VestingEscrowWallet', accounts => { } let stepCount = 6; await increaseTime(durationUtil.minutes(stepCount) + durationUtil.seconds(100)); - await I_VestingEscrowWallet.updateAll({from: wallet_admin}); let numberOfTokens = 100000 + (30000 / 6 * stepCount) + (2000 / 10 * stepCount); const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); + assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); - assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); + assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), 100000); + assert.equal(tx.logs[1].args._beneficiary, account_beneficiary3); + assert.equal(tx.logs[1].args._numberOfTokens.toNumber(), 30000 / 6 * stepCount); + assert.equal(tx.logs[2].args._beneficiary, account_beneficiary3); + assert.equal(tx.logs[2].args._numberOfTokens.toNumber(), 2000 / 10 * stepCount); let balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); assert.equal(balance.toNumber(), numberOfTokens); stepCount = 4; await increaseTime(durationUtil.minutes(stepCount) + durationUtil.seconds(100)); - await I_VestingEscrowWallet.updateAll({from: wallet_admin}); - numberOfTokens = (2000 / 10 * stepCount); const tx2 = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); assert.equal(tx2.logs[0].args._beneficiary, account_beneficiary3); - assert.equal(tx2.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); + assert.equal(tx2.logs[0].args._numberOfTokens.toNumber(), 2000 / 10 * stepCount); balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); assert.equal(balance.toNumber(), totalNumberOfTokens); @@ -528,12 +522,6 @@ contract('VestingEscrowWallet', accounts => { ); }); - it("Should fail to get available tokens -- fail because address is invalid", async () => { - await catchRevert( - I_VestingEscrowWallet.getAvailableTokens(0) - ); - }); - it("Should not be able to add schedule -- fail because of permissions check", async () => { let numberOfTokens = schedules[0].numberOfTokens; let duration = schedules[0].duration; @@ -583,6 +571,10 @@ contract('VestingEscrowWallet', accounts => { checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 1, {from: wallet_admin}); + + + + await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); @@ -612,7 +604,7 @@ contract('VestingEscrowWallet', accounts => { checkScheduleLog(tx.logs[0], account_beneficiary1, numberOfTokens, duration, frequency, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); - assert.equal(scheduleCount, 1); + assert.equal(scheduleCount.toNumber(), 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); @@ -759,29 +751,27 @@ contract('VestingEscrowWallet', accounts => { let startTime = latestTime() + durationUtil.seconds(100); await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); } - let stepCount = 6; + let stepCount = 3; await increaseTime(durationUtil.minutes(stepCount) + durationUtil.seconds(100)); - await I_VestingEscrowWallet.updateAll({from: wallet_admin}); - let numberOfTokens = 100000 + (30000 / 6 * stepCount) + (2000 / 10 * stepCount); const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary3, 0, {from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); - assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); + assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), 100000 / 4 * stepCount); let balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); - assert.equal(balance.toNumber(), numberOfTokens); + assert.equal(balance.toNumber(), 100000 / 4 * stepCount); - stepCount = 4; - await increaseTime(durationUtil.minutes(stepCount) + durationUtil.seconds(100)); - await I_VestingEscrowWallet.updateAll({from: wallet_admin}); + stepCount = 7; + await increaseTime(durationUtil.minutes(stepCount)); - numberOfTokens = (2000 / 10 * stepCount); const tx2 = await I_VestingEscrowWallet.revokeAllSchedules(account_beneficiary3, {from: wallet_admin}); assert.equal(tx2.logs[0].args._beneficiary, account_beneficiary3); - assert.equal(tx2.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); + assert.equal(tx2.logs[0].args._numberOfTokens.toNumber(), 2000); + assert.equal(tx2.logs[1].args._beneficiary, account_beneficiary3); + assert.equal(tx2.logs[1].args._numberOfTokens.toNumber(), 30000); balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); - assert.equal(balance.toNumber(), totalNumberOfTokens); + assert.equal(balance.toNumber(), totalNumberOfTokens - 100000 / 4); await I_SecurityToken.transfer(token_owner, balance, {from: account_beneficiary3}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); @@ -992,8 +982,6 @@ contract('VestingEscrowWallet', accounts => { }); it("Should send available tokens to the beneficiaries addresses", async () => { - await I_VestingEscrowWallet.updateAll({from: wallet_admin}); - const tx = await I_VestingEscrowWallet.pushAvailableTokensMulti(beneficiaries, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { From b416076067d6a6ba3be9d150b465932d5b88e4cf Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 28 Nov 2018 11:21:29 +0200 Subject: [PATCH 60/93] changes in multi-operations --- .../modules/Wallet/VestingEscrowWallet.sol | 96 +++++++++++-------- test/z_vesting_escrow_wallet.js | 84 +++++++++------- 2 files changed, 105 insertions(+), 75 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 275d12e96..a1141977c 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -254,7 +254,7 @@ contract VestingEscrowWallet is IWallet { internal { _validateSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); - require(_index < schedules[_beneficiary].length, "Schedule not found"); + _checkSchedule(_beneficiary, _index); Schedule storage schedule = schedules[_beneficiary][_index]; /*solium-disable-next-line security/no-block-members*/ require(now < schedule.startTime, "Schedule started"); @@ -276,8 +276,7 @@ contract VestingEscrowWallet is IWallet { * @param _index index of the schedule */ function revokeSchedule(address _beneficiary, uint256 _index) external withPerm(ADMIN) { - require(_beneficiary != address(0), "Invalid address"); - require(_index < schedules[_beneficiary].length, "Schedule not found"); + _checkSchedule(_beneficiary, _index); _sendTokens(_beneficiary, _index); Schedule[] storage userSchedules = schedules[_beneficiary]; uint256 releasedTokens = _getReleasedTokens(_beneficiary, _index); @@ -316,8 +315,7 @@ contract VestingEscrowWallet is IWallet { * @return beneficiary's schedule */ function getSchedule(address _beneficiary, uint256 _index) external view returns(uint256, uint256, uint256, uint256, State) { - require(_beneficiary != address(0), "Invalid address"); - require(_index < schedules[_beneficiary].length, "Schedule not found"); + _checkSchedule(_beneficiary, _index); Schedule storage schedule = schedules[_beneficiary][_index]; return ( schedule.numberOfTokens, @@ -371,17 +369,6 @@ contract VestingEscrowWallet is IWallet { } } - /** - * @notice Used to bulk send available tokens for each of beneficiaries - * @param _beneficiaries array of beneficiary's addresses - */ - function pushAvailableTokensMulti(address[] _beneficiaries) external withPerm(ADMIN) { - require(_beneficiaries.length > 1, "Array size should be greater than one"); - for (uint256 i = 0; i < _beneficiaries.length; i++) { - pushAvailableTokens(_beneficiaries[i]); - } - } - /** * @notice Used to remove beneficiaries without schedules */ @@ -397,26 +384,44 @@ contract VestingEscrowWallet is IWallet { } } + /** + * @notice Used to bulk send available tokens for each of beneficiaries + * @param _beneficiaries array of beneficiary's addresses + */ + function pushAvailableTokensMulti(address[] _beneficiaries) external withPerm(ADMIN) { + require(_beneficiaries.length > 1, "Array size should be greater than one"); + for (uint256 i = 0; i < _beneficiaries.length; i++) { + pushAvailableTokens(_beneficiaries[i]); + } + } + /** * @notice Used to bulk add vesting schedules for each of beneficiaries * @param _beneficiaries array of beneficiary's addresses - * @param _numberOfTokens number of tokens - * @param _duration vesting duration - * @param _frequency vesting frequency - * @param _startTime vesting start time + * @param _numberOfTokens array of number of tokens + * @param _durations array of vesting duration + * @param _frequencies array of vesting frequency + * @param _startTimes array of vesting start time */ function addScheduleMulti( address[] _beneficiaries, - uint256 _numberOfTokens, - uint256 _duration, - uint256 _frequency, - uint256 _startTime + uint256[] _numberOfTokens, + uint256[] _durations, + uint256[] _frequencies, + uint256[] _startTimes ) external withPerm(ADMIN) { + require( + _beneficiaries.length == _numberOfTokens.length && /*solium-disable-line operator-whitespace*/ + _beneficiaries.length == _durations.length && /*solium-disable-line operator-whitespace*/ + _beneficiaries.length == _frequencies.length && /*solium-disable-line operator-whitespace*/ + _beneficiaries.length == _startTimes.length, + "Arrays sizes mismatch" + ); for (uint256 i = 0; i < _beneficiaries.length; i++) { - _addSchedule(_beneficiaries[i], _numberOfTokens, _duration, _frequency, _startTime); + _addSchedule(_beneficiaries[i], _numberOfTokens[i], _durations[i], _frequencies[i], _startTimes[i]); } } @@ -424,11 +429,12 @@ contract VestingEscrowWallet is IWallet { * @notice Used to bulk add vesting schedules from template for each of beneficiaries * @param _beneficiaries array of beneficiary's addresses * @param _index index of the template - * @param _startTime vesting start time + * @param _startTimes array of vesting start time */ - function addScheduleFromTemplateMulti(address[] _beneficiaries, uint256 _index, uint256 _startTime) external withPerm(ADMIN) { + function addScheduleFromTemplateMulti(address[] _beneficiaries, uint256 _index, uint256[] _startTimes) external withPerm(ADMIN) { + require(_beneficiaries.length == _startTimes.length, "Arrays sizes mismatch"); for (uint256 i = 0; i < _beneficiaries.length; i++) { - _addScheduleFromTemplate(_beneficiaries[i], _index, _startTime); + _addScheduleFromTemplate(_beneficiaries[i], _index, _startTimes[i]); } } @@ -446,25 +452,32 @@ contract VestingEscrowWallet is IWallet { * @notice Used to bulk modify vesting schedules for each of beneficiaries * @param _beneficiaries array of beneficiary's addresses * @param _indexes array of beneficiary's indexes of schedule - * @param _numberOfTokens number of tokens - * @param _duration vesting duration - * @param _frequency vesting frequency - * @param _startTime vesting start time + * @param _numberOfTokens array of number of tokens + * @param _durations array of vesting duration + * @param _frequencies array of vesting frequency + * @param _startTimes array of vesting start time */ function modifyScheduleMulti( address[] _beneficiaries, uint256[] _indexes, - uint256 _numberOfTokens, - uint256 _duration, - uint256 _frequency, - uint256 _startTime + uint256[] _numberOfTokens, + uint256[] _durations, + uint256[] _frequencies, + uint256[] _startTimes ) - external + public withPerm(ADMIN) { - require(_beneficiaries.length == _indexes.length, "Arrays sizes mismatch"); + require( + _beneficiaries.length == _indexes.length && /*solium-disable-line operator-whitespace*/ + _beneficiaries.length == _numberOfTokens.length && /*solium-disable-line operator-whitespace*/ + _beneficiaries.length == _durations.length && /*solium-disable-line operator-whitespace*/ + _beneficiaries.length == _frequencies.length && /*solium-disable-line operator-whitespace*/ + _beneficiaries.length == _startTimes.length, + "Arrays sizes mismatch" + ); for (uint256 i = 0; i < _beneficiaries.length; i++) { - _modifySchedule(_beneficiaries[i], _indexes[i], _numberOfTokens, _duration, _frequency, _startTime); + _modifySchedule(_beneficiaries[i], _indexes[i], _numberOfTokens[i], _durations[i], _frequencies[i], _startTimes[i]); } } @@ -483,6 +496,11 @@ contract VestingEscrowWallet is IWallet { require(now < _startTime, "Date in the past"); } + function _checkSchedule(address _beneficiary, uint256 _index) internal view { + require(_beneficiary != address(0), "Invalid address"); + require(_index < schedules[_beneficiary].length, "Schedule not found"); + } + function _validateTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) internal pure { require(_numberOfTokens > 0, "Zero amount"); require(_duration % _frequency == 0, "Duration and frequency mismatch"); diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 6c629628e..0c331dda1 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -886,83 +886,95 @@ contract('VestingEscrowWallet', accounts => { describe("Tests for multi operations", async () => { it("Should not be able to add schedules to the beneficiaries -- fail because of permissions check", async () => { + let startTimes = [latestTime() + 100, latestTime() + 100, latestTime() + 100]; await catchRevert( - I_VestingEscrowWallet.addScheduleMulti([account_beneficiary1], 10000, 4, 1, latestTime() + 100, {from: account_beneficiary1}) + I_VestingEscrowWallet.addScheduleMulti(beneficiaries, [10000, 10000, 10000], [4, 4, 4], [1, 1, 1], startTimes, {from: account_beneficiary1}) ); }); + it("Should not be able to add schedules to the beneficiaries -- fail because of arrays sizes mismatch", async () => { + let startTimes = [latestTime() + 100, latestTime() + 100, latestTime() + 100]; + let totalNumberOfTokens = 60000; + await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); + await catchRevert( + I_VestingEscrowWallet.addScheduleMulti(beneficiaries, [20000, 30000, 10000], [4, 4], [1, 1, 1], startTimes, {from: wallet_admin}) + ); + I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + }); + it("Should add schedules for 3 beneficiaries", async () => { - let numberOfTokens = 30000; - let duration = durationUtil.weeks(4); - let frequency = durationUtil.weeks(1); - let startTime = latestTime() + durationUtil.seconds(100); + let numberOfTokens = [20000, 30000, 10000]; + let durations = [durationUtil.weeks(4), durationUtil.weeks(3), durationUtil.weeks(4)]; + let frequencies = [durationUtil.weeks(2), durationUtil.weeks(1), durationUtil.weeks(1)]; + let startTimes = [latestTime() + durationUtil.days(1), latestTime() + durationUtil.days(2), latestTime() + durationUtil.days(3)]; - let totalNumberOfTokens = numberOfTokens * 3; + let totalNumberOfTokens = 60000; await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); - let tx = await I_VestingEscrowWallet.addScheduleMulti(beneficiaries, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + let tx = await I_VestingEscrowWallet.addScheduleMulti(beneficiaries, numberOfTokens, durations, frequencies, startTimes, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; let beneficiary = beneficiaries[i]; - checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTime); + checkScheduleLog(log, beneficiary, numberOfTokens[i], durations[i], frequencies[i], startTimes[i]); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(beneficiary); assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); - checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); + checkSchedule(schedule, numberOfTokens[i], durations[i], frequencies[i], startTimes[i], CREATED); } }); - it("Should not be able modify vesting schedule for 3 beneficiary's addresses", async () => { - let numberOfTokens = 25000; - let duration = durationUtil.seconds(50); - let frequency = durationUtil.seconds(10); + it("Should not be able modify vesting schedule for 3 beneficiary's addresses -- fail because of arrays sizes mismatch", async () => { + let numberOfTokens = [25000, 25000, 25000]; + let durations = [durationUtil.seconds(50), durationUtil.seconds(50), durationUtil.seconds(50)]; + let frequencies = [durationUtil.seconds(10), durationUtil.seconds(10), durationUtil.seconds(10)]; let timeShift = durationUtil.seconds(100); - let startTime = latestTime() + timeShift; + let startTimes = [latestTime() + timeShift, latestTime() + timeShift, latestTime() + timeShift]; let indexes = [0, 0, 0, 0]; await catchRevert( - I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) + I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, indexes, numberOfTokens, durations, frequencies, startTimes, {from: wallet_admin}) ); }); it("Should not be able to modify schedules for the beneficiaries -- fail because of permissions check", async () => { - let numberOfTokens = 25000; - let duration = durationUtil.seconds(50); - let frequency = durationUtil.seconds(10); + let numberOfTokens = [25000, 25000, 25000]; + let durations = [durationUtil.seconds(50), durationUtil.seconds(50), durationUtil.seconds(50)]; + let frequencies = [durationUtil.seconds(10), durationUtil.seconds(10), durationUtil.seconds(10)]; let timeShift = durationUtil.seconds(100); - let startTime = latestTime() + timeShift; + let startTimes = [latestTime() + timeShift, latestTime() + timeShift, latestTime() + timeShift]; let indexes = [0, 0, 0]; await catchRevert( - I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: account_beneficiary1}) + I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, indexes, numberOfTokens, durations, frequencies, startTimes, {from: account_beneficiary1}) ); }); it("Should modify vesting schedule for 3 beneficiary's addresses", async () => { - let numberOfTokens = 25000; - let duration = durationUtil.seconds(50); - let frequency = durationUtil.seconds(10); + let numberOfTokens = [15000, 15000, 15000]; + let durations = [durationUtil.seconds(50), durationUtil.seconds(50), durationUtil.seconds(50)]; + let frequencies = [durationUtil.seconds(10), durationUtil.seconds(10), durationUtil.seconds(10)]; let timeShift = durationUtil.seconds(100); - let startTime = latestTime() + timeShift; + let startTimes = [latestTime() + timeShift, latestTime() + timeShift, latestTime() + timeShift]; let indexes = [0, 0, 0]; - const tx = await I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, indexes, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); - await increaseTime(timeShift + frequency); + const tx = await I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, indexes, numberOfTokens, durations, frequencies, startTimes, {from: wallet_admin}); + await increaseTime(timeShift + frequencies[0]); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; let beneficiary = beneficiaries[i]; - checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTime); + checkScheduleLog(log, beneficiary, numberOfTokens[i], durations[i], frequencies[i], startTimes[i]); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(beneficiary); assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); - checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, STARTED); + checkSchedule(schedule, numberOfTokens[i], durations[i], frequencies[i], startTimes[i], STARTED); } let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); @@ -988,10 +1000,10 @@ contract('VestingEscrowWallet', accounts => { let log = tx.logs[i]; let beneficiary = beneficiaries[i]; assert.equal(log.args._beneficiary, beneficiary); - assert.equal(log.args._numberOfTokens.toNumber(), 5000); + assert.equal(log.args._numberOfTokens.toNumber(), 3000); let balance = await I_SecurityToken.balanceOf.call(beneficiary); - assert.equal(balance.toNumber(), 5000); + assert.equal(balance.toNumber(), 3000); await I_SecurityToken.transfer(token_owner, balance, {from: beneficiary}); await I_VestingEscrowWallet.revokeAllSchedules(beneficiary, {from: wallet_admin}); @@ -1003,7 +1015,7 @@ contract('VestingEscrowWallet', accounts => { let numberOfTokens = 18000; let duration = durationUtil.weeks(3); let frequency = durationUtil.weeks(1); - let startTime = latestTime() + durationUtil.seconds(100); + let startTimes = [latestTime() + durationUtil.seconds(100), latestTime() + durationUtil.seconds(100), latestTime() + durationUtil.seconds(100)]; let totalNumberOfTokens = numberOfTokens * 3; await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); @@ -1011,7 +1023,7 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_admin}); await catchRevert( - I_VestingEscrowWallet.addScheduleFromTemplateMulti([account_beneficiary1, account_beneficiary2], 0, startTime, {from: account_beneficiary1}) + I_VestingEscrowWallet.addScheduleFromTemplateMulti(beneficiaries, 0, startTimes, {from: account_beneficiary1}) ); }); @@ -1019,26 +1031,26 @@ contract('VestingEscrowWallet', accounts => { let numberOfTokens = 18000; let duration = durationUtil.weeks(3); let frequency = durationUtil.weeks(1); - let startTime = latestTime() + durationUtil.seconds(100); + let startTimes = [latestTime() + durationUtil.seconds(100), latestTime() + durationUtil.seconds(100), latestTime() + durationUtil.seconds(100)]; let totalNumberOfTokens = numberOfTokens * 3; await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_admin}); - let tx = await I_VestingEscrowWallet.addScheduleFromTemplateMulti(beneficiaries, 0, startTime, {from: wallet_admin}); + let tx = await I_VestingEscrowWallet.addScheduleFromTemplateMulti(beneficiaries, 0, startTimes, {from: wallet_admin}); await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; let beneficiary = beneficiaries[i]; - checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTime); + checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTimes[i]); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(beneficiary); assert.equal(scheduleCount.toNumber(), 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); - checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); + checkSchedule(schedule, numberOfTokens, duration, frequency, startTimes[i], CREATED); } }); From 0c498615b4c923b3306439164bcf6d405e78161b Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 28 Nov 2018 11:47:45 +0200 Subject: [PATCH 61/93] use msg.sender instead of _treasury --- .../modules/Wallet/VestingEscrowWallet.sol | 24 ++++++------------- .../Wallet/VestingEscrowWalletFactory.sol | 4 ---- test/z_vesting_escrow_wallet.js | 9 ++----- 3 files changed, 9 insertions(+), 28 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index a1141977c..52c3e5a8f 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -29,7 +29,6 @@ contract VestingEscrowWallet is IWallet { enum State {CREATED, STARTED, COMPLETED} - address public treasury; uint256 public unassignedTokens; mapping (address => Schedule[]) public schedules; @@ -55,8 +54,8 @@ contract VestingEscrowWallet is IWallet { ); event RevokeAllSchedules(address indexed _beneficiary); event RevokeSchedule(address indexed _beneficiary, uint256 _index); - event DepositTokens(uint256 _numberOfTokens); - event SendToTreasury(uint256 _numberOfTokens); + event DepositTokens(uint256 _numberOfTokens, address _sender); + event SendToTreasury(uint256 _numberOfTokens, address _sender); event SendTokens(address indexed _beneficiary, uint256 _numberOfTokens); event AddTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, uint256 _index); event RemoveTemplate(uint256 _index); @@ -72,20 +71,11 @@ contract VestingEscrowWallet is IWallet { { } - /** - * @notice Function used to initialize the different variables - * @param _treasury Address of the treasury - */ - function configure(address _treasury) public onlyFactory { - require(_treasury != address(0), "Invalid address"); - treasury = _treasury; - } - /** * @notice This function returns the signature of the configure function */ function getInitFunction() public pure returns (bytes4) { - return bytes4(keccak256("configure(address)")); + return bytes4(0); } /** @@ -97,9 +87,9 @@ contract VestingEscrowWallet is IWallet { function _depositTokens(uint256 _numberOfTokens) internal { require(_numberOfTokens > 0, "Should be greater than zero"); - ISecurityToken(securityToken).transferFrom(treasury, this, _numberOfTokens); + ISecurityToken(securityToken).transferFrom(msg.sender, this, _numberOfTokens); unassignedTokens = unassignedTokens.add(_numberOfTokens); - emit DepositTokens(_numberOfTokens); + emit DepositTokens(_numberOfTokens, msg.sender); } /** @@ -108,8 +98,8 @@ contract VestingEscrowWallet is IWallet { function sendToTreasury() external withPerm(ADMIN) { uint256 amount = unassignedTokens; unassignedTokens = 0; - ISecurityToken(securityToken).transfer(treasury, amount); - emit SendToTreasury(amount); + ISecurityToken(securityToken).transfer(msg.sender, amount); + emit SendToTreasury(amount, msg.sender); } /** diff --git a/contracts/modules/Wallet/VestingEscrowWalletFactory.sol b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol index 88db1919d..c58a04192 100644 --- a/contracts/modules/Wallet/VestingEscrowWalletFactory.sol +++ b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol @@ -34,10 +34,6 @@ contract VestingEscrowWalletFactory is ModuleFactory { require(polyToken.transferFrom(msg.sender, owner, setupCost), "Failed transferFrom due to insufficent Allowance provided"); } VestingEscrowWallet vestingEscrowWallet = new VestingEscrowWallet(msg.sender, address(polyToken)); - //Checks that _data is valid (not calling anything it shouldn't) - require(Util.getSig(_data) == vestingEscrowWallet.getInitFunction(), "Invalid data"); - /*solium-disable-next-line security/no-low-level-calls*/ - require(address(vestingEscrowWallet).call(_data), "Unsuccessfull call"); /*solium-disable-next-line security/no-block-members*/ emit GenerateModuleFromFactory(address(vestingEscrowWallet), getName(), address(this), msg.sender, setupCost, now); return address(vestingEscrowWallet); diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 0c331dda1..8c5d3fba5 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -71,7 +71,7 @@ contract('VestingEscrowWallet', accounts => { // Accounts setup account_polymath = accounts[0]; token_owner = accounts[1]; - wallet_admin = accounts[2]; + wallet_admin = token_owner; account_beneficiary1 = accounts[6]; account_beneficiary2 = accounts[7]; @@ -173,13 +173,8 @@ contract('VestingEscrowWallet', accounts => { }); it("Should successfully attach the VestingEscrowWallet with the security token", async () => { - let bytesData = encodeModuleCall( - ["address"], - [token_owner] - ); - await I_SecurityToken.changeGranularity(1, {from: token_owner}); - const tx = await I_SecurityToken.addModule(I_VestingEscrowWalletFactory.address, bytesData, 0, 0, { from: token_owner }); + const tx = await I_SecurityToken.addModule(I_VestingEscrowWalletFactory.address, "", 0, 0, { from: token_owner }); assert.equal(tx.logs[2].args._types[0].toNumber(), 6, "VestingEscrowWallet doesn't get deployed"); assert.equal( From 125a199649cf73e605a2fa311d7708f3fe5f1c15 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 28 Nov 2018 12:35:09 +0200 Subject: [PATCH 62/93] minor fix --- contracts/modules/Wallet/VestingEscrowWalletFactory.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/modules/Wallet/VestingEscrowWalletFactory.sol b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol index c58a04192..d0035da10 100644 --- a/contracts/modules/Wallet/VestingEscrowWalletFactory.sol +++ b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol @@ -29,7 +29,7 @@ contract VestingEscrowWalletFactory is ModuleFactory { * _data Data used for the intialization of the module factory variables * @return address Contract address of the Module */ - function deploy(bytes _data) external returns(address) { + function deploy(bytes /*_data*/) external returns(address) { if (setupCost > 0) { require(polyToken.transferFrom(msg.sender, owner, setupCost), "Failed transferFrom due to insufficent Allowance provided"); } From 4854ace6948caf6fd4d6c3c2a09f2ba83fe22498 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 28 Nov 2018 12:35:25 +0200 Subject: [PATCH 63/93] updated permissions_list.md --- docs/permissions_list.md | 51 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/docs/permissions_list.md b/docs/permissions_list.md index b49c95a0e..de3fd2930 100644 --- a/docs/permissions_list.md +++ b/docs/permissions_list.md @@ -271,6 +271,57 @@ removeTransferLimitInPercentageMulti + + Wallet + VestingEscrowWallet + depositTokens() + withPerm(ADMIN) + + + sendToTreasury() + + + pushAvailableTokens() + + + addTemplate() + + + removeTemplate() + + + addSchedule() + + + addScheduleFromTemplate() + + + modifySchedule() + + + revokeSchedule() + + + revokeAllSchedules() + + + trimBeneficiaries() + + + pushAvailableTokensMulti() + + + addScheduleMulti() + + + addScheduleFromTemplateMulti() + + + revokeSchedulesMulti() + + + modifyScheduleMulti() + From e9f1129161b37b288ae493db1ebfede4d1207f29 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 28 Nov 2018 13:19:20 +0200 Subject: [PATCH 64/93] fixed permissions_list.md --- docs/permissions_list.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/permissions_list.md b/docs/permissions_list.md index de3fd2930..009781c05 100644 --- a/docs/permissions_list.md +++ b/docs/permissions_list.md @@ -270,8 +270,9 @@ removeTransferLimitInPercentageMulti - - + + + Wallet VestingEscrowWallet depositTokens() From cb975a524b3f43f1f3c4d0d4fb964d4d6ceaf849 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 28 Nov 2018 12:00:37 +0000 Subject: [PATCH 65/93] Keep ABI constant --- .../GeneralTransferManager.sol | 66 ++++++++++++------- test/h_general_transfer_manager.js | 36 +++++----- test/helpers/signData.js | 2 +- 3 files changed, 60 insertions(+), 44 deletions(-) diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index 04028fead..080c8be17 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -35,10 +35,10 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag address _investor, uint256 _dateAdded, address _addedBy, - uint64 _fromTime, - uint64 _toTime, - uint64 _expiryTime, - uint8 _canBuyFromSTO + uint256 _fromTime, + uint256 _toTime, + uint256 _expiryTime, + bool _canBuyFromSTO ); /** @@ -177,15 +177,21 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag */ function modifyWhitelist( address _investor, - uint64 _fromTime, - uint64 _toTime, - uint64 _expiryTime, - uint8 _canBuyFromSTO + uint256 _fromTime, + uint256 _toTime, + uint256 _expiryTime, + bool _canBuyFromSTO ) public withPerm(WHITELIST) { - _modifyWhitelist(_investor, _fromTime, _toTime, _expiryTime, _canBuyFromSTO); + uint8 canBuyFromSTO = 0; + if (_canBuyFromSTO) { + canBuyFromSTO = 1; + } + _modifyWhitelist(_investor, uint64(_fromTime), uint64(_toTime), uint64(_expiryTime), canBuyFromSTO); + /*solium-disable-next-line security/no-block-members*/ + emit ModifyWhitelist(_investor, now, msg.sender, _fromTime, _toTime, _expiryTime, _canBuyFromSTO); } /** @@ -210,8 +216,6 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag investors.push(_investor); } whitelist[_investor] = TimeRestriction(_fromTime, _toTime, _expiryTime, _canBuyFromSTO, uint8(1)); - /*solium-disable-next-line security/no-block-members*/ - emit ModifyWhitelist(_investor, now, msg.sender, _fromTime, _toTime, _expiryTime, _canBuyFromSTO); } /** @@ -224,17 +228,25 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag */ function modifyWhitelistMulti( address[] _investors, - uint64[] _fromTimes, - uint64[] _toTimes, - uint64[] _expiryTimes, - uint8[] _canBuyFromSTO + uint256[] _fromTimes, + uint256[] _toTimes, + uint256[] _expiryTimes, + bool[] _canBuyFromSTO ) public withPerm(WHITELIST) { require(_investors.length == _fromTimes.length, "Mismatched input lengths"); require(_fromTimes.length == _toTimes.length, "Mismatched input lengths"); require(_toTimes.length == _expiryTimes.length, "Mismatched input lengths"); require(_canBuyFromSTO.length == _toTimes.length, "Mismatched input length"); + uint8 canBuyFromSTO; for (uint256 i = 0; i < _investors.length; i++) { - _modifyWhitelist(_investors[i], _fromTimes[i], _toTimes[i], _expiryTimes[i], _canBuyFromSTO[i]); + if (_canBuyFromSTO[i]) { + canBuyFromSTO = 1; + } else { + canBuyFromSTO = 0; + } + _modifyWhitelist(_investors[i], uint64(_fromTimes[i]), uint64(_toTimes[i]), uint64(_expiryTimes[i]), canBuyFromSTO); + /*solium-disable-next-line security/no-block-members*/ + emit ModifyWhitelist(_investors[i], now, msg.sender, _fromTimes[i], _toTimes[i], _expiryTimes[i], _canBuyFromSTO[i]); } } @@ -254,21 +266,21 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag */ function modifyWhitelistSigned( address _investor, - uint64 _fromTime, - uint64 _toTime, - uint64 _expiryTime, - uint8 _canBuyFromSTO, - uint64 _validFrom, - uint64 _validTo, + uint256 _fromTime, + uint256 _toTime, + uint256 _expiryTime, + bool _canBuyFromSTO, + uint256 _validFrom, + uint256 _validTo, uint256 _nonce, uint8 _v, bytes32 _r, bytes32 _s ) public { /*solium-disable-next-line security/no-block-members*/ - require(_validFrom <= uint64(now), "ValidFrom is too early"); + require(_validFrom <= now, "ValidFrom is too early"); /*solium-disable-next-line security/no-block-members*/ - require(_validTo >= uint64(now), "ValidTo is too late"); + require(_validTo >= now, "ValidTo is too late"); require(!nonceMap[_investor][_nonce], "Already used signature"); nonceMap[_investor][_nonce] = true; bytes32 hash = keccak256( @@ -278,7 +290,11 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag if (whitelist[_investor].added == uint8(0)) { investors.push(_investor); } - whitelist[_investor] = TimeRestriction(_fromTime, _toTime, _expiryTime, _canBuyFromSTO, uint8(1)); + uint8 canBuyFromSTO = 0; + if (_canBuyFromSTO) { + canBuyFromSTO = 1; + } + whitelist[_investor] = TimeRestriction(uint64(_fromTime), uint64(_toTime), uint64(_expiryTime), canBuyFromSTO, uint8(1)); /*solium-disable-next-line security/no-block-members*/ emit ModifyWhitelist(_investor, now, msg.sender, _fromTime, _toTime, _expiryTime, _canBuyFromSTO); } diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 5dbcf5a6c..f8b1ed989 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -188,7 +188,7 @@ contract("GeneralTransferManager", accounts => { [latestTime() + duration.days(30), latestTime() + duration.days(30)], [latestTime() + duration.days(90), latestTime() + duration.days(90)], [latestTime() + duration.years(1), latestTime() + duration.years(1)], - [0, 0], + [false, false], { from: account_issuer, gas: 6000000 @@ -316,7 +316,7 @@ contract("GeneralTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 6000000 @@ -378,7 +378,7 @@ contract("GeneralTransferManager", accounts => { latestTime() + duration.days(10), latestTime() + duration.days(10), latestTime() + duration.days(20), - 1, + true, { from: account_issuer, gas: 6000000 @@ -424,7 +424,7 @@ contract("GeneralTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(20), - 1, + true, { from: account_issuer, gas: 6000000 @@ -484,7 +484,7 @@ contract("GeneralTransferManager", accounts => { fromTime, toTime, expiryTime, - 1, + true, validFrom, validTo, nonce, @@ -501,7 +501,7 @@ contract("GeneralTransferManager", accounts => { fromTime, toTime, expiryTime, - 1, + true, validFrom, validTo, nonce, @@ -528,7 +528,7 @@ contract("GeneralTransferManager", accounts => { fromTime, toTime, expiryTime, - 1, + true, validFrom, validTo, nonce, @@ -545,7 +545,7 @@ contract("GeneralTransferManager", accounts => { fromTime, toTime, expiryTime, - 1, + true, validFrom, validTo, nonce, @@ -572,7 +572,7 @@ contract("GeneralTransferManager", accounts => { fromTime, toTime, expiryTime, - 1, + true, validFrom, validTo, nonce, @@ -589,7 +589,7 @@ contract("GeneralTransferManager", accounts => { fromTime, toTime, expiryTime, - 1, + true, validFrom, validTo, nonce, @@ -616,7 +616,7 @@ contract("GeneralTransferManager", accounts => { latestTime(), latestTime() + duration.days(80), expiryTime + duration.days(200), - 1, + true, validFrom, validTo, nonce, @@ -632,7 +632,7 @@ contract("GeneralTransferManager", accounts => { latestTime(), latestTime() + duration.days(80), expiryTime + duration.days(200), - 1, + true, validFrom, validTo, nonce, @@ -672,7 +672,7 @@ contract("GeneralTransferManager", accounts => { latestTime(), latestTime() + duration.days(80), expiryTime + duration.days(200), - 1, + true, validFrom, validTo, nonce, @@ -688,7 +688,7 @@ contract("GeneralTransferManager", accounts => { latestTime(), latestTime() + duration.days(80), expiryTime + duration.days(200), - 1, + true, validFrom, validTo, nonce, @@ -795,7 +795,7 @@ contract("GeneralTransferManager", accounts => { [fromTime, fromTime], [toTime, toTime], [expiryTime, expiryTime], - [1, 1], + [true, true], { from: account_delegate, gas: 6000000 @@ -835,7 +835,7 @@ contract("GeneralTransferManager", accounts => { [fromTime, fromTime], [toTime], [expiryTime, expiryTime], - [1, 1], + [true, true], { from: account_delegate, gas: 6000000 @@ -855,7 +855,7 @@ contract("GeneralTransferManager", accounts => { [fromTime, fromTime], [toTime, toTime], [expiryTime], - [1, 1], + [true, true], { from: account_delegate, gas: 6000000 @@ -874,7 +874,7 @@ contract("GeneralTransferManager", accounts => { [fromTime, fromTime], [toTime, toTime], [expiryTime, expiryTime], - [1, 1], + [true, true], { from: token_owner, gas: 6000000 diff --git a/test/helpers/signData.js b/test/helpers/signData.js index 2e5c1ad61..ea7476cc3 100644 --- a/test/helpers/signData.js +++ b/test/helpers/signData.js @@ -6,7 +6,7 @@ const ethUtil = require("ethereumjs-util"); function signData(tmAddress, investorAddress, fromTime, toTime, expiryTime, restricted, validFrom, validTo, nonce, pk) { let packedData = utils .solidityKeccak256( - ["address", "address", "uint64", "uint64", "uint64", "uint8", "uint64", "uint64", "uint256"], + ["address", "address", "uint256", "uint256", "uint256", "bool", "uint256", "uint256", "uint256"], [tmAddress, investorAddress, fromTime, toTime, expiryTime, restricted, validFrom, validTo, nonce] ) .slice(2); From 37aafb8acb3e2a265011e54c9d545594c1c1adb4 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 28 Nov 2018 19:31:54 +0000 Subject: [PATCH 66/93] Fixes --- .../GeneralTransferManager.sol | 71 ++++++++++---- .../GeneralTransferManagerFactory.sol | 2 +- .../GeneralTransferManagerStorage.sol | 8 +- test/b_capped_sto.js | 12 +-- test/c_checkpoints.js | 6 +- test/d_count_transfer_manager.js | 8 +- test/e_erc20_dividends.js | 8 +- test/f_ether_dividends.js | 10 +- test/h_general_transfer_manager.js | 92 ++++++++----------- test/i_Issuance.js | 4 +- test/j_manual_approval_transfer_manager.js | 6 +- test/l_percentage_transfer_manager.js | 6 +- test/m_presale_sto.js | 6 +- test/o_security_token.js | 20 ++-- test/p_usd_tiered_sto.js | 12 +-- test/q_usd_tiered_sto_sim.js | 4 +- test/r_concurrent_STO.js | 2 +- test/v_tracked_redemptions.js | 4 +- ...kup_volume_restriction_transfer_manager.js | 6 +- test/x_single_trade_volume_restriction.js | 10 +- test/y_scheduled_checkpoints.js | 6 +- 21 files changed, 164 insertions(+), 139 deletions(-) diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index 080c8be17..c43531db7 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -24,7 +24,7 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag // Emit when there is change in the flag variable called signingAddress event ChangeSigningAddress(address _signingAddress); // Emit when investor details get modified related to their whitelisting - event OffsetModified(uint64 _time, uint8 _isForward); + event DefaultsModified(uint64 _defaultFromTime, uint64 _defaultToTime); // _fromTime is the time from which the _investor can send tokens // _toTime is the time from which the _investor can receive tokens @@ -52,10 +52,10 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag { } - function modifyOffset(uint64 _time, uint8 _isForward) public withPerm(FLAGS) { - offset.time = _time; - offset.isForward = _isForward; - emit OffsetModified(_time, _isForward); + function modifyDefaults(uint64 _defaultFromTime, uint64 _defaultToTime) public withPerm(FLAGS) { + defaults.fromTime = _defaultFromTime; + defaults.toTime = _defaultToTime; + emit DefaultsModified(_defaultFromTime, _defaultToTime); } /** @@ -126,7 +126,7 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag allowAllBurnTransfers = _allowAllBurnTransfers; emit AllowAllBurnTransfers(_allowAllBurnTransfers); } - + event Times(uint64 _from, uint64 _to); /** * @notice Default implementation of verifyTransfer used by SecurityToken * If the transfer request comes from the STO, it only checks that the investor is in the whitelist @@ -156,13 +156,15 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag if (allowAllWhitelistIssuances && _from == issuanceAddress) { return _onWhitelist(_to) ? Result.VALID : Result.NA; } + (uint64 adjustedFromTime, uint64 adjustedToTime) = _adjustTimes(whitelist[_from].fromTime, whitelist[_to].toTime); + if (_from == issuanceAddress) { - return (_onWhitelist(_to) && _adjustTimes(whitelist[_to].toTime) <= uint64(now)) ? Result.VALID : Result.NA; + return (_onWhitelist(_to) && (adjustedToTime <= uint64(now))) ? Result.VALID : Result.NA; } //Anyone on the whitelist can transfer provided the blocknumber is large enough /*solium-disable-next-line security/no-block-members*/ - return ((_onWhitelist(_from) && _adjustTimes(whitelist[_from].fromTime) <= uint64(now)) && - (_onWhitelist(_to) && _adjustTimes(whitelist[_to].toTime) <= uint64(now))) ? Result.VALID : Result.NA; /*solium-disable-line security/no-block-members*/ + return ((_onWhitelist(_from) && (adjustedFromTime <= uint64(now))) && + (_onWhitelist(_to) && (adjustedToTime <= uint64(now)))) ? Result.VALID : Result.NA; /*solium-disable-line security/no-block-members*/ } return Result.NA; } @@ -326,14 +328,19 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag return attached; } - function _adjustTimes(uint64 _time) internal view returns(uint64) { - if (offset.isForward != 0) { - require(_time + offset.time > _time); - return _time + offset.time; - } else { - require(_time >= offset.time); - return _time - offset.time; + /** + * @notice Internal function to adjust times using default values + */ + function _adjustTimes(uint64 _fromTime, uint64 _toTime) internal view returns(uint64, uint64) { + uint64 adjustedFromTime = _fromTime; + uint64 adjustedToTime = _toTime; + if (_fromTime == 0) { + adjustedFromTime = defaults.fromTime; + } + if (_toTime == 0) { + adjustedToTime = defaults.toTime; } + return (adjustedFromTime, adjustedToTime); } /** @@ -343,6 +350,38 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag return investors; } + /** + * @dev Returns list of all investors data + */ + function getAllInvestorsData() external view returns(uint256[], uint256[], uint256[], bool[]) { + return _investorsData(investors); + } + + /** + * @dev Returns list of specified investors data + */ + function getInvestorsData(address[] _investors) external view returns(uint256[], uint256[], uint256[], bool[]) { + return _investorsData(_investors); + } + + function _investorsData(address[] _investors) internal view returns(uint256[], uint256[], uint256[], bool[]) { + uint256[] memory fromTimes = new uint256[](_investors.length); + uint256[] memory toTimes = new uint256[](_investors.length); + uint256[] memory expiryTimes = new uint256[](_investors.length); + bool[] memory canBuyFromSTOs = new bool[](_investors.length); + for (uint256 i = 0; i < _investors.length; i++) { + fromTimes[i] = whitelist[_investors[i]].fromTime; + toTimes[i] = whitelist[_investors[i]].toTime; + expiryTimes[i] = whitelist[_investors[i]].expiryTime; + if (whitelist[_investors[i]].canBuyFromSTO == 0) { + canBuyFromSTOs[i] = false; + } else { + canBuyFromSTOs[i] = true; + } + } + return (fromTimes, toTimes, expiryTimes, canBuyFromSTOs); + } + /** * @notice Return the permissions flag that are associated with general trnasfer manager */ diff --git a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol index 4c81be20a..27c894fb2 100644 --- a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol @@ -18,7 +18,7 @@ contract GeneralTransferManagerFactory is ModuleFactory { ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { require(_logicContract != address(0), "Invalid logic contract"); - version = "1.0.0"; + version = "2.0.0"; name = "GeneralTransferManager"; title = "General Transfer Manager"; description = "Manage transfers using a time based whitelist"; diff --git a/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol b/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol index f5c162080..cca7b5dd1 100644 --- a/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol +++ b/contracts/modules/TransferManager/GeneralTransferManagerStorage.sol @@ -24,13 +24,13 @@ contract GeneralTransferManagerStorage { } // Allows all TimeRestrictions to be offset - struct Offset { - uint64 time; - uint8 isForward; + struct Defaults { + uint64 fromTime; + uint64 toTime; } // Offset to be applied to all timings (except KYC expiry) - Offset public offset; + Defaults public defaults; // List of all addresses that have been added to the GTM at some point address[] public investors; diff --git a/test/b_capped_sto.js b/test/b_capped_sto.js index b1365ad3b..5024b0dfc 100644 --- a/test/b_capped_sto.js +++ b/test/b_capped_sto.js @@ -360,7 +360,7 @@ contract("CappedSTO", accounts => { balanceOfReceiver = await web3.eth.getBalance(account_fundsReceiver); // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, true, { from: account_issuer }); @@ -443,7 +443,7 @@ contract("CappedSTO", accounts => { fromTime, toTime + duration.days(20), expiryTime, - 1, + true, { from: account_issuer } @@ -565,7 +565,7 @@ contract("CappedSTO", accounts => { it("Should successfully whitelist investor 3", async () => { balanceOfReceiver = await web3.eth.getBalance(account_fundsReceiver); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, true, { from: account_issuer, gas: 500000 }); @@ -733,7 +733,7 @@ contract("CappedSTO", accounts => { "Tokens are not transfered properly" ); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, P_fromTime, P_toTime, P_expiryTime, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, P_fromTime, P_toTime, P_expiryTime, true, { from: account_issuer, gas: 500000 }); @@ -800,7 +800,7 @@ contract("CappedSTO", accounts => { P_fromTime, P_toTime + duration.days(20), P_expiryTime, - 1, + true, { from: account_issuer, gas: 500000 @@ -997,7 +997,7 @@ contract("CappedSTO", accounts => { await I_PolyToken.getTokens(polyToInvest * Math.pow(10, 18), account_investor3); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, P_fromTime, P_toTime, P_expiryTime, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, P_fromTime, P_toTime, P_expiryTime, true, { from: account_issuer, gas: 500000 }); diff --git a/test/c_checkpoints.js b/test/c_checkpoints.js index 2ba198f83..6a08b6dea 100644 --- a/test/c_checkpoints.js +++ b/test/c_checkpoints.js @@ -149,7 +149,7 @@ contract("Checkpoints", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 0, + false, { from: account_issuer, gas: 6000000 @@ -176,7 +176,7 @@ contract("Checkpoints", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 0, + false, { from: account_issuer, gas: 6000000 @@ -201,7 +201,7 @@ contract("Checkpoints", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 0, + false, { from: account_issuer, gas: 6000000 diff --git a/test/d_count_transfer_manager.js b/test/d_count_transfer_manager.js index 4e86bdbb6..1a1e7717a 100644 --- a/test/d_count_transfer_manager.js +++ b/test/d_count_transfer_manager.js @@ -200,7 +200,7 @@ contract("CountTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 500000 @@ -230,7 +230,7 @@ contract("CountTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 500000 @@ -257,7 +257,7 @@ contract("CountTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 500000 @@ -282,7 +282,7 @@ contract("CountTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 500000 diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index 6a4baeab6..aac008d4a 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -202,7 +202,7 @@ contract("ERC20DividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(30), - 1, + true, { from: account_issuer, gas: 500000 @@ -232,7 +232,7 @@ contract("ERC20DividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(30), - 1, + true, { from: account_issuer, gas: 500000 @@ -372,7 +372,7 @@ contract("ERC20DividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(20), - 1, + true, { from: account_issuer, gas: 500000 @@ -434,7 +434,7 @@ contract("ERC20DividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 500000 diff --git a/test/f_ether_dividends.js b/test/f_ether_dividends.js index 68c11f72f..694b8611a 100644 --- a/test/f_ether_dividends.js +++ b/test/f_ether_dividends.js @@ -200,7 +200,7 @@ contract("EtherDividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(30), - 1, + true, { from: account_issuer, gas: 500000 @@ -230,7 +230,7 @@ contract("EtherDividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(30), - 1, + true, { from: account_issuer, gas: 500000 @@ -364,7 +364,7 @@ contract("EtherDividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(20), - 1, + true, { from: account_issuer, gas: 500000 @@ -415,7 +415,7 @@ contract("EtherDividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 500000 @@ -719,7 +719,7 @@ contract("EtherDividendCheckpoint", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 500000 diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index f8b1ed989..5d019f521 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -197,6 +197,8 @@ contract("GeneralTransferManager", accounts => { assert.equal(tx.logs[0].args._investor, account_affiliates1); assert.equal(tx.logs[1].args._investor, account_affiliates2); assert.deepEqual(await I_GeneralTransferManager.getInvestors.call(), [account_affiliates1, account_affiliates2]); + console.log(await I_GeneralTransferManager.getAllInvestorsData.call()); + console.log(await I_GeneralTransferManager.getInvestorsData.call([account_affiliates1, account_affiliates2])); }); it("Should whitelist lots of addresses and check gas", async () => { @@ -367,7 +369,7 @@ contract("GeneralTransferManager", accounts => { }); }); - describe("Buy tokens using on-chain whitelist and negative offset", async () => { + describe("Buy tokens using on-chain whitelist and defaults", async () => { // let snap_id; it("Should Buy the tokens", async () => { @@ -375,8 +377,8 @@ contract("GeneralTransferManager", accounts => { // snap_id = await takeSnapshot(); let tx = await I_GeneralTransferManager.modifyWhitelist( account_investor1, - latestTime() + duration.days(10), - latestTime() + duration.days(10), + 0, + 0, latestTime() + duration.days(20), true, { @@ -391,36 +393,8 @@ contract("GeneralTransferManager", accounts => { "Failed in adding the investor in whitelist" ); - // Jump time - await increaseTime(5000); - - // Mint some tokens - await I_DummySTO.generateTokens(account_investor1, web3.utils.toWei("1", "ether"), { from: token_owner }); - - await catchRevert(I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1})); - assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toNumber(), web3.utils.toWei("3", "ether")); - }); - - it("Add an offset and check transfers are disabled", async () => { - let tx = await I_GeneralTransferManager.modifyOffset(duration.days(10), 0, {from: token_owner}); - await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); - assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toNumber(), web3.utils.toWei("3", "ether")); - tx = await I_GeneralTransferManager.modifyOffset(0, 0, {from: token_owner}); - // await revertToSnapshot(snap_id); - }); - - }); - - - describe("Buy tokens using on-chain whitelist and positive offset", async () => { - // let snap_id; - - it("Should Buy the tokens", async () => { - - // Add the Investor in to the whitelist - // snap_id = await takeSnapshot(); - let tx = await I_GeneralTransferManager.modifyWhitelist( - account_investor1, + tx = await I_GeneralTransferManager.modifyWhitelist( + account_investor2, latestTime(), latestTime(), latestTime() + duration.days(20), @@ -433,37 +407,49 @@ contract("GeneralTransferManager", accounts => { assert.equal( tx.logs[0].args._investor.toLowerCase(), - account_investor1.toLowerCase(), + account_investor2.toLowerCase(), "Failed in adding the investor in whitelist" ); // Jump time await increaseTime(5000); - // console.log("vT1: " + JSON.stringify(await I_GeneralTransferManager.verifyTransfer.call(account_investor1, account_investor1, web3.utils.toWei("1", "ether"), "", false))); - // console.log("vT2: " + JSON.stringify(await I_GeneralTransferManager.verifyTransfer.call("0x0000000000000000000000000000000000000000", account_investor1, web3.utils.toWei("1", "ether"), "", false))); - // Mint some tokens - console.log(await I_GeneralTransferManager.offset.call()); - await I_DummySTO.generateTokens(account_investor1, web3.utils.toWei("1", "ether"), { from: token_owner }); + // Can transfer tokens + await I_SecurityToken.transfer(account_investor2, web3.utils.toWei("1", "ether"), {from: account_investor1}); + assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toNumber(), web3.utils.toWei("1", "ether")); + assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toNumber(), web3.utils.toWei("1", "ether")); + }); - assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toNumber(), web3.utils.toWei("4", "ether")); - await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); + it("Add a from default and check transfers are disabled then enabled in the future", async () => { + let tx = await I_GeneralTransferManager.modifyDefaults(latestTime() + duration.days(5), 0, {from: token_owner}); + await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor2}); + await catchRevert(I_SecurityToken.transfer(account_investor2, web3.utils.toWei("1", "ether"), {from: account_investor1})); + await increaseTime(duration.days(5)); + await I_SecurityToken.transfer(account_investor2, web3.utils.toWei("1", "ether"), {from: account_investor1}); }); - it("Add an offset and check transfers are disabled", async () => { - let tx = await I_GeneralTransferManager.modifyOffset(duration.days(10), 1, {from: token_owner}); - // console.log("vT1: " + JSON.stringify(await I_GeneralTransferManager.verifyTransfer.call(account_investor1, account_investor1, web3.utils.toWei("1", "ether"), "", false))); - // console.log("vT2: " + JSON.stringify(await I_GeneralTransferManager.verifyTransfer.call("0x0000000000000000000000000000000000000000", account_investor1, web3.utils.toWei("1", "ether"), "", false))); + it("Add a to default and check transfers are disabled then enabled in the future", async () => { + let tx = await I_GeneralTransferManager.modifyDefaults(0, latestTime() + duration.days(5), {from: token_owner}); + await catchRevert(I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor2})); + await I_SecurityToken.transfer(account_investor2, web3.utils.toWei("1", "ether"), {from: account_investor1}); + await increaseTime(duration.days(5)); + await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("2", "ether"), {from: account_investor2}); + // revert changes + await I_GeneralTransferManager.modifyWhitelist( + account_investor2, + 0, + 0, + 0, + false, + { + from: account_issuer, + gas: 6000000 + } + ); + await I_GeneralTransferManager.modifyDefaults(0, 0, {from: token_owner}); + }); - await catchRevert(I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1})); - await increaseTime(duration.days(10)); - // console.log("vT1: " + JSON.stringify(await I_GeneralTransferManager.verifyTransfer.call(account_investor1, account_investor1, web3.utils.toWei("1", "ether"), "", false))); - // console.log("vT2: " + JSON.stringify(await I_GeneralTransferManager.verifyTransfer.call("0x0000000000000000000000000000000000000000", account_investor1, web3.utils.toWei("1", "ether"), "", false))); - await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor1}); - tx = await I_GeneralTransferManager.modifyOffset(0, 0, {from: token_owner}); - // await revertToSnapshot(snap_id); - }); }); diff --git a/test/i_Issuance.js b/test/i_Issuance.js index efcf0db96..ac1fcdd37 100644 --- a/test/i_Issuance.js +++ b/test/i_Issuance.js @@ -215,7 +215,7 @@ contract("Issuance", accounts => { fromTime + duration.days(70), toTime + duration.days(90), expiryTime + duration.days(50), - 1, + true, { from: account_polymath } @@ -271,7 +271,7 @@ contract("Issuance", accounts => { }); it("should add the investor into the whitelist by the delegate", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor2, fromTime, toTime, expiryTime, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor2, fromTime, toTime, expiryTime, true, { from: account_delegate, gas: 7000000 }); diff --git a/test/j_manual_approval_transfer_manager.js b/test/j_manual_approval_transfer_manager.js index c817f5c44..0461f287a 100644 --- a/test/j_manual_approval_transfer_manager.js +++ b/test/j_manual_approval_transfer_manager.js @@ -171,7 +171,7 @@ contract("ManualApprovalTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 6000000 @@ -201,7 +201,7 @@ contract("ManualApprovalTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 6000000 @@ -290,7 +290,7 @@ contract("ManualApprovalTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 6000000 diff --git a/test/l_percentage_transfer_manager.js b/test/l_percentage_transfer_manager.js index 530b202c8..e122bdea2 100644 --- a/test/l_percentage_transfer_manager.js +++ b/test/l_percentage_transfer_manager.js @@ -192,7 +192,7 @@ contract("PercentageTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 6000000 @@ -222,7 +222,7 @@ contract("PercentageTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 6000000 @@ -287,7 +287,7 @@ contract("PercentageTransferManager", accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 6000000 diff --git a/test/m_presale_sto.js b/test/m_presale_sto.js index 35a348c30..a89932dc4 100644 --- a/test/m_presale_sto.js +++ b/test/m_presale_sto.js @@ -236,7 +236,7 @@ contract("PreSaleSTO", accounts => { expiryTime = toTime + duration.days(100); // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, true, { from: account_issuer, gas: 6000000 }); @@ -277,7 +277,7 @@ contract("PreSaleSTO", accounts => { expiryTime = toTime + duration.days(100); // Add the Investor in to the whitelist - let tx1 = await I_GeneralTransferManager.modifyWhitelist(account_investor2, fromTime, toTime, expiryTime, 1, { + let tx1 = await I_GeneralTransferManager.modifyWhitelist(account_investor2, fromTime, toTime, expiryTime, true, { from: account_issuer, gas: 6000000 }); @@ -285,7 +285,7 @@ contract("PreSaleSTO", accounts => { assert.equal(tx1.logs[0].args._investor, account_investor2, "Failed in adding the investor in whitelist"); // Add the Investor in to the whitelist - let tx2 = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, 1, { + let tx2 = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, true, { from: account_issuer, gas: 6000000 }); diff --git a/test/o_security_token.js b/test/o_security_token.js index 7d2722a20..52521181e 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -193,7 +193,7 @@ contract("SecurityToken", accounts => { let toTime = fromTime + duration.days(100); let expiryTime = toTime + duration.days(100); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_affiliate1, fromTime, toTime, expiryTime, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_affiliate1, fromTime, toTime, expiryTime, true, { from: token_owner, gas: 6000000 }); @@ -212,7 +212,7 @@ contract("SecurityToken", accounts => { let toTime = fromTime + duration.days(100); let expiryTime = toTime + duration.days(100); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_affiliate2, fromTime, toTime, expiryTime, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_affiliate2, fromTime, toTime, expiryTime, true, { from: token_owner, gas: 6000000 }); @@ -517,7 +517,7 @@ contract("SecurityToken", accounts => { toTime = fromTime + duration.days(100); expiryTime = toTime + duration.days(100); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, true, { from: token_owner, gas: 6000000 }); @@ -614,7 +614,7 @@ contract("SecurityToken", accounts => { }); it("Should transfer from whitelist investor1 to whitelist investor 2", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor2, fromTime, toTime, expiryTime, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor2, fromTime, toTime, expiryTime, true, { from: token_owner, gas: 500000 }); @@ -636,7 +636,7 @@ contract("SecurityToken", accounts => { it("Should transferFrom from one investor to other", async () => { await I_SecurityToken.approve(account_investor1, 2 * Math.pow(10, 18), { from: account_investor2 }); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, true, { from: token_owner, gas: 500000 }); @@ -682,7 +682,7 @@ contract("SecurityToken", accounts => { }); it("Should add the investor in the whitelist by the delegate", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, fromTime, toTime, expiryTime, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, fromTime, toTime, expiryTime, true, { from: account_delegate, gas: 6000000 }); @@ -722,7 +722,7 @@ contract("SecurityToken", accounts => { }); it("Should remove investor from the whitelist by the delegate", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, 0, 0, 0, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, 0, 0, 0, true, { from: account_delegate, gas: 6000000 }); @@ -751,7 +751,7 @@ contract("SecurityToken", accounts => { }); it("Should fail in buying to tokens", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, fromTime, toTime, expiryTime, 1, { + let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, fromTime, toTime, expiryTime, true, { from: account_delegate, gas: 6000000 }); @@ -939,7 +939,7 @@ contract("SecurityToken", accounts => { latestTime(), latestTime() + duration.seconds(2), latestTime() + duration.days(50), - 1, + true, { from: account_delegate, gas: 6000000 @@ -982,7 +982,7 @@ contract("SecurityToken", accounts => { latestTime(), latestTime() + duration.seconds(2), latestTime() + duration.days(50), - 1, + true, { from: account_delegate, gas: 6000000 diff --git a/test/p_usd_tiered_sto.js b/test/p_usd_tiered_sto.js index 8a274942a..1bec3697f 100644 --- a/test/p_usd_tiered_sto.js +++ b/test/p_usd_tiered_sto.js @@ -1005,7 +1005,7 @@ contract("USDTieredSTO", accounts => { let fromTime = latestTime(); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let whitelisted = 1; + let whitelisted = true; await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); @@ -1105,7 +1105,7 @@ contract("USDTieredSTO", accounts => { let fromTime = latestTime(); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let whitelisted = 1; + let whitelisted = true; await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); @@ -1160,7 +1160,7 @@ contract("USDTieredSTO", accounts => { let fromTime = latestTime(); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let whitelisted = 1; + let whitelisted = true; await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); @@ -1230,7 +1230,7 @@ contract("USDTieredSTO", accounts => { let fromTime = latestTime(); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let whitelisted = 1; + let whitelisted = true; await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); @@ -1285,7 +1285,7 @@ contract("USDTieredSTO", accounts => { let fromTime = latestTime(); let toTime = latestTime(); let expiryTime = toTime + duration.days(100); - let whitelisted = 1; + let whitelisted = true; await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER }); @@ -1353,7 +1353,7 @@ contract("USDTieredSTO", accounts => { let fromTime = latestTime(); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let whitelisted = 1; + let whitelisted = true; const tx1 = await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, { from: ISSUER diff --git a/test/q_usd_tiered_sto_sim.js b/test/q_usd_tiered_sto_sim.js index 31929ade5..b287cb201 100644 --- a/test/q_usd_tiered_sto_sim.js +++ b/test/q_usd_tiered_sto_sim.js @@ -353,13 +353,13 @@ contract("USDTieredSTO Sim", accounts => { let fromTime = latestTime() + duration.days(15); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let canBuyFromSTO = 1; + let canBuyFromSTO = true; await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, canBuyFromSTO, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(ACCREDITED2, fromTime, toTime, expiryTime, canBuyFromSTO, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, canBuyFromSTO, { from: ISSUER }); await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED2, fromTime, toTime, expiryTime, canBuyFromSTO, { from: ISSUER }); - await I_GeneralTransferManager.modifyWhitelist(NOTAPPROVED, fromTime, toTime, expiryTime, 0, { from: ISSUER }); + await I_GeneralTransferManager.modifyWhitelist(NOTAPPROVED, fromTime, toTime, expiryTime, false, { from: ISSUER }); await increaseTime(duration.days(3)); diff --git a/test/r_concurrent_STO.js b/test/r_concurrent_STO.js index 36761308e..60cdd14f9 100644 --- a/test/r_concurrent_STO.js +++ b/test/r_concurrent_STO.js @@ -159,7 +159,7 @@ contract("Concurrent STO", accounts => { let fromTime = latestTime(); let toTime = latestTime() + duration.days(15); let expiryTime = toTime + duration.days(100); - let canBuyFromSTO = 1; + let canBuyFromSTO = true; let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, canBuyFromSTO, { from: account_issuer, diff --git a/test/v_tracked_redemptions.js b/test/v_tracked_redemptions.js index eacddd87e..2d5ae8c6c 100644 --- a/test/v_tracked_redemptions.js +++ b/test/v_tracked_redemptions.js @@ -190,7 +190,7 @@ contract("TrackedRedemption", accounts => { latestTime(), latestTime(), latestTime() + duration.days(30), - 1, + true, { from: account_issuer, gas: 500000 @@ -220,7 +220,7 @@ contract("TrackedRedemption", accounts => { latestTime(), latestTime(), latestTime() + duration.days(30), - 1, + true, { from: account_issuer, gas: 500000 diff --git a/test/w_lockup_volume_restriction_transfer_manager.js b/test/w_lockup_volume_restriction_transfer_manager.js index 7646fb031..358e5b702 100644 --- a/test/w_lockup_volume_restriction_transfer_manager.js +++ b/test/w_lockup_volume_restriction_transfer_manager.js @@ -165,7 +165,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer }); @@ -192,7 +192,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer }); @@ -249,7 +249,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer }); diff --git a/test/x_single_trade_volume_restriction.js b/test/x_single_trade_volume_restriction.js index 25243a638..99fe5cb9e 100644 --- a/test/x_single_trade_volume_restriction.js +++ b/test/x_single_trade_volume_restriction.js @@ -165,7 +165,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, { + true, { from: account_issuer }); @@ -193,7 +193,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, { + true, { from: account_issuer }); @@ -542,7 +542,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, { + true, { from: account_issuer } ); @@ -552,7 +552,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, { + true, { from: account_issuer } ); @@ -562,7 +562,7 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, { + true, { from: account_issuer } ); diff --git a/test/y_scheduled_checkpoints.js b/test/y_scheduled_checkpoints.js index 864c6b9a1..5fcc03a74 100644 --- a/test/y_scheduled_checkpoints.js +++ b/test/y_scheduled_checkpoints.js @@ -192,7 +192,7 @@ contract('ScheduledCheckpoint', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 6000000 @@ -235,7 +235,7 @@ contract('ScheduledCheckpoint', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 6000000 @@ -270,7 +270,7 @@ contract('ScheduledCheckpoint', accounts => { latestTime(), latestTime(), latestTime() + duration.days(10), - 1, + true, { from: account_issuer, gas: 6000000 From 29886635ffe51e43803b337a41eb10f463e3e7ce Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 28 Nov 2018 20:03:50 +0000 Subject: [PATCH 67/93] Update change log --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e19e93ce..4b0a145fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,8 @@ All notable changes to this project will be documented in this file. * Removed individual mappings for tier data removed in UDSTSTO. # GeneralTransferManager -* Add an Offset that can be used to move all from & to dates forwards or backwards by a fixed offset. +* `getInvestors`, `getAllInvestorsData`, `getInvestorsData` added to GTM to allow easy data queries. +* `modifyDefaults(uint64 _defaultFromTime, uint64 _defaultToTime)` added which sets a default timestamp used when `fromTime` or `toTime` are 0 * Add `address[] public investors` to record a list of all addresses that have been added to the whitelist (`getInvestors`) * Fix for when `allowAllWhitelistIssuances` is FALSE * Make GTM a Proxy based implementation to reduce deployment gas costs From dd62de4ce81ce745376410fc2d650260d82060ab Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Thu, 29 Nov 2018 19:36:26 +0200 Subject: [PATCH 68/93] data structure refactoring --- .../modules/Wallet/VestingEscrowWallet.sol | 346 ++++++++++-------- 1 file changed, 201 insertions(+), 145 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 52c3e5a8f..f4af38955 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -14,16 +14,20 @@ contract VestingEscrowWallet is IWallet { bytes32 public constant ADMIN = "ADMIN"; struct Schedule { - uint256 numberOfTokens; + //name of the template + bytes32 templateName; + //tokens that were already claimed uint256 claimedTokens; - uint256 duration; - uint256 frequency; + //start time of the schedule uint256 startTime; } struct Template { + //total amount of tokens uint256 numberOfTokens; + //schedule duration uint256 duration; + //schedule frequency uint256 frequency; } @@ -31,34 +35,49 @@ contract VestingEscrowWallet is IWallet { uint256 public unassignedTokens; - mapping (address => Schedule[]) public schedules; address[] public beneficiaries; - Template[] public templates; + //holds schedules for user + mapping(address => Schedule[]) public schedules; + //holds template names for user + mapping(address => bytes32[]) internal userToTemplates; + //mapping use to store the indexes for different template names for a user + mapping(address => mapping(bytes32 => uint256)) internal templateToScheduleIndex; + + //holds user for template + mapping(bytes32 => address[]) internal templateToUsers; + //mapping use to store the indexes for users for a template + mapping(bytes32 => mapping(address => uint256)) internal templateToUserIndex; + mapping(bytes32 => Template) templates; + bytes32[] public templateNames; + + // Emit when new schedule is added event AddSchedule( address indexed _beneficiary, - uint256 _numberOfTokens, - uint256 _duration, - uint256 _frequency, - uint256 _startTime, - uint256 _index + bytes32 _templateName, + uint256 _startTime ); + // Emit when schedule is modified event ModifySchedule( address indexed _beneficiary, - uint256 _index, - uint256 _numberOfTokens, - uint256 _duration, - uint256 _frequency, + bytes32 _templateName, uint256 _startTime ); + // Emit when all schedules are revoked for user event RevokeAllSchedules(address indexed _beneficiary); - event RevokeSchedule(address indexed _beneficiary, uint256 _index); + // Emit when schedule is revoked + event RevokeSchedule(address indexed _beneficiary, bytes32 _templateName); + // Emit when tokes are deposited to wallet event DepositTokens(uint256 _numberOfTokens, address _sender); + // Emit when all unassigned tokens are sent to treasury event SendToTreasury(uint256 _numberOfTokens, address _sender); + // Emit when is sent tokes to user event SendTokens(address indexed _beneficiary, uint256 _numberOfTokens); - event AddTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, uint256 _index); - event RemoveTemplate(uint256 _index); + // Emit when template is added + event AddTemplate(bytes32 _name, uint256 _numberOfTokens, uint256 _duration, uint256 _frequency); + // Emit when template is removed + event RemoveTemplate(bytes32 _name); /** * @notice Constructor @@ -119,27 +138,43 @@ contract VestingEscrowWallet is IWallet { /** * @notice Add template + * @param _name name of template * @param _numberOfTokens number of tokens * @param _duration vesting duration * @param _frequency vesting frequency */ - function addTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) external withPerm(ADMIN) { + function addTemplate(bytes32 _name, uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) external withPerm(ADMIN) { + _addTemplate(_name, _numberOfTokens, _duration, _frequency); + } + + function _addTemplate(bytes32 _name, uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) internal { + require(!_isTemplateExists(_name)); _validateTemplate(_numberOfTokens, _duration, _frequency); - templates.push(Template(_numberOfTokens, _duration, _frequency)); - emit AddTemplate(_numberOfTokens, _duration, _frequency, templates.length - 1); + templateNames.push(_name); + templates[_name] = Template(_numberOfTokens, _duration, _frequency); + emit AddTemplate(_name, _numberOfTokens, _duration, _frequency); } /** * @notice Removes template - * @param _index index of the template + * @param _name name of template */ - function removeTemplate(uint256 _index) external withPerm(ADMIN) { - require(_index < templates.length, "Template not found"); - if (_index != templates.length - 1) { - templates[_index] = templates[templates.length - 1]; + function removeTemplate(bytes32 _name) external withPerm(ADMIN) { + require(_isTemplateExists(_name)); + require(!_isTemplateUsed(_name)); + // delete template data + delete templates[_name]; + uint256 i; + for (i = 0; i < templateNames.length; i++) { + if (_name == templateNames[i]) { + break; + } + } + if (i != templateNames.length - 1) { + templateNames[i] = templateNames[templateNames.length - 1]; } - templates.length--; - emit RemoveTemplate(_index); + templateNames.length--; + emit RemoveTemplate(_name); } /** @@ -147,12 +182,21 @@ contract VestingEscrowWallet is IWallet { * @return count of templates */ function getTemplateCount() external view returns(uint256) { - return templates.length; + return templateNames.length; + } + + /** + * @notice get the list of template names + * @return bytes32 Array of template names + */ + function getTemplateNames() external view returns(bytes32[]) { + return templateNames; } /** * @notice Adds vesting schedules for each of beneficiary * @param _beneficiary beneficiary's addresses + * @param _templateName name of the template that will be created * @param _numberOfTokens number of tokens * @param _duration vesting duration * @param _frequency vesting frequency @@ -160,6 +204,7 @@ contract VestingEscrowWallet is IWallet { */ function addSchedule( address _beneficiary, + bytes32 _templateName, uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, @@ -168,11 +213,12 @@ contract VestingEscrowWallet is IWallet { public withPerm(ADMIN) { - _addSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); + _addSchedule(_beneficiary, _templateName, _numberOfTokens, _duration, _frequency, _startTime); } function _addSchedule( address _beneficiary, + bytes32 _templateName, uint256 _numberOfTokens, uint256 _duration, uint256 _frequency, @@ -180,102 +226,98 @@ contract VestingEscrowWallet is IWallet { ) internal { - _validateSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); - if (_numberOfTokens > unassignedTokens) { - _depositTokens(_numberOfTokens.sub(unassignedTokens)); - } - unassignedTokens = unassignedTokens.sub(_numberOfTokens); - //add beneficiary to the schedule list only if adding first schedule - if (schedules[_beneficiary].length == 0) { - beneficiaries.push(_beneficiary); - } - schedules[_beneficiary].push(Schedule(_numberOfTokens, 0, _duration, _frequency, _startTime)); - uint256 index = schedules[_beneficiary].length - 1; - emit AddSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime, index); + _addTemplate(_templateName, _numberOfTokens, _duration, _frequency); + _addScheduleFromTemplate(_beneficiary, _templateName, _startTime); } /** * @notice Adds vesting schedules from template for each of beneficiary * @param _beneficiary beneficiary's addresses - * @param _index index of the template + * @param _templateName name of the template * @param _startTime vesting start time */ - function addScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startTime) external withPerm(ADMIN) { - _addScheduleFromTemplate(_beneficiary, _index, _startTime); + function addScheduleFromTemplate(address _beneficiary, bytes32 _templateName, uint256 _startTime) external withPerm(ADMIN) { + _addScheduleFromTemplate(_beneficiary, _templateName, _startTime); } - function _addScheduleFromTemplate(address _beneficiary, uint256 _index, uint256 _startTime) internal { - require(_index < templates.length, "Template not found"); - Template memory template = templates[_index]; - _addSchedule(_beneficiary, template.numberOfTokens, template.duration, template.frequency, _startTime); + function _addScheduleFromTemplate(address _beneficiary, bytes32 _templateName, uint256 _startTime) internal { + require(_beneficiary != address(0), "Invalid address"); + require(_isTemplateExists(_templateName)); + uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; + require( + schedules[_beneficiary].length == 0 || + schedules[_beneficiary][index].templateName != _templateName, + "Schedule from this template already added" + ); + require(now < _startTime, "Date in the past"); + uint256 numberOfTokens = templates[_templateName].numberOfTokens; + if (numberOfTokens > unassignedTokens) { + _depositTokens(numberOfTokens.sub(unassignedTokens)); + } + unassignedTokens = unassignedTokens.sub(numberOfTokens); + //add beneficiary to the schedule list only if adding first schedule + if (schedules[_beneficiary].length == 0) { + beneficiaries.push(_beneficiary); + } + schedules[_beneficiary].push(Schedule(_templateName, 0, _startTime)); + userToTemplates[_beneficiary].push(_templateName); + templateToScheduleIndex[_beneficiary][_templateName] = schedules[_beneficiary].length - 1; + templateToUsers[_templateName].push(_beneficiary); + templateToUserIndex[_templateName][_beneficiary] = templateToUsers[_templateName].length - 1; + emit AddSchedule(_beneficiary, _templateName, _startTime); } /** * @notice Modifies vesting schedules for each of beneficiary * @param _beneficiary beneficiary's addresses - * @param _index index of schedule - * @param _numberOfTokens number of tokens - * @param _duration vesting duration - * @param _frequency vesting frequency + * @param _templateName name of the template * @param _startTime vesting start time */ - function modifySchedule( - address _beneficiary, - uint256 _index, - uint256 _numberOfTokens, - uint256 _duration, - uint256 _frequency, - uint256 _startTime - ) - public - withPerm(ADMIN) - { - _modifySchedule(_beneficiary, _index, _numberOfTokens, _duration, _frequency, _startTime); + function modifySchedule(address _beneficiary, bytes32 _templateName, uint256 _startTime) public withPerm(ADMIN) { + _modifySchedule(_beneficiary, _templateName, _startTime); } - function _modifySchedule( - address _beneficiary, - uint256 _index, - uint256 _numberOfTokens, - uint256 _duration, - uint256 _frequency, - uint256 _startTime - ) - internal - { - _validateSchedule(_beneficiary, _numberOfTokens, _duration, _frequency, _startTime); - _checkSchedule(_beneficiary, _index); - Schedule storage schedule = schedules[_beneficiary][_index]; + function _modifySchedule(address _beneficiary, bytes32 _templateName, uint256 _startTime) internal { + _checkSchedule(_beneficiary, _templateName); + require(now < _startTime, "Date in the past"); + uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; + Schedule storage schedule = schedules[_beneficiary][index]; /*solium-disable-next-line security/no-block-members*/ require(now < schedule.startTime, "Schedule started"); - if (_numberOfTokens <= schedule.numberOfTokens) { - unassignedTokens = unassignedTokens.add(schedule.numberOfTokens.sub(_numberOfTokens)); - } else { - if (_numberOfTokens.sub(schedule.numberOfTokens) > unassignedTokens) { - _depositTokens(_numberOfTokens.sub(schedule.numberOfTokens).sub(unassignedTokens)); - } - unassignedTokens = unassignedTokens.sub(_numberOfTokens.sub(schedule.numberOfTokens)); - } - schedules[_beneficiary][_index] = Schedule(_numberOfTokens, 0, _duration, _frequency, _startTime); - emit ModifySchedule(_beneficiary, _index, _numberOfTokens, _duration, _frequency, _startTime); + schedule.startTime = _startTime; + emit ModifySchedule(_beneficiary, _templateName, _startTime); } /** * @notice Revokes beneficiary's schedule * @param _beneficiary beneficiary's address - * @param _index index of the schedule + * @param _templateName name of the template */ - function revokeSchedule(address _beneficiary, uint256 _index) external withPerm(ADMIN) { - _checkSchedule(_beneficiary, _index); - _sendTokens(_beneficiary, _index); + function revokeSchedule(address _beneficiary, bytes32 _templateName) external withPerm(ADMIN) { + _checkSchedule(_beneficiary, _templateName); + uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; + _sendTokens(_beneficiary, index); Schedule[] storage userSchedules = schedules[_beneficiary]; - uint256 releasedTokens = _getReleasedTokens(_beneficiary, _index); - unassignedTokens = unassignedTokens.add(userSchedules[_index].numberOfTokens.sub(releasedTokens)); - if (_index != userSchedules.length - 1) { - userSchedules[_index] = userSchedules[userSchedules.length - 1]; + //update unassignedTokens + uint256 releasedTokens = _getReleasedTokens(_beneficiary, index); + unassignedTokens = unassignedTokens.add(templates[_templateName].numberOfTokens.sub(releasedTokens)); + //delete user schedule and relation between user and template + if (index != userSchedules.length - 1) { + userSchedules[index] = userSchedules[userSchedules.length - 1]; + userToTemplates[_beneficiary][index] = userToTemplates[_beneficiary][userToTemplates[_beneficiary].length - 1]; } userSchedules.length--; - emit RevokeSchedule(_beneficiary, _index); + userToTemplates[_beneficiary].length--; + delete templateToScheduleIndex[_beneficiary][_templateName]; + //delete relation between template and user + uint256 templateIndex = templateToUserIndex[_templateName][_beneficiary]; + if (templateIndex != templateToUsers[_templateName].length - 1) { + templateToUsers[_templateName][templateIndex] = templateToUsers[_templateName][templateToUsers[_templateName].length - 1]; + } + templateToUsers[_templateName].length--; + delete templateToUserIndex[_templateName][_beneficiary]; + + emit RevokeSchedule(_beneficiary, _templateName); } /** @@ -292,41 +334,62 @@ contract VestingEscrowWallet is IWallet { Schedule[] storage userSchedules = schedules[_beneficiary]; for (uint256 i = 0; i < userSchedules.length; i++) { uint256 releasedTokens = _getReleasedTokens(_beneficiary, i); - unassignedTokens = unassignedTokens.add(userSchedules[i].numberOfTokens.sub(releasedTokens)); + Template storage template = templates[userSchedules[i].templateName]; + unassignedTokens = unassignedTokens.add(template.numberOfTokens.sub(releasedTokens)); + delete templateToScheduleIndex[_beneficiary][userSchedules[i].templateName]; } userSchedules.length = 0; + delete userToTemplates[_beneficiary]; emit RevokeAllSchedules(_beneficiary); } /** * @notice Returns beneficiary's schedule * @param _beneficiary beneficiary's address - * @param _index index of the schedule + * @param _templateName name of the template * @return beneficiary's schedule */ - function getSchedule(address _beneficiary, uint256 _index) external view returns(uint256, uint256, uint256, uint256, State) { - _checkSchedule(_beneficiary, _index); - Schedule storage schedule = schedules[_beneficiary][_index]; + function getSchedule(address _beneficiary, bytes32 _templateName) external view returns(uint256, uint256, uint256, uint256, State) { + _checkSchedule(_beneficiary, _templateName); + uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; + Schedule storage schedule = schedules[_beneficiary][index]; return ( - schedule.numberOfTokens, - schedule.duration, - schedule.frequency, + templates[schedule.templateName].numberOfTokens, + templates[schedule.templateName].duration, + templates[schedule.templateName].frequency, schedule.startTime, - getScheduleState(_beneficiary, _index) + getScheduleState(_beneficiary, _templateName) ); } - function getScheduleState(address _beneficiary, uint256 _index) public view returns(State) { - Schedule memory schedule = schedules[_beneficiary][_index]; + /** + * @notice Returns state of the schedule + * @param _beneficiary beneficiary's address + * @return state of the schedule + */ + function getScheduleState(address _beneficiary, bytes32 _templateName) public view returns(State) { + _checkSchedule(_beneficiary, _templateName); + uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; + Schedule memory schedule = schedules[_beneficiary][index]; if (now < schedule.startTime) { return State.CREATED; - } else if (now > schedule.startTime && now < schedule.startTime.add(schedule.duration)) { + } else if (now > schedule.startTime && now < schedule.startTime.add(templates[_templateName].duration)) { return State.STARTED; } else { return State.COMPLETED; } } + /** + * @notice Returns list of template names + * @param _beneficiary beneficiary's address + * @return list of template names + */ + function getTemplateNames(address _beneficiary) external view returns(bytes32[]) { + require(_beneficiary != address(0), "Invalid address"); + return userToTemplates[_beneficiary]; + } + /** * @notice Returns count of beneficiary's schedules * @param _beneficiary beneficiary's address @@ -345,15 +408,16 @@ contract VestingEscrowWallet is IWallet { function _getReleasedTokens(address _beneficiary, uint256 _index) internal view returns(uint256) { Schedule storage schedule = schedules[_beneficiary][_index]; + Template storage template = templates[schedule.templateName]; /*solium-disable-next-line security/no-block-members*/ if (now > schedule.startTime) { - uint256 periodCount = schedule.duration.div(schedule.frequency); + uint256 periodCount = template.duration.div(template.frequency); /*solium-disable-next-line security/no-block-members*/ - uint256 periodNumber = (now.sub(schedule.startTime)).div(schedule.frequency); + uint256 periodNumber = (now.sub(schedule.startTime)).div(template.frequency); if (periodNumber > periodCount) { periodNumber = periodCount; } - return schedule.numberOfTokens.mul(periodNumber).div(periodCount); + return template.numberOfTokens.mul(periodNumber).div(periodCount); } else { return 0; } @@ -388,6 +452,7 @@ contract VestingEscrowWallet is IWallet { /** * @notice Used to bulk add vesting schedules for each of beneficiaries * @param _beneficiaries array of beneficiary's addresses + * @param _templateNames array of the template names * @param _numberOfTokens array of number of tokens * @param _durations array of vesting duration * @param _frequencies array of vesting frequency @@ -395,15 +460,17 @@ contract VestingEscrowWallet is IWallet { */ function addScheduleMulti( address[] _beneficiaries, + bytes32[] _templateNames, uint256[] _numberOfTokens, uint256[] _durations, uint256[] _frequencies, uint256[] _startTimes ) - external + public withPerm(ADMIN) { require( + _beneficiaries.length == _templateNames.length && /*solium-disable-line operator-whitespace*/ _beneficiaries.length == _numberOfTokens.length && /*solium-disable-line operator-whitespace*/ _beneficiaries.length == _durations.length && /*solium-disable-line operator-whitespace*/ _beneficiaries.length == _frequencies.length && /*solium-disable-line operator-whitespace*/ @@ -411,20 +478,20 @@ contract VestingEscrowWallet is IWallet { "Arrays sizes mismatch" ); for (uint256 i = 0; i < _beneficiaries.length; i++) { - _addSchedule(_beneficiaries[i], _numberOfTokens[i], _durations[i], _frequencies[i], _startTimes[i]); + _addSchedule(_beneficiaries[i], _templateNames[i], _numberOfTokens[i], _durations[i], _frequencies[i], _startTimes[i]); } } /** * @notice Used to bulk add vesting schedules from template for each of beneficiaries * @param _beneficiaries array of beneficiary's addresses - * @param _index index of the template + * @param _templateNames array of the template names * @param _startTimes array of vesting start time */ - function addScheduleFromTemplateMulti(address[] _beneficiaries, uint256 _index, uint256[] _startTimes) external withPerm(ADMIN) { - require(_beneficiaries.length == _startTimes.length, "Arrays sizes mismatch"); + function addScheduleFromTemplateMulti(address[] _beneficiaries, bytes32[] _templateNames, uint256[] _startTimes) external withPerm(ADMIN) { + require(_beneficiaries.length == _templateNames.length && _beneficiaries.length == _startTimes.length, "Arrays sizes mismatch"); for (uint256 i = 0; i < _beneficiaries.length; i++) { - _addScheduleFromTemplate(_beneficiaries[i], _index, _startTimes[i]); + _addScheduleFromTemplate(_beneficiaries[i], _templateNames[i], _startTimes[i]); } } @@ -441,54 +508,43 @@ contract VestingEscrowWallet is IWallet { /** * @notice Used to bulk modify vesting schedules for each of beneficiaries * @param _beneficiaries array of beneficiary's addresses - * @param _indexes array of beneficiary's indexes of schedule - * @param _numberOfTokens array of number of tokens - * @param _durations array of vesting duration - * @param _frequencies array of vesting frequency + * @param _templateNames array of the template names * @param _startTimes array of vesting start time */ function modifyScheduleMulti( address[] _beneficiaries, - uint256[] _indexes, - uint256[] _numberOfTokens, - uint256[] _durations, - uint256[] _frequencies, + bytes32[] _templateNames, uint256[] _startTimes ) public withPerm(ADMIN) { require( - _beneficiaries.length == _indexes.length && /*solium-disable-line operator-whitespace*/ - _beneficiaries.length == _numberOfTokens.length && /*solium-disable-line operator-whitespace*/ - _beneficiaries.length == _durations.length && /*solium-disable-line operator-whitespace*/ - _beneficiaries.length == _frequencies.length && /*solium-disable-line operator-whitespace*/ + _beneficiaries.length == _templateNames.length && /*solium-disable-line operator-whitespace*/ _beneficiaries.length == _startTimes.length, "Arrays sizes mismatch" ); for (uint256 i = 0; i < _beneficiaries.length; i++) { - _modifySchedule(_beneficiaries[i], _indexes[i], _numberOfTokens[i], _durations[i], _frequencies[i], _startTimes[i]); + _modifySchedule(_beneficiaries[i], _templateNames[i], _startTimes[i]); } } - function _validateSchedule( - address _beneficiary, - uint256 _numberOfTokens, - uint256 _duration, - uint256 _frequency, - uint256 _startTime - ) - internal - view - { + function _checkSchedule(address _beneficiary, bytes32 _templateName) internal view { require(_beneficiary != address(0), "Invalid address"); - _validateTemplate(_numberOfTokens, _duration, _frequency); - require(now < _startTime, "Date in the past"); + uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; + require( + index < schedules[_beneficiary].length && + schedules[_beneficiary][index].templateName == _templateName, + "Schedule not found" + ); } - function _checkSchedule(address _beneficiary, uint256 _index) internal view { - require(_beneficiary != address(0), "Invalid address"); - require(_index < schedules[_beneficiary].length, "Schedule not found"); + function _isTemplateExists(bytes32 _name) internal view returns(bool) { + return templates[_name].numberOfTokens > 0; + } + + function _isTemplateUsed(bytes32 _name) internal view returns(bool) { + return templateToUsers[_name].length > 0; } function _validateTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) internal pure { From 4c4c9adb163c4bd424797d207e90aa312795c631 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Thu, 29 Nov 2018 20:00:19 +0200 Subject: [PATCH 69/93] refactored revokeSchedule() --- .../modules/Wallet/VestingEscrowWallet.sol | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index f4af38955..454f9afa6 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -297,11 +297,16 @@ contract VestingEscrowWallet is IWallet { _checkSchedule(_beneficiary, _templateName); uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; _sendTokens(_beneficiary, index); - Schedule[] storage userSchedules = schedules[_beneficiary]; - //update unassignedTokens uint256 releasedTokens = _getReleasedTokens(_beneficiary, index); unassignedTokens = unassignedTokens.add(templates[_templateName].numberOfTokens.sub(releasedTokens)); - //delete user schedule and relation between user and template + _deleteUserToTemplates(_beneficiary, _templateName); + _deleteTemplateToUsers(_beneficiary, _templateName); + emit RevokeSchedule(_beneficiary, _templateName); + } + + function _deleteUserToTemplates(address _beneficiary, bytes32 _templateName) internal { + uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; + Schedule[] storage userSchedules = schedules[_beneficiary]; if (index != userSchedules.length - 1) { userSchedules[index] = userSchedules[userSchedules.length - 1]; userToTemplates[_beneficiary][index] = userToTemplates[_beneficiary][userToTemplates[_beneficiary].length - 1]; @@ -309,15 +314,16 @@ contract VestingEscrowWallet is IWallet { userSchedules.length--; userToTemplates[_beneficiary].length--; delete templateToScheduleIndex[_beneficiary][_templateName]; - //delete relation between template and user + } + + function _deleteTemplateToUsers(address _beneficiary, bytes32 _templateName) internal { + uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; uint256 templateIndex = templateToUserIndex[_templateName][_beneficiary]; if (templateIndex != templateToUsers[_templateName].length - 1) { templateToUsers[_templateName][templateIndex] = templateToUsers[_templateName][templateToUsers[_templateName].length - 1]; } templateToUsers[_templateName].length--; delete templateToUserIndex[_templateName][_beneficiary]; - - emit RevokeSchedule(_beneficiary, _templateName); } /** @@ -337,8 +343,9 @@ contract VestingEscrowWallet is IWallet { Template storage template = templates[userSchedules[i].templateName]; unassignedTokens = unassignedTokens.add(template.numberOfTokens.sub(releasedTokens)); delete templateToScheduleIndex[_beneficiary][userSchedules[i].templateName]; + _deleteTemplateToUsers(_beneficiary, userSchedules[i].templateName); } - userSchedules.length = 0; + delete schedules[_beneficiary]; delete userToTemplates[_beneficiary]; emit RevokeAllSchedules(_beneficiary); } From 11b000e1644581295a0986a7b8bc50bcbddce8e6 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Thu, 29 Nov 2018 22:57:08 +0200 Subject: [PATCH 70/93] contract size optimization --- contracts/modules/Wallet/VestingEscrowWallet.sol | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 454f9afa6..c1aa7fd49 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -317,7 +317,6 @@ contract VestingEscrowWallet is IWallet { } function _deleteTemplateToUsers(address _beneficiary, bytes32 _templateName) internal { - uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; uint256 templateIndex = templateToUserIndex[_templateName][_beneficiary]; if (templateIndex != templateToUsers[_templateName].length - 1) { templateToUsers[_templateName][templateIndex] = templateToUsers[_templateName][templateToUsers[_templateName].length - 1]; @@ -365,16 +364,11 @@ contract VestingEscrowWallet is IWallet { templates[schedule.templateName].duration, templates[schedule.templateName].frequency, schedule.startTime, - getScheduleState(_beneficiary, _templateName) + _getScheduleState(_beneficiary, _templateName) ); } - /** - * @notice Returns state of the schedule - * @param _beneficiary beneficiary's address - * @return state of the schedule - */ - function getScheduleState(address _beneficiary, bytes32 _templateName) public view returns(State) { + function _getScheduleState(address _beneficiary, bytes32 _templateName) internal view returns(State) { _checkSchedule(_beneficiary, _templateName); uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; Schedule memory schedule = schedules[_beneficiary][index]; From a3f46e53be800887d10d5242e06f6bb3999ca030 Mon Sep 17 00:00:00 2001 From: satyam Date: Fri, 30 Nov 2018 14:35:22 +0530 Subject: [PATCH 71/93] fixes in the code --- .../modules/Wallet/VestingEscrowWallet.sol | 143 ++++++++++-------- 1 file changed, 84 insertions(+), 59 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index c1aa7fd49..f5049019a 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -1,8 +1,6 @@ pragma solidity ^0.4.24; -import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; -import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; import "./IWallet.sol"; /** @@ -14,42 +12,48 @@ contract VestingEscrowWallet is IWallet { bytes32 public constant ADMIN = "ADMIN"; struct Schedule { - //name of the template + // Name of the template bytes32 templateName; - //tokens that were already claimed + // Tokens that were already claimed uint256 claimedTokens; - //start time of the schedule + // Start time of the schedule uint256 startTime; } struct Template { - //total amount of tokens + // Total amount of tokens uint256 numberOfTokens; - //schedule duration + // Schedule duration (How long the schedule will last) uint256 duration; - //schedule frequency + // Schedule frequency (It is a cliff time period) uint256 frequency; } + // States used to represent the status of the schedule enum State {CREATED, STARTED, COMPLETED} - + // Number of tokens that are hold by the `this` contract but are unassigned to any schedule uint256 public unassignedTokens; - + // Address of the Treasury wallet. All of the unassigned token will transfer to that address. + address public treasuryWallet; + // List of all beneficiaries who have the schedules running/completed/created address[] public beneficiaries; - //holds schedules for user + // Holds schedules array corresponds to the affiliate/employee address mapping(address => Schedule[]) public schedules; - //holds template names for user + // Holds template names array corresponds to the affiliate/employee address mapping(address => bytes32[]) internal userToTemplates; - //mapping use to store the indexes for different template names for a user - mapping(address => mapping(bytes32 => uint256)) internal templateToScheduleIndex; - - //holds user for template + // Mapping use to store the indexes for different template names for a user. + // affiliate/employee address => template name => index + mapping(address => mapping(bytes32 => uint256)) internal userToTemplateIndex; + // Holds affiliate/employee addresses coressponds to the template name mapping(bytes32 => address[]) internal templateToUsers; - //mapping use to store the indexes for users for a template + // Mapping use to store the indexes for different users for a template. + // template name => affiliate/employee address => index mapping(bytes32 => mapping(address => uint256)) internal templateToUserIndex; - + // Store the template details corresponds to the template name mapping(bytes32 => Template) templates; + + // List of all template names bytes32[] public templateNames; // Emit when new schedule is added @@ -78,6 +82,8 @@ contract VestingEscrowWallet is IWallet { event AddTemplate(bytes32 _name, uint256 _numberOfTokens, uint256 _duration, uint256 _frequency); // Emit when template is removed event RemoveTemplate(bytes32 _name); + // Emit when the treasury wallet gets changed + event TreasuryWalletChanged(address _newWallet, address _oldWallet); /** * @notice Constructor @@ -94,7 +100,26 @@ contract VestingEscrowWallet is IWallet { * @notice This function returns the signature of the configure function */ function getInitFunction() public pure returns (bytes4) { - return bytes4(0); + return bytes4(keccak256("configure(address)")); + } + + /** + * @notice Use to intialize the treasury wallet address + * @param _treasuryWallet Address of the treasury wallet + */ + function configure(address _treasuryWallet) public onlyFactory { + require(_treasuryWallet != address(0), "Invalid address"); + treasuryWallet = _treasuryWallet; + } + + /** + * @notice Use to change the treasury wallet address + * @param _newTreasuryWallet Address of the treasury wallet + */ + function changeTreasuryWallet(address _newTreasuryWallet) public onlyOwner { + require(_newTreasuryWallet != address(0)); + emit TreasuryWalletChanged(_newTreasuryWallet, treasuryWallet); + treasuryWallet = _newTreasuryWallet; } /** @@ -105,8 +130,8 @@ contract VestingEscrowWallet is IWallet { } function _depositTokens(uint256 _numberOfTokens) internal { - require(_numberOfTokens > 0, "Should be greater than zero"); - ISecurityToken(securityToken).transferFrom(msg.sender, this, _numberOfTokens); + require(_numberOfTokens > 0, "Should be > 0"); + ISecurityToken(securityToken).transferFrom(msg.sender, address(this), _numberOfTokens); unassignedTokens = unassignedTokens.add(_numberOfTokens); emit DepositTokens(_numberOfTokens, msg.sender); } @@ -117,7 +142,7 @@ contract VestingEscrowWallet is IWallet { function sendToTreasury() external withPerm(ADMIN) { uint256 amount = unassignedTokens; unassignedTokens = 0; - ISecurityToken(securityToken).transfer(msg.sender, amount); + ISecurityToken(securityToken).transfer(treasuryWallet, amount); emit SendToTreasury(amount, msg.sender); } @@ -132,7 +157,7 @@ contract VestingEscrowWallet is IWallet { /** * @notice Used to withdraw available tokens by beneficiary */ - function withdrawAvailableTokens() external { + function pullAvailableTokens() external { _sendTokens(msg.sender); } @@ -148,7 +173,8 @@ contract VestingEscrowWallet is IWallet { } function _addTemplate(bytes32 _name, uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) internal { - require(!_isTemplateExists(_name)); + require(_name != bytes32(0), "Invalid name"); + require(!_isTemplateExists(_name), "Already exists"); _validateTemplate(_numberOfTokens, _duration, _frequency); templateNames.push(_name); templates[_name] = Template(_numberOfTokens, _duration, _frequency); @@ -160,8 +186,8 @@ contract VestingEscrowWallet is IWallet { * @param _name name of template */ function removeTemplate(bytes32 _name) external withPerm(ADMIN) { - require(_isTemplateExists(_name)); - require(!_isTemplateUsed(_name)); + require(_isTemplateExists(_name), "Already exists"); + require(templateToUsers[_name].length == 0); // delete template data delete templates[_name]; uint256 i; @@ -210,7 +236,7 @@ contract VestingEscrowWallet is IWallet { uint256 _frequency, uint256 _startTime ) - public + external withPerm(ADMIN) { _addSchedule(_beneficiary, _templateName, _numberOfTokens, _duration, _frequency, _startTime); @@ -243,13 +269,12 @@ contract VestingEscrowWallet is IWallet { function _addScheduleFromTemplate(address _beneficiary, bytes32 _templateName, uint256 _startTime) internal { require(_beneficiary != address(0), "Invalid address"); require(_isTemplateExists(_templateName)); - uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; + uint256 index = userToTemplateIndex[_beneficiary][_templateName]; require( - schedules[_beneficiary].length == 0 || schedules[_beneficiary][index].templateName != _templateName, - "Schedule from this template already added" + "Already added" ); - require(now < _startTime, "Date in the past"); + require(_startTime >= now, "Date in the past"); uint256 numberOfTokens = templates[_templateName].numberOfTokens; if (numberOfTokens > unassignedTokens) { _depositTokens(numberOfTokens.sub(unassignedTokens)); @@ -261,7 +286,7 @@ contract VestingEscrowWallet is IWallet { } schedules[_beneficiary].push(Schedule(_templateName, 0, _startTime)); userToTemplates[_beneficiary].push(_templateName); - templateToScheduleIndex[_beneficiary][_templateName] = schedules[_beneficiary].length - 1; + userToTemplateIndex[_beneficiary][_templateName] = schedules[_beneficiary].length - 1; templateToUsers[_templateName].push(_beneficiary); templateToUserIndex[_templateName][_beneficiary] = templateToUsers[_templateName].length - 1; emit AddSchedule(_beneficiary, _templateName, _startTime); @@ -279,8 +304,8 @@ contract VestingEscrowWallet is IWallet { function _modifySchedule(address _beneficiary, bytes32 _templateName, uint256 _startTime) internal { _checkSchedule(_beneficiary, _templateName); - require(now < _startTime, "Date in the past"); - uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; + require(_startTime > now, "Date in the past"); + uint256 index = userToTemplateIndex[_beneficiary][_templateName]; Schedule storage schedule = schedules[_beneficiary][index]; /*solium-disable-next-line security/no-block-members*/ require(now < schedule.startTime, "Schedule started"); @@ -295,8 +320,8 @@ contract VestingEscrowWallet is IWallet { */ function revokeSchedule(address _beneficiary, bytes32 _templateName) external withPerm(ADMIN) { _checkSchedule(_beneficiary, _templateName); - uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; - _sendTokens(_beneficiary, index); + uint256 index = userToTemplateIndex[_beneficiary][_templateName]; + _sendTokensPerSchedule(_beneficiary, index); uint256 releasedTokens = _getReleasedTokens(_beneficiary, index); unassignedTokens = unassignedTokens.add(templates[_templateName].numberOfTokens.sub(releasedTokens)); _deleteUserToTemplates(_beneficiary, _templateName); @@ -305,21 +330,23 @@ contract VestingEscrowWallet is IWallet { } function _deleteUserToTemplates(address _beneficiary, bytes32 _templateName) internal { - uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; + uint256 index = userToTemplateIndex[_beneficiary][_templateName]; Schedule[] storage userSchedules = schedules[_beneficiary]; if (index != userSchedules.length - 1) { userSchedules[index] = userSchedules[userSchedules.length - 1]; userToTemplates[_beneficiary][index] = userToTemplates[_beneficiary][userToTemplates[_beneficiary].length - 1]; + userToTemplateIndex[_beneficiary][userSchedules[index].templateName] = index; } userSchedules.length--; userToTemplates[_beneficiary].length--; - delete templateToScheduleIndex[_beneficiary][_templateName]; + delete userToTemplateIndex[_beneficiary][_templateName]; } function _deleteTemplateToUsers(address _beneficiary, bytes32 _templateName) internal { uint256 templateIndex = templateToUserIndex[_templateName][_beneficiary]; if (templateIndex != templateToUsers[_templateName].length - 1) { templateToUsers[_templateName][templateIndex] = templateToUsers[_templateName][templateToUsers[_templateName].length - 1]; + templateToUserIndex[_templateName][templateToUsers[_templateName][templateIndex]] = templateIndex; } templateToUsers[_templateName].length--; delete templateToUserIndex[_templateName][_beneficiary]; @@ -339,9 +366,9 @@ contract VestingEscrowWallet is IWallet { Schedule[] storage userSchedules = schedules[_beneficiary]; for (uint256 i = 0; i < userSchedules.length; i++) { uint256 releasedTokens = _getReleasedTokens(_beneficiary, i); - Template storage template = templates[userSchedules[i].templateName]; + Template memory template = templates[userSchedules[i].templateName]; unassignedTokens = unassignedTokens.add(template.numberOfTokens.sub(releasedTokens)); - delete templateToScheduleIndex[_beneficiary][userSchedules[i].templateName]; + delete userToTemplateIndex[_beneficiary][userSchedules[i].templateName]; _deleteTemplateToUsers(_beneficiary, userSchedules[i].templateName); } delete schedules[_beneficiary]; @@ -355,22 +382,23 @@ contract VestingEscrowWallet is IWallet { * @param _templateName name of the template * @return beneficiary's schedule */ - function getSchedule(address _beneficiary, bytes32 _templateName) external view returns(uint256, uint256, uint256, uint256, State) { + function getSchedule(address _beneficiary, bytes32 _templateName) external view returns(uint256, uint256, uint256, uint256, uint256, State) { _checkSchedule(_beneficiary, _templateName); - uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; - Schedule storage schedule = schedules[_beneficiary][index]; + uint256 index = userToTemplateIndex[_beneficiary][_templateName]; + Schedule memory schedule = schedules[_beneficiary][index]; return ( templates[schedule.templateName].numberOfTokens, templates[schedule.templateName].duration, templates[schedule.templateName].frequency, schedule.startTime, + schedule.claimedTokens, _getScheduleState(_beneficiary, _templateName) ); } function _getScheduleState(address _beneficiary, bytes32 _templateName) internal view returns(State) { _checkSchedule(_beneficiary, _templateName); - uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; + uint256 index = userToTemplateIndex[_beneficiary][_templateName]; Schedule memory schedule = schedules[_beneficiary][index]; if (now < schedule.startTime) { return State.CREATED; @@ -402,14 +430,14 @@ contract VestingEscrowWallet is IWallet { } function _getAvailableTokens(address _beneficiary, uint256 _index) internal view returns(uint256) { - Schedule storage schedule = schedules[_beneficiary][_index]; + Schedule memory schedule = schedules[_beneficiary][_index]; uint256 releasedTokens = _getReleasedTokens(_beneficiary, _index); return releasedTokens.sub(schedule.claimedTokens); } function _getReleasedTokens(address _beneficiary, uint256 _index) internal view returns(uint256) { - Schedule storage schedule = schedules[_beneficiary][_index]; - Template storage template = templates[schedule.templateName]; + Schedule memory schedule = schedules[_beneficiary][_index]; + Template memory template = templates[schedule.templateName]; /*solium-disable-next-line security/no-block-members*/ if (now > schedule.startTime) { uint256 periodCount = template.duration.div(template.frequency); @@ -426,11 +454,11 @@ contract VestingEscrowWallet is IWallet { /** * @notice Used to remove beneficiaries without schedules + * TODO: Improve the Trim beneficiary logic -- remain because of size of bytecode hit the limit */ function trimBeneficiaries() external withPerm(ADMIN) { for (uint256 i = 0; i < beneficiaries.length; i++) { if (schedules[beneficiaries[i]].length == 0) { - delete schedules[beneficiaries[i]]; if (i != beneficiaries.length - 1) { beneficiaries[i] = beneficiaries[beneficiaries.length - 1]; } @@ -444,7 +472,6 @@ contract VestingEscrowWallet is IWallet { * @param _beneficiaries array of beneficiary's addresses */ function pushAvailableTokensMulti(address[] _beneficiaries) external withPerm(ADMIN) { - require(_beneficiaries.length > 1, "Array size should be greater than one"); for (uint256 i = 0; i < _beneficiaries.length; i++) { pushAvailableTokens(_beneficiaries[i]); } @@ -532,7 +559,7 @@ contract VestingEscrowWallet is IWallet { function _checkSchedule(address _beneficiary, bytes32 _templateName) internal view { require(_beneficiary != address(0), "Invalid address"); - uint256 index = templateToScheduleIndex[_beneficiary][_templateName]; + uint256 index = userToTemplateIndex[_beneficiary][_templateName]; require( index < schedules[_beneficiary].length && schedules[_beneficiary][index].templateName == _templateName, @@ -544,24 +571,22 @@ contract VestingEscrowWallet is IWallet { return templates[_name].numberOfTokens > 0; } - function _isTemplateUsed(bytes32 _name) internal view returns(bool) { - return templateToUsers[_name].length > 0; - } - - function _validateTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) internal pure { + function _validateTemplate(uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) internal view { require(_numberOfTokens > 0, "Zero amount"); - require(_duration % _frequency == 0, "Duration and frequency mismatch"); + require(_duration % _frequency == 0, "Invalid frequency"); uint256 periodCount = _duration.div(_frequency); - require(_numberOfTokens % periodCount == 0, "Tokens and periods mismatch"); + require(_numberOfTokens % periodCount == 0); + uint256 amountPerPeriod = _numberOfTokens.div(periodCount); + require(amountPerPeriod % ISecurityToken(securityToken).granularity() == 0, "Invalid granularity"); } function _sendTokens(address _beneficiary) internal { for (uint256 i = 0; i < schedules[_beneficiary].length; i++) { - _sendTokens(_beneficiary, i); + _sendTokensPerSchedule(_beneficiary, i); } } - function _sendTokens(address _beneficiary, uint256 _index) internal { + function _sendTokensPerSchedule(address _beneficiary, uint256 _index) internal { uint256 amount = _getAvailableTokens(_beneficiary, _index); if (amount > 0) { schedules[_beneficiary][_index].claimedTokens = schedules[_beneficiary][_index].claimedTokens.add(amount); From 6d12750340ccdd17dbf5af47af573d7025c3a820 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Fri, 30 Nov 2018 14:58:32 +0200 Subject: [PATCH 72/93] test fixes - data structure refactoring (not finished) --- .../modules/Wallet/VestingEscrowWallet.sol | 1 + test/z_vesting_escrow_wallet.js | 264 +++++++++--------- 2 files changed, 126 insertions(+), 139 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index f5049019a..c8a05defe 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -271,6 +271,7 @@ contract VestingEscrowWallet is IWallet { require(_isTemplateExists(_templateName)); uint256 index = userToTemplateIndex[_beneficiary][_templateName]; require( + schedules[_beneficiary].length == 0 || schedules[_beneficiary][index].templateName != _templateName, "Already added" ); diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 8c5d3fba5..bad3e9e8e 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -71,7 +71,7 @@ contract('VestingEscrowWallet', accounts => { // Accounts setup account_polymath = accounts[0]; token_owner = accounts[1]; - wallet_admin = token_owner; + wallet_admin = accounts[2]; account_beneficiary1 = accounts[6]; account_beneficiary2 = accounts[7]; @@ -173,8 +173,13 @@ contract('VestingEscrowWallet', accounts => { }); it("Should successfully attach the VestingEscrowWallet with the security token", async () => { + let bytesData = encodeModuleCall( + ["address"], + [token_owner] + ); + await I_SecurityToken.changeGranularity(1, {from: token_owner}); - const tx = await I_SecurityToken.addModule(I_VestingEscrowWalletFactory.address, "", 0, 0, { from: token_owner }); + const tx = await I_SecurityToken.addModule(I_VestingEscrowWalletFactory.address, bytesData, 0, 0, { from: token_owner }); assert.equal(tx.logs[2].args._types[0].toNumber(), 6, "VestingEscrowWallet doesn't get deployed"); assert.equal( @@ -317,6 +322,7 @@ contract('VestingEscrowWallet', accounts => { }); it("Should not be able to push available tokens -- fail because of permissions check", async () => { + let templateName = "template-01"; let numberOfTokens = 75000; let duration = durationUtil.seconds(30); let frequency = durationUtil.seconds(10); @@ -324,7 +330,7 @@ contract('VestingEscrowWallet', accounts => { let startTime = latestTime() + timeShift; await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); - await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + await I_VestingEscrowWallet.addSchedule(account_beneficiary3, templateName, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency); await catchRevert( @@ -345,20 +351,19 @@ contract('VestingEscrowWallet', accounts => { }); it("Should fail to modify vesting schedule -- fail because schedule already started", async () => { - let numberOfTokens = 75000; - let duration = durationUtil.seconds(30); - let frequency = durationUtil.seconds(10); - let timeShift = durationUtil.seconds(100); + let templateName = "template-01"; let startTime = latestTime() + timeShift; await catchRevert( - I_VestingEscrowWallet.modifySchedule(account_beneficiary3, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) + I_VestingEscrowWallet.modifySchedule(account_beneficiary3, templateName, startTime, {from: wallet_admin}) ); await I_VestingEscrowWallet.revokeAllSchedules(account_beneficiary3, {from: wallet_admin}); + await I_VestingEscrowWallet.removeTemplate(templateName, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); it("Should withdraw available tokens to the beneficiary address", async () => { + let templateName = "template-02"; let numberOfTokens = 33000; let duration = durationUtil.seconds(30); let frequency = durationUtil.seconds(10); @@ -366,7 +371,7 @@ contract('VestingEscrowWallet', accounts => { let startTime = latestTime() + timeShift; await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); - await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + await I_VestingEscrowWallet.addSchedule(account_beneficiary3, templateName, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency * 3); const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); @@ -376,27 +381,31 @@ contract('VestingEscrowWallet', accounts => { let balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); assert.equal(balance.toNumber(), numberOfTokens); - let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary3, 0); + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary3, templateName); checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, COMPLETED); await I_SecurityToken.transfer(token_owner, balance, {from: account_beneficiary3}); await I_VestingEscrowWallet.revokeAllSchedules(account_beneficiary3, {from: wallet_admin}); + await I_VestingEscrowWallet.removeTemplate(templateName, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); it("Should withdraw available tokens 2 times by 3 schedules to the beneficiary address", async () => { let schedules = [ { + templateName: "template-1-01", numberOfTokens: 100000, duration: durationUtil.minutes(4), frequency: durationUtil.minutes(1) }, { + templateName: "template-1-02", numberOfTokens: 30000, duration: durationUtil.minutes(6), frequency: durationUtil.minutes(1) }, { + templateName: "template-1-03", numberOfTokens: 2000, duration: durationUtil.minutes(10), frequency: durationUtil.minutes(1) @@ -407,11 +416,12 @@ contract('VestingEscrowWallet', accounts => { await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); for (let i = 0; i < schedules.length; i++) { + let templateName = schedules[i].templateName; let numberOfTokens = schedules[i].numberOfTokens; let duration = schedules[i].duration; let frequency = schedules[i].frequency; let startTime = latestTime() + durationUtil.seconds(100); - await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + await I_VestingEscrowWallet.addSchedule(account_beneficiary3, templateName, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); } let stepCount = 6; await increaseTime(durationUtil.minutes(stepCount) + durationUtil.seconds(100)); @@ -441,6 +451,9 @@ contract('VestingEscrowWallet', accounts => { await I_SecurityToken.transfer(token_owner, balance, {from: account_beneficiary3}); await I_VestingEscrowWallet.revokeAllSchedules(account_beneficiary3, {from: wallet_admin}); + for (let i = 0; i < schedules.length; i++) { + await I_VestingEscrowWallet.removeTemplate(schedules[i].templateName, {from: wallet_admin}); + } await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); @@ -450,18 +463,21 @@ contract('VestingEscrowWallet', accounts => { let schedules = [ { + templateName: "template-2-01", numberOfTokens: 100000, duration: durationUtil.years(4), frequency: durationUtil.years(1), startTime: latestTime() + durationUtil.days(1) }, { + templateName: "template-2-02", numberOfTokens: 30000, duration: durationUtil.weeks(6), frequency: durationUtil.weeks(1), startTime: latestTime() + durationUtil.days(2) }, { + templateName: "template-2-03", numberOfTokens: 2000, duration: durationUtil.days(10), frequency: durationUtil.days(2), @@ -471,43 +487,43 @@ contract('VestingEscrowWallet', accounts => { it("Should fail to add vesting schedule to the beneficiary address -- fail because address in invalid", async () => { await catchRevert( - I_VestingEscrowWallet.addSchedule(0, 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) + I_VestingEscrowWallet.addSchedule(0, "template-2-01", 100000, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) ); }); it("Should fail to add vesting schedule to the beneficiary address -- fail because start date in the past", async () => { await catchRevert( - I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 1, latestTime() - durationUtil.days(1), {from: wallet_admin}) + I_VestingEscrowWallet.addSchedule(account_beneficiary1, "template-2-01", 100000, 4, 1, latestTime() - durationUtil.days(1), {from: wallet_admin}) ); }); it("Should fail to add vesting schedule to the beneficiary address -- fail because number of tokens is 0", async () => { await catchRevert( - I_VestingEscrowWallet.addSchedule(account_beneficiary1, 0, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) + I_VestingEscrowWallet.addSchedule(account_beneficiary1, "template-2-01", 0, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) ); }); it("Should fail to add vesting schedule to the beneficiary address -- fail because duration can't be divided entirely by frequency", async () => { await catchRevert( - I_VestingEscrowWallet.addSchedule(account_beneficiary1, 100000, 4, 3, latestTime() + durationUtil.days(1), {from: wallet_admin}) + I_VestingEscrowWallet.addSchedule(account_beneficiary1, "template-2-01", 100000, 4, 3, latestTime() + durationUtil.days(1), {from: wallet_admin}) ); }); it("Should fail to add vesting schedule to the beneficiary address -- fail because number of tokens can't be divided entirely by period count", async () => { await catchRevert( - I_VestingEscrowWallet.addSchedule(account_beneficiary1, 5, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) + I_VestingEscrowWallet.addSchedule(account_beneficiary1, "template-2-01", 5, 4, 1, latestTime() + durationUtil.days(1), {from: wallet_admin}) ); }); it("Should fail to get vesting schedule -- fail because address is invalid", async () => { await catchRevert( - I_VestingEscrowWallet.getSchedule(0, 0) + I_VestingEscrowWallet.getSchedule(0, "template-2-01") ); }); it("Should fail to get vesting schedule -- fail because schedule not found", async () => { await catchRevert( - I_VestingEscrowWallet.getSchedule(account_beneficiary1, 0) + I_VestingEscrowWallet.getSchedule(account_beneficiary1, "template-2-01") ); }); @@ -518,6 +534,7 @@ contract('VestingEscrowWallet', accounts => { }); it("Should not be able to add schedule -- fail because of permissions check", async () => { + let templateName = schedules[0].templateName; let numberOfTokens = schedules[0].numberOfTokens; let duration = schedules[0].duration; let frequency = schedules[0].frequency; @@ -525,120 +542,93 @@ contract('VestingEscrowWallet', accounts => { await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); await catchRevert( - I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: account_beneficiary1}) + I_VestingEscrowWallet.addSchedule(account_beneficiary1, templateName, numberOfTokens, duration, frequency, startTime, {from: account_beneficiary1}) ); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); it("Should add vesting schedule to the beneficiary address", async () => { + let templateName = schedules[0].templateName; let numberOfTokens = schedules[0].numberOfTokens; let duration = schedules[0].duration; let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); - const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, templateName, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); - checkScheduleLog(tx.logs[0], account_beneficiary1, numberOfTokens, duration, frequency, startTime); + checkScheduleLog(tx.logs[0], account_beneficiary1, templateName, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); assert.equal(scheduleCount, 1); - let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, templateName); checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); }); it("Should add vesting schedule without depositing to the beneficiary address", async () => { + let templateName = "template-2-01-2"; let numberOfTokens = schedules[0].numberOfTokens; let duration = schedules[0].duration; let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); - const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, templateName, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); assert.equal(tx.logs[0].args._numberOfTokens, numberOfTokens); - checkScheduleLog(tx.logs[1], account_beneficiary1, numberOfTokens, duration, frequency, startTime); + checkScheduleLog(tx.logs[1], account_beneficiary1, templateName, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); assert.equal(scheduleCount, 2); - let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 1); + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, templateName); checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); - await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 1, {from: wallet_admin}); - - - - + await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, templateName, {from: wallet_admin}); + await I_VestingEscrowWallet.removeTemplate(templateName, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); it("Should fail to modify vesting schedule -- fail because schedule not found", async () => { - let numberOfTokens = schedules[0].numberOfTokens; - let duration = schedules[0].duration; - let frequency = schedules[0].frequency; + let templateName = "template-2-03"; let startTime = schedules[0].startTime; await catchRevert( - I_VestingEscrowWallet.modifySchedule(account_beneficiary1, 2, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}) + I_VestingEscrowWallet.modifySchedule(account_beneficiary1, templateName, startTime, {from: wallet_admin}) ); }); it("Should not be able to modify schedule -- fail because of permissions check", async () => { await catchRevert( - I_VestingEscrowWallet.modifySchedule(account_beneficiary1, 0, 10000, 4, 1, latestTime() + 100, {from: account_beneficiary1}) + I_VestingEscrowWallet.modifySchedule(account_beneficiary1, "template-2-01", 10000, 4, 1, latestTime() + 100, {from: account_beneficiary1}) ); }); it("Should modify vesting schedule for the beneficiary's address", async () => { - let numberOfTokens = schedules[1].numberOfTokens; - let duration = schedules[1].duration; - let frequency = schedules[1].frequency; + let numberOfTokens = schedules[0].numberOfTokens; + let duration = schedules[0].duration; + let frequency = schedules[0].frequency; let startTime = schedules[1].startTime; - const tx = await I_VestingEscrowWallet.modifySchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.modifySchedule(account_beneficiary1, "template-2-01", startTime, {from: wallet_admin}); - checkScheduleLog(tx.logs[0], account_beneficiary1, numberOfTokens, duration, frequency, startTime); + checkScheduleLog(tx.logs[0], account_beneficiary1, templateName, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); assert.equal(scheduleCount.toNumber(), 1); - let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, "template-2-01"); checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); - let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); - assert.equal(unassignedTokens.toNumber(), schedules[0].numberOfTokens - schedules[1].numberOfTokens); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); - it("Should modify vesting schedule without depositing for the beneficiary's address", async () => { - let numberOfTokens = schedules[0].numberOfTokens + schedules[1].numberOfTokens; - let duration = schedules[0].duration; - let frequency = schedules[0].frequency; - let startTime = schedules[0].startTime; - await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); - const tx = await I_VestingEscrowWallet.modifySchedule(account_beneficiary1, 0, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); - - assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), schedules[0].numberOfTokens); - checkScheduleLog(tx.logs[1], account_beneficiary1, numberOfTokens, duration, frequency, startTime); - - let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); - assert.equal(scheduleCount, 1); - - let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); - checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); - - let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); - assert.equal(unassignedTokens.toNumber(), 0); - }); - it("Should not be able to revoke schedule -- fail because of permissions check", async () => { await catchRevert( - I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: account_beneficiary1}) + I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, "template-2-01", {from: account_beneficiary1}) ); }); it("Should revoke vesting schedule from the beneficiary address", async () => { - const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, "template-2-01", {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary1); @@ -646,17 +636,19 @@ contract('VestingEscrowWallet', accounts => { let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); assert.equal(scheduleCount, 0); + + await I_VestingEscrowWallet.removeTemplate("template-2-01", {from: account_beneficiary1}) }); it("Should fail to revoke vesting schedule -- fail because address is invalid", async () => { await catchRevert( - I_VestingEscrowWallet.revokeSchedule(0, 0, {from: wallet_admin}) + I_VestingEscrowWallet.revokeSchedule(0, "template-2-01", {from: wallet_admin}) ); }); it("Should fail to revoke vesting schedule -- fail because schedule not found", async () => { await catchRevert( - I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 1, {from: wallet_admin}) + I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, "template-2-02", {from: wallet_admin}) ); }); @@ -671,13 +663,14 @@ contract('VestingEscrowWallet', accounts => { await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); for (let i = 0; i < schedules.length; i++) { + let templateName = schedules[i].templateName; let numberOfTokens = schedules[i].numberOfTokens; let duration = schedules[i].duration; let frequency = schedules[i].frequency; let startTime = schedules[i].startTime; - const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary2, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary2, templateName, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); - checkScheduleLog(tx.logs[0], account_beneficiary2, numberOfTokens, duration, frequency, startTime); + checkScheduleLog(tx.logs[0], account_beneficiary2, templateName, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2); assert.equal(scheduleCount, i + 1); @@ -694,17 +687,15 @@ contract('VestingEscrowWallet', accounts => { }); it("Should revoke vesting schedule from the beneficiary address", async () => { - const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary2, 1, {from: wallet_admin}); + let templateName = schedules[1].templateName; + const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary2, templateName, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); - assert.equal(tx.logs[0].args._index, 1); + assert.equal(tx.logs[0].args._templateName, templateName); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2); assert.equal(scheduleCount, 2); - - let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, 1); - checkSchedule(schedule, schedules[2].numberOfTokens, schedules[2].duration, schedules[2].frequency, schedules[2].startTime, CREATED); }); it("Should revoke 2 vesting schedules from the beneficiary address", async () => { @@ -720,16 +711,19 @@ contract('VestingEscrowWallet', accounts => { it("Should push available tokens during revoking vesting schedule", async () => { let schedules = [ { + templateName: "template-3-01", numberOfTokens: 100000, duration: durationUtil.minutes(4), frequency: durationUtil.minutes(1) }, { + templateName: "template-3-02", numberOfTokens: 30000, duration: durationUtil.minutes(6), frequency: durationUtil.minutes(1) }, { + templateName: "template-3-03", numberOfTokens: 2000, duration: durationUtil.minutes(10), frequency: durationUtil.minutes(1) @@ -740,16 +734,17 @@ contract('VestingEscrowWallet', accounts => { await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); for (let i = 0; i < schedules.length; i++) { + let templateName = schedules[i].templateName; let numberOfTokens = schedules[i].numberOfTokens; let duration = schedules[i].duration; let frequency = schedules[i].frequency; let startTime = latestTime() + durationUtil.seconds(100); - await I_VestingEscrowWallet.addSchedule(account_beneficiary3, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + await I_VestingEscrowWallet.addSchedule(account_beneficiary3, templateName, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); } let stepCount = 3; await increaseTime(durationUtil.minutes(stepCount) + durationUtil.seconds(100)); - const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary3, 0, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary3, "template-3-01", {from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), 100000 / 4 * stepCount); @@ -765,6 +760,10 @@ contract('VestingEscrowWallet', accounts => { assert.equal(tx2.logs[1].args._beneficiary, account_beneficiary3); assert.equal(tx2.logs[1].args._numberOfTokens.toNumber(), 30000); + for (let i = 0; i < schedules.length; i++) { + await I_VestingEscrowWallet.removeTemplate(schedules[i].templateName, {from: wallet_admin}); + } + balance = await I_SecurityToken.balanceOf.call(account_beneficiary3); assert.equal(balance.toNumber(), totalNumberOfTokens - 100000 / 4); @@ -778,18 +777,21 @@ contract('VestingEscrowWallet', accounts => { let schedules = [ { + templateName: "template-4-01", numberOfTokens: 100000, duration: durationUtil.years(4), frequency: durationUtil.years(1), startTime: latestTime() + durationUtil.days(1) }, { + templateName: "template-4-02", numberOfTokens: 30000, duration: durationUtil.weeks(6), frequency: durationUtil.weeks(1), startTime: latestTime() + durationUtil.days(2) }, { + templateName: "template-4-03", numberOfTokens: 2000, duration: durationUtil.days(10), frequency: durationUtil.days(2), @@ -799,17 +801,19 @@ contract('VestingEscrowWallet', accounts => { it("Should not be able to add template -- fail because of permissions check", async () => { await catchRevert( - I_VestingEscrowWallet.addTemplate(25000, 4, 1, {from: account_beneficiary1}) + I_VestingEscrowWallet.addTemplate("template-4-01", 25000, 4, 1, {from: account_beneficiary1}) ); }); it("Should add 3 Templates", async () => { for (let i = 0; i < schedules.length; i++) { + let templateName = schedules[i].templateName; let numberOfTokens = schedules[i].numberOfTokens; let duration = schedules[i].duration; let frequency = schedules[i].frequency; - const tx = await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.addTemplate(templateName, numberOfTokens, duration, frequency, {from: wallet_admin}); + assert.equal(tx.logs[0].args._name, templateName); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); assert.equal(tx.logs[0].args._duration.toNumber(), duration); assert.equal(tx.logs[0].args._frequency.toNumber(), frequency); @@ -818,39 +822,40 @@ contract('VestingEscrowWallet', accounts => { it("Should not be able to remove template -- fail because of permissions check", async () => { await catchRevert( - I_VestingEscrowWallet.removeTemplate(1, {from: account_beneficiary1}) + I_VestingEscrowWallet.removeTemplate("template-4-02", {from: account_beneficiary1}) ); }); it("Should remove template", async () => { - const tx = await I_VestingEscrowWallet.removeTemplate(1, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.removeTemplate("template-4-02", {from: wallet_admin}); - assert.equal(tx.logs[0].args._index, 1); + assert.equal(tx.logs[0].args._name, removeTemplate); }); it("Should fail to add vesting schedule from template -- fail because template not found", async () => { let startTime = schedules[2].startTime; await catchRevert( - I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 1, startTime, {from: wallet_admin}) + I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, "template-4-02", startTime, {from: wallet_admin}) ); }); it("Should not be able to add schedule from template -- fail because of permissions check", async () => { await catchRevert( - I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 0, latestTime(), {from: account_beneficiary1}) + I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, "template-4-01", latestTime(), {from: account_beneficiary1}) ); }); it("Should add vesting schedule from template", async () => { + let templateName = schedules[2].templateName; let numberOfTokens = schedules[2].numberOfTokens; let duration = schedules[2].duration; let frequency = schedules[2].frequency; let startTime = schedules[2].startTime; await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); - const tx = await I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, 1, startTime, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, templateName, startTime, {from: wallet_admin}); - checkScheduleLog(tx.logs[0], account_beneficiary1, numberOfTokens, duration, frequency, startTime); + checkScheduleLog(tx.logs[0], account_beneficiary1, templateName, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); assert.equal(scheduleCount, 1); @@ -858,19 +863,19 @@ contract('VestingEscrowWallet', accounts => { let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); - await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, 0, {from: wallet_admin}); + await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, templateName, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); it("Should fail to remove template", async () => { await catchRevert( - I_VestingEscrowWallet.removeTemplate(2, {from: wallet_admin}) + I_VestingEscrowWallet.removeTemplate("template-4-02", {from: wallet_admin}) ); }); it("Should remove 2 Templates", async () => { - await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_admin}); - await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_admin}); + await I_VestingEscrowWallet.removeTemplate("template-4-01", {from: wallet_admin}); + await I_VestingEscrowWallet.removeTemplate("template-4-03", {from: wallet_admin}); let templateCount = await I_VestingEscrowWallet.getTemplateCount.call({from: wallet_admin}); assert.equal(templateCount, 0); @@ -880,10 +885,12 @@ contract('VestingEscrowWallet', accounts => { describe("Tests for multi operations", async () => { + let templateNames = ["template-5-01", "template-5-02", "template-5-03"]; + it("Should not be able to add schedules to the beneficiaries -- fail because of permissions check", async () => { let startTimes = [latestTime() + 100, latestTime() + 100, latestTime() + 100]; await catchRevert( - I_VestingEscrowWallet.addScheduleMulti(beneficiaries, [10000, 10000, 10000], [4, 4, 4], [1, 1, 1], startTimes, {from: account_beneficiary1}) + I_VestingEscrowWallet.addScheduleMulti(beneficiaries, templateNames, [10000, 10000, 10000], [4, 4, 4], [1, 1, 1], startTimes, {from: account_beneficiary1}) ); }); @@ -893,27 +900,28 @@ contract('VestingEscrowWallet', accounts => { await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); await catchRevert( - I_VestingEscrowWallet.addScheduleMulti(beneficiaries, [20000, 30000, 10000], [4, 4], [1, 1, 1], startTimes, {from: wallet_admin}) + I_VestingEscrowWallet.addScheduleMulti(beneficiaries, templateNames, [20000, 30000, 10000], [4, 4], [1, 1, 1], startTimes, {from: wallet_admin}) ); I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); it("Should add schedules for 3 beneficiaries", async () => { - let numberOfTokens = [20000, 30000, 10000]; - let durations = [durationUtil.weeks(4), durationUtil.weeks(3), durationUtil.weeks(4)]; - let frequencies = [durationUtil.weeks(2), durationUtil.weeks(1), durationUtil.weeks(1)]; - let startTimes = [latestTime() + durationUtil.days(1), latestTime() + durationUtil.days(2), latestTime() + durationUtil.days(3)]; + let numberOfTokens = [15000, 15000, 15000]; + let durations = [durationUtil.seconds(50), durationUtil.seconds(50), durationUtil.seconds(50)]; + let frequencies = [durationUtil.seconds(10), durationUtil.seconds(10), durationUtil.seconds(10)]; + let timeShift = durationUtil.seconds(100); + let startTimes = [latestTime() + timeShift, latestTime() + timeShift, latestTime() + timeShift]; let totalNumberOfTokens = 60000; await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); - let tx = await I_VestingEscrowWallet.addScheduleMulti(beneficiaries, numberOfTokens, durations, frequencies, startTimes, {from: wallet_admin}); + let tx = await I_VestingEscrowWallet.addScheduleMulti(beneficiaries, templateNames, numberOfTokens, durations, frequencies, startTimes, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; let beneficiary = beneficiaries[i]; - checkScheduleLog(log, beneficiary, numberOfTokens[i], durations[i], frequencies[i], startTimes[i]); + checkScheduleLog(log, beneficiary, templateNames[i], startTimes[i]); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(beneficiary); assert.equal(scheduleCount, 1); @@ -924,28 +932,20 @@ contract('VestingEscrowWallet', accounts => { }); it("Should not be able modify vesting schedule for 3 beneficiary's addresses -- fail because of arrays sizes mismatch", async () => { - let numberOfTokens = [25000, 25000, 25000]; - let durations = [durationUtil.seconds(50), durationUtil.seconds(50), durationUtil.seconds(50)]; - let frequencies = [durationUtil.seconds(10), durationUtil.seconds(10), durationUtil.seconds(10)]; let timeShift = durationUtil.seconds(100); let startTimes = [latestTime() + timeShift, latestTime() + timeShift, latestTime() + timeShift]; - let indexes = [0, 0, 0, 0]; await catchRevert( - I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, indexes, numberOfTokens, durations, frequencies, startTimes, {from: wallet_admin}) + I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, ["template-5-01"], startTimes, {from: wallet_admin}) ); }); it("Should not be able to modify schedules for the beneficiaries -- fail because of permissions check", async () => { - let numberOfTokens = [25000, 25000, 25000]; - let durations = [durationUtil.seconds(50), durationUtil.seconds(50), durationUtil.seconds(50)]; - let frequencies = [durationUtil.seconds(10), durationUtil.seconds(10), durationUtil.seconds(10)]; let timeShift = durationUtil.seconds(100); let startTimes = [latestTime() + timeShift, latestTime() + timeShift, latestTime() + timeShift]; - let indexes = [0, 0, 0]; await catchRevert( - I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, indexes, numberOfTokens, durations, frequencies, startTimes, {from: account_beneficiary1}) + I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, templateNames, startTimes, {from: account_beneficiary1}) ); }); @@ -956,24 +956,20 @@ contract('VestingEscrowWallet', accounts => { let timeShift = durationUtil.seconds(100); let startTimes = [latestTime() + timeShift, latestTime() + timeShift, latestTime() + timeShift]; - let indexes = [0, 0, 0]; - const tx = await I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, indexes, numberOfTokens, durations, frequencies, startTimes, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.modifyScheduleMulti(beneficiaries, templateNames, startTimes, {from: wallet_admin}); await increaseTime(timeShift + frequencies[0]); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; let beneficiary = beneficiaries[i]; - checkScheduleLog(log, beneficiary, numberOfTokens[i], durations[i], frequencies[i], startTimes[i]); + checkScheduleLog(log, beneficiary, templateNames[i], startTimes[i]); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(beneficiary); assert.equal(scheduleCount, 1); - let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); + let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, templateNames[i]); checkSchedule(schedule, numberOfTokens[i], durations[i], frequencies[i], startTimes[i], STARTED); } - - let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); - assert.equal(unassignedTokens.toNumber(), 5000 * beneficiaries.length); }); it("Should not be able to send available tokens to the beneficiaries addresses -- fail because of array size", async () => { @@ -1002,11 +998,13 @@ contract('VestingEscrowWallet', accounts => { await I_SecurityToken.transfer(token_owner, balance, {from: beneficiary}); await I_VestingEscrowWallet.revokeAllSchedules(beneficiary, {from: wallet_admin}); + await I_VestingEscrowWallet.removeTemplate(templateNames[i], {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); } }); it("Should not be able to add schedules from template to the beneficiaries -- fail because of permissions check", async () => { + let templateName = "template-5-01"; let numberOfTokens = 18000; let duration = durationUtil.weeks(3); let frequency = durationUtil.weeks(1); @@ -1015,44 +1013,34 @@ contract('VestingEscrowWallet', accounts => { let totalNumberOfTokens = numberOfTokens * 3; await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); - await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_admin}); + await I_VestingEscrowWallet.addTemplate(templateName, numberOfTokens, duration, frequency, {from: wallet_admin}); await catchRevert( - I_VestingEscrowWallet.addScheduleFromTemplateMulti(beneficiaries, 0, startTimes, {from: account_beneficiary1}) + I_VestingEscrowWallet.addScheduleFromTemplateMulti(beneficiaries, templateName, startTimes, {from: account_beneficiary1}) ); }); it("Should add schedules from template for 3 beneficiaries", async () => { - let numberOfTokens = 18000; - let duration = durationUtil.weeks(3); - let frequency = durationUtil.weeks(1); - let startTimes = [latestTime() + durationUtil.seconds(100), latestTime() + durationUtil.seconds(100), latestTime() + durationUtil.seconds(100)]; - - let totalNumberOfTokens = numberOfTokens * 3; - await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); - await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); - await I_VestingEscrowWallet.addTemplate(numberOfTokens, duration, frequency, {from: wallet_admin}); - - let tx = await I_VestingEscrowWallet.addScheduleFromTemplateMulti(beneficiaries, 0, startTimes, {from: wallet_admin}); - await I_VestingEscrowWallet.removeTemplate(0, {from: wallet_admin}); + let templateName = "template-5-01"; + let tx = await I_VestingEscrowWallet.addScheduleFromTemplateMulti(beneficiaries, [templateName, templateName, templateName], startTimes, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; let beneficiary = beneficiaries[i]; - checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTimes[i]); + checkScheduleLog(log, beneficiary, templateName, startTimes[i]); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(beneficiary); assert.equal(scheduleCount.toNumber(), 1); - let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); + let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, templateName); checkSchedule(schedule, numberOfTokens, duration, frequency, startTimes[i], CREATED); } - + await I_VestingEscrowWallet.removeTemplate(templateName, {from: wallet_admin}); }); it("Should not be able to revoke schedules of the beneficiaries -- fail because of permissions check", async () => { await catchRevert( - I_VestingEscrowWallet.revokeSchedulesMulti([account_beneficiary1], {from: account_beneficiary1}) + I_VestingEscrowWallet.revokeSchedulesMulti(beneficiaries, {from: account_beneficiary1}) ); }); @@ -1076,11 +1064,9 @@ contract('VestingEscrowWallet', accounts => { }); -function checkScheduleLog(log, beneficiary, numberOfTokens, duration, frequency, startTime) { +function checkScheduleLog(log, beneficiary, templateName, startTime) { assert.equal(log.args._beneficiary, beneficiary); - assert.equal(log.args._numberOfTokens.toNumber(), numberOfTokens); - assert.equal(log.args._duration.toNumber(), duration); - assert.equal(log.args._frequency.toNumber(), frequency); + assert.equal(log.args._templateName, templateName); assert.equal(log.args._startTime.toNumber(), startTime); } @@ -1089,7 +1075,7 @@ function checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, assert.equal(schedule[1].toNumber(), duration); assert.equal(schedule[2].toNumber(), frequency); assert.equal(schedule[3].toNumber(), startTime); - assert.equal(schedule[4].toNumber(), state); + assert.equal(schedule[5].toNumber(), state); } function getTotalNumberOfTokens(schedules) { From 976e6d6934fbb3240c237fae99ec71f93af2fbf5 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Fri, 30 Nov 2018 16:23:39 +0200 Subject: [PATCH 73/93] removed trim function, changed pushAvailableTokensMulti --- .../modules/Wallet/VestingEscrowWallet.sol | 25 +++++-------------- test/z_vesting_escrow_wallet.js | 7 +++--- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index c8a05defe..09c6151c9 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -453,28 +453,15 @@ contract VestingEscrowWallet is IWallet { } } - /** - * @notice Used to remove beneficiaries without schedules - * TODO: Improve the Trim beneficiary logic -- remain because of size of bytecode hit the limit - */ - function trimBeneficiaries() external withPerm(ADMIN) { - for (uint256 i = 0; i < beneficiaries.length; i++) { - if (schedules[beneficiaries[i]].length == 0) { - if (i != beneficiaries.length - 1) { - beneficiaries[i] = beneficiaries[beneficiaries.length - 1]; - } - beneficiaries.length--; - } - } - } - /** * @notice Used to bulk send available tokens for each of beneficiaries - * @param _beneficiaries array of beneficiary's addresses + * @param _fromIndex start index of array of beneficiary's addresses + * @param _toIndex end index of array of beneficiary's addresses */ - function pushAvailableTokensMulti(address[] _beneficiaries) external withPerm(ADMIN) { - for (uint256 i = 0; i < _beneficiaries.length; i++) { - pushAvailableTokens(_beneficiaries[i]); + function pushAvailableTokensMulti(uint256 _fromIndex, uint256 _toIndex) external withPerm(ADMIN) { + require(_toIndex <= beneficiaries.length - 1, "Array out of bound"); + for (uint256 i = _fromIndex; i <= _toIndex; i++) { + pushAvailableTokens(beneficiaries[i]); } } diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index bad3e9e8e..cc0aed2d3 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -974,18 +974,18 @@ contract('VestingEscrowWallet', accounts => { it("Should not be able to send available tokens to the beneficiaries addresses -- fail because of array size", async () => { await catchRevert( - I_VestingEscrowWallet.pushAvailableTokensMulti([account_beneficiary1], {from: wallet_admin}) + I_VestingEscrowWallet.pushAvailableTokensMulti(0, 2, {from: wallet_admin}) ); }); it("Should not be able to send available tokens to the beneficiaries -- fail because of permissions check", async () => { await catchRevert( - I_VestingEscrowWallet.pushAvailableTokensMulti([account_beneficiary1], {from: account_beneficiary1}) + I_VestingEscrowWallet.pushAvailableTokensMulti(0, 2, {from: account_beneficiary1}) ); }); it("Should send available tokens to the beneficiaries addresses", async () => { - const tx = await I_VestingEscrowWallet.pushAvailableTokensMulti(beneficiaries, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.pushAvailableTokensMulti(0, 2, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; @@ -1056,7 +1056,6 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 0); } - await I_VestingEscrowWallet.trimBeneficiaries({from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); From b9df9cbcab5681d95437aae4b02937c25eb11780 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Fri, 30 Nov 2018 17:35:13 +0200 Subject: [PATCH 74/93] minor fixes with treasury --- contracts/modules/Wallet/VestingEscrowWallet.sol | 2 +- contracts/modules/Wallet/VestingEscrowWalletFactory.sol | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 09c6151c9..361512698 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -131,7 +131,7 @@ contract VestingEscrowWallet is IWallet { function _depositTokens(uint256 _numberOfTokens) internal { require(_numberOfTokens > 0, "Should be > 0"); - ISecurityToken(securityToken).transferFrom(msg.sender, address(this), _numberOfTokens); + ISecurityToken(securityToken).transferFrom(treasuryWallet, address(this), _numberOfTokens); unassignedTokens = unassignedTokens.add(_numberOfTokens); emit DepositTokens(_numberOfTokens, msg.sender); } diff --git a/contracts/modules/Wallet/VestingEscrowWalletFactory.sol b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol index d0035da10..88db1919d 100644 --- a/contracts/modules/Wallet/VestingEscrowWalletFactory.sol +++ b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol @@ -29,11 +29,15 @@ contract VestingEscrowWalletFactory is ModuleFactory { * _data Data used for the intialization of the module factory variables * @return address Contract address of the Module */ - function deploy(bytes /*_data*/) external returns(address) { + function deploy(bytes _data) external returns(address) { if (setupCost > 0) { require(polyToken.transferFrom(msg.sender, owner, setupCost), "Failed transferFrom due to insufficent Allowance provided"); } VestingEscrowWallet vestingEscrowWallet = new VestingEscrowWallet(msg.sender, address(polyToken)); + //Checks that _data is valid (not calling anything it shouldn't) + require(Util.getSig(_data) == vestingEscrowWallet.getInitFunction(), "Invalid data"); + /*solium-disable-next-line security/no-low-level-calls*/ + require(address(vestingEscrowWallet).call(_data), "Unsuccessfull call"); /*solium-disable-next-line security/no-block-members*/ emit GenerateModuleFromFactory(address(vestingEscrowWallet), getName(), address(this), msg.sender, setupCost, now); return address(vestingEscrowWallet); From 861fbea17e2ccdd4cd976c79b9543240990e3ffe Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Fri, 30 Nov 2018 11:03:42 -0500 Subject: [PATCH 75/93] Updates --- .../GeneralTransferManager.sol | 85 +++++++++---------- test/h_general_transfer_manager.js | 6 +- 2 files changed, 41 insertions(+), 50 deletions(-) diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index c43531db7..5412afe94 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -24,7 +24,7 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag // Emit when there is change in the flag variable called signingAddress event ChangeSigningAddress(address _signingAddress); // Emit when investor details get modified related to their whitelisting - event DefaultsModified(uint64 _defaultFromTime, uint64 _defaultToTime); + event ChangeDefaults(uint64 _defaultFromTime, uint64 _defaultToTime); // _fromTime is the time from which the _investor can send tokens // _toTime is the time from which the _investor can receive tokens @@ -52,12 +52,6 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag { } - function modifyDefaults(uint64 _defaultFromTime, uint64 _defaultToTime) public withPerm(FLAGS) { - defaults.fromTime = _defaultFromTime; - defaults.toTime = _defaultToTime; - emit DefaultsModified(_defaultFromTime, _defaultToTime); - } - /** * @notice This function returns the signature of configure function */ @@ -65,6 +59,17 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag return bytes4(0); } + /** + * @notice Used to change the default times used when fromTime / toTime are zero + * @param _defaultFromTime default for zero fromTime + * @param _defaultToTime default for zero toTime + */ + function changeDefaults(uint64 _defaultFromTime, uint64 _defaultToTime) public withPerm(FLAGS) { + defaults.fromTime = _defaultFromTime; + defaults.toTime = _defaultToTime; + emit ChangeDefaults(_defaultFromTime, _defaultToTime); + } + /** * @notice Used to change the Issuance Address * @param _issuanceAddress new address for the issuance @@ -126,7 +131,7 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag allowAllBurnTransfers = _allowAllBurnTransfers; emit AllowAllBurnTransfers(_allowAllBurnTransfers); } - event Times(uint64 _from, uint64 _to); + /** * @notice Default implementation of verifyTransfer used by SecurityToken * If the transfer request comes from the STO, it only checks that the investor is in the whitelist @@ -150,17 +155,21 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag //Anyone on the whitelist can transfer, regardless of time return (_onWhitelist(_to) && _onWhitelist(_from)) ? Result.VALID : Result.NA; } - if (_from == issuanceAddress && (whitelist[_to].canBuyFromSTO == 0) && _isSTOAttached()) { - return Result.NA; - } - if (allowAllWhitelistIssuances && _from == issuanceAddress) { - return _onWhitelist(_to) ? Result.VALID : Result.NA; - } - (uint64 adjustedFromTime, uint64 adjustedToTime) = _adjustTimes(whitelist[_from].fromTime, whitelist[_to].toTime); + (uint64 adjustedFromTime, uint64 adjustedToTime) = _adjustTimes(whitelist[_from].fromTime, whitelist[_to].toTime); if (_from == issuanceAddress) { - return (_onWhitelist(_to) && (adjustedToTime <= uint64(now))) ? Result.VALID : Result.NA; + // Possible STO transaction, but investor not allowed to purchased from STO + if ((whitelist[_to].canBuyFromSTO == 0) && _isSTOAttached()) { + return Result.NA; + } + // if allowAllWhitelistIssuances is true, so time stamp ignored + if (allowAllWhitelistIssuances) { + return _onWhitelist(_to) ? Result.VALID : Result.NA; + } else { + return (_onWhitelist(_to) && (adjustedToTime <= uint64(now))) ? Result.VALID : Result.NA; + } } + //Anyone on the whitelist can transfer provided the blocknumber is large enough /*solium-disable-next-line security/no-block-members*/ return ((_onWhitelist(_from) && (adjustedFromTime <= uint64(now))) && @@ -187,13 +196,7 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag public withPerm(WHITELIST) { - uint8 canBuyFromSTO = 0; - if (_canBuyFromSTO) { - canBuyFromSTO = 1; - } - _modifyWhitelist(_investor, uint64(_fromTime), uint64(_toTime), uint64(_expiryTime), canBuyFromSTO); - /*solium-disable-next-line security/no-block-members*/ - emit ModifyWhitelist(_investor, now, msg.sender, _fromTime, _toTime, _expiryTime, _canBuyFromSTO); + _modifyWhitelist(_investor, _fromTime, _toTime, _expiryTime, _canBuyFromSTO); } /** @@ -206,18 +209,23 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag */ function _modifyWhitelist( address _investor, - uint64 _fromTime, - uint64 _toTime, - uint64 _expiryTime, - uint8 _canBuyFromSTO + uint256 _fromTime, + uint256 _toTime, + uint256 _expiryTime, + bool _canBuyFromSTO ) internal { require(_investor != address(0), "Invalid investor"); + uint8 canBuyFromSTO = 0; + if (_canBuyFromSTO) { + canBuyFromSTO = 1; + } if (whitelist[_investor].added == uint8(0)) { investors.push(_investor); } - whitelist[_investor] = TimeRestriction(_fromTime, _toTime, _expiryTime, _canBuyFromSTO, uint8(1)); + whitelist[_investor] = TimeRestriction(uint64(_fromTime), uint64(_toTime), uint64(_expiryTime), canBuyFromSTO, uint8(1)); + emit ModifyWhitelist(_investor, now, msg.sender, _fromTime, _toTime, _expiryTime, _canBuyFromSTO); } /** @@ -239,16 +247,8 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag require(_fromTimes.length == _toTimes.length, "Mismatched input lengths"); require(_toTimes.length == _expiryTimes.length, "Mismatched input lengths"); require(_canBuyFromSTO.length == _toTimes.length, "Mismatched input length"); - uint8 canBuyFromSTO; for (uint256 i = 0; i < _investors.length; i++) { - if (_canBuyFromSTO[i]) { - canBuyFromSTO = 1; - } else { - canBuyFromSTO = 0; - } - _modifyWhitelist(_investors[i], uint64(_fromTimes[i]), uint64(_toTimes[i]), uint64(_expiryTimes[i]), canBuyFromSTO); - /*solium-disable-next-line security/no-block-members*/ - emit ModifyWhitelist(_investors[i], now, msg.sender, _fromTimes[i], _toTimes[i], _expiryTimes[i], _canBuyFromSTO[i]); + _modifyWhitelist(_investors[i], _fromTimes[i], _toTimes[i], _expiryTimes[i], _canBuyFromSTO[i]); } } @@ -289,16 +289,7 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag abi.encodePacked(this, _investor, _fromTime, _toTime, _expiryTime, _canBuyFromSTO, _validFrom, _validTo, _nonce) ); _checkSig(hash, _v, _r, _s); - if (whitelist[_investor].added == uint8(0)) { - investors.push(_investor); - } - uint8 canBuyFromSTO = 0; - if (_canBuyFromSTO) { - canBuyFromSTO = 1; - } - whitelist[_investor] = TimeRestriction(uint64(_fromTime), uint64(_toTime), uint64(_expiryTime), canBuyFromSTO, uint8(1)); - /*solium-disable-next-line security/no-block-members*/ - emit ModifyWhitelist(_investor, now, msg.sender, _fromTime, _toTime, _expiryTime, _canBuyFromSTO); + _modifyWhitelist(_investor, _fromTime, _toTime, _expiryTime, _canBuyFromSTO); } /** diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 5d019f521..d00108376 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -421,7 +421,7 @@ contract("GeneralTransferManager", accounts => { }); it("Add a from default and check transfers are disabled then enabled in the future", async () => { - let tx = await I_GeneralTransferManager.modifyDefaults(latestTime() + duration.days(5), 0, {from: token_owner}); + let tx = await I_GeneralTransferManager.changeDefaults(latestTime() + duration.days(5), 0, {from: token_owner}); await I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor2}); await catchRevert(I_SecurityToken.transfer(account_investor2, web3.utils.toWei("1", "ether"), {from: account_investor1})); await increaseTime(duration.days(5)); @@ -429,7 +429,7 @@ contract("GeneralTransferManager", accounts => { }); it("Add a to default and check transfers are disabled then enabled in the future", async () => { - let tx = await I_GeneralTransferManager.modifyDefaults(0, latestTime() + duration.days(5), {from: token_owner}); + let tx = await I_GeneralTransferManager.changeDefaults(0, latestTime() + duration.days(5), {from: token_owner}); await catchRevert(I_SecurityToken.transfer(account_investor1, web3.utils.toWei("1", "ether"), {from: account_investor2})); await I_SecurityToken.transfer(account_investor2, web3.utils.toWei("1", "ether"), {from: account_investor1}); await increaseTime(duration.days(5)); @@ -446,7 +446,7 @@ contract("GeneralTransferManager", accounts => { gas: 6000000 } ); - await I_GeneralTransferManager.modifyDefaults(0, 0, {from: token_owner}); + await I_GeneralTransferManager.changeDefaults(0, 0, {from: token_owner}); }); From 11702df8b86daa83033a735ecd1bf9447e06ff53 Mon Sep 17 00:00:00 2001 From: satyam Date: Mon, 3 Dec 2018 14:04:57 +0530 Subject: [PATCH 76/93] adopting the optimisation deployment of factory --- .../modules/Wallet/VestingEscrowWallet.sol | 45 +---------------- .../Wallet/VestingEscrowWalletFactory.sol | 15 +++--- .../Wallet/VestingEscrowWalletStorage.sol | 50 +++++++++++++++++++ contracts/proxy/VestingEscrowWalletProxy.sol | 27 ++++++++++ 4 files changed, 88 insertions(+), 49 deletions(-) create mode 100644 contracts/modules/Wallet/VestingEscrowWalletStorage.sol create mode 100644 contracts/proxy/VestingEscrowWalletProxy.sol diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 361512698..2ec52c0e4 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -1,6 +1,7 @@ pragma solidity ^0.4.24; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; +import "./VestingEscrowWalletStorage.sol"; import "./IWallet.sol"; /** @@ -11,51 +12,9 @@ contract VestingEscrowWallet is IWallet { bytes32 public constant ADMIN = "ADMIN"; - struct Schedule { - // Name of the template - bytes32 templateName; - // Tokens that were already claimed - uint256 claimedTokens; - // Start time of the schedule - uint256 startTime; - } - - struct Template { - // Total amount of tokens - uint256 numberOfTokens; - // Schedule duration (How long the schedule will last) - uint256 duration; - // Schedule frequency (It is a cliff time period) - uint256 frequency; - } - // States used to represent the status of the schedule enum State {CREATED, STARTED, COMPLETED} - // Number of tokens that are hold by the `this` contract but are unassigned to any schedule - uint256 public unassignedTokens; - // Address of the Treasury wallet. All of the unassigned token will transfer to that address. - address public treasuryWallet; - // List of all beneficiaries who have the schedules running/completed/created - address[] public beneficiaries; - - // Holds schedules array corresponds to the affiliate/employee address - mapping(address => Schedule[]) public schedules; - // Holds template names array corresponds to the affiliate/employee address - mapping(address => bytes32[]) internal userToTemplates; - // Mapping use to store the indexes for different template names for a user. - // affiliate/employee address => template name => index - mapping(address => mapping(bytes32 => uint256)) internal userToTemplateIndex; - // Holds affiliate/employee addresses coressponds to the template name - mapping(bytes32 => address[]) internal templateToUsers; - // Mapping use to store the indexes for different users for a template. - // template name => affiliate/employee address => index - mapping(bytes32 => mapping(address => uint256)) internal templateToUserIndex; - // Store the template details corresponds to the template name - mapping(bytes32 => Template) templates; - - // List of all template names - bytes32[] public templateNames; - + // Emit when new schedule is added event AddSchedule( address indexed _beneficiary, diff --git a/contracts/modules/Wallet/VestingEscrowWalletFactory.sol b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol index 88db1919d..62de4c1c6 100644 --- a/contracts/modules/Wallet/VestingEscrowWalletFactory.sol +++ b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "./VestingEscrowWallet.sol"; +import "../../proxy/VestingEscrowWalletProxy.sol"; import "../ModuleFactory.sol"; import "../../libraries/Util.sol"; @@ -8,20 +8,23 @@ import "../../libraries/Util.sol"; * @title Factory for deploying VestingEscrowWallet module */ contract VestingEscrowWalletFactory is ModuleFactory { - + + address public logicContract; /** * @notice Constructor * @param _polyAddress Address of the polytoken */ - constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public + constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost, address _logicContract) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { + require(_logicContract != address(0), "Invalid address"); version = "1.0.0"; name = "VestingEscrowWallet"; title = "Vesting Escrow Wallet"; description = "Manage vesting schedules to employees / affiliates"; compatibleSTVersionRange["lowerBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); compatibleSTVersionRange["upperBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); + logicContract = _logicContract; } /** @@ -33,7 +36,7 @@ contract VestingEscrowWalletFactory is ModuleFactory { if (setupCost > 0) { require(polyToken.transferFrom(msg.sender, owner, setupCost), "Failed transferFrom due to insufficent Allowance provided"); } - VestingEscrowWallet vestingEscrowWallet = new VestingEscrowWallet(msg.sender, address(polyToken)); + VestingEscrowWalletProxy vestingEscrowWallet = new VestingEscrowWalletProxy(msg.sender, address(polyToken), logicContract); //Checks that _data is valid (not calling anything it shouldn't) require(Util.getSig(_data) == vestingEscrowWallet.getInitFunction(), "Invalid data"); /*solium-disable-next-line security/no-low-level-calls*/ @@ -65,8 +68,8 @@ contract VestingEscrowWalletFactory is ModuleFactory { */ function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](2); - availableTags[0] = "Vested Wallet"; - availableTags[1] = "Escrow"; + availableTags[0] = "Vested"; + availableTags[1] = "Escrow Wallet"; return availableTags; } } diff --git a/contracts/modules/Wallet/VestingEscrowWalletStorage.sol b/contracts/modules/Wallet/VestingEscrowWalletStorage.sol new file mode 100644 index 000000000..f51b7e8a1 --- /dev/null +++ b/contracts/modules/Wallet/VestingEscrowWalletStorage.sol @@ -0,0 +1,50 @@ +pragma solidity ^0.4.24; + +/** + * @title Wallet for core vesting escrow functionality + */ +contract VestingEscrowWalletStorage { + + struct Schedule { + // Name of the template + bytes32 templateName; + // Tokens that were already claimed + uint256 claimedTokens; + // Start time of the schedule + uint256 startTime; + } + + struct Template { + // Total amount of tokens + uint256 numberOfTokens; + // Schedule duration (How long the schedule will last) + uint256 duration; + // Schedule frequency (It is a cliff time period) + uint256 frequency; + } + + // Number of tokens that are hold by the `this` contract but are unassigned to any schedule + uint256 public unassignedTokens; + // Address of the Treasury wallet. All of the unassigned token will transfer to that address. + address public treasuryWallet; + // List of all beneficiaries who have the schedules running/completed/created + address[] public beneficiaries; + + // Holds schedules array corresponds to the affiliate/employee address + mapping(address => Schedule[]) public schedules; + // Holds template names array corresponds to the affiliate/employee address + mapping(address => bytes32[]) internal userToTemplates; + // Mapping use to store the indexes for different template names for a user. + // affiliate/employee address => template name => index + mapping(address => mapping(bytes32 => uint256)) internal userToTemplateIndex; + // Holds affiliate/employee addresses coressponds to the template name + mapping(bytes32 => address[]) internal templateToUsers; + // Mapping use to store the indexes for different users for a template. + // template name => affiliate/employee address => index + mapping(bytes32 => mapping(address => uint256)) internal templateToUserIndex; + // Store the template details corresponds to the template name + mapping(bytes32 => Template) templates; + + // List of all template names + bytes32[] public templateNames; +} \ No newline at end of file diff --git a/contracts/proxy/VestingEscrowWalletProxy.sol b/contracts/proxy/VestingEscrowWalletProxy.sol new file mode 100644 index 000000000..7f73203eb --- /dev/null +++ b/contracts/proxy/VestingEscrowWalletProxy.sol @@ -0,0 +1,27 @@ +pragma solidity ^0.4.24; + +import "../modules/wallet/VestingEscrowWalletStorage.sol"; +import "./OwnedProxy.sol"; +import "../Pausable.sol"; +import "../modules/ModuleStorage.sol"; + /** + * @title Escrow wallet module for vesting functionality + */ +contract VestingEscrowWalletProxy is VestingEscrowWalletStorage, ModuleStorage, Pausable, OwnedProxy { + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + * @param _implementation representing the address of the new implementation to be set + */ + constructor (address _securityToken, address _polyAddress, address _implementation) + public + ModuleStorage(_securityToken, _polyAddress) + { + require( + _implementation != address(0), + "Implementation address should not be 0x" + ); + __implementation = _implementation; + } + } \ No newline at end of file From 2026bcaea0661b57d9228b49b7bc5b1b8372e5ae Mon Sep 17 00:00:00 2001 From: satyam Date: Mon, 3 Dec 2018 14:11:19 +0530 Subject: [PATCH 77/93] add require statement in factory constructors --- .../modules/Checkpoint/ERC20DividendCheckpointFactory.sol | 2 ++ .../modules/Checkpoint/EtherDividendCheckpointFactory.sol | 2 ++ .../modules/TransferManager/GeneralTransferManagerFactory.sol | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol b/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol index a684e553b..b7e668111 100644 --- a/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol +++ b/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol @@ -16,10 +16,12 @@ contract ERC20DividendCheckpointFactory is ModuleFactory { * @param _setupCost Setup cost of the module * @param _usageCost Usage cost of the module * @param _subscriptionCost Subscription cost of the module + * @param _logicContract Contract address that contains the logic related to `description` */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost, address _logicContract) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { + require(_logicContract != address(0), "Invalid logic contract"); version = "1.0.0"; name = "ERC20DividendCheckpoint"; title = "ERC20 Dividend Checkpoint"; diff --git a/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol b/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol index 3129fba42..2d8d8f529 100644 --- a/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol +++ b/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol @@ -16,10 +16,12 @@ contract EtherDividendCheckpointFactory is ModuleFactory { * @param _setupCost Setup cost of the module * @param _usageCost Usage cost of the module * @param _subscriptionCost Subscription cost of the module + * @param _logicContract Contract address that contains the logic related to `description` */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost, address _logicContract) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { + require(_logicContract != address(0), "Invalid logic contract"); version = "1.0.0"; name = "EtherDividendCheckpoint"; title = "Ether Dividend Checkpoint"; diff --git a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol index 27c894fb2..4259e8b9f 100644 --- a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol @@ -13,6 +13,10 @@ contract GeneralTransferManagerFactory is ModuleFactory { /** * @notice Constructor * @param _polyAddress Address of the polytoken + * @param _setupCost Setup cost of the module + * @param _usageCost Usage cost of the module + * @param _subscriptionCost Subscription cost of the module + * @param _logicContract Contract address that contains the logic related to `description` */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost, address _logicContract) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) From df121ea290c8603cf21d734aefeaedef38a738f5 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Mon, 3 Dec 2018 14:48:24 +0200 Subject: [PATCH 78/93] test fixes - data structure refactoring --- .../modules/Wallet/VestingEscrowWallet.sol | 16 +- docs/permissions_list.md | 9 +- test/z_vesting_escrow_wallet.js | 183 +++++++++++++----- 3 files changed, 148 insertions(+), 60 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 361512698..6e2fe717e 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -37,6 +37,8 @@ contract VestingEscrowWallet is IWallet { address public treasuryWallet; // List of all beneficiaries who have the schedules running/completed/created address[] public beneficiaries; + // Flag whether beneficiary has been already added or not + mapping(address => bool) internal beneficiaryAdded; // Holds schedules array corresponds to the affiliate/employee address mapping(address => Schedule[]) public schedules; @@ -131,7 +133,7 @@ contract VestingEscrowWallet is IWallet { function _depositTokens(uint256 _numberOfTokens) internal { require(_numberOfTokens > 0, "Should be > 0"); - ISecurityToken(securityToken).transferFrom(treasuryWallet, address(this), _numberOfTokens); + ISecurityToken(securityToken).transferFrom(msg.sender, address(this), _numberOfTokens); unassignedTokens = unassignedTokens.add(_numberOfTokens); emit DepositTokens(_numberOfTokens, msg.sender); } @@ -186,8 +188,8 @@ contract VestingEscrowWallet is IWallet { * @param _name name of template */ function removeTemplate(bytes32 _name) external withPerm(ADMIN) { - require(_isTemplateExists(_name), "Already exists"); - require(templateToUsers[_name].length == 0); + require(_isTemplateExists(_name), "Template not found"); + require(templateToUsers[_name].length == 0, "Template is used"); // delete template data delete templates[_name]; uint256 i; @@ -215,7 +217,7 @@ contract VestingEscrowWallet is IWallet { * @notice get the list of template names * @return bytes32 Array of template names */ - function getTemplateNames() external view returns(bytes32[]) { + function getAllTemplateNames() external view returns(bytes32[]) { return templateNames; } @@ -268,7 +270,7 @@ contract VestingEscrowWallet is IWallet { function _addScheduleFromTemplate(address _beneficiary, bytes32 _templateName, uint256 _startTime) internal { require(_beneficiary != address(0), "Invalid address"); - require(_isTemplateExists(_templateName)); + require(_isTemplateExists(_templateName), "Template not found"); uint256 index = userToTemplateIndex[_beneficiary][_templateName]; require( schedules[_beneficiary].length == 0 || @@ -281,9 +283,9 @@ contract VestingEscrowWallet is IWallet { _depositTokens(numberOfTokens.sub(unassignedTokens)); } unassignedTokens = unassignedTokens.sub(numberOfTokens); - //add beneficiary to the schedule list only if adding first schedule - if (schedules[_beneficiary].length == 0) { + if (!beneficiaryAdded[_beneficiary]) { beneficiaries.push(_beneficiary); + beneficiaryAdded[_beneficiary] = true; } schedules[_beneficiary].push(Schedule(_templateName, 0, _startTime)); userToTemplates[_beneficiary].push(_templateName); diff --git a/docs/permissions_list.md b/docs/permissions_list.md index 009781c05..61de6d2d7 100644 --- a/docs/permissions_list.md +++ b/docs/permissions_list.md @@ -275,8 +275,12 @@ Wallet VestingEscrowWallet + changeTreasuryWallet() + onlyOwner + + depositTokens() - withPerm(ADMIN) + withPerm(ADMIN) sendToTreasury() @@ -305,9 +309,6 @@ revokeAllSchedules() - - trimBeneficiaries() - pushAvailableTokensMulti() diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index cc0aed2d3..5bc1f335b 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -274,9 +274,32 @@ contract('VestingEscrowWallet', accounts => { describe("Depositing and withdrawing tokens", async () => { + it("Should not be able to change treasury wallet -- fail because address is invalid", async () => { + await catchRevert( + I_VestingEscrowWallet.changeTreasuryWallet(0, {from: token_owner}) + ); + }); + + it("Should not be able to deposit -- fail because of permissions check", async () => { + await catchRevert( + I_VestingEscrowWallet.changeTreasuryWallet(account_beneficiary1, {from: account_beneficiary1}) + ); + }); + + it("Should change treasury wallet", async () => { + const tx = await I_VestingEscrowWallet.changeTreasuryWallet(account_beneficiary1, {from: token_owner}); + + assert.equal(tx.logs[0].args._newWallet, account_beneficiary1); + assert.equal(tx.logs[0].args._oldWallet, token_owner); + let treasuryWallet = await I_VestingEscrowWallet.treasuryWallet.call(); + assert.equal(treasuryWallet, account_beneficiary1); + + await I_VestingEscrowWallet.changeTreasuryWallet(token_owner, {from: token_owner}); + }); + it("Should fail to deposit zero amount of tokens", async () => { await catchRevert( - I_VestingEscrowWallet.depositTokens(0, {from: wallet_admin}) + I_VestingEscrowWallet.depositTokens(0, {from: token_owner}) ); }); @@ -291,7 +314,7 @@ contract('VestingEscrowWallet', accounts => { it("Should deposit tokens for new vesting schedules", async () => { let numberOfTokens = 25000; await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); - const tx = await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: token_owner}); assert.equal(tx.logs[0].args._numberOfTokens, numberOfTokens); @@ -329,7 +352,7 @@ contract('VestingEscrowWallet', accounts => { let timeShift = durationUtil.seconds(100); let startTime = latestTime() + timeShift; await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); - await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.addSchedule(account_beneficiary3, templateName, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency); @@ -338,6 +361,12 @@ contract('VestingEscrowWallet', accounts => { ); }); + it("Should not be able to remove template -- fail because template is used", async () => { + await catchRevert( + I_VestingEscrowWallet.removeTemplate("template-01", {from: wallet_admin}) + ); + }); + it("Should push available tokens to the beneficiary address", async () => { let numberOfTokens = 75000; const tx = await I_VestingEscrowWallet.pushAvailableTokens(account_beneficiary3, {from: wallet_admin}); @@ -352,7 +381,7 @@ contract('VestingEscrowWallet', accounts => { it("Should fail to modify vesting schedule -- fail because schedule already started", async () => { let templateName = "template-01"; - let startTime = latestTime() + timeShift; + let startTime = latestTime() + 100; await catchRevert( I_VestingEscrowWallet.modifySchedule(account_beneficiary3, templateName, startTime, {from: wallet_admin}) ); @@ -362,6 +391,12 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); + it("Should fail to modify vesting schedule -- fail because date in the past", async () => { + await catchRevert( + I_VestingEscrowWallet.modifySchedule(account_beneficiary3, "template-01", latestTime() - 1000, {from: wallet_admin}) + ); + }); + it("Should withdraw available tokens to the beneficiary address", async () => { let templateName = "template-02"; let numberOfTokens = 33000; @@ -370,11 +405,11 @@ contract('VestingEscrowWallet', accounts => { let timeShift = durationUtil.seconds(100); let startTime = latestTime() + timeShift; await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); - await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.addSchedule(account_beneficiary3, templateName, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); await increaseTime(timeShift + frequency * 3); - const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); + const tx = await I_VestingEscrowWallet.pullAvailableTokens({from: account_beneficiary3}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); @@ -414,7 +449,7 @@ contract('VestingEscrowWallet', accounts => { let totalNumberOfTokens = getTotalNumberOfTokens(schedules); await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); - await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: token_owner}); for (let i = 0; i < schedules.length; i++) { let templateName = schedules[i].templateName; let numberOfTokens = schedules[i].numberOfTokens; @@ -427,7 +462,7 @@ contract('VestingEscrowWallet', accounts => { await increaseTime(durationUtil.minutes(stepCount) + durationUtil.seconds(100)); let numberOfTokens = 100000 + (30000 / 6 * stepCount) + (2000 / 10 * stepCount); - const tx = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); + const tx = await I_VestingEscrowWallet.pullAvailableTokens({from: account_beneficiary3}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), 100000); @@ -442,7 +477,7 @@ contract('VestingEscrowWallet', accounts => { stepCount = 4; await increaseTime(durationUtil.minutes(stepCount) + durationUtil.seconds(100)); - const tx2 = await I_VestingEscrowWallet.withdrawAvailableTokens({from: account_beneficiary3}); + const tx2 = await I_VestingEscrowWallet.pullAvailableTokens({from: account_beneficiary3}); assert.equal(tx2.logs[0].args._beneficiary, account_beneficiary3); assert.equal(tx2.logs[0].args._numberOfTokens.toNumber(), 2000 / 10 * stepCount); @@ -540,7 +575,7 @@ contract('VestingEscrowWallet', accounts => { let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); - await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: token_owner}); await catchRevert( I_VestingEscrowWallet.addSchedule(account_beneficiary1, templateName, numberOfTokens, duration, frequency, startTime, {from: account_beneficiary1}) ); @@ -554,16 +589,20 @@ contract('VestingEscrowWallet', accounts => { let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); - await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: token_owner}); const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, templateName, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); - checkScheduleLog(tx.logs[0], account_beneficiary1, templateName, startTime); + checkTemplateLog(tx.logs[0], templateName, numberOfTokens, duration, frequency); + checkScheduleLog(tx.logs[1], account_beneficiary1, templateName, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); assert.equal(scheduleCount, 1); let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, templateName); checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); + + let templates = await I_VestingEscrowWallet.getTemplateNames.call(account_beneficiary1); + assert.equal(web3.utils.hexToUtf8(templates[0]), templateName); }); it("Should add vesting schedule without depositing to the beneficiary address", async () => { @@ -573,10 +612,11 @@ contract('VestingEscrowWallet', accounts => { let frequency = schedules[0].frequency; let startTime = schedules[0].startTime; await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, {from: token_owner}); - const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, templateName, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary1, templateName, numberOfTokens, duration, frequency, startTime, {from: token_owner}); - assert.equal(tx.logs[0].args._numberOfTokens, numberOfTokens); - checkScheduleLog(tx.logs[1], account_beneficiary1, templateName, startTime); + checkTemplateLog(tx.logs[0], templateName, numberOfTokens, duration, frequency); + assert.equal(tx.logs[1].args._numberOfTokens, numberOfTokens); + checkScheduleLog(tx.logs[2], account_beneficiary1, templateName, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); assert.equal(scheduleCount, 2); @@ -599,16 +639,17 @@ contract('VestingEscrowWallet', accounts => { it("Should not be able to modify schedule -- fail because of permissions check", async () => { await catchRevert( - I_VestingEscrowWallet.modifySchedule(account_beneficiary1, "template-2-01", 10000, 4, 1, latestTime() + 100, {from: account_beneficiary1}) + I_VestingEscrowWallet.modifySchedule(account_beneficiary1, "template-2-01", latestTime() + 100, {from: account_beneficiary1}) ); }); it("Should modify vesting schedule for the beneficiary's address", async () => { + let templateName = "template-2-01"; let numberOfTokens = schedules[0].numberOfTokens; let duration = schedules[0].duration; let frequency = schedules[0].frequency; let startTime = schedules[1].startTime; - const tx = await I_VestingEscrowWallet.modifySchedule(account_beneficiary1, "template-2-01", startTime, {from: wallet_admin}); + const tx = await I_VestingEscrowWallet.modifySchedule(account_beneficiary1, templateName, startTime, {from: wallet_admin}); checkScheduleLog(tx.logs[0], account_beneficiary1, templateName, startTime); @@ -628,16 +669,17 @@ contract('VestingEscrowWallet', accounts => { }); it("Should revoke vesting schedule from the beneficiary address", async () => { - const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, "template-2-01", {from: wallet_admin}); + let templateName = "template-2-01"; + const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, templateName, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary1); - assert.equal(tx.logs[0].args._index, 0); + assert.equal(web3.utils.hexToUtf8(tx.logs[0].args._templateName), templateName); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); assert.equal(scheduleCount, 0); - await I_VestingEscrowWallet.removeTemplate("template-2-01", {from: account_beneficiary1}) + await I_VestingEscrowWallet.removeTemplate(templateName, {from: wallet_admin}) }); it("Should fail to revoke vesting schedule -- fail because address is invalid", async () => { @@ -661,7 +703,7 @@ contract('VestingEscrowWallet', accounts => { it("Should add 3 vesting schedules to the beneficiary address", async () => { let totalNumberOfTokens = getTotalNumberOfTokens(schedules); await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); - await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: token_owner}); for (let i = 0; i < schedules.length; i++) { let templateName = schedules[i].templateName; let numberOfTokens = schedules[i].numberOfTokens; @@ -670,12 +712,13 @@ contract('VestingEscrowWallet', accounts => { let startTime = schedules[i].startTime; const tx = await I_VestingEscrowWallet.addSchedule(account_beneficiary2, templateName, numberOfTokens, duration, frequency, startTime, {from: wallet_admin}); - checkScheduleLog(tx.logs[0], account_beneficiary2, templateName, startTime); + checkTemplateLog(tx.logs[0], templateName, numberOfTokens, duration, frequency); + checkScheduleLog(tx.logs[1], account_beneficiary2, templateName, startTime); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2); assert.equal(scheduleCount, i + 1); - let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, i); + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary2, templateName); checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); } }); @@ -686,13 +729,13 @@ contract('VestingEscrowWallet', accounts => { ); }); - it("Should revoke vesting schedule from the beneficiary address", async () => { + it("Should revoke 1 of 3 vesting schedule from the beneficiary address", async () => { let templateName = schedules[1].templateName; const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary2, templateName, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); - assert.equal(tx.logs[0].args._templateName, templateName); + assert.equal(web3.utils.hexToUtf8(tx.logs[0].args._templateName), templateName); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary2); assert.equal(scheduleCount, 2); @@ -732,7 +775,7 @@ contract('VestingEscrowWallet', accounts => { let totalNumberOfTokens = getTotalNumberOfTokens(schedules); await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); - await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: token_owner}); for (let i = 0; i < schedules.length; i++) { let templateName = schedules[i].templateName; let numberOfTokens = schedules[i].numberOfTokens; @@ -805,6 +848,12 @@ contract('VestingEscrowWallet', accounts => { ); }); + it("Should not be able to add template -- fail because of invalid name", async () => { + await catchRevert( + I_VestingEscrowWallet.addTemplate("", 25000, 4, 1, {from: wallet_admin}) + ); + }); + it("Should add 3 Templates", async () => { for (let i = 0; i < schedules.length; i++) { let templateName = schedules[i].templateName; @@ -813,23 +862,35 @@ contract('VestingEscrowWallet', accounts => { let frequency = schedules[i].frequency; const tx = await I_VestingEscrowWallet.addTemplate(templateName, numberOfTokens, duration, frequency, {from: wallet_admin}); - assert.equal(tx.logs[0].args._name, templateName); + assert.equal(web3.utils.hexToUtf8(tx.logs[0].args._name), templateName); assert.equal(tx.logs[0].args._numberOfTokens.toNumber(), numberOfTokens); assert.equal(tx.logs[0].args._duration.toNumber(), duration); assert.equal(tx.logs[0].args._frequency.toNumber(), frequency); } }); + it("Should not be able to add template -- fail because template already exists", async () => { + await catchRevert( + I_VestingEscrowWallet.addTemplate("template-4-01", 25000, 4, 1, {from: wallet_admin}) + ); + }); + it("Should not be able to remove template -- fail because of permissions check", async () => { await catchRevert( I_VestingEscrowWallet.removeTemplate("template-4-02", {from: account_beneficiary1}) ); }); + it("Should not be able to remove template -- fail because template not found", async () => { + await catchRevert( + I_VestingEscrowWallet.removeTemplate("template-444-02", {from: wallet_admin}) + ); + }); + it("Should remove template", async () => { const tx = await I_VestingEscrowWallet.removeTemplate("template-4-02", {from: wallet_admin}); - assert.equal(tx.logs[0].args._name, removeTemplate); + assert.equal(web3.utils.hexToUtf8(tx.logs[0].args._name), "template-4-02"); }); it("Should fail to add vesting schedule from template -- fail because template not found", async () => { @@ -845,6 +906,12 @@ contract('VestingEscrowWallet', accounts => { ); }); + it("Should not be able to add vesting schedule from template -- fail because template not found", async () => { + await catchRevert( + I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, "template-777", latestTime() + 100, {from: wallet_admin}) + ); + }); + it("Should add vesting schedule from template", async () => { let templateName = schedules[2].templateName; let numberOfTokens = schedules[2].numberOfTokens; @@ -852,7 +919,7 @@ contract('VestingEscrowWallet', accounts => { let frequency = schedules[2].frequency; let startTime = schedules[2].startTime; await I_SecurityToken.approve(I_VestingEscrowWallet.address, numberOfTokens, { from: token_owner }); - await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.depositTokens(numberOfTokens, {from: token_owner}); const tx = await I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, templateName, startTime, {from: wallet_admin}); checkScheduleLog(tx.logs[0], account_beneficiary1, templateName, startTime); @@ -860,13 +927,20 @@ contract('VestingEscrowWallet', accounts => { let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(account_beneficiary1); assert.equal(scheduleCount, 1); - let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, 0); + let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, templateName); checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, templateName, {from: wallet_admin}); await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); + it("Should not be able to add vesting schedule from template -- fail because template already added", async () => { + let templateName = schedules[2].templateName; + await catchRevert( + I_VestingEscrowWallet.addScheduleFromTemplate(account_beneficiary1, templateName, latestTime() + 100, {from: wallet_admin}) + ); + }); + it("Should fail to remove template", async () => { await catchRevert( I_VestingEscrowWallet.removeTemplate("template-4-02", {from: wallet_admin}) @@ -874,11 +948,13 @@ contract('VestingEscrowWallet', accounts => { }); it("Should remove 2 Templates", async () => { + let templateCount = await I_VestingEscrowWallet.getTemplateCount.call({from: wallet_admin}); + await I_VestingEscrowWallet.removeTemplate("template-4-01", {from: wallet_admin}); await I_VestingEscrowWallet.removeTemplate("template-4-03", {from: wallet_admin}); - let templateCount = await I_VestingEscrowWallet.getTemplateCount.call({from: wallet_admin}); - assert.equal(templateCount, 0); + let templateCountAfterRemoving = await I_VestingEscrowWallet.getTemplateCount.call({from: wallet_admin}); + assert.equal(templateCount - templateCountAfterRemoving, 2); }); }); @@ -898,7 +974,7 @@ contract('VestingEscrowWallet', accounts => { let startTimes = [latestTime() + 100, latestTime() + 100, latestTime() + 100]; let totalNumberOfTokens = 60000; await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); - await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: token_owner}); await catchRevert( I_VestingEscrowWallet.addScheduleMulti(beneficiaries, templateNames, [20000, 30000, 10000], [4, 4], [1, 1, 1], startTimes, {from: wallet_admin}) ); @@ -914,19 +990,20 @@ contract('VestingEscrowWallet', accounts => { let totalNumberOfTokens = 60000; await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); - await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: token_owner}); let tx = await I_VestingEscrowWallet.addScheduleMulti(beneficiaries, templateNames, numberOfTokens, durations, frequencies, startTimes, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { - let log = tx.logs[i]; + let templateName = templateNames[i]; let beneficiary = beneficiaries[i]; - checkScheduleLog(log, beneficiary, templateNames[i], startTimes[i]); + checkTemplateLog(tx.logs[i* 2], templateName, numberOfTokens[i], durations[i], frequencies[i]); + checkScheduleLog(tx.logs[i * 2 + 1], beneficiary, templateName, startTimes[i]); let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(beneficiary); assert.equal(scheduleCount, 1); - let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, 0); + let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, templateName); checkSchedule(schedule, numberOfTokens[i], durations[i], frequencies[i], startTimes[i], CREATED); } }); @@ -974,7 +1051,7 @@ contract('VestingEscrowWallet', accounts => { it("Should not be able to send available tokens to the beneficiaries addresses -- fail because of array size", async () => { await catchRevert( - I_VestingEscrowWallet.pushAvailableTokensMulti(0, 2, {from: wallet_admin}) + I_VestingEscrowWallet.pushAvailableTokensMulti(0, 3, {from: wallet_admin}) ); }); @@ -990,7 +1067,6 @@ contract('VestingEscrowWallet', accounts => { for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; let beneficiary = beneficiaries[i]; - assert.equal(log.args._beneficiary, beneficiary); assert.equal(log.args._numberOfTokens.toNumber(), 3000); let balance = await I_SecurityToken.balanceOf.call(beneficiary); @@ -1004,38 +1080,40 @@ contract('VestingEscrowWallet', accounts => { }); it("Should not be able to add schedules from template to the beneficiaries -- fail because of permissions check", async () => { - let templateName = "template-5-01"; + let templateName = "template-6-01"; let numberOfTokens = 18000; let duration = durationUtil.weeks(3); let frequency = durationUtil.weeks(1); + let templateNames = [templateName, templateName, templateName]; let startTimes = [latestTime() + durationUtil.seconds(100), latestTime() + durationUtil.seconds(100), latestTime() + durationUtil.seconds(100)]; let totalNumberOfTokens = numberOfTokens * 3; await I_SecurityToken.approve(I_VestingEscrowWallet.address, totalNumberOfTokens, {from: token_owner}); - await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: wallet_admin}); + await I_VestingEscrowWallet.depositTokens(totalNumberOfTokens, {from: token_owner}); await I_VestingEscrowWallet.addTemplate(templateName, numberOfTokens, duration, frequency, {from: wallet_admin}); await catchRevert( - I_VestingEscrowWallet.addScheduleFromTemplateMulti(beneficiaries, templateName, startTimes, {from: account_beneficiary1}) + I_VestingEscrowWallet.addScheduleFromTemplateMulti(beneficiaries, templateNames, startTimes, {from: account_beneficiary1}) ); }); it("Should add schedules from template for 3 beneficiaries", async () => { - let templateName = "template-5-01"; + let templateName = "template-6-01"; + let numberOfTokens = 18000; + let duration = durationUtil.weeks(3); + let frequency = durationUtil.weeks(1); + let templateNames = [templateName, templateName, templateName]; + let startTimes = [latestTime() + 100, latestTime() + 100, latestTime() + 100]; - let tx = await I_VestingEscrowWallet.addScheduleFromTemplateMulti(beneficiaries, [templateName, templateName, templateName], startTimes, {from: wallet_admin}); + let tx = await I_VestingEscrowWallet.addScheduleFromTemplateMulti(beneficiaries, templateNames, startTimes, {from: wallet_admin}); for (let i = 0; i < beneficiaries.length; i++) { let log = tx.logs[i]; let beneficiary = beneficiaries[i]; checkScheduleLog(log, beneficiary, templateName, startTimes[i]); - let scheduleCount = await I_VestingEscrowWallet.getScheduleCount.call(beneficiary); - assert.equal(scheduleCount.toNumber(), 1); - let schedule = await I_VestingEscrowWallet.getSchedule.call(beneficiary, templateName); checkSchedule(schedule, numberOfTokens, duration, frequency, startTimes[i], CREATED); } - await I_VestingEscrowWallet.removeTemplate(templateName, {from: wallet_admin}); }); it("Should not be able to revoke schedules of the beneficiaries -- fail because of permissions check", async () => { @@ -1063,9 +1141,16 @@ contract('VestingEscrowWallet', accounts => { }); +function checkTemplateLog(log, templateName, numberOfTokens, duration, frequency) { + assert.equal(web3.utils.hexToUtf8(log.args._name), templateName); + assert.equal(log.args._numberOfTokens.toNumber(), numberOfTokens); + assert.equal(log.args._duration.toNumber(), duration); + assert.equal(log.args._frequency.toNumber(), frequency); +} + function checkScheduleLog(log, beneficiary, templateName, startTime) { assert.equal(log.args._beneficiary, beneficiary); - assert.equal(log.args._templateName, templateName); + assert.equal(web3.utils.hexToUtf8(log.args._templateName), templateName); assert.equal(log.args._startTime.toNumber(), startTime); } From c3a64aca3fd75d7863c8a9959df47e3c34db37b2 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Mon, 3 Dec 2018 15:56:21 +0200 Subject: [PATCH 79/93] minor fix in tests --- test/z_vesting_escrow_wallet.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 5bc1f335b..a9328074a 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -855,6 +855,7 @@ contract('VestingEscrowWallet', accounts => { }); it("Should add 3 Templates", async () => { + let oldTemplateCount = await I_VestingEscrowWallet.getTemplateCount.call(); for (let i = 0; i < schedules.length; i++) { let templateName = schedules[i].templateName; let numberOfTokens = schedules[i].numberOfTokens; @@ -867,6 +868,11 @@ contract('VestingEscrowWallet', accounts => { assert.equal(tx.logs[0].args._duration.toNumber(), duration); assert.equal(tx.logs[0].args._frequency.toNumber(), frequency); } + let templateNames = await I_VestingEscrowWallet.getAllTemplateNames.call(); + + for (let i = 0, j = oldTemplateCount; i < schedules.length; i++, j++) { + assert.equal(web3.utils.hexToUtf8(templateNames[j]), schedules[i].templateName); + } }); it("Should not be able to add template -- fail because template already exists", async () => { From ff45016459f42bb12157fcf3d4c5e429ca6e406a Mon Sep 17 00:00:00 2001 From: satyam Date: Mon, 3 Dec 2018 19:53:39 +0530 Subject: [PATCH 80/93] remove the test cases for the STVRTM --- test/x_single_trade_volume_restriction.js | 726 ---------------------- 1 file changed, 726 deletions(-) delete mode 100644 test/x_single_trade_volume_restriction.js diff --git a/test/x_single_trade_volume_restriction.js b/test/x_single_trade_volume_restriction.js deleted file mode 100644 index 99fe5cb9e..000000000 --- a/test/x_single_trade_volume_restriction.js +++ /dev/null @@ -1,726 +0,0 @@ -import latestTime from './helpers/latestTime'; -import { duration, promisifyLogWatch, latestBlock } from './helpers/utils'; -import { takeSnapshot, increaseTime, revertToSnapshot } from './helpers/time'; -import { encodeModuleCall } from './helpers/encodeCall'; -import {deploySingleTradeVolumeRMAndVerified, setUpPolymathNetwork } from "./helpers/createInstances"; -import { catchRevert } from "./helpers/exceptions"; - -const SecurityToken = artifacts.require('./SecurityToken.sol'); -const GeneralPermissionManagerFactory = artifacts.require('./GeneralPermissionManagerFactory.sol'); -const GeneralTransferManager = artifacts.require('./GeneralTransferManager'); -const SingleTradeVolumeRestrictionManager = artifacts.require('./SingleTradeVolumeRestrictionTM'); -const CountTransferManagerFactory = artifacts.require('./CountTransferManagerFactory.sol'); -const GeneralPermissionManager = artifacts.require('./GeneralPermissionManager'); - -const Web3 = require('web3'); -const BigNumber = require('bignumber.js'); -const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")) // Hardcoded development port - -contract('SingleTradeVolumeRestrictionManager', accounts => { - - - - // Accounts Variable declaration - let account_polymath; - let account_issuer; - let token_owner; - let account_investor1; - let account_investor2; - let account_investor3; - let account_investor4; - let account_investor5; - let zero_address = '0x0000000000000000000000000000000000000000'; - - // investor Details - let fromTime = latestTime(); - let toTime = latestTime(); - let expiryTime = toTime + duration.days(15); - - let message = "Transaction Should Fail!"; - - // Contract Instance Declaration - let I_SecurityTokenRegistryProxy - let I_GeneralTransferManagerFactory; - let I_GeneralPermissionManager; - let I_GeneralTransferManager; - let I_SingleTradeVolumeRestrictionManagerFactory; - let I_SingleTradeVolumeRestrictionManager; - let P_SingleTradeVolumeRestrictionManagerFactory; - let P_SingleTradeVolumeRestrictionManager; - let I_SingleTradeVolumeRestrictionPercentageManager; - let I_ModuleRegistry; - let I_MRProxied; - let I_ModuleRegistryProxy; - let I_FeatureRegistry; - let I_SecurityTokenRegistry; - let I_STRProxied; - let I_STFactory; - let I_SecurityToken; - let I_PolyToken; - let I_PolymathRegistry; - - // SecurityToken Details - const name = "Team"; - const symbol = "sap"; - const tokenDetails = "This is equity type of issuance"; - const decimals = 18; - const contact = "team@polymath.network"; - const STVRParameters = ["bool", "uint256", "bool"]; - - // Module key - const delegateManagerKey = 1; - const transferManagerKey = 2; - const stoKey = 3; - - // Initial fee for ticker registry and security token registry - const initRegFee = web3.utils.toWei("250"); - - before(async () => { - // Accounts setup - account_polymath = accounts[0]; - account_issuer = accounts[1]; - - token_owner = account_issuer; - - account_investor1 = accounts[6]; - account_investor2 = accounts[7]; - account_investor3 = accounts[8]; - account_investor4 = accounts[9]; - account_investor5 = accounts[5]; - - let instances = await setUpPolymathNetwork(account_polymath, token_owner); - - [ - I_PolymathRegistry, - I_PolyToken, - I_FeatureRegistry, - I_ModuleRegistry, - I_ModuleRegistryProxy, - I_MRProxied, - I_GeneralTransferManagerFactory, - I_STFactory, - I_SecurityTokenRegistry, - I_SecurityTokenRegistryProxy, - I_STRProxied - ] = instances; - - // STEP 4: Deploy the SingleTradeVolumeRestrictionManagerFactory - [I_SingleTradeVolumeRestrictionManagerFactory] = await deploySingleTradeVolumeRMAndVerified(account_polymath, I_MRProxied, I_PolyToken.address, 0); - [P_SingleTradeVolumeRestrictionManagerFactory] = await deploySingleTradeVolumeRMAndVerified(account_polymath, I_MRProxied, I_PolyToken.address, web3.utils.toWei("500")); - - }); - - describe("Generate the SecurityToken", async () => { - it("Should register the ticker before the generation of the security token", async () => { - await I_PolyToken.approve(I_STRProxied.address, initRegFee, { - from: token_owner - }); - let tx = await I_STRProxied.registerTicker(token_owner, symbol, contact, { - from: token_owner - }); - assert.equal(tx.logs[0].args._owner, token_owner); - assert.equal(tx.logs[0].args._ticker, symbol.toUpperCase()); - }); - - it("Should generate the new security token with the same symbol as registered above", async () => { - await I_PolyToken.approve(I_STRProxied.address, initRegFee, { - from: token_owner - }); - let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { - from: token_owner - }); - - // Verify the successful generation of the security token - assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); - - I_SecurityToken = SecurityToken.at(tx.logs[1].args._securityTokenAddress); - - const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({ - from: _blockNo - }), 1); - - // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._types[0].toNumber(), 2); - assert.equal( - web3.utils.toAscii(log.args._name) - .replace(/\u0000/g, ''), - "GeneralTransferManager" - ); - }); - - it("Should intialize the auto attached modules", async () => { - let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; - I_GeneralTransferManager = GeneralTransferManager.at(moduleData); - }); - }); - // - describe("Buy tokens using whitelist & manual approvals", async () => { - - it("Should Buy the tokens", async () => { - // Add the Investor in to the whitelist - - let tx = await I_GeneralTransferManager.modifyWhitelist( - account_investor1, - latestTime(), - latestTime(), - latestTime() + duration.days(10), - true, { - from: account_issuer - }); - - assert.equal(tx.logs[0].args._investor.toLowerCase(), account_investor1.toLowerCase(), "Failed in adding the investor in whitelist"); - - // Jump time - await increaseTime(5000); - - // Mint some tokens - await I_SecurityToken.mint(account_investor1, web3.utils.toWei('100', 'ether'), { - from: token_owner - }); - - assert.equal( - (await I_SecurityToken.balanceOf(account_investor1)).toNumber(), - web3.utils.toWei('100', 'ether') - ); - }); - - it("Should Buy some more tokens", async () => { - // Add the Investor in to the whitelist - - let tx = await I_GeneralTransferManager.modifyWhitelist( - account_investor2, - latestTime(), - latestTime(), - latestTime() + duration.days(10), - true, { - from: account_issuer - }); - - assert.equal(tx.logs[0].args._investor.toLowerCase(), account_investor2.toLowerCase(), "Failed in adding the investor in whitelist"); - - // Mint some tokens - await I_SecurityToken.mint(account_investor2, web3.utils.toWei('1', 'ether'), { - from: token_owner - }); - - assert.equal( - (await I_SecurityToken.balanceOf(account_investor2)).toNumber(), - web3.utils.toWei('1', 'ether') - ); - }); - // - it("Fails to attach the SingleTradeVolumeRestrictionManager with the security token due to fees not paid", async () => { - let managerArgs = encodeModuleCall(STVRParameters, [true, 90, false]); - - await I_PolyToken.getTokens(web3.utils.toWei("500", "ether"), token_owner); - await catchRevert( - I_SecurityToken.addModule(P_SingleTradeVolumeRestrictionManagerFactory.address, managerArgs, web3.utils.toWei("500", "ether"), 0, { from: token_owner}) - ); - }); - - it("Should successfully attach the Paid SingleTradeVolumeRestrictionManager with the security token", async () => { - let managerArgs = encodeModuleCall(STVRParameters, [false, 90, false]); - await I_PolyToken.transfer(I_SecurityToken.address, web3.utils.toWei("500", "ether"), { from: token_owner }); - - let tx = await I_SecurityToken.addModule(P_SingleTradeVolumeRestrictionManagerFactory.address, managerArgs, web3.utils.toWei("500", "ether"), 0, { - from: token_owner - }); - - assert.equal(tx.logs[3].args._types[0].toNumber(), transferManagerKey, "SingleTradeVolumeRestrictionManager did not get deployed"); - assert.equal( - web3.utils.toAscii(tx.logs[3].args._name) - .replace(/\u0000/g, ''), - "SingleTradeVolumeRestrictionTM", - "SingleTradeVolumeRestrictionManagerFactory module was not added" - ); - P_SingleTradeVolumeRestrictionManager = SingleTradeVolumeRestrictionManager.at(tx.logs[3].args._module); - }); - - it("Should successfully attach the SingleTradeVolumeRestrictionManager with the security token", async () => { - let managerArgs = encodeModuleCall(STVRParameters, [false, (7 * Math.pow(10, 16)).toString(), false]) - const tx = await I_SecurityToken.addModule(I_SingleTradeVolumeRestrictionManagerFactory.address, managerArgs, 0, 0, { - from: token_owner - }); - assert.equal(tx.logs[2].args._types[0].toNumber(), transferManagerKey, "TransferManager doesn't get deployed"); - assert.equal( - web3.utils.toAscii(tx.logs[2].args._name) - .replace(/\u0000/g, ''), - "SingleTradeVolumeRestrictionTM", - "SingleTradeVolumeRestriction module was not added" - ); - I_SingleTradeVolumeRestrictionManager = SingleTradeVolumeRestrictionManager.at(tx.logs[2].args._module); - }); - - it("Should successfully attach the SingleTradeVolumeRestrictionManager (Percentage) with the security token", async () => { - let managerArgs = encodeModuleCall(STVRParameters, [true, 90, false]); - const tx = await I_SecurityToken.addModule(I_SingleTradeVolumeRestrictionManagerFactory.address, managerArgs, 0, 0, { - from: token_owner - }); - assert.equal(tx.logs[2].args._types[0].toNumber(), transferManagerKey, "PercentageTransferManager doesn't get deployed"); - assert.equal( - web3.utils.toAscii(tx.logs[2].args._name) - .replace(/\u0000/g, ''), - "SingleTradeVolumeRestrictionTM", - "SingleTradeVolumeRestriction module was not added" - ); - I_SingleTradeVolumeRestrictionPercentageManager = SingleTradeVolumeRestrictionManager.at(tx.logs[2].args._module); - }); - - it('should return get permissions', async () => { - let permissions = await I_SingleTradeVolumeRestrictionPercentageManager.getPermissions(); - assert.equal(permissions.length, 1, "Invalid Permissions"); - assert.equal( - web3.utils.toAscii(permissions[0]).replace(/\u0000/g, ''), - "ADMIN", - 'Wrong permissions' - ); - }); - - it("Should allow the primary issuance", async() => { - let snapId = await takeSnapshot(); - await I_SingleTradeVolumeRestrictionManager.setAllowPrimaryIssuance(true, {from: token_owner}); - await catchRevert( - I_SingleTradeVolumeRestrictionManager.setAllowPrimaryIssuance(true, {from: token_owner}) - ) - await revertToSnapshot(snapId); - }) - - it("add exempt wallet -- Not authorised ", async () => { - await catchRevert ( - I_SingleTradeVolumeRestrictionManager.addExemptWallet(accounts[5]) - ); - - await catchRevert( - I_SingleTradeVolumeRestrictionManager.addExemptWallet(zero_address, { from: token_owner }) - ); - - let tx = await I_SingleTradeVolumeRestrictionManager.addExemptWallet(accounts[5], { - from: token_owner - }); - assert.equal(tx.logs[0].args._wallet, accounts[5], "Wrong wallet added as exempt"); - }); - - it("Should remove an exempt wallet", async () => { - await catchRevert ( - I_SingleTradeVolumeRestrictionManager.removeExemptWallet(accounts[5]) - ); - // 0 address are not allowed to add - await catchRevert ( - I_SingleTradeVolumeRestrictionManager.removeExemptWallet(zero_address, { from: token_owner }) - ); - - let tx = await I_SingleTradeVolumeRestrictionManager.removeExemptWallet(accounts[5], { from: token_owner }); - assert.equal(tx.logs[0].args._wallet, accounts[5], "Wrong wallet removed from exempt"); - }); - - it('should set transfer limit for a wallet', async () => { - await catchRevert ( - I_SingleTradeVolumeRestrictionManager.setTransferLimitInTokens(accounts[4], 100) - ); - - // Transfer limits can't be set to 0 - await catchRevert ( - I_SingleTradeVolumeRestrictionManager.setTransferLimitInTokens(accounts[4], 0, { from: token_owner }) - ); - - // Transfer limit cannot be set in percentage - await catchRevert( - I_SingleTradeVolumeRestrictionManager.setTransferLimitInPercentage(accounts[4], 10, { from: token_owner }) - ); - - let tx = await I_SingleTradeVolumeRestrictionManager.setTransferLimitInTokens(accounts[4], 100, { - from: token_owner - }); - assert.equal(tx.logs[0].args._wallet, accounts[4]); - assert.equal(tx.logs[0].args._amount, 100); - - await catchRevert( - I_SingleTradeVolumeRestrictionPercentageManager.setTransferLimitInPercentage(accounts[4], 0, { from: token_owner }) - ); - // Transfer limit can not be set to more 0 - await catchRevert ( - I_SingleTradeVolumeRestrictionPercentageManager.setTransferLimitInPercentage(accounts[4], 101 * 10 ** 16, { from: token_owner }) - ); - // Transfer limit in tokens can not be set for a manager that has transfer limit set as percentage - await catchRevert ( - I_SingleTradeVolumeRestrictionPercentageManager.setTransferLimitInTokens(accounts[4], 1, { from: token_owner }) - ); - - tx = await I_SingleTradeVolumeRestrictionPercentageManager.setTransferLimitInPercentage(accounts[4], 50, { from: token_owner }); - assert.equal(tx.logs[0].args._wallet, accounts[4], "Wrong wallet added to transfer limits"); - assert.equal(tx.logs[0].args._percentage, 50, "Wrong percentage set"); - }); - - it('should remove transfer limit for wallet', async () => { - // Non Admins cannot set/remove transfer limits - await catchRevert ( - I_SingleTradeVolumeRestrictionManager.removeTransferLimitInTokens(accounts[4]) - ); - - // Non Admins cannot set/remove transfer limits - await catchRevert ( - I_SingleTradeVolumeRestrictionManager.removeTransferLimitInTokens(accounts[0], { from: token_owner }) - ); - - let tx = await I_SingleTradeVolumeRestrictionManager.removeTransferLimitInTokens(accounts[4], { - from: token_owner - }); - assert.equal(tx.logs[0].args._wallet, accounts[4], "Wrong wallet removed"); - }); - - it("Should pause the tranfers at Manager level", async () => { - let tx = await I_SingleTradeVolumeRestrictionManager.pause({ - from: token_owner - }); - }); - - it('Should be able to set a global transfer limit', async () => { - // only owner is allowed - await catchRevert( - I_SingleTradeVolumeRestrictionManager.changeGlobalLimitInTokens(100 * 10 ** 18) - ); - //Cannot change global limit in percentage when set to tokens - await catchRevert( - I_SingleTradeVolumeRestrictionManager.changeGlobalLimitInPercentage(100 * 10 ** 18, { from: token_owner }) - ); - // Global limit cannot be set to 0 - await catchRevert( - I_SingleTradeVolumeRestrictionManager.changeGlobalLimitInTokens(0, { from: token_owner }) - ); - - let tx = await I_SingleTradeVolumeRestrictionManager.changeGlobalLimitInTokens(10, { - from: token_owner - }); - assert.equal(tx.logs[0].args._amount, 10, "Global Limit not set"); - - //Global limit can be set by non-admins - await catchRevert( - I_SingleTradeVolumeRestrictionPercentageManager.changeGlobalLimitInTokens(89) - ); - // cannot change global limit in tokens if transfer limit is set to percentage - await catchRevert( - I_SingleTradeVolumeRestrictionPercentageManager.changeGlobalLimitInTokens(89, { from: token_owner }) - ); - // Cannot set global limit in tokens to 0 - await catchRevert( - I_SingleTradeVolumeRestrictionPercentageManager.changeGlobalLimitInTokens(0, { from: token_owner }) - ); - - tx = await I_SingleTradeVolumeRestrictionPercentageManager.changeGlobalLimitInPercentage(40, { from: token_owner }); - assert.equal(tx.logs[0].args._percentage, 40, "Global Limit not set"); - // Global limit cannot be set to more than 100 - await catchRevert( - I_SingleTradeVolumeRestrictionPercentageManager.changeGlobalLimitInPercentage(101 * 10 ** 16, { from: token_owner }) - ); - // Global limit in percentage cannot be set when limit is in tokens - await catchRevert( - I_SingleTradeVolumeRestrictionManager.changeGlobalLimitInPercentage(10, { from: token_owner }) - ); - // Global limit in tokens cannot be set when limit is in percentage - await catchRevert( - I_SingleTradeVolumeRestrictionPercentageManager.changeGlobalLimitInTokens(10, { from: token_owner }) - ); - }); - - it("Should perform batch updates", async () => { - let wallets = [accounts[0], accounts[1], accounts[2]]; - let tokenLimits = [1, 2, 3]; - let percentageLimits = [5, 6, 7]; - - // Exempt wallet multi cannot be empty wallet - await catchRevert( - P_SingleTradeVolumeRestrictionManager.addExemptWalletMulti([], { from: token_owner }) - ); - - // add exempt wallet multi - let tx = await P_SingleTradeVolumeRestrictionManager.addExemptWalletMulti(wallets, { - from: token_owner - }); - let logs = tx.logs.filter(log => log.event === 'ExemptWalletAdded'); - assert.equal(logs.length, wallets.length, "Batch Exempt wallets not added"); - for (let i = 0; i < logs.length; i++) { - assert.equal(logs[i].args._wallet, wallets[i], "Wallet not added as exempt wallet"); - } - - // Exempt wallet multi cannot be empty wallet - await catchRevert( - P_SingleTradeVolumeRestrictionManager.removeExemptWalletMulti([], { from: token_owner }) - ); - - // remove exempt wallet multi - tx = await P_SingleTradeVolumeRestrictionManager.removeExemptWalletMulti(wallets, { - from: token_owner - }) - logs = tx.logs.filter(log => log.event === 'ExemptWalletRemoved'); - assert.equal(logs.length, wallets.length, "Batch Exempt wallets not removed"); - - for (let i = 0; i < logs.length; i++) { - assert.equal(logs[i].args._wallet, wallets[i], "Wallet not added as exempt wallet"); - } - // wallets cannot be empty - await catchRevert( - P_SingleTradeVolumeRestrictionManager.setTransferLimitInTokensMulti([], tokenLimits, { from: token_owner }) - ); - // wallet array length dont match - await catchRevert( - P_SingleTradeVolumeRestrictionManager.setTransferLimitInTokensMulti([accounts[0]], tokenLimits, { from: token_owner }) - ); - - tx = await P_SingleTradeVolumeRestrictionManager.setTransferLimitInTokensMulti(wallets, tokenLimits, { - from: token_owner - }); - logs = tx.logs.filter(log => log.event == 'TransferLimitInTokensSet'); - assert.equal(wallets.length, logs.length, "Transfer limit not set"); - for (let i = 0; i < wallets.length; i++) { - assert.equal(logs[i].args._wallet, wallets[i], "transfer limit not set for wallet"); - assert.equal(logs[i].args._amount.toNumber(), tokenLimits[i]); - } - // Wallets cannot be empty - await catchRevert( - P_SingleTradeVolumeRestrictionManager.removeTransferLimitInTokensMulti([], { from: token_owner }) - ); - tx = await P_SingleTradeVolumeRestrictionManager.removeTransferLimitInTokensMulti(wallets, { - from: token_owner - }); - logs = tx.logs.filter(log => log.event === 'TransferLimitInTokensRemoved'); - assert.equal(logs.length, wallets.length, "Transfer limit not removed"); - for (let i = 0; i < wallets.length; i++) { - assert.equal(logs[i].args._wallet, wallets[i], "transfer limit not removed for wallet"); - } - // wallets cannot be empty - await catchRevert( - I_SingleTradeVolumeRestrictionPercentageManager.setTransferLimitInPercentageMulti([], percentageLimits, { from: token_owner }) - ); - // wallets and amounts dont match be empty - await catchRevert( - I_SingleTradeVolumeRestrictionPercentageManager.setTransferLimitInPercentageMulti(wallets, [], { from: token_owner }) - ); - tx = await I_SingleTradeVolumeRestrictionPercentageManager.setTransferLimitInPercentageMulti(wallets, percentageLimits, { - from: token_owner - }); - logs = tx.logs.filter(log => log.event == 'TransferLimitInPercentageSet'); - assert.equal(logs.length, wallets.length, "transfer limits not set for wallets"); - - for (let i = 0; i < wallets.length; i++) { - assert.equal(logs[i].args._wallet, wallets[i], "Transfer limit not set for wallet"); - assert.equal(logs[i].args._percentage.toNumber(), percentageLimits[i]); - } - // Wallets cannot be empty - await catchRevert( - I_SingleTradeVolumeRestrictionPercentageManager.removeTransferLimitInPercentageMulti([], { from: token_owner }) - ); - - tx = await I_SingleTradeVolumeRestrictionPercentageManager.removeTransferLimitInPercentageMulti(wallets, { - from: token_owner - }); - logs = tx.logs.filter(log => log.event == 'TransferLimitInPercentageRemoved'); - assert.equal(logs.length, wallets.length, "transfer limits not set for wallets"); - - for (let i = 0; i < wallets.length; i++) { - assert.equal(logs[i].args._wallet, wallets[i], "Transfer limit not set for wallet"); - } - // Wallet should not be removed - await catchRevert( - I_SingleTradeVolumeRestrictionPercentageManager.removeTransferLimitInPercentage(wallets[0], { from: token_owner }) - ); - }) - - it('should be able to transfer tokens SingleTradeVolumeRestriction', async () => { - await I_SingleTradeVolumeRestrictionManager.unpause({ - from: token_owner - }) - await I_SingleTradeVolumeRestrictionPercentageManager.pause({ - from: token_owner - }) - await P_SingleTradeVolumeRestrictionManager.pause({ - from: token_owner - }); - - await I_GeneralTransferManager.modifyWhitelist( - account_investor3, - latestTime(), - latestTime(), - latestTime() + duration.days(10), - true, { - from: account_issuer - } - ); - - await I_GeneralTransferManager.modifyWhitelist( - account_investor4, - latestTime(), - latestTime(), - latestTime() + duration.days(10), - true, { - from: account_issuer - } - ); - - await I_GeneralTransferManager.modifyWhitelist( - account_investor5, - latestTime(), - latestTime(), - latestTime() + duration.days(10), - true, { - from: account_issuer - } - ); - - - //setting a max of 5 tokens - await I_SingleTradeVolumeRestrictionManager.changeGlobalLimitInTokens(web3.utils.toWei('5', 'ether'), { - from: token_owner - }) - // Transfer should have not happened - await catchRevert( - I_SecurityToken.transfer(account_investor3, web3.utils.toWei('6', 'ether'), { from: account_investor1 }) - ); - - await I_SecurityToken.transfer(account_investor3, web3.utils.toWei('4', 'ether'), { - from: account_investor1 - }); - assert.equal((await I_SecurityToken.balanceOf(account_investor3)).toNumber(), web3.utils.toWei('4', 'ether')); - - // exempt wallet - await I_SingleTradeVolumeRestrictionManager.addExemptWallet(account_investor1, { - from: token_owner - }); - await I_SecurityToken.transfer(account_investor5, web3.utils.toWei('7', 'ether'), { - from: account_investor1 - }); - assert.equal((await I_SecurityToken.balanceOf(account_investor5)).toNumber(), web3.utils.toWei('7', 'ether')); - - //special limits wallet - await I_SingleTradeVolumeRestrictionManager.setTransferLimitInTokens(account_investor5, web3.utils.toWei('5', 'ether'), { - from: token_owner - }); - - // Transfer should have not happened - await catchRevert( - I_SecurityToken.transfer(account_investor4, web3.utils.toWei('7', 'ether'), { from: account_investor5 }) - ); - - await I_SecurityToken.transfer(account_investor4, web3.utils.toWei('4', 'ether'), { - from: account_investor5 - }) - assert.equal((await I_SecurityToken.balanceOf(account_investor4)).toNumber(), web3.utils.toWei('4', 'ether')) - }) - - it('should be able to transfer tokens (percentage transfer limit)', async () => { - await I_SingleTradeVolumeRestrictionManager.pause({ - from: token_owner - }); - let balance = (await I_SecurityToken.balanceOf(account_investor2)).toNumber(); - await I_SecurityToken.transfer(account_investor1, balance, { - from: account_investor2 - }); - - - balance = (await I_SecurityToken.balanceOf(account_investor3)).toNumber(); - - await I_SecurityToken.transfer(account_investor1, balance, { - from: account_investor3 - }); - - - balance = (await I_SecurityToken.balanceOf(account_investor4)).toNumber(); - await I_SecurityToken.transfer(account_investor1, balance, { - from: account_investor4 - }); - - balance = (await I_SecurityToken.balanceOf(account_investor5)).toNumber(); - await I_SecurityToken.transfer(account_investor1, balance, { - from: account_investor5 - }); - - await I_SingleTradeVolumeRestrictionPercentageManager.unpause({ - from: token_owner - }); - // // - await I_SingleTradeVolumeRestrictionPercentageManager.changeGlobalLimitInPercentage(49 * 10 ** 16, { - from: token_owner - }); - - // Transfer above limit happened - await catchRevert( - I_SecurityToken.transfer(account_investor2, web3.utils.toWei('90', 'ether'), { from: account_investor1 }) - ); - - await I_SecurityToken.transfer(account_investor2, web3.utils.toWei('20', 'ether'), { - from: account_investor1 - }); - assert.equal((await I_SecurityToken.balanceOf(account_investor2)).toNumber(), web3.utils.toWei('20', 'ether')) - - await I_SingleTradeVolumeRestrictionPercentageManager.setTransferLimitInPercentage(account_investor1, 5 * 10 ** 16, { - from: token_owner - }); - // transfer happened above limit - await catchRevert( - I_SecurityToken.transfer(account_investor2, web3.utils.toWei('35', 'ether'), { from: account_investor1 }) - ); - - await I_SecurityToken.transfer(account_investor3, web3.utils.toWei('1', 'ether'), { - from: account_investor1 - }); - assert.equal((await I_SecurityToken.balanceOf(account_investor3)).toNumber(), web3.utils.toWei('1', 'ether')); - }); - - it('should change transfer limits to tokens', async () => { - // Should not change to percentage again - await catchRevert( - I_SingleTradeVolumeRestrictionPercentageManager.changeTransferLimitToPercentage(1, { from: token_owner }) - ); - - - let tx = await I_SingleTradeVolumeRestrictionPercentageManager.changeTransferLimitToTokens(1, { - from: token_owner - }); - assert.equal(await I_SingleTradeVolumeRestrictionPercentageManager.isTransferLimitInPercentage(), false, "Error Changing"); - assert.equal(tx.logs[0].args._amount.toNumber(), 1, "Transfer limit not changed"); - }) - - it('should change transfer limits to percentage', async () => { - // Should not change to tokens again - await catchRevert( - I_SingleTradeVolumeRestrictionManager.changeTransferLimitToTokens(1, { from: token_owner }) - ); - - let tx = await I_SingleTradeVolumeRestrictionPercentageManager.changeTransferLimitToPercentage(1, { - from: token_owner - }); - assert.ok(await I_SingleTradeVolumeRestrictionPercentageManager.isTransferLimitInPercentage(), "Error Changing"); - assert.equal(tx.logs[0].args._percentage.toNumber(), 1, "Transfer limit not changed"); - }) - - - - }); - - describe("SingleTradeVolumeRestrictionManager Factory test cases", async () => { - - it("Should get the exact details of the factory", async () => { - assert.equal(await I_SingleTradeVolumeRestrictionManagerFactory.getSetupCost.call(), 0); - assert.equal((await I_SingleTradeVolumeRestrictionManagerFactory.getTypes.call())[0], 2); - let name = web3.utils.toUtf8(await I_SingleTradeVolumeRestrictionManagerFactory.getName.call()); - assert.equal(name, "SingleTradeVolumeRestrictionTM", "Wrong Module added"); - let desc = await I_SingleTradeVolumeRestrictionManagerFactory.description.call(); - assert.equal(desc, "Imposes volume restriction on a single trade", "Wrong Module added"); - let title = await I_SingleTradeVolumeRestrictionManagerFactory.title.call(); - assert.equal(title, "Single Trade Volume Restriction Manager", "Wrong Module added"); - let inst = await I_SingleTradeVolumeRestrictionManagerFactory.getInstructions.call(); - assert.equal(inst, "Allows an issuer to impose volume restriction on a single trade. Init function takes two parameters. First parameter is a bool indicating if restriction is in percentage. The second parameter is the value in percentage or amount of tokens", "Wrong Module added"); - let version = await I_SingleTradeVolumeRestrictionManagerFactory.version.call(); - assert.equal(version, "1.0.0", "Version not correct"); - }); - - it("Should get the tags of the factory", async () => { - let tags = await I_SingleTradeVolumeRestrictionManagerFactory.getTags.call(); - assert.equal(web3.utils.toUtf8(tags[0]), "Single Trade"); - assert.equal(web3.utils.toUtf8(tags[1]), "Transfer"); - assert.equal(web3.utils.toUtf8(tags[2]), "Volume"); - }); - - - }); -}); From 9af58992bbe143794d9ab71fd6956132ca5ad564 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 3 Dec 2018 15:16:29 -0500 Subject: [PATCH 81/93] Return investor data in getAllInvestorsData --- .../modules/TransferManager/GeneralTransferManager.sol | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index 5412afe94..12bfa72ca 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -344,8 +344,11 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, ITransferManag /** * @dev Returns list of all investors data */ - function getAllInvestorsData() external view returns(uint256[], uint256[], uint256[], bool[]) { - return _investorsData(investors); + function getAllInvestorsData() external view returns(address[], uint256[], uint256[], uint256[], bool[]) { + (uint256[] memory fromTimes, uint256[] memory toTimes, uint256[] memory expiryTimes, bool[] memory canBuyFromSTOs) + = _investorsData(investors); + return (investors, fromTimes, toTimes, expiryTimes, canBuyFromSTOs); + } /** From e394850343c4e3a4b192b8510b31f2c2df8f590e Mon Sep 17 00:00:00 2001 From: Victor Date: Mon, 3 Dec 2018 17:42:22 -0300 Subject: [PATCH 82/93] CLI changes according GTM optimizations --- CLI/commands/transfer_manager.js | 62 +++++++++++++++++++++-- CLI/package.json | 1 + CLI/yarn.lock | 85 +++++++++++++++++++++++++++++++- 3 files changed, 142 insertions(+), 6 deletions(-) diff --git a/CLI/commands/transfer_manager.js b/CLI/commands/transfer_manager.js index 44ae64ca1..af50af8cb 100644 --- a/CLI/commands/transfer_manager.js +++ b/CLI/commands/transfer_manager.js @@ -6,6 +6,7 @@ var contracts = require('./helpers/contract_addresses'); var abis = require('./helpers/contract_abis'); var gbl = require('./common/global'); var whitelist = require('./whitelist'); +const { table } = require('table') // App flow let tokenSymbol; @@ -316,6 +317,8 @@ async function generalTransferManager() { let displayAllowAllWhitelistTransfers = await currentTransferManager.methods.allowAllWhitelistTransfers().call(); let displayAllowAllWhitelistIssuances = await currentTransferManager.methods.allowAllWhitelistIssuances().call(); let displayAllowAllBurnTransfers = await currentTransferManager.methods.allowAllBurnTransfers().call(); + let displayDefaults = await currentTransferManager.methods.defaults().call(); + let displayInvestors = await currentTransferManager.methods.getInvestors().call(); console.log(`- Issuance address: ${displayIssuanceAddress}`); console.log(`- Signing address: ${displaySigningAddress}`); @@ -323,10 +326,18 @@ async function generalTransferManager() { console.log(`- Allow all whitelist transfers: ${displayAllowAllWhitelistTransfers ? `YES` : `NO`}`); console.log(`- Allow all whitelist issuances: ${displayAllowAllWhitelistIssuances ? `YES` : `NO`}`); console.log(`- Allow all burn transfers: ${displayAllowAllBurnTransfers ? `YES` : `NO`}`); + console.log(`- Default times:`); + console.log(` - From time: ${displayDefaults.fromTime} (${moment.unix(displayDefaults.fromTime).format('MMMM Do YYYY, HH:mm:ss')})`); + console.log(` - To time: ${displayDefaults.toTime} (${moment.unix(displayDefaults.toTime).format('MMMM Do YYYY, HH:mm:ss')})`); + console.log(`- Investors: ${displayInvestors.length}`); // ------------------ - let options = ['Modify whitelist', 'Modify whitelist from CSV', /*'Modify Whitelist Signed',*/ - `Change issuance address`, 'Change signing address']; + let options = []; + if (displayInvestors.length > 0) { + options.push(`Show investors`, `Show whitelist data`); + } + options.push('Modify whitelist', 'Modify whitelist from CSV', /*'Modify Whitelist Signed',*/ + 'Change the default times used when they are zero', `Change issuance address`, 'Change signing address'); if (displayAllowAllTransfers) { options.push('Disallow all transfers'); } else { @@ -352,6 +363,34 @@ async function generalTransferManager() { let optionSelected = options[index]; console.log('Selected:', index != -1 ? optionSelected : 'Return', '\n'); switch (optionSelected) { + case `Show investors`: + console.log('***** List of investors on whitelist *****'); + displayInvestors.map(i => console.log(i)); + break; + case `Show whitelist data`: + let investorsToShow = readlineSync.question(`Enter the addresses of the investors you want to show (i.e: addr1,addr2,addr3) or leave empty to show them all: `, { + limit: function (input) { + return input === '' || input.split(",").every(a => web3.utils.isAddress(a)); + }, + limitMessage: `All addresses must be valid` + }); + if (investorsToShow === '') { + let whitelistData = await currentTransferManager.methods.getAllInvestorsData().call(); + showWhitelistTable(whitelistData[0], whitelistData[1], whitelistData[2], whitelistData[3], whitelistData[4]); + } else { + let investorsArray = investorsToShow.split(','); + let whitelistData = await currentTransferManager.methods.getInvestorsData(investorsArray).call(); + showWhitelistTable(investorsArray, whitelistData[0], whitelistData[1], whitelistData[2], whitelistData[3]); + } + break; + case 'Change the default times used when they are zero': + let fromTimeDefault = readlineSync.questionInt(`Enter the default time (Unix Epoch time) used when fromTime is zero: `); + let toTimeDefault = readlineSync.questionInt(`Enter the default time (Unix Epoch time) used when fromTime is zero: `); + let changeDefaultsAction = currentTransferManager.methods.changeDefaults(fromTimeDefault, toTimeDefault); + let changeDefaultsReceipt = await common.sendTransaction(changeDefaultsAction); + let changeDefaultsEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, changeDefaultsReceipt.logs, 'ChangeDefaults'); + console.log(chalk.green(`Default times have been updated successfully!`)); + break; case 'Modify whitelist': let investor = readlineSync.question('Enter the address to whitelist: ', { limit: function (input) { @@ -373,7 +412,7 @@ async function generalTransferManager() { case 'Modify whitelist from CSV': console.log(chalk.yellow(`Data is going to be read from 'data/whitelist_data.csv'. Be sure this file is updated!`)); if (readlineSync.keyInYNStrict(`Do you want to continue?`)) { - await whitelist.executeApp(tokenSymbl); + await whitelist.executeApp(tokenSymbol); } break; /* @@ -468,6 +507,21 @@ async function generalTransferManager() { } } +function showWhitelistTable(investorsArray, fromTimeArray, toTimeArray, expiryTimeArray, canBuyFromSTOArray) { + let dataTable = [['Investor', 'From time', 'To time', 'KYC expiry date', 'Restricted']]; + for (let i = 0; i < investorsArray.length; i++) { + dataTable.push([ + investorsArray[i], + moment.unix(fromTimeArray[i]).format('MM/DD/YYYY HH:mm'), + moment.unix(toTimeArray[i]).format('MM/DD/YYYY HH:mm'), + moment.unix(expiryTimeArray[i]).format('MM/DD/YYYY HH:mm'), + canBuyFromSTOArray[i] ? 'YES' : 'NO' + ]); + } + console.log(); + console.log(table(dataTable)); +} + async function manualApprovalTransferManager() { console.log(chalk.blue(`Manual Approval Transfer Manager at ${currentTransferManager.options.address}`), '\n'); @@ -498,7 +552,7 @@ async function manualApprovalTransferManager() { if (manualApproval) { console.log(`Manual approval found!`); console.log(`Allowance: ${web3.utils.fromWei(manualApproval.allowance)}`); - console.log(`Expiry time: ${moment.unix(manualApproval.expiryTime).format('MMMM Do YYYY, HH:mm:ss')};`) + console.log(`Expiry time: ${moment.unix(manualApproval.expiryTime).format('MMMM Do YYYY, HH:mm:ss')}`); } else { console.log(chalk.yellow(`There are no manual approvals from ${from} to ${to}.`)); } diff --git a/CLI/package.json b/CLI/package.json index 95a391b45..59fb4650f 100644 --- a/CLI/package.json +++ b/CLI/package.json @@ -16,6 +16,7 @@ "readline-sync": "^1.4.9", "request": "^2.88.0", "request-promise": "^4.2.2", + "table": "^5.1.1", "web3": "1.0.0-beta.35" } } diff --git a/CLI/yarn.lock b/CLI/yarn.lock index 4d20bee11..0723cde58 100644 --- a/CLI/yarn.lock +++ b/CLI/yarn.lock @@ -30,7 +30,22 @@ ajv@^5.3.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ansi-styles@^3.2.1: +ajv@^6.6.1: + version "6.6.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.1.tgz#6360f5ed0d80f232cc2b294c362d5dc2e538dd61" + integrity sha512-ZoJjft5B+EJBjUyu9C9Hc0OZyPZSSlOF+plzouTrg6UlA8f+e/n8NIgBFG/9tppJtpPWfthHakK7juJdNDODww== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -68,6 +83,11 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" @@ -736,6 +756,11 @@ fast-deep-equal@^1.0.0: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -1037,6 +1062,11 @@ is-callable@^1.1.3: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + is-function@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" @@ -1115,6 +1145,11 @@ json-schema-traverse@^0.3.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" @@ -1150,7 +1185,7 @@ keccakjs@^0.2.1: browserify-sha3 "^0.0.1" sha3 "^1.1.0" -lodash@^4.13.1: +lodash@^4.13.1, lodash@^4.17.11: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== @@ -1491,6 +1526,11 @@ punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + qs@6.5.2, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -1744,6 +1784,15 @@ simple-get@^2.7.0: once "^1.3.1" simple-concat "^1.0.0" +slice-ansi@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.0.0.tgz#5373bdb8559b45676e8541c66916cdd6251612e7" + integrity sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + sshpk@^1.7.0: version "1.15.1" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.15.1.tgz#b79a089a732e346c6e0714830f36285cd38191a2" @@ -1779,6 +1828,14 @@ strict-uri-encode@^1.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= +string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -1786,6 +1843,13 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + strip-dirs@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" @@ -1826,6 +1890,16 @@ swarm-js@0.1.37: tar.gz "^1.0.5" xhr-request-promise "^0.1.2" +table@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/table/-/table-5.1.1.tgz#92030192f1b7b51b6eeab23ed416862e47b70837" + integrity sha512-NUjapYb/qd4PeFW03HnAuOJ7OMcBkJlqeClWxeNlQ0lXGSb52oZXGzkO0/I0ARegQ2eUT1g2VDJH0eUxDRcHmw== + dependencies: + ajv "^6.6.1" + lodash "^4.17.11" + slice-ansi "2.0.0" + string-width "^2.1.1" + tar-stream@^1.5.2: version "1.6.2" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" @@ -1951,6 +2025,13 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + url-parse-lax@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" From 04f02c1d72eb486b71d4c39cefb28ac05796c6dd Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 3 Dec 2018 18:58:46 -0500 Subject: [PATCH 83/93] Bump versions --- contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol | 2 +- contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol | 2 +- .../modules/TransferManager/GeneralTransferManagerFactory.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol b/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol index b7e668111..bae9913b8 100644 --- a/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol +++ b/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol @@ -22,7 +22,7 @@ contract ERC20DividendCheckpointFactory is ModuleFactory { ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { require(_logicContract != address(0), "Invalid logic contract"); - version = "1.0.0"; + version = "2.1.0"; name = "ERC20DividendCheckpoint"; title = "ERC20 Dividend Checkpoint"; description = "Create ERC20 dividends for token holders at a specific checkpoint"; diff --git a/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol b/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol index 2d8d8f529..712292d0a 100644 --- a/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol +++ b/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol @@ -22,7 +22,7 @@ contract EtherDividendCheckpointFactory is ModuleFactory { ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { require(_logicContract != address(0), "Invalid logic contract"); - version = "1.0.0"; + version = "2.1.0"; name = "EtherDividendCheckpoint"; title = "Ether Dividend Checkpoint"; description = "Create ETH dividends for token holders at a specific checkpoint"; diff --git a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol index 4259e8b9f..cffc61a32 100644 --- a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol @@ -22,7 +22,7 @@ contract GeneralTransferManagerFactory is ModuleFactory { ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { require(_logicContract != address(0), "Invalid logic contract"); - version = "2.0.0"; + version = "2.1.0"; name = "GeneralTransferManager"; title = "General Transfer Manager"; description = "Manage transfers using a time based whitelist"; From 847c0ff1804460a4010461e737487ac25e0d4cb5 Mon Sep 17 00:00:00 2001 From: satyam Date: Tue, 4 Dec 2018 15:38:34 +0530 Subject: [PATCH 84/93] version changes --- CHANGELOG.md | 8 ++++++-- .../ManualApprovalTransferManagerFactory.sol | 2 +- test/e_erc20_dividends.js | 2 +- test/f_ether_dividends.js | 2 +- test/h_general_transfer_manager.js | 2 +- test/j_manual_approval_transfer_manager.js | 2 +- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 288ed8037..483d50c8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,13 +16,17 @@ All notable changes to this project will be documented in this file. ## GeneralTransferManager * `getInvestors`, `getAllInvestorsData`, `getInvestorsData` added to GTM to allow easy data queries. * `modifyDefaults(uint64 _defaultFromTime, uint64 _defaultToTime)` added which sets a default timestamp used when `fromTime` or `toTime` are 0 -* Add `address[] public investors` to record a list of all addresses that have been added to the whitelist (`getInvestors`) +* Add `address[] public investors` to record a list of all addresses that have been added to the whitelist (`getInvestors`). +* Changed the version of `GeneralTransferManagerFactory` from `1.0.0` to `2.1.0`. ## Manual Approval TransferManager * Removed `0x0` check for the `_from` address to `ManualApprovalTransferManager`. This allows for the Issuer/Transfer Agent to approve a one-off mint of tokens that otherwise would not be possible. -* Changed the version of `ManualApprovalTransferManagerFactory` from `1.0.0` to `2.0.1`. +* Changed the version of `ManualApprovalTransferManagerFactory` from `1.0.0` to `2.1.0`. * Deployed 2.0.1 `ManualApprovalTransferManagerFactory` to address 0x6af2afad53cb334e62b90ddbdcf3a086f654c298 +## Dividends +* Changed the version of `ERC20DividendCheckpointFactory` & `EtherDividendCheckpointFactory` from `1.0.0` to `2.1.0`. + ## Changed * `getAllModulesAndPermsFromTypes()` does not take securityToken address as a parameter anymore. * General Transfer Manager: Fix for when `allowAllWhitelistIssuances` is FALSE diff --git a/contracts/modules/TransferManager/ManualApprovalTransferManagerFactory.sol b/contracts/modules/TransferManager/ManualApprovalTransferManagerFactory.sol index 9c5513ee7..3fd33a39b 100644 --- a/contracts/modules/TransferManager/ManualApprovalTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/ManualApprovalTransferManagerFactory.sol @@ -18,7 +18,7 @@ contract ManualApprovalTransferManagerFactory is ModuleFactory { constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { - version = "2.0.1"; + version = "2.1.0"; name = "ManualApprovalTransferManager"; title = "Manual Approval Transfer Manager"; description = "Manage transfers using single approvals / blocking"; diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index aac008d4a..96f27883b 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -1105,7 +1105,7 @@ contract("ERC20DividendCheckpoint", accounts => { it("should get the exact details of the factory", async () => { assert.equal((await I_ERC20DividendCheckpointFactory.getSetupCost.call()).toNumber(), 0); assert.equal((await I_ERC20DividendCheckpointFactory.getTypes.call())[0], 4); - assert.equal(await I_ERC20DividendCheckpointFactory.version.call(), "1.0.0"); + assert.equal(await I_ERC20DividendCheckpointFactory.version.call(), "2.1.0"); assert.equal( web3.utils.toAscii(await I_ERC20DividendCheckpointFactory.getName.call()).replace(/\u0000/g, ""), "ERC20DividendCheckpoint", diff --git a/test/f_ether_dividends.js b/test/f_ether_dividends.js index 694b8611a..6b7461629 100644 --- a/test/f_ether_dividends.js +++ b/test/f_ether_dividends.js @@ -954,7 +954,7 @@ contract("EtherDividendCheckpoint", accounts => { it("should get the exact details of the factory", async () => { assert.equal((await I_EtherDividendCheckpointFactory.getSetupCost.call()).toNumber(), 0); assert.equal((await I_EtherDividendCheckpointFactory.getTypes.call())[0], 4); - assert.equal(await I_EtherDividendCheckpointFactory.version.call(), "1.0.0"); + assert.equal(await I_EtherDividendCheckpointFactory.version.call(), "2.1.0"); assert.equal( web3.utils.toAscii(await I_EtherDividendCheckpointFactory.getName.call()).replace(/\u0000/g, ""), "EtherDividendCheckpoint", diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index d00108376..76a9d5806 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -890,7 +890,7 @@ contract("GeneralTransferManager", accounts => { "Allows an issuer to maintain a time based whitelist of authorised token holders.Addresses are added via modifyWhitelist and take a fromTime (the time from which they can send tokens) and a toTime (the time from which they can receive tokens). There are additional flags, allowAllWhitelistIssuances, allowAllWhitelistTransfers & allowAllTransfers which allow you to set corresponding contract level behaviour. Init function takes no parameters.", "Wrong Module added" ); - assert.equal(await I_GeneralPermissionManagerFactory.version.call(), "1.0.0"); + assert.equal(await I_GeneralTransferManagerFactory.version.call(), "2.1.0"); }); it("Should get the tags of the factory", async () => { diff --git a/test/j_manual_approval_transfer_manager.js b/test/j_manual_approval_transfer_manager.js index 5779a1c13..dae21b9c1 100644 --- a/test/j_manual_approval_transfer_manager.js +++ b/test/j_manual_approval_transfer_manager.js @@ -541,7 +541,7 @@ contract("ManualApprovalTransferManager", accounts => { "Allows an issuer to set manual approvals or blocks for specific pairs of addresses and amounts. Init function takes no parameters.", "Wrong Module added" ); - assert.equal(await I_ManualApprovalTransferManagerFactory.version.call(), "2.0.1"); + assert.equal(await I_ManualApprovalTransferManagerFactory.version.call(), "2.1.0"); }); it("Should get the tags of the factory", async () => { From fcbb93dd3a0c7f766f3b150bcfc89372f6b5e335 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Tue, 4 Dec 2018 12:43:06 +0200 Subject: [PATCH 85/93] updated doc for getSchedule --- contracts/modules/Wallet/VestingEscrowWallet.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 6e2fe717e..02236ec29 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -383,7 +383,7 @@ contract VestingEscrowWallet is IWallet { * @notice Returns beneficiary's schedule * @param _beneficiary beneficiary's address * @param _templateName name of the template - * @return beneficiary's schedule + * @return beneficiary's schedule data (numberOfTokens, duration, frequency, startTime, claimedTokens, State) */ function getSchedule(address _beneficiary, bytes32 _templateName) external view returns(uint256, uint256, uint256, uint256, uint256, State) { _checkSchedule(_beneficiary, _templateName); From 7cf5c59533892f45b76c9321dc1aaa169af945e3 Mon Sep 17 00:00:00 2001 From: Pablo Ruiz Date: Tue, 4 Dec 2018 07:42:48 -0500 Subject: [PATCH 86/93] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 483d50c8b..bcf26f35e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ All notable changes to this project will be documented in this file. * `getInvestors`, `getAllInvestorsData`, `getInvestorsData` added to GTM to allow easy data queries. * `modifyDefaults(uint64 _defaultFromTime, uint64 _defaultToTime)` added which sets a default timestamp used when `fromTime` or `toTime` are 0 * Add `address[] public investors` to record a list of all addresses that have been added to the whitelist (`getInvestors`). +* General Transfer Manager: Fix for when `allowAllWhitelistIssuances` is FALSE +* General Transfer Manager: Make GTM a Proxy based implementation to reduce deployment gas costs * Changed the version of `GeneralTransferManagerFactory` from `1.0.0` to `2.1.0`. ## Manual Approval TransferManager @@ -26,11 +28,11 @@ All notable changes to this project will be documented in this file. ## Dividends * Changed the version of `ERC20DividendCheckpointFactory` & `EtherDividendCheckpointFactory` from `1.0.0` to `2.1.0`. +* Applied proxy pattern to Dividends modules ## Changed * `getAllModulesAndPermsFromTypes()` does not take securityToken address as a parameter anymore. -* General Transfer Manager: Fix for when `allowAllWhitelistIssuances` is FALSE -* General Transfer Manager: Make GTM a Proxy based implementation to reduce deployment gas costs + # v1.5.0 - Release Candidate From 6f0bed7707c73c58c2ccfe275f14851f39c82328 Mon Sep 17 00:00:00 2001 From: satyam Date: Wed, 5 Dec 2018 12:47:46 +0530 Subject: [PATCH 87/93] VEW deployable by proxy --- contracts/interfaces/IBoot.sol | 7 ++++++ .../modules/Wallet/VestingEscrowWallet.sol | 2 +- .../Wallet/VestingEscrowWalletFactory.sol | 5 ++-- migrations/2_deploy_contracts.js | 24 +++++++++++++++++-- test/helpers/createInstances.js | 5 +++- test/z_vesting_escrow_wallet.js | 8 +++---- 6 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 contracts/interfaces/IBoot.sol diff --git a/contracts/interfaces/IBoot.sol b/contracts/interfaces/IBoot.sol new file mode 100644 index 000000000..dd293664d --- /dev/null +++ b/contracts/interfaces/IBoot.sol @@ -0,0 +1,7 @@ +pragma solidity ^0.4.24; + +interface IBoot { + + function getInitFunction() external pure returns (bytes4); + +} \ No newline at end of file diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 49365089d..78785b4b0 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -7,7 +7,7 @@ import "./IWallet.sol"; /** * @title Wallet for core vesting escrow functionality */ -contract VestingEscrowWallet is IWallet { +contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { using SafeMath for uint256; bytes32 public constant ADMIN = "ADMIN"; diff --git a/contracts/modules/Wallet/VestingEscrowWalletFactory.sol b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol index 62de4c1c6..238d571ea 100644 --- a/contracts/modules/Wallet/VestingEscrowWalletFactory.sol +++ b/contracts/modules/Wallet/VestingEscrowWalletFactory.sol @@ -1,6 +1,7 @@ pragma solidity ^0.4.24; import "../../proxy/VestingEscrowWalletProxy.sol"; +import "../../interfaces/IBoot.sol"; import "../ModuleFactory.sol"; import "../../libraries/Util.sol"; @@ -38,7 +39,7 @@ contract VestingEscrowWalletFactory is ModuleFactory { } VestingEscrowWalletProxy vestingEscrowWallet = new VestingEscrowWalletProxy(msg.sender, address(polyToken), logicContract); //Checks that _data is valid (not calling anything it shouldn't) - require(Util.getSig(_data) == vestingEscrowWallet.getInitFunction(), "Invalid data"); + require(Util.getSig(_data) == IBoot(vestingEscrowWallet).getInitFunction(), "Invalid data"); /*solium-disable-next-line security/no-low-level-calls*/ require(address(vestingEscrowWallet).call(_data), "Unsuccessfull call"); /*solium-disable-next-line security/no-block-members*/ @@ -60,7 +61,7 @@ contract VestingEscrowWalletFactory is ModuleFactory { */ function getInstructions() external view returns(string) { /*solium-disable-next-line max-len*/ - return "Issuer can send tokens to and then select the address that would be able to withdraw them according to their specific vesting schedule."; + return "Issuer can deposit tokens to the contract and create the vesting schedule for the given address (Affiliate/Employee). These address can withdraw tokens according to there vesting schedule."; } /** diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index f25cfab35..6ba616bfa 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -9,6 +9,8 @@ const EtherDividendCheckpointLogic = artifacts.require('./EtherDividendCheckpoin const ERC20DividendCheckpointLogic = artifacts.require('./ERC20DividendCheckpoint.sol') const EtherDividendCheckpointFactory = artifacts.require('./EtherDividendCheckpointFactory.sol') const ERC20DividendCheckpointFactory = artifacts.require('./ERC20DividendCheckpointFactory.sol') +const VestingEscrowWalletFactory = artifacts.require('./VestingEscrowWalletFactory.sol'); +const VestingEscrowWalletLogic = artifacts.require('./VestingEscrowWallet.sol'); const ModuleRegistry = artifacts.require('./ModuleRegistry.sol'); const ModuleRegistryProxy = artifacts.require('./ModuleRegistryProxy.sol'); const ManualApprovalTransferManagerFactory = artifacts.require('./ManualApprovalTransferManagerFactory.sol') @@ -153,13 +155,21 @@ module.exports = function (deployer, network, accounts) { // manager attach with the securityToken contract at the time of deployment) return deployer.deploy(GeneralTransferManagerLogic, "0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000", {from: PolymathAccount}); }).then(() => { - // B) Deploy the GeneralTransferManagerLogic Contract (Factory used to generate the GeneralTransferManager contract and this + // B) Deploy the ERC20DividendCheckpointLogic Contract (Factory used to generate the ERC20DividendCheckpoint contract and this // manager attach with the securityToken contract at the time of deployment) return deployer.deploy(ERC20DividendCheckpointLogic, "0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000", {from: PolymathAccount}); }).then(() => { - // B) Deploy the GeneralTransferManagerLogic Contract (Factory used to generate the GeneralTransferManager contract and this + // B) Deploy the EtherDividendCheckpointLogic Contract (Factory used to generate the EtherDividendCheckpoint contract and this // manager attach with the securityToken contract at the time of deployment) return deployer.deploy(EtherDividendCheckpointLogic, "0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000", {from: PolymathAccount}); + }).then(() => { + // B) Deploy the VestingEscrowWalletLogic Contract (Factory used to generate the VestingEscrowWallet contract and this + // manager attach with the securityToken contract at the time of deployment) + return deployer.deploy(VestingEscrowWalletLogic, "0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000", {from: PolymathAccount}); + }).then(() => { + // B) Deploy the VestingEscrowWalletFactory Contract (Factory used to generate the VestingEscrowWallet contract and this + // manager attach with the securityToken contract at the time of deployment) + return deployer.deploy(VestingEscrowWalletFactory, PolyToken, 0, 0, 0, VestingEscrowWalletLogic.address, {from: PolymathAccount}); }).then(() => { // B) Deploy the GeneralTransferManagerFactory Contract (Factory used to generate the GeneralTransferManager contract and this // manager attach with the securityToken contract at the time of deployment) @@ -215,6 +225,10 @@ module.exports = function (deployer, network, accounts) { // D) Register the PercentageTransferManagerFactory in the ModuleRegistry to make the factory available at the protocol level. // So any securityToken can use that factory to generate the PercentageTransferManager contract. return moduleRegistry.registerModule(PercentageTransferManagerFactory.address, {from: PolymathAccount}); + }).then(() => { + // D) Register the VestingEscrowWalletFactory in the ModuleRegistry to make the factory available at the protocol level. + // So any securityToken can use that factory to generate the VestingEscrowWallet contract. + return moduleRegistry.registerModule(VestingEscrowWalletFactory.address, {from: PolymathAccount}); }).then(() => { // D) Register the CountTransferManagerFactory in the ModuleRegistry to make the factory available at the protocol level. // So any securityToken can use that factory to generate the CountTransferManager contract. @@ -274,6 +288,11 @@ module.exports = function (deployer, network, accounts) { // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. return moduleRegistry.verifyModule(ManualApprovalTransferManagerFactory.address, true, {from: PolymathAccount}); + }).then(() => { + // F) Once the VestingEscrowWalletFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken + // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. + // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. + return moduleRegistry.verifyModule(VestingEscrowWalletFactory.address, true, {from: PolymathAccount}); }).then(() => { // M) Deploy the CappedSTOFactory (Use to generate the CappedSTO contract which will used to collect the funds ). return deployer.deploy(CappedSTOFactory, PolyToken, cappedSTOSetupCost, 0, 0, {from: PolymathAccount}) @@ -333,6 +352,7 @@ module.exports = function (deployer, network, accounts) { ERC20DividendCheckpointLogic: ${ERC20DividendCheckpointLogic.address} EtherDividendCheckpointFactory: ${EtherDividendCheckpointFactory.address} ERC20DividendCheckpointFactory: ${ERC20DividendCheckpointFactory.address} + VestingEscrowWalletFactory: ${VestingEscrowWalletFactory.address} --------------------------------------------------------------------------------- `); console.log('\n'); diff --git a/test/helpers/createInstances.js b/test/helpers/createInstances.js index cea1929cf..767b2c632 100644 --- a/test/helpers/createInstances.js +++ b/test/helpers/createInstances.js @@ -33,6 +33,7 @@ const DummySTOFactory = artifacts.require("./DummySTOFactory.sol"); const MockBurnFactory = artifacts.require("./MockBurnFactory.sol"); const MockWrongTypeFactory = artifacts.require("./MockWrongTypeFactory.sol"); const VestingEscrowWalletFactory = artifacts.require("./VestingEscrowWalletFactory.sol"); +const VestingEscrowWallet = artifacts.require("./VestingEscrowWallet.sol"); const Web3 = require("web3"); const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); // Hardcoded development port @@ -69,6 +70,7 @@ let I_PolyToken; let I_STFactory; let I_PolymathRegistry; let I_SecurityTokenRegistryProxy; +let I_VestingEscrowWalletLogic; let I_STRProxied; let I_MRProxied; @@ -406,7 +408,8 @@ export async function deployRedemptionAndVerifyed(accountPolymath, MRProxyInstan } export async function deployVestingEscrowWalletAndVerifyed(accountPolymath, MRProxyInstance, polyToken, setupCost) { - I_VestingEscrowWalletFactory = await VestingEscrowWalletFactory.new(polyToken, setupCost, 0, 0, { from: accountPolymath }); + I_VestingEscrowWalletLogic = await VestingEscrowWallet.new("0x0000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000", { from: accountPolymath }); + I_VestingEscrowWalletFactory = await VestingEscrowWalletFactory.new(polyToken, setupCost, 0, 0, I_VestingEscrowWalletLogic.address, { from: accountPolymath }); assert.notEqual( I_VestingEscrowWalletFactory.address.valueOf(), diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index a9328074a..754bd65bd 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -259,15 +259,15 @@ contract('VestingEscrowWallet', accounts => { it("Should get the tags of the factory", async () => { let tags = await I_VestingEscrowWalletFactory.getTags.call(); assert.equal(tags.length, 2); - assert.equal(web3.utils.toAscii(tags[0]).replace(/\u0000/g, ""), "Vested Wallet"); - assert.equal(web3.utils.toAscii(tags[1]).replace(/\u0000/g, ""), "Escrow"); + assert.equal(web3.utils.toAscii(tags[0]).replace(/\u0000/g, ""), "Vested"); + assert.equal(web3.utils.toAscii(tags[1]).replace(/\u0000/g, ""), "Escrow Wallet"); }); it("Should get the instructions of the factory", async () => { assert.equal( (await I_VestingEscrowWalletFactory.getInstructions.call()).replace(/\u0000/g, ""), - "Issuer can send tokens to and then select the address that would be able to withdraw them according to their specific vesting schedule." + - ""); + "Issuer can deposit tokens to the contract and create the vesting schedule for the given address (Affiliate/Employee). These address can withdraw tokens according to there vesting schedule." + ); }); }); From 8a8926214709bac11e4eccf9f79a78b733809aa8 Mon Sep 17 00:00:00 2001 From: satyam Date: Wed, 5 Dec 2018 13:21:04 +0530 Subject: [PATCH 88/93] minor fix --- contracts/proxy/VestingEscrowWalletProxy.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/proxy/VestingEscrowWalletProxy.sol b/contracts/proxy/VestingEscrowWalletProxy.sol index 7f73203eb..0138e0402 100644 --- a/contracts/proxy/VestingEscrowWalletProxy.sol +++ b/contracts/proxy/VestingEscrowWalletProxy.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../modules/wallet/VestingEscrowWalletStorage.sol"; +import "../modules/Wallet/VestingEscrowWalletStorage.sol"; import "./OwnedProxy.sol"; import "../Pausable.sol"; import "../modules/ModuleStorage.sol"; From 137e6ebb9c8575c8e782c07479d2ac134076798e Mon Sep 17 00:00:00 2001 From: satyam Date: Wed, 5 Dec 2018 18:59:36 +0530 Subject: [PATCH 89/93] small fix in the pushAvalilableTokensMulti --- contracts/modules/Wallet/VestingEscrowWallet.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 78785b4b0..d7a425051 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -420,7 +420,8 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { function pushAvailableTokensMulti(uint256 _fromIndex, uint256 _toIndex) external withPerm(ADMIN) { require(_toIndex <= beneficiaries.length - 1, "Array out of bound"); for (uint256 i = _fromIndex; i <= _toIndex; i++) { - pushAvailableTokens(beneficiaries[i]); + if (schedules[beneficiaries[i]].length !=0) + pushAvailableTokens(beneficiaries[i]); } } From c7c16ec31ef1e2d5b75c8b068e4b65e69d2004f7 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Mon, 10 Dec 2018 18:13:43 +0200 Subject: [PATCH 90/93] Applied review comments --- .../modules/Wallet/VestingEscrowWallet.sol | 34 ++++++------ .../Wallet/VestingEscrowWalletStorage.sol | 2 + test/z_vesting_escrow_wallet.js | 54 +++++++++++++------ 3 files changed, 58 insertions(+), 32 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index d7a425051..872946ccf 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -90,18 +90,24 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { function _depositTokens(uint256 _numberOfTokens) internal { require(_numberOfTokens > 0, "Should be > 0"); - ISecurityToken(securityToken).transferFrom(msg.sender, address(this), _numberOfTokens); + require( + ISecurityToken(securityToken).transferFrom(msg.sender, address(this), _numberOfTokens), + "Failed transferFrom due to insufficent Allowance provided" + ); unassignedTokens = unassignedTokens.add(_numberOfTokens); emit DepositTokens(_numberOfTokens, msg.sender); } /** * @notice Sends unassigned tokens to treasury + * @param _amount amount of tokens that should be send */ - function sendToTreasury() external withPerm(ADMIN) { + function sendToTreasury(uint256 _amount) external withPerm(ADMIN) { + require(_amount > 0, "Amount cannot be zero"); + require(_amount <= unassignedTokens, "Amount is greater than unassigned tokens"); uint256 amount = unassignedTokens; unassignedTokens = 0; - ISecurityToken(securityToken).transfer(treasuryWallet, amount); + require(ISecurityToken(securityToken).transfer(treasuryWallet, amount), "Transfer failed"); emit SendToTreasury(amount, msg.sender); } @@ -136,7 +142,7 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { require(!_isTemplateExists(_name), "Already exists"); _validateTemplate(_numberOfTokens, _duration, _frequency); templateNames.push(_name); - templates[_name] = Template(_numberOfTokens, _duration, _frequency); + templates[_name] = Template(_numberOfTokens, _duration, _frequency, templateNames.length - 1); emit AddTemplate(_name, _numberOfTokens, _duration, _frequency); } @@ -147,18 +153,16 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { function removeTemplate(bytes32 _name) external withPerm(ADMIN) { require(_isTemplateExists(_name), "Template not found"); require(templateToUsers[_name].length == 0, "Template is used"); - // delete template data - delete templates[_name]; - uint256 i; - for (i = 0; i < templateNames.length; i++) { - if (_name == templateNames[i]) { - break; - } - } - if (i != templateNames.length - 1) { - templateNames[i] = templateNames[templateNames.length - 1]; + uint256 index = templates[_name].index; + if (index != templateNames.length - 1) { + templateNames[index] = templateNames[templateNames.length - 1]; } templateNames.length--; + if (index != templateNames.length) { + templates[templateNames[index]].index = index; + } + // delete template data + delete templates[_name]; emit RemoveTemplate(_name); } @@ -538,7 +542,7 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { uint256 amount = _getAvailableTokens(_beneficiary, _index); if (amount > 0) { schedules[_beneficiary][_index].claimedTokens = schedules[_beneficiary][_index].claimedTokens.add(amount); - ISecurityToken(securityToken).transfer(_beneficiary, amount); + require(ISecurityToken(securityToken).transfer(_beneficiary, amount), "Transfer failed"); emit SendTokens(_beneficiary, amount); } } diff --git a/contracts/modules/Wallet/VestingEscrowWalletStorage.sol b/contracts/modules/Wallet/VestingEscrowWalletStorage.sol index bdf7d5df4..af40d32bf 100644 --- a/contracts/modules/Wallet/VestingEscrowWalletStorage.sol +++ b/contracts/modules/Wallet/VestingEscrowWalletStorage.sol @@ -21,6 +21,8 @@ contract VestingEscrowWalletStorage { uint256 duration; // Schedule frequency (It is a cliff time period) uint256 frequency; + // Index of the template in an array template names + uint256 index; } // Number of tokens that are hold by the `this` contract but are unassigned to any schedule diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 754bd65bd..d15acddd1 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -327,13 +327,26 @@ contract('VestingEscrowWallet', accounts => { it("Should not be able to withdraw tokens to a treasury -- fail because of permissions check", async () => { await catchRevert( - I_VestingEscrowWallet.sendToTreasury({from: account_beneficiary1}) + I_VestingEscrowWallet.sendToTreasury(10, {from: account_beneficiary1}) + ); + }); + + it("Should not be able to withdraw tokens to a treasury -- fail because of zero amount", async () => { + await catchRevert( + I_VestingEscrowWallet.sendToTreasury(0, {from: wallet_admin}) + ); + }); + + it("Should not be able to withdraw tokens to a treasury -- fail because amount is greater than unassigned tokens", async () => { + let numberOfTokens = 25000 * 2; + await catchRevert( + I_VestingEscrowWallet.sendToTreasury(numberOfTokens, {from: wallet_admin}) ); }); it("Should withdraw tokens to a treasury", async () => { let numberOfTokens = 25000; - const tx = await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + const tx = await I_VestingEscrowWallet.sendToTreasury(numberOfTokens, {from: wallet_admin}); assert.equal(tx.logs[0].args._numberOfTokens, numberOfTokens); @@ -388,7 +401,8 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.revokeAllSchedules(account_beneficiary3, {from: wallet_admin}); await I_VestingEscrowWallet.removeTemplate(templateName, {from: wallet_admin}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + await I_VestingEscrowWallet.sendToTreasury(unassignedTokens, {from: wallet_admin}); }); it("Should fail to modify vesting schedule -- fail because date in the past", async () => { @@ -422,7 +436,6 @@ contract('VestingEscrowWallet', accounts => { await I_SecurityToken.transfer(token_owner, balance, {from: account_beneficiary3}); await I_VestingEscrowWallet.revokeAllSchedules(account_beneficiary3, {from: wallet_admin}); await I_VestingEscrowWallet.removeTemplate(templateName, {from: wallet_admin}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); it("Should withdraw available tokens 2 times by 3 schedules to the beneficiary address", async () => { @@ -489,7 +502,6 @@ contract('VestingEscrowWallet', accounts => { for (let i = 0; i < schedules.length; i++) { await I_VestingEscrowWallet.removeTemplate(schedules[i].templateName, {from: wallet_admin}); } - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); }); @@ -579,7 +591,8 @@ contract('VestingEscrowWallet', accounts => { await catchRevert( I_VestingEscrowWallet.addSchedule(account_beneficiary1, templateName, numberOfTokens, duration, frequency, startTime, {from: account_beneficiary1}) ); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + await I_VestingEscrowWallet.sendToTreasury(unassignedTokens, {from: wallet_admin}); }); it("Should add vesting schedule to the beneficiary address", async () => { @@ -626,7 +639,8 @@ contract('VestingEscrowWallet', accounts => { await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, templateName, {from: wallet_admin}); await I_VestingEscrowWallet.removeTemplate(templateName, {from: wallet_admin}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + await I_VestingEscrowWallet.sendToTreasury(unassignedTokens, {from: wallet_admin}); }); it("Should fail to modify vesting schedule -- fail because schedule not found", async () => { @@ -658,8 +672,6 @@ contract('VestingEscrowWallet', accounts => { let schedule = await I_VestingEscrowWallet.getSchedule.call(account_beneficiary1, "template-2-01"); checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); - - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); }); it("Should not be able to revoke schedule -- fail because of permissions check", async () => { @@ -671,7 +683,8 @@ contract('VestingEscrowWallet', accounts => { it("Should revoke vesting schedule from the beneficiary address", async () => { let templateName = "template-2-01"; const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, templateName, {from: wallet_admin}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + await I_VestingEscrowWallet.sendToTreasury(unassignedTokens, {from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary1); assert.equal(web3.utils.hexToUtf8(tx.logs[0].args._templateName), templateName); @@ -732,7 +745,8 @@ contract('VestingEscrowWallet', accounts => { it("Should revoke 1 of 3 vesting schedule from the beneficiary address", async () => { let templateName = schedules[1].templateName; const tx = await I_VestingEscrowWallet.revokeSchedule(account_beneficiary2, templateName, {from: wallet_admin}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + await I_VestingEscrowWallet.sendToTreasury(unassignedTokens, {from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); assert.equal(web3.utils.hexToUtf8(tx.logs[0].args._templateName), templateName); @@ -743,7 +757,8 @@ contract('VestingEscrowWallet', accounts => { it("Should revoke 2 vesting schedules from the beneficiary address", async () => { const tx = await I_VestingEscrowWallet.revokeAllSchedules(account_beneficiary2, {from: wallet_admin}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + await I_VestingEscrowWallet.sendToTreasury(unassignedTokens, {from: wallet_admin}); assert.equal(tx.logs[0].args._beneficiary, account_beneficiary2); @@ -811,7 +826,8 @@ contract('VestingEscrowWallet', accounts => { assert.equal(balance.toNumber(), totalNumberOfTokens - 100000 / 4); await I_SecurityToken.transfer(token_owner, balance, {from: account_beneficiary3}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + await I_VestingEscrowWallet.sendToTreasury(unassignedTokens, {from: wallet_admin}); }); }); @@ -937,7 +953,8 @@ contract('VestingEscrowWallet', accounts => { checkSchedule(schedule, numberOfTokens, duration, frequency, startTime, CREATED); await I_VestingEscrowWallet.revokeSchedule(account_beneficiary1, templateName, {from: wallet_admin}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + await I_VestingEscrowWallet.sendToTreasury(unassignedTokens, {from: wallet_admin}); }); it("Should not be able to add vesting schedule from template -- fail because template already added", async () => { @@ -984,7 +1001,8 @@ contract('VestingEscrowWallet', accounts => { await catchRevert( I_VestingEscrowWallet.addScheduleMulti(beneficiaries, templateNames, [20000, 30000, 10000], [4, 4], [1, 1, 1], startTimes, {from: wallet_admin}) ); - I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + await I_VestingEscrowWallet.sendToTreasury(unassignedTokens, {from: wallet_admin}); }); it("Should add schedules for 3 beneficiaries", async () => { @@ -1081,7 +1099,8 @@ contract('VestingEscrowWallet', accounts => { await I_SecurityToken.transfer(token_owner, balance, {from: beneficiary}); await I_VestingEscrowWallet.revokeAllSchedules(beneficiary, {from: wallet_admin}); await I_VestingEscrowWallet.removeTemplate(templateNames[i], {from: wallet_admin}); - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + await I_VestingEscrowWallet.sendToTreasury(unassignedTokens, {from: wallet_admin}); } }); @@ -1140,7 +1159,8 @@ contract('VestingEscrowWallet', accounts => { assert.equal(scheduleCount, 0); } - await I_VestingEscrowWallet.sendToTreasury({from: wallet_admin}); + let unassignedTokens = await I_VestingEscrowWallet.unassignedTokens.call(); + await I_VestingEscrowWallet.sendToTreasury(unassignedTokens, {from: wallet_admin}); }); }); From affcf54146858352cb7a696bf93fdd0462124e95 Mon Sep 17 00:00:00 2001 From: satyam Date: Mon, 10 Dec 2018 22:03:19 +0530 Subject: [PATCH 91/93] remove the irrevalent if conditions --- contracts/modules/Wallet/VestingEscrowWallet.sol | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 872946ccf..4e0f089b7 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -156,11 +156,9 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { uint256 index = templates[_name].index; if (index != templateNames.length - 1) { templateNames[index] = templateNames[templateNames.length - 1]; - } - templateNames.length--; - if (index != templateNames.length) { templates[templateNames[index]].index = index; } + templateNames.length--; // delete template data delete templates[_name]; emit RemoveTemplate(_name); From af0ab90a294bc4cc1da6f9b4594e0fb558f4f260 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Tue, 18 Dec 2018 17:37:18 +0200 Subject: [PATCH 92/93] Improved the natspec comments --- .../modules/Wallet/VestingEscrowWallet.sol | 135 +++++++++--------- 1 file changed, 68 insertions(+), 67 deletions(-) diff --git a/contracts/modules/Wallet/VestingEscrowWallet.sol b/contracts/modules/Wallet/VestingEscrowWallet.sol index 4e0f089b7..17f6dbb08 100644 --- a/contracts/modules/Wallet/VestingEscrowWallet.sol +++ b/contracts/modules/Wallet/VestingEscrowWallet.sol @@ -63,7 +63,7 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Use to intialize the treasury wallet address + * @notice Used to initialize the treasury wallet address * @param _treasuryWallet Address of the treasury wallet */ function configure(address _treasuryWallet) public onlyFactory { @@ -72,7 +72,7 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Use to change the treasury wallet address + * @notice Used to change the treasury wallet address * @param _newTreasuryWallet Address of the treasury wallet */ function changeTreasuryWallet(address _newTreasuryWallet) public onlyOwner { @@ -82,7 +82,8 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Used to deposit tokens from treasury + * @notice Used to deposit tokens from treasury wallet to the vesting escrow wallet + * @param _numberOfTokens Number of tokens that should be deposited */ function depositTokens(uint256 _numberOfTokens) external withPerm(ADMIN) { _depositTokens(_numberOfTokens); @@ -99,8 +100,8 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Sends unassigned tokens to treasury - * @param _amount amount of tokens that should be send + * @notice Sends unassigned tokens to the treasury wallet + * @param _amount Amount of tokens that should be send to the treasury wallet */ function sendToTreasury(uint256 _amount) external withPerm(ADMIN) { require(_amount > 0, "Amount cannot be zero"); @@ -112,8 +113,8 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Pushes available tokens to beneficiary - * @param _beneficiary beneficiary's address + * @notice Pushes available tokens to the beneficiary's address + * @param _beneficiary Address of the beneficiary who will receive tokens */ function pushAvailableTokens(address _beneficiary) public withPerm(ADMIN) { _sendTokens(_beneficiary); @@ -127,11 +128,11 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Add template - * @param _name name of template - * @param _numberOfTokens number of tokens - * @param _duration vesting duration - * @param _frequency vesting frequency + * @notice Adds template that can be used for creating schedule + * @param _name Name of the template will be created + * @param _numberOfTokens Number of tokens that should be assigned to schedule + * @param _duration Duration of the vesting schedule + * @param _frequency Frequency of the vesting schedule */ function addTemplate(bytes32 _name, uint256 _numberOfTokens, uint256 _duration, uint256 _frequency) external withPerm(ADMIN) { _addTemplate(_name, _numberOfTokens, _duration, _frequency); @@ -147,8 +148,8 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Removes template - * @param _name name of template + * @notice Removes template with a given name + * @param _name Name of the template that will be removed */ function removeTemplate(bytes32 _name) external withPerm(ADMIN) { require(_isTemplateExists(_name), "Template not found"); @@ -165,29 +166,29 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Returns count of templates - * @return count of templates + * @notice Returns count of the templates those can be used for creating schedule + * @return Count of the templates */ function getTemplateCount() external view returns(uint256) { return templateNames.length; } /** - * @notice get the list of template names - * @return bytes32 Array of template names + * @notice Gets the list of the template names those can be used for creating schedule + * @return bytes32 Array of all template names were created */ function getAllTemplateNames() external view returns(bytes32[]) { return templateNames; } /** - * @notice Adds vesting schedules for each of beneficiary - * @param _beneficiary beneficiary's addresses - * @param _templateName name of the template that will be created - * @param _numberOfTokens number of tokens - * @param _duration vesting duration - * @param _frequency vesting frequency - * @param _startTime vesting start time + * @notice Adds vesting schedules for each of the beneficiary's address + * @param _beneficiary Address of the beneficiary for whom it is scheduled + * @param _templateName Name of the template that will be created + * @param _numberOfTokens Total number of tokens for created schedule + * @param _duration Duration of the created vesting schedule + * @param _frequency Frequency of the created vesting schedule + * @param _startTime Start time of the created vesting schedule */ function addSchedule( address _beneficiary, @@ -218,10 +219,10 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Adds vesting schedules from template for each of beneficiary - * @param _beneficiary beneficiary's addresses - * @param _templateName name of the template - * @param _startTime vesting start time + * @notice Adds vesting schedules from template for the beneficiary + * @param _beneficiary Address of the beneficiary for whom it is scheduled + * @param _templateName Name of the exists template + * @param _startTime Start time of the created vesting schedule */ function addScheduleFromTemplate(address _beneficiary, bytes32 _templateName, uint256 _startTime) external withPerm(ADMIN) { _addScheduleFromTemplate(_beneficiary, _templateName, _startTime); @@ -255,10 +256,10 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Modifies vesting schedules for each of beneficiary - * @param _beneficiary beneficiary's addresses - * @param _templateName name of the template - * @param _startTime vesting start time + * @notice Modifies vesting schedules for each of the beneficiary + * @param _beneficiary Address of the beneficiary for whom it is modified + * @param _templateName Name of the template was used for schedule creation + * @param _startTime Start time of the created vesting schedule */ function modifySchedule(address _beneficiary, bytes32 _templateName, uint256 _startTime) public withPerm(ADMIN) { _modifySchedule(_beneficiary, _templateName, _startTime); @@ -276,9 +277,9 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Revokes beneficiary's schedule - * @param _beneficiary beneficiary's address - * @param _templateName name of the template + * @notice Revokes vesting schedule with given template name for given beneficiary + * @param _beneficiary Address of the beneficiary for whom it is revoked + * @param _templateName Name of the template was used for schedule creation */ function revokeSchedule(address _beneficiary, bytes32 _templateName) external withPerm(ADMIN) { _checkSchedule(_beneficiary, _templateName); @@ -315,8 +316,8 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Revokes all beneficiary's schedules - * @param _beneficiary beneficiary's address + * @notice Revokes all vesting schedules for given beneficiary's address + * @param _beneficiary Address of the beneficiary for whom all schedules will be revoked */ function revokeAllSchedules(address _beneficiary) public withPerm(ADMIN) { _revokeAllSchedules(_beneficiary); @@ -339,9 +340,9 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Returns beneficiary's schedule - * @param _beneficiary beneficiary's address - * @param _templateName name of the template + * @notice Returns beneficiary's schedule created using template name + * @param _beneficiary Address of the beneficiary who will receive tokens + * @param _templateName Name of the template was used for schedule creation * @return beneficiary's schedule data (numberOfTokens, duration, frequency, startTime, claimedTokens, State) */ function getSchedule(address _beneficiary, bytes32 _templateName) external view returns(uint256, uint256, uint256, uint256, uint256, State) { @@ -372,9 +373,9 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Returns list of template names - * @param _beneficiary beneficiary's address - * @return list of template names + * @notice Returns list of the template names for given beneficiary's address + * @param _beneficiary Address of the beneficiary + * @return List of the template names that were used for schedule creation */ function getTemplateNames(address _beneficiary) external view returns(bytes32[]) { require(_beneficiary != address(0), "Invalid address"); @@ -382,9 +383,9 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Returns count of beneficiary's schedules - * @param _beneficiary beneficiary's address - * @return count of beneficiary's schedules + * @notice Returns count of the schedules were created for given beneficiary + * @param _beneficiary Address of the beneficiary + * @return Count of beneficiary's schedules */ function getScheduleCount(address _beneficiary) external view returns(uint256) { require(_beneficiary != address(0), "Invalid address"); @@ -415,9 +416,9 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Used to bulk send available tokens for each of beneficiaries - * @param _fromIndex start index of array of beneficiary's addresses - * @param _toIndex end index of array of beneficiary's addresses + * @notice Used to bulk send available tokens for each of the beneficiaries + * @param _fromIndex Start index of array of beneficiary's addresses + * @param _toIndex End index of array of beneficiary's addresses */ function pushAvailableTokensMulti(uint256 _fromIndex, uint256 _toIndex) external withPerm(ADMIN) { require(_toIndex <= beneficiaries.length - 1, "Array out of bound"); @@ -428,13 +429,13 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Used to bulk add vesting schedules for each of beneficiaries - * @param _beneficiaries array of beneficiary's addresses - * @param _templateNames array of the template names - * @param _numberOfTokens array of number of tokens - * @param _durations array of vesting duration - * @param _frequencies array of vesting frequency - * @param _startTimes array of vesting start time + * @notice Used to bulk add vesting schedules for each of beneficiary + * @param _beneficiaries Array of the beneficiary's addresses + * @param _templateNames Array of the template names + * @param _numberOfTokens Array of number of tokens should be assigned to schedules + * @param _durations Array of the vesting duration + * @param _frequencies Array of the vesting frequency + * @param _startTimes Array of the vesting start time */ function addScheduleMulti( address[] _beneficiaries, @@ -461,10 +462,10 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Used to bulk add vesting schedules from template for each of beneficiaries - * @param _beneficiaries array of beneficiary's addresses - * @param _templateNames array of the template names - * @param _startTimes array of vesting start time + * @notice Used to bulk add vesting schedules from template for each of the beneficiary + * @param _beneficiaries Array of beneficiary's addresses + * @param _templateNames Array of the template names were used for schedule creation + * @param _startTimes Array of the vesting start time */ function addScheduleFromTemplateMulti(address[] _beneficiaries, bytes32[] _templateNames, uint256[] _startTimes) external withPerm(ADMIN) { require(_beneficiaries.length == _templateNames.length && _beneficiaries.length == _startTimes.length, "Arrays sizes mismatch"); @@ -474,8 +475,8 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Used to bulk revoke vesting schedules for each of beneficiaries - * @param _beneficiaries array of beneficiary's addresses + * @notice Used to bulk revoke vesting schedules for each of the beneficiaries + * @param _beneficiaries Array of the beneficiary's addresses */ function revokeSchedulesMulti(address[] _beneficiaries) external withPerm(ADMIN) { for (uint256 i = 0; i < _beneficiaries.length; i++) { @@ -484,10 +485,10 @@ contract VestingEscrowWallet is VestingEscrowWalletStorage, IWallet { } /** - * @notice Used to bulk modify vesting schedules for each of beneficiaries - * @param _beneficiaries array of beneficiary's addresses - * @param _templateNames array of the template names - * @param _startTimes array of vesting start time + * @notice Used to bulk modify vesting schedules for each of the beneficiaries + * @param _beneficiaries Array of the beneficiary's addresses + * @param _templateNames Array of the template names + * @param _startTimes Array of the vesting start time */ function modifyScheduleMulti( address[] _beneficiaries, From 9088434c1f3f340caf1ead09646dd7e5821563d5 Mon Sep 17 00:00:00 2001 From: Dmitriy Kostin Date: Wed, 19 Dec 2018 10:14:14 +0200 Subject: [PATCH 93/93] added VestingEscrowWalletLogic to output --- migrations/2_deploy_contracts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index eefc66d28..4beb28252 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -357,6 +357,7 @@ module.exports = function (deployer, network, accounts) { EtherDividendCheckpointFactory: ${EtherDividendCheckpointFactory.address} ERC20DividendCheckpointFactory: ${ERC20DividendCheckpointFactory.address} VestingEscrowWalletFactory: ${VestingEscrowWalletFactory.address} + VestingEscrowWalletLogic: ${VestingEscrowWalletLogic.address} --------------------------------------------------------------------------------- `); console.log('\n');