Skip to content

Commit 108015d

Browse files
authored
Merge branch 'dev-3.0.0' into gtm-logic-refactor
2 parents 764683d + 92807d1 commit 108015d

36 files changed

+249
-79
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ 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+
* Allows an explicit token factory version to be used during creation of securityToken.
25+
* Rename the `getProtocolVersion()` to `getLatestProtocolVersion()`.
2426
* Return SecurityToken version in the `getSecurityTokenData()` function.
2527

2628
## GeneralTransferManager

contracts/STRGetter.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ contract STRGetter is EternalStorage {
222222
/**
223223
* @notice Gets Protocol version
224224
*/
225-
function getProtocolVersion() public view returns(uint8[] memory) {
225+
function getLatestProtocolVersion() public view returns(uint8[] memory) {
226226
return VersionUtils.unpack(uint24(getUintValue(Encoder.getKey("latestVersion"))));
227227
}
228228

contracts/SecurityTokenRegistry.sol

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ contract SecurityTokenRegistry is EternalStorage, Proxy {
104104
address _registrant,
105105
bool _fromAdmin,
106106
uint256 _usdFee,
107-
uint256 _polyFee
107+
uint256 _polyFee,
108+
uint256 _protocolVersion
108109
);
109110
// Emit after ticker registration
110111
event RegisterTicker(
@@ -487,41 +488,64 @@ contract SecurityTokenRegistry is EternalStorage, Proxy {
487488
* @param _ticker is the ticker symbol of the security token
488489
* @param _tokenDetails is the off-chain details of the token
489490
* @param _divisible is whether or not the token is divisible
491+
* @param _protocolVersion Version of securityToken contract
492+
* - `_protocolVersion` is the packed value of uin8[3] array (it will be calculated offchain)
493+
* - if _protocolVersion == 0 then latest version of securityToken will be generated
490494
*/
491495
function generateSecurityToken(
492496
string calldata _name,
493497
string calldata _ticker,
494498
string calldata _tokenDetails,
495-
bool _divisible
499+
bool _divisible,
500+
uint256 _protocolVersion
496501
)
497502
external
498503
whenNotPausedOrOwner
499504
{
505+
uint256 protocolVersion = _protocolVersion;
500506
require(bytes(_name).length > 0 && bytes(_ticker).length > 0, "Bad ticker");
507+
if (_protocolVersion == 0) {
508+
protocolVersion = getUintValue(Encoder.getKey("latestVersion"));
509+
}
510+
require(protocolVersion != uint256(0), "Invalid version");
501511
string memory ticker = Util.upper(_ticker);
502512
bytes32 statusKey = Encoder.getKey("registeredTickers_status", ticker);
503513
require(!getBoolValue(statusKey), "Already deployed");
504514
set(statusKey, true);
505515
require(_tickerOwner(ticker) == msg.sender, "Not authorised");
506516
/*solium-disable-next-line security/no-block-members*/
507517
require(getUintValue(Encoder.getKey("registeredTickers_expiryDate", ticker)) >= now, "Ticker expired");
508-
(uint256 _usdFee, uint256 _polyFee) = _takeFee(STLAUNCHFEE);
518+
_deployToken(_name, ticker, _tokenDetails, msg.sender, _divisible, protocolVersion);
519+
}
509520

510-
address newSecurityTokenAddress = ISTFactory(getAddressValue(Encoder.getKey("protocolVersionST", getUintValue(Encoder.getKey("latestVersion"))))).deployToken(
521+
function _deployToken(
522+
string memory _name,
523+
string memory _ticker,
524+
string memory _tokenDetails,
525+
address _issuer,
526+
bool _divisible,
527+
uint256 _protocolVersion
528+
)
529+
internal
530+
{
531+
(uint256 _usdFee, uint256 _polyFee) = _takeFee(STLAUNCHFEE);
532+
address newSecurityTokenAddress = ISTFactory(getAddressValue(Encoder.getKey("protocolVersionST", _protocolVersion))).deployToken(
511533
_name,
512-
ticker,
534+
_ticker,
513535
18,
514536
_tokenDetails,
515-
msg.sender,
537+
_issuer,
516538
_divisible,
517539
getAddressValue(POLYMATHREGISTRY)
518540
);
519541

520542
/*solium-disable-next-line security/no-block-members*/
521-
_storeSecurityTokenData(newSecurityTokenAddress, ticker, _tokenDetails, now);
522-
set(Encoder.getKey("tickerToSecurityToken", ticker), newSecurityTokenAddress);
543+
_storeSecurityTokenData(newSecurityTokenAddress, _ticker, _tokenDetails, now);
544+
set(Encoder.getKey("tickerToSecurityToken", _ticker), newSecurityTokenAddress);
523545
/*solium-disable-next-line security/no-block-members*/
524-
emit NewSecurityToken(ticker, _name, newSecurityTokenAddress, msg.sender, now, msg.sender, false, _usdFee, _polyFee);
546+
emit NewSecurityToken(
547+
_ticker, _name, newSecurityTokenAddress, msg.sender, now, msg.sender, false, _usdFee, _polyFee, _protocolVersion
548+
);
525549
}
526550

527551
/**
@@ -543,7 +567,7 @@ contract SecurityTokenRegistry is EternalStorage, Proxy {
543567
)
544568
external
545569
onlyOwner
546-
{
570+
{
547571
require(bytes(_name).length > 0 && bytes(_ticker).length > 0, "Bad data");
548572
require(bytes(_ticker).length <= 10, "Bad ticker");
549573
require(_deployedAt != 0 && _owner != address(0), "Bad data");
@@ -559,7 +583,9 @@ contract SecurityTokenRegistry is EternalStorage, Proxy {
559583
set(Encoder.getKey("tickerToSecurityToken", ticker), _securityToken);
560584
_modifyTicker(_owner, ticker, _name, registrationTime, expiryTime, true);
561585
_storeSecurityTokenData(_securityToken, ticker, _tokenDetails, _deployedAt);
562-
emit NewSecurityToken(ticker, _name, _securityToken, _owner, _deployedAt, msg.sender, true, uint256(0), uint256(0));
586+
emit NewSecurityToken(
587+
ticker, _name, _securityToken, _owner, _deployedAt, msg.sender, true, uint256(0), uint256(0), 0
588+
);
563589
}
564590

565591
/**

contracts/interfaces/ISecurityTokenRegistry.sol

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,22 @@ pragma solidity ^0.5.0;
55
*/
66
interface ISecurityTokenRegistry {
77
/**
8-
* @notice Creates a new Security Token and saves it to the registry
9-
* @param _name Name of the token
10-
* @param _ticker Ticker ticker of the security token
11-
* @param _tokenDetails Off-chain details of the token
12-
* @param _divisible Whether the token is divisible or not
13-
*/
14-
function generateSecurityToken(string calldata _name, string calldata _ticker, string calldata _tokenDetails, bool _divisible) external;
8+
* @notice Deploys an instance of a new Security Token and records it to the registry
9+
* @param _name is the name of the token
10+
* @param _ticker is the ticker symbol of the security token
11+
* @param _tokenDetails is the off-chain details of the token
12+
* @param _divisible is whether or not the token is divisible
13+
* @param _protocolVersion Version of securityToken contract
14+
* - `_protocolVersion` is the packed value of uin8[3] array (it will be calculated offchain)
15+
* - if _protocolVersion == 0 then latest version of securityToken will be generated
16+
*/
17+
function generateSecurityToken(
18+
string calldata _name,
19+
string calldata _ticker,
20+
string calldata _tokenDetails,
21+
bool _divisible,
22+
uint256 _protocolVersion
23+
) external;
1524

1625
/**
1726
* @notice Adds a new custom Security Token and saves it to the registry. (Token should follow the ISecurityToken interface)

contracts/mocks/STFactoryMock.sol

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
pragma solidity ^0.5.0;
2+
3+
import "./SecurityTokenMock.sol";
4+
import "../interfaces/ISTFactory.sol";
5+
import "../datastore/DataStoreFactory.sol";
6+
7+
/**
8+
* @title Proxy for deploying SecurityToken instances
9+
*/
10+
contract STFactoryMock is ISTFactory {
11+
address public transferManagerFactory;
12+
address public stDelegate;
13+
DataStoreFactory public dataStoreFactory;
14+
15+
constructor(address _transferManagerFactory, address _dataStoreFactory, address _stDelegate) public {
16+
transferManagerFactory = _transferManagerFactory;
17+
dataStoreFactory = DataStoreFactory(_dataStoreFactory);
18+
stDelegate = _stDelegate;
19+
}
20+
21+
/**
22+
* @notice deploys the token and adds default modules like the GeneralTransferManager.
23+
* Future versions of the proxy can attach different modules or pass different parameters.
24+
*/
25+
function deployToken(
26+
string calldata _name,
27+
string calldata _symbol,
28+
uint8 _decimals,
29+
string calldata _tokenDetails,
30+
address _issuer,
31+
bool _divisible,
32+
address _polymathRegistry
33+
)
34+
external
35+
returns(address)
36+
{
37+
SecurityTokenMock newSecurityToken = new SecurityTokenMock(
38+
_name,
39+
_symbol,
40+
_decimals,
41+
_divisible ? 1 : uint256(10) ** _decimals,
42+
_tokenDetails,
43+
_polymathRegistry,
44+
stDelegate
45+
);
46+
//NB When dataStore is generated, the security token address is automatically set via the constructor in DataStoreProxy.
47+
newSecurityToken.changeDataStore(dataStoreFactory.generateDataStore(address(newSecurityToken)));
48+
newSecurityToken.addModule(transferManagerFactory, "", 0, 0);
49+
newSecurityToken.transferOwnership(_issuer);
50+
return address(newSecurityToken);
51+
}
52+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
pragma solidity ^0.5.0;
2+
3+
import "../tokens/SecurityToken.sol";
4+
5+
/**
6+
* @title Security Token contract
7+
* @notice SecurityToken is an ERC1400 token with added capabilities:
8+
* @notice - Implements the ERC1400 Interface
9+
* @notice - Transfers are restricted
10+
* @notice - Modules can be attached to it to control its behaviour
11+
* @notice - ST should not be deployed directly, but rather the SecurityTokenRegistry should be used
12+
* @notice - ST does not inherit from ISecurityToken due to:
13+
* @notice - https://github.com/ethereum/solidity/issues/4847
14+
*/
15+
contract SecurityTokenMock is SecurityToken {
16+
17+
/**
18+
* @notice constructor
19+
* @param _name Name of the SecurityToken
20+
* @param _symbol Symbol of the Token
21+
* @param _decimals Decimals for the securityToken
22+
* @param _granularity granular level of the token
23+
* @param _tokenDetails Details of the token that are stored off-chain
24+
* @param _polymathRegistry Contract address of the polymath registry
25+
* @param _delegate Contract address of the delegate
26+
*/
27+
constructor(
28+
string memory _name,
29+
string memory _symbol,
30+
uint8 _decimals,
31+
uint256 _granularity,
32+
string memory _tokenDetails,
33+
address _polymathRegistry,
34+
address _delegate
35+
)
36+
public
37+
SecurityToken(_name, _symbol, _decimals, _granularity, _tokenDetails, _polymathRegistry,_delegate)
38+
{
39+
securityTokenVersion = SemanticVersion(2, 2, 0);
40+
}
41+
42+
43+
}

contracts/tokens/SecurityToken.sol

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import "../interfaces/ITransferManager.sol";
1616
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
1717
import "openzeppelin-solidity/contracts/utils/ReentrancyGuard.sol";
1818
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
19-
import "openzeppelin-solidity/contracts/utils/ReentrancyGuard.sol";
2019
import "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";
2120

2221
/**
@@ -144,7 +143,7 @@ contract SecurityToken is ERC20, ERC20Detailed, Ownable, ReentrancyGuard, Securi
144143
delegate = _delegate;
145144
tokenDetails = _tokenDetails;
146145
granularity = _granularity;
147-
securityTokenVersion = SemanticVersion(2, 0, 0);
146+
securityTokenVersion = SemanticVersion(3, 0, 0);
148147
}
149148

150149
/**

test/b_capped_sto.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ contract("CappedSTO", async (accounts) => {
174174
it("Should generate the new security token with the same symbol as registered above", async () => {
175175
await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner });
176176

177-
let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner });
177+
let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, 0, { from: token_owner });
178178

179179
// Verify the successful generation of the security token
180180
assert.equal(tx.logs[2].args._ticker, symbol, "SecurityToken doesn't get deployed");
@@ -622,7 +622,7 @@ contract("CappedSTO", async (accounts) => {
622622
it("POLY: Should generate the new security token with the same symbol as registered above", async () => {
623623
await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner });
624624

625-
let tx = await I_STRProxied.generateSecurityToken(P_name, P_symbol, P_tokenDetails, false, { from: token_owner });
625+
let tx = await I_STRProxied.generateSecurityToken(P_name, P_symbol, P_tokenDetails, false, 0, { from: token_owner });
626626

627627
// Verify the successful generation of the security token
628628
assert.equal(tx.logs[2].args._ticker, P_symbol, "SecurityToken doesn't get deployed");

test/c_checkpoints.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ contract("Checkpoints", async function(accounts) {
126126

127127
it("Should generate the new security token with the same symbol as registered above", async () => {
128128
await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner });
129-
let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner });
129+
let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, 0, { from: token_owner });
130130

131131
// Verify the successful generation of the security token
132132
assert.equal(tx.logs[2].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed");

test/d_count_transfer_manager.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ contract("CountTransferManager", async (accounts) => {
143143
it("Should generate the new security token with the same symbol as registered above", async () => {
144144
await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner });
145145

146-
let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner });
146+
let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, 0, { from: token_owner });
147147
// Verify the successful generation of the security token
148148
assert.equal(tx.logs[2].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed");
149149

@@ -363,7 +363,7 @@ contract("CountTransferManager", async (accounts) => {
363363

364364
await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner });
365365

366-
let tx2 = await I_STRProxied.generateSecurityToken(name, symbol2, tokenDetails, false, { from: token_owner });
366+
let tx2 = await I_STRProxied.generateSecurityToken(name, symbol2, tokenDetails, false, 0, { from: token_owner });
367367

368368
I_SecurityToken2 = await SecurityToken.at(tx2.logs[2].args._securityTokenAddress);
369369
stGetter2 = await STGetter.at(I_SecurityToken2.address);

0 commit comments

Comments
 (0)