Skip to content

Commit

Permalink
Merge pull request #224 from PolymathNetwork/freeze-minting
Browse files Browse the repository at this point in the history
Freeze Minting Permanently
  • Loading branch information
Stephane Gosselin committed Aug 30, 2018
2 parents ad97605 + d64b8b1 commit bb50297
Show file tree
Hide file tree
Showing 25 changed files with 845 additions and 411 deletions.
37 changes: 37 additions & 0 deletions contracts/FeatureRegistry.sol
@@ -0,0 +1,37 @@
pragma solidity ^0.4.24;

import "./ReclaimTokens.sol";
import "./interfaces/IFeatureRegistry.sol";

/**
* @title Registry for managing polymath feature switches
*/
contract FeatureRegistry is IFeatureRegistry, ReclaimTokens {

mapping (bytes32 => bool) public featureStatus;

event LogChangeFeatureStatus(string _nameKey, bool _newStatus);

/**
* @notice Get the status of a feature
* @param _nameKey is the key for the feature status mapping
* @return bool
*/
function getFeatureStatus(string _nameKey) external view returns(bool) {
bytes32 key = keccak256(bytes(_nameKey));
return featureStatus[key];
}

/**
* @notice change a feature status
* @param _nameKey is the key for the feature status mapping
* @param _newStatus is the new feature status
*/
function setFeatureStatus(string _nameKey, bool _newStatus) public onlyOwner {
bytes32 key = keccak256(bytes(_nameKey));
require(featureStatus[key] != _newStatus, "New feature status must be different than existing status");
emit LogChangeFeatureStatus(_nameKey, _newStatus);
featureStatus[key] = _newStatus;
}

}
2 changes: 2 additions & 0 deletions contracts/RegistryUpdater.sol
Expand Up @@ -9,6 +9,7 @@ contract RegistryUpdater is Ownable {
address public moduleRegistry;
address public securityTokenRegistry;
address public tickerRegistry;
address public featureRegistry;
address public polyToken;

constructor (address _polymathRegistry) public {
Expand All @@ -20,6 +21,7 @@ contract RegistryUpdater is Ownable {
moduleRegistry = PolymathRegistry(polymathRegistry).getAddress("ModuleRegistry");
securityTokenRegistry = PolymathRegistry(polymathRegistry).getAddress("SecurityTokenRegistry");
tickerRegistry = PolymathRegistry(polymathRegistry).getAddress("TickerRegistry");
featureRegistry = PolymathRegistry(polymathRegistry).getAddress("FeatureRegistry");
polyToken = PolymathRegistry(polymathRegistry).getAddress("PolyToken");
}

Expand Down
15 changes: 15 additions & 0 deletions contracts/interfaces/IFeatureRegistry.sol
@@ -0,0 +1,15 @@
pragma solidity ^0.4.24;

/**
* @title Interface for managing polymath feature switches
*/
interface IFeatureRegistry {

/**
* @notice Get the status of a feature
* @param _nameKey is the key for the feature status mapping
* @return bool
*/
function getFeatureStatus(string _nameKey) external view returns(bool);

}
9 changes: 2 additions & 7 deletions contracts/interfaces/ISecurityToken.sol
Expand Up @@ -154,14 +154,9 @@ interface ISecurityToken {
function unfreezeTransfers() external;

/**
* @notice End token minting period permanently for Issuer
* @notice End token minting period permanently
*/
function finishMintingIssuer() external;

/**
* @notice End token minting period permanently for STOs
*/
function finishMintingSTO() external;
function freezeMinting() external;

/**
* @notice mints new tokens and assigns them to the target _investor.
Expand Down
106 changes: 49 additions & 57 deletions contracts/tokens/SecurityToken.sol
Expand Up @@ -5,6 +5,7 @@ import "../interfaces/IPolyToken.sol";
import "../interfaces/IModule.sol";
import "../interfaces/IModuleFactory.sol";
import "../interfaces/IModuleRegistry.sol";
import "../interfaces/IFeatureRegistry.sol";
import "../modules/TransferManager/ITransferManager.sol";
import "../modules/PermissionManager/IPermissionManager.sol";
import "../interfaces/ITokenBurner.sol";
Expand Down Expand Up @@ -49,8 +50,11 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr
// Reference to token burner contract
ITokenBurner public tokenBurner;

// Use to halt all the transactions
bool public freeze = false;
// Use to temporarily halt all transactions
bool public transfersFrozen;

// Use to permanently halt all minting
bool public mintingFrozen;

struct ModuleData {
bytes32 name;
Expand All @@ -66,9 +70,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr
mapping (address => Checkpoint[]) public checkpointBalances;
Checkpoint[] public checkpointTotalSupply;

bool public finishedIssuerMinting = false;
bool public finishedSTOMinting = false;

mapping (bytes4 => bool) transferFunctions;

// Module list should be order agnostic!
Expand Down Expand Up @@ -97,36 +98,35 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr
event LogModuleRemoved(uint8 indexed _type, address _module, uint256 _timestamp);
// Emit when the budget allocated to a module is changed
event LogModuleBudgetChanged(uint8 indexed _moduleType, address _module, uint256 _budget);
// Emit when all the transfers get freeze
event LogFreezeTransfers(bool _freeze, uint256 _timestamp);
// Emit when transfers are frozen or unfrozen
event LogFreezeTransfers(bool _status, uint256 _timestamp);
// Emit when new checkpoint created
event LogCheckpointCreated(uint256 indexed _checkpointId, uint256 _timestamp);
// Emit when the minting get finished for the Issuer
event LogFinishMintingIssuer(uint256 _timestamp);
// Emit when the minting get finished for the STOs
event LogFinishMintingSTO(uint256 _timestamp);
// Emit when is permanently frozen by the issuer
event LogFreezeMinting(uint256 _timestamp);
// Change the STR address in the event of a upgrade
event LogChangeSTRAddress(address indexed _oldAddress, address indexed _newAddress);
// Events to log minting and burning
event Minted(address indexed to, uint256 amount);
event Burnt(address indexed _burner, uint256 _value);

// If _fallback is true, then for STO module type we only allow the module if it is set, if it is not set we only allow the owner
// for other _moduleType we allow both issuer and module.
modifier onlyModule(uint8 _moduleType, bool _fallback) {
//Loop over all modules of type _moduleType
// Require msg.sender to be the specified module type
modifier onlyModule(uint8 _moduleType) {
bool isModuleType = false;
for (uint8 i = 0; i < modules[_moduleType].length; i++) {
isModuleType = isModuleType || (modules[_moduleType][i].moduleAddress == msg.sender);
}
if (_fallback && !isModuleType) {
if (_moduleType == STO_KEY)
require(modules[_moduleType].length == 0 && msg.sender == owner, "Sender is not owner or STO module is attached");
else
require(msg.sender == owner, "Sender is not owner");
} else {
require(isModuleType, "Sender is not correct module type");
require(isModuleType, "msg.sender is not correct module type");
_;
}

// Require msg.sender to be the specified module type or the owner of the token
modifier onlyModuleOrOwner(uint8 _moduleType) {
bool isModuleType = false;
for (uint8 i = 0; i < modules[_moduleType].length; i++) {
isModuleType = isModuleType || (modules[_moduleType][i].moduleAddress == msg.sender);
}
require(msg.sender == owner || isModuleType, "msg.sender is not owner and not correct module type");
_;
}

Expand All @@ -135,14 +135,13 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr
_;
}

// Checks whether the minting is allowed or not, check for the owner if owner is no the msg.sender then check
// for the finishedSTOMinting flag because only STOs and owner are allowed for minting
modifier isMintingAllowed() {
if (msg.sender == owner) {
require(!finishedIssuerMinting, "Minting is finished for Issuer");
} else {
require(!finishedSTOMinting, "Minting is finished for STOs");
}
require(!mintingFrozen, "Minting is permanently frozen");
_;
}

modifier isEnabled(string _nameKey) {
require(IFeatureRegistry(featureRegistry).getFeatureStatus(_nameKey));
_;
}

Expand Down Expand Up @@ -411,21 +410,21 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr
}

/**
* @notice freeze all the transfers
* @notice freeze transfers
*/
function freezeTransfers() external onlyOwner {
require(!freeze);
freeze = true;
emit LogFreezeTransfers(freeze, now);
require(!transfersFrozen);
transfersFrozen = true;
emit LogFreezeTransfers(true, now);
}

/**
* @notice un-freeze all the transfers
* @notice unfreeze transfers
*/
function unfreezeTransfers() external onlyOwner {
require(freeze);
freeze = false;
emit LogFreezeTransfers(freeze, now);
require(transfersFrozen);
transfersFrozen = false;
emit LogFreezeTransfers(false, now);
}

/**
Expand Down Expand Up @@ -516,7 +515,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr
* @return bool
*/
function verifyTransfer(address _from, address _to, uint256 _amount) public checkGranularity(_amount) returns (bool) {
if (!freeze) {
if (!transfersFrozen) {
bool isTransfer = false;
if (transferFunctions[getSig(msg.data)]) {
isTransfer = true;
Expand Down Expand Up @@ -545,29 +544,22 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr
}

/**
* @notice End token minting period permanently for Issuer
*/
function finishMintingIssuer() external onlyOwner {
finishedIssuerMinting = true;
emit LogFinishMintingIssuer(now);
}

/**
* @notice End token minting period permanently for STOs
* @notice Permanently freeze minting of this security token.
* @dev It MUST NOT be possible to increase `totalSuppy` after this function is called.
*/
function finishMintingSTO() external onlyOwner {
finishedSTOMinting = true;
emit LogFinishMintingSTO(now);
function freezeMinting() external isMintingAllowed() isEnabled("freezeMintingAllowed") onlyOwner {
mintingFrozen = true;
emit LogFreezeMinting(now);
}

/**
* @notice mints new tokens and assigns them to the target _investor.
* @dev Can only be called by the STO attached to the token (Or by the ST owner if there's no STO attached yet)
* @param _investor Address to whom the minted tokens will be dilivered
* @param _amount Number of tokens get minted
* @dev Can only be called by the issuer or STO attached to the token
* @param _investor Address where the minted tokens will be delivered
* @param _amount Number of tokens be minted
* @return success
*/
function mint(address _investor, uint256 _amount) public onlyModule(STO_KEY, true) checkGranularity(_amount) isMintingAllowed() returns (bool success) {
function mint(address _investor, uint256 _amount) public onlyModuleOrOwner(STO_KEY) checkGranularity(_amount) isMintingAllowed() returns (bool success) {
require(_investor != address(0), "Investor address should not be 0x");
adjustInvestorCount(address(0), _investor, _amount);
require(verifyTransfer(address(0), _investor, _amount), "Transfer is not valid");
Expand All @@ -582,12 +574,12 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr

/**
* @notice mints new tokens and assigns them to the target _investor.
* Can only be called by the STO attached to the token (Or by the ST owner if there's no STO attached yet)
* @dev Can only be called by the issuer or STO attached to the token.
* @param _investors A list of addresses to whom the minted tokens will be dilivered
* @param _amounts A list of number of tokens get minted and transfer to corresponding address of the investor from _investor[] list
* @return success
*/
function mintMulti(address[] _investors, uint256[] _amounts) external onlyModule(STO_KEY, true) returns (bool success) {
function mintMulti(address[] _investors, uint256[] _amounts) external onlyModuleOrOwner(STO_KEY) returns (bool success) {
require(_investors.length == _amounts.length, "Mis-match in the length of the arrays");
for (uint256 i = 0; i < _investors.length; i++) {
mint(_investors[i], _amounts[i]);
Expand Down Expand Up @@ -662,7 +654,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr
* @notice Creates a checkpoint that can be used to query historical balances / totalSuppy
* @return uint256
*/
function createCheckpoint() external onlyModule(CHECKPOINT_KEY, true) returns(uint256) {
function createCheckpoint() external onlyModuleOrOwner(CHECKPOINT_KEY) returns(uint256) {
require(currentCheckpointId < 2**256 - 1);
currentCheckpointId = currentCheckpointId + 1;
emit LogCheckpointCreated(currentCheckpointId, now);
Expand Down
46 changes: 27 additions & 19 deletions migrations/2_deploy_contracts.js
Expand Up @@ -8,9 +8,10 @@ const EtherDividendCheckpointFactory = artifacts.require('./EtherDividendCheckpo
const ERC20DividendCheckpointFactory = artifacts.require('./ERC20DividendCheckpointFactory.sol')
const ManualApprovalTransferManagerFactory = artifacts.require('./ManualApprovalTransferManagerFactory.sol')
const CappedSTOFactory = artifacts.require('./CappedSTOFactory.sol')
const USDTieredSTOFactory = artifacts.require('./USDTieredSTOFactory.sol');
const USDTieredSTOFactory = artifacts.require('./USDTieredSTOFactory.sol')
const SecurityTokenRegistry = artifacts.require('./SecurityTokenRegistry.sol')
const TickerRegistry = artifacts.require('./TickerRegistry.sol')
const FeatureRegistry = artifacts.require('./FeatureRegistry.sol')
const STFactory = artifacts.require('./tokens/STFactory.sol')
const DevPolyToken = artifacts.require('./helpers/PolyTokenFaucet.sol')
const MockOracle = artifacts.require('./MockOracle.sol')
Expand Down Expand Up @@ -193,6 +194,12 @@ module.exports = function (deployer, network, accounts) {
}).then(() => {
// Assign the address into the SecurityTokenRegistry key
return polymathRegistry.changeAddress("SecurityTokenRegistry", SecurityTokenRegistry.address, {from: PolymathAccount});
}).then(() => {
// K) Deploy the FeatureRegistry contract to control feature switches
return deployer.deploy(FeatureRegistry, PolymathRegistry.address, {from: PolymathAccount});
}).then(() => {
// Assign the address into the FeatureRegistry key
return polymathRegistry.changeAddress("FeatureRegistry", FeatureRegistry.address, {from: PolymathAccount});
}).then(() => {
// Update all addresses into the registry contract by calling the function updateFromregistry
return SecurityTokenRegistry.at(SecurityTokenRegistry.address).updateFromRegistry({from: PolymathAccount});
Expand Down Expand Up @@ -233,30 +240,31 @@ module.exports = function (deployer, network, accounts) {
}).then(() => {
console.log('\n');
console.log(`
-------------------- Polymath Network Smart Contracts: --------------------
PolymathRegistry: ${PolymathRegistry.address}
TickerRegistry: ${TickerRegistry.address}
ModuleRegistry: ${ModuleRegistry.address}
SecurityTokenRegistry: ${SecurityTokenRegistry.address}
--------------------- Polymath Network Smart Contracts: ---------------------
PolymathRegistry: ${PolymathRegistry.address}
TickerRegistry: ${TickerRegistry.address}
SecurityTokenRegistry: ${SecurityTokenRegistry.address}
ModuleRegistry: ${ModuleRegistry.address}
FeatureRegistry: ${FeatureRegistry.address}
ETHOracle: ${ETHOracle.address}
POLYOracle: ${POLYOracle.address}
ETHOracle: ${ETHOracle}
POLYOracle: ${POLYOracle}
STFactory: ${STFactory.address}
GeneralTransferManagerFactory: ${GeneralTransferManagerFactory.address}
GeneralPermissionManagerFactory: ${GeneralPermissionManagerFactory.address}
STFactory: ${STFactory.address}
GeneralTransferManagerFactory: ${GeneralTransferManagerFactory.address}
GeneralPermissionManagerFactory: ${GeneralPermissionManagerFactory.address}
CappedSTOFactory: ${CappedSTOFactory.address}
USDTieredSTOFactory: ${USDTieredSTOFactory.address}
CappedSTOFactory: ${CappedSTOFactory.address}
USDTieredSTOFactory: ${USDTieredSTOFactory.address}
CountTransferManagerFactory: ${CountTransferManagerFactory.address}
PercentageTransferManagerFactory: ${PercentageTransferManagerFactory.address}
CountTransferManagerFactory: ${CountTransferManagerFactory.address}
PercentageTransferManagerFactory: ${PercentageTransferManagerFactory.address}
ManualApprovalTransferManagerFactory:
${ManualApprovalTransferManagerFactory.address}
${ManualApprovalTransferManagerFactory.address}
EtherDividendCheckpointFactory: ${EtherDividendCheckpointFactory.address}
ERC20DividendCheckpointFactory: ${ERC20DividendCheckpointFactory.address}
---------------------------------------------------------------------------
EtherDividendCheckpointFactory: ${EtherDividendCheckpointFactory.address}
ERC20DividendCheckpointFactory: ${ERC20DividendCheckpointFactory.address}
-----------------------------------------------------------------------------
`);
console.log('\n');
// -------- END OF POLYMATH NETWORK Configuration -------//
Expand Down

0 comments on commit bb50297

Please sign in to comment.