Skip to content

Commit 01101d0

Browse files
maxsam4adamdossa
authored andcommitted
Protocol upgrade fixes (#733)
* Update tags, types, lower & upper bounds (#725) * Make useModule backwards compatible * Make deployToken backwards compatible (#726) * Make deployToken backwards compatible * Small fix for scheduledCheckpoint * Updated STR interface * Removed extra event * Fix interface mismatch * cleaning up as per the audit recommendation (#722)
1 parent 5ab283c commit 01101d0

33 files changed

+109
-84
lines changed

contracts/ModuleRegistry.sol

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage {
4343
bytes32 constant POLYMATHREGISTRY = 0x90eeab7c36075577c7cc5ff366e389fefa8a18289b949bab3529ab4471139d4d; //keccak256("polymathRegistry")
4444
bytes32 constant FEATURE_REGISTRY = 0xed9ca06607835ad25ecacbcb97f2bc414d4a51ecf391b5ae42f15991227ab146; //keccak256("featureRegistry")
4545
bytes32 constant SECURITY_TOKEN_REGISTRY = 0x12ada4f7ee6c2b7b933330be61fefa007a1f497dc8df1b349b48071a958d7a81; //keccak256("securityTokenRegistry")
46-
46+
4747
///////////////
4848
//// Modifiers
4949
///////////////
@@ -118,6 +118,18 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage {
118118
return IFeatureRegistry(getAddressValue(FEATURE_REGISTRY)).getFeatureStatus("customModulesAllowed");
119119
}
120120

121+
122+
/**
123+
* @notice Called by a SecurityToken (2.x) to check if the ModuleFactory is verified or appropriate custom module
124+
* @dev ModuleFactory reputation increases by one every time it is deployed(used) by a ST.
125+
* @dev Any module can be added during token creation without being registered if it is defined in the token proxy deployment contract
126+
* @dev The feature switch for custom modules is labelled "customModulesAllowed"
127+
* @param _moduleFactory is the address of the relevant module factory
128+
*/
129+
function useModule(address _moduleFactory) external {
130+
useModule(_moduleFactory, false);
131+
}
132+
121133
/**
122134
* @notice Called by a SecurityToken to check if the ModuleFactory is verified or appropriate custom module
123135
* @dev ModuleFactory reputation increases by one every time it is deployed(used) by a ST.
@@ -126,7 +138,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage {
126138
* @param _moduleFactory is the address of the relevant module factory
127139
* @param _isUpgrade whether or not the function is being called as a result of an upgrade
128140
*/
129-
function useModule(address _moduleFactory, bool _isUpgrade) external nonReentrant {
141+
function useModule(address _moduleFactory, bool _isUpgrade) public nonReentrant {
130142
if (_customModules()) {
131143
require(
132144
getBoolValue(Encoder.getKey("verified", _moduleFactory)) || getAddressValue(Encoder.getKey("factoryOwner", _moduleFactory))
@@ -155,8 +167,8 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage {
155167
*/
156168
function isCompatibleModule(address _moduleFactory, address _securityToken) public view returns(bool) {
157169
uint8[] memory _latestVersion = ISecurityToken(_securityToken).getVersion();
158-
uint8[] memory _lowerBound = IModuleFactory(_moduleFactory).lowerSTVersionBounds();
159-
uint8[] memory _upperBound = IModuleFactory(_moduleFactory).upperSTVersionBounds();
170+
uint8[] memory _lowerBound = IModuleFactory(_moduleFactory).getLowerSTVersionBounds();
171+
uint8[] memory _upperBound = IModuleFactory(_moduleFactory).getUpperSTVersionBounds();
160172
bool _isLowerAllowed = VersionUtils.lessThanOrEqual(_lowerBound, _latestVersion);
161173
bool _isUpperAllowed = VersionUtils.greaterThanOrEqual(_upperBound, _latestVersion);
162174
return (_isLowerAllowed && _isUpperAllowed);
@@ -183,7 +195,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage {
183195
//Enforce type uniqueness
184196
uint256 i;
185197
uint256 j;
186-
uint8[] memory moduleTypes = moduleFactory.types();
198+
uint8[] memory moduleTypes = moduleFactory.getTypes();
187199
for (i = 1; i < moduleTypes.length; i++) {
188200
for (j = 0; j < i; j++) {
189201
require(moduleTypes[i] != moduleTypes[j], "Type mismatch");
@@ -304,14 +316,14 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage {
304316
uint256 i;
305317
uint256 j;
306318
for (i = 0; i < _modules.length; i++) {
307-
counter = counter + IModuleFactory(_modules[i]).tags().length;
319+
counter = counter + IModuleFactory(_modules[i]).getTags().length;
308320
}
309321
bytes32[] memory tags = new bytes32[](counter);
310322
address[] memory modules = new address[](counter);
311323
bytes32[] memory tempTags;
312324
counter = 0;
313325
for (i = 0; i < _modules.length; i++) {
314-
tempTags = IModuleFactory(_modules[i]).tags();
326+
tempTags = IModuleFactory(_modules[i]).getTags();
315327
for (j = 0; j < tempTags.length; j++) {
316328
tags[counter] = tempTags[j];
317329
modules[counter] = _modules[i];

contracts/SecurityTokenRegistry.sol

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ contract SecurityTokenRegistry is EternalStorage, Proxy {
108108
// Emit when ownership of the ticker gets changed
109109
event ChangeTickerOwnership(string _ticker, address indexed _oldOwner, address indexed _newOwner);
110110
// Emit at the time of launching a new security token of version 3.0+
111-
event NewSecurityTokenCreated(
111+
event NewSecurityToken(
112112
string _ticker,
113113
string _name,
114114
address indexed _securityTokenAddress,
@@ -173,10 +173,14 @@ contract SecurityTokenRegistry is EternalStorage, Proxy {
173173
* @dev Throws if called by any account other than the owner.
174174
*/
175175
modifier onlyOwner() {
176-
require(msg.sender == owner(), "Only owner");
176+
_onlyOwner();
177177
_;
178178
}
179179

180+
function _onlyOwner() internal view {
181+
require(msg.sender == owner(), "Only owner");
182+
}
183+
180184
modifier onlyOwnerOrSelf() {
181185
require(msg.sender == owner() || msg.sender == address(this), "Only owner or self");
182186
_;
@@ -639,7 +643,7 @@ contract SecurityTokenRegistry is EternalStorage, Proxy {
639643
_ticker, _name, newSecurityTokenAddress, issuer, now, issuer, false, _polyFee
640644
);
641645
} else {
642-
emit NewSecurityTokenCreated(
646+
emit NewSecurityToken(
643647
_ticker, _name, newSecurityTokenAddress, issuer, now, issuer, false, _usdFee, _polyFee, _protocolVersion
644648
);
645649
}
@@ -691,15 +695,24 @@ contract SecurityTokenRegistry is EternalStorage, Proxy {
691695
internal
692696
returns(address newSecurityTokenAddress)
693697
{
698+
// In v2.x of STFactory, the final argument to deployToken is the PolymathRegistry.
699+
// In v3.x of STFactory, the final argument to deployToken is the Treasury wallet.
700+
uint8[] memory upperLimit = new uint8[](3);
701+
upperLimit[0] = 2;
702+
upperLimit[1] = 99;
703+
upperLimit[2] = 99;
704+
if (VersionUtils.lessThanOrEqual(VersionUtils.unpack(uint24(_protocolVersion)), upperLimit)) {
705+
_wallet = getAddressValue(POLYMATHREGISTRY);
706+
}
707+
694708
newSecurityTokenAddress = ISTFactory(getAddressValue(Encoder.getKey("protocolVersionST", _protocolVersion))).deployToken(
695709
_name,
696710
_ticker,
697711
18,
698712
_tokenDetails,
699713
_issuer,
700714
_divisible,
701-
_wallet,
702-
getAddressValue(POLYMATHREGISTRY)
715+
_wallet
703716
);
704717

705718
/*solium-disable-next-line security/no-block-members*/
@@ -739,7 +752,7 @@ contract SecurityTokenRegistry is EternalStorage, Proxy {
739752
set(Encoder.getKey("tickerToSecurityToken", ticker), _securityToken);
740753
_modifyTicker(_owner, ticker, registrationTime, expiryTime, true);
741754
_storeSecurityTokenData(_securityToken, ticker, _tokenDetails, _deployedAt);
742-
emit NewSecurityTokenCreated(
755+
emit NewSecurityToken(
743756
ticker, ISecurityToken(_securityToken).name(), _securityToken, _owner, _deployedAt, msg.sender, true, uint256(0), uint256(0), 0
744757
);
745758
}
@@ -951,5 +964,4 @@ contract SecurityTokenRegistry is EternalStorage, Proxy {
951964
function owner() public view returns(address) {
952965
return getAddressValue(OWNER);
953966
}
954-
955967
}

contracts/interfaces/IModuleFactory.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ interface IModuleFactory {
4747
/**
4848
* @notice Type of the Module factory
4949
*/
50-
function types() external view returns(uint8[] memory moduleTypes);
50+
function getTypes() external view returns(uint8[] memory moduleTypes);
5151

5252
/**
5353
* @notice Get the tags related to the module factory
5454
*/
55-
function tags() external view returns(bytes32[] memory moduleTags);
55+
function getTags() external view returns(bytes32[] memory moduleTags);
5656

5757
/**
5858
* @notice Used to change the setup fee
@@ -83,13 +83,13 @@ interface IModuleFactory {
8383
* @notice Used to get the lower bound
8484
* @return Lower bound
8585
*/
86-
function lowerSTVersionBounds() external view returns(uint8[] memory lowerBounds);
86+
function getLowerSTVersionBounds() external view returns(uint8[] memory lowerBounds);
8787

8888
/**
8989
* @notice Used to get the upper bound
9090
* @return Upper bound
9191
*/
92-
function upperSTVersionBounds() external view returns(uint8[] memory upperBounds);
92+
function getUpperSTVersionBounds() external view returns(uint8[] memory upperBounds);
9393

9494
/**
9595
* @notice Updates the tags of the ModuleFactory

contracts/interfaces/IModuleRegistry.sol

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ interface IModuleRegistry {
2727
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
2828

2929

30+
/**
31+
* @notice Called by a security token (2.x) to notify the registry it is using a module
32+
* @param _moduleFactory is the address of the relevant module factory
33+
*/
34+
function useModule(address _moduleFactory) external;
35+
3036
/**
3137
* @notice Called by a security token to notify the registry it is using a module
3238
* @param _moduleFactory is the address of the relevant module factory

contracts/interfaces/ISTFactory.sol

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ interface ISTFactory {
2323
* @param _issuer is the owner of the Security Token
2424
* @param _divisible whether the token is divisible or not
2525
* @param _treasuryWallet Ethereum address which will holds the STs.
26-
* @param _polymathRegistry is the address of the Polymath Registry contract
2726
*/
2827
function deployToken(
2928
string calldata _name,
@@ -32,10 +31,9 @@ interface ISTFactory {
3231
string calldata _tokenDetails,
3332
address _issuer,
3433
bool _divisible,
35-
address _treasuryWallet,
36-
address _polymathRegistry
37-
)
38-
external
34+
address _treasuryWallet //In v2.x this is the Polymath Registry
35+
)
36+
external
3937
returns(address tokenAddress);
4038

4139
/**

contracts/interfaces/ISecurityTokenRegistry.sol

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ interface ISecurityTokenRegistry {
2424
// Emit when ownership of the ticker gets changed
2525
event ChangeTickerOwnership(string _ticker, address indexed _oldOwner, address indexed _newOwner);
2626
// Emit at the time of launching a new security token of version 3.0+
27-
event NewSecurityTokenCreated(
27+
event NewSecurityToken(
2828
string _ticker,
2929
string _name,
3030
address indexed _securityTokenAddress,
@@ -244,8 +244,7 @@ interface ISecurityTokenRegistry {
244244
string memory tokenSymbol,
245245
address tokenAddress,
246246
string memory tokenDetails,
247-
uint256 tokenTime,
248-
uint8[] memory tokenVersion
247+
uint256 tokenTime
249248
);
250249

251250
/**

contracts/mocks/MockFactory.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ contract MockFactory is DummySTOFactory {
2929
/**
3030
* @notice Type of the Module factory
3131
*/
32-
function types() external view returns(uint8[] memory) {
32+
function getTypes() external view returns(uint8[] memory) {
3333
if (!typesSwitch) {
3434
uint8[] memory res = new uint8[](0);
3535
return res;

contracts/mocks/MockWrongTypeFactory.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ contract MockWrongTypeFactory is MockBurnFactory {
2828
/**
2929
* @notice Type of the Module factory
3030
*/
31-
function types() external view returns(uint8[] memory) {
31+
function getTypes() external view returns(uint8[] memory) {
3232
uint8[] memory res = new uint8[](1);
3333
res[0] = 4;
3434
return res;

contracts/mocks/TestSTOFactory.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ contract TestSTOFactory is DummySTOFactory {
2828
/**
2929
* @notice Gets the tags related to the module factory
3030
*/
31-
function tags() external view returns(bytes32[] memory) {
31+
function getTags() external view returns(bytes32[] memory) {
3232
bytes32[] memory availableTags = new bytes32[](4);
3333
availableTags[0] = "Test";
3434
availableTags[1] = "Non-refundable";

contracts/modules/Checkpoint/Voting/PLCR/PLCRVotingCheckpoint.sol

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ contract PLCRVotingCheckpoint is PLCRVotingCheckpointStorage, VotingCheckpoint {
5353
withPerm(ADMIN)
5454
{
5555
uint256 startTime = now;
56-
uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint();
56+
uint256 checkpointId = securityToken.createCheckpoint();
5757
_createBallotWithCheckpoint(_commitDuration, _revealDuration, _noOfProposals, _quorumPercentage, checkpointId, startTime);
5858
}
5959

@@ -78,7 +78,7 @@ contract PLCRVotingCheckpoint is PLCRVotingCheckpointStorage, VotingCheckpoint {
7878
withPerm(ADMIN)
7979
{
8080
// validate the checkpointId, It should be less than or equal to the current checkpointId of the securityToken
81-
require(_checkpointId <= ISecurityToken(securityToken).currentCheckpointId(), "Invalid checkpoint Id");
81+
require(_checkpointId <= securityToken.currentCheckpointId(), "Invalid checkpoint Id");
8282
_createBallotWithCheckpoint(_commitDuration, _revealDuration, _noOfProposals, _quorumPercentage, _checkpointId, _startTime);
8383
}
8484

@@ -140,7 +140,7 @@ contract PLCRVotingCheckpoint is PLCRVotingCheckpointStorage, VotingCheckpoint {
140140
require(ballot.investorToProposal[msg.sender].secretVote == bytes32(0), "Already voted");
141141
require(ballot.isActive, "Inactive ballot");
142142
// Get the balance of the voter (i.e `msg.sender`) at the checkpoint on which ballot was created.
143-
uint256 weight = ISecurityToken(securityToken).balanceOfAt(msg.sender, ballot.checkpointId);
143+
uint256 weight = securityToken.balanceOfAt(msg.sender, ballot.checkpointId);
144144
require(weight > 0, "Zero weight is not allowed");
145145
// Update the storage value. Assigned `0` as vote option it will be updated when voter reveals its vote.
146146
ballot.investorToProposal[msg.sender] = Vote(0, _secretVote);
@@ -170,7 +170,7 @@ contract PLCRVotingCheckpoint is PLCRVotingCheckpointStorage, VotingCheckpoint {
170170
"Invalid vote"
171171
);
172172
// Get the balance of the voter (i.e `msg.sender`) at the checkpoint on which ballot was created.
173-
uint256 weight = ISecurityToken(securityToken).balanceOfAt(msg.sender, ballot.checkpointId);
173+
uint256 weight = securityToken.balanceOfAt(msg.sender, ballot.checkpointId);
174174
bytes32 secretVote = ballot.investorToProposal[msg.sender].secretVote;
175175
// update the storage values
176176
ballot.proposalToVotes[_choiceOfProposal] = ballot.proposalToVotes[_choiceOfProposal].add(weight);
@@ -283,7 +283,7 @@ contract PLCRVotingCheckpoint is PLCRVotingCheckpointStorage, VotingCheckpoint {
283283
uint256 i = 0;
284284
uint256 counter = 0;
285285
uint256 maxWeight = 0;
286-
uint256 supplyAtCheckpoint = ISecurityToken(securityToken).totalSupplyAt(ballot.checkpointId);
286+
uint256 supplyAtCheckpoint = securityToken.totalSupplyAt(ballot.checkpointId);
287287
uint256 quorumWeight = (supplyAtCheckpoint.mul(ballot.quorum)).div(10 ** 18);
288288
voteWeighting = new uint256[](ballot.totalProposals);
289289
for (i = 0; i < ballot.totalProposals; i++) {
@@ -342,7 +342,7 @@ contract PLCRVotingCheckpoint is PLCRVotingCheckpointStorage, VotingCheckpoint {
342342
Ballot memory ballot = ballots[_ballotId];
343343
return (
344344
ballot.quorum,
345-
ISecurityToken(securityToken).totalSupplyAt(ballot.checkpointId),
345+
securityToken.totalSupplyAt(ballot.checkpointId),
346346
ballot.checkpointId,
347347
ballot.startTime,
348348
(uint256(ballot.startTime).add(uint256(ballot.commitDuration))).add(uint256(ballot.revealDuration)),

contracts/modules/Experimental/Mixed/ScheduledCheckpoint.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ contract ScheduledCheckpoint is ICheckpoint, TransferManager {
5757
*/
5858
function addSchedule(bytes32 _name, uint256 _startTime, uint256 _interval, TimeUnit _timeUnit) external {
5959
_onlySecurityTokenOwner();
60+
require(_name != bytes32(""), "Empty name");
6061
require(_startTime > now, "Start time must be in the future");
6162
require(schedules[_name].name == bytes32(0), "Name already in use");
6263
schedules[_name].name = _name;
@@ -75,6 +76,7 @@ contract ScheduledCheckpoint is ICheckpoint, TransferManager {
7576
*/
7677
function removeSchedule(bytes32 _name) external {
7778
_onlySecurityTokenOwner();
79+
require(_name != bytes32(""), "Empty name");
7880
require(schedules[_name].name == _name, "Name does not exist");
7981
uint256 index = schedules[_name].index;
8082
names[index] = names[names.length - 1];

contracts/modules/ModuleFactory.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@ contract ModuleFactory is IModuleFactory, Ownable {
5050
/**
5151
* @notice Type of the Module factory
5252
*/
53-
function types() external view returns(uint8[] memory) {
53+
function getTypes() external view returns(uint8[] memory) {
5454
return typesData;
5555
}
5656

5757
/**
5858
* @notice Get the tags related to the module factory
5959
*/
60-
function tags() external view returns(bytes32[] memory) {
60+
function getTags() external view returns(bytes32[] memory) {
6161
return tagsData;
6262
}
6363

@@ -154,15 +154,15 @@ contract ModuleFactory is IModuleFactory, Ownable {
154154
* @notice Used to get the lower bound
155155
* @return lower bound
156156
*/
157-
function lowerSTVersionBounds() external view returns(uint8[] memory) {
157+
function getLowerSTVersionBounds() external view returns(uint8[] memory) {
158158
return VersionUtils.unpack(compatibleSTVersionRange["lowerBound"]);
159159
}
160160

161161
/**
162162
* @notice Used to get the upper bound
163163
* @return upper bound
164164
*/
165-
function upperSTVersionBounds() external view returns(uint8[] memory) {
165+
function getUpperSTVersionBounds() external view returns(uint8[] memory) {
166166
return VersionUtils.unpack(compatibleSTVersionRange["upperBound"]);
167167
}
168168

contracts/modules/TransferManager/TransferManager.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ contract TransferManager is ITransferManager, Module {
2626
*/
2727
function getTokensByPartition(bytes32 _partition, address _tokenHolder, uint256 /*_additionalBalance*/) external view returns(uint256) {
2828
if (_partition == UNLOCKED)
29-
return ISecurityToken(securityToken).balanceOf(_tokenHolder);
29+
return securityToken.balanceOf(_tokenHolder);
3030
return uint256(0);
3131
}
3232

0 commit comments

Comments
 (0)