Skip to content

Commit b83785c

Browse files
authored
Merge pull request #567 from PolymathNetwork/add-version-getSecurityTokenData
Add version to `getSecurityTokenData` (referenced directly from token using getVersion)
2 parents a87995f + f6daaa4 commit b83785c

File tree

56 files changed

+413
-315
lines changed

Some content is hidden

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

56 files changed

+413
-315
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ All notable changes to this project will be documented in this file.
2121
* Replaced `updatePolyTokenAddress()` function with `updateFromRegistry()` in `SecurityTokenRegistry`.
2222
* Migrate all the getters of `SecurityTokenRegsitry.sol` to `STRGetter.sol` contract.
2323
* Removed `_polyToken` parameter from `initialize` function in `SecurityTokenRegistry`.
24+
* Return SecurityToken version in the `getSecurityTokenData()` function.
2425

2526
## GeneralTransferManager
2627
* `modifyWhitelist()` function renamed to `modifyKYCData()`.

contracts/STRGetter.sol

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pragma solidity ^0.5.0;
22

33
import "./storage/EternalStorage.sol";
4+
import "./interfaces/ISecurityToken.sol";
45
import "./libraries/Util.sol";
56
import "./libraries/Encoder.sol";
67
import "./interfaces/IOwnable.sol";
@@ -199,13 +200,15 @@ contract STRGetter is EternalStorage {
199200
* @return address is the issuer of the security Token.
200201
* @return string is the details of the security token.
201202
* @return uint256 is the timestamp at which security Token was deployed.
203+
* @return version of the securityToken
202204
*/
203-
function getSecurityTokenData(address _securityToken) external view returns (string memory, address, string memory, uint256) {
205+
function getSecurityTokenData(address _securityToken) external view returns (string memory, address, string memory, uint256, uint8[] memory) {
204206
return (
205207
getStringValue(Encoder.getKey("securityTokens_ticker", _securityToken)),
206208
IOwnable(_securityToken).owner(),
207209
getStringValue(Encoder.getKey("securityTokens_tokenDetails", _securityToken)),
208-
getUintValue(Encoder.getKey("securityTokens_deployedAt", _securityToken))
210+
getUintValue(Encoder.getKey("securityTokens_deployedAt", _securityToken)),
211+
ISecurityToken(_securityToken).getVersion()
209212
);
210213
}
211214

contracts/interfaces/ISecurityTokenRegistry.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,10 @@ interface ISecurityTokenRegistry {
7979
* @return string Symbol of the Security Token.
8080
* @return address Address of the issuer of Security Token.
8181
* @return string Details of the Token.
82-
* @return uint256 Timestamp at which Security Token get launched on Polymath platform.
82+
* @return uint256 Timestamp at which Security Token get launched on Polymath platform
83+
* @return version of the securityToken
8384
*/
84-
function getSecurityTokenData(address _securityToken) external view returns(string memory, address, string memory, uint256);
85+
function getSecurityTokenData(address _securityToken) external view returns(string memory, address, string memory, uint256, uint8[] memory);
8586

8687
/**
8788
* @notice Get the current STFactory Address
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 & 9 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
{
144144
_validDividendIndex(_dividendIndex);
145145
Dividend storage dividend = dividends[_dividendIndex];
@@ -161,8 +161,7 @@ contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module {
161161
uint256 _start,
162162
uint256 _iterations
163163
) public
164-
withPerm(DISTRIBUTE)
165-
164+
withPerm(OPERATOR)
166165
{
167166
_validDividendIndex(_dividendIndex);
168167
Dividend storage dividend = dividends[_dividendIndex];
@@ -393,8 +392,8 @@ contract DividendCheckpoint is DividendCheckpointStorage, ICheckpoint, Module {
393392
*/
394393
function getPermissions() public view returns(bytes32[] memory) {
395394
bytes32[] memory allPermissions = new bytes32[](2);
396-
allPermissions[0] = DISTRIBUTE;
397-
allPermissions[1] = MANAGE;
395+
allPermissions[0] = ADMIN;
396+
allPermissions[1] = OPERATOR;
398397
return allPermissions;
399398
}
400399

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)