Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Freeze Minting #224

Merged
merged 6 commits into from
Aug 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions contracts/FeatureRegistry.sol
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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;
thegostep marked this conversation as resolved.
Show resolved Hide resolved

// 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
Original file line number Diff line number Diff line change
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
Loading