From a861ad93027681f73b5bfddddfd8557b6344f1ce Mon Sep 17 00:00:00 2001 From: satyam Date: Wed, 20 Feb 2019 16:58:58 +0530 Subject: [PATCH 1/3] remove the investor array and add isVolRestricted flag for investors --- contracts/libraries/VolumeRestrictionLib.sol | 166 ++++++++++++------ .../TransferManager/VolumeRestrictionTM.sol | 24 ++- .../VolumeRestrictionTMFactory.sol | 3 +- .../VolumeRestrictionTMStorage.sol | 18 +- test/y_volume_restriction_tm.js | 3 + 5 files changed, 143 insertions(+), 71 deletions(-) diff --git a/contracts/libraries/VolumeRestrictionLib.sol b/contracts/libraries/VolumeRestrictionLib.sol index 589256de1..026fef96e 100644 --- a/contracts/libraries/VolumeRestrictionLib.sol +++ b/contracts/libraries/VolumeRestrictionLib.sol @@ -1,5 +1,6 @@ pragma solidity ^0.5.0; +import "../interfaces/IDataStore.sol"; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "../storage/modules/TransferManager/VolumeRestrictionTMStorage.sol"; @@ -7,6 +8,12 @@ library VolumeRestrictionLib { using SafeMath for uint256; + uint256 internal constant ONE = uint256(1); + uint8 internal constant INDEX = uint8(2); + bytes32 internal constant INVESTORFLAGS = "INVESTORFLAGS"; + bytes32 internal constant INVESTORSKEY = 0xdf3a8dd24acdd05addfc6aeffef7574d2de3f844535ec91e8e0f3e45dba96731; //keccak256(abi.encodePacked("INVESTORS")) + bytes32 internal constant WHITELIST = "WHITELIST"; + function _checkLengthOfArray( address[] memory _holders, uint256[] memory _allowedTokens, @@ -28,60 +35,89 @@ library VolumeRestrictionLib { ); } - function deleteHolderFromList(VolumeRestrictionTMStorage.RestrictedData storage data, address _holder, uint8 _typeOfPeriod) public { + function deleteHolderFromList( + mapping(address => uint8) storage holderToRestrictionType, + address _holder, + address _dataStore, + uint8 _typeOfPeriod + ) + public + { // Deleting the holder if holder's type of Period is `Both` type otherwise // it will assign the given type `_typeOfPeriod` to the _holder typeOfPeriod // `_typeOfPeriod` it always be contrary to the removing restriction // if removing restriction is individual then typeOfPeriod is TypeOfPeriod.OneDay // in uint8 its value is 1. if removing restriction is daily individual then typeOfPeriod // is TypeOfPeriod.MultipleDays in uint8 its value is 0. - if (data.restrictedHolders[_holder].typeOfPeriod != uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both)) { - uint128 index = data.restrictedHolders[_holder].index; - uint256 _len = data.restrictedAddresses.length; - if (index != _len) { - data.restrictedHolders[data.restrictedAddresses[_len - 1]].index = index; - data.restrictedAddresses[index - 1] = data.restrictedAddresses[_len - 1]; - } - delete data.restrictedHolders[_holder]; - data.restrictedAddresses.length--; + if (holderToRestrictionType[_holder] != uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both)) { + IDataStore dataStore = IDataStore(_dataStore); + uint256 flags = dataStore.getUint256(_getKey(INVESTORFLAGS, _holder)); + flags = flags & ~(ONE << INDEX); + dataStore.setUint256(_getKey(INVESTORFLAGS, _holder), flags); } else { - data.restrictedHolders[_holder].typeOfPeriod = _typeOfPeriod; + holderToRestrictionType[_holder] = _typeOfPeriod; } } - function addRestrictionData(VolumeRestrictionTMStorage.RestrictedData storage data, address _holder, uint8 _callFrom, uint256 _endTime) public { - uint128 index = data.restrictedHolders[_holder].index; - if (data.restrictedHolders[_holder].seen == 0) { - data.restrictedAddresses.push(_holder); - index = uint128(data.restrictedAddresses.length); + function addRestrictionData( + mapping(address => uint8) storage holderToRestrictionType, + address _holder, + uint8 _callFrom, + uint256 _endTime, + address _dataStore + ) + public + { + IDataStore dataStore = IDataStore(_dataStore); + + uint256 flags = dataStore.getUint256(_getKey(INVESTORFLAGS, _holder)); + if (!_isExistingInvestor(_holder, dataStore)) { + dataStore.insertAddress(INVESTORSKEY, _holder); + //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, _holder), uint256(1)); } - uint8 _type = _getTypeOfPeriod(data.restrictedHolders[_holder].typeOfPeriod, _callFrom, _endTime); - data.restrictedHolders[_holder] = VolumeRestrictionTMStorage.RestrictedHolder(uint8(1), _type, index); + if (!_isVolRestricted(flags)) { + flags = flags | (ONE << INDEX); + dataStore.setUint256(_getKey(INVESTORFLAGS, _holder), flags); + } + uint8 _type = _getTypeOfPeriod(holderToRestrictionType[_holder], _callFrom, _endTime); + holderToRestrictionType[_holder] = _type; } - function _getTypeOfPeriod(uint8 _currentTypeOfPeriod, uint8 _callFrom, uint256 _endTime) internal pure returns(uint8) { - if (_currentTypeOfPeriod != _callFrom && _endTime != uint256(0)) - return uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both); - else - return _callFrom; - } + /** + * @notice Provide the restriction details of all the restricted addresses + * @return address List of the restricted addresses + * @return uint256 List of the tokens allowed to the restricted addresses corresponds to restricted address + * @return uint256 List of the start time of the restriction corresponds to restricted address + * @return uint256 List of the rolling period in days for a restriction corresponds to restricted address. + * @return uint256 List of the end time of the restriction corresponds to restricted address. + * @return uint8 List of the type of restriction to validate the value of the `allowedTokens` + * of the restriction corresponds to restricted address + */ function getRestrictionData( - VolumeRestrictionTMStorage.RestrictedData storage _holderData, - VolumeRestrictionTMStorage.IndividualRestrictions storage _individualRestrictions - ) public view returns( - address[] memory allAddresses, - uint256[] memory allowedTokens, - uint256[] memory startTime, - uint256[] memory rollingPeriodInDays, - uint256[] memory endTime, - uint8[] memory typeOfRestriction - ) + mapping(address => uint8) storage holderToRestrictionType, + VolumeRestrictionTMStorage.IndividualRestrictions storage _individualRestrictions, + address _dataStore + ) + public + view + returns( + address[] memory allAddresses, + uint256[] memory allowedTokens, + uint256[] memory startTime, + uint256[] memory rollingPeriodInDays, + uint256[] memory endTime, + uint8[] memory typeOfRestriction + ) { - uint256 counter = 0; - uint256 i = 0; - for (i = 0; i < _holderData.restrictedAddresses.length; i++) { - counter = counter + (_holderData.restrictedHolders[_holderData.restrictedAddresses[i]].typeOfPeriod == uint8(2) ? 2 : 1); + address[] memory investors = IDataStore(_dataStore).getAddressArray(INVESTORSKEY); + uint256 counter; + uint256 i; + for (i = 0; i < investors.length; i++) { + if (_isVolRestricted(IDataStore(_dataStore).getUint256(_getKey(INVESTORFLAGS, investors[i])))) { + counter = counter + (holderToRestrictionType[investors[i]] == uint8(2) ? 2 : 1); + } } allAddresses = new address[](counter); allowedTokens = new uint256[](counter); @@ -90,19 +126,29 @@ library VolumeRestrictionLib { endTime = new uint256[](counter); typeOfRestriction = new uint8[](counter); counter = 0; - for (i = 0; i < _holderData.restrictedAddresses.length; i++) { - allAddresses[counter] = _holderData.restrictedAddresses[i]; - if (_holderData.restrictedHolders[_holderData.restrictedAddresses[i]].typeOfPeriod == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.MultipleDays)) { - _setValues(_individualRestrictions.individualRestriction[_holderData.restrictedAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); - } - else if (_holderData.restrictedHolders[_holderData.restrictedAddresses[i]].typeOfPeriod == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.OneDay)) { - _setValues(_individualRestrictions.individualDailyRestriction[_holderData.restrictedAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); + for (i = 0; i < investors.length; i++) { + if (_isVolRestricted(IDataStore(_dataStore).getUint256(_getKey(INVESTORFLAGS, investors[i])))) { + uint256 typeValue = (holderToRestrictionType[investors[i]] == uint8(2) ? 2 : 1); + if (typeValue == 2) { + allAddresses[counter] = investors[i]; + counter++; + } + allAddresses[counter] = investors[i]; + counter++; } - else if (_holderData.restrictedHolders[_holderData.restrictedAddresses[i]].typeOfPeriod == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both)) { - _setValues(_individualRestrictions.individualRestriction[_holderData.restrictedAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); + } + counter = 0; + for (i = 0; i < allAddresses.length; i++) { + if (holderToRestrictionType[allAddresses[i]] == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.MultipleDays)) { + _setValues(_individualRestrictions.individualRestriction[allAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); + } + else if (holderToRestrictionType[allAddresses[i]] == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.OneDay)) { + _setValues(_individualRestrictions.individualDailyRestriction[allAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); + } + else if (holderToRestrictionType[allAddresses[i]] == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both)) { + _setValues(_individualRestrictions.individualRestriction[allAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); counter++; - allAddresses[counter] = _holderData.restrictedAddresses[i]; - _setValues(_individualRestrictions.individualDailyRestriction[_holderData.restrictedAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); + _setValues(_individualRestrictions.individualDailyRestriction[allAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); } counter++; } @@ -127,4 +173,26 @@ library VolumeRestrictionLib { typeOfRestriction[index] = uint8(restriction.typeOfRestriction); } + function _isVolRestricted(uint256 _flags) internal pure returns(bool) { + uint256 volRestricted = (_flags >> INDEX) & ONE; + return (volRestricted > 0 ? true : false); + } + + function _getTypeOfPeriod(uint8 _currentTypeOfPeriod, uint8 _callFrom, uint256 _endTime) internal pure returns(uint8) { + if (_currentTypeOfPeriod != _callFrom && _endTime != uint256(0)) + return uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both); + else + return _callFrom; + } + + 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; + } + + function _getKey(bytes32 _key1, address _key2) internal pure returns(bytes32) { + return bytes32(keccak256(abi.encodePacked(_key1, _key2))); + } + } diff --git a/contracts/modules/TransferManager/VolumeRestrictionTM.sol b/contracts/modules/TransferManager/VolumeRestrictionTM.sol index c57cc4929..7fe125d55 100644 --- a/contracts/modules/TransferManager/VolumeRestrictionTM.sol +++ b/contracts/modules/TransferManager/VolumeRestrictionTM.sol @@ -245,7 +245,14 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, TransferManager { _endTime, RestrictionType(_restrictionType) ); - VolumeRestrictionLib.addRestrictionData(holderData, _holder, uint8(TypeOfPeriod.MultipleDays), individualRestrictions.individualRestriction[_holder].endTime); + VolumeRestrictionLib + .addRestrictionData( + holderToRestrictionType, + _holder, + uint8(TypeOfPeriod.MultipleDays), + individualRestrictions.individualRestriction[_holder].endTime, + getDataStore() + ); emit AddIndividualRestriction( _holder, _allowedTokens, @@ -292,7 +299,14 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, TransferManager { _endTime, RestrictionType(_restrictionType) ); - VolumeRestrictionLib.addRestrictionData(holderData, _holder, uint8(TypeOfPeriod.OneDay), individualRestrictions.individualRestriction[_holder].endTime); + VolumeRestrictionLib + .addRestrictionData( + holderToRestrictionType, + _holder, + uint8(TypeOfPeriod.OneDay), + individualRestrictions.individualDailyRestriction[_holder].endTime, + getDataStore() + ); emit AddIndividualDailyRestriction( _holder, _allowedTokens, @@ -457,7 +471,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, TransferManager { require(_holder != address(0)); require(individualRestrictions.individualRestriction[_holder].endTime != 0); individualRestrictions.individualRestriction[_holder] = VolumeRestriction(0, 0, 0, 0, RestrictionType(0)); - VolumeRestrictionLib.deleteHolderFromList(holderData, _holder, uint8(TypeOfPeriod.OneDay)); + VolumeRestrictionLib.deleteHolderFromList(holderToRestrictionType, _holder, getDataStore(), uint8(TypeOfPeriod.OneDay)); bucketData.userToBucket[_holder].lastTradedDayTime = 0; bucketData.userToBucket[_holder].sumOfLastPeriod = 0; bucketData.userToBucket[_holder].daysCovered = 0; @@ -482,7 +496,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, TransferManager { require(_holder != address(0)); require(individualRestrictions.individualDailyRestriction[_holder].endTime != 0); individualRestrictions.individualDailyRestriction[_holder] = VolumeRestriction(0, 0, 0, 0, RestrictionType(0)); - VolumeRestrictionLib.deleteHolderFromList(holderData, _holder, uint8(TypeOfPeriod.MultipleDays)); + VolumeRestrictionLib.deleteHolderFromList(holderToRestrictionType, _holder, getDataStore(), uint8(TypeOfPeriod.MultipleDays)); bucketData.userToBucket[_holder].dailyLastTradedDayTime = 0; emit IndividualDailyRestrictionRemoved(_holder); } @@ -1122,7 +1136,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, TransferManager { uint256[] memory endTime, uint8[] memory typeOfRestriction ) { - return VolumeRestrictionLib.getRestrictionData(holderData, individualRestrictions); + return VolumeRestrictionLib.getRestrictionData(holderToRestrictionType, individualRestrictions, getDataStore()); } /** diff --git a/contracts/modules/TransferManager/VolumeRestrictionTMFactory.sol b/contracts/modules/TransferManager/VolumeRestrictionTMFactory.sol index 77ed2c7bd..0502ab61f 100644 --- a/contracts/modules/TransferManager/VolumeRestrictionTMFactory.sol +++ b/contracts/modules/TransferManager/VolumeRestrictionTMFactory.sol @@ -48,8 +48,9 @@ contract VolumeRestrictionTMFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[] memory) { - uint8[] memory res = new uint8[](1); + uint8[] memory res = new uint8[](2); res[0] = 2; + res[1] = 6; return res; } diff --git a/contracts/storage/modules/TransferManager/VolumeRestrictionTMStorage.sol b/contracts/storage/modules/TransferManager/VolumeRestrictionTMStorage.sol index 0c88cbd65..00228124a 100644 --- a/contracts/storage/modules/TransferManager/VolumeRestrictionTMStorage.sol +++ b/contracts/storage/modules/TransferManager/VolumeRestrictionTMStorage.sol @@ -9,22 +9,8 @@ contract VolumeRestrictionTMStorage { enum TypeOfPeriod { MultipleDays, OneDay, Both } - struct RestrictedHolder { - // 1 represent true & 0 for false - uint8 seen; - // Type of period will be enum index of TypeOfPeriod enum - uint8 typeOfPeriod; - // Index of the array where the holder address lives - uint128 index; - } - - struct RestrictedData { - mapping(address => RestrictedHolder) restrictedHolders; - address[] restrictedAddresses; - } - - // Restricted data (refernce from the VolumeRestrictionLib library ) - RestrictedData holderData; + // Store the type of restriction corresponds to token holder address + mapping(address => uint8) holderToRestrictionType; struct VolumeRestriction { // If typeOfRestriction is `Percentage` then allowedTokens will be in diff --git a/test/y_volume_restriction_tm.js b/test/y_volume_restriction_tm.js index e915aaa16..35a192699 100644 --- a/test/y_volume_restriction_tm.js +++ b/test/y_volume_restriction_tm.js @@ -791,11 +791,14 @@ contract('VolumeRestrictionTransferManager', accounts => { assert.equal(tx.logs[0].args._holder, account_investor3); assert.equal(tx.logs[0].args._typeOfRestriction, 0); assert.equal((tx.logs[0].args._allowedTokens).toString(), new BN(web3.utils.toWei("6"))); + console.log("HELLO HOW DO you DO"); let data = await I_VolumeRestrictionTM.getRestrictionData.call(); await printRestrictedData(data); + console.log("HELLO HOW DO you DO12"); assert.equal(data[0].length, 2); assert.equal(data[0][1], account_investor3); let dataRestriction = await I_VolumeRestrictionTM.getIndividualDailyRestriction.call(account_investor3); + console.log("HELLO HOW DO you DO123"); console.log(` *** Individual Daily restriction data *** Allowed Tokens: ${dataRestriction[0].div(new BN(10).pow(new BN(18))).toString()} From aa2fc688ea5abcd5597ca2d2f4f968965e212b65 Mon Sep 17 00:00:00 2001 From: satyam Date: Thu, 21 Feb 2019 16:49:27 +0530 Subject: [PATCH 2/3] minor fix in the contract --- contracts/libraries/VolumeRestrictionLib.sol | 30 +++++++------------ .../TransferManager/VolumeRestrictionTM.sol | 4 +-- test/y_volume_restriction_tm.js | 3 -- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/contracts/libraries/VolumeRestrictionLib.sol b/contracts/libraries/VolumeRestrictionLib.sol index 026fef96e..9d30711b4 100644 --- a/contracts/libraries/VolumeRestrictionLib.sol +++ b/contracts/libraries/VolumeRestrictionLib.sol @@ -128,29 +128,21 @@ library VolumeRestrictionLib { counter = 0; for (i = 0; i < investors.length; i++) { if (_isVolRestricted(IDataStore(_dataStore).getUint256(_getKey(INVESTORFLAGS, investors[i])))) { - uint256 typeValue = (holderToRestrictionType[investors[i]] == uint8(2) ? 2 : 1); - if (typeValue == 2) { - allAddresses[counter] = investors[i]; + allAddresses[counter] = investors[i]; + if (holderToRestrictionType[investors[i]] == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.MultipleDays)) { + _setValues(_individualRestrictions.individualRestriction[investors[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); + } + else if (holderToRestrictionType[investors[i]] == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.OneDay)) { + _setValues(_individualRestrictions.individualDailyRestriction[investors[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); + } + else if (holderToRestrictionType[investors[i]] == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both)) { + _setValues(_individualRestrictions.individualRestriction[investors[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); counter++; + allAddresses[counter] = investors[i]; + _setValues(_individualRestrictions.individualDailyRestriction[investors[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); } - allAddresses[counter] = investors[i]; - counter++; - } - } - counter = 0; - for (i = 0; i < allAddresses.length; i++) { - if (holderToRestrictionType[allAddresses[i]] == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.MultipleDays)) { - _setValues(_individualRestrictions.individualRestriction[allAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); - } - else if (holderToRestrictionType[allAddresses[i]] == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.OneDay)) { - _setValues(_individualRestrictions.individualDailyRestriction[allAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); - } - else if (holderToRestrictionType[allAddresses[i]] == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both)) { - _setValues(_individualRestrictions.individualRestriction[allAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); counter++; - _setValues(_individualRestrictions.individualDailyRestriction[allAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); } - counter++; } } diff --git a/contracts/modules/TransferManager/VolumeRestrictionTM.sol b/contracts/modules/TransferManager/VolumeRestrictionTM.sol index 7fe125d55..d96563041 100644 --- a/contracts/modules/TransferManager/VolumeRestrictionTM.sol +++ b/contracts/modules/TransferManager/VolumeRestrictionTM.sol @@ -304,7 +304,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, TransferManager { holderToRestrictionType, _holder, uint8(TypeOfPeriod.OneDay), - individualRestrictions.individualDailyRestriction[_holder].endTime, + individualRestrictions.individualRestriction[_holder].endTime, getDataStore() ); emit AddIndividualDailyRestriction( @@ -314,7 +314,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, TransferManager { 1, _endTime, _restrictionType - ); + ); } /** diff --git a/test/y_volume_restriction_tm.js b/test/y_volume_restriction_tm.js index 35a192699..e915aaa16 100644 --- a/test/y_volume_restriction_tm.js +++ b/test/y_volume_restriction_tm.js @@ -791,14 +791,11 @@ contract('VolumeRestrictionTransferManager', accounts => { assert.equal(tx.logs[0].args._holder, account_investor3); assert.equal(tx.logs[0].args._typeOfRestriction, 0); assert.equal((tx.logs[0].args._allowedTokens).toString(), new BN(web3.utils.toWei("6"))); - console.log("HELLO HOW DO you DO"); let data = await I_VolumeRestrictionTM.getRestrictionData.call(); await printRestrictedData(data); - console.log("HELLO HOW DO you DO12"); assert.equal(data[0].length, 2); assert.equal(data[0][1], account_investor3); let dataRestriction = await I_VolumeRestrictionTM.getIndividualDailyRestriction.call(account_investor3); - console.log("HELLO HOW DO you DO123"); console.log(` *** Individual Daily restriction data *** Allowed Tokens: ${dataRestriction[0].div(new BN(10).pow(new BN(18))).toString()} From cd4526418247f0ca5e65ce0b1d45ce3ee0796b7b Mon Sep 17 00:00:00 2001 From: satyam Date: Thu, 21 Feb 2019 17:39:55 +0530 Subject: [PATCH 3/3] update docs --- docs/investor_flags.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/investor_flags.md b/docs/investor_flags.md index 9ccf74473..0b8fb9c38 100644 --- a/docs/investor_flags.md +++ b/docs/investor_flags.md @@ -19,5 +19,10 @@ canNotBuyFromSto Defines if an Investor is restricted from participating in STOs + + 2 + isVolRestricted + Defines if an Investor has the trade volume restriction (VRTM) or not +