Skip to content

Commit 43f3cb6

Browse files
authored
Merge pull request #566 from PolymathNetwork/takeSP-export
Refactor takeSnapShot
2 parents 892c6ff + 733eebf commit 43f3cb6

File tree

52 files changed

+401
-310
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+401
-310
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/Checkpoint/DividendCheckpoint.sol

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,15 @@ contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module {
7979
* @notice Creates a checkpoint on the security token
8080
* @return Checkpoint ID
8181
*/
82-
function createCheckpoint() public withPerm(CHECKPOINT) returns(uint256) {
82+
function createCheckpoint() public withPerm(OPERATOR) returns(uint256) {
8383
return ISecurityToken(securityToken).createCheckpoint();
8484
}
8585

8686
/**
8787
* @notice Function to clear and set list of excluded addresses used for future dividends
8888
* @param _excluded Addresses of investors
8989
*/
90-
function setDefaultExcluded(address[] memory _excluded) public withPerm(MANAGE) {
90+
function setDefaultExcluded(address[] memory _excluded) public withPerm(ADMIN) {
9191
require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many excluded addresses");
9292
for (uint256 j = 0; j < _excluded.length; j++) {
9393
require(_excluded[j] != address(0), "Invalid address");
@@ -105,7 +105,7 @@ contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module {
105105
* @param _investors Addresses of investors
106106
* @param _withholding Withholding tax for individual investors (multiplied by 10**16)
107107
*/
108-
function setWithholding(address[] memory _investors, uint256[] memory _withholding) public withPerm(MANAGE) {
108+
function setWithholding(address[] memory _investors, uint256[] memory _withholding) public withPerm(ADMIN) {
109109
require(_investors.length == _withholding.length, "Mismatched input lengths");
110110
/*solium-disable-next-line security/no-block-members*/
111111
emit SetWithholding(_investors, _withholding);
@@ -120,7 +120,7 @@ contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module {
120120
* @param _investors Addresses of investor
121121
* @param _withholding Withholding tax for all investors (multiplied by 10**16)
122122
*/
123-
function setWithholdingFixed(address[] memory _investors, uint256 _withholding) public withPerm(MANAGE) {
123+
function setWithholdingFixed(address[] memory _investors, uint256 _withholding) public withPerm(ADMIN) {
124124
require(_withholding <= 10 ** 18, "Incorrect withholding tax");
125125
/*solium-disable-next-line security/no-block-members*/
126126
emit SetWithholdingFixed(_investors, _withholding);
@@ -139,7 +139,7 @@ contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module {
139139
address payable[] memory _payees
140140
)
141141
public
142-
withPerm(DISTRIBUTE)
142+
withPerm(OPERATOR)
143143
validDividendIndex(_dividendIndex)
144144
{
145145
Dividend storage dividend = dividends[_dividendIndex];
@@ -161,7 +161,7 @@ contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module {
161161
uint256 _start,
162162
uint256 _iterations
163163
) public
164-
withPerm(DISTRIBUTE)
164+
withPerm(OPERATOR)
165165
validDividendIndex(_dividendIndex)
166166
{
167167
Dividend storage dividend = dividends[_dividendIndex];
@@ -391,8 +391,8 @@ contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module {
391391
*/
392392
function getPermissions() public view returns(bytes32[] memory) {
393393
bytes32[] memory allPermissions = new bytes32[](2);
394-
allPermissions[0] = DISTRIBUTE;
395-
allPermissions[1] = MANAGE;
394+
allPermissions[0] = ADMIN;
395+
allPermissions[1] = OPERATOR;
396396
return allPermissions;
397397
}
398398

contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ contract ERC20DividendCheckpoint is ERC20DividendCheckpointStorage, DividendChec
5656
bytes32 _name
5757
)
5858
external
59-
withPerm(MANAGE)
59+
withPerm(ADMIN)
6060
{
6161
createDividendWithExclusions(_maturity, _expiry, _token, _amount, excluded, _name);
6262
}
@@ -79,7 +79,7 @@ contract ERC20DividendCheckpoint is ERC20DividendCheckpointStorage, DividendChec
7979
bytes32 _name
8080
)
8181
external
82-
withPerm(MANAGE)
82+
withPerm(ADMIN)
8383
{
8484
_createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, excluded, _name);
8585
}
@@ -102,7 +102,7 @@ contract ERC20DividendCheckpoint is ERC20DividendCheckpointStorage, DividendChec
102102
bytes32 _name
103103
)
104104
public
105-
withPerm(MANAGE)
105+
withPerm(ADMIN)
106106
{
107107
uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint();
108108
_createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, checkpointId, _excluded, _name);
@@ -128,7 +128,7 @@ contract ERC20DividendCheckpoint is ERC20DividendCheckpointStorage, DividendChec
128128
bytes32 _name
129129
)
130130
public
131-
withPerm(MANAGE)
131+
withPerm(ADMIN)
132132
{
133133
_createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, _excluded, _name);
134134
}
@@ -251,7 +251,7 @@ contract ERC20DividendCheckpoint is ERC20DividendCheckpointStorage, DividendChec
251251
* @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends
252252
* @param _dividendIndex Dividend to reclaim
253253
*/
254-
function reclaimDividend(uint256 _dividendIndex) external withPerm(MANAGE) {
254+
function reclaimDividend(uint256 _dividendIndex) external withPerm(OPERATOR) {
255255
require(_dividendIndex < dividends.length, "Invalid dividend");
256256
/*solium-disable-next-line security/no-block-members*/
257257
require(now >= dividends[_dividendIndex].expiry, "Dividend expiry in future");
@@ -267,7 +267,7 @@ contract ERC20DividendCheckpoint is ERC20DividendCheckpointStorage, DividendChec
267267
* @notice Allows issuer to withdraw withheld tax
268268
* @param _dividendIndex Dividend to withdraw from
269269
*/
270-
function withdrawWithholding(uint256 _dividendIndex) external withPerm(MANAGE) {
270+
function withdrawWithholding(uint256 _dividendIndex) external withPerm(OPERATOR) {
271271
require(_dividendIndex < dividends.length, "Invalid dividend");
272272
Dividend storage dividend = dividends[_dividendIndex];
273273
uint256 remainingWithheld = dividend.totalWithheld.sub(dividend.totalWithheldWithdrawn);

0 commit comments

Comments
 (0)