diff --git a/CHANGELOG.md b/CHANGELOG.md index c5e428e11..94a8c2ce4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ All notable changes to this project will be documented in this file. * Fixed `addModule` function to be backwards compatible and call the new `addModuleWithLabel` function with an empty label. * Fixed event `ModuleAdded` to also emit `_label`. * Fixed function `getModule` to also return the respective module label. +* Added datastore that is used to store data like investor list that is shared among modules. +* `getInvestorCount()` now returns length of investor array that is everyone who ever held some st or has kyc data attached. +* `holderCount()` returns the number of current st holders. +* Added flags for Investors. Accredited and canbuyfromsto are now flags ## STR * Introduce new contract `STRGetter.sol`. It only contains the getter functions of the STR. @@ -19,7 +23,9 @@ All notable changes to this project will be documented in this file. * Removed `_polyToken` parameter from `initialize` function in `SecurityTokenRegistry`. ## GeneralTransferManager -* Add `_isAccredited` variable in the `modifyWhitelist()` function of the GeneralTransferManager. +* `modifyWhitelist()` function renamed to `modifyKYCData()`. +* Added functions to modify and get flags +* `canBuyFromSto` is now `canNotBuyFromSto` and it is the flag `1` ## Generalize * Removed `_polyAddress` parameter from constructors of all modules and module factories. diff --git a/contracts/datastore/DataStore.sol b/contracts/datastore/DataStore.sol index 3c68aac97..958f8c51d 100644 --- a/contracts/datastore/DataStore.sol +++ b/contracts/datastore/DataStore.sol @@ -12,26 +12,24 @@ contract DataStore is DataStoreStorage, IDataStore { //NB To modify a specific element of an array, First push a new element to the array and then delete the old element. //Whenver an element is deleted from an Array, last element of that array is moved to the index of deleted element. //Delegate with MANAGEDATA permission can modify data. - event SecurityTokenChanged(address indexed _oldSecurityToken, address indexed _newSecurityToken); - modifier onlyAuthorized() { - bool isOwner = msg.sender == IOwnable(address(securityToken)).owner(); - require(isOwner || - securityToken.isModule(msg.sender, DATA_KEY) || - securityToken.checkPermission(msg.sender, address(this), MANAGEDATA), + function _isAuthorized() internal view { + require(msg.sender == address(securityToken) || + msg.sender == IOwnable(address(securityToken)).owner() || + securityToken.checkPermission(msg.sender, address(this), MANAGEDATA) || + securityToken.isModule(msg.sender, DATA_KEY), "Unauthorized" ); - _; } modifier validKey(bytes32 _key) { - require(_key != bytes32(0), "Missing key"); + require(_key != bytes32(0), "bad key"); _; } modifier validArrayLength(uint256 _keyLength, uint256 _dataLength) { - require(_keyLength == _dataLength, "Array length mismatch"); + require(_keyLength == _dataLength, "bad length"); _; } @@ -55,27 +53,33 @@ contract DataStore is DataStoreStorage, IDataStore { * @param _key Unique key to identify the data * @param _data Data to be stored against the key */ - function setUint256(bytes32 _key, uint256 _data) external onlyAuthorized { - _setData(_key, _data); + function setUint256(bytes32 _key, uint256 _data) external { + _isAuthorized(); + _setData(_key, _data, false); } - function setBytes32(bytes32 _key, bytes32 _data) external onlyAuthorized { - _setData(_key, _data); + function setBytes32(bytes32 _key, bytes32 _data) external { + _isAuthorized(); + _setData(_key, _data, false); } - function setAddress(bytes32 _key, address _data) external onlyAuthorized { - _setData(_key, _data); + function setAddress(bytes32 _key, address _data) external { + _isAuthorized(); + _setData(_key, _data, false); } - function setString(bytes32 _key, string calldata _data) external onlyAuthorized { - _setData(_key, _data); + function setBool(bytes32 _key, bool _data) external { + _isAuthorized(); + _setData(_key, _data, false); } - function setBytes(bytes32 _key, bytes calldata _data) external onlyAuthorized { + function setString(bytes32 _key, string calldata _data) external { + _isAuthorized(); _setData(_key, _data); } - function setBool(bytes32 _key, bool _data) external onlyAuthorized { + function setBytes(bytes32 _key, bytes calldata _data) external { + _isAuthorized(); _setData(_key, _data); } @@ -84,19 +88,23 @@ contract DataStore is DataStoreStorage, IDataStore { * @param _key Unique key to identify the array * @param _data Array to be stored against the key */ - function setUint256Array(bytes32 _key, uint256[] calldata _data) external onlyAuthorized { + function setUint256Array(bytes32 _key, uint256[] calldata _data) external { + _isAuthorized(); _setData(_key, _data); } - function setBytes32Array(bytes32 _key, bytes32[] calldata _data) external onlyAuthorized { + function setBytes32Array(bytes32 _key, bytes32[] calldata _data) external { + _isAuthorized(); _setData(_key, _data); } - function setAddressArray(bytes32 _key, address[] calldata _data) external onlyAuthorized { + function setAddressArray(bytes32 _key, address[] calldata _data) external { + _isAuthorized(); _setData(_key, _data); } - function setBoolArray(bytes32 _key, bool[] calldata _data) external onlyAuthorized { + function setBoolArray(bytes32 _key, bool[] calldata _data) external { + _isAuthorized(); _setData(_key, _data); } @@ -105,20 +113,24 @@ contract DataStore is DataStoreStorage, IDataStore { * @param _key Unique key to identify the array * @param _data Element to push into the array */ - function insertUint256(bytes32 _key, uint256 _data) external onlyAuthorized { - _insertData(_key, _data); + function insertUint256(bytes32 _key, uint256 _data) external { + _isAuthorized(); + _setData(_key, _data, true); } - function insertBytes32(bytes32 _key, bytes32 _data) external onlyAuthorized { - _insertData(_key, _data); + function insertBytes32(bytes32 _key, bytes32 _data) external { + _isAuthorized(); + _setData(_key, _data, true); } - function insertAddress(bytes32 _key, address _data) external onlyAuthorized { - _insertData(_key, _data); + function insertAddress(bytes32 _key, address _data) external { + _isAuthorized(); + _setData(_key, _data, true); } - function insertBool(bytes32 _key, bool _data) external onlyAuthorized { - _insertData(_key, _data); + function insertBool(bytes32 _key, bool _data) external { + _isAuthorized(); + _setData(_key, _data, true); } /** @@ -127,19 +139,23 @@ contract DataStore is DataStoreStorage, IDataStore { * @param _key Unique key to identify the array * @param _index Index of the element to delete */ - function deleteUint256(bytes32 _key, uint256 _index) external onlyAuthorized { + function deleteUint256(bytes32 _key, uint256 _index) external { + _isAuthorized(); _deleteUint(_key, _index); } - function deleteBytes32(bytes32 _key, uint256 _index) external onlyAuthorized { + function deleteBytes32(bytes32 _key, uint256 _index) external { + _isAuthorized(); _deleteBytes32(_key, _index); } - function deleteAddress(bytes32 _key, uint256 _index) external onlyAuthorized { + function deleteAddress(bytes32 _key, uint256 _index) external { + _isAuthorized(); _deleteAddress(_key, _index); } - function deleteBool(bytes32 _key, uint256 _index) external onlyAuthorized { + function deleteBool(bytes32 _key, uint256 _index) external { + _isAuthorized(); _deleteBool(_key, _index); } @@ -148,27 +164,31 @@ contract DataStore is DataStoreStorage, IDataStore { * @param _keys Array of keys to identify the data * @param _data Array of data to be stored against the respective keys */ - function setUint256Multi(bytes32[] calldata _keys, uint256[] calldata _data) external onlyAuthorized validArrayLength(_keys.length, _data.length) { + function setUint256Multi(bytes32[] calldata _keys, uint256[] calldata _data) external validArrayLength(_keys.length, _data.length) { + _isAuthorized(); for (uint256 i = 0; i < _keys.length; i++) { - _setData(_keys[i], _data[i]); + _setData(_keys[i], _data[i], false); } } - function setBytes32Multi(bytes32[] calldata _keys, bytes32[] calldata _data) external onlyAuthorized validArrayLength(_keys.length, _data.length) { + function setBytes32Multi(bytes32[] calldata _keys, bytes32[] calldata _data) external validArrayLength(_keys.length, _data.length) { + _isAuthorized(); for (uint256 i = 0; i < _keys.length; i++) { - _setData(_keys[i], _data[i]); + _setData(_keys[i], _data[i], false); } } - function setAddressMulti(bytes32[] calldata _keys, address[] calldata _data) external onlyAuthorized validArrayLength(_keys.length, _data.length) { + function setAddressMulti(bytes32[] calldata _keys, address[] calldata _data) external validArrayLength(_keys.length, _data.length) { + _isAuthorized(); for (uint256 i = 0; i < _keys.length; i++) { - _setData(_keys[i], _data[i]); + _setData(_keys[i], _data[i], false); } } - function setBoolMulti(bytes32[] calldata _keys, bool[] calldata _data) external onlyAuthorized validArrayLength(_keys.length, _data.length) { + function setBoolMulti(bytes32[] calldata _keys, bool[] calldata _data) external validArrayLength(_keys.length, _data.length) { + _isAuthorized(); for (uint256 i = 0; i < _keys.length; i++) { - _setData(_keys[i], _data[i]); + _setData(_keys[i], _data[i], false); } } @@ -177,27 +197,31 @@ contract DataStore is DataStoreStorage, IDataStore { * @param _keys Array of keys to identify the data * @param _data Array of data to be inserted in arrays of the respective keys */ - function insertUint256Multi(bytes32[] calldata _keys, uint256[] calldata _data) external onlyAuthorized validArrayLength(_keys.length, _data.length) { + function insertUint256Multi(bytes32[] calldata _keys, uint256[] calldata _data) external validArrayLength(_keys.length, _data.length) { + _isAuthorized(); for (uint256 i = 0; i < _keys.length; i++) { - _insertData(_keys[i], _data[i]); + _setData(_keys[i], _data[i], true); } } - function insertBytes32Multi(bytes32[] calldata _keys, bytes32[] calldata _data) external onlyAuthorized validArrayLength(_keys.length, _data.length) { + function insertBytes32Multi(bytes32[] calldata _keys, bytes32[] calldata _data) external validArrayLength(_keys.length, _data.length) { + _isAuthorized(); for (uint256 i = 0; i < _keys.length; i++) { - _insertData(_keys[i], _data[i]); + _setData(_keys[i], _data[i], true); } } - function insertAddressMulti(bytes32[] calldata _keys, address[] calldata _data) external onlyAuthorized validArrayLength(_keys.length, _data.length) { + function insertAddressMulti(bytes32[] calldata _keys, address[] calldata _data) external validArrayLength(_keys.length, _data.length) { + _isAuthorized(); for (uint256 i = 0; i < _keys.length; i++) { - _insertData(_keys[i], _data[i]); + _setData(_keys[i], _data[i], true); } } - function insertBoolMulti(bytes32[] calldata _keys, bool[] calldata _data) external onlyAuthorized validArrayLength(_keys.length, _data.length) { + function insertBoolMulti(bytes32[] calldata _keys, bool[] calldata _data) external validArrayLength(_keys.length, _data.length) { + _isAuthorized(); for (uint256 i = 0; i < _keys.length; i++) { - _insertData(_keys[i], _data[i]); + _setData(_keys[i], _data[i], true); } } @@ -273,16 +297,60 @@ contract DataStore is DataStoreStorage, IDataStore { return boolArrayData[_key][_index]; } - function _setData(bytes32 _key, uint256 _data) internal validKey(_key) { - uintData[_key] = _data; + function getUint256ArrayElements(bytes32 _key, uint256 _startIndex, uint256 _endIndex) external view returns(uint256[] memory array) { + uint256 size = _endIndex - _startIndex + 1; + array = new uint256[](size); + for(uint256 i; i < size; i++) + array[i] = uintArrayData[_key][i + _startIndex]; + } + + function getBytes32ArrayElements(bytes32 _key, uint256 _startIndex, uint256 _endIndex) external view returns(bytes32[] memory array) { + uint256 size = _endIndex - _startIndex + 1; + array = new bytes32[](size); + for(uint256 i; i < size; i++) + array[i] = bytes32ArrayData[_key][i + _startIndex]; + } + + function getAddressArrayElements(bytes32 _key, uint256 _startIndex, uint256 _endIndex) external view returns(address[] memory array) { + uint256 size = _endIndex - _startIndex + 1; + array = new address[](size); + for(uint256 i; i < size; i++) + array[i] = addressArrayData[_key][i + _startIndex]; + } + + function getBoolArrayElements(bytes32 _key, uint256 _startIndex, uint256 _endIndex) external view returns(bool[] memory array) { + uint256 size = _endIndex - _startIndex + 1; + array = new bool[](size); + for(uint256 i; i < size; i++) + array[i] = boolArrayData[_key][i + _startIndex]; + } + + function _setData(bytes32 _key, uint256 _data, bool _insert) internal validKey(_key) { + if (_insert) + uintArrayData[_key].push(_data); + else + uintData[_key] = _data; + } + + function _setData(bytes32 _key, bytes32 _data, bool _insert) internal validKey(_key) { + if (_insert) + bytes32ArrayData[_key].push(_data); + else + bytes32Data[_key] = _data; } - function _setData(bytes32 _key, bytes32 _data) internal validKey(_key) { - bytes32Data[_key] = _data; + function _setData(bytes32 _key, address _data, bool _insert) internal validKey(_key) { + if (_insert) + addressArrayData[_key].push(_data); + else + addressData[_key] = _data; } - function _setData(bytes32 _key, address _data) internal validKey(_key) { - addressData[_key] = _data; + function _setData(bytes32 _key, bool _data, bool _insert) internal validKey(_key) { + if (_insert) + boolArrayData[_key].push(_data); + else + boolData[_key] = _data; } function _setData(bytes32 _key, string memory _data) internal validKey(_key) { @@ -293,10 +361,6 @@ contract DataStore is DataStoreStorage, IDataStore { bytesData[_key] = _data; } - function _setData(bytes32 _key, bool _data) internal validKey(_key) { - boolData[_key] = _data; - } - function _setData(bytes32 _key, uint256[] memory _data) internal validKey(_key) { uintArrayData[_key] = _data; } @@ -313,51 +377,27 @@ contract DataStore is DataStoreStorage, IDataStore { boolArrayData[_key] = _data; } - function _insertData(bytes32 _key, uint256 _data) internal validKey(_key) { - uintArrayData[_key].push(_data); - } - - function _insertData(bytes32 _key, bytes32 _data) internal validKey(_key) { - bytes32ArrayData[_key].push(_data); - } - - function _insertData(bytes32 _key, address _data) internal validKey(_key) { - addressArrayData[_key].push(_data); - } - - function _insertData(bytes32 _key, bool _data) internal validKey(_key) { - boolArrayData[_key].push(_data); - } - function _deleteUint(bytes32 _key, uint256 _index) internal validKey(_key) { require(uintArrayData[_key].length > _index, "Invalid Index"); //Also prevents undeflow - if(uintArrayData[_key].length - 1 != _index) { - uintArrayData[_key][_index] = uintArrayData[_key][uintArrayData[_key].length - 1]; - } + uintArrayData[_key][_index] = uintArrayData[_key][uintArrayData[_key].length - 1]; uintArrayData[_key].length--; } function _deleteBytes32(bytes32 _key, uint256 _index) internal validKey(_key) { require(bytes32ArrayData[_key].length > _index, "Invalid Index"); //Also prevents undeflow - if(bytes32ArrayData[_key].length - 1 != _index) { - bytes32ArrayData[_key][_index] = bytes32ArrayData[_key][bytes32ArrayData[_key].length - 1]; - } + bytes32ArrayData[_key][_index] = bytes32ArrayData[_key][bytes32ArrayData[_key].length - 1]; bytes32ArrayData[_key].length--; } function _deleteAddress(bytes32 _key, uint256 _index) internal validKey(_key) { require(addressArrayData[_key].length > _index, "Invalid Index"); //Also prevents undeflow - if(addressArrayData[_key].length - 1 != _index) { - addressArrayData[_key][_index] = addressArrayData[_key][addressArrayData[_key].length - 1]; - } + addressArrayData[_key][_index] = addressArrayData[_key][addressArrayData[_key].length - 1]; addressArrayData[_key].length--; } function _deleteBool(bytes32 _key, uint256 _index) internal validKey(_key) { require(boolArrayData[_key].length > _index, "Invalid Index"); //Also prevents undeflow - if(boolArrayData[_key].length - 1 != _index) { - boolArrayData[_key][_index] = boolArrayData[_key][boolArrayData[_key].length - 1]; - } + boolArrayData[_key][_index] = boolArrayData[_key][boolArrayData[_key].length - 1]; boolArrayData[_key].length--; } } diff --git a/contracts/datastore/DataStoreStorage.sol b/contracts/datastore/DataStoreStorage.sol index 9d724f070..64423f39d 100644 --- a/contracts/datastore/DataStoreStorage.sol +++ b/contracts/datastore/DataStoreStorage.sol @@ -16,6 +16,6 @@ contract DataStoreStorage { mapping (bytes32 => address[]) internal addressArrayData; mapping (bytes32 => bool[]) internal boolArrayData; - uint8 constant DATA_KEY = 6; - bytes32 public constant MANAGEDATA = "MANAGEDATA"; + uint8 internal constant DATA_KEY = 6; + bytes32 internal constant MANAGEDATA = "MANAGEDATA"; } diff --git a/contracts/interfaces/IDataStore.sol b/contracts/interfaces/IDataStore.sol index bb1aa5aa4..33df6b934 100644 --- a/contracts/interfaces/IDataStore.sol +++ b/contracts/interfaces/IDataStore.sol @@ -125,4 +125,12 @@ interface IDataStore { function getAddressArrayElement(bytes32 _key, uint256 _index) external view returns(address); function getBoolArrayElement(bytes32 _key, uint256 _index) external view returns(bool); + + function getUint256ArrayElements(bytes32 _key, uint256 _startIndex, uint256 _endIndex) external view returns(uint256[] memory); + + function getBytes32ArrayElements(bytes32 _key, uint256 _startIndex, uint256 _endIndex) external view returns(bytes32[] memory); + + function getAddressArrayElements(bytes32 _key, uint256 _startIndex, uint256 _endIndex) external view returns(address[] memory); + + function getBoolArrayElements(bytes32 _key, uint256 _startIndex, uint256 _endIndex) external view returns(bool[] memory); } diff --git a/contracts/interfaces/ISecurityToken.sol b/contracts/interfaces/ISecurityToken.sol index c1671db53..af0fb6a0c 100644 --- a/contracts/interfaces/ISecurityToken.sol +++ b/contracts/interfaces/ISecurityToken.sol @@ -316,6 +316,11 @@ interface ISecurityToken { */ function getInvestorCount() external view returns(uint256); + /** + * @notice Gets the holder count (investors with non zero balance) + */ + function holderCount() external view returns(uint256); + /** * @notice Overloaded version of the transfer function * @param _to receiver of transfer diff --git a/contracts/libraries/TokenLib.sol b/contracts/libraries/TokenLib.sol index 239c57941..bbbf78bb9 100644 --- a/contracts/libraries/TokenLib.sol +++ b/contracts/libraries/TokenLib.sol @@ -2,10 +2,14 @@ pragma solidity ^0.5.0; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "../interfaces/IPoly.sol"; +import "../interfaces/IDataStore.sol"; library TokenLib { using SafeMath for uint256; + bytes32 internal constant WHITELIST = "WHITELIST"; + bytes32 internal constant INVESTORSKEY = 0xdf3a8dd24acdd05addfc6aeffef7574d2de3f844535ec91e8e0f3e45dba96731; //keccak256(abi.encodePacked("INVESTORS")) + // Struct for module data struct ModuleData { bytes32 name; @@ -24,15 +28,6 @@ library TokenLib { uint256 value; } - struct InvestorDataStorage { - // List of investors who have ever held a non-zero token balance - mapping(address => bool) investorListed; - // List of token holders - address[] investors; - // Total number of non-zero token holders - uint256 investorCount; - } - // Emit when Module is archived from the SecurityToken event ModuleArchived(uint8[] _types, address _module); // Emit when Module is unarchived from the SecurityToken @@ -217,40 +212,54 @@ library TokenLib { /** * @notice Keeps track of the number of non-zero token holders - * @param _investorData Date releated to investor metrics + * @param _holderCount Number of current token holders * @param _from Sender of transfer * @param _to Receiver of transfer * @param _value Value of transfer * @param _balanceTo Balance of the _to address * @param _balanceFrom Balance of the _from address + * @param _dataStore address of data store */ function adjustInvestorCount( - InvestorDataStorage storage _investorData, + uint256 _holderCount, address _from, address _to, uint256 _value, uint256 _balanceTo, - uint256 _balanceFrom + uint256 _balanceFrom, + address _dataStore ) public + returns(uint256) { if ((_value == 0) || (_from == _to)) { - return; + return _holderCount; } // Check whether receiver is a new token holder if ((_balanceTo == 0) && (_to != address(0))) { - _investorData.investorCount = (_investorData.investorCount).add(1); + _holderCount = _holderCount.add(1); + IDataStore dataStore = IDataStore(_dataStore); + if (!_isExistingInvestor(_to, dataStore)) { + dataStore.insertAddress(INVESTORSKEY, _to); + //KYC data can not be present if added is false and hence we can set packed KYC as uint256(1) to set added as true + dataStore.setUint256(_getKey(WHITELIST, _to), uint256(1)); + } } // Check whether sender is moving all of their tokens if (_value == _balanceFrom) { - _investorData.investorCount = (_investorData.investorCount).sub(1); - } - //Also adjust investor list - if (!_investorData.investorListed[_to] && (_to != address(0))) { - _investorData.investors.push(_to); - _investorData.investorListed[_to] = true; + _holderCount = _holderCount.sub(1); } + return _holderCount; + } + + function _getKey(bytes32 _key1, address _key2) internal pure returns(bytes32) { + return bytes32(keccak256(abi.encodePacked(_key1, _key2))); } + function _isExistingInvestor(address _investor, IDataStore dataStore) internal view returns(bool) { + uint256 data = dataStore.getUint256(_getKey(WHITELIST, _investor)); + //extracts `added` from packed `whitelistData` + return uint8(data) == 0 ? false : true; + } } diff --git a/contracts/libraries/VersionUtils.sol b/contracts/libraries/VersionUtils.sol index 8375cde68..e878389bb 100644 --- a/contracts/libraries/VersionUtils.sol +++ b/contracts/libraries/VersionUtils.sol @@ -110,21 +110,22 @@ library VersionUtils { /** * @notice Used to packed the KYC data */ - function packKYC(uint64 _a, uint64 _b, uint64 _c, uint8 _d, uint8 _e, uint8 _f) internal pure returns(uint256) { - return (uint256(_a) << 152) | (uint256(_b) << 88) | (uint256(_c) << 24) | (uint256(_d) << 16) | (uint256(_e) << 8) | uint256(_f); + function packKYC(uint64 _a, uint64 _b, uint64 _c, uint8 _d) internal pure returns(uint256) { + // this function packs 3 uint64 and a uint8 together in a uint256 to save storage cost + // a is rotated left by 136 bits, b is rotated left by 72 bits and c is rotated left by 8 bits. + // rotation pads empty bits with zeroes so now we can safely do a bitwise OR operation to pack + // all the variables together. + return (uint256(_a) << 136) | (uint256(_b) << 72) | (uint256(_c) << 8) | uint256(_d); } /** * @notice Used to convert packed data into KYC data * @param _packedVersion Packed data */ - function unpackKYC(uint256 _packedVersion) internal pure returns(uint64 fromTime, uint64 toTime, uint64 expiryTime, uint8 canBuy, uint8 added, uint8 accredited) { - fromTime = uint64(_packedVersion >> 152); - toTime = uint64(_packedVersion >> 88); - expiryTime = uint64(_packedVersion >> 24); - canBuy = uint8(_packedVersion >> 16); - added = uint8(_packedVersion >> 8); - accredited = uint8(_packedVersion); + function unpackKYC(uint256 _packedVersion) internal pure returns(uint64 fromTime, uint64 toTime, uint64 expiryTime, uint8 added) { + fromTime = uint64(_packedVersion >> 136); + toTime = uint64(_packedVersion >> 72); + expiryTime = uint64(_packedVersion >> 8); + added = uint8(_packedVersion); } - } diff --git a/contracts/modules/STO/CappedSTO.sol b/contracts/modules/STO/CappedSTO.sol index 8286da28f..4cec5d9c9 100644 --- a/contracts/modules/STO/CappedSTO.sol +++ b/contracts/modules/STO/CappedSTO.sol @@ -208,10 +208,10 @@ contract CappedSTO is CappedSTOStorage, STO, ReentrancyGuard { Observe state and use revert statements to undo rollback when valid conditions are not met. */ function _postValidatePurchase( - address, /*_beneficiary*/ + address _beneficiary, uint256 /*_investedAmount*/ - ) internal pure { - // optional override + ) internal view { + require(_canBuy(_beneficiary), "Unauthorized"); } /** diff --git a/contracts/modules/STO/DummySTO.sol b/contracts/modules/STO/DummySTO.sol index 8b1a9101d..f562be892 100644 --- a/contracts/modules/STO/DummySTO.sol +++ b/contracts/modules/STO/DummySTO.sol @@ -47,6 +47,7 @@ contract DummySTO is DummySTOStorage, STO { function generateTokens(address _investor, uint256 _amount) public withPerm(ADMIN) { require(!paused, "Should not be paused"); require(_amount > 0, "Amount should be greater than 0"); + require(_canBuy(_investor), "Unauthorized"); ISecurityToken(securityToken).mint(_investor, _amount); if (investors[_investor] == 0) { investorCount = investorCount + 1; diff --git a/contracts/modules/STO/PreSaleSTO.sol b/contracts/modules/STO/PreSaleSTO.sol index 824b808fc..98fd033f3 100644 --- a/contracts/modules/STO/PreSaleSTO.sol +++ b/contracts/modules/STO/PreSaleSTO.sol @@ -71,13 +71,14 @@ contract PreSaleSTO is PreSaleSTOStorage, STO { uint256 _amount, uint256 _etherContributed, uint256 _polyContributed - ) - public - withPerm(PRE_SALE_ADMIN) + ) + public + withPerm(PRE_SALE_ADMIN) { /*solium-disable-next-line security/no-block-members*/ require(now <= endTime, "Already passed Endtime"); require(_amount > 0, "No. of tokens provided should be greater the zero"); + require(_canBuy(_investor), "Unauthorized"); ISecurityToken(securityToken).mint(_investor, _amount); if (investors[_investor] == uint256(0)) { investorCount = investorCount.add(1); @@ -101,9 +102,9 @@ contract PreSaleSTO is PreSaleSTOStorage, STO { uint256[] memory _amounts, uint256[] memory _etherContributed, uint256[] memory _polyContributed - ) - public - withPerm(PRE_SALE_ADMIN) + ) + public + withPerm(PRE_SALE_ADMIN) { require(_investors.length == _amounts.length, "Mis-match in length of the arrays"); require(_etherContributed.length == _polyContributed.length, "Mis-match in length of the arrays"); diff --git a/contracts/modules/STO/STO.sol b/contracts/modules/STO/STO.sol index d3f28c5fd..ae69238fd 100644 --- a/contracts/modules/STO/STO.sol +++ b/contracts/modules/STO/STO.sol @@ -70,4 +70,13 @@ contract STO is ISTO, STOStorage, Module, Pausable { emit SetFundRaiseTypes(_fundRaiseTypes); } + function _canBuy(address _investor) internal view returns(bool) { + IDataStore dataStore = IDataStore(getDataStore()); + uint256 flags = dataStore.getUint256(_getKey(INVESTORFLAGS, _investor)); + return(flags & (uint256(1) << 1) == 0); + } + + function _getKey(bytes32 _key1, address _key2) internal pure returns(bytes32) { + return bytes32(keccak256(abi.encodePacked(_key1, _key2))); + } } diff --git a/contracts/modules/STO/STOStorage.sol b/contracts/modules/STO/STOStorage.sol index 96793d6d5..87ae2c3e0 100644 --- a/contracts/modules/STO/STOStorage.sol +++ b/contracts/modules/STO/STOStorage.sol @@ -5,6 +5,7 @@ pragma solidity ^0.5.0; */ contract STOStorage { + bytes32 internal constant INVESTORFLAGS = "INVESTORFLAGS"; mapping (uint8 => bool) public fundRaiseTypes; mapping (uint8 => uint256) public fundsRaised; diff --git a/contracts/modules/STO/USDTieredSTO.sol b/contracts/modules/STO/USDTieredSTO.sol index 18231229c..6de21c48d 100644 --- a/contracts/modules/STO/USDTieredSTO.sol +++ b/contracts/modules/STO/USDTieredSTO.sol @@ -199,7 +199,7 @@ contract USDTieredSTO is USDTieredSTOStorage, STO { internal { require( - _tokensPerTierTotal.length > 0 && + _tokensPerTierTotal.length > 0 && _ratePerTier.length == _tokensPerTierTotal.length && _ratePerTierDiscountPoly.length == _tokensPerTierTotal.length && _tokensPerTierDiscountPoly.length == _tokensPerTierTotal.length, @@ -272,24 +272,6 @@ contract USDTieredSTO is USDTieredSTOStorage, STO { totalTokensSold = tempSold; } - /** - * @notice Modifies the list of accredited addresses - * @param _investors Array of investor addresses to modify - * @param _accredited Array of bools specifying accreditation status - */ - function changeAccredited(address[] memory _investors, bool[] memory _accredited) public onlyOwner { - require(_investors.length == _accredited.length, "Array length mismatch"); - for (uint256 i = 0; i < _investors.length; i++) { - if (_accredited[i]) { - investors[_investors[i]].accredited = uint8(1); - } else { - investors[_investors[i]].accredited = uint8(0); - } - _addToInvestorsList(_investors[i]); - emit SetAccredited(_investors[i], _accredited[i]); - } - } - /** * @notice Modifies the list of overrides for non-accredited limits in USD * @param _investors Array of investor addresses to modify @@ -299,34 +281,26 @@ contract USDTieredSTO is USDTieredSTOStorage, STO { //nonAccreditedLimitUSDOverride require(_investors.length == _nonAccreditedLimit.length, "Array length mismatch"); for (uint256 i = 0; i < _investors.length; i++) { - investors[_investors[i]].nonAccreditedLimitUSDOverride = _nonAccreditedLimit[i]; - _addToInvestorsList(_investors[i]); + nonAccreditedLimitUSDOverride[_investors[i]] = _nonAccreditedLimit[i]; emit SetNonAccreditedLimit(_investors[i], _nonAccreditedLimit[i]); } } - function _addToInvestorsList(address _investor) internal { - if (investors[_investor].seen == uint8(0)) { - investors[_investor].seen = uint8(1); - investorsList.push(_investor); - } - } - /** * @notice Returns investor accredited & non-accredited override informatiomn - * @return address[] list of all configured investors - * @return bool[] whether investor is accredited - * @return uint256[] any USD overrides for non-accredited limits for the investor + * @return investors list of all configured investors + * @return accredited whether investor is accredited + * @return override any USD overrides for non-accredited limits for the investor */ - function getAccreditedData() external view returns (address[] memory, bool[] memory, uint256[] memory) { - bool[] memory accrediteds = new bool[](investorsList.length); - uint256[] memory nonAccreditedLimitUSDOverrides = new uint256[](investorsList.length); - uint256 i; - for (i = 0; i < investorsList.length; i++) { - accrediteds[i] = (investors[investorsList[i]].accredited == uint8(0)? false: true); - nonAccreditedLimitUSDOverrides[i] = investors[investorsList[i]].nonAccreditedLimitUSDOverride; + function getAccreditedData() external view returns (address[] memory investors, bool[] memory accredited, uint256[] memory overrides) { + IDataStore dataStore = IDataStore(getDataStore()); + investors = dataStore.getAddressArray(INVESTORSKEY); + accredited = new bool[](investors.length); + overrides = new uint256[](investors.length); + for (uint256 i = 0; i < investors.length; i++) { + accredited[i] = _getIsAccredited(investors[i], dataStore); + overrides[i] = nonAccreditedLimitUSDOverride[investors[i]]; } - return (investorsList, accrediteds, nonAccreditedLimitUSDOverrides); } /** @@ -443,6 +417,8 @@ contract USDTieredSTO is USDTieredSTOStorage, STO { require(_beneficiary == msg.sender, "Beneficiary != funder"); } + require(_canBuy(_beneficiary), "Unauthorized"); + uint256 originalUSD = DecimalMath.mul(_rate, _investmentValue); uint256 allowedUSD = _buyTokensChecks(_beneficiary, _investmentValue, originalUSD); @@ -489,8 +465,8 @@ contract USDTieredSTO is USDTieredSTOStorage, STO { require(investedUSD.add(investorInvestedUSD[_beneficiary]) >= minimumInvestmentUSD, "Investment < min"); netInvestedUSD = investedUSD; // Check for non-accredited cap - if (investors[_beneficiary].accredited == uint8(0)) { - uint256 investorLimitUSD = (investors[_beneficiary].nonAccreditedLimitUSDOverride == 0) ? nonAccreditedLimitUSD : investors[_beneficiary].nonAccreditedLimitUSDOverride; + if (!_isAccredited(_beneficiary)) { + uint256 investorLimitUSD = (nonAccreditedLimitUSDOverride[_beneficiary] == 0) ? nonAccreditedLimitUSD : nonAccreditedLimitUSDOverride[_beneficiary]; require(investorInvestedUSD[_beneficiary] < investorLimitUSD, "Over Non-accredited investor limit"); if (investedUSD.add(investorInvestedUSD[_beneficiary]) > investorLimitUSD) netInvestedUSD = investorLimitUSD.sub(investorInvestedUSD[_beneficiary]); @@ -568,6 +544,17 @@ contract USDTieredSTO is USDTieredSTOStorage, STO { } } + function _isAccredited(address _investor) internal view returns(bool) { + IDataStore dataStore = IDataStore(getDataStore()); + return _getIsAccredited(_investor, dataStore); + } + + function _getIsAccredited(address _investor, IDataStore dataStore) internal view returns(bool) { + uint256 flags = dataStore.getUint256(_getKey(INVESTORFLAGS, _investor)); + uint256 flag = flags & uint256(1); //isAccredited is flag 0 so we don't need to bit shift flags. + return flag > 0 ? true : false; + } + ///////////// // Getters // ///////////// @@ -577,7 +564,7 @@ contract USDTieredSTO is USDTieredSTOStorage, STO { * @return bool Whether the STO is accepting investments */ function isOpen() public view returns(bool) { - /*solium-disable-next-line security/no-block-members*/ + /*solium-disable-next-line security/no-block-members*/ if (isFinalized || now < startTime || now >= endTime || capReached()) return false; return true; diff --git a/contracts/modules/TransferManager/CountTransferManager.sol b/contracts/modules/TransferManager/CountTransferManager.sol index b598505f0..381584389 100644 --- a/contracts/modules/TransferManager/CountTransferManager.sol +++ b/contracts/modules/TransferManager/CountTransferManager.sol @@ -34,7 +34,7 @@ contract CountTransferManager is CountTransferManagerStorage, TransferManager { returns(Result) { if (!paused) { - if (maxHolderCount < ISecurityToken(securityToken).getInvestorCount()) { + if (maxHolderCount < ISecurityToken(securityToken).holderCount()) { // Allow transfers to existing maxHolders if (ISecurityToken(securityToken).balanceOf(_to) != 0 || ISecurityToken(securityToken).balanceOf(_from) == _amount) { return Result.NA; diff --git a/contracts/modules/TransferManager/GeneralTransferManager.sol b/contracts/modules/TransferManager/GeneralTransferManager.sol index 0139291ef..981830437 100644 --- a/contracts/modules/TransferManager/GeneralTransferManager.sol +++ b/contracts/modules/TransferManager/GeneralTransferManager.sol @@ -34,15 +34,19 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage // 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( + event ModifyKYCData( address indexed _investor, uint256 _dateAdded, address indexed _addedBy, uint256 _fromTime, uint256 _toTime, - uint256 _expiryTime, - bool _canBuyFromSTO, - bool _isAccredited + uint256 _expiryTime + ); + + event ModifyInvestorFlag( + address indexed _investor, + uint8 indexed _flag, + bool _value ); /** @@ -158,7 +162,6 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage uint64 fromExpiry; uint64 toExpiry; uint64 toTime; - uint8 canBuyFromSTO; if (allowAllTransfers) { //All transfers allowed, regardless of whitelist return Result.VALID; @@ -167,7 +170,7 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage return Result.VALID; } - (fromTime, fromExpiry, canBuyFromSTO, toTime, toExpiry) = _getValuesForTransfer(_from, _to); + (fromTime, fromExpiry, toTime, toExpiry) = _getValuesForTransfer(_from, _to); if (allowAllWhitelistTransfers) { //Anyone on the whitelist can transfer, regardless of time @@ -176,10 +179,6 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage // Using the local variables to avoid the stack too deep error (fromTime, toTime) = _adjustTimes(fromTime, toTime); if (_from == issuanceAddress) { - // Possible STO transaction, but investor not allowed to purchased from STO - if ((canBuyFromSTO == uint8(0)) && _isSTOAttached()) { - return Result.NA; - } // if allowAllWhitelistIssuances is true, so time stamp ignored if (allowAllWhitelistIssuances) { return _validExpiry(toExpiry) ? Result.VALID : Result.NA; @@ -197,84 +196,120 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage } /** - * @notice Adds or removes addresses from the whitelist. + * @notice Add or remove KYC info of an investor. * @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. - * @param _isAccredited is used to differentiate whether the investor is Accredited or not. */ - function modifyWhitelist( + function modifyKYCData( address _investor, uint256 _fromTime, uint256 _toTime, - uint256 _expiryTime, - bool _canBuyFromSTO, - bool _isAccredited + uint256 _expiryTime ) public withPerm(WHITELIST) { - _modifyWhitelist(_investor, _fromTime, _toTime, _expiryTime, _canBuyFromSTO, _isAccredited); + _modifyKYCData(_investor, _fromTime, _toTime, _expiryTime); + } + + function _modifyKYCData(address _investor, uint256 _fromTime, uint256 _toTime, uint256 _expiryTime) internal { + require(_investor != address(0), "Invalid investor"); + IDataStore dataStore = IDataStore(getDataStore()); + if (!_isExistingInvestor(_investor, dataStore)) { + dataStore.insertAddress(INVESTORSKEY, _investor); + } + uint256 _data = VersionUtils.packKYC(uint64(_fromTime), uint64(_toTime), uint64(_expiryTime), uint8(1)); + dataStore.setUint256(_getKey(WHITELIST, _investor), _data); + emit ModifyKYCData(_investor, now, msg.sender, _fromTime, _toTime, _expiryTime); } /** - * @notice Adds or removes addresses from the whitelist. - * @param _investor is the address to whitelist + * @notice Add or remove KYC info of an investor. + * @param _investors 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. - * @param _isAccredited is used to differentiate whether the investor is Accredited or not. */ - function _modifyWhitelist(address _investor, uint256 _fromTime, uint256 _toTime, uint256 _expiryTime, bool _canBuyFromSTO, bool _isAccredited) internal { + function modifyKYCDataMulti( + address[] memory _investors, + uint256[] memory _fromTime, + uint256[] memory _toTime, + uint256[] memory _expiryTime + ) + public + withPerm(WHITELIST) + { + require( + _investors.length == _fromTime.length && + _fromTime.length == _toTime.length && + _toTime.length == _expiryTime.length, + "Mismatched input lengths" + ); + for (uint256 i = 0; i < _investors.length; i++) { + _modifyKYCData(_investors[i], _fromTime[i], _toTime[i], _expiryTime[i]); + } + } + + /** + * @notice Used to modify investor Flag. + * @dev Flags are properties about investors that can be true or false like isAccredited + * @param _investor is the address of the investor. + * @param _flag index of flag to change. flag is used to know specifics about investor like isAccredited. + * @param _value value of the flag. a flag can be true or false. + */ + function modifyInvestorFlag( + address _investor, + uint8 _flag, + bool _value + ) + public + withPerm(WHITELIST) + { + _modifyInvestorFlag(_investor, _flag, _value); + } + + + function _modifyInvestorFlag(address _investor, uint8 _flag, bool _value) internal { require(_investor != address(0), "Invalid investor"); - uint8 added; - uint8 canBuyFromSTO; - uint8 isAccredited; IDataStore dataStore = IDataStore(getDataStore()); - added = _getAddedValue(_investor, dataStore); - if (added == uint8(0)) { - investors.push(_investor); + if (!_isExistingInvestor(_investor, dataStore)) { + dataStore.insertAddress(INVESTORSKEY, _investor); + //KYC data can not be present if added is false and hence we can set packed KYC as uint256(1) to set added as true + dataStore.setUint256(_getKey(WHITELIST, _investor), uint256(1)); } - canBuyFromSTO = _canBuyFromSTO ? 1 : 0; - isAccredited = _isAccredited ? 1 : 0; - uint256 _data = VersionUtils.packKYC(uint64(_fromTime), uint64(_toTime), uint64(_expiryTime), canBuyFromSTO, uint8(1), isAccredited); - dataStore.setUint256(_getKey(WHITELIST, _investor), _data); - emit ModifyWhitelist(_investor, now, msg.sender, _fromTime, _toTime, _expiryTime, _canBuyFromSTO, _isAccredited); + //NB Flags are packed together in a uint256 to save gas. We can have a maximum of 256 flags. + uint256 flags = dataStore.getUint256(_getKey(INVESTORFLAGS, _investor)); + if (_value) + flags = flags | (ONE << _flag); + else + flags = flags & ~(ONE << _flag); + dataStore.setUint256(_getKey(INVESTORFLAGS, _investor), flags); + emit ModifyInvestorFlag(_investor, _flag, _value); } /** - * @notice Adds or removes addresses from the whitelist. - * @param _investors List of the addresses to whitelist - * @param _fromTimes An array of the moment when the sale lockup period ends and the investor can freely sell his tokens - * @param _toTimes An array of the moment when the purchase lockup period ends and the investor can freely purchase tokens from others - * @param _expiryTimes An array of the moment till investors KYC will be validated. After that investor need to do re-KYC - * @param _canBuyFromSTO An array of boolean values. - * @param _isAccredited An array of boolean values to differentiate whether the investor is Accredited or not. + * @notice Used to modify investor data. + * @param _investors List of the addresses to modify data about. + * @param _flag index of flag to change. flag is used to know specifics about investor like isAccredited. + * @param _value value of the flag. a flag can be true or false. */ - function modifyWhitelistMulti( + function modifyInvestorFlagMulti( address[] memory _investors, - uint256[] memory _fromTimes, - uint256[] memory _toTimes, - uint256[] memory _expiryTimes, - bool[] memory _canBuyFromSTO, - bool[] memory _isAccredited + uint8[] memory _flag, + bool[] memory _value ) public withPerm(WHITELIST) { require( - _investors.length == _fromTimes.length && - _fromTimes.length == _toTimes.length && - _toTimes.length == _expiryTimes.length && - _canBuyFromSTO.length == _toTimes.length && - _canBuyFromSTO.length == _isAccredited.length, + _investors.length == _flag.length && + _flag.length == _value.length, "Mismatched input lengths" ); for (uint256 i = 0; i < _investors.length; i++) { - _modifyWhitelist(_investors[i], _fromTimes[i], _toTimes[i], _expiryTimes[i], _canBuyFromSTO[i], _isAccredited[i]); + _modifyInvestorFlag(_investors[i], _flag[i], _value[i]); } } @@ -284,20 +319,16 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage * @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. - * @param _isAccredited is used to differentiate whether the investor is Accredited or not. * @param _validFrom is the time that this signature is valid from * @param _validTo is the time that this signature is valid until * @param _nonce nonce of signature (avoid replay attack) * @param _signature issuer signature */ - function modifyWhitelistSigned( + function modifyKYCDataSigned( address _investor, uint256 _fromTime, uint256 _toTime, uint256 _expiryTime, - bool _canBuyFromSTO, - bool _isAccredited, uint256 _validFrom, uint256 _validTo, uint256 _nonce, @@ -312,10 +343,10 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage require(!nonceMap[_investor][_nonce], "Already used signature"); nonceMap[_investor][_nonce] = true; bytes32 hash = keccak256( - abi.encodePacked(this, _investor, _fromTime, _toTime, _expiryTime, _canBuyFromSTO, _isAccredited, _validFrom, _validTo, _nonce) + abi.encodePacked(this, _investor, _fromTime, _toTime, _expiryTime, _validFrom, _validTo, _nonce) ); _checkSig(hash, _signature); - _modifyWhitelist(_investor, _fromTime, _toTime, _expiryTime, _canBuyFromSTO, _isAccredited); + _modifyKYCData(_investor, _fromTime, _toTime, _expiryTime); } /** @@ -344,14 +375,6 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage return (_lockTime <= uint64(now)); /*solium-disable-line security/no-block-members*/ } - /** - * @notice Internal function use to know whether the STO is attached or not - */ - function _isSTOAttached() internal view returns(bool) { - bool attached = ISecurityToken(securityToken).getModulesByType(3).length > 0; - return attached; - } - /** * @notice Internal function to adjust times using default values */ @@ -371,87 +394,104 @@ contract GeneralTransferManager is GeneralTransferManagerStorage, TransferManage return bytes32(keccak256(abi.encodePacked(_key1, _key2))); } - function _getValues(address _investor, IDataStore dataStore) internal view returns( + function _getKYCValues(address _investor, IDataStore dataStore) internal view returns( uint64 fromTime, uint64 toTime, uint64 expiryTime, - uint8 canBuyFromSTO, - uint8 added, - uint8 isAccredited + uint8 added ) { - uint256 _whitelistData = dataStore.getUint256(_getKey(WHITELIST, _investor)); - (fromTime, toTime, expiryTime, canBuyFromSTO, added, isAccredited) = VersionUtils.unpackKYC(_whitelistData); + uint256 data = dataStore.getUint256(_getKey(WHITELIST, _investor)); + (fromTime, toTime, expiryTime, added) = VersionUtils.unpackKYC(data); } - function _getAddedValue(address _investor, IDataStore dataStore) internal view returns(uint8) { - uint256 _whitelistData = dataStore.getUint256(_getKey(WHITELIST, _investor)); + function _isExistingInvestor(address _investor, IDataStore dataStore) internal view returns(bool) { + uint256 data = dataStore.getUint256(_getKey(WHITELIST, _investor)); //extracts `added` from packed `_whitelistData` - return uint8(_whitelistData >> 8); + return uint8(data) == 0 ? false : true; } - function _getValuesForTransfer(address _from, address _to) internal view returns(uint64 fromTime, uint64 fromExpiry, uint8 canBuyFromSTO, uint64 toTime, uint64 toExpiry) { + function _getValuesForTransfer(address _from, address _to) internal view returns(uint64 fromTime, uint64 fromExpiry, uint64 toTime, uint64 toExpiry) { IDataStore dataStore = IDataStore(getDataStore()); - (fromTime,, fromExpiry,,,) = _getValues(_from, dataStore); - (, toTime, toExpiry, canBuyFromSTO,,) = _getValues(_to, dataStore); + (fromTime, , fromExpiry, ) = _getKYCValues(_from, dataStore); + (, toTime, toExpiry, ) = _getKYCValues(_to, dataStore); } /** * @dev Returns list of all investors */ - function getInvestors() public view returns(address[] memory) { - return investors; + function getAllInvestors() public view returns(address[] memory investors) { + IDataStore dataStore = IDataStore(getDataStore()); + investors = dataStore.getAddressArray(INVESTORSKEY); + } + + /** + * @dev Returns list of investors in a range + */ + function getInvestors(uint256 _fromIndex, uint256 _toIndex) public view returns(address[] memory investors) { + IDataStore dataStore = IDataStore(getDataStore()); + investors = dataStore.getAddressArrayElements(INVESTORSKEY, _fromIndex, _toIndex); + } + + function getAllInvestorFlags() public view returns(address[] memory investors, uint256[] memory flags) { + investors = getAllInvestors(); + flags = new uint256[](investors.length); + for (uint256 i = 0; i < investors.length; i++) { + flags[i] = _getInvestorFlags(investors[i]); + } + } + + function getInvestorFlag(address _investor, uint8 _flag) public view returns(bool value) { + uint256 flag = (_getInvestorFlags(_investor) >> _flag) & ONE; + value = flag > 0 ? true : false; + } + + function getInvestorFlags(address _investor) public view returns(uint256 flags) { + flags = _getInvestorFlags(_investor); + } + + function _getInvestorFlags(address _investor) public view returns(uint256 flags) { + IDataStore dataStore = IDataStore(getDataStore()); + flags = dataStore.getUint256(_getKey(INVESTORFLAGS, _investor)); } /** * @dev Returns list of all investors data */ - function getAllInvestorsData() external view returns( - address[] memory, + function getAllKYCData() external view returns( + address[] memory investors, uint256[] memory fromTimes, uint256[] memory toTimes, - uint256[] memory expiryTimes, - bool[] memory canBuyFromSTOs, - bool[] memory isAccrediteds + uint256[] memory expiryTimes ) { - (fromTimes, toTimes, expiryTimes, canBuyFromSTOs, isAccrediteds) = _investorsData(getInvestors()); - return (getInvestors(), fromTimes, toTimes, expiryTimes, canBuyFromSTOs, isAccrediteds); - + investors = getAllInvestors(); + (fromTimes, toTimes, expiryTimes) = _kycData(investors); + return (investors, fromTimes, toTimes, expiryTimes); } /** * @dev Returns list of specified investors data */ - function getInvestorsData(address[] calldata _investors) external view returns( - uint256[] memory, + function getKYCData(address[] calldata _investors) external view returns( uint256[] memory, uint256[] memory, - bool[] memory, - bool[] memory + uint256[] memory ) { - return _investorsData(_investors); + return _kycData(_investors); } - function _investorsData(address[] memory _investors) internal view returns( - uint256[] memory, + function _kycData(address[] memory _investors) internal view returns( uint256[] memory, uint256[] memory, - bool[] memory, - bool[] memory + uint256[] memory ) { 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); - bool[] memory isAccrediteds = new bool[](_investors.length); for (uint256 i = 0; i < _investors.length; i++) { - uint8 canBuyFromSTO; - uint8 isAccredited; - (fromTimes[i], toTimes[i], expiryTimes[i], canBuyFromSTO,,isAccredited) = _getValues(_investors[i], IDataStore(getDataStore())); - canBuyFromSTOs[i] = canBuyFromSTO == 0 ? false : true; - isAccrediteds[i] = isAccredited == 0 ? false : true; + (fromTimes[i], toTimes[i], expiryTimes[i], ) = _getKYCValues(_investors[i], IDataStore(getDataStore())); } - return (fromTimes, toTimes, expiryTimes, canBuyFromSTOs, isAccrediteds); + return (fromTimes, toTimes, expiryTimes); } /** diff --git a/contracts/storage/GeneralTransferManagerStorage.sol b/contracts/storage/GeneralTransferManagerStorage.sol index b481e31d5..f246b3675 100644 --- a/contracts/storage/GeneralTransferManagerStorage.sol +++ b/contracts/storage/GeneralTransferManagerStorage.sol @@ -6,28 +6,27 @@ pragma solidity ^0.5.0; contract GeneralTransferManagerStorage { bytes32 public constant WHITELIST = "WHITELIST"; + bytes32 public constant INVESTORSKEY = 0xdf3a8dd24acdd05addfc6aeffef7574d2de3f844535ec91e8e0f3e45dba96731; //keccak256(abi.encodePacked("INVESTORS")) + bytes32 public constant INVESTORFLAGS = "INVESTORFLAGS"; bytes32 public constant FLAGS = "FLAGS"; + uint256 internal constant ONE = uint256(1); //Address from which issuances come - address public issuanceAddress = address(0); + address public issuanceAddress; //Address which can sign whitelist changes - address public signingAddress = address(0); + address public signingAddress; -/* - //from and to timestamps that an investor can send / receive tokens respectively - struct TimeRestriction { - uint64 fromTime; - uint64 toTime; - uint64 expiryTime; - uint8 canBuyFromSTO; - uint8 added; - } - // An address can only send / receive tokens once their corresponding uint256 > block.number - // (unless allowAllTransfers == true or allowAllWhitelistTransfers == true) - mapping (address => TimeRestriction) public whitelist; -*/ + // //from and to timestamps that an investor can send / receive tokens respectively + // // Now Stored in DataStore + // struct TimeRestriction { + // uint64 fromTime; + // uint64 toTime; + // uint64 expiryTime; + // uint8 added; + // } + // Allows all TimeRestrictions to be offset struct Defaults { uint64 fromTime; @@ -37,9 +36,6 @@ contract GeneralTransferManagerStorage { // Offset to be applied to all timings (except KYC expiry) Defaults public defaults; - // List of all addresses that have been added to the GTM at some point - address[] public investors; - // Map of used nonces by customer mapping(address => mapping(uint256 => bool)) public nonceMap; @@ -51,5 +47,5 @@ contract GeneralTransferManagerStorage { bool public allowAllWhitelistIssuances = true; //If true, time lock is ignored for burn transactions bool public allowAllBurnTransfers = false; - + } diff --git a/contracts/storage/USDTieredSTOStorage.sol b/contracts/storage/USDTieredSTOStorage.sol index 267df4f58..4e37c6dd1 100644 --- a/contracts/storage/USDTieredSTOStorage.sol +++ b/contracts/storage/USDTieredSTOStorage.sol @@ -6,6 +6,9 @@ import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; * @title Contract used to store layout for the USDTieredSTO storage */ contract USDTieredSTOStorage { + + bytes32 internal constant INVESTORSKEY = 0xdf3a8dd24acdd05addfc6aeffef7574d2de3f844535ec91e8e0f3e45dba96731; //keccak256(abi.encodePacked("INVESTORS")) + ///////////// // Storage // ///////////// @@ -27,14 +30,7 @@ contract USDTieredSTOStorage { uint256 mintedDiscountPoly; } - struct Investor { - // Whether investor is accredited (0 = non-accredited, 1 = accredited) - uint8 accredited; - // Whether we have seen the investor before (already added to investors list) - uint8 seen; - // Overrides for default limit in USD for non-accredited investors multiplied by 10**18 (0 = no override) - uint256 nonAccreditedLimitUSDOverride; - } + mapping(address => uint256) public nonAccreditedLimitUSDOverride; mapping(bytes32 => mapping(bytes32 => string)) oracleKeys; @@ -65,16 +61,9 @@ contract USDTieredSTOStorage { // Amount in fund raise type invested by each investor mapping(address => mapping(uint8 => uint256)) public investorInvested; - // Accredited & non-accredited investor data - mapping (address => Investor) public investors; - // List of active stable coin addresses mapping (address => bool) internal usdTokenEnabled; - // List of all addresses that have been added as accredited or non-accredited without - // the default limit - address[] public investorsList; - // Default limit in USD for non-accredited investors multiplied by 10**18 uint256 public nonAccreditedLimitUSD; diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 4da34cbdb..9f7b7fe59 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -14,6 +14,7 @@ import "openzeppelin-solidity/contracts/utils/ReentrancyGuard.sol"; import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; import "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol"; import "../libraries/TokenLib.sol"; +import "../interfaces/IDataStore.sol"; /** * @title Security Token contract @@ -28,7 +29,7 @@ import "../libraries/TokenLib.sol"; contract SecurityToken is ERC20, ERC20Detailed, ReentrancyGuard, RegistryUpdater { using SafeMath for uint256; - TokenLib.InvestorDataStorage investorData; + bytes32 internal constant INVESTORSKEY = 0xdf3a8dd24acdd05addfc6aeffef7574d2de3f844535ec91e8e0f3e45dba96731; //keccak256(abi.encodePacked("INVESTORS")) // Used to hold the semantic version data struct SemanticVersion { @@ -69,6 +70,9 @@ contract SecurityToken is ERC20, ERC20Detailed, ReentrancyGuard, RegistryUpdater // Address of the data store used to store shared data address public dataStore; + // Number of investors with non-zero balance + uint256 public holderCount; + // Records added modules - module list should be order agnostic! mapping(uint8 => address[]) modules; @@ -134,8 +138,8 @@ contract SecurityToken is ERC20, ERC20Detailed, ReentrancyGuard, RegistryUpdater event DisableController(); function _isModule(address _module, uint8 _type) internal view returns(bool) { - require(modulesToData[_module].module == _module, "Wrong address"); - require(!modulesToData[_module].isArchived, "Module archived"); + if (modulesToData[_module].module != _module || modulesToData[_module].isArchived) + return false; for (uint256 i = 0; i < modulesToData[_module].moduleTypes.length; i++) { if (modulesToData[_module].moduleTypes[i] == _type) { return true; @@ -388,7 +392,7 @@ contract SecurityToken is ERC20, ERC20Detailed, ReentrancyGuard, RegistryUpdater * @param _value value of transfer */ function _adjustInvestorCount(address _from, address _to, uint256 _value) internal { - TokenLib.adjustInvestorCount(investorData, _from, _to, _value, balanceOf(_to), balanceOf(_from)); + holderCount = TokenLib.adjustInvestorCount(holderCount, _from, _to, _value, balanceOf(_to), balanceOf(_from), dataStore); } /** @@ -396,59 +400,56 @@ contract SecurityToken is ERC20, ERC20Detailed, ReentrancyGuard, RegistryUpdater * NB - this length may differ from investorCount as it contains all investors that ever held tokens * @return list of addresses */ - function getInvestors() external view returns(address[] memory) { - return investorData.investors; + function getInvestors() public view returns(address[] memory investors) { + IDataStore dataStoreInstance = IDataStore(dataStore); + investors = dataStoreInstance.getAddressArray(INVESTORSKEY); } /** - * @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 + * @notice returns an array of investors with non zero balance at a given checkpoint * @param _checkpointId Checkpoint id at which investor list is to be populated * @return list of investors */ function getInvestorsAt(uint256 _checkpointId) external view returns(address[] memory) { - uint256 count = 0; + uint256 count; uint256 i; - for (i = 0; i < investorData.investors.length; i++) { - if (balanceOfAt(investorData.investors[i], _checkpointId) > 0) { + IDataStore dataStoreInstance = IDataStore(dataStore); + address[] memory investors = dataStoreInstance.getAddressArray(INVESTORSKEY); + for (i = 0; i < investors.length; i++) { + if (balanceOfAt(investors[i], _checkpointId) > 0) { count++; } } - address[] memory investors = new address[](count); + address[] memory holders = new address[](count); count = 0; - for (i = 0; i < investorData.investors.length; i++) { - if (balanceOfAt(investorData.investors[i], _checkpointId) > 0) { - investors[count] = investorData.investors[i]; + for (i = 0; i < investors.length; i++) { + if (balanceOfAt(investors[i], _checkpointId) > 0) { + holders[count] = investors[i]; count++; } } - return investors; + return holders; } /** * @notice generates subset of investors - * NB - can be used in batches if investor list is large + * NB - can be used in batches if investor list is large. start and end both are included in array. * @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[] memory) { - require(_end <= investorData.investors.length, "Invalid end"); - address[] memory investors = new address[](_end.sub(_start)); - uint256 index = 0; - for (uint256 i = _start; i < _end; i++) { - investors[index] = investorData.investors[i]; - index++; - } - return investors; + IDataStore dataStoreInstance = IDataStore(dataStore); + return dataStoreInstance.getAddressArrayElements(INVESTORSKEY, _start, _end); } /** - * @notice Returns the investor count + * @notice Returns the count of address that were added as (potential) investors * @return Investor count */ function getInvestorCount() external view returns(uint256) { - return investorData.investorCount; + IDataStore dataStoreInstance = IDataStore(dataStore); + return dataStoreInstance.getAddressArrayLength(INVESTORSKEY); } /** @@ -838,5 +839,4 @@ contract SecurityToken is ERC20, ERC20Detailed, ReentrancyGuard, RegistryUpdater _version[2] = securityTokenVersion.patch; return _version; } - } diff --git a/docs/investor_flags.md b/docs/investor_flags.md new file mode 100644 index 000000000..9ccf74473 --- /dev/null +++ b/docs/investor_flags.md @@ -0,0 +1,23 @@ +# Flags List + + + + + + + + + + + + + + + + + + + + + +
Flag Name Description
0 isAccredited Defines if an Investor is Accredited or not. True for Accredited, false for not Accredited.
1 canNotBuyFromSto Defines if an Investor is restricted from participating in STOs
diff --git a/package.json b/package.json index e8a7e72ef..4c45a49ab 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ }, "scripts": { "test": "scripts/test.sh 2> /dev/null", + "gas": "scripts/gasUsage.sh", "wintest": "scripts\\wintest.cmd", "wincov": "scripts\\wincov.cmd", "docs": "scripts/docs.sh", @@ -85,6 +86,7 @@ "eslint-plugin-node": "^8.0.0", "eslint-plugin-promise": "^4.0.1", "eslint-plugin-standard": "^4.0.0", + "eth-gas-reporter": "^0.1.12", "ethereum-bridge": "^0.6.1", "ethereumjs-abi": "^0.6.5", "ganache-cli": "^6.2.4", @@ -95,7 +97,7 @@ "solidity-coverage": "^0.5.11", "solidity-docgen": "^0.1.0", "solium": "^1.1.6", - "truffle": "^5.0.0", + "truffle": "^5.0.4", "truffle-wallet-provider": "0.0.5" }, "greenkeeper": { diff --git a/scripts/gasUsage.sh b/scripts/gasUsage.sh new file mode 100755 index 000000000..a7794d371 --- /dev/null +++ b/scripts/gasUsage.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +mv truffle-config.js truffle-config-bk.js +cp truffle-config-gas.js truffle-config.js + +scripts/test.sh + +mv truffle-config-bk.js truffle-config.js \ No newline at end of file diff --git a/test/b_capped_sto.js b/test/b_capped_sto.js index 8e637736e..8392f189a 100644 --- a/test/b_capped_sto.js +++ b/test/b_capped_sto.js @@ -316,7 +316,7 @@ contract("CappedSTO", async (accounts) => { P_expiryTime = toTime + duration.days(100); // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, true, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_investor1, fromTime, toTime, expiryTime, { from: account_issuer }); @@ -386,13 +386,11 @@ contract("CappedSTO", async (accounts) => { it("Should buy the granular unit tokens and refund pending amount", async () => { await I_SecurityToken_ETH.changeGranularity(new BN(10).pow(new BN(21)), { from: token_owner }); - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor2, fromTime, toTime + duration.days(20), expiryTime, - true, - false, { from: account_issuer } @@ -531,7 +529,7 @@ contract("CappedSTO", async (accounts) => { it("Should successfully whitelist investor 3", async () => { balanceOfReceiver = new BN(await web3.eth.getBalance(account_fundsReceiver)); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, true, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_investor3, fromTime, toTime, expiryTime, { from: account_issuer, gas: 500000 }); @@ -697,7 +695,7 @@ contract("CappedSTO", async (accounts) => { 10500, "Tokens are not transfered properly" ); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, P_fromTime, P_toTime, P_expiryTime, true, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_investor1, P_fromTime, P_toTime, P_expiryTime, { from: account_issuer, gas: 500000 }); @@ -756,13 +754,11 @@ contract("CappedSTO", async (accounts) => { it("Should buy the granular unit tokens and charge only required POLY", async () => { await I_SecurityToken_POLY.changeGranularity(new BN(10).pow(new BN(22)), { from: token_owner }); - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor2, P_fromTime, P_toTime + duration.days(20), P_expiryTime, - true, - false, { from: account_issuer, gas: 500000 @@ -973,7 +969,7 @@ contract("CappedSTO", async (accounts) => { await I_PolyToken.getTokens(polyToInvest.mul(new BN(10).pow(new BN(18))), account_investor3); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, P_fromTime, P_toTime, P_expiryTime, true, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_investor3, P_fromTime, P_toTime, P_expiryTime, { from: account_issuer, gas: 500000 }); diff --git a/test/c_checkpoints.js b/test/c_checkpoints.js index 707310678..20a1488ce 100644 --- a/test/c_checkpoints.js +++ b/test/c_checkpoints.js @@ -148,13 +148,11 @@ contract("Checkpoints", async function(accounts) { it("Should Buy the tokens", async () => { // Add the Investor in to the whitelist let ltime = new BN(await latestTime()); - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor1, ltime, ltime, ltime.add(new BN(duration.days(10))), - false, - false, { from: account_issuer, gas: 6000000 @@ -175,13 +173,11 @@ contract("Checkpoints", async function(accounts) { it("Should Buy some more tokens", async () => { // Add the Investor in to the whitelist let ltime = new BN(await latestTime()); - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor2, ltime, ltime, ltime.add(new BN(duration.days(10))), - false, - false, { from: account_issuer, gas: 6000000 @@ -202,13 +198,11 @@ contract("Checkpoints", async function(accounts) { it("Add a new token holder", async () => { let ltime = new BN(await latestTime()); - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor3, ltime, ltime, ltime.add(new BN(duration.days(10))), - false, - false, { from: account_issuer, gas: 6000000 diff --git a/test/d_count_transfer_manager.js b/test/d_count_transfer_manager.js index 1dd9a544e..64ac16798 100644 --- a/test/d_count_transfer_manager.js +++ b/test/d_count_transfer_manager.js @@ -200,13 +200,11 @@ contract("CountTransferManager", async (accounts) => { it("Should Buy the tokens", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor1, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 500000 @@ -231,13 +229,11 @@ contract("CountTransferManager", async (accounts) => { it("Should Buy some more tokens", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor2, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 500000 @@ -259,13 +255,11 @@ contract("CountTransferManager", async (accounts) => { it("Should able to buy some more tokens (more than 2 hoders) -- because CountTransferManager is paused", async () => { await I_CountTransferManager.pause({ from: account_issuer }); let snapId = await takeSnapshot(); - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor3, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 500000 @@ -285,13 +279,11 @@ contract("CountTransferManager", async (accounts) => { it("Should fail to buy some more tokens (more than 2 holders)", async () => { await I_CountTransferManager.unpause({ from: account_issuer }); // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor3, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 500000 @@ -374,52 +366,44 @@ contract("CountTransferManager", async (accounts) => { }); it("add 3 holders to the token", async () => { - await I_GeneralTransferManager2.modifyWhitelist( + await I_GeneralTransferManager2.modifyKYCData( account_investor1, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 500000 } ); - await I_GeneralTransferManager2.modifyWhitelist( + await I_GeneralTransferManager2.modifyKYCData( account_investor2, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 500000 } ); - await I_GeneralTransferManager2.modifyWhitelist( + await I_GeneralTransferManager2.modifyKYCData( account_investor3, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 500000 } ); - await I_GeneralTransferManager2.modifyWhitelist( + await I_GeneralTransferManager2.modifyKYCData( account_investor4, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 500000 @@ -465,11 +449,11 @@ contract("CountTransferManager", async (accounts) => { it("Should allow add a new token holder while transfer all the tokens at one go", async () => { let amount = await I_SecurityToken2.balanceOf(account_investor2); - let investorCount = await I_SecurityToken2.getInvestorCount({ from: account_investor2 }); + let investorCount = await I_SecurityToken2.holderCount({ from: account_investor2 }); console.log("current investor count is " + investorCount); await I_SecurityToken2.transfer(account_investor4, amount, { from: account_investor2 }); assert((await I_SecurityToken2.balanceOf(account_investor4)).toString(), amount.toString(), { from: account_investor2 }); - assert(await I_SecurityToken2.getInvestorCount({ from: account_investor2 }), investorCount); + assert(await I_SecurityToken2.holderCount({ from: account_investor2 }), investorCount); }); }); diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index 577c8dfc0..9a78e96e1 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -209,13 +209,11 @@ contract("ERC20DividendCheckpoint", async (accounts) => { it("Buy some tokens for account_investor1 (1 ETH)", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor1, currentTime, currentTime, currentTime.add(new BN(duration.days(30))), - true, - false, { from: account_issuer, gas: 500000 @@ -240,13 +238,11 @@ contract("ERC20DividendCheckpoint", async (accounts) => { it("Buy some tokens for account_investor2 (2 ETH)", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor2, currentTime, currentTime, currentTime.add(new BN(duration.days(30))), - true, - false, { from: account_issuer, gas: 500000 @@ -387,13 +383,11 @@ contract("ERC20DividendCheckpoint", async (accounts) => { it("Buy some tokens for account_temp (1 ETH)", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_temp, currentTime, currentTime, currentTime.add(new BN(duration.days(20))), - true, - false, { from: account_issuer, gas: 500000 @@ -451,13 +445,11 @@ contract("ERC20DividendCheckpoint", async (accounts) => { it("Buy some tokens for account_investor3 (7 ETH)", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor3, currentTime, currentTime, currentTime.add(new BN(duration.days(100000))), - true, - false, { from: account_issuer, gas: 500000 diff --git a/test/f_ether_dividends.js b/test/f_ether_dividends.js index ca539b6eb..d59e16ce1 100644 --- a/test/f_ether_dividends.js +++ b/test/f_ether_dividends.js @@ -203,13 +203,11 @@ contract("EtherDividendCheckpoint", async (accounts) => { it("Buy some tokens for account_investor1 (1 ETH)", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor1, currentTime, currentTime, currentTime.add(new BN(duration.days(300000))), - true, - false, { from: account_issuer, gas: 500000 @@ -234,13 +232,11 @@ contract("EtherDividendCheckpoint", async (accounts) => { it("Buy some tokens for account_investor2 (2 ETH)", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor2, currentTime, currentTime, currentTime.add(new BN(duration.days(3000000))), - true, - false, { from: account_issuer, gas: 500000 @@ -369,13 +365,11 @@ contract("EtherDividendCheckpoint", async (accounts) => { it("Buy some tokens for account_temp (1 ETH)", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_temp, currentTime, currentTime, currentTime.add(new BN(duration.days(200000))), - true, - false, { from: account_issuer, gas: 500000 @@ -421,13 +415,11 @@ contract("EtherDividendCheckpoint", async (accounts) => { it("Buy some tokens for account_investor3 (7 ETH)", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor3, currentTime, currentTime, currentTime.add(new BN(duration.days(10000))), - true, - false, { from: account_issuer, gas: 500000 @@ -728,13 +720,11 @@ contract("EtherDividendCheckpoint", async (accounts) => { }); it("Assign token balance to an address that can't receive funds", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( I_PolyToken.address, currentTime, currentTime, currentTime.add(new BN(duration.days(1000000))), - true, - false, { from: account_issuer, gas: 500000 diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 33fb1edca..b9462c906 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -201,15 +201,30 @@ contract("GeneralTransferManager", async (accounts) => { await revertToSnapshot(snap_id); }); + it("Should add investor flags", async () => { + let snap_id = await takeSnapshot(); + await I_GeneralTransferManager.modifyInvestorFlagMulti([account_investor1, account_investor1, account_investor2], [0, 1, 1], [true, true, true], { from: account_issuer }); + let investors = await I_GeneralTransferManager.getInvestors(0, 1); + assert.equal(investors[0], account_investor1); + assert.equal(investors[1], account_investor2); + let investorCount = await I_SecurityToken.getInvestorCount(); + assert.equal(investorCount.toNumber(), 2); + let allInvestorFlags = await I_GeneralTransferManager.getAllInvestorFlags(); + assert.deepEqual(investors, allInvestorFlags[0]); + assert.equal(allInvestorFlags[1][0].toNumber(), 3)//0x000....00011 + assert.equal(allInvestorFlags[1][1].toNumber(), 2)//0x000....00010 + let investorFlags = await I_GeneralTransferManager.getInvestorFlags(allInvestorFlags[0][0]); + assert.equal(investorFlags, 3)//0x000....00011 + await revertToSnapshot(snap_id); + }); + it("Should whitelist the affiliates before the STO attached", async () => { console.log(`Estimate gas of one Whitelist: - ${await I_GeneralTransferManager.modifyWhitelist.estimateGas( + ${await I_GeneralTransferManager.modifyKYCData.estimateGas( account_affiliates1, currentTime + currentTime.add(new BN(duration.days(30))), currentTime + currentTime.add(new BN(duration.days(90))), currentTime + currentTime.add(new BN(duration.days(965))), - false, - false, { from: account_issuer } @@ -222,31 +237,30 @@ contract("GeneralTransferManager", async (accounts) => { let expiryTime1 = currentTime + currentTime.add(new BN(duration.days(965))); let expiryTime2 = currentTime.add(new BN(duration.days(365))); - let tx = await I_GeneralTransferManager.modifyWhitelistMulti( + let tx = await I_GeneralTransferManager.modifyKYCDataMulti( [account_affiliates1, account_affiliates2], [fromTime1, fromTime2], [toTime1, toTime2], [expiryTime1, expiryTime2], - [false, false], - [false, false], { from: account_issuer, gas: 6000000 } ); + await I_GeneralTransferManager.modifyInvestorFlagMulti([account_affiliates1, account_affiliates2], [1, 1], [true, true], { from: account_issuer }); 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()); - let data = await I_GeneralTransferManager.getInvestorsData.call([account_affiliates1, account_affiliates2]); + assert.deepEqual(await I_GeneralTransferManager.getAllInvestors.call(), [account_affiliates1, account_affiliates2]); + console.log(await I_GeneralTransferManager.getAllKYCData.call()); + let data = await I_GeneralTransferManager.getKYCData.call([account_affiliates1, account_affiliates2]); assert.equal(data[0][0].toString(), fromTime1); assert.equal(data[0][1].toString(), fromTime2); assert.equal(data[1][0].toString(), toTime1); assert.equal(data[1][1].toString(), toTime2); assert.equal(data[2][0].toString(), expiryTime1); assert.equal(data[2][1].toString(), expiryTime2); - assert.isFalse(data[3][0]); - assert.isFalse(data[3][1]); + assert.equal(await I_GeneralTransferManager.getInvestorFlag(account_affiliates1, 1), true); + assert.equal(await I_GeneralTransferManager.getInvestorFlag(account_affiliates2, 1), true); }); it("Should whitelist lots of addresses and check gas", async () => { @@ -257,13 +271,12 @@ contract("GeneralTransferManager", async (accounts) => { let times = range1(50); let bools = rangeB(50); - let tx = await I_GeneralTransferManager.modifyWhitelistMulti(mockInvestors, times, times, times, bools, bools, { - from: account_issuer, - gas: 7900000 + let tx = await I_GeneralTransferManager.modifyKYCDataMulti(mockInvestors, times, times, times, { + from: account_issuer }); console.log("Multi Whitelist x 50: " + tx.receipt.gasUsed); assert.deepEqual( - await I_GeneralTransferManager.getInvestors.call(), + await I_GeneralTransferManager.getAllInvestors.call(), [account_affiliates1, account_affiliates2].concat(mockInvestors) ); }); @@ -358,13 +371,11 @@ contract("GeneralTransferManager", async (accounts) => { it("Should Buy the tokens", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor1, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 6000000 @@ -422,7 +433,7 @@ contract("GeneralTransferManager", async (accounts) => { 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, new BN(0), new BN(0), currentTime.add(new BN(duration.days(20))), true, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_investor1, new BN(0), new BN(0), currentTime.add(new BN(duration.days(20))), { from: account_issuer, gas: 6000000 }); @@ -433,13 +444,11 @@ contract("GeneralTransferManager", async (accounts) => { "Failed in adding the investor in whitelist" ); - tx = await I_GeneralTransferManager.modifyWhitelist( + tx = await I_GeneralTransferManager.modifyKYCData( account_investor2, currentTime, currentTime, currentTime.add(new BN(duration.days(20))), - true, - true, { from: account_issuer, gas: 6000000 @@ -476,7 +485,7 @@ contract("GeneralTransferManager", async (accounts) => { await increaseTime(duration.days(2)); await I_SecurityToken.transfer(account_investor1, new BN(web3.utils.toWei("2", "ether")), { from: account_investor2 }); // revert changes - await I_GeneralTransferManager.modifyWhitelist(account_investor2, new BN(0), new BN(0), new BN(0), false, false, { + await I_GeneralTransferManager.modifyKYCData(account_investor2, new BN(0), new BN(0), new BN(0), { from: account_issuer, gas: 6000000 }); @@ -517,8 +526,6 @@ contract("GeneralTransferManager", async (accounts) => { fromTime, toTime, expiryTime, - true, - false, validFrom, validTo, nonce, @@ -526,13 +533,11 @@ contract("GeneralTransferManager", async (accounts) => { ); await catchRevert( - I_GeneralTransferManager.modifyWhitelistSigned( + I_GeneralTransferManager.modifyKYCDataSigned( account_investor2, fromTime, toTime, expiryTime, - true, - false, validFrom, validTo, nonce, @@ -557,8 +562,6 @@ contract("GeneralTransferManager", async (accounts) => { fromTime, toTime, expiryTime, - true, - false, validFrom, validTo, nonce, @@ -566,13 +569,11 @@ contract("GeneralTransferManager", async (accounts) => { ); await catchRevert( - I_GeneralTransferManager.modifyWhitelistSigned( + I_GeneralTransferManager.modifyKYCDataSigned( account_investor2, fromTime, toTime, expiryTime, - true, - false, validFrom, validTo, nonce, @@ -597,8 +598,6 @@ contract("GeneralTransferManager", async (accounts) => { fromTime, toTime, expiryTime, - true, - false, validFrom, validTo, nonce, @@ -606,13 +605,11 @@ contract("GeneralTransferManager", async (accounts) => { ); await catchRevert( - I_GeneralTransferManager.modifyWhitelistSigned( + I_GeneralTransferManager.modifyKYCDataSigned( account_investor2, fromTime, toTime, expiryTime, - true, - false, validFrom, validTo, nonce, @@ -637,21 +634,17 @@ contract("GeneralTransferManager", async (accounts) => { currentTime.toNumber(), currentTime.add(new BN(duration.days(100))).toNumber(), expiryTime + duration.days(200), - true, - false, validFrom, validTo, nonce, signer.privateKey ); - let tx = await I_GeneralTransferManager.modifyWhitelistSigned( + let tx = await I_GeneralTransferManager.modifyKYCDataSigned( account_investor2, currentTime.toNumber(), currentTime.add(new BN(duration.days(100))).toNumber(), expiryTime + duration.days(200), - true, - false, validFrom, validTo, nonce, @@ -689,8 +682,6 @@ contract("GeneralTransferManager", async (accounts) => { currentTime.toNumber(), currentTime.add(new BN(duration.days(100))).toNumber(), expiryTime + duration.days(200), - true, - false, validFrom, validTo, nonce, @@ -698,13 +689,11 @@ contract("GeneralTransferManager", async (accounts) => { ); await catchRevert( - I_GeneralTransferManager.modifyWhitelistSigned( + I_GeneralTransferManager.modifyKYCDataSigned( account_investor2, currentTime.toNumber(), currentTime.add(new BN(duration.days(100))).toNumber(), expiryTime + duration.days(200), - true, - false, validFrom, validTo, nonce, @@ -729,21 +718,17 @@ contract("GeneralTransferManager", async (accounts) => { currentTime.toNumber(), currentTime.add(new BN(duration.days(100))).toNumber(), expiryTime + duration.days(200), - true, - false, validFrom, validTo, nonce, "0x" + token_owner_pk ); - await I_GeneralTransferManager.modifyWhitelistSigned( + await I_GeneralTransferManager.modifyKYCDataSigned( account_investor2, currentTime.toNumber(), currentTime.add(new BN(duration.days(100))).toNumber(), expiryTime + duration.days(200), - true, - false, validFrom, validTo, nonce, @@ -827,13 +812,11 @@ contract("GeneralTransferManager", async (accounts) => { let expiryTime = toTime + duration.days(10); await catchRevert( - I_GeneralTransferManager.modifyWhitelistMulti( + I_GeneralTransferManager.modifyKYCDataMulti( [account_investor3, account_investor4], [fromTime, fromTime], [toTime, toTime], [expiryTime, expiryTime], - [true, true], - [true, true], { from: account_delegate, gas: 6000000 @@ -848,13 +831,11 @@ contract("GeneralTransferManager", async (accounts) => { let expiryTime = toTime + duration.days(10); await catchRevert( - I_GeneralTransferManager.modifyWhitelistMulti( + I_GeneralTransferManager.modifyKYCDataMulti( [account_investor3, account_investor4], [fromTime], [toTime, toTime], [expiryTime, expiryTime], - [1, 1], - [true, true], { from: account_delegate, gas: 6000000 @@ -869,13 +850,11 @@ contract("GeneralTransferManager", async (accounts) => { let expiryTime = toTime + duration.days(10); await catchRevert( - I_GeneralTransferManager.modifyWhitelistMulti( + I_GeneralTransferManager.modifyKYCDataMulti( [account_investor3, account_investor4], [fromTime, fromTime], [toTime], [expiryTime, expiryTime], - [true, true], - [true, true], { from: account_delegate, gas: 6000000 @@ -890,13 +869,11 @@ contract("GeneralTransferManager", async (accounts) => { let expiryTime = toTime + duration.days(10); await catchRevert( - I_GeneralTransferManager.modifyWhitelistMulti( + I_GeneralTransferManager.modifyKYCDataMulti( [account_investor3, account_investor4], [fromTime, fromTime], [toTime, toTime], [expiryTime], - [true, true], - [true, true], { from: account_delegate, gas: 6000000 @@ -910,13 +887,11 @@ contract("GeneralTransferManager", async (accounts) => { let toTime = await latestTime() + duration.days(20); let expiryTime = toTime + duration.days(10); - let tx = await I_GeneralTransferManager.modifyWhitelistMulti( + let tx = await I_GeneralTransferManager.modifyKYCDataMulti( [account_investor3, account_investor4], [fromTime, fromTime], [toTime, toTime], [expiryTime, expiryTime], - [true, true], - [true, true], { from: token_owner, gas: 6000000 diff --git a/test/helpers/signData.js b/test/helpers/signData.js index 73a2ff761..0d675d7a7 100644 --- a/test/helpers/signData.js +++ b/test/helpers/signData.js @@ -5,11 +5,11 @@ const Web3 = require("web3"); let BN = Web3.utils.BN; //this, _investor, _fromTime, _toTime, _validTo -function signData(tmAddress, investorAddress, fromTime, toTime, expiryTime, restricted, validFrom, validTo, nonce, pk) { +function signData(tmAddress, investorAddress, fromTime, toTime, expiryTime, validFrom, validTo, nonce, pk) { let packedData = utils .solidityKeccak256( - ["address", "address", "uint256", "uint256", "uint256", "bool", "uint256", "uint256", "uint256"], - [tmAddress, investorAddress, fromTime, toTime, expiryTime, restricted, validFrom, validTo, nonce] + ["address", "address", "uint256", "uint256", "uint256", "uint256", "uint256", "uint256"], + [tmAddress, investorAddress, fromTime, toTime, expiryTime, validFrom, validTo, nonce] ) .slice(2); packedData = new Buffer(packedData, "hex"); @@ -27,8 +27,8 @@ function getSignSTMData(tmAddress, nonce, expiry, fromAddress, toAddress, amount return data; } -function getSignGTMData(tmAddress, investorAddress, fromTime, toTime, expiryTime, restricted, accredited, validFrom, validTo, nonce, pk) { - let hash = web3.utils.soliditySha3({t: 'address', v: tmAddress}, {t: 'address', v: investorAddress}, {t: 'uint256', v: new BN(fromTime)}, {t: 'uint256', v: new BN(toTime)}, {t: 'uint256', v: new BN(expiryTime)}, {t: 'bool', v: restricted}, {t: 'bool', v: accredited}, {t: 'uint256', v: new BN(validFrom)}, {t: 'uint256', v: new BN(validTo)}, {t: 'uint256', v: new BN(nonce)}); +function getSignGTMData(tmAddress, investorAddress, fromTime, toTime, expiryTime, validFrom, validTo, nonce, pk) { + let hash = web3.utils.soliditySha3({t: 'address', v: tmAddress}, {t: 'address', v: investorAddress}, {t: 'uint256', v: new BN(fromTime)}, {t: 'uint256', v: new BN(toTime)}, {t: 'uint256', v: new BN(expiryTime)}, {t: 'uint256', v: new BN(validFrom)}, {t: 'uint256', v: new BN(validTo)}, {t: 'uint256', v: new BN(nonce)}); let signature = (web3.eth.accounts.sign(hash, pk)); return signature.signature; } diff --git a/test/i_Issuance.js b/test/i_Issuance.js index 321f6c8d5..78291f7dd 100644 --- a/test/i_Issuance.js +++ b/test/i_Issuance.js @@ -205,13 +205,11 @@ contract("Issuance", async (accounts) => { toTime = await latestTime() + duration.days(15); expiryTime = toTime + duration.days(100); - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor1, fromTime + duration.days(70), toTime + duration.days(90), expiryTime + duration.days(50), - true, - false, { from: account_polymath } @@ -271,7 +269,7 @@ contract("Issuance", async (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, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_investor2, fromTime, toTime, expiryTime, { from: account_delegate, gas: 7000000 }); diff --git a/test/j_manual_approval_transfer_manager.js b/test/j_manual_approval_transfer_manager.js index bb4b10403..2d3244e38 100644 --- a/test/j_manual_approval_transfer_manager.js +++ b/test/j_manual_approval_transfer_manager.js @@ -170,13 +170,11 @@ contract("ManualApprovalTransferManager", accounts => { it("Should Buy the tokens", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor1, currentTime, currentTime, currentTime.add(new BN(duration.days(30))), - true, - false, { from: account_issuer, gas: 6000000 @@ -201,13 +199,11 @@ contract("ManualApprovalTransferManager", accounts => { it("Should Buy some more tokens", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor2, currentTime, currentTime, currentTime.add(new BN(duration.days(30))), - true, - false, { from: account_issuer, gas: 6000000 @@ -291,13 +287,11 @@ contract("ManualApprovalTransferManager", accounts => { }); it("Add a new token holder", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor3, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 6000000 diff --git a/test/l_percentage_transfer_manager.js b/test/l_percentage_transfer_manager.js index 880f87606..eafc4fd42 100644 --- a/test/l_percentage_transfer_manager.js +++ b/test/l_percentage_transfer_manager.js @@ -197,13 +197,11 @@ contract("PercentageTransferManager", async (accounts) => { it("Should Buy the tokens", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor1, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 6000000 @@ -228,13 +226,11 @@ contract("PercentageTransferManager", async (accounts) => { it("Should Buy some more tokens", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor2, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 6000000 @@ -294,13 +290,11 @@ contract("PercentageTransferManager", async (accounts) => { }); it("Add a new token holder", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor3, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 6000000 diff --git a/test/m_presale_sto.js b/test/m_presale_sto.js index b5056bf0a..c323fd1b3 100644 --- a/test/m_presale_sto.js +++ b/test/m_presale_sto.js @@ -241,7 +241,7 @@ contract("PreSaleSTO", async (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, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_investor1, fromTime, toTime, expiryTime, { from: account_issuer, gas: 6000000 }); @@ -282,7 +282,7 @@ contract("PreSaleSTO", async (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, false, { + let tx1 = await I_GeneralTransferManager.modifyKYCData(account_investor2, fromTime, toTime, expiryTime, { from: account_issuer, gas: 6000000 }); @@ -290,7 +290,7 @@ contract("PreSaleSTO", async (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, false, { + let tx2 = await I_GeneralTransferManager.modifyKYCData(account_investor3, fromTime, toTime, expiryTime, { from: account_issuer, gas: 6000000 }); diff --git a/test/o_security_token.js b/test/o_security_token.js index e5a2a1d40..38fb10c81 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -199,7 +199,7 @@ contract("SecurityToken", async (accounts) => { let toTime = new BN(currentTime.add(new BN(duration.days(100)))); let expiryTime = new BN(toTime.add(new BN(duration.days(100)))); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_affiliate1, currentTime, toTime, expiryTime, true, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_affiliate1, currentTime, toTime, expiryTime, { from: token_owner, gas: 6000000 }); @@ -218,7 +218,7 @@ contract("SecurityToken", async (accounts) => { let toTime = new BN(currentTime.add(new BN(duration.days(100)))); let expiryTime = new BN(toTime.add(new BN(duration.days(100)))); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_affiliate2, currentTime, toTime, expiryTime, true, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_affiliate2, currentTime, toTime, expiryTime, { from: token_owner, gas: 6000000 }); @@ -536,7 +536,7 @@ contract("SecurityToken", async (accounts) => { toTime = fromTime + duration.days(100); expiryTime = toTime + duration.days(100); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, true, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_investor1, fromTime, toTime, expiryTime, { from: token_owner, gas: 6000000 }); @@ -648,7 +648,7 @@ contract("SecurityToken", async (accounts) => { }); it("Should transfer from whitelist investor1 to whitelist investor 2", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor2, fromTime, toTime, expiryTime, true, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_investor2, fromTime, toTime, expiryTime, { from: token_owner, gas: 500000 }); @@ -670,7 +670,7 @@ contract("SecurityToken", async (accounts) => { it("Should transferFrom from one investor to other", async () => { await I_SecurityToken.approve(account_investor1, new BN(2).mul(new BN(10).pow(new BN(18))), { from: account_investor2 }); - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor3, fromTime, toTime, expiryTime, true, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_investor3, fromTime, toTime, expiryTime, { from: token_owner, gas: 500000 }); @@ -715,7 +715,7 @@ contract("SecurityToken", async (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, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_temp, fromTime, toTime, expiryTime, { from: account_delegate, gas: 6000000 }); @@ -755,7 +755,7 @@ contract("SecurityToken", async (accounts) => { }); it("Should remove investor from the whitelist by the delegate", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, new BN(0), new BN(0), new BN(0), true, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_temp, new BN(0), new BN(0), new BN(0), { from: account_delegate, gas: 6000000 }); @@ -784,7 +784,7 @@ contract("SecurityToken", async (accounts) => { }); it("Should fail in buying to tokens", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist(account_temp, fromTime, toTime, expiryTime, true, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_temp, fromTime, toTime, expiryTime, { from: account_delegate, gas: 6000000 }); @@ -863,7 +863,6 @@ contract("SecurityToken", async (accounts) => { it("Should force burn the tokens - value too high", async () => { await I_GeneralTransferManager.changeAllowAllBurnTransfers(true, { from: token_owner }); - let currentInvestorCount = await I_SecurityToken.getInvestorCount.call(); let currentBalance = await I_SecurityToken.balanceOf(account_temp); await catchRevert( I_SecurityToken.forceBurn(account_temp, currentBalance + new BN(web3.utils.toWei("500", "ether")), "0x0", "0x0", { @@ -873,19 +872,18 @@ contract("SecurityToken", async (accounts) => { }); it("Should force burn the tokens - wrong caller", async () => { await I_GeneralTransferManager.changeAllowAllBurnTransfers(true, { from: token_owner }); - let currentInvestorCount = await I_SecurityToken.getInvestorCount.call(); let currentBalance = await I_SecurityToken.balanceOf(account_temp); await catchRevert(I_SecurityToken.forceBurn(account_temp, currentBalance, "0x0", "0x0", { from: token_owner })); }); it("Should burn the tokens", async () => { - let currentInvestorCount = await I_SecurityToken.getInvestorCount.call(); + let currentInvestorCount = await I_SecurityToken.holderCount.call(); let currentBalance = await I_SecurityToken.balanceOf(account_temp); // console.log(currentInvestorCount.toString(), currentBalance.toString()); let tx = await I_SecurityToken.forceBurn(account_temp, currentBalance, "0x0", "0x0", { from: account_controller }); // console.log(tx.logs[1].args._value.toNumber(), currentBalance.toNumber()); assert.equal(tx.logs[1].args._value.toString(), currentBalance.toString()); - let newInvestorCount = await I_SecurityToken.getInvestorCount.call(); + let newInvestorCount = await I_SecurityToken.holderCount.call(); // console.log(newInvestorCount.toString()); assert.equal(newInvestorCount.toNumber() + 1, currentInvestorCount.toNumber(), "Investor count drops by one"); }); @@ -928,17 +926,17 @@ contract("SecurityToken", async (accounts) => { it("Should get filtered investors", async () => { let investors = await I_SecurityToken.getInvestors.call(); console.log("All Investors: " + investors); - let filteredInvestors = await I_SecurityToken.iterateInvestors.call(0, 1); - console.log("Filtered Investors (0, 1): " + filteredInvestors); + let filteredInvestors = await I_SecurityToken.iterateInvestors.call(0, 0); + console.log("Filtered Investors (0, 0): " + filteredInvestors); assert.equal(filteredInvestors[0], investors[0]); assert.equal(filteredInvestors.length, 1); - filteredInvestors = await I_SecurityToken.iterateInvestors.call(2, 4); - console.log("Filtered Investors (2, 4): " + filteredInvestors); + filteredInvestors = await I_SecurityToken.iterateInvestors.call(2, 3); + console.log("Filtered Investors (2, 3): " + filteredInvestors); assert.equal(filteredInvestors[0], investors[2]); assert.equal(filteredInvestors[1], investors[3]); assert.equal(filteredInvestors.length, 2); - filteredInvestors = await I_SecurityToken.iterateInvestors.call(0, 4); - console.log("Filtered Investors (0, 4): " + filteredInvestors); + filteredInvestors = await I_SecurityToken.iterateInvestors.call(0, 3); + console.log("Filtered Investors (0, 3): " + filteredInvestors); assert.equal(filteredInvestors[0], investors[0]); assert.equal(filteredInvestors[1], investors[1]); assert.equal(filteredInvestors[2], investors[2]); @@ -965,13 +963,11 @@ contract("SecurityToken", async (accounts) => { I_MockRedemptionManager = await MockRedemptionManager.at(tx.logs[2].args._module); // adding the burn module into the GTM currentTime = new BN(await latestTime()); - tx = await I_GeneralTransferManager.modifyWhitelist( + tx = await I_GeneralTransferManager.modifyKYCData( I_MockRedemptionManager.address, currentTime, currentTime.add(new BN(duration.seconds(2))), currentTime.add(new BN(duration.days(50))), - true, - false, { from: account_delegate, gas: 6000000 @@ -1008,13 +1004,11 @@ contract("SecurityToken", async (accounts) => { // adding the burn module into the GTM currentTime = new BN(await latestTime()); - tx = await I_GeneralTransferManager.modifyWhitelist( + tx = await I_GeneralTransferManager.modifyKYCData( I_MockRedemptionManager.address, currentTime, currentTime.add(new BN(duration.seconds(2))), currentTime.add(new BN(duration.days(50))), - true, - false, { from: account_delegate, gas: 6000000 @@ -1095,7 +1089,7 @@ contract("SecurityToken", async (accounts) => { let sender = account_investor1; let receiver = account_investor2; - let start_investorCount = await I_SecurityToken.getInvestorCount.call(); + let start_investorCount = await I_SecurityToken.holderCount.call(); let start_balInv1 = await I_SecurityToken.balanceOf.call(account_investor1); let start_balInv2 = await I_SecurityToken.balanceOf.call(account_investor2); @@ -1108,7 +1102,7 @@ contract("SecurityToken", async (accounts) => { { from: account_controller } ); - let end_investorCount = await I_SecurityToken.getInvestorCount.call(); + let end_investorCount = await I_SecurityToken.holderCount.call(); let end_balInv1 = await I_SecurityToken.balanceOf.call(account_investor1); let end_balInv2 = await I_SecurityToken.balanceOf.call(account_investor2); diff --git a/test/p_usd_tiered_sto.js b/test/p_usd_tiered_sto.js index 1da3d9f20..4e3983966 100644 --- a/test/p_usd_tiered_sto.js +++ b/test/p_usd_tiered_sto.js @@ -1010,15 +1010,13 @@ contract("USDTieredSTO", async (accounts) => { let expiryTime = toTime + duration.days(100); let whitelisted = true; - await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, true, { from: ISSUER }); - await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, false, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(ACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); + await I_GeneralTransferManager.modifyInvestorFlag(ACCREDITED1, 0, true, { from: ISSUER }); //set as Accredited + await I_GeneralTransferManager.modifyKYCData(NONACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); // // Advance time to after STO start // await increaseTime(duration.days(3)); - // Set as accredited - await I_USDTieredSTO_Array[stoId].changeAccredited([ACCREDITED1], [true], { from: ISSUER }); - // Prep for investments let investment_ETH = new BN(web3.utils.toWei("1", "ether")); // Invest 1 ETH let investment_POLY = new BN(web3.utils.toWei("10000", "ether")); // Invest 10000 POLY @@ -1056,14 +1054,14 @@ contract("USDTieredSTO", async (accounts) => { // let expiryTime = toTime + duration.days(100); // 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 }); + // await I_GeneralTransferManager.modifyKYCData(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted,{ from: ISSUER }); + // await I_GeneralTransferManager.modifyKYCData(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted,{ from: ISSUER }); // Advance time to after STO start await increaseTime(duration.days(3)); // Set as accredited - await I_USDTieredSTO_Array[stoId].changeAccredited([ACCREDITED1], [true], { from: ISSUER }); + await I_GeneralTransferManager.modifyInvestorFlag(ACCREDITED1, 0, true, { from: ISSUER }); // Prep for investments let investment_ETH = new BN(web3.utils.toWei("1", "ether")); // Invest 1 ETH @@ -1110,15 +1108,13 @@ contract("USDTieredSTO", async (accounts) => { let expiryTime = toTime + duration.days(100); let whitelisted = true; - await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, true, { from: ISSUER }); - await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, false, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(ACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); + await I_GeneralTransferManager.modifyInvestorFlag(ACCREDITED1, 0, true, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(NONACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); // Advance time to after STO start await increaseTime(duration.days(3)); - // Set as accredited - await I_USDTieredSTO_Array[stoId].changeAccredited([ACCREDITED1], [true], { from: ISSUER }); - let investment_USD = new BN(2).mul(e18); let investment_ETH = await convert(stoId, tierId, false, "USD", "ETH", investment_USD); let investment_POLY = await convert(stoId, tierId, false, "USD", "POLY", investment_USD); @@ -1165,15 +1161,13 @@ contract("USDTieredSTO", async (accounts) => { let expiryTime = toTime + duration.days(100); let whitelisted = true; - await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, true, { from: ISSUER }); - await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted,false, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(ACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); + await I_GeneralTransferManager.modifyInvestorFlag(ACCREDITED1, 0, true, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(NONACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); // Advance time to after STO start await increaseTime(duration.days(3)); - // Set as accredited - await I_USDTieredSTO_Array[stoId].changeAccredited([ACCREDITED1], [true], { from: ISSUER }); - // Pause the STO await I_USDTieredSTO_Array[stoId].pause({ from: ISSUER }); assert.equal(await I_USDTieredSTO_Array[stoId].paused.call(), true, "STO did not pause successfully"); @@ -1235,15 +1229,13 @@ contract("USDTieredSTO", async (accounts) => { let expiryTime = toTime.add(new BN(duration.days(100))); let whitelisted = true; - await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, true, { from: ISSUER }); - await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, false, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(ACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); + await I_GeneralTransferManager.modifyInvestorFlag(ACCREDITED1, 0, true, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(NONACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); // Advance time to after STO start await increaseTime(duration.days(3)); - // Set as accredited - await I_USDTieredSTO_Array[stoId].changeAccredited([ACCREDITED1], [true], { from: ISSUER }); - // Prep for investments let investment_DAI = web3.utils.toWei("500", "ether"); // Invest 10000 POLY await I_DaiToken.getTokens(investment_DAI, NONACCREDITED1); @@ -1282,17 +1274,15 @@ contract("USDTieredSTO", async (accounts) => { let expiryTime = toTime + duration.days(100); let whitelisted = true; - await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, true, { from: ISSUER }); - await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, false, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(ACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); + await I_GeneralTransferManager.modifyInvestorFlag(ACCREDITED1, 0, true, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(NONACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); // Advance time to after STO end await increaseTime(duration.days(3)); assert.equal(await I_USDTieredSTO_Array[stoId].isOpen(), false, "STO is not showing correct status"); - // Set as accredited - await I_USDTieredSTO_Array[stoId].changeAccredited([ACCREDITED1], [true], { from: ISSUER }); - // Prep for investments let investment_ETH = new BN(web3.utils.toWei("1", "ether")); // Invest 1 ETH let investment_POLY = new BN(web3.utils.toWei("10000", "ether")); // Invest 10000 POLY @@ -1337,16 +1327,14 @@ contract("USDTieredSTO", async (accounts) => { let expiryTime = toTime + duration.days(100); let whitelisted = true; - await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, true, { from: ISSUER }); - await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, false, { from: ISSUER }); - await I_GeneralTransferManager.modifyWhitelist(RESERVEWALLET, fromTime, toTime, expiryTime, whitelisted, false, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(ACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); + await I_GeneralTransferManager.modifyInvestorFlag(ACCREDITED1, 0, true, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(NONACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(RESERVEWALLET, fromTime, toTime, expiryTime, { from: ISSUER }); // Advance time to after STO start await increaseTime(duration.days(3)); - // Set as accredited - await I_USDTieredSTO_Array[stoId].changeAccredited([ACCREDITED1], [true], { from: ISSUER }); - // Finalize STO await I_USDTieredSTO_Array[stoId].finalize({ from: ISSUER }); assert.equal(await I_USDTieredSTO_Array[stoId].isFinalized.call(), true, "STO has not been finalized"); @@ -1405,35 +1393,19 @@ contract("USDTieredSTO", async (accounts) => { let expiryTime = toTime + duration.days(100); let whitelisted = true; - const tx1 = await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, whitelisted, false, { + const tx1 = await I_GeneralTransferManager.modifyKYCData(NONACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); assert.equal(tx1.logs[0].args._investor, NONACCREDITED1, "Failed in adding the investor in whitelist"); - const tx2 = await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, whitelisted, true, { + const tx2 = await I_GeneralTransferManager.modifyKYCData(ACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); + await I_GeneralTransferManager.modifyInvestorFlag(ACCREDITED1, 0, true, { from: ISSUER }); assert.equal(tx2.logs[0].args._investor, ACCREDITED1, "Failed in adding the investor in whitelist"); }); - it("should successfully modify accredited addresses for first STO", async () => { + it("should successfully modify accredited addresses for the STOs", async () => { let stoId = 0; - let investorStatus = await I_USDTieredSTO_Array[stoId].investors.call(NONACCREDITED1); - let status1 = investorStatus[0].toNumber(); - assert.equal(status1, 0, "Initial accreditation is set to true"); - - await I_USDTieredSTO_Array[stoId].changeAccredited([NONACCREDITED1], [true], { from: ISSUER }); - investorStatus = await I_USDTieredSTO_Array[stoId].investors.call(NONACCREDITED1); - let status2 = investorStatus[0].toNumber(); - assert.equal(status2, 1, "Failed to set single address"); - - await I_USDTieredSTO_Array[stoId].changeAccredited([NONACCREDITED1, ACCREDITED1], [false, true], { from: ISSUER }); - investorStatus = await I_USDTieredSTO_Array[stoId].investors.call(NONACCREDITED1); - let status3 = investorStatus[0].toNumber(); - assert.equal(status3, 0, "Failed to set multiple addresses"); - investorStatus = await I_USDTieredSTO_Array[stoId].investors.call(ACCREDITED1); - let status4 = investorStatus[0].toNumber(); - assert.equal(status4, 1, "Failed to set multiple addresses"); - let totalStatus = await I_USDTieredSTO_Array[stoId].getAccreditedData.call(); console.log(totalStatus); assert.equal(totalStatus[0][0], NONACCREDITED1, "Account match"); @@ -1442,19 +1414,6 @@ contract("USDTieredSTO", async (accounts) => { assert.equal(totalStatus[1][1], true, "Account match"); assert.equal(totalStatus[2][0].toNumber(), 0, "override match"); assert.equal(totalStatus[2][1].toNumber(), 0, "override match"); - await catchRevert(I_USDTieredSTO_Array[stoId].changeAccredited([NONACCREDITED1, ACCREDITED1], [true], { from: ISSUER })); - }); - - it("should successfully modify accredited addresses for second STO", async () => { - let stoId = 1; - - await I_USDTieredSTO_Array[stoId].changeAccredited([NONACCREDITED1, ACCREDITED1], [false, true], { from: ISSUER }); - let investorStatus = await I_USDTieredSTO_Array[stoId].investors.call(NONACCREDITED1); - let status1 = investorStatus[0].toNumber(); - investorStatus = await I_USDTieredSTO_Array[stoId].investors.call(ACCREDITED1); - let status2 = investorStatus[0].toNumber(); - assert.equal(status1, 0, "Failed to set multiple address"); - assert.equal(status2, 1, "Failed to set multiple address"); }); }); @@ -1862,8 +1821,6 @@ contract("USDTieredSTO", async (accounts) => { let stoId = 0; let tierId = 0; - await I_USDTieredSTO_Array[stoId].changeAccredited([ACCREDITED1], [true], { from: ISSUER }); - let investment_Token = new BN(50).mul(e18); let investment_USD = await convert(stoId, tierId, false, "TOKEN", "USD", investment_Token); let investment_ETH = await convert(stoId, tierId, false, "TOKEN", "ETH", investment_Token); @@ -2163,8 +2120,8 @@ contract("USDTieredSTO", async (accounts) => { await I_USDTieredSTO_Array[stoId].changeNonAccreditedLimit([NONACCREDITED1], [_nonAccreditedLimitUSD[stoId].div(new BN(2))], { from: ISSUER }); - let investorStatus = await I_USDTieredSTO_Array[stoId].investors.call(NONACCREDITED1); - console.log("Current limit: " + investorStatus[2].toString()); + let investorLimit = await I_USDTieredSTO_Array[stoId].nonAccreditedLimitUSDOverride.call(NONACCREDITED1); + console.log("Current limit: " + investorLimit.toString()); let totalStatus = await I_USDTieredSTO_Array[stoId].getAccreditedData.call(); assert.equal(totalStatus[0][0], NONACCREDITED1, "Account match"); @@ -2179,8 +2136,7 @@ contract("USDTieredSTO", async (accounts) => { let stoId = 0; let tierId = 0; - let investorStatus = await I_USDTieredSTO_Array[stoId].investors.call(NONACCREDITED1); - let investment_USD = investorStatus[2];//await I_USDTieredSTO_Array[stoId].nonAccreditedLimitUSDOverride(NONACCREDITED1); //_nonAccreditedLimitUSD[stoId]; + let investment_USD = await I_USDTieredSTO_Array[stoId].nonAccreditedLimitUSDOverride.call(NONACCREDITED1);//await I_USDTieredSTO_Array[stoId].nonAccreditedLimitUSDOverride(NONACCREDITED1); //_nonAccreditedLimitUSD[stoId]; let investment_Token = await convert(stoId, tierId, false, "USD", "TOKEN", investment_USD); let investment_ETH = await convert(stoId, tierId, false, "USD", "ETH", investment_USD); let investment_POLY = await convert(stoId, tierId, false, "USD", "POLY", investment_USD); @@ -2665,8 +2621,6 @@ contract("USDTieredSTO", async (accounts) => { let startTier = 2; let endTier = 3; - await I_USDTieredSTO_Array[stoId].changeAccredited([ACCREDITED1], [true], { from: ISSUER }); - assert.equal( (await I_USDTieredSTO_Array[stoId].currentTier.call()).toString(), startTier, @@ -3440,8 +3394,6 @@ contract("USDTieredSTO", async (accounts) => { let stoId = 2; let tierId = 0; - await I_USDTieredSTO_Array[stoId].changeAccredited([ACCREDITED1], [true], { from: ISSUER }); - let investment_Token = new BN(5).mul(e18); let investment_USD = await convert(stoId, tierId, false, "TOKEN", "USD", investment_Token); let investment_ETH = await convert(stoId, tierId, false, "TOKEN", "ETH", investment_Token); @@ -3846,7 +3798,6 @@ contract("USDTieredSTO", async (accounts) => { await I_SecurityToken.changeGranularity(e18, { from: ISSUER }); let stoId = 4; let tierId = 0; - await I_USDTieredSTO_Array[stoId].changeAccredited([ACCREDITED1], [true], { from: ISSUER }); let investment_Tokens = new BN(1050).mul(e16); let investment_POLY = await convert(stoId, tierId, true, "TOKEN", "POLY", investment_Tokens); @@ -4062,7 +4013,6 @@ contract("USDTieredSTO", async (accounts) => { it("should fail when rate set my contract is too low", async () => { let stoId = 4; let tierId = 0; - await I_USDTieredSTO_Array[stoId].changeAccredited([ACCREDITED1], [true], { from: ISSUER }); let investment_Tokens = new BN(e18); let investment_POLY = await convert(stoId, tierId, true, "TOKEN", "POLY", investment_Tokens); let investment_ETH = await convert(stoId, tierId, true, "TOKEN", "ETH", investment_Tokens); diff --git a/test/q_usd_tiered_sto_sim.js b/test/q_usd_tiered_sto_sim.js index 8862bab3d..30e72d055 100644 --- a/test/q_usd_tiered_sto_sim.js +++ b/test/q_usd_tiered_sto_sim.js @@ -372,17 +372,20 @@ contract("USDTieredSTO Sim", async (accounts) => { let expiryTime = toTime + duration.days(100); let canBuyFromSTO = true; - await I_GeneralTransferManager.modifyWhitelist(ACCREDITED1, fromTime, toTime, expiryTime, canBuyFromSTO, true, { from: ISSUER }); - await I_GeneralTransferManager.modifyWhitelist(ACCREDITED2, fromTime, toTime, expiryTime, canBuyFromSTO, true, { from: ISSUER }); - await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED1, fromTime, toTime, expiryTime, canBuyFromSTO, false, { from: ISSUER }); - await I_GeneralTransferManager.modifyWhitelist(NONACCREDITED2, fromTime, toTime, expiryTime, canBuyFromSTO, false, { from: ISSUER }); - await I_GeneralTransferManager.modifyWhitelist(NOTAPPROVED, fromTime, toTime, expiryTime, false, false, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(ACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); + await I_GeneralTransferManager.modifyInvestorFlag(ACCREDITED1, 0, true, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(ACCREDITED2, fromTime, toTime, expiryTime, { from: ISSUER }); + await I_GeneralTransferManager.modifyInvestorFlag(ACCREDITED2, 0, true, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(NONACCREDITED1, fromTime, toTime, expiryTime, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(NONACCREDITED2, fromTime, toTime, expiryTime, { from: ISSUER }); + await I_GeneralTransferManager.modifyKYCData(NOTAPPROVED, fromTime, toTime, expiryTime, { from: ISSUER }); + await I_GeneralTransferManager.modifyInvestorFlag(NOTAPPROVED, 1, true, { from: ISSUER }); await increaseTime(duration.days(3)); // Accreditation - await I_USDTieredSTO_Array[stoId].changeAccredited([ACCREDITED1, ACCREDITED2], [true, true], { from: ISSUER }); - await I_USDTieredSTO_Array[stoId].changeAccredited([NONACCREDITED1, NONACCREDITED2], [false, false], { from: ISSUER }); + await I_GeneralTransferManager.modifyInvestorFlag(ACCREDITED1, 0, true, { from: ISSUER }); + await I_GeneralTransferManager.modifyInvestorFlag(ACCREDITED2, 0, true, { from: ISSUER }); }); }); diff --git a/test/r_concurrent_STO.js b/test/r_concurrent_STO.js index e25647af3..e36207717 100644 --- a/test/r_concurrent_STO.js +++ b/test/r_concurrent_STO.js @@ -167,7 +167,7 @@ contract("Concurrent STO", async (accounts) => { let expiryTime = toTime + duration.days(100); let canBuyFromSTO = true; - let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, canBuyFromSTO, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(account_investor1, fromTime, toTime, expiryTime, { from: account_issuer, gas: 500000 }); diff --git a/test/v_tracked_redemptions.js b/test/v_tracked_redemptions.js index ad9f588b1..dd22c1c51 100644 --- a/test/v_tracked_redemptions.js +++ b/test/v_tracked_redemptions.js @@ -187,13 +187,11 @@ contract("TrackedRedemption", async (accounts) => { it("Buy some tokens for account_investor1 (1 ETH)", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor1, currentTime, currentTime, currentTime.add(new BN(duration.days(30))), - true, - false, { from: account_issuer, gas: 500000 @@ -218,13 +216,11 @@ contract("TrackedRedemption", async (accounts) => { it("Buy some tokens for account_investor2 (2 ETH)", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor2, currentTime, currentTime, currentTime.add(new BN(duration.days(30))), - true, - false, { from: account_issuer, gas: 500000 diff --git a/test/w_lockup_transfer_manager.js b/test/w_lockup_transfer_manager.js index ac54788a1..7e0a59ae2 100644 --- a/test/w_lockup_transfer_manager.js +++ b/test/w_lockup_transfer_manager.js @@ -197,13 +197,11 @@ contract('LockUpTransferManager', accounts => { it("Should Buy the tokens from non-divisible", async() => { // Add the Investor in to the whitelist console.log(account_investor1); - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor1, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer }); @@ -225,13 +223,11 @@ contract('LockUpTransferManager', accounts => { it("Should Buy some more tokens from non-divisible tokens", async() => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor2, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer }); @@ -296,13 +292,11 @@ contract('LockUpTransferManager', accounts => { it("Add a new token holder", async() => { - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor3, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer }); diff --git a/test/x_scheduled_checkpoints.js b/test/x_scheduled_checkpoints.js index 745aa0ab0..536ace060 100644 --- a/test/x_scheduled_checkpoints.js +++ b/test/x_scheduled_checkpoints.js @@ -177,13 +177,11 @@ contract("ScheduledCheckpoint", async (accounts) => { // Add the Investor in to the whitelist console.log("3: " + await latestTime()); - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor1, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 6000000 @@ -223,13 +221,11 @@ contract("ScheduledCheckpoint", async (accounts) => { it("Should Buy some more tokens for account_investor2", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor2, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 6000000 @@ -260,13 +256,11 @@ contract("ScheduledCheckpoint", async (accounts) => { }); it("Add a new token holder - account_investor3", async () => { - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor3, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer, gas: 6000000 diff --git a/test/y_volume_restriction_tm.js b/test/y_volume_restriction_tm.js index c46fe3a9c..5fac4428a 100644 --- a/test/y_volume_restriction_tm.js +++ b/test/y_volume_restriction_tm.js @@ -224,13 +224,11 @@ contract('VolumeRestrictionTransferManager', accounts => { it("Transfer some tokens to different account", async() => { // Add tokens in to the whitelist let newLatestTime = await getLatestTime(); - await I_GeneralTransferManager.modifyWhitelistMulti( + await I_GeneralTransferManager.modifyKYCDataMulti( [account_investor1, account_investor2, account_investor3], [newLatestTime, newLatestTime, newLatestTime], [newLatestTime, newLatestTime, newLatestTime], [newLatestTime.add(new BN(duration.days(60))), newLatestTime.add(new BN(duration.days(60))), newLatestTime.add(new BN(duration.days(60)))], - [true, true, true], - [false,false,false], { from: token_owner } @@ -1299,13 +1297,11 @@ contract('VolumeRestrictionTransferManager', accounts => { it("Should add the investor 4 in the whitelist", async() => { let newLatestTime = await getLatestTime(); - await I_GeneralTransferManager.modifyWhitelist( + await I_GeneralTransferManager.modifyKYCData( account_investor4, newLatestTime, newLatestTime, newLatestTime.add(new BN(duration.days(30))), - true, - false, { from: token_owner } diff --git a/test/z_blacklist_transfer_manager.js b/test/z_blacklist_transfer_manager.js index 0038052b6..f34c3e9e9 100644 --- a/test/z_blacklist_transfer_manager.js +++ b/test/z_blacklist_transfer_manager.js @@ -214,13 +214,11 @@ contract('BlacklistTransferManager', accounts => { it("Should Buy the tokens", async() => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor1, currentTime, currentTime, currentTime.add(new BN(duration.days(50))), - true, - false, { from: account_issuer }); @@ -242,13 +240,11 @@ contract('BlacklistTransferManager', accounts => { it("Should Buy some more tokens", async() => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor2, currentTime, currentTime, currentTime.add(new BN(duration.days(50))), - true, - false, { from: account_issuer }); @@ -267,13 +263,11 @@ contract('BlacklistTransferManager', accounts => { it("Should Buy some more tokens", async() => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor3, currentTime, currentTime, currentTime.add(new BN(duration.days(50))), - true, - false, { from: account_issuer }); @@ -292,13 +286,11 @@ contract('BlacklistTransferManager', accounts => { it("Should Buy some more tokens", async() => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor4, currentTime, currentTime, currentTime.add(new BN(duration.days(50))), - true, - false, { from: account_issuer }); @@ -317,13 +309,11 @@ contract('BlacklistTransferManager', accounts => { it("Should Buy some more tokens", async() => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor5, currentTime, currentTime, currentTime.add(new BN(duration.days(50))), - true, - false, { from: account_issuer }); diff --git a/test/z_fuzzer_volumn_restriction_transfer_manager.js b/test/z_fuzzer_volumn_restriction_transfer_manager.js index c9e5f56d8..2f0a80195 100644 --- a/test/z_fuzzer_volumn_restriction_transfer_manager.js +++ b/test/z_fuzzer_volumn_restriction_transfer_manager.js @@ -212,13 +212,11 @@ contract('VolumeRestrictionTransferManager', accounts => { it("Transfer some tokens to different account", async() => { // Add tokens in to the whitelist currentTime = new BN(await latestTime()); - await I_GeneralTransferManager.modifyWhitelistMulti( + await I_GeneralTransferManager.modifyKYCDataMulti( [account_investor1, account_investor2, account_investor3], [currentTime, currentTime, currentTime], [currentTime, currentTime, currentTime], [currentTime.add(new BN(duration.days(60))), currentTime.add(new BN(duration.days(60))), currentTime.add(new BN(duration.days(60)))], - [true, true, true], - [false, false, false], { from: token_owner } diff --git a/test/z_general_permission_manager_fuzzer.js b/test/z_general_permission_manager_fuzzer.js index b78b07b43..86d723299 100644 --- a/test/z_general_permission_manager_fuzzer.js +++ b/test/z_general_permission_manager_fuzzer.js @@ -353,18 +353,16 @@ contract("GeneralPermissionManager Fuzz", async (accounts) => { console.log("3"); if (randomPerms === "WHITELIST") { - let tx = await I_GeneralTransferManager.modifyWhitelist(accounts[j], fromTime, toTime, expiryTime, 1, false, { + let tx = await I_GeneralTransferManager.modifyKYCData(accounts[j], fromTime, toTime, expiryTime, { from: accounts[j] }); assert.equal(tx.logs[0].args._investor, accounts[j]); console.log("3.1"); - let tx2 = await I_GeneralTransferManager.modifyWhitelistMulti( + let tx2 = await I_GeneralTransferManager.modifyKYCDataMulti( [accounts[3], accounts[4]], [fromTime, fromTime], [toTime, toTime], [expiryTime, expiryTime], - [1, 1], - [false, false], { from: accounts[j] } ); console.log(tx2.logs[1].args); @@ -373,17 +371,15 @@ contract("GeneralPermissionManager Fuzz", async (accounts) => { } else { console.log("3.3"); await catchRevert( - I_GeneralTransferManager.modifyWhitelist(accounts[j], fromTime, toTime, expiryTime, 1, false, { from: accounts[j] }) + I_GeneralTransferManager.modifyKYCData(accounts[j], fromTime, toTime, expiryTime, { from: accounts[j] }) ); console.log("3.4"); await catchRevert( - I_GeneralTransferManager.modifyWhitelistMulti( + I_GeneralTransferManager.modifyKYCDataMulti( [accounts[3], accounts[4]], [fromTime, fromTime], [toTime, toTime], [expiryTime, expiryTime], - [1, 1], - [false, false], { from: accounts[j] } ) ); diff --git a/test/z_vesting_escrow_wallet.js b/test/z_vesting_escrow_wallet.js index 57f102052..c80744dc5 100644 --- a/test/z_vesting_escrow_wallet.js +++ b/test/z_vesting_escrow_wallet.js @@ -193,13 +193,11 @@ contract('VestingEscrowWallet', accounts => { it("Should Buy the tokens for token_owner", async() => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( token_owner, currentTime, currentTime, currentTime.add(new BN(durationUtil.days(10))), - true, - false, { from: token_owner, gas: 6000000 @@ -220,13 +218,11 @@ contract('VestingEscrowWallet', accounts => { it("Should whitelist investors", async() => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelistMulti( + let tx = await I_GeneralTransferManager.modifyKYCDataMulti( [I_VestingEscrowWallet.address, account_beneficiary1, account_beneficiary2, account_beneficiary3], [currentTime, currentTime, currentTime, currentTime], [currentTime, currentTime, currentTime, currentTime], [currentTime.add(new BN(durationUtil.days(10))), currentTime.add(new BN(durationUtil.days(10))), currentTime.add(new BN(durationUtil.days(10))), currentTime.add(new BN(durationUtil.days(10)))], - [true, true, true, true], - [false, false, false, false], { from: token_owner, gas: 6000000 diff --git a/test/za_datastore.js b/test/za_datastore.js index aa3860151..526583c21 100644 --- a/test/za_datastore.js +++ b/test/za_datastore.js @@ -218,6 +218,8 @@ contract("Data store", async (accounts) => { let arrLen = await I_DataStore.getUint256ArrayLength(key); await I_DataStore.insertUint256(key, new BN(10), { from: token_owner }); let arrElement = await I_DataStore.getUint256ArrayElement(key, arrLen.toNumber()); + let arrElements = await I_DataStore.getUint256ArrayElements(key, 0, arrLen.toNumber()); + assert.equal(arrElement.toNumber(), arrElements[arrLen.toNumber()].toNumber()); assert.equal(arrLen.toNumber() + 1, (await I_DataStore.getUint256ArrayLength(key)).toNumber(), "Incorrect Array Length"); assert.equal(arrElement.toNumber(), 10, "Incorrect array element"); }); @@ -226,6 +228,8 @@ contract("Data store", async (accounts) => { let arrLen = await I_DataStore.getBytes32ArrayLength(key); await I_DataStore.insertBytes32(key, bytes32data, { from: token_owner }); let arrElement = await I_DataStore.getBytes32ArrayElement(key, arrLen.toNumber()); + let arrElements = await I_DataStore.getBytes32ArrayElements(key, 0, arrLen.toNumber()); + assert.equal(arrElement, arrElements[arrLen.toNumber()]); assert.equal(arrLen.toNumber() + 1, (await I_DataStore.getBytes32ArrayLength(key)).toNumber(), "Incorrect Array Length"); assert.equal(arrElement, bytes32data, "Incorrect array element"); }); @@ -234,6 +238,8 @@ contract("Data store", async (accounts) => { let arrLen = await I_DataStore.getAddressArrayLength(key); await I_DataStore.insertAddress(key, address_one, { from: token_owner }); let arrElement = await I_DataStore.getAddressArrayElement(key, arrLen.toNumber()); + let arrElements = await I_DataStore.getAddressArrayElements(key, 0, arrLen.toNumber()); + assert.equal(arrElement, arrElements[arrLen.toNumber()]); assert.equal(arrLen.toNumber() + 1, (await I_DataStore.getAddressArrayLength(key)).toNumber(), "Incorrect Array Length"); assert.equal(arrElement, address_one, "Incorrect array element"); }); @@ -242,6 +248,8 @@ contract("Data store", async (accounts) => { let arrLen = await I_DataStore.getBoolArrayLength(key); await I_DataStore.insertBool(key, true, { from: token_owner }); let arrElement = await I_DataStore.getBoolArrayElement(key, arrLen.toNumber()); + let arrElements = await I_DataStore.getBoolArrayElements(key, 0, arrLen.toNumber()); + assert.equal(arrElement, arrElements[arrLen.toNumber()]); assert.equal(arrLen.toNumber() + 1, (await I_DataStore.getBoolArrayLength(key)).toNumber(), "Incorrect Array Length"); assert.equal(arrElement, true, "Incorrect array element"); }); diff --git a/test/zb_signed_transfer_manager.js b/test/zb_signed_transfer_manager.js index 105729b14..98a81ca35 100644 --- a/test/zb_signed_transfer_manager.js +++ b/test/zb_signed_transfer_manager.js @@ -160,13 +160,11 @@ contract("SignedTransferManager", accounts => { it("Should Buy the tokens", async () => { // Add the Investor in to the whitelist - let tx = await I_GeneralTransferManager.modifyWhitelist( + let tx = await I_GeneralTransferManager.modifyKYCData( account_investor1, currentTime, currentTime, currentTime.add(new BN(duration.days(10))), - true, - false, { from: account_issuer } diff --git a/truffle-config-gas.js b/truffle-config-gas.js new file mode 100644 index 000000000..8f690985f --- /dev/null +++ b/truffle-config-gas.js @@ -0,0 +1,81 @@ +require('babel-register'); +require('babel-polyfill'); +const fs = require('fs'); +const NonceTrackerSubprovider = require("web3-provider-engine/subproviders/nonce-tracker") + +const HDWalletProvider = require("truffle-hdwallet-provider-privkey"); + +module.exports = { + networks: { + development: { + host: 'localhost', + port: 8545, + network_id: '*', // Match any network id + gas: 7900000, + }, + mainnet: { + host: 'localhost', + port: 8545, + network_id: '1', // Match any network id + gas: 7900000, + gasPrice: 10000000000 + }, + ropsten: { + // provider: new HDWalletProvider(privKey, "http://localhost:8545"), + host: 'localhost', + port: 8545, + network_id: '3', // Match any network id + gas: 4500000, + gasPrice: 150000000000 + }, + rinkeby: { + // provider: new HDWalletProvider(privKey, "http://localhost:8545"), + host: 'localhost', + port: 8545, + network_id: '4', // Match any network id + gas: 7500000, + gasPrice: 10000000000 + }, + kovan: { + provider: () => { + const key = fs.readFileSync('./privKey').toString(); + let wallet = new HDWalletProvider(key, "https://kovan.infura.io/") + var nonceTracker = new NonceTrackerSubprovider() + wallet.engine._providers.unshift(nonceTracker) + nonceTracker.setEngine(wallet.engine) + return wallet + }, + network_id: '42', // Match any network id + gas: 7900000, + gasPrice: 5000000000 + }, + coverage: { + host: "localhost", + network_id: "*", + port: 8545, // <-- If you change this, also set the port option in .solcover.js. + gas: 0xfffffffff , // <-- Use this high gas value + gasPrice: 0x01 // <-- Use this low gas price + } + }, + compilers: { + solc: { + version: "native", + settings: { + optimizer: { + enabled: true, + runs: 200 + } + } + } + }, + mocha: { + enableTimeouts: false, + reporter: 'eth-gas-reporter', + reporterOptions : { + currency: 'USD', + gasPrice: 5, + onlyCalledMethods: true, + showTimeSpent: true + } + } +}; diff --git a/yarn.lock b/yarn.lock index acb5a45dc..04adc5fef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -33,10 +33,44 @@ valid-url "^1.0.9" yargs "^11.0.0" +"@types/concat-stream@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@types/concat-stream/-/concat-stream-1.6.0.tgz#394dbe0bb5fee46b38d896735e8b68ef2390d00d" + integrity sha1-OU2+C7X+5Gs42JZzXoto7yOQ0A0= + dependencies: + "@types/node" "*" + +"@types/form-data@0.0.33": + version "0.0.33" + resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-0.0.33.tgz#c9ac85b2a5fd18435b8c85d9ecb50e6d6c893ff8" + integrity sha1-yayFsqX9GENbjIXZ7LUObWyJP/g= + dependencies: + "@types/node" "*" + +"@types/node@*": + version "11.9.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-11.9.3.tgz#14adbb5ab8cd563f549fbae8dbe92e0b7d6e76cc" + integrity sha512-DMiqG51GwES/c4ScBY0u5bDlH44+oY8AeYHjY1SGCWidD7h08o1dfHue/TGK7REmif2KiJzaUskO+Q0eaeZ2fQ== + "@types/node@^10.3.2": version "10.12.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.2.tgz#d77f9faa027cadad9c912cd47f4f8b07b0fb0864" +"@types/node@^8.0.0": + version "8.10.40" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.40.tgz#4314888d5cd537945d73e9ce165c04cc550144a4" + integrity sha512-RRSjdwz63kS4u7edIwJUn8NqKLLQ6LyqF/X4+4jp38MBT3Vwetewi2N4dgJEshLbDwNgOJXNYoOwzVZUSSLhkQ== + +"@types/node@^9.3.0", "@types/node@^9.4.1": + version "9.6.42" + resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.42.tgz#96fd9c8cf15fbf2c16fe525fc2be97c49cdd0c2f" + integrity sha512-SpeVQJFekfnEaZZO1yl4je/36upII36L7gOT4DBx51B1GeAB45mmDb3a5OBQB+ZeFxVVOP37r8Owsl940G/fBg== + +"@types/qs@^6.2.31": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.5.1.tgz#a38f69c62528d56ba7bd1f91335a8004988d72f7" + integrity sha512-mNhVdZHdtKHMMxbqzNK3RzkBcN1cux3AvuCYGTvjEIQT2uheH3eCAyYsbMbh2Bq8nXkeOWs1kyDiF7geWRFQ4Q== + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -45,6 +79,13 @@ abbrev@1.0.x: version "1.0.9" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" +abi-decoder@^1.0.8: + version "1.2.0" + resolved "https://registry.yarnpkg.com/abi-decoder/-/abi-decoder-1.2.0.tgz#c42882dbb91b444805f0cd203a87a5cc3c22f4a8" + integrity sha512-y2OKSEW4gf2838Eavc56vQY9V46zaXkf3Jl1WpTfUBbzAVrXSr4JRZAAWv55Tv9s5WNz1rVgBgz5d2aJIL1QCg== + dependencies: + web3 "^0.18.4" + abstract-leveldown@~2.6.0: version "2.6.3" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz#1c5e8c6a5ef965ae8c35dfb3a8770c476b82c4b8" @@ -257,6 +298,11 @@ array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" +asap@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + asn1.js@^4.0.0: version "4.10.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" @@ -1387,7 +1433,7 @@ chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" -charenc@~0.0.1: +"charenc@>= 0.0.1", charenc@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" @@ -1472,6 +1518,16 @@ cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" +cli-table3@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" + integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== + dependencies: + object-assign "^4.1.0" + string-width "^2.1.1" + optionalDependencies: + colors "^1.1.2" + cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" @@ -1584,6 +1640,16 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" +concat-stream@^1.4.6, 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" + readable-stream "^2.2.2" + typedarray "^0.0.6" + console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" @@ -1711,7 +1777,7 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -crypt@~0.0.1: +"crypt@>= 0.0.1", crypt@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" @@ -2402,6 +2468,24 @@ eth-block-tracker@^2.2.2: pify "^2.3.0" tape "^4.6.3" +eth-gas-reporter@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/eth-gas-reporter/-/eth-gas-reporter-0.1.12.tgz#6b761e05c33ae85be47840dd07468ab51d473dd8" + integrity sha512-Ao5uiXSA5Ep5fi/YvGCsFJMelMKj0fMJkAvWYzPVe1h3Mg9Z7X3Rs51ovG9izFZH7wSqnqydiC6SKDhZWpxK2g== + dependencies: + abi-decoder "^1.0.8" + cli-table3 "^0.5.0" + colors "^1.1.2" + lodash "^4.17.4" + mocha "^4.1.0" + req-cwd "^2.0.0" + request "^2.83.0" + request-promise-native "^1.0.5" + sha1 "^1.1.1" + shelljs "^0.7.8" + solidity-parser-antlr "^0.2.10" + sync-request "^6.0.0" + 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" @@ -2956,7 +3040,7 @@ forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" -form-data@~2.3.2: +form-data@^2.2.0, form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" dependencies: @@ -3087,6 +3171,11 @@ 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" +get-port@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" + integrity sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw= + get-stream@^2.2.0: version "2.3.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" @@ -3362,6 +3451,18 @@ 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" +http-basic@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/http-basic/-/http-basic-7.0.0.tgz#82f0a506be942732ec8deebee80e746ef5736dba" + integrity sha1-gvClBr6UJzLsje6+6A50bvVzbbo= + dependencies: + "@types/concat-stream" "^1.6.0" + "@types/node" "^9.4.1" + caseless "~0.12.0" + concat-stream "^1.4.6" + http-response-object "^3.0.1" + parse-cache-control "^1.0.1" + http-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" @@ -3375,6 +3476,13 @@ http-https@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" +http-response-object@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-3.0.1.tgz#90174d44c27b5e797cf6efe51a043bc889ae64bf" + integrity sha512-6L0Fkd6TozA8kFSfh9Widst0wfza3U1Ex2RjJ6zNDK0vR1U1auUR6jY4Nn2Xl7CCy0ikFmxW1XcspVpb9RvwTg== + dependencies: + "@types/node" "^9.3.0" + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -4847,6 +4955,11 @@ parse-asn1@^5.0.0: evp_bytestokey "^1.0.0" pbkdf2 "^3.0.3" +parse-cache-control@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-cache-control/-/parse-cache-control-1.0.1.tgz#8eeab3e54fa56920fe16ba38f77fa21aacc2d74e" + integrity sha1-juqz5U+laSD+Fro493+iGqzC104= + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -5042,6 +5155,13 @@ promise-to-callback@^1.0.0: is-fn "^1.0.0" set-immediate-shim "^1.0.1" +promise@^8.0.0: + version "8.0.2" + resolved "https://registry.yarnpkg.com/promise/-/promise-8.0.2.tgz#9dcd0672192c589477d56891271bdc27547ae9f0" + integrity sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw== + dependencies: + asap "~2.0.6" + prompt@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/prompt/-/prompt-1.0.0.tgz#8e57123c396ab988897fb327fd3aedc3e735e4fe" @@ -5106,6 +5226,11 @@ qs@6.5.2, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" +qs@^6.4.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.6.0.tgz#a99c0f69a8d26bf7ef012f871cdabb0aee4424c2" + integrity sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA== + query-string@^5.0.1: version "5.1.1" resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" @@ -5232,7 +5357,7 @@ readable-stream@^1.0.33: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, 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: +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" dependencies: @@ -5350,18 +5475,41 @@ req-cwd@^1.0.1: dependencies: req-from "^1.0.1" +req-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/req-cwd/-/req-cwd-2.0.0.tgz#d4082b4d44598036640fb73ddea01ed53db49ebc" + integrity sha1-1AgrTURZgDZkD7c93qAe1T20nrw= + dependencies: + req-from "^2.0.0" + req-from@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/req-from/-/req-from-1.0.1.tgz#bf81da5147947d32d13b947dc12a58ad4587350e" dependencies: resolve-from "^2.0.0" +req-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/req-from/-/req-from-2.0.0.tgz#d74188e47f93796f4aa71df6ee35ae689f3e0e70" + integrity sha1-10GI5H+TeW9Kpx327jWuaJ8+DnA= + dependencies: + resolve-from "^3.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" dependencies: lodash "^4.13.1" +request-promise-native@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" + integrity sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU= + dependencies: + request-promise-core "1.1.1" + stealthy-require "^1.1.0" + tough-cookie ">=2.3.3" + request-promise@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-4.2.2.tgz#d1ea46d654a6ee4f8ee6a4fea1018c22911904b4" @@ -5371,7 +5519,7 @@ request-promise@^4.2.2: stealthy-require "^1.1.0" tough-cookie ">=2.3.3" -request@^2.67.0, request@^2.79.0, request@^2.81.0, request@^2.85.0, request@^2.88.0: +request@^2.67.0, request@^2.79.0, request@^2.81.0, request@^2.83.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" dependencies: @@ -5427,6 +5575,11 @@ resolve-from@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -5698,6 +5851,14 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +sha1@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/sha1/-/sha1-1.1.1.tgz#addaa7a93168f393f19eb2b15091618e2700f848" + integrity sha1-rdqnqTFo85PxnrKxUJFhjicA+Eg= + dependencies: + charenc ">= 0.0.1" + crypt ">= 0.0.1" + sha3@^1.1.0: version "1.2.2" resolved "https://registry.yarnpkg.com/sha3/-/sha3-1.2.2.tgz#a66c5098de4c25bc88336ec8b4817d005bca7ba9" @@ -5714,7 +5875,7 @@ shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" -shelljs@^0.7.4: +shelljs@^0.7.4, shelljs@^0.7.8: version "0.7.8" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" dependencies: @@ -5862,6 +6023,11 @@ solidity-docgen@^0.1.0: react-dom "^16.2.0" shelljs "^0.8.1" +solidity-parser-antlr@^0.2.10: + version "0.2.15" + resolved "https://registry.yarnpkg.com/solidity-parser-antlr/-/solidity-parser-antlr-0.2.15.tgz#4be687a0a53da268c6a07398e0cfb3168896d610" + integrity sha512-EzRI8/TR/ljTXkZAyAjb0w4G20wH2XM7pcNf87ifdV825AbUv7DkY7HmiZCTj6NeKtIx8Y1s0NZWPbj+JTp8Zw== + 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" @@ -6193,6 +6359,22 @@ swarm-js@0.1.37: tar.gz "^1.0.5" xhr-request-promise "^0.1.2" +sync-request@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/sync-request/-/sync-request-6.0.0.tgz#db867eccc4ed31bbcb9fa3732393a3413da582ed" + integrity sha512-jGNIAlCi9iU4X3Dm4oQnNQshDD3h0/1A7r79LyqjbjUnj69sX6mShAXlhRXgImsfVKtTcnra1jfzabdZvp+Lmw== + dependencies: + http-response-object "^3.0.1" + sync-rpc "^1.2.1" + then-request "^6.0.0" + +sync-rpc@^1.2.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/sync-rpc/-/sync-rpc-1.3.4.tgz#24bcbdb2ffcb98f23690c15b304660085cdd206c" + integrity sha512-Iug+t1ICVFenUcTnDu8WXFnT+k8IVoLKGh8VA3eXUtl2Rt9SjKX3YEv33OenABqpTPL9QEaHv1+CNn2LK8vMow== + dependencies: + get-port "^3.1.0" + table@^5.0.2: version "5.1.0" resolved "https://registry.yarnpkg.com/table/-/table-5.1.0.tgz#69a54644f6f01ad1628f8178715b408dc6bf11f7" @@ -6286,6 +6468,23 @@ text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" +then-request@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/then-request/-/then-request-6.0.0.tgz#2cab198e48f2d8e79c8c1ed260198368a4a0bcba" + integrity sha512-xA+7uEMc+jsQIoyySJ93Ad08Kuqnik7u6jLS5hR91Z3smAoCfL3M8/MqMlobAa9gzBfO9pA88A/AntfepkkMJQ== + dependencies: + "@types/concat-stream" "^1.6.0" + "@types/form-data" "0.0.33" + "@types/node" "^8.0.0" + "@types/qs" "^6.2.31" + caseless "~0.12.0" + concat-stream "^1.6.0" + form-data "^2.2.0" + http-basic "^7.0.0" + http-response-object "^3.0.1" + promise "^8.0.0" + qs "^6.4.0" + 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" @@ -6438,9 +6637,10 @@ truffle-wallet-provider@0.0.5: web3 "^0.18.2" web3-provider-engine "^8.4.0" -truffle@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/truffle/-/truffle-5.0.0.tgz#2e4e2eedc5583ae38c7227585e5177d6360fbc6d" +truffle@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/truffle/-/truffle-5.0.4.tgz#fc68cb6a6a35b46a7ca69eca7b64d161b491db3d" + integrity sha512-pZYFbU10Hb6PiTalJm+dB6s1qIZjE5qc0ux5fIgQ7Nj24zDrlYmOYruP3yhuqywwzr3PUHGPxr6hXuje0BFYoA== dependencies: app-module-path "^2.2.0" mocha "^4.1.0" @@ -6502,6 +6702,11 @@ typedarray-to-buffer@^3.1.2: 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"