11pragma solidity ^ 0.5.0 ;
22
3+ import "../interfaces/IDataStore.sol " ;
34import "openzeppelin-solidity/contracts/math/SafeMath.sol " ;
45import "../storage/modules/TransferManager/VolumeRestrictionTMStorage.sol " ;
56
67library 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}
0 commit comments