Skip to content

Commit 733eebf

Browse files
authored
Merge pull request #560 from PolymathNetwork/add-isVolRestricted
Remove the investor array and add isVolRestricted flag for investors
2 parents 1f85d8b + cd45264 commit 733eebf

File tree

5 files changed

+140
-74
lines changed

5 files changed

+140
-74
lines changed
Lines changed: 111 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
pragma solidity ^0.5.0;
22

3+
import "../interfaces/IDataStore.sol";
34
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
45
import "../storage/modules/TransferManager/VolumeRestrictionTMStorage.sol";
56

67
library VolumeRestrictionLib {
78

89
using SafeMath for uint256;
910

11+
uint256 internal constant ONE = uint256(1);
12+
uint8 internal constant INDEX = uint8(2);
13+
bytes32 internal constant INVESTORFLAGS = "INVESTORFLAGS";
14+
bytes32 internal constant INVESTORSKEY = 0xdf3a8dd24acdd05addfc6aeffef7574d2de3f844535ec91e8e0f3e45dba96731; //keccak256(abi.encodePacked("INVESTORS"))
15+
bytes32 internal constant WHITELIST = "WHITELIST";
16+
1017
function _checkLengthOfArray(
1118
address[] memory _holders,
1219
uint256[] memory _allowedTokens,
@@ -28,60 +35,89 @@ library VolumeRestrictionLib {
2835
);
2936
}
3037

31-
function deleteHolderFromList(VolumeRestrictionTMStorage.RestrictedData storage data, address _holder, uint8 _typeOfPeriod) public {
38+
function deleteHolderFromList(
39+
mapping(address => uint8) storage holderToRestrictionType,
40+
address _holder,
41+
address _dataStore,
42+
uint8 _typeOfPeriod
43+
)
44+
public
45+
{
3246
// Deleting the holder if holder's type of Period is `Both` type otherwise
3347
// it will assign the given type `_typeOfPeriod` to the _holder typeOfPeriod
3448
// `_typeOfPeriod` it always be contrary to the removing restriction
3549
// if removing restriction is individual then typeOfPeriod is TypeOfPeriod.OneDay
3650
// in uint8 its value is 1. if removing restriction is daily individual then typeOfPeriod
3751
// is TypeOfPeriod.MultipleDays in uint8 its value is 0.
38-
if (data.restrictedHolders[_holder].typeOfPeriod != uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both)) {
39-
uint128 index = data.restrictedHolders[_holder].index;
40-
uint256 _len = data.restrictedAddresses.length;
41-
if (index != _len) {
42-
data.restrictedHolders[data.restrictedAddresses[_len - 1]].index = index;
43-
data.restrictedAddresses[index - 1] = data.restrictedAddresses[_len - 1];
44-
}
45-
delete data.restrictedHolders[_holder];
46-
data.restrictedAddresses.length--;
52+
if (holderToRestrictionType[_holder] != uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both)) {
53+
IDataStore dataStore = IDataStore(_dataStore);
54+
uint256 flags = dataStore.getUint256(_getKey(INVESTORFLAGS, _holder));
55+
flags = flags & ~(ONE << INDEX);
56+
dataStore.setUint256(_getKey(INVESTORFLAGS, _holder), flags);
4757
} else {
48-
data.restrictedHolders[_holder].typeOfPeriod = _typeOfPeriod;
58+
holderToRestrictionType[_holder] = _typeOfPeriod;
4959
}
5060
}
5161

52-
function addRestrictionData(VolumeRestrictionTMStorage.RestrictedData storage data, address _holder, uint8 _callFrom, uint256 _endTime) public {
53-
uint128 index = data.restrictedHolders[_holder].index;
54-
if (data.restrictedHolders[_holder].seen == 0) {
55-
data.restrictedAddresses.push(_holder);
56-
index = uint128(data.restrictedAddresses.length);
62+
function addRestrictionData(
63+
mapping(address => uint8) storage holderToRestrictionType,
64+
address _holder,
65+
uint8 _callFrom,
66+
uint256 _endTime,
67+
address _dataStore
68+
)
69+
public
70+
{
71+
IDataStore dataStore = IDataStore(_dataStore);
72+
73+
uint256 flags = dataStore.getUint256(_getKey(INVESTORFLAGS, _holder));
74+
if (!_isExistingInvestor(_holder, dataStore)) {
75+
dataStore.insertAddress(INVESTORSKEY, _holder);
76+
//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
77+
dataStore.setUint256(_getKey(WHITELIST, _holder), uint256(1));
5778
}
58-
uint8 _type = _getTypeOfPeriod(data.restrictedHolders[_holder].typeOfPeriod, _callFrom, _endTime);
59-
data.restrictedHolders[_holder] = VolumeRestrictionTMStorage.RestrictedHolder(uint8(1), _type, index);
79+
if (!_isVolRestricted(flags)) {
80+
flags = flags | (ONE << INDEX);
81+
dataStore.setUint256(_getKey(INVESTORFLAGS, _holder), flags);
82+
}
83+
uint8 _type = _getTypeOfPeriod(holderToRestrictionType[_holder], _callFrom, _endTime);
84+
holderToRestrictionType[_holder] = _type;
6085
}
6186

62-
function _getTypeOfPeriod(uint8 _currentTypeOfPeriod, uint8 _callFrom, uint256 _endTime) internal pure returns(uint8) {
63-
if (_currentTypeOfPeriod != _callFrom && _endTime != uint256(0))
64-
return uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both);
65-
else
66-
return _callFrom;
67-
}
6887

88+
/**
89+
* @notice Provide the restriction details of all the restricted addresses
90+
* @return address List of the restricted addresses
91+
* @return uint256 List of the tokens allowed to the restricted addresses corresponds to restricted address
92+
* @return uint256 List of the start time of the restriction corresponds to restricted address
93+
* @return uint256 List of the rolling period in days for a restriction corresponds to restricted address.
94+
* @return uint256 List of the end time of the restriction corresponds to restricted address.
95+
* @return uint8 List of the type of restriction to validate the value of the `allowedTokens`
96+
* of the restriction corresponds to restricted address
97+
*/
6998
function getRestrictionData(
70-
VolumeRestrictionTMStorage.RestrictedData storage _holderData,
71-
VolumeRestrictionTMStorage.IndividualRestrictions storage _individualRestrictions
72-
) public view returns(
73-
address[] memory allAddresses,
74-
uint256[] memory allowedTokens,
75-
uint256[] memory startTime,
76-
uint256[] memory rollingPeriodInDays,
77-
uint256[] memory endTime,
78-
uint8[] memory typeOfRestriction
79-
)
99+
mapping(address => uint8) storage holderToRestrictionType,
100+
VolumeRestrictionTMStorage.IndividualRestrictions storage _individualRestrictions,
101+
address _dataStore
102+
)
103+
public
104+
view
105+
returns(
106+
address[] memory allAddresses,
107+
uint256[] memory allowedTokens,
108+
uint256[] memory startTime,
109+
uint256[] memory rollingPeriodInDays,
110+
uint256[] memory endTime,
111+
uint8[] memory typeOfRestriction
112+
)
80113
{
81-
uint256 counter = 0;
82-
uint256 i = 0;
83-
for (i = 0; i < _holderData.restrictedAddresses.length; i++) {
84-
counter = counter + (_holderData.restrictedHolders[_holderData.restrictedAddresses[i]].typeOfPeriod == uint8(2) ? 2 : 1);
114+
address[] memory investors = IDataStore(_dataStore).getAddressArray(INVESTORSKEY);
115+
uint256 counter;
116+
uint256 i;
117+
for (i = 0; i < investors.length; i++) {
118+
if (_isVolRestricted(IDataStore(_dataStore).getUint256(_getKey(INVESTORFLAGS, investors[i])))) {
119+
counter = counter + (holderToRestrictionType[investors[i]] == uint8(2) ? 2 : 1);
120+
}
85121
}
86122
allAddresses = new address[](counter);
87123
allowedTokens = new uint256[](counter);
@@ -90,21 +126,23 @@ library VolumeRestrictionLib {
90126
endTime = new uint256[](counter);
91127
typeOfRestriction = new uint8[](counter);
92128
counter = 0;
93-
for (i = 0; i < _holderData.restrictedAddresses.length; i++) {
94-
allAddresses[counter] = _holderData.restrictedAddresses[i];
95-
if (_holderData.restrictedHolders[_holderData.restrictedAddresses[i]].typeOfPeriod == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.MultipleDays)) {
96-
_setValues(_individualRestrictions.individualRestriction[_holderData.restrictedAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter);
97-
}
98-
else if (_holderData.restrictedHolders[_holderData.restrictedAddresses[i]].typeOfPeriod == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.OneDay)) {
99-
_setValues(_individualRestrictions.individualDailyRestriction[_holderData.restrictedAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter);
100-
}
101-
else if (_holderData.restrictedHolders[_holderData.restrictedAddresses[i]].typeOfPeriod == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both)) {
102-
_setValues(_individualRestrictions.individualRestriction[_holderData.restrictedAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter);
129+
for (i = 0; i < investors.length; i++) {
130+
if (_isVolRestricted(IDataStore(_dataStore).getUint256(_getKey(INVESTORFLAGS, investors[i])))) {
131+
allAddresses[counter] = investors[i];
132+
if (holderToRestrictionType[investors[i]] == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.MultipleDays)) {
133+
_setValues(_individualRestrictions.individualRestriction[investors[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter);
134+
}
135+
else if (holderToRestrictionType[investors[i]] == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.OneDay)) {
136+
_setValues(_individualRestrictions.individualDailyRestriction[investors[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter);
137+
}
138+
else if (holderToRestrictionType[investors[i]] == uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both)) {
139+
_setValues(_individualRestrictions.individualRestriction[investors[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter);
140+
counter++;
141+
allAddresses[counter] = investors[i];
142+
_setValues(_individualRestrictions.individualDailyRestriction[investors[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter);
143+
}
103144
counter++;
104-
allAddresses[counter] = _holderData.restrictedAddresses[i];
105-
_setValues(_individualRestrictions.individualDailyRestriction[_holderData.restrictedAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter);
106145
}
107-
counter++;
108146
}
109147
}
110148

@@ -127,4 +165,26 @@ library VolumeRestrictionLib {
127165
typeOfRestriction[index] = uint8(restriction.typeOfRestriction);
128166
}
129167

168+
function _isVolRestricted(uint256 _flags) internal pure returns(bool) {
169+
uint256 volRestricted = (_flags >> INDEX) & ONE;
170+
return (volRestricted > 0 ? true : false);
171+
}
172+
173+
function _getTypeOfPeriod(uint8 _currentTypeOfPeriod, uint8 _callFrom, uint256 _endTime) internal pure returns(uint8) {
174+
if (_currentTypeOfPeriod != _callFrom && _endTime != uint256(0))
175+
return uint8(VolumeRestrictionTMStorage.TypeOfPeriod.Both);
176+
else
177+
return _callFrom;
178+
}
179+
180+
function _isExistingInvestor(address _investor, IDataStore dataStore) internal view returns(bool) {
181+
uint256 data = dataStore.getUint256(_getKey(WHITELIST, _investor));
182+
//extracts `added` from packed `_whitelistData`
183+
return uint8(data) == 0 ? false : true;
184+
}
185+
186+
function _getKey(bytes32 _key1, address _key2) internal pure returns(bytes32) {
187+
return bytes32(keccak256(abi.encodePacked(_key1, _key2)));
188+
}
189+
130190
}

contracts/modules/TransferManager/VolumeRestrictionTM.sol

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,14 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, TransferManager {
242242
_endTime,
243243
RestrictionType(_restrictionType)
244244
);
245-
VolumeRestrictionLib.addRestrictionData(holderData, _holder, uint8(TypeOfPeriod.MultipleDays), individualRestrictions.individualRestriction[_holder].endTime);
245+
VolumeRestrictionLib
246+
.addRestrictionData(
247+
holderToRestrictionType,
248+
_holder,
249+
uint8(TypeOfPeriod.MultipleDays),
250+
individualRestrictions.individualRestriction[_holder].endTime,
251+
getDataStore()
252+
);
246253
emit AddIndividualRestriction(
247254
_holder,
248255
_allowedTokens,
@@ -289,15 +296,22 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, TransferManager {
289296
_endTime,
290297
RestrictionType(_restrictionType)
291298
);
292-
VolumeRestrictionLib.addRestrictionData(holderData, _holder, uint8(TypeOfPeriod.OneDay), individualRestrictions.individualRestriction[_holder].endTime);
299+
VolumeRestrictionLib
300+
.addRestrictionData(
301+
holderToRestrictionType,
302+
_holder,
303+
uint8(TypeOfPeriod.OneDay),
304+
individualRestrictions.individualRestriction[_holder].endTime,
305+
getDataStore()
306+
);
293307
emit AddIndividualDailyRestriction(
294308
_holder,
295309
_allowedTokens,
296310
_startTime,
297311
1,
298312
_endTime,
299313
_restrictionType
300-
);
314+
);
301315
}
302316

303317
/**
@@ -454,7 +468,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, TransferManager {
454468
require(_holder != address(0));
455469
require(individualRestrictions.individualRestriction[_holder].endTime != 0);
456470
individualRestrictions.individualRestriction[_holder] = VolumeRestriction(0, 0, 0, 0, RestrictionType(0));
457-
VolumeRestrictionLib.deleteHolderFromList(holderData, _holder, uint8(TypeOfPeriod.OneDay));
471+
VolumeRestrictionLib.deleteHolderFromList(holderToRestrictionType, _holder, getDataStore(), uint8(TypeOfPeriod.OneDay));
458472
bucketData.userToBucket[_holder].lastTradedDayTime = 0;
459473
bucketData.userToBucket[_holder].sumOfLastPeriod = 0;
460474
bucketData.userToBucket[_holder].daysCovered = 0;
@@ -479,7 +493,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, TransferManager {
479493
require(_holder != address(0));
480494
require(individualRestrictions.individualDailyRestriction[_holder].endTime != 0);
481495
individualRestrictions.individualDailyRestriction[_holder] = VolumeRestriction(0, 0, 0, 0, RestrictionType(0));
482-
VolumeRestrictionLib.deleteHolderFromList(holderData, _holder, uint8(TypeOfPeriod.MultipleDays));
496+
VolumeRestrictionLib.deleteHolderFromList(holderToRestrictionType, _holder, getDataStore(), uint8(TypeOfPeriod.MultipleDays));
483497
bucketData.userToBucket[_holder].dailyLastTradedDayTime = 0;
484498
emit IndividualDailyRestrictionRemoved(_holder);
485499
}
@@ -1119,7 +1133,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, TransferManager {
11191133
uint256[] memory endTime,
11201134
uint8[] memory typeOfRestriction
11211135
) {
1122-
return VolumeRestrictionLib.getRestrictionData(holderData, individualRestrictions);
1136+
return VolumeRestrictionLib.getRestrictionData(holderToRestrictionType, individualRestrictions, getDataStore());
11231137
}
11241138

11251139
/**

contracts/modules/TransferManager/VolumeRestrictionTMFactory.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ contract VolumeRestrictionTMFactory is ModuleFactory {
4848
* @notice Type of the Module factory
4949
*/
5050
function getTypes() external view returns(uint8[] memory) {
51-
uint8[] memory res = new uint8[](1);
51+
uint8[] memory res = new uint8[](2);
5252
res[0] = 2;
53+
res[1] = 6;
5354
return res;
5455
}
5556

contracts/storage/modules/TransferManager/VolumeRestrictionTMStorage.sol

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,8 @@ contract VolumeRestrictionTMStorage {
99

1010
enum TypeOfPeriod { MultipleDays, OneDay, Both }
1111

12-
struct RestrictedHolder {
13-
// 1 represent true & 0 for false
14-
uint8 seen;
15-
// Type of period will be enum index of TypeOfPeriod enum
16-
uint8 typeOfPeriod;
17-
// Index of the array where the holder address lives
18-
uint128 index;
19-
}
20-
21-
struct RestrictedData {
22-
mapping(address => RestrictedHolder) restrictedHolders;
23-
address[] restrictedAddresses;
24-
}
25-
26-
// Restricted data (refernce from the VolumeRestrictionLib library )
27-
RestrictedData holderData;
12+
// Store the type of restriction corresponds to token holder address
13+
mapping(address => uint8) holderToRestrictionType;
2814

2915
struct VolumeRestriction {
3016
// If typeOfRestriction is `Percentage` then allowedTokens will be in

docs/investor_flags.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,10 @@
1919
<td> canNotBuyFromSto </td>
2020
<td> Defines if an Investor is restricted from participating in STOs</td>
2121
</tr>
22+
<tr>
23+
<td> 2 </td>
24+
<td> isVolRestricted </td>
25+
<td> Defines if an Investor has the trade volume restriction (VRTM) or not </td>
26+
</tr>
2227
</tbody>
2328
</table>

0 commit comments

Comments
 (0)