From fc0bace123a922a88ce2b305014078c2c70ee513 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Tue, 2 Oct 2018 21:34:13 +0100 Subject: [PATCH 01/28] WIP --- contracts/ModuleRegistry.sol | 25 ++-- contracts/interfaces/IModuleFactory.sol | 2 +- contracts/interfaces/ISecurityToken.sol | 6 - contracts/interfaces/ITokenBurner.sol | 10 -- contracts/mocks/MockFactory.sol | 12 +- contracts/mocks/MockTokenBurner.sol | 19 --- contracts/mocks/TestSTOFactory.sol | 14 +- .../modules/Burn/TrackedRedemptionFactory.sol | 14 +- .../ERC20DividendCheckpointFactory.sol | 16 +-- .../EtherDividendCheckpointFactory.sol | 16 +-- .../GeneralPermissionManagerFactory.sol | 16 +-- contracts/modules/STO/CappedSTOFactory.sol | 14 +- contracts/modules/STO/DummySTOFactory.sol | 14 +- contracts/modules/STO/PreSaleSTOFactory.sol | 14 +- contracts/modules/STO/USDTieredSTOFactory.sol | 16 +-- .../CountTransferManagerFactory.sol | 16 +-- .../GeneralTransferManagerFactory.sol | 14 +- .../ManualApprovalTransferManagerFactory.sol | 18 +-- .../PercentageTransferManagerFactory.sol | 16 +-- contracts/tokens/SecurityToken.sol | 127 +++++++++++------- 20 files changed, 198 insertions(+), 201 deletions(-) delete mode 100644 contracts/interfaces/ITokenBurner.sol delete mode 100644 contracts/mocks/MockTokenBurner.sol diff --git a/contracts/ModuleRegistry.sol b/contracts/ModuleRegistry.sol index f0249e2fd..30316cc4c 100644 --- a/contracts/ModuleRegistry.sol +++ b/contracts/ModuleRegistry.sol @@ -126,8 +126,8 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { } else { require(getBool(Encoder.getKey('verified', _moduleFactory)), "ModuleFactory must be verified"); } - require(_isCompatibleModule(_moduleFactory, msg.sender), "Version should within the compatible range of ST"); - require(getUint(Encoder.getKey('registry',_moduleFactory)) != 0, "ModuleFactory type should not be 0"); + require(_isCompatibleModule(_moduleFactory, msg.sender), "Incompatable versions"); + require(getArrayUint(Encoder.getKey('registry',_moduleFactory)) != [], "ModuleFactory not registered"); pushArray(Encoder.getKey('reputation', _moduleFactory), msg.sender); emit ModuleUsed(_moduleFactory, msg.sender); } @@ -153,14 +153,16 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { } else { require(msg.sender == getAddress(Encoder.getKey("owner")), "Only owner allowed to register modules"); } - require(getUint(Encoder.getKey('registry', _moduleFactory)) == 0, "Module factory should not be pre-registered"); + require(getArrayUint(Encoder.getKey('registry', _moduleFactory)) == [], "Module factory should not be pre-registered"); IModuleFactory moduleFactory = IModuleFactory(_moduleFactory); - uint8 moduleType = moduleFactory.getType(); - require(moduleType != 0, "Factory moduleType should not equal to 0"); - set(Encoder.getKey('registry', _moduleFactory), uint256(moduleType)); + uint8[] moduleTypes = moduleFactory.getTypes(); + for (uint256 i = 0; i < moduleTypes.length; i++) { + require(moduleTypes[i] != 0, "Factory moduleType should not equal to 0"); + pushArray(Encoder.getKey('registry', _moduleFactory), moduleTypes[i]); + } set(Encoder.getKey('moduleListIndex', _moduleFactory), uint256(getArrayAddress(Encoder.getKey('moduleList', uint256(moduleType))).length)); pushArray(Encoder.getKey('moduleList', uint256(moduleType)), _moduleFactory); - emit ModuleRegistered (_moduleFactory, IOwnable(_moduleFactory).owner()); + emit ModuleRegistered(_moduleFactory, IOwnable(_moduleFactory).owner()); } /** @@ -168,9 +170,8 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @param _moduleFactory is the address of the module factory to be deleted from the registry */ function removeModule(address _moduleFactory) external whenNotPausedOrOwner { - uint256 moduleType = getUint(Encoder.getKey('registry', _moduleFactory)); - - require(moduleType != 0, "Module factory should be registered"); + uint8[] moduleTypes = getArrayUint(Encoder.getKey('registry', _moduleFactory)); + require(moduleTypes != [], "Module factory not registered"); require(msg.sender == IOwnable(_moduleFactory).owner() || msg.sender == getAddress(Encoder.getKey('owner')), "msg.sender must be the Module Factory owner or registry curator"); @@ -187,7 +188,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { deleteArrayAddress(Encoder.getKey('moduleList', moduleType), last); // delete registry[_moduleFactory]; - set(Encoder.getKey('registry', _moduleFactory), uint256(0)); + setArray(Encoder.getKey('registry', _moduleFactory), []); // delete reputation[_moduleFactory]; setArray(Encoder.getKey('reputation', _moduleFactory), new address[](0)); // delete verified[_moduleFactory]; @@ -206,7 +207,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @return bool */ function verifyModule(address _moduleFactory, bool _verified) external onlyOwner { - require(getUint(Encoder.getKey('registry', _moduleFactory)) != uint256(0), "Module factory must be registered"); + require(getUint(Encoder.getKey('registry', _moduleFactory)) != [], "Module factory must be registered"); set(Encoder.getKey('verified', _moduleFactory), _verified); emit ModuleVerified(_moduleFactory, _verified); } diff --git a/contracts/interfaces/IModuleFactory.sol b/contracts/interfaces/IModuleFactory.sol index 38f2a9e0d..839bb26ed 100644 --- a/contracts/interfaces/IModuleFactory.sol +++ b/contracts/interfaces/IModuleFactory.sol @@ -24,7 +24,7 @@ interface IModuleFactory { /** * @notice Type of the Module factory */ - function getType() external view returns(uint8); + function getTypes() external view returns(uint8[]); /** * @notice Get the name of the Module diff --git a/contracts/interfaces/ISecurityToken.sol b/contracts/interfaces/ISecurityToken.sol index c36f45270..ced158b9c 100644 --- a/contracts/interfaces/ISecurityToken.sol +++ b/contracts/interfaces/ISecurityToken.sol @@ -180,12 +180,6 @@ interface ISecurityToken { */ function mintMulti(address[] _investors, uint256[] _values) external returns (bool success); - /** - * @notice used to set the token Burner address. It can only be called by the owner - * @param _tokenBurner Address of the token burner contract - */ - function setTokenBurner(address _tokenBurner) external; - /** * @notice Removes a module attached to the SecurityToken * @param _module address of module to archive diff --git a/contracts/interfaces/ITokenBurner.sol b/contracts/interfaces/ITokenBurner.sol deleted file mode 100644 index bf5ca0819..000000000 --- a/contracts/interfaces/ITokenBurner.sol +++ /dev/null @@ -1,10 +0,0 @@ -pragma solidity ^0.4.24; - -/** - * @title Interface for the token burner contract - */ -interface ITokenBurner { - - function burn(address _burner, uint256 _value ) external returns(bool); - -} diff --git a/contracts/mocks/MockFactory.sol b/contracts/mocks/MockFactory.sol index 2f7772d77..90e64235d 100644 --- a/contracts/mocks/MockFactory.sol +++ b/contracts/mocks/MockFactory.sol @@ -40,8 +40,8 @@ contract MockFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getType() public view returns(uint8) { - return 0; + function getTypes() external view returns(uint8[]) { + return [0]; } /** @@ -54,14 +54,14 @@ contract MockFactory is ModuleFactory { /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } @@ -82,14 +82,14 @@ contract MockFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Mock Manager - This is mock in nature"; } /** * @notice Get the tags related to the module factory */ - function getTags() public view returns(bytes32[]) { + function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](4); availableTags[0] = "Mock"; return availableTags; diff --git a/contracts/mocks/MockTokenBurner.sol b/contracts/mocks/MockTokenBurner.sol deleted file mode 100644 index cd5c4be23..000000000 --- a/contracts/mocks/MockTokenBurner.sol +++ /dev/null @@ -1,19 +0,0 @@ -pragma solidity ^0.4.24; - -import "../interfaces/ITokenBurner.sol"; - -contract MockTokenBurner is ITokenBurner { - - address public securityToken; - - constructor (address _securityToken) public { - securityToken = _securityToken; - } - - function burn(address /* _burner */, uint256 /* _value */) public view returns(bool) { - require(msg.sender == securityToken); - // Add the schematics for the burner( token holder) that backing the burning of the securities - return true; - } - -} diff --git a/contracts/mocks/TestSTOFactory.sol b/contracts/mocks/TestSTOFactory.sol index 71521e242..89540d1c1 100644 --- a/contracts/mocks/TestSTOFactory.sol +++ b/contracts/mocks/TestSTOFactory.sol @@ -40,28 +40,28 @@ contract TestSTOFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getType() public view returns(uint8) { - return 3; + function getTypes() external view returns(uint8[]) { + return [3]; } /** * @notice Get the name of the Module */ - function getName() public view returns(bytes32) { + function getName() external view returns(bytes32) { return name; } /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } @@ -82,14 +82,14 @@ contract TestSTOFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Test STO - you can mint tokens at will"; } /** * @notice Get the tags related to the module factory */ - function getTags() public view returns(bytes32[]) { + function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](4); availableTags[0] = "Test"; availableTags[1] = "Non-refundable"; diff --git a/contracts/modules/Burn/TrackedRedemptionFactory.sol b/contracts/modules/Burn/TrackedRedemptionFactory.sol index 94003286b..99907f977 100644 --- a/contracts/modules/Burn/TrackedRedemptionFactory.sol +++ b/contracts/modules/Burn/TrackedRedemptionFactory.sol @@ -41,21 +41,21 @@ contract TrackedRedemptionFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getType() public view returns(uint8) { - return 5; + function getTypes() external view returns(uint8[]) { + return [5]; } /** * @notice Get the name of the Module */ - function getName() public view returns(bytes32) { + function getName() external view returns(bytes32) { return name; } /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } @@ -69,7 +69,7 @@ contract TrackedRedemptionFactory is ModuleFactory { /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } @@ -83,14 +83,14 @@ contract TrackedRedemptionFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Allows an investor to redeem security tokens which are tracked by this module"; } /** * @notice Get the tags related to the module factory */ - function getTags() public view returns(bytes32[]) { + function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](2); availableTags[0] = "Redemption"; availableTags[1] = "Tracked"; diff --git a/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol b/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol index d789ad5e3..f978725f8 100644 --- a/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol +++ b/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol @@ -17,7 +17,7 @@ contract ERC20DividendCheckpointFactory is ModuleFactory { */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) - { + { version = "1.0.0"; name = "ERC20DividendCheckpoint"; title = "ERC20 Dividend Checkpoint"; @@ -41,28 +41,28 @@ contract ERC20DividendCheckpointFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getType() public view returns(uint8) { - return 4; + function getTypes() external view returns(uint8[]) { + return [4]; } /** * @notice Get the name of the Module */ - function getName() public view returns(bytes32) { + function getName() external view returns(bytes32) { return name; } /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } @@ -83,14 +83,14 @@ contract ERC20DividendCheckpointFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Create a ERC20 dividend which will be paid out to token holders proportional to their balances at the point the dividend is created"; } /** * @notice Get the tags related to the module factory */ - function getTags() public view returns(bytes32[]) { + function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](3); availableTags[0] = "ERC20"; availableTags[1] = "Dividend"; diff --git a/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol b/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol index 146691d82..76d3a9f12 100644 --- a/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol +++ b/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol @@ -17,7 +17,7 @@ contract EtherDividendCheckpointFactory is ModuleFactory { */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) - { + { version = "1.0.0"; name = "EtherDividendCheckpoint"; title = "Ether Dividend Checkpoint"; @@ -41,28 +41,28 @@ contract EtherDividendCheckpointFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getType() public view returns(uint8) { - return 4; + function getTypse() external view returns(uint8[]) { + return [4]; } /** * @notice Get the name of the Module */ - function getName() public view returns(bytes32) { + function getName() external view returns(bytes32) { return name; } /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } @@ -83,14 +83,14 @@ contract EtherDividendCheckpointFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Create a dividend which will be paid out to token holders proportional to their balances at the point the dividend is created"; } /** * @notice Get the tags related to the module factory */ - function getTags() public view returns(bytes32[]) { + function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](3); availableTags[0] = "ETH"; availableTags[1] = "Checkpoint"; diff --git a/contracts/modules/PermissionManager/GeneralPermissionManagerFactory.sol b/contracts/modules/PermissionManager/GeneralPermissionManagerFactory.sol index e6e6e65a1..67d0b7df8 100644 --- a/contracts/modules/PermissionManager/GeneralPermissionManagerFactory.sol +++ b/contracts/modules/PermissionManager/GeneralPermissionManagerFactory.sol @@ -14,7 +14,7 @@ contract GeneralPermissionManagerFactory is ModuleFactory { */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) - { + { version = "1.0.0"; name = "GeneralPermissionManager"; title = "General Permission Manager"; @@ -38,28 +38,28 @@ contract GeneralPermissionManagerFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getType() public view returns(uint8) { - return 1; + function getTypes() external view returns(uint8[]) { + return [1]; } /** * @notice Get the name of the Module */ - function getName() public view returns(bytes32) { + function getName() external view returns(bytes32) { return name; } /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } @@ -80,14 +80,14 @@ contract GeneralPermissionManagerFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Add and remove permissions for the SecurityToken and associated modules. Permission types should be encoded as bytes32 values, and attached using the withPerm modifier to relevant functions.No initFunction required."; } /** * @notice Get the tags related to the module factory */ - function getTags() public view returns(bytes32[]) { + function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](0); return availableTags; } diff --git a/contracts/modules/STO/CappedSTOFactory.sol b/contracts/modules/STO/CappedSTOFactory.sol index 982f790f0..6b75612a0 100644 --- a/contracts/modules/STO/CappedSTOFactory.sol +++ b/contracts/modules/STO/CappedSTOFactory.sol @@ -43,28 +43,28 @@ contract CappedSTOFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getType() public view returns(uint8) { - return 3; + function getTypes() external view returns(uint8[]) { + return [3]; } /** * @notice Get the name of the Module */ - function getName() public view returns(bytes32) { + function getName() external view returns(bytes32) { return name; } /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } @@ -85,14 +85,14 @@ contract CappedSTOFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Initialises a capped STO. Init parameters are _startTime (time STO starts), _endTime (time STO ends), _cap (cap in tokens for STO), _rate (POLY/ETH to token rate), _fundRaiseType (whether you are raising in POLY or ETH), _polyToken (address of POLY token), _fundsReceiver (address which will receive funds)"; } /** * @notice Get the tags related to the module factory */ - function getTags() public view returns(bytes32[]) { + function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](4); availableTags[0] = "Capped"; availableTags[1] = "Non-refundable"; diff --git a/contracts/modules/STO/DummySTOFactory.sol b/contracts/modules/STO/DummySTOFactory.sol index ec249b420..137cf6b6d 100644 --- a/contracts/modules/STO/DummySTOFactory.sol +++ b/contracts/modules/STO/DummySTOFactory.sol @@ -42,28 +42,28 @@ contract DummySTOFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getType() public view returns(uint8) { - return 3; + function getTypes() external view returns(uint8[]) { + return [3]; } /** * @notice Get the name of the Module */ - function getName() public view returns(bytes32) { + function getName() external view returns(bytes32) { return name; } /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } @@ -84,14 +84,14 @@ contract DummySTOFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Dummy STO - you can mint tokens at will"; } /** * @notice Get the tags related to the module factory */ - function getTags() public view returns(bytes32[]) { + function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](4); availableTags[0] = "Dummy"; availableTags[1] = "Non-refundable"; diff --git a/contracts/modules/STO/PreSaleSTOFactory.sol b/contracts/modules/STO/PreSaleSTOFactory.sol index 03ca13bbe..223392669 100644 --- a/contracts/modules/STO/PreSaleSTOFactory.sol +++ b/contracts/modules/STO/PreSaleSTOFactory.sol @@ -45,28 +45,28 @@ contract PreSaleSTOFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getType() public view returns(uint8) { - return 3; + function getTypes() external view returns(uint8[]) { + return [3]; } /** * @notice Get the name of the Module */ - function getName() public view returns(bytes32) { + function getName() external view returns(bytes32) { return name; } /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } @@ -87,14 +87,14 @@ contract PreSaleSTOFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Configure and track pre-sale token allocations"; } /** * @notice Get the tags related to the module factory */ - function getTags() public view returns(bytes32[]) { + function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](1); availableTags[0] = "Presale"; return availableTags; diff --git a/contracts/modules/STO/USDTieredSTOFactory.sol b/contracts/modules/STO/USDTieredSTOFactory.sol index 1b01cec66..4f9d772f0 100644 --- a/contracts/modules/STO/USDTieredSTOFactory.sol +++ b/contracts/modules/STO/USDTieredSTOFactory.sol @@ -17,7 +17,7 @@ contract USDTieredSTOFactory is ModuleFactory { */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost, address _proxyFactoryAddress) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) - { + { require(_proxyFactoryAddress != address(0), "0x address is not allowed"); USDTieredSTOProxyAddress = _proxyFactoryAddress; version = "1.0.0"; @@ -49,28 +49,28 @@ contract USDTieredSTOFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getType() public view returns(uint8) { - return 3; + function getTypes() external view returns(uint8[]) { + return [3]; } /** * @notice Get the name of the Module */ - function getName() public view returns(bytes32) { + function getName() external view returns(bytes32) { return name; } /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } @@ -91,14 +91,14 @@ contract USDTieredSTOFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Initialises a USD tiered STO."; } /** * @notice Get the tags related to the module factory */ - function getTags() public view returns(bytes32[]) { + function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](4); availableTags[0] = "USD"; availableTags[1] = "Tiered"; diff --git a/contracts/modules/TransferManager/CountTransferManagerFactory.sol b/contracts/modules/TransferManager/CountTransferManagerFactory.sol index aa7d2cda2..43acf38a6 100644 --- a/contracts/modules/TransferManager/CountTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/CountTransferManagerFactory.sol @@ -15,7 +15,7 @@ contract CountTransferManagerFactory is ModuleFactory { */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) - { + { version = "1.0.0"; name = "CountTransferManager"; title = "Count Transfer Manager"; @@ -43,28 +43,28 @@ contract CountTransferManagerFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getType() public view returns(uint8) { - return 2; + function getTypes() external view returns(uint8[]) { + return [2]; } /** * @notice Get the name of the Module */ - function getName() public view returns(bytes32) { + function getName() external view returns(bytes32) { return name; } /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } @@ -85,14 +85,14 @@ contract CountTransferManagerFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Allows an issuer to restrict the total number of non-zero token holders"; } /** * @notice Get the tags related to the module factory */ - function getTags() public view returns(bytes32[]) { + function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](2); availableTags[0] = "Count"; availableTags[1] = "Transfer Restriction"; diff --git a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol index a3490130b..8ca244340 100644 --- a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol @@ -14,7 +14,7 @@ contract GeneralTransferManagerFactory is ModuleFactory { */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) - { + { version = "1.0.0"; name = "GeneralTransferManager"; title = "General Transfer Manager"; @@ -40,21 +40,21 @@ contract GeneralTransferManagerFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getType() public view returns(uint8) { - return 2; + function getTypes() external view returns(uint8[]) { + return [2]; } /** * @notice Get the name of the Module */ - function getName() public view returns(bytes32) { + function getName() external view returns(bytes32) { return name; } /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } @@ -68,7 +68,7 @@ contract GeneralTransferManagerFactory is ModuleFactory { /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } @@ -82,7 +82,7 @@ contract GeneralTransferManagerFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Allows an issuer to maintain a time based whitelist of authorised token holders.Addresses are added via modifyWhitelist, and take a fromTime (the time from which they can send tokens) and a toTime (the time from which they can receive tokens). There are additional flags, allowAllWhitelistIssuances, allowAllWhitelistTransfers & allowAllTransfers which allow you to set corresponding contract level behaviour. Init function takes no parameters."; } diff --git a/contracts/modules/TransferManager/ManualApprovalTransferManagerFactory.sol b/contracts/modules/TransferManager/ManualApprovalTransferManagerFactory.sol index 2c0e60eb5..ddc026042 100644 --- a/contracts/modules/TransferManager/ManualApprovalTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/ManualApprovalTransferManagerFactory.sol @@ -17,7 +17,7 @@ contract ManualApprovalTransferManagerFactory is ModuleFactory { */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) - { + { version = "1.0.0"; name = "ManualApprovalTransferManager"; title = "Manual Approval Transfer Manager"; @@ -41,31 +41,31 @@ contract ManualApprovalTransferManagerFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getType() public view returns(uint8) { - return 2; + function getTypes() external view returns(uint8[]) { + return [2]; } /** * @notice Get the name of the Module */ - function getName() public view returns(bytes32) { + function getName() external view returns(bytes32) { return name; } /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } - + /** * @notice Get the version of the Module */ @@ -83,14 +83,14 @@ contract ManualApprovalTransferManagerFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Allows an issuer to set manual approvals or blocks for specific pairs of addresses and amounts. Init function takes no parameters."; } /** * @notice Get the tags related to the module factory */ - function getTags() public view returns(bytes32[]) { + function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](2); availableTags[0] = "ManualApproval"; availableTags[1] = "Transfer Restriction"; diff --git a/contracts/modules/TransferManager/PercentageTransferManagerFactory.sol b/contracts/modules/TransferManager/PercentageTransferManagerFactory.sol index 59949880c..80ae0bd05 100644 --- a/contracts/modules/TransferManager/PercentageTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/PercentageTransferManagerFactory.sol @@ -15,7 +15,7 @@ contract PercentageTransferManagerFactory is ModuleFactory { */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) - { + { version = "1.0.0"; name = "PercentageTransferManager"; title = "Percentage Transfer Manager"; @@ -44,28 +44,28 @@ contract PercentageTransferManagerFactory is ModuleFactory { * @notice Type of the Module factory * @return uint8 */ - function getType() public view returns(uint8) { - return 2; + function getTypes() external view returns(uint8[]) { + return [2]; } /** * @notice Get the name of the Module */ - function getName() public view returns(bytes32) { + function getName() external view returns(bytes32) { return name; } /** * @notice Get the description of the Module */ - function getDescription() public view returns(string) { + function getDescription() external view returns(string) { return description; } /** * @notice Get the title of the Module */ - function getTitle() public view returns(string) { + function getTitle() external view returns(string) { return title; } @@ -86,14 +86,14 @@ contract PercentageTransferManagerFactory is ModuleFactory { /** * @notice Get the Instructions that helped to used the module */ - function getInstructions() public view returns(string) { + function getInstructions() external view returns(string) { return "Allows an issuer to restrict the total number of non-zero token holders"; } /** * @notice Get the tags related to the module factory */ - function getTags() public view returns(bytes32[]) { + function getTags() external view returns(bytes32[]) { bytes32[] memory availableTags = new bytes32[](2); availableTags[0] = "Percentage"; availableTags[1] = "Transfer Restriction"; diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index c3d8ca8fb..655625b71 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -39,8 +39,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // off-chain hash string public tokenDetails; - uint8 public constant PERMISSIONMANAGER_KEY = 1; - uint8 public constant TRANSFERMANAGER_KEY = 2; + uint8 public constant PERMISSION_KEY = 1; + uint8 public constant TRANSFER_KEY = 2; uint8 public constant MINT_KEY = 3; uint8 public constant CHECKPOINT_KEY = 4; uint8 public constant BURN_KEY = 5; @@ -68,40 +68,49 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // address whitelisted by issuer as controller address public controller; + // Struct for module data struct ModuleData { bytes32 name; address module; address moduleFactory; bool isArchived; - uint8 moduleType; - uint256 moduleIndex; + uint8[] moduleTypes; + uint256[] moduleIndexes; uint256 nameIndex; + mapping (uint8 => bool) moduleType; + mapping (uint8 => uint256) moduleIndex; } + // Records added modules - module list should be order agnostic! + mapping (uint8 => address[]) public modules; + + // Records information about the module + mapping (address => ModuleData) modulesToData; + + // Records added module names - module list should be order agnostic! + mapping (bytes32 => address[]) names; + // Structures to maintain checkpoints of balances for governance / dividends struct Checkpoint { uint256 checkpointId; uint256 value; } + // Map each investor to a series of checkpoints mapping (address => Checkpoint[]) public checkpointBalances; - Checkpoint[] public checkpointTotalSupply; - uint256[] public checkpointTimes; - - // Records added modules - module list should be order agnostic! - mapping (uint8 => address[]) public modules; - // Records information about the module - mapping (address => ModuleData) modulesToData; + // List of checkpoints that relate to total supply + Checkpoint[] public checkpointTotalSupply; - // Records added module names - module list should be order agnostic! - mapping (bytes32 => address[]) names; + // Times at which each checkpoint was created + uint256[] public checkpointTimes; + // List of investors (may not be pruned to remove old investors with current zero balances) mapping (address => bool) public investorListed; // Emit at the time when module get added event ModuleAdded( - uint8 indexed _type, + uint8[] indexed _types, bytes32 _name, address _moduleFactory, address _module, @@ -115,13 +124,13 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // Emit when the granularity get changed event GranularityChanged(uint256 _oldGranularity, uint256 _newGranularity); // Emit when Module get removed from the securityToken - event ModuleRemoved(uint8 indexed _type, address _module, uint256 _timestamp); + event ModuleRemoved(uint8[] indexed _types, address _module, uint256 _timestamp); // Emit when Module get archived from the securityToken - event ModuleArchived(uint8 indexed _type, address _module, uint256 _timestamp); + event ModuleArchived(uint8[] indexed _types, address _module, uint256 _timestamp); // Emit when Module get unarchived from the securityToken - event ModuleUnarchived(uint8 indexed _type, address _module, uint256 _timestamp); + event ModuleUnarchived(uint8[] indexed _types, address _module, uint256 _timestamp); // Emit when the budget allocated to a module is changed - event ModuleBudgetChanged(uint8 indexed _moduleType, address _module, uint256 _oldBudget, uint256 _budget); + event ModuleBudgetChanged(uint8[] indexed _moduleTypes, address _module, uint256 _oldBudget, uint256 _budget); // Emit when transfers are frozen or unfrozen event FreezeTransfers(bool _status, uint256 _timestamp); // Emit when new checkpoint created @@ -142,7 +151,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr function isModule(address _module, uint8 _type) internal view returns (bool) { require(modulesToData[_module].module == _module, "Address mismatch"); - require(modulesToData[_module].moduleType == _type, "Type mismatch"); + require(modulesToData[_module].moduleType[_type], "Type mismatch"); require(!modulesToData[_module].isArchived, "Module archived"); return true; } @@ -246,7 +255,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr //Check that module exists in registry - will throw otherwise IModuleRegistry(moduleRegistry).useModule(_moduleFactory); IModuleFactory moduleFactory = IModuleFactory(_moduleFactory); - uint8 moduleType = moduleFactory.getType(); + uint8[] memory moduleTypes = moduleFactory.getTypes(); /* require(modules[moduleType].length < MAX_MODULES, "Limit of MAX MODULES is reached"); */ uint256 moduleCost = moduleFactory.getSetupCost(); require(moduleCost <= _maxCost, "Module cost too high"); @@ -259,11 +268,25 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr require(ERC20(polyToken).approve(module, _budget), "Insufficient funds for budget"); //Add to SecurityToken module map bytes32 moduleName = moduleFactory.getName(); - modulesToData[module] = ModuleData(moduleName, module, _moduleFactory, false, moduleType, modules[moduleType].length, names[moduleName].length); - modules[moduleType].push(module); + uint256[] memory moduleIndexes = new uint256[](moduleTypes.length); + //TODO: Enforce uniqueness + uint256 i; + uint256 j; + for (i = 0; i < moduleTypes.length; i++) { + for (j = i; j < moduleTypes.length; j++) { + require(moduleTypes[i] != moduleTypes[j], "Bad types"); + } + } + for (i = 0; i < moduleTypes.length; i++) { + moduleIndexes[i] = modules[moduleTypes[i]].length; + } + modulesToData[module] = ModuleData(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); + for (i = 0; i < moduleTypes.length; i++) { + modules[moduleTypes[i]].push(module); + } names[moduleName].push(module); //Emit log event - emit ModuleAdded(moduleType, moduleName, _moduleFactory, module, moduleCost, _budget, now); + emit ModuleAdded(moduleTypes, moduleName, _moduleFactory, module, moduleCost, _budget, now); } /** @@ -273,7 +296,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr function archiveModule(address _module) external onlyOwner { require(!modulesToData[_module].isArchived, "Module already archived"); require(modulesToData[_module].module != address(0), "Module missing"); - emit ModuleArchived(modulesToData[_module].moduleType, _module, now); + emit ModuleArchived(modulesToData[_module].moduleTypes, _module, now); modulesToData[_module].isArchived = true; } @@ -283,10 +306,26 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr */ function unarchiveModule(address _module) external onlyOwner { require(modulesToData[_module].isArchived, "Module already unarchived"); - emit ModuleUnarchived(modulesToData[_module].moduleType, _module, now); + emit ModuleUnarchived(modulesToData[_module].moduleTypes, _module, now); modulesToData[_module].isArchived = false; } + function _removeModuleWithIndex(uint8 _type, uint256 _index) internal { + uint256 length = modules[_type].length; + modules[_type][_index] = modules[_type][length - 1]; + modules[_type].length = length - 1; + + if ((length - 1) != _index) { + //Need to find index of _type in moduleTypes of module we are moving + uint8[] memory newTypes = modulesToData[modules[_type][_index]].moduleTypes; + for (uint256 i = 0; i < newTypes.length; i++) { + if (newTypes[i] == _type) { + modulesToData[modules[_type][_index]].moduleIndexes[i] = _index; + } + } + } + } + /** * @notice Removes a module attached to the SecurityToken * @param _module address of module to unarchive @@ -294,18 +333,15 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr function removeModule(address _module) external onlyOwner { require(modulesToData[_module].isArchived, "Module not archived"); require(modulesToData[_module].module != address(0), "Module missing"); - emit ModuleRemoved(modulesToData[_module].moduleType, _module, now); + emit ModuleRemoved(modulesToData[_module].moduleTypes, _module, now); // Remove from module type list - uint256 index = modulesToData[_module].moduleIndex; - uint8 moduleType = modulesToData[_module].moduleType; - uint256 length = modules[moduleType].length; - modules[moduleType][index] = modules[moduleType][length - 1]; - modules[moduleType].length = length - 1; - if ((length - 1) != index) { - modulesToData[modules[moduleType][index]].moduleIndex = index; + uint8[] moduleTypes = modulesToData[_module].moduleTypes; + for (uint256 i = 0; i < moduleTypes.length; i++) { + _removeModuleWithIndex(moduleTypes[i], modulesToData[_module].moduleIndexes[i]); } + // Remove from module names list - index = modulesToData[_module].nameIndex; + uint256 index = modulesToData[_module].nameIndex; bytes32 name = modulesToData[_module].name; length = names[name].length; names[name][index] = names[name][length - 1]; @@ -325,18 +361,13 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return address module factory address * @return bool module archived * @return uint8 module type - * @return uint256 module index - * @return uint256 name index - */ - function getModule(address _module) external view returns (bytes32, address, address, bool, uint8, uint256, uint256) { + function getModule(address _module) external view returns (bytes32, address, address, bool, uint8[]) { return (modulesToData[_module].name, modulesToData[_module].module, modulesToData[_module].moduleFactory, modulesToData[_module].isArchived, - modulesToData[_module].moduleType, - modulesToData[_module].moduleIndex, - modulesToData[_module].nameIndex); + modulesToData[_module].moduleTypes, } /** @@ -379,7 +410,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr } else { require(IERC20(polyToken).increaseApproval(_module, _budget.sub(_currentAllowance)), "Insufficient balance to increaseApproval"); } - emit ModuleBudgetChanged(modulesToData[_module].moduleType, _module, _currentAllowance, _budget); + emit ModuleBudgetChanged(modulesToData[_module].moduleTypes, _module, _currentAllowance, _budget); } /** @@ -561,7 +592,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr */ function _verifyTransfer(address _from, address _to, uint256 _value, bool _isTransfer) internal checkGranularity(_value) returns (bool) { if (!transfersFrozen) { - if (modules[TRANSFERMANAGER_KEY].length == 0) { + if (modules[TRANSFER_KEY].length == 0) { return true; } bool isInvalid = false; @@ -569,8 +600,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr bool isForceValid = false; bool unarchived = false; address module; - for (uint8 i = 0; i < modules[TRANSFERMANAGER_KEY].length; i++) { - module = modules[TRANSFERMANAGER_KEY][i]; + for (uint8 i = 0; i < modules[TRANSFER_KEY].length; i++) { + module = modules[TRANSFER_KEY][i]; if (!modulesToData[module].isArchived) { unarchived = true; ITransferManager.Result valid = ITransferManager(module).verifyTransfer(_from, _to, _value, _isTransfer); @@ -701,12 +732,12 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return success */ function checkPermission(address _delegate, address _module, bytes32 _perm) public view returns(bool) { - if (modules[PERMISSIONMANAGER_KEY].length == 0) { + if (modules[PERMISSION_KEY].length == 0) { return false; } - for (uint8 i = 0; i < modules[PERMISSIONMANAGER_KEY].length; i++) { - if (IPermissionManager(modules[PERMISSIONMANAGER_KEY][i]).checkPermission(_delegate, _module, _perm)) { + for (uint8 i = 0; i < modules[PERMISSION_KEY].length; i++) { + if (IPermissionManager(modules[PERMISSION_KEY][i]).checkPermission(_delegate, _module, _perm)) { return true; } } From a925a8c682b09b7d5d1d80b9978a43b5d863f2db Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Tue, 2 Oct 2018 21:59:18 +0100 Subject: [PATCH 02/28] Fixes --- contracts/ModuleRegistry.sol | 26 +++++++++---------- contracts/mocks/MockFactory.sol | 4 ++- contracts/mocks/TestSTOFactory.sol | 4 ++- .../modules/Burn/TrackedRedemptionFactory.sol | 6 +++-- .../ERC20DividendCheckpointFactory.sol | 6 +++-- .../EtherDividendCheckpointFactory.sol | 8 +++--- .../GeneralPermissionManagerFactory.sol | 6 +++-- contracts/modules/STO/CappedSTOFactory.sol | 6 +++-- contracts/modules/STO/DummySTOFactory.sol | 6 +++-- contracts/modules/STO/PreSaleSTOFactory.sol | 6 +++-- contracts/modules/STO/USDTieredSTOFactory.sol | 6 +++-- .../CountTransferManagerFactory.sol | 6 +++-- .../GeneralTransferManagerFactory.sol | 6 +++-- .../ManualApprovalTransferManagerFactory.sol | 6 +++-- .../PercentageTransferManagerFactory.sol | 6 +++-- contracts/tokens/SecurityToken.sol | 9 +++---- 16 files changed, 72 insertions(+), 45 deletions(-) diff --git a/contracts/ModuleRegistry.sol b/contracts/ModuleRegistry.sol index 30316cc4c..60e5478a4 100644 --- a/contracts/ModuleRegistry.sol +++ b/contracts/ModuleRegistry.sol @@ -126,8 +126,8 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { } else { require(getBool(Encoder.getKey('verified', _moduleFactory)), "ModuleFactory must be verified"); } - require(_isCompatibleModule(_moduleFactory, msg.sender), "Incompatable versions"); - require(getArrayUint(Encoder.getKey('registry',_moduleFactory)) != [], "ModuleFactory not registered"); + require(_isCompatibleModule(_moduleFactory, msg.sender), "Version should within the compatible range of ST"); + require(getUint(Encoder.getKey('registry',_moduleFactory)) != 0, "ModuleFactory type should not be 0"); pushArray(Encoder.getKey('reputation', _moduleFactory), msg.sender); emit ModuleUsed(_moduleFactory, msg.sender); } @@ -153,16 +153,15 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { } else { require(msg.sender == getAddress(Encoder.getKey("owner")), "Only owner allowed to register modules"); } - require(getArrayUint(Encoder.getKey('registry', _moduleFactory)) == [], "Module factory should not be pre-registered"); + require(getUint(Encoder.getKey('registry', _moduleFactory)) == 0, "Module factory should not be pre-registered"); IModuleFactory moduleFactory = IModuleFactory(_moduleFactory); - uint8[] moduleTypes = moduleFactory.getTypes(); - for (uint256 i = 0; i < moduleTypes.length; i++) { - require(moduleTypes[i] != 0, "Factory moduleType should not equal to 0"); - pushArray(Encoder.getKey('registry', _moduleFactory), moduleTypes[i]); - } + require(moduleFactory.getTypes().length != 0, "Factory must have type"); + // NB - here we index by the first type of the module. + uint8 moduleType = moduleFactory.getTypes()[0]; + set(Encoder.getKey('registry', _moduleFactory), uint256(moduleType)); set(Encoder.getKey('moduleListIndex', _moduleFactory), uint256(getArrayAddress(Encoder.getKey('moduleList', uint256(moduleType))).length)); pushArray(Encoder.getKey('moduleList', uint256(moduleType)), _moduleFactory); - emit ModuleRegistered(_moduleFactory, IOwnable(_moduleFactory).owner()); + emit ModuleRegistered (_moduleFactory, IOwnable(_moduleFactory).owner()); } /** @@ -170,8 +169,9 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @param _moduleFactory is the address of the module factory to be deleted from the registry */ function removeModule(address _moduleFactory) external whenNotPausedOrOwner { - uint8[] moduleTypes = getArrayUint(Encoder.getKey('registry', _moduleFactory)); - require(moduleTypes != [], "Module factory not registered"); + uint256 moduleType = getUint(Encoder.getKey('registry', _moduleFactory)); + + require(moduleType != 0, "Module factory should be registered"); require(msg.sender == IOwnable(_moduleFactory).owner() || msg.sender == getAddress(Encoder.getKey('owner')), "msg.sender must be the Module Factory owner or registry curator"); @@ -188,7 +188,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { deleteArrayAddress(Encoder.getKey('moduleList', moduleType), last); // delete registry[_moduleFactory]; - setArray(Encoder.getKey('registry', _moduleFactory), []); + set(Encoder.getKey('registry', _moduleFactory), uint256(0)); // delete reputation[_moduleFactory]; setArray(Encoder.getKey('reputation', _moduleFactory), new address[](0)); // delete verified[_moduleFactory]; @@ -207,7 +207,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @return bool */ function verifyModule(address _moduleFactory, bool _verified) external onlyOwner { - require(getUint(Encoder.getKey('registry', _moduleFactory)) != [], "Module factory must be registered"); + require(getUint(Encoder.getKey('registry', _moduleFactory)) != uint256(0), "Module factory must be registered"); set(Encoder.getKey('verified', _moduleFactory), _verified); emit ModuleVerified(_moduleFactory, _verified); } diff --git a/contracts/mocks/MockFactory.sol b/contracts/mocks/MockFactory.sol index 90e64235d..ba1f38083 100644 --- a/contracts/mocks/MockFactory.sol +++ b/contracts/mocks/MockFactory.sol @@ -41,7 +41,9 @@ contract MockFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - return [0]; + uint8[] memory res = new uint8[](1); + res[0] = 0; + return res; } /** diff --git a/contracts/mocks/TestSTOFactory.sol b/contracts/mocks/TestSTOFactory.sol index 89540d1c1..71517dcb8 100644 --- a/contracts/mocks/TestSTOFactory.sol +++ b/contracts/mocks/TestSTOFactory.sol @@ -41,7 +41,9 @@ contract TestSTOFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - return [3]; + uint8[] memory res = new uint8[](1); + res[0] = 3; + return res; } /** diff --git a/contracts/modules/Burn/TrackedRedemptionFactory.sol b/contracts/modules/Burn/TrackedRedemptionFactory.sol index 99907f977..6611b2875 100644 --- a/contracts/modules/Burn/TrackedRedemptionFactory.sol +++ b/contracts/modules/Burn/TrackedRedemptionFactory.sol @@ -42,13 +42,15 @@ contract TrackedRedemptionFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - return [5]; + uint8[] memory res = new uint8[](1); + res[0] = 5; + return res; } /** * @notice Get the name of the Module */ - function getName() external view returns(bytes32) { + function getName() public view returns(bytes32) { return name; } diff --git a/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol b/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol index f978725f8..8d3644510 100644 --- a/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol +++ b/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol @@ -42,13 +42,15 @@ contract ERC20DividendCheckpointFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - return [4]; + uint8[] memory res = new uint8[](1); + res[0] = 4; + return res; } /** * @notice Get the name of the Module */ - function getName() external view returns(bytes32) { + function getName() public view returns(bytes32) { return name; } diff --git a/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol b/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol index 76d3a9f12..487af022b 100644 --- a/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol +++ b/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol @@ -41,14 +41,16 @@ contract EtherDividendCheckpointFactory is ModuleFactory { /** * @notice Type of the Module factory */ - function getTypse() external view returns(uint8[]) { - return [4]; + function getTypes() external view returns(uint8[]) { + uint8[] memory res = new uint8[](1); + res[0] = 4; + return res; } /** * @notice Get the name of the Module */ - function getName() external view returns(bytes32) { + function getName() public view returns(bytes32) { return name; } diff --git a/contracts/modules/PermissionManager/GeneralPermissionManagerFactory.sol b/contracts/modules/PermissionManager/GeneralPermissionManagerFactory.sol index 67d0b7df8..078f408dc 100644 --- a/contracts/modules/PermissionManager/GeneralPermissionManagerFactory.sol +++ b/contracts/modules/PermissionManager/GeneralPermissionManagerFactory.sol @@ -39,13 +39,15 @@ contract GeneralPermissionManagerFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - return [1]; + uint8[] memory res = new uint8[](1); + res[0] = 1; + return res; } /** * @notice Get the name of the Module */ - function getName() external view returns(bytes32) { + function getName() public view returns(bytes32) { return name; } diff --git a/contracts/modules/STO/CappedSTOFactory.sol b/contracts/modules/STO/CappedSTOFactory.sol index 6b75612a0..3c3597957 100644 --- a/contracts/modules/STO/CappedSTOFactory.sol +++ b/contracts/modules/STO/CappedSTOFactory.sol @@ -44,13 +44,15 @@ contract CappedSTOFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - return [3]; + uint8[] memory res = new uint8[](1); + res[0] = 3; + return res; } /** * @notice Get the name of the Module */ - function getName() external view returns(bytes32) { + function getName() public view returns(bytes32) { return name; } diff --git a/contracts/modules/STO/DummySTOFactory.sol b/contracts/modules/STO/DummySTOFactory.sol index 137cf6b6d..e4ddb8136 100644 --- a/contracts/modules/STO/DummySTOFactory.sol +++ b/contracts/modules/STO/DummySTOFactory.sol @@ -43,13 +43,15 @@ contract DummySTOFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - return [3]; + uint8[] memory res = new uint8[](1); + res[0] = 3; + return res; } /** * @notice Get the name of the Module */ - function getName() external view returns(bytes32) { + function getName() public view returns(bytes32) { return name; } diff --git a/contracts/modules/STO/PreSaleSTOFactory.sol b/contracts/modules/STO/PreSaleSTOFactory.sol index 223392669..a939fce19 100644 --- a/contracts/modules/STO/PreSaleSTOFactory.sol +++ b/contracts/modules/STO/PreSaleSTOFactory.sol @@ -46,13 +46,15 @@ contract PreSaleSTOFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - return [3]; + uint8[] memory res = new uint8[](1); + res[0] = 3; + return res; } /** * @notice Get the name of the Module */ - function getName() external view returns(bytes32) { + function getName() public view returns(bytes32) { return name; } diff --git a/contracts/modules/STO/USDTieredSTOFactory.sol b/contracts/modules/STO/USDTieredSTOFactory.sol index 4f9d772f0..e5a459f73 100644 --- a/contracts/modules/STO/USDTieredSTOFactory.sol +++ b/contracts/modules/STO/USDTieredSTOFactory.sol @@ -50,13 +50,15 @@ contract USDTieredSTOFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - return [3]; + uint8[] memory res = new uint8[](1); + res[0] = 3; + return res; } /** * @notice Get the name of the Module */ - function getName() external view returns(bytes32) { + function getName() public view returns(bytes32) { return name; } diff --git a/contracts/modules/TransferManager/CountTransferManagerFactory.sol b/contracts/modules/TransferManager/CountTransferManagerFactory.sol index 43acf38a6..1fe47a853 100644 --- a/contracts/modules/TransferManager/CountTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/CountTransferManagerFactory.sol @@ -44,13 +44,15 @@ contract CountTransferManagerFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - return [2]; + uint8[] memory res = new uint8[](1); + res[0] = 2; + return res; } /** * @notice Get the name of the Module */ - function getName() external view returns(bytes32) { + function getName() public view returns(bytes32) { return name; } diff --git a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol index 8ca244340..60e85f8f4 100644 --- a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol @@ -41,13 +41,15 @@ contract GeneralTransferManagerFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - return [2]; + uint8[] memory res = new uint8[](1); + res[0] = 2; + return res; } /** * @notice Get the name of the Module */ - function getName() external view returns(bytes32) { + function getName() public view returns(bytes32) { return name; } diff --git a/contracts/modules/TransferManager/ManualApprovalTransferManagerFactory.sol b/contracts/modules/TransferManager/ManualApprovalTransferManagerFactory.sol index ddc026042..e3ad15901 100644 --- a/contracts/modules/TransferManager/ManualApprovalTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/ManualApprovalTransferManagerFactory.sol @@ -42,13 +42,15 @@ contract ManualApprovalTransferManagerFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - return [2]; + uint8[] memory res = new uint8[](1); + res[0] = 2; + return res; } /** * @notice Get the name of the Module */ - function getName() external view returns(bytes32) { + function getName() public view returns(bytes32) { return name; } diff --git a/contracts/modules/TransferManager/PercentageTransferManagerFactory.sol b/contracts/modules/TransferManager/PercentageTransferManagerFactory.sol index 80ae0bd05..573c79ba1 100644 --- a/contracts/modules/TransferManager/PercentageTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/PercentageTransferManagerFactory.sol @@ -45,13 +45,15 @@ contract PercentageTransferManagerFactory is ModuleFactory { * @return uint8 */ function getTypes() external view returns(uint8[]) { - return [2]; + uint8[] memory res = new uint8[](1); + res[0] = 2; + return res; } /** * @notice Get the name of the Module */ - function getName() external view returns(bytes32) { + function getName() public view returns(bytes32) { return name; } diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 655625b71..2622d7fb5 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -335,19 +335,18 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr require(modulesToData[_module].module != address(0), "Module missing"); emit ModuleRemoved(modulesToData[_module].moduleTypes, _module, now); // Remove from module type list - uint8[] moduleTypes = modulesToData[_module].moduleTypes; + uint8[] memory moduleTypes = modulesToData[_module].moduleTypes; for (uint256 i = 0; i < moduleTypes.length; i++) { _removeModuleWithIndex(moduleTypes[i], modulesToData[_module].moduleIndexes[i]); } - // Remove from module names list uint256 index = modulesToData[_module].nameIndex; bytes32 name = modulesToData[_module].name; - length = names[name].length; + uint256 length = names[name].length; names[name][index] = names[name][length - 1]; names[name].length = length - 1; if ((length - 1) != index) { - modulesToData[modules[moduleType][index]].nameIndex = index; + modulesToData[names[name][index]].nameIndex = index; } // Remove from modulesToData delete modulesToData[_module]; @@ -367,7 +366,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr modulesToData[_module].module, modulesToData[_module].moduleFactory, modulesToData[_module].isArchived, - modulesToData[_module].moduleTypes, + modulesToData[_module].moduleTypes); } /** From 4838de702475b10666134183f625780aa7a3892b Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Tue, 2 Oct 2018 22:05:04 +0100 Subject: [PATCH 03/28] Merge branch 'development-1.5.0' into support_multiple_module_types # Conflicts: # contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol # contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol # contracts/tokens/SecurityToken.sol --- CHANGELOG.md | 1 + CLI/commands/ST20Generator.js | 6 +- CLI/commands/TickerRollForward.js | 4 +- CLI/commands/common/common_functions.js | 5 + CLI/commands/contract_manager.js | 15 +- CLI/commands/dividends_manager.js | 26 +- CLI/commands/helpers/contract_addresses.js | 2 +- contracts/SecurityTokenRegistry.sol | 293 ++++++----- contracts/interfaces/IOwnable.sol | 2 +- .../interfaces/ISecurityTokenRegistry.sol | 30 ++ .../modules/Checkpoint/DividendCheckpoint.sol | 453 +++++++++--------- .../Checkpoint/ERC20DividendCheckpoint.sol | 363 ++++++++------ .../Checkpoint/EtherDividendCheckpoint.sol | 330 +++++++------ contracts/modules/Checkpoint/ICheckpoint.sol | 16 +- contracts/oracles/MakerDAOOracle.sol | 12 +- contracts/oracles/PolyOracle.sol | 22 +- contracts/tokens/SecurityToken.sol | 50 +- scripts/test.sh | 6 +- test/a_poly_oracle.js | 20 +- test/b_capped_sto.js | 18 +- test/c_checkpoints.js | 2 +- test/d_count_transfer_manager.js | 2 +- test/e_erc20_dividends.js | 48 +- test/f_ether_dividends.js | 42 +- test/g_general_permission_manager.js | 2 +- test/h_general_transfer_manager.js | 2 +- test/j_manual_approval_transfer_manager.js | 2 +- test/k_module_registry.js | 4 +- test/l_percentage_transfer_manager.js | 2 +- test/m_presale_sto.js | 12 +- test/n_security_token_registry.js | 95 +++- test/o_security_token.js | 8 +- test/r_concurrent_STO.js | 2 +- test/t_security_token_registry_proxy.js | 2 +- test/v_tracked_redemptions.js | 2 +- 35 files changed, 1086 insertions(+), 815 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52e0d50da..ca2181f6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. [__1.5.0__](https://www.npmjs.com/package/polymath-core?activeTab=readme) __15-08-18__ ## Added +* Added `name` field to dividends struct in DividendCheckpoint. #295 * Added `getTagsByType`, `getTagsByTypeAndToken`, `getModulesByType`, `getModulesByTypeAndToken` to MR * Added `getTokensByOwner` to STR * Added withholding tax to ether & erc20 dividends diff --git a/CLI/commands/ST20Generator.js b/CLI/commands/ST20Generator.js index ae8466ad0..1b7fd034b 100644 --- a/CLI/commands/ST20Generator.js +++ b/CLI/commands/ST20Generator.js @@ -23,8 +23,6 @@ const MODULES_TYPES = { DIVIDENDS: 4 } -const REG_FEE_KEY = 'tickerRegFee'; -const LAUNCH_FEE_KEY = 'stLaunchFee'; const cappedSTOFee = 20000; const usdTieredSTOFee = 100000; const tokenDetails = ""; @@ -103,8 +101,8 @@ async function step_ticker_reg(){ console.log('\n\x1b[34m%s\x1b[0m',"Token Creation - Symbol Registration"); let available = false; + let regFee = web3.utils.fromWei(await securityTokenRegistry.methods.getTickerRegistrationFee().call()); let isDeployed; - let regFee = web3.utils.fromWei(await securityTokenRegistry.methods.getUintValues(web3.utils.soliditySha3(REG_FEE_KEY)).call()); while (!available) { console.log(chalk.green(`\nRegistering the new token symbol requires ${regFee} POLY & deducted from '${Issuer.address}', Current balance is ${(await currentBalance(Issuer.address))} POLY\n`)); @@ -156,7 +154,7 @@ async function step_token_deploy(){ } else { console.log('\n\x1b[34m%s\x1b[0m',"Token Creation - Token Deployment"); - let launchFee = web3.utils.fromWei(await securityTokenRegistry.methods.getUintValues(web3.utils.soliditySha3(LAUNCH_FEE_KEY)).call()); + let launchFee = web3.utils.fromWei(await securityTokenRegistry.methods.getSecurityTokenLaunchFee().call()); console.log(chalk.green(`\nToken deployment requires ${launchFee} POLY & deducted from '${Issuer.address}', Current balance is ${(await currentBalance(Issuer.address))} POLY\n`)); if (typeof _tokenConfig !== 'undefined' && _tokenConfig.hasOwnProperty('name')) { diff --git a/CLI/commands/TickerRollForward.js b/CLI/commands/TickerRollForward.js index 732eb1b97..97bd1f519 100644 --- a/CLI/commands/TickerRollForward.js +++ b/CLI/commands/TickerRollForward.js @@ -13,8 +13,6 @@ var abis = require('./helpers/contract_abis'); let remoteNetwork = process.argv.slice(2)[0]; //batch size ///////////////////////// GLOBAL VARS ///////////////////////// -const REG_FEE_KEY = 'tickerRegFee'; - let ticker_data = []; let registered_tickers = []; let failed_tickers = []; @@ -80,7 +78,7 @@ async function readFile() { async function registerTickers() { // Poly approval for registration fees let polyBalance = BigNumber(await polyToken.methods.balanceOf(Issuer.address).call()); - let fee = web3.utils.fromWei(await securityTokenRegistry.methods.getUintValues(web3.utils.soliditySha3(REG_FEE_KEY)).call()); + let fee = web3.utils.fromWei(await securityTokenRegistry.methods.getTickerRegistrationFee().call()); let totalFee = BigNumber(ticker_data.length).mul(fee); if (totalFee.gt(polyBalance)) { diff --git a/CLI/commands/common/common_functions.js b/CLI/commands/common/common_functions.js index 07de69fec..dbf3aa8dd 100644 --- a/CLI/commands/common/common_functions.js +++ b/CLI/commands/common/common_functions.js @@ -50,7 +50,12 @@ module.exports = { sendTransaction: async function (from, action, gasPrice, value, factor) { if (typeof factor === 'undefined') factor = 1.2; + let block = await web3.eth.getBlock("latest"); + let networkGasLimit = block.gasLimit; + let gas = Math.round(factor * (await action.estimateGas({ from: from.address, value: value}))); + if (gas > networkGasLimit) gas = networkGasLimit; + console.log(chalk.black.bgYellowBright(`---- Transaction executed: ${action._method.name} - Gas limit provided: ${gas} ----`)); let nonce = await web3.eth.getTransactionCount(from.address); diff --git a/CLI/commands/contract_manager.js b/CLI/commands/contract_manager.js index 60af89396..594522f6f 100644 --- a/CLI/commands/contract_manager.js +++ b/CLI/commands/contract_manager.js @@ -13,11 +13,6 @@ var global = require('./common/global'); var contracts = require('./helpers/contract_addresses'); var abis = require('./helpers/contract_abis'); -const OWNER_KEY = 'owner'; -const REG_FEE_KEY = 'tickerRegFee'; -const LAUNCH_FEE_KEY = 'stLaunchFee'; -const EXPIRY_LIMIT_KEY = 'expiryLimit'; - // App flow let currentContract = null; @@ -79,7 +74,7 @@ async function selectContract() { async function strActions() { console.log('\n\x1b[34m%s\x1b[0m',"Security Token Registry - Main menu"); - let contractOwner = await currentContract.methods.getAddressValues(web3.utils.soliditySha3(OWNER_KEY)).call(); + let contractOwner = await currentContract.methods.owner().call(); if (contractOwner != Issuer.address) { console.log(chalk.red(`You are not the owner of this contract. Current owner is ${contractOwner}`)); @@ -117,7 +112,7 @@ async function strActions() { console.log(chalk.green(`Ticker has been updated successfuly`)); break; case 'Remove Ticker': - let tickerToRemove = readlineSync.question('Enter the token symbol that you want to add or modify: '); + let tickerToRemove = readlineSync.question('Enter the token symbol that you want to remove: '); let tickerToRemoveDetails = await currentContract.methods.getTickerDetails(tickerToRemove).call(); if (tickerToRemoveDetails[1] == 0) { console.log(chalk.yellow(`${ticker} does not exist.`)); @@ -168,7 +163,7 @@ async function strActions() { console.log(chalk.green(`Security Token has been updated successfuly`)); break; case 'Change Expiry Limit': - let currentExpiryLimit = await currentContract.methods.getUintValues(web3.utils.soliditySha3(EXPIRY_LIMIT_KEY)).call(); + let currentExpiryLimit = await currentContract.methods.getExpiryLimit().call(); console.log(chalk.yellow(`Current expiry limit is ${Math.floor(parseInt(currentExpiryLimit)/60/60/24)} days`)); let newExpiryLimit = duration.days(readlineSync.questionInt('Enter a new value in days for expiry limit: ')); let changeExpiryLimitAction = currentContract.methods.changeExpiryLimit(newExpiryLimit); @@ -177,7 +172,7 @@ async function strActions() { console.log(chalk.green(`Expiry limit was changed successfuly. New limit is ${Math.floor(parseInt(changeExpiryLimitEvent._newExpiry)/60/60/24)} days\n`)); break; case 'Change registration fee': - let currentRegFee = web3.utils.fromWei(await currentContract.methods.getUintValues(web3.utils.soliditySha3(REG_FEE_KEY)).call()); + let currentRegFee = web3.utils.fromWei(await currentContract.methods.getTickerRegistrationFee().call()); console.log(chalk.yellow(`\nCurrent ticker registration fee is ${currentRegFee} POLY`)); let newRegFee = web3.utils.toWei(readlineSync.questionInt('Enter a new value in POLY for ticker registration fee: ').toString()); let changeRegFeeAction = currentContract.methods.changeTickerRegistrationFee(newRegFee); @@ -186,7 +181,7 @@ async function strActions() { console.log(chalk.green(`Fee was changed successfuly. New fee is ${web3.utils.fromWei(changeRegFeeEvent._newFee)} POLY\n`)); break; case 'Change ST launch fee': - let currentLaunchFee = web3.utils.fromWei(await currentContract.methods.getUintValues(web3.utils.soliditySha3(LAUNCH_FEE_KEY)).call()); + let currentLaunchFee = web3.utils.fromWei(await currentContract.methods.getSecurityTokenLaunchFee().call()); console.log(chalk.yellow(`\nCurrent ST launch fee is ${currentLaunchFee} POLY`)); let newLaunchFee = web3.utils.toWei(readlineSync.questionInt('Enter a new value in POLY for ST launch fee: ').toString()); let changeLaunchFeeAction = currentContract.methods.changeSecurityLaunchFee(newLaunchFee); diff --git a/CLI/commands/dividends_manager.js b/CLI/commands/dividends_manager.js index aeb81d818..a757b78ef 100644 --- a/CLI/commands/dividends_manager.js +++ b/CLI/commands/dividends_manager.js @@ -137,10 +137,11 @@ async function start_explorer(){ await taxHoldingMenu(); break; case 'Create dividends': - let dividend = readlineSync.question(`How much ${dividendsType} would you like to distribute to token holders?: `); + let divName = readlineSync.question(`Enter a name or title to indetify this dividend: `); + let dividend = readlineSync.question(`How much ${dividendsType} would you like to distribute to token holders?: `); await checkBalance(dividend); let checkpointId = currentCheckpoint == 0 ? 0 : await selectCheckpoint(true); // If there are no checkpoints, it must create a new one - await createDividends(dividend, checkpointId); + await createDividends(divName, dividend, checkpointId); break; case 'Explore account at checkpoint': let _address = readlineSync.question('Enter address to explore: '); @@ -316,7 +317,7 @@ async function taxHoldingMenu() { } } -async function createDividends(dividend, checkpointId) { +async function createDividends(name, dividend, checkpointId) { await addDividendsModule(); let time = Math.floor(Date.now()/1000); @@ -332,17 +333,17 @@ async function createDividends(dividend, checkpointId) { await common.sendTransaction(Issuer, approveAction, defaultGasPrice); if (checkpointId > 0) { if (useDefaultExcluded) { - createDividendAction = currentDividendsModule.methods.createDividendWithCheckpoint(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), checkpointId); + createDividendAction = currentDividendsModule.methods.createDividendWithCheckpoint(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), checkpointId, web3.utils.toHex(name)); } else { let excluded = getExcludedFromDataFile(); - createDividendAction = currentDividendsModule.methods.createDividendWithCheckpointAndExclusions(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), checkpointId, excluded); + createDividendAction = currentDividendsModule.methods.createDividendWithCheckpointAndExclusions(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), checkpointId, excluded, web3.utils.toHex(name)); } } else { if (useDefaultExcluded) { - createDividendAction = currentDividendsModule.methods.createDividend(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend)); + createDividendAction = currentDividendsModule.methods.createDividend(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), web3.utils.toHex(name)); } else { let excluded = getExcludedFromDataFile(); - createDividendAction = currentDividendsModule.methods.createDividendWithExclusions(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), excluded); + createDividendAction = currentDividendsModule.methods.createDividendWithExclusions(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), excluded, web3.utils.toHex(name)); } } let receipt = await common.sendTransaction(Issuer, createDividendAction, defaultGasPrice); @@ -351,17 +352,17 @@ async function createDividends(dividend, checkpointId) { } else if (dividendsType == 'ETH') { if (checkpointId > 0) { if (useDefaultExcluded) { - createDividendAction = currentDividendsModule.methods.createDividendWithCheckpoint(maturityTime, expiryTime, checkpointId); + createDividendAction = currentDividendsModule.methods.createDividendWithCheckpoint(maturityTime, expiryTime, checkpointId, web3.utils.toHex(name)); } else { let excluded = getExcludedFromDataFile(); - createDividendAction = currentDividendsModule.methods.createDividendWithCheckpointAndExclusions(maturityTime, expiryTime, checkpointId, excluded); + createDividendAction = currentDividendsModule.methods.createDividendWithCheckpointAndExclusions(maturityTime, expiryTime, checkpointId, excluded, web3.utils.toHex(name)); } } else { if (useDefaultExcluded) { - createDividendAction = currentDividendsModule.methods.createDividend(maturityTime, expiryTime); + createDividendAction = currentDividendsModule.methods.createDividend(maturityTime, expiryTime, web3.utils.toHex(name)); } else { let excluded = getExcludedFromDataFile(); - createDividendAction = currentDividendsModule.methods.createDividendWithExclusions(maturityTime, expiryTime, excluded); + createDividendAction = currentDividendsModule.methods.createDividendWithExclusions(maturityTime, expiryTime, excluded, web3.utils.toHex(name)); } } let receipt = await common.sendTransaction(Issuer, createDividendAction, defaultGasPrice, web3.utils.toWei(dividend)); @@ -543,7 +544,8 @@ async function selectDividend(filter) { if (dividends.length > 0) { let options = dividends.map(function(d) { - return `Created: ${moment.unix(d.created).format('MMMM Do YYYY, HH:mm:ss')} + return `${web3.utils.toAscii(d.name)} + Created: ${moment.unix(d.created).format('MMMM Do YYYY, HH:mm:ss')} Maturity: ${moment.unix(d.maturity).format('MMMM Do YYYY, HH:mm:ss')} Expiry: ${moment.unix(d.expiry).format('MMMM Do YYYY, HH:mm:ss')} At checkpoint: ${d.checkpointId} diff --git a/CLI/commands/helpers/contract_addresses.js b/CLI/commands/helpers/contract_addresses.js index 60c2531ea..b6dca4eeb 100644 --- a/CLI/commands/helpers/contract_addresses.js +++ b/CLI/commands/helpers/contract_addresses.js @@ -79,7 +79,7 @@ module.exports = { }, getModuleFactoryAddressByName: async function(stAddress, moduleType, moduleName) { let moduleRegistry = await getModuleRegistry(); - let availableModules = await moduleRegistry.methods.getAvailableModulesOfType(moduleType, stAddress).call(); + let availableModules = await moduleRegistry.methods.getModulesByTypeAndToken(moduleType, stAddress).call(); let result = null; let counter = 0; diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 1ae6193ff..438e2eef5 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -78,8 +78,6 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // Emit when ownership of the ticker gets changed event ChangeTickerOwnership(string _ticker, address indexed _oldOwner, address indexed _newOwner); - // Emit when a ticker details is modified - event ModifyTickerDetails(address _owner, string _ticker, string _name, uint256 _registrationDate, uint256 _expiryDate, bool _status); // Emit at the time of launching a new security token event NewSecurityToken( string _ticker, @@ -88,7 +86,8 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { address indexed _owner, uint256 _addedAt, address _registrant, - bool _fromAdmin + bool _fromAdmin, + uint256 _registrationFee ); // Emit after ticker registration event RegisterTicker( @@ -97,7 +96,8 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { string _name, uint256 indexed _registrationDate, uint256 indexed _expiryDate, - bool _fromAdmin + bool _fromAdmin, + uint256 _registrationFee ); ///////////////////////////// @@ -108,7 +108,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { - require(msg.sender == getAddress(Encoder.getKey("owner"))); + require(msg.sender == owner()); _; } @@ -116,10 +116,10 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @notice Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPausedOrOwner() { - if (msg.sender == getAddress(Encoder.getKey("owner"))) - _; + if (msg.sender == owner()) + _; else { - require(!getBool(Encoder.getKey("paused")), "Already paused"); + require(!isPaused(), "Already paused"); _; } } @@ -128,7 +128,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @notice Modifier to make a function callable only when the contract is not paused and ignore is msg.sender is owner. */ modifier whenNotPaused() { - require(!getBool(Encoder.getKey("paused")), "Already paused"); + require(!isPaused(), "Already paused"); _; } @@ -137,20 +137,15 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @notice Modifier to make a function callable only when the contract is paused. */ modifier whenPaused() { - require(getBool(Encoder.getKey("paused")), "Should not be paused"); + require(isPaused(), "Should not be paused"); _; } + ///////////////////////////// // Initialization ///////////////////////////// - // Constructor - constructor () public - { - - } - /** * @notice initializes instance of STR * @param _polymathRegistry is the address of the Polymath Registry @@ -162,9 +157,8 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function initialize(address _polymathRegistry, address _STFactory, uint256 _stLaunchFee, uint256 _tickerRegFee, address _polyToken, address _owner) payable external { require(!getBool(Encoder.getKey("initialised"))); - require(_STFactory != address(0) && _polyToken != address(0) && _owner != address(0) && _polymathRegistry != address(0), "In-valid address"); + require(_STFactory != address(0) && _polyToken != address(0) && _owner != address(0) && _polymathRegistry != address(0), "Invalid address"); require(_stLaunchFee != 0 && _tickerRegFee != 0, "Fees should not be 0"); - // address polyToken = _polyToken; set(Encoder.getKey("polyToken"), _polyToken); set(Encoder.getKey("stLaunchFee"), _stLaunchFee); set(Encoder.getKey("tickerRegFee"), _tickerRegFee); @@ -192,16 +186,26 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { require(_owner != address(0), "Owner should not be 0x"); require(bytes(_ticker).length > 0 && bytes(_ticker).length <= 10, "Ticker length range (0,10]"); // Attempt to charge the reg fee if it is > 0 POLY - if (getUint(Encoder.getKey("tickerRegFee")) > 0) - require(IERC20(getAddress(Encoder.getKey("polyToken"))).transferFrom(msg.sender, address(this), getUint(Encoder.getKey("tickerRegFee"))), "Sufficent allowance is not provided"); + uint256 tickerFee = getTickerRegistrationFee(); + if (tickerFee > 0) + require(IERC20(getAddress(Encoder.getKey("polyToken"))).transferFrom(msg.sender, address(this), tickerFee), "Insufficent allowance"); string memory ticker = Util.upper(_ticker); - require(_tickerAvailable(ticker), "Ticker is already reserved"); + require(_tickerAvailable(ticker), "Ticker is reserved"); // Check whether ticker was previously registered (and expired) - address previousOwner = getAddress(Encoder.getKey("registeredTickers_owner", _ticker)); + address previousOwner = _tickerOwner(ticker); if (previousOwner != address(0)) { - _deleteTickerOwnership(previousOwner, _ticker); + _deleteTickerOwnership(previousOwner, ticker); } - _addTicker(_owner, ticker, _tokenName, now, now.add(getUint(Encoder.getKey("expiryLimit"))), false, false); + _addTicker(_owner, ticker, _tokenName, now, now.add(getExpiryLimit()), false, false, tickerFee); + } + + /** + * @notice Internal - Sets the details of the ticker + */ + function _addTicker(address _owner, string _ticker, string _tokenName, uint256 _registrationDate, uint256 _expiryDate, bool _status, bool _fromAdmin, uint256 _fee) internal { + _setTickerOwnership(_owner, _ticker); + _storeTickerDetails(_ticker, _owner, _registrationDate, _expiryDate, _tokenName, _status); + emit RegisterTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, _fromAdmin, _fee); } /** @@ -218,7 +222,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { require(bytes(_ticker).length > 0 && bytes(_ticker).length <= 10, "Ticker length range (0,10]"); require(_expiryDate != 0 && _registrationDate != 0, "Dates should not be 0"); require(_registrationDate <= _expiryDate, "Registration date should < expiry date"); - require(_owner != address(0), "In-valid address"); + require(_owner != address(0), "Invalid address"); string memory ticker = Util.upper(_ticker); _modifyTicker(_owner, ticker, _tokenName, _registrationDate, _expiryDate, _status); } @@ -227,20 +231,22 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @notice Internal -- Modifies the ticker details. */ function _modifyTicker(address _owner, string _ticker, string _tokenName, uint256 _registrationDate, uint256 _expiryDate, bool _status) internal { - address currentOwner = getAddress(Encoder.getKey("registeredTickers_owner", _ticker)); - if (currentOwner == address(0) && _registrationDate == 0 && _expiryDate == 0) { - _addTicker(_owner, _ticker, _tokenName, now, now.add(getUint(Encoder.getKey("expiryLimit"))), _status, true); - return; - } - // If ticker exists, and is registered to a different owner, switch over - if ((currentOwner != address(0)) && (currentOwner != _owner)) { - _transferTickerOwnership(currentOwner, _owner, _ticker); + address currentOwner = _tickerOwner(_ticker); + if (currentOwner != address(0)) { + _deleteTickerOwnership(currentOwner, _ticker); } - if (getBool(Encoder.getKey("registeredTickers_status", _ticker)) && !_status) { + if (_tickerStatus(_ticker) && !_status) { set(Encoder.getKey("tickerToSecurityToken", _ticker), address(0)); } - _storeTickerDetails(_ticker, _owner, _registrationDate, _expiryDate, _tokenName, _status); - emit RegisterTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, true); + // If status is true, there must be a security token linked to the ticker already + if (_status) { + require(getAddress(Encoder.getKey("tickerToSecurityToken", _ticker)) != address(0), "Token not registered"); + } + _addTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, _status, true, uint256(0)); + } + + function _tickerOwner(string _ticker) internal view returns(address) { + return getAddress(Encoder.getKey("registeredTickers_owner", _ticker)); } /** @@ -249,12 +255,12 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function removeTicker(string _ticker) external onlyOwner { string memory ticker = Util.upper(_ticker); - address owner = getAddress(Encoder.getKey("registeredTickers_owner", ticker)); + address owner = _tickerOwner(ticker); require(owner != address(0), "Ticker doesn't exist"); _deleteTickerOwnership(owner, ticker); set(Encoder.getKey("tickerToSecurityToken", ticker), address(0)); _storeTickerDetails(ticker, address(0), 0, 0, "", false); - emit TickerRemoved(_ticker, now, msg.sender); + emit TickerRemoved(ticker, now, msg.sender); } /** @@ -263,8 +269,8 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @return bool */ function _tickerAvailable(string _ticker) internal view returns(bool) { - if (getAddress(Encoder.getKey("registeredTickers_owner", _ticker)) != address(0)) { - if (now > getUint(Encoder.getKey("registeredTickers_expiryDate", _ticker)) && !getBool(Encoder.getKey("registeredTickers_status", _ticker))) { + if (_tickerOwner(_ticker) != address(0)) { + if ((now > getUint(Encoder.getKey("registeredTickers_expiryDate", _ticker))) && !_tickerStatus(_ticker)) { return true; } else return false; @@ -272,13 +278,8 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { return true; } - /** - * @notice Internal - Sets the details of the ticker - */ - function _addTicker(address _owner, string _ticker, string _tokenName, uint256 _registrationDate, uint256 _expiryDate, bool _status, bool _fromAdmin) internal { - _setTickerOwner(_owner, _ticker); - _storeTickerDetails(_ticker, _owner, _registrationDate, _expiryDate, _tokenName, _status); - emit RegisterTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, _fromAdmin); + function _tickerStatus(string _ticker) internal returns(bool) { + return getBool(Encoder.getKey("registeredTickers_status", _ticker)); } /** @@ -286,13 +287,15 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _owner is the address of the owner of the ticker * @param _ticker is the ticker symbol */ - function _setTickerOwner(address _owner, string _ticker) internal { - uint256 length = uint256(getArrayBytes32(Encoder.getKey("userToTickers", _owner)).length); - pushArray(Encoder.getKey("userToTickers", _owner), Util.stringToBytes32(_ticker)); + function _setTickerOwnership(address _owner, string _ticker) internal { + bytes32 _ownerKey = Encoder.getKey("userToTickers", _owner); + uint256 length = uint256(getArrayBytes32(_ownerKey).length); + pushArray(_ownerKey, Util.stringToBytes32(_ticker)); set(Encoder.getKey("tickerIndex", _ticker), length); - if (!getBool(Encoder.getKey("seenUsers", _owner))) { + bytes32 seenKey = Encoder.getKey("seenUsers", _owner); + if (!getBool(seenKey)) { pushArray(Encoder.getKey("activeUsers"), _owner); - set(Encoder.getKey("seenUsers", _owner), true); + set(seenKey, true); } } @@ -300,16 +303,21 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @notice Internal - Stores the ticker details */ function _storeTickerDetails(string _ticker, address _owner, uint256 _registrationDate, uint256 _expiryDate, string _tokenName, bool _status) internal { - if (getAddress(Encoder.getKey("registeredTickers_owner", _ticker)) != _owner) - set(Encoder.getKey("registeredTickers_owner", _ticker), _owner); - if (getUint(Encoder.getKey("registeredTickers_registrationDate", _ticker)) != _registrationDate) - set(Encoder.getKey("registeredTickers_registrationDate", _ticker), _registrationDate); - if (getUint(Encoder.getKey("registeredTickers_expiryDate", _ticker)) != _expiryDate) - set(Encoder.getKey("registeredTickers_expiryDate", _ticker), _expiryDate); - if (Encoder.getKey(getString(Encoder.getKey("registeredTickers_tokenName", _ticker))) != Encoder.getKey(_tokenName)) - set(Encoder.getKey("registeredTickers_tokenName", _ticker), _tokenName); - if (getBool(Encoder.getKey("registeredTickers_status", _ticker)) != _status) - set(Encoder.getKey("registeredTickers_status", _ticker), _status); + bytes32 key = Encoder.getKey("registeredTickers_owner", _ticker); + if (getAddress(key) != _owner) + set(key, _owner); + key = Encoder.getKey("registeredTickers_registrationDate", _ticker); + if (getUint(key) != _registrationDate) + set(key, _registrationDate); + key = Encoder.getKey("registeredTickers_expiryDate", _ticker); + if (getUint(key) != _expiryDate) + set(key, _expiryDate); + key = Encoder.getKey("registeredTickers_tokenName", _ticker); + if (Encoder.getKey(getString(key)) != Encoder.getKey(_tokenName)) + set(key, _tokenName); + key = Encoder.getKey("registeredTickers_status", _ticker); + if (getBool(key) != _status) + set(key, _status); } /** @@ -319,39 +327,30 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function transferTickerOwnership(address _newOwner, string _ticker) external whenNotPausedOrOwner { string memory ticker = Util.upper(_ticker); - require(_newOwner != address(0), "In-valid address"); - require(getAddress(Encoder.getKey("registeredTickers_owner", ticker)) == msg.sender, "Not authorised"); - _transferTickerOwnership(msg.sender, _newOwner, ticker); - set(Encoder.getKey("registeredTickers_owner", ticker), _newOwner); - } - - /** - * @notice Internal - Transfers the control of ticker to a newOwner - * @param _oldOwner is the previous owner - * @param _newOwner is the the new owner - * @param _ticker is the ticker symbol - */ - function _transferTickerOwnership(address _oldOwner, address _newOwner, string _ticker) internal { - if(getBool(Encoder.getKey("registeredTickers_status", _ticker))) - require(IOwnable(getAddress(Encoder.getKey("tickerToSecurityToken", _ticker))).owner() == _newOwner, "Ticker can only be transferred to its token owner"); - - _deleteTickerOwnership(_oldOwner, _ticker); - _setTickerOwner(_newOwner, _ticker); - emit ChangeTickerOwnership(_ticker, _oldOwner, _newOwner); + require(_newOwner != address(0), "Invalid address"); + bytes32 ownerKey = Encoder.getKey("registeredTickers_owner", ticker); + require(getAddress(ownerKey) == msg.sender, "Not authorised"); + if (_tickerStatus(ticker)) + require(IOwnable(getAddress(Encoder.getKey("tickerToSecurityToken", ticker))).owner() == _newOwner, "New owner does not match token owner"); + _deleteTickerOwnership(msg.sender, ticker); + _setTickerOwnership(_newOwner, ticker); + set(ownerKey, _newOwner); + emit ChangeTickerOwnership(ticker, msg.sender, _newOwner); } /** * @notice Internal - Removes the owner of a ticker */ function _deleteTickerOwnership(address _owner, string _ticker) internal { - uint256 _index = uint256(getUint(Encoder.getKey("tickerIndex", _ticker))); - assert(_index < getArrayBytes32(Encoder.getKey("userToTickers", _owner)).length); - // deleting the _index from the data strucutre userToTickers[_oldowner][_index]; - deleteArrayBytes32(Encoder.getKey("userToTickers", _owner), _index); - - if (getArrayBytes32(Encoder.getKey("userToTickers", _owner)).length > _index) { - bytes32 switchedTicker = getArrayBytes32(Encoder.getKey("userToTickers", _owner))[_index]; - set(Encoder.getKey("tickerIndex", Util.bytes32ToString(switchedTicker)), _index); + uint256 index = uint256(getUint(Encoder.getKey("tickerIndex", _ticker))); + bytes32 ownerKey = Encoder.getKey("userToTickers", _owner); + bytes32[] memory tickers = getArrayBytes32(ownerKey); + assert(index < tickers.length); + assert(_tickerOwner(_ticker) == _owner); + deleteArrayBytes32(ownerKey, index); + if (getArrayBytes32(ownerKey).length > index) { + bytes32 switchedTicker = getArrayBytes32(ownerKey)[index]; + set(Encoder.getKey("tickerIndex", Util.bytes32ToString(switchedTicker)), index); } } @@ -361,8 +360,9 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function changeExpiryLimit(uint256 _newExpiry) external onlyOwner { require(_newExpiry >= 1 days, "Expiry should >= 1 day"); - emit ChangeExpiryLimit(getUint(Encoder.getKey('expiryLimit')), _newExpiry); - set(Encoder.getKey('expiryLimit'), _newExpiry); + bytes32 key = Encoder.getKey('expiryLimit'); + emit ChangeExpiryLimit(getUint(key), _newExpiry); + set(key, _newExpiry); } /** @@ -372,12 +372,12 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { function getTickersByOwner(address _owner) external view returns(bytes32[]) { uint counter = 0; // accessing the data structure userTotickers[_owner].length - uint _len = getArrayBytes32(Encoder.getKey("userToTickers", _owner)).length; - bytes32[] memory tempList = new bytes32[](_len); - for (uint i = 0; i < _len; i++) { - string memory _ticker = Util.bytes32ToString(getArrayBytes32(Encoder.getKey("userToTickers", _owner))[i]); - if (getUint(Encoder.getKey("registeredTickers_expiryDate", _ticker)) >= now || getBool(Encoder.getKey("registeredTickers_status", _ticker))) { - tempList[counter] = getArrayBytes32(Encoder.getKey("userToTickers", _owner))[i]; + bytes32[] memory tickers = getArrayBytes32(Encoder.getKey("userToTickers", _owner)); + bytes32[] memory tempList = new bytes32[](tickers.length); + for (uint i = 0; i < tickers.length; i++) { + string memory ticker = Util.bytes32ToString(tickers[i]); + if (getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)) >= now || _tickerStatus(ticker)) { + tempList[counter] = tickers[i]; counter ++; } } @@ -437,14 +437,16 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function getTickerDetails(string _ticker) external view returns (address, uint256, uint256, string, bool) { string memory ticker = Util.upper(_ticker); - if (getBool(Encoder.getKey("registeredTickers_status", ticker)) == true || getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)) > now) { + bool tickerStatus = _tickerStatus(ticker); + uint256 expiryDate = getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)); + if ((tickerStatus == true) || (expiryDate > now)) { return ( - getAddress(Encoder.getKey("registeredTickers_owner", ticker)), + _tickerOwner(ticker), getUint(Encoder.getKey("registeredTickers_registrationDate", ticker)), - getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)), + expiryDate, getString(Encoder.getKey("registeredTickers_tokenName", ticker)), - getBool(Encoder.getKey("registeredTickers_status", ticker)) + tickerStatus ); } else return (address(0), uint256(0), uint256(0), "", false); @@ -464,15 +466,15 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { function generateSecurityToken(string _name, string _ticker, string _tokenDetails, bool _divisible) external whenNotPausedOrOwner { require(bytes(_name).length > 0 && bytes(_ticker).length > 0, "Ticker length > 0"); string memory ticker = Util.upper(_ticker); - - require(getBool(Encoder.getKey("registeredTickers_status", ticker)) != true, "Already deployed"); - require(getAddress(Encoder.getKey("registeredTickers_owner", ticker)) == msg.sender, "Not authorised"); + bytes32 statusKey = Encoder.getKey("registeredTickers_status", ticker); + require(!getBool(statusKey), "Already deployed"); + set(statusKey, true); + require(_tickerOwner(ticker) == msg.sender, "Not authorised"); require(getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)) >= now, "Ticker gets expired"); - set(Encoder.getKey("registeredTickers_status", ticker), true); - - if (getUint(Encoder.getKey("stLaunchFee")) > 0) - require(IERC20(getAddress(Encoder.getKey("polyToken"))).transferFrom(msg.sender, address(this), getUint(Encoder.getKey("stLaunchFee"))), "Insufficient allowance"); + uint256 launchFee = getSecurityTokenLaunchFee(); + if (launchFee > 0) + require(IERC20(getAddress(Encoder.getKey("polyToken"))).transferFrom(msg.sender, address(this), launchFee), "Insufficient allowance"); address newSecurityTokenAddress = ISTFactory(getSTFactoryAddress()).deployToken( _name, @@ -486,7 +488,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { _storeSecurityTokenData(newSecurityTokenAddress, ticker, _tokenDetails, now); set(Encoder.getKey("tickerToSecurityToken", ticker), newSecurityTokenAddress); - emit NewSecurityToken(ticker, _name, newSecurityTokenAddress, msg.sender, now, msg.sender, false); + emit NewSecurityToken(ticker, _name, newSecurityTokenAddress, msg.sender, now, msg.sender, false, launchFee); } /** @@ -504,11 +506,16 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { require(_deployedAt != 0 && _owner != address(0), "0 value params not allowed"); string memory ticker = Util.upper(_ticker); require(_securityToken != address(0), "ST address is 0x"); - // If ticker didn't previously exist, it will be created - _modifyTicker(_owner, ticker, _name, getUint(Encoder.getKey("registeredTickers_registrationDate", ticker)), getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)), true); + uint256 registrationTime = getUint(Encoder.getKey("registeredTickers_registrationDate", ticker)); + uint256 expiryTime = getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)); + if (registrationTime == 0) { + registrationTime = now; + expiryTime = registrationTime.add(getExpiryLimit()); + } set(Encoder.getKey("tickerToSecurityToken", ticker), _securityToken); + _modifyTicker(_owner, ticker, _name, registrationTime, expiryTime, true); _storeSecurityTokenData(_securityToken, ticker, _tokenDetails, _deployedAt); - emit NewSecurityToken(ticker, _name, _securityToken, _owner, _deployedAt, msg.sender, true); + emit NewSecurityToken(ticker, _name, _securityToken, _owner, _deployedAt, msg.sender, true, getSecurityTokenLaunchFee()); } /** @@ -566,8 +573,9 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function transferOwnership(address _newOwner) external onlyOwner { require(_newOwner != address(0)); - emit OwnershipTransferred(getAddress(Encoder.getKey("owner")), _newOwner); - set(Encoder.getKey("owner"), _newOwner); + bytes32 key = Encoder.getKey("owner"); + emit OwnershipTransferred(getAddress(key), _newOwner); + set(key, _newOwner); } /** @@ -591,9 +599,11 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _tickerRegFee is the registration fee in POLY tokens (base 18 decimals) */ function changeTickerRegistrationFee(uint256 _tickerRegFee) external onlyOwner { - require(getUint(Encoder.getKey('tickerRegFee')) != _tickerRegFee); - emit ChangeTickerRegistrationFee(getUint(Encoder.getKey('tickerRegFee')), _tickerRegFee); - set(Encoder.getKey('tickerRegFee'), _tickerRegFee); + bytes32 key = Encoder.getKey('tickerRegFee'); + uint256 fee = getUint(key); + require(fee != _tickerRegFee); + emit ChangeTickerRegistrationFee(fee, _tickerRegFee); + set(key, _tickerRegFee); } /** @@ -601,9 +611,11 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _stLaunchFee is the registration fee in POLY tokens (base 18 decimals) */ function changeSecurityLaunchFee(uint256 _stLaunchFee) external onlyOwner { - require(getUint(Encoder.getKey("stLaunchFee")) != _stLaunchFee); - emit ChangeSecurityLaunchFee(getUint(Encoder.getKey("stLaunchFee")), _stLaunchFee); - set(Encoder.getKey("stLaunchFee"), _stLaunchFee); + bytes32 key = Encoder.getKey('stLaunchFee'); + uint256 fee = getUint(key); + require(fee != _stLaunchFee); + emit ChangeSecurityLaunchFee(fee, _stLaunchFee); + set(key, _stLaunchFee); } /** @@ -614,7 +626,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { require(_tokenContract != address(0)); IERC20 token = IERC20(_tokenContract); uint256 balance = token.balanceOf(address(this)); - require(token.transfer(getAddress(Encoder.getKey("owner")), balance)); + require(token.transfer(owner(), balance)); } /** @@ -667,5 +679,44 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { set(Encoder.getKey("polyToken"), _newAddress); } + /** + * @notice Gets the security token launch fee + * @return Fee amount + */ + function getSecurityTokenLaunchFee() public view returns(uint256) { + return getUint(Encoder.getKey("stLaunchFee")); + } + + /** + * @notice Gets the ticker registration fee + * @return Fee amount + */ + function getTickerRegistrationFee() public view returns(uint256) { + return getUint(Encoder.getKey("tickerRegFee")); + } + + /** + * @notice Gets the expiry limit + * @return Expiry limit + */ + function getExpiryLimit() public view returns(uint256) { + return getUint(Encoder.getKey("expiryLimit")); + } + + /** + * @notice Check whether the registry is paused or not + * @return bool + */ + function isPaused() public view returns(bool) { + return getBool(Encoder.getKey("paused")); + } + + /** + * @notice Gets the owner of the contract + * @return address owner + */ + function owner() public view returns(address) { + return getAddress(Encoder.getKey("owner")); + } } diff --git a/contracts/interfaces/IOwnable.sol b/contracts/interfaces/IOwnable.sol index 15849e181..de8a8d14f 100644 --- a/contracts/interfaces/IOwnable.sol +++ b/contracts/interfaces/IOwnable.sol @@ -10,7 +10,7 @@ interface IOwnable { /** * @dev Returns owner */ - function owner() external returns (address); + function owner() external view returns (address); /** * @dev Allows the current owner to relinquish control of the contract. diff --git a/contracts/interfaces/ISecurityTokenRegistry.sol b/contracts/interfaces/ISecurityTokenRegistry.sol index d7ec8f9f0..2bacd39d7 100644 --- a/contracts/interfaces/ISecurityTokenRegistry.sol +++ b/contracts/interfaces/ISecurityTokenRegistry.sol @@ -159,4 +159,34 @@ interface ISecurityTokenRegistry { */ function updatePolyTokenAddress(address _newAddress) external; + /** + * @notice Gets the security token launch fee + * @return Fee amount + */ + function getSecurityTokenLaunchFee() external view returns(uint256); + + /** + * @notice Gets the ticker registration fee + * @return Fee amount + */ + function getTickerRegistrationFee() external view returns(uint256); + + /** + * @notice Gets the expiry limit + * @return Expiry limit + */ + function getExpiryLimit() external view returns(uint256); + + /** + * @notice Check whether the registry is paused or not + * @return bool + */ + function isPaused() external view returns(bool); + + /** + * @notice Gets the owner of the contract + * @return address owner + */ + function owner() external view returns(address); + } diff --git a/contracts/modules/Checkpoint/DividendCheckpoint.sol b/contracts/modules/Checkpoint/DividendCheckpoint.sol index d751e02fe..fc70a9fde 100644 --- a/contracts/modules/Checkpoint/DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/DividendCheckpoint.sol @@ -1,226 +1,227 @@ -pragma solidity ^0.4.24; - -import "./ICheckpoint.sol"; -import "../Module.sol"; -import "../../interfaces/ISecurityToken.sol"; -import "openzeppelin-solidity/contracts/math/SafeMath.sol"; -import "openzeppelin-solidity/contracts/math/Math.sol"; - -/** - * @title Checkpoint module for issuing ether dividends - * @dev abstract contract - */ -contract DividendCheckpoint is ICheckpoint, Module { - using SafeMath for uint256; - - uint256 public EXCLUDED_ADDRESS_LIMIT = 50; - bytes32 public constant DISTRIBUTE = "DISTRIBUTE"; - - struct Dividend { - uint256 checkpointId; - uint256 created; // Time at which the dividend was created - uint256 maturity; // Time after which dividend can be claimed - set to 0 to bypass - uint256 expiry; // Time until which dividend can be claimed - after this time any remaining amount can be withdrawn by issuer - set to very high value to bypass - uint256 amount; // Dividend amount in WEI - uint256 claimedAmount; // Amount of dividend claimed so far - uint256 totalSupply; // Total supply at the associated checkpoint (avoids recalculating this) - bool reclaimed; // True if expiry has passed and issuer has reclaimed remaining dividend - uint256 dividendWithheld; - uint256 dividendWithheldReclaimed; - mapping (address => bool) claimed; // List of addresses which have claimed dividend - mapping (address => bool) dividendExcluded; // List of addresses which cannot claim dividends - } - - // List of all dividends - Dividend[] public dividends; - - // List of addresses which cannot claim dividends - address[] public excluded; - - // Mapping from address to withholding tax as a percentage * 10**16 - mapping (address => uint256) public withholdingTax; - - // Total amount of ETH withheld per investor - mapping (address => uint256) public investorWithheld; - - event SetDefaultExcludedAddresses(address[] _excluded, uint256 _timestamp); - event SetWithholding(address[] _investors, uint256[] _withholding, uint256 _timestamp); - event SetWithholdingFixed(address[] _investors, uint256 _withholding, uint256 _timestamp); - - modifier validDividendIndex(uint256 _dividendIndex) { - require(_dividendIndex < dividends.length, "Incorrect dividend index"); - require(now >= dividends[_dividendIndex].maturity, "Dividend maturity is in the future"); - require(now < dividends[_dividendIndex].expiry, "Dividend expiry is in the past"); - require(!dividends[_dividendIndex].reclaimed, "Dividend has been reclaimed by issuer"); - _; - } - - /** - * @notice Init function i.e generalise function to maintain the structure of the module contract - * @return bytes4 - */ - function getInitFunction() public pure returns (bytes4) { - return bytes4(0); - } - - /** - * @notice Return the default excluded addresses - * @return List of excluded addresses - */ - function getDefaultExcluded() external view returns (address[]) { - return excluded; - } - - /** - * @notice Function to clear and set list of excluded addresses used for future dividends - * @param _excluded addresses of investor - */ - function setDefaultExcluded(address[] _excluded) public onlyOwner { - require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many excluded addresses"); - excluded = _excluded; - emit SetDefaultExcludedAddresses(excluded, now); - } - - /** - * @notice Function to set withholding tax rates for investors - * @param _investors addresses of investor - * @param _withholding withholding tax for individual investors (multiplied by 10**16) - */ - function setWithholding(address[] _investors, uint256[] _withholding) public onlyOwner { - require(_investors.length == _withholding.length, "Mismatched input lengths"); - emit SetWithholding(_investors, _withholding, now); - for (uint256 i = 0; i < _investors.length; i++) { - require(_withholding[i] <= 10**18, "Incorrect withholding tax"); - withholdingTax[_investors[i]] = _withholding[i]; - } - } - - /** - * @notice Function to set withholding tax rates for investors - * @param _investors addresses of investor - * @param _withholding withholding tax for all investors (multiplied by 10**16) - */ - function setWithholdingFixed(address[] _investors, uint256 _withholding) public onlyOwner { - require(_withholding <= 10**18, "Incorrect withholding tax"); - emit SetWithholdingFixed(_investors, _withholding, now); - for (uint256 i = 0; i < _investors.length; i++) { - withholdingTax[_investors[i]] = _withholding; - } - } - - /** - * @notice Issuer can push dividends to provided addresses - * @param _dividendIndex Dividend to push - * @param _payees Addresses to which to push the dividend - */ - function pushDividendPaymentToAddresses(uint256 _dividendIndex, address[] _payees) public withPerm(DISTRIBUTE) validDividendIndex(_dividendIndex) { - Dividend storage dividend = dividends[_dividendIndex]; - for (uint256 i = 0; i < _payees.length; i++) { - if ((!dividend.claimed[_payees[i]]) && (!dividend.dividendExcluded[_payees[i]])) { - _payDividend(_payees[i], dividend, _dividendIndex); - } - } - } - - /** - * @notice Issuer can push dividends using the investor list from the security token - * @param _dividendIndex Dividend to push - * @param _start Index in investor list at which to start pushing dividends - * @param _iterations Number of addresses to push dividends for - */ - function pushDividendPayment(uint256 _dividendIndex, uint256 _start, uint256 _iterations) public withPerm(DISTRIBUTE) validDividendIndex(_dividendIndex) { - Dividend storage dividend = dividends[_dividendIndex]; - uint256 numberInvestors = ISecurityToken(securityToken).getInvestorsLength(); - for (uint256 i = _start; i < Math.min256(numberInvestors, _start.add(_iterations)); i++) { - address payee = ISecurityToken(securityToken).investors(i); - if ((!dividend.claimed[payee]) && (!dividend.dividendExcluded[payee])) { - _payDividend(payee, dividend, _dividendIndex); - } - } - } - - /** - * @notice Investors can pull their own dividends - * @param _dividendIndex Dividend to pull - */ - function pullDividendPayment(uint256 _dividendIndex) public validDividendIndex(_dividendIndex) - { - Dividend storage dividend = dividends[_dividendIndex]; - require(!dividend.claimed[msg.sender], "Dividend already claimed by msg.sender"); - require(!dividend.dividendExcluded[msg.sender], "msg.sender excluded from Dividend"); - _payDividend(msg.sender, dividend, _dividendIndex); - } - - /** - * @notice Internal function for paying dividends - * @param _payee address of investor - * @param _dividend storage with previously issued dividends - * @param _dividendIndex Dividend to pay - */ - function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal; - - /** - * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends - * @param _dividendIndex Dividend to reclaim - */ - function reclaimDividend(uint256 _dividendIndex) external; - - /** - * @notice Calculate amount of dividends claimable - * @param _dividendIndex Dividend to calculate - * @param _payee Affected investor address - * @return claim, withheld amounts - */ - function calculateDividend(uint256 _dividendIndex, address _payee) public view returns(uint256, uint256) { - require(_dividendIndex < dividends.length, "Incorrect dividend index"); - Dividend storage dividend = dividends[_dividendIndex]; - if (dividend.claimed[_payee] || dividend.dividendExcluded[_payee]) { - return (0, 0); - } - uint256 balance = ISecurityToken(securityToken).balanceOfAt(_payee, dividend.checkpointId); - uint256 claim = balance.mul(dividend.amount).div(dividend.totalSupply); - uint256 withheld = claim.mul(withholdingTax[_payee]).div(uint256(10**18)); - return (claim, withheld); - } - - /** - * @notice Get the index according to the checkpoint id - * @param _checkpointId Checkpoint id to query - * @return uint256[] - */ - function getDividendIndex(uint256 _checkpointId) public view returns(uint256[]) { - uint256 counter = 0; - for(uint256 i = 0; i < dividends.length; i++) { - if (dividends[i].checkpointId == _checkpointId) { - counter++; - } - } - - uint256[] memory index = new uint256[](counter); - counter = 0; - for(uint256 j = 0; j < dividends.length; j++) { - if (dividends[j].checkpointId == _checkpointId) { - index[counter] = j; - counter++; - } - } - return index; - } - - /** - * @notice Allows issuer to withdraw withheld tax - * @param _dividendIndex Dividend to withdraw from - */ - function withdrawWithholding(uint256 _dividendIndex) external; - - /** - * @notice Return the permissions flag that are associated with STO - * @return bytes32 array - */ - function getPermissions() public view returns(bytes32[]) { - bytes32[] memory allPermissions = new bytes32[](1); - allPermissions[0] = DISTRIBUTE; - return allPermissions; - } - -} +pragma solidity ^0.4.24; + +import "./ICheckpoint.sol"; +import "../Module.sol"; +import "../../interfaces/ISecurityToken.sol"; +import "openzeppelin-solidity/contracts/math/SafeMath.sol"; +import "openzeppelin-solidity/contracts/math/Math.sol"; + +/** + * @title Checkpoint module for issuing ether dividends + * @dev abstract contract + */ +contract DividendCheckpoint is ICheckpoint, Module { + using SafeMath for uint256; + + uint256 public EXCLUDED_ADDRESS_LIMIT = 50; + bytes32 public constant DISTRIBUTE = "DISTRIBUTE"; + + struct Dividend { + uint256 checkpointId; + uint256 created; // Time at which the dividend was created + uint256 maturity; // Time after which dividend can be claimed - set to 0 to bypass + uint256 expiry; // Time until which dividend can be claimed - after this time any remaining amount can be withdrawn by issuer - set to very high value to bypass + uint256 amount; // Dividend amount in WEI + uint256 claimedAmount; // Amount of dividend claimed so far + uint256 totalSupply; // Total supply at the associated checkpoint (avoids recalculating this) + bool reclaimed; // True if expiry has passed and issuer has reclaimed remaining dividend + uint256 dividendWithheld; + uint256 dividendWithheldReclaimed; + mapping (address => bool) claimed; // List of addresses which have claimed dividend + mapping (address => bool) dividendExcluded; // List of addresses which cannot claim dividends + bytes32 name; // Name/title - used for identification + } + + // List of all dividends + Dividend[] public dividends; + + // List of addresses which cannot claim dividends + address[] public excluded; + + // Mapping from address to withholding tax as a percentage * 10**16 + mapping (address => uint256) public withholdingTax; + + // Total amount of ETH withheld per investor + mapping (address => uint256) public investorWithheld; + + event SetDefaultExcludedAddresses(address[] _excluded, uint256 _timestamp); + event SetWithholding(address[] _investors, uint256[] _withholding, uint256 _timestamp); + event SetWithholdingFixed(address[] _investors, uint256 _withholding, uint256 _timestamp); + + modifier validDividendIndex(uint256 _dividendIndex) { + require(_dividendIndex < dividends.length, "Incorrect dividend index"); + require(now >= dividends[_dividendIndex].maturity, "Dividend maturity is in the future"); + require(now < dividends[_dividendIndex].expiry, "Dividend expiry is in the past"); + require(!dividends[_dividendIndex].reclaimed, "Dividend has been reclaimed by issuer"); + _; + } + + /** + * @notice Init function i.e generalise function to maintain the structure of the module contract + * @return bytes4 + */ + function getInitFunction() public pure returns (bytes4) { + return bytes4(0); + } + + /** + * @notice Return the default excluded addresses + * @return List of excluded addresses + */ + function getDefaultExcluded() external view returns (address[]) { + return excluded; + } + + /** + * @notice Function to clear and set list of excluded addresses used for future dividends + * @param _excluded addresses of investor + */ + function setDefaultExcluded(address[] _excluded) public onlyOwner { + require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many excluded addresses"); + excluded = _excluded; + emit SetDefaultExcludedAddresses(excluded, now); + } + + /** + * @notice Function to set withholding tax rates for investors + * @param _investors addresses of investor + * @param _withholding withholding tax for individual investors (multiplied by 10**16) + */ + function setWithholding(address[] _investors, uint256[] _withholding) public onlyOwner { + require(_investors.length == _withholding.length, "Mismatched input lengths"); + emit SetWithholding(_investors, _withholding, now); + for (uint256 i = 0; i < _investors.length; i++) { + require(_withholding[i] <= 10**18, "Incorrect withholding tax"); + withholdingTax[_investors[i]] = _withholding[i]; + } + } + + /** + * @notice Function to set withholding tax rates for investors + * @param _investors addresses of investor + * @param _withholding withholding tax for all investors (multiplied by 10**16) + */ + function setWithholdingFixed(address[] _investors, uint256 _withholding) public onlyOwner { + require(_withholding <= 10**18, "Incorrect withholding tax"); + emit SetWithholdingFixed(_investors, _withholding, now); + for (uint256 i = 0; i < _investors.length; i++) { + withholdingTax[_investors[i]] = _withholding; + } + } + + /** + * @notice Issuer can push dividends to provided addresses + * @param _dividendIndex Dividend to push + * @param _payees Addresses to which to push the dividend + */ + function pushDividendPaymentToAddresses(uint256 _dividendIndex, address[] _payees) public withPerm(DISTRIBUTE) validDividendIndex(_dividendIndex) { + Dividend storage dividend = dividends[_dividendIndex]; + for (uint256 i = 0; i < _payees.length; i++) { + if ((!dividend.claimed[_payees[i]]) && (!dividend.dividendExcluded[_payees[i]])) { + _payDividend(_payees[i], dividend, _dividendIndex); + } + } + } + + /** + * @notice Issuer can push dividends using the investor list from the security token + * @param _dividendIndex Dividend to push + * @param _start Index in investor list at which to start pushing dividends + * @param _iterations Number of addresses to push dividends for + */ + function pushDividendPayment(uint256 _dividendIndex, uint256 _start, uint256 _iterations) public withPerm(DISTRIBUTE) validDividendIndex(_dividendIndex) { + Dividend storage dividend = dividends[_dividendIndex]; + uint256 numberInvestors = ISecurityToken(securityToken).getInvestorsLength(); + for (uint256 i = _start; i < Math.min256(numberInvestors, _start.add(_iterations)); i++) { + address payee = ISecurityToken(securityToken).investors(i); + if ((!dividend.claimed[payee]) && (!dividend.dividendExcluded[payee])) { + _payDividend(payee, dividend, _dividendIndex); + } + } + } + + /** + * @notice Investors can pull their own dividends + * @param _dividendIndex Dividend to pull + */ + function pullDividendPayment(uint256 _dividendIndex) public validDividendIndex(_dividendIndex) + { + Dividend storage dividend = dividends[_dividendIndex]; + require(!dividend.claimed[msg.sender], "Dividend already claimed by msg.sender"); + require(!dividend.dividendExcluded[msg.sender], "msg.sender excluded from Dividend"); + _payDividend(msg.sender, dividend, _dividendIndex); + } + + /** + * @notice Internal function for paying dividends + * @param _payee address of investor + * @param _dividend storage with previously issued dividends + * @param _dividendIndex Dividend to pay + */ + function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal; + + /** + * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends + * @param _dividendIndex Dividend to reclaim + */ + function reclaimDividend(uint256 _dividendIndex) external; + + /** + * @notice Calculate amount of dividends claimable + * @param _dividendIndex Dividend to calculate + * @param _payee Affected investor address + * @return claim, withheld amounts + */ + function calculateDividend(uint256 _dividendIndex, address _payee) public view returns(uint256, uint256) { + require(_dividendIndex < dividends.length, "Incorrect dividend index"); + Dividend storage dividend = dividends[_dividendIndex]; + if (dividend.claimed[_payee] || dividend.dividendExcluded[_payee]) { + return (0, 0); + } + uint256 balance = ISecurityToken(securityToken).balanceOfAt(_payee, dividend.checkpointId); + uint256 claim = balance.mul(dividend.amount).div(dividend.totalSupply); + uint256 withheld = claim.mul(withholdingTax[_payee]).div(uint256(10**18)); + return (claim, withheld); + } + + /** + * @notice Get the index according to the checkpoint id + * @param _checkpointId Checkpoint id to query + * @return uint256[] + */ + function getDividendIndex(uint256 _checkpointId) public view returns(uint256[]) { + uint256 counter = 0; + for(uint256 i = 0; i < dividends.length; i++) { + if (dividends[i].checkpointId == _checkpointId) { + counter++; + } + } + + uint256[] memory index = new uint256[](counter); + counter = 0; + for(uint256 j = 0; j < dividends.length; j++) { + if (dividends[j].checkpointId == _checkpointId) { + index[counter] = j; + counter++; + } + } + return index; + } + + /** + * @notice Allows issuer to withdraw withheld tax + * @param _dividendIndex Dividend to withdraw from + */ + function withdrawWithholding(uint256 _dividendIndex) external; + + /** + * @notice Return the permissions flag that are associated with STO + * @return bytes32 array + */ + function getPermissions() public view returns(bytes32[]) { + bytes32[] memory allPermissions = new bytes32[](1); + allPermissions[0] = DISTRIBUTE; + return allPermissions; + } + +} diff --git a/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol b/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol index ad61b24a8..60d84a41b 100644 --- a/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol @@ -1,157 +1,206 @@ -pragma solidity ^0.4.24; - -import "./DividendCheckpoint.sol"; -import "../../interfaces/IERC20.sol"; - -/** - * @title Checkpoint module for issuing ERC20 dividends - */ -contract ERC20DividendCheckpoint is DividendCheckpoint { - using SafeMath for uint256; - - // Mapping to token address for each dividend - mapping (uint256 => address) public dividendTokens; - - event ERC20DividendDeposited(address indexed _depositor, uint256 _checkpointId, uint256 _created, uint256 _maturity, uint256 _expiry, address indexed _token, uint256 _amount, uint256 _totalSupply, uint256 _dividendIndex); - event ERC20DividendClaimed(address indexed _payee, uint256 _dividendIndex, address indexed _token, uint256 _amount, uint256 _withheld); - event ERC20DividendReclaimed(address indexed _claimer, uint256 _dividendIndex, address indexed _token, uint256 _claimedAmount); - event ERC20DividendWithholdingWithdrawn(address indexed _claimer, uint256 _dividendIndex, address indexed _token, uint256 _withheldAmount); - - /** - * @notice Constructor - * @param _securityToken Address of the security token - * @param _polyAddress Address of the polytoken - */ - constructor (address _securityToken, address _polyAddress) public - Module(_securityToken, _polyAddress) - { - } - - /** - * @notice Creates a dividend and checkpoint for the dividend - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _token Address of ERC20 token in which dividend is to be denominated - * @param _amount Amount of specified token for dividend - */ - function createDividend(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount) external onlyOwner { - createDividendWithExclusions(_maturity, _expiry, _token, _amount, excluded); - } - - /** - * @notice Creates a dividend with a provided checkpoint - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _token Address of ERC20 token in which dividend is to be denominated - * @param _amount Amount of specified token for dividend - * @param _checkpointId Checkpoint id from which to create dividends - */ - function createDividendWithCheckpoint(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 _checkpointId) external onlyOwner { - createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, excluded); - } - - /** - * @notice Creates a dividend and checkpoint for the dividend - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _token Address of ERC20 token in which dividend is to be denominated - * @param _amount Amount of specified token for dividend - * @param _excluded List of addresses to exclude - */ - function createDividendWithExclusions(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, address[] _excluded) public onlyOwner { - uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint(); - createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, checkpointId, _excluded); - } - - /** - * @notice Creates a dividend with a provided checkpoint - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _token Address of ERC20 token in which dividend is to be denominated - * @param _amount Amount of specified token for dividend - * @param _checkpointId Checkpoint id from which to create dividends - * @param _excluded List of addresses to exclude - */ - function createDividendWithCheckpointAndExclusions(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 _checkpointId, address[] _excluded) public onlyOwner { - require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many addresses excluded"); - require(_expiry > _maturity, "Expiry is before maturity"); - require(_expiry > now, "Expiry is in the past"); - require(_amount > 0, "No dividend sent"); - require(_token != address(0), "0x not valid token"); - require(_checkpointId <= ISecurityToken(securityToken).currentCheckpointId(), "Invalid checkpoint"); - require(IERC20(_token).transferFrom(msg.sender, address(this), _amount), "Unable to transfer tokens for dividend"); - uint256 dividendIndex = dividends.length; - uint256 currentSupply = ISecurityToken(securityToken).totalSupplyAt(_checkpointId); - uint256 excludedSupply = 0; - for (uint256 i = 0; i < _excluded.length; i++) { - excludedSupply = excludedSupply.add(ISecurityToken(securityToken).balanceOfAt(_excluded[i], _checkpointId)); - } - dividends.push( - Dividend( - _checkpointId, - now, - _maturity, - _expiry, - _amount, - 0, - currentSupply.sub(excludedSupply), - false, - 0, - 0 - ) - ); - for (uint256 j = 0; j < _excluded.length; j++) { - dividends[dividends.length - 1].dividendExcluded[_excluded[j]] = true; - } - dividendTokens[dividendIndex] = _token; - emit ERC20DividendDeposited(msg.sender, _checkpointId, now, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex); - } - - /** - * @notice Internal function for paying dividends - * @param _payee address of investor - * @param _dividend storage with previously issued dividends - * @param _dividendIndex Dividend to pay - */ - function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal { - (uint256 claim, uint256 withheld) = calculateDividend(_dividendIndex, _payee); - _dividend.claimed[_payee] = true; - _dividend.claimedAmount = claim.add(_dividend.claimedAmount); - uint256 claimAfterWithheld = claim.sub(withheld); - if (claimAfterWithheld > 0) { - require(IERC20(dividendTokens[_dividendIndex]).transfer(_payee, claimAfterWithheld), "Unable to transfer tokens"); - _dividend.dividendWithheld = _dividend.dividendWithheld.add(withheld); - investorWithheld[_payee] = investorWithheld[_payee].add(withheld); - emit ERC20DividendClaimed(_payee, _dividendIndex, dividendTokens[_dividendIndex], claim, withheld); - } - } - - /** - * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends - * @param _dividendIndex Dividend to reclaim - */ - function reclaimDividend(uint256 _dividendIndex) external onlyOwner { - require(_dividendIndex < dividends.length, "Incorrect dividend index"); - require(now >= dividends[_dividendIndex].expiry, "Dividend expiry is in the future"); - require(!dividends[_dividendIndex].reclaimed, "Dividend already claimed"); - dividends[_dividendIndex].reclaimed = true; - Dividend storage dividend = dividends[_dividendIndex]; - uint256 remainingAmount = dividend.amount.sub(dividend.claimedAmount); - require(IERC20(dividendTokens[_dividendIndex]).transfer(msg.sender, remainingAmount), "Unable to transfer tokens"); - emit ERC20DividendReclaimed(msg.sender, _dividendIndex, dividendTokens[_dividendIndex], remainingAmount); - } - - /** - * @notice Allows issuer to withdraw withheld tax - * @param _dividendIndex Dividend to withdraw from - */ - function withdrawWithholding(uint256 _dividendIndex) external onlyOwner { - require(_dividendIndex < dividends.length, "Incorrect dividend index"); - Dividend storage dividend = dividends[_dividendIndex]; - uint256 remainingWithheld = dividend.dividendWithheld.sub(dividend.dividendWithheldReclaimed); - dividend.dividendWithheldReclaimed = dividend.dividendWithheld; - require(IERC20(dividendTokens[_dividendIndex]).transfer(msg.sender, remainingWithheld), "Unable to transfer tokens"); - emit ERC20DividendWithholdingWithdrawn(msg.sender, _dividendIndex, dividendTokens[_dividendIndex], remainingWithheld); - } - -} +pragma solidity ^0.4.24; + +import "./DividendCheckpoint.sol"; +import "../../interfaces/IERC20.sol"; + +/** + * @title Checkpoint module for issuing ERC20 dividends + */ +contract ERC20DividendCheckpoint is DividendCheckpoint { + using SafeMath for uint256; + + // Mapping to token address for each dividend + mapping (uint256 => address) public dividendTokens; + + event ERC20DividendDeposited(address indexed _depositor, uint256 _checkpointId, uint256 _created, uint256 _maturity, uint256 _expiry, address indexed _token, uint256 _amount, uint256 _totalSupply, uint256 _dividendIndex, bytes32 indexed _name); + event ERC20DividendClaimed(address indexed _payee, uint256 _dividendIndex, address indexed _token, uint256 _amount, uint256 _withheld); + event ERC20DividendReclaimed(address indexed _claimer, uint256 _dividendIndex, address indexed _token, uint256 _claimedAmount); + event ERC20DividendWithholdingWithdrawn(address indexed _claimer, uint256 _dividendIndex, address indexed _token, uint256 _withheldAmount); + + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + */ + constructor (address _securityToken, address _polyAddress) public + Module(_securityToken, _polyAddress) + { + } + + /** + * @notice Creates a dividend and checkpoint for the dividend + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _name name/title for identification + */ + function createDividend(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, bytes32 _name) external onlyOwner { + createDividendWithExclusions(_maturity, _expiry, _token, _amount, excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _checkpointId Checkpoint id from which to create dividends + * @param _name name/title for identification + */ + function createDividendWithCheckpoint(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 _checkpointId, bytes32 _name) external onlyOwner { + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, excluded, _name); + } + + /** + * @notice Creates a dividend and checkpoint for the dividend + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _excluded List of addresses to exclude + * @param _name name/title for identification + */ + function createDividendWithExclusions(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, address[] _excluded, bytes32 _name) public onlyOwner { + uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint(); + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, checkpointId, _excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _checkpointId Checkpoint id from which to create dividends + * @param _excluded List of addresses to exclude + * @param _name name/title for identification + */ + function createDividendWithCheckpointAndExclusions( + uint256 _maturity, + uint256 _expiry, + address _token, + uint256 _amount, + uint256 _checkpointId, + address[] _excluded, + bytes32 _name + ) + public + onlyOwner + { + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, _excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _checkpointId Checkpoint id from which to create dividends + * @param _excluded List of addresses to exclude + * @param _name name/title for identification + */ + function _createDividendWithCheckpointAndExclusions( + uint256 _maturity, + uint256 _expiry, + address _token, + uint256 _amount, + uint256 _checkpointId, + address[] _excluded, + bytes32 _name + ) + internal + { + require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many addresses excluded"); + require(_expiry > _maturity, "Expiry is before maturity"); + require(_expiry > now, "Expiry is in the past"); + require(_amount > 0, "No dividend sent"); + require(_token != address(0), "0x not valid token"); + require(_checkpointId <= ISecurityToken(securityToken).currentCheckpointId(), "Invalid checkpoint"); + require(IERC20(_token).transferFrom(msg.sender, address(this), _amount), "Unable to transfer tokens for dividend"); + require(_name[0] != 0); + uint256 dividendIndex = dividends.length; + uint256 currentSupply = ISecurityToken(securityToken).totalSupplyAt(_checkpointId); + uint256 excludedSupply = 0; + for (uint256 i = 0; i < _excluded.length; i++) { + excludedSupply = excludedSupply.add(ISecurityToken(securityToken).balanceOfAt(_excluded[i], _checkpointId)); + } + dividends.push( + Dividend( + _checkpointId, + now, + _maturity, + _expiry, + _amount, + 0, + currentSupply.sub(excludedSupply), + false, + 0, + 0, + _name + ) + ); + for (uint256 j = 0; j < _excluded.length; j++) { + dividends[dividends.length - 1].dividendExcluded[_excluded[j]] = true; + } + dividendTokens[dividendIndex] = _token; + _emitERC20DividendDepositedEvent(_checkpointId, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex, _name); + } + + /** + * @notice emits the ERC20DividendDeposited event. + * Seperated into a different function as a workaround for stack too deep error + */ + function _emitERC20DividendDepositedEvent(uint256 _checkpointId, uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 currentSupply, uint256 dividendIndex, bytes32 _name) internal { + emit ERC20DividendDeposited(msg.sender, _checkpointId, now, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex, _name); + } + + /** + * @notice Internal function for paying dividends + * @param _payee address of investor + * @param _dividend storage with previously issued dividends + * @param _dividendIndex Dividend to pay + */ + function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal { + (uint256 claim, uint256 withheld) = calculateDividend(_dividendIndex, _payee); + _dividend.claimed[_payee] = true; + _dividend.claimedAmount = claim.add(_dividend.claimedAmount); + uint256 claimAfterWithheld = claim.sub(withheld); + if (claimAfterWithheld > 0) { + require(IERC20(dividendTokens[_dividendIndex]).transfer(_payee, claimAfterWithheld), "Unable to transfer tokens"); + _dividend.dividendWithheld = _dividend.dividendWithheld.add(withheld); + investorWithheld[_payee] = investorWithheld[_payee].add(withheld); + emit ERC20DividendClaimed(_payee, _dividendIndex, dividendTokens[_dividendIndex], claim, withheld); + } + } + + /** + * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends + * @param _dividendIndex Dividend to reclaim + */ + function reclaimDividend(uint256 _dividendIndex) external onlyOwner { + require(_dividendIndex < dividends.length, "Incorrect dividend index"); + require(now >= dividends[_dividendIndex].expiry, "Dividend expiry is in the future"); + require(!dividends[_dividendIndex].reclaimed, "Dividend already claimed"); + dividends[_dividendIndex].reclaimed = true; + Dividend storage dividend = dividends[_dividendIndex]; + uint256 remainingAmount = dividend.amount.sub(dividend.claimedAmount); + require(IERC20(dividendTokens[_dividendIndex]).transfer(msg.sender, remainingAmount), "Unable to transfer tokens"); + emit ERC20DividendReclaimed(msg.sender, _dividendIndex, dividendTokens[_dividendIndex], remainingAmount); + } + + /** + * @notice Allows issuer to withdraw withheld tax + * @param _dividendIndex Dividend to withdraw from + */ + function withdrawWithholding(uint256 _dividendIndex) external onlyOwner { + require(_dividendIndex < dividends.length, "Incorrect dividend index"); + Dividend storage dividend = dividends[_dividendIndex]; + uint256 remainingWithheld = dividend.dividendWithheld.sub(dividend.dividendWithheldReclaimed); + dividend.dividendWithheldReclaimed = dividend.dividendWithheld; + require(IERC20(dividendTokens[_dividendIndex]).transfer(msg.sender, remainingWithheld), "Unable to transfer tokens"); + emit ERC20DividendWithholdingWithdrawn(msg.sender, _dividendIndex, dividendTokens[_dividendIndex], remainingWithheld); + } + +} diff --git a/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol b/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol index 1d17e1abb..d8ecb2e9a 100644 --- a/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol @@ -1,147 +1,183 @@ -pragma solidity ^0.4.24; - -import "./DividendCheckpoint.sol"; - -/** - * @title Checkpoint module for issuing ether dividends - */ -contract EtherDividendCheckpoint is DividendCheckpoint { - using SafeMath for uint256; - - event EtherDividendDeposited(address indexed _depositor, uint256 _checkpointId, uint256 _created, uint256 _maturity, uint256 _expiry, uint256 _amount, uint256 _totalSupply, uint256 _dividendIndex); - event EtherDividendClaimed(address indexed _payee, uint256 _dividendIndex, uint256 _amount, uint256 _withheld); - event EtherDividendReclaimed(address indexed _claimer, uint256 _dividendIndex, uint256 _claimedAmount); - event EtherDividendClaimFailed(address indexed _payee, uint256 _dividendIndex, uint256 _amount, uint256 _withheld); - event EtherDividendWithholdingWithdrawn(address indexed _claimer, uint256 _dividendIndex, uint256 _withheldAmount); - - /** - * @notice Constructor - * @param _securityToken Address of the security token - * @param _polyAddress Address of the polytoken - */ - constructor (address _securityToken, address _polyAddress) public - Module(_securityToken, _polyAddress) - { - } - - /** - * @notice Creates a dividend and checkpoint for the dividend, using global list of excluded addresses - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - */ - function createDividend(uint256 _maturity, uint256 _expiry) payable external onlyOwner { - createDividendWithExclusions(_maturity, _expiry, excluded); - } - - /** - * @notice Creates a dividend with a provided checkpoint, using global list of excluded addresses - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _checkpointId Id of the checkpoint from which to issue dividend - */ - function createDividendWithCheckpoint(uint256 _maturity, uint256 _expiry, uint256 _checkpointId) payable external onlyOwner { - createDividendWithCheckpointAndExclusions(_maturity, _expiry, _checkpointId, excluded); - } - - /** - * @notice Creates a dividend and checkpoint for the dividend, specifying explicit excluded addresses - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _excluded List of addresses to exclude - */ - function createDividendWithExclusions(uint256 _maturity, uint256 _expiry, address[] _excluded) payable public onlyOwner { - uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint(); - createDividendWithCheckpointAndExclusions(_maturity, _expiry, checkpointId, _excluded); - } - - /** - * @notice Creates a dividend with a provided checkpoint, specifying explicit excluded addresses - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _checkpointId Id of the checkpoint from which to issue dividend - * @param _excluded List of addresses to exclude - */ - function createDividendWithCheckpointAndExclusions(uint256 _maturity, uint256 _expiry, uint256 _checkpointId, address[] _excluded) payable public onlyOwner { - require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many addresses excluded"); - require(_expiry > _maturity, "Expiry is before maturity"); - require(_expiry > now, "Expiry is in the past"); - require(msg.value > 0, "No dividend sent"); - require(_checkpointId <= ISecurityToken(securityToken).currentCheckpointId()); - uint256 dividendIndex = dividends.length; - uint256 currentSupply = ISecurityToken(securityToken).totalSupplyAt(_checkpointId); - uint256 excludedSupply = 0; - for (uint256 i = 0; i < _excluded.length; i++) { - excludedSupply = excludedSupply.add(ISecurityToken(securityToken).balanceOfAt(_excluded[i], _checkpointId)); - } - dividends.push( - Dividend( - _checkpointId, - now, - _maturity, - _expiry, - msg.value, - 0, - currentSupply.sub(excludedSupply), - false, - 0, - 0 - ) - ); - for (uint256 j = 0; j < _excluded.length; j++) { - dividends[dividends.length - 1].dividendExcluded[_excluded[j]] = true; - } - emit EtherDividendDeposited(msg.sender, _checkpointId, now, _maturity, _expiry, msg.value, currentSupply, dividendIndex); - } - - /** - * @notice Internal function for paying dividends - * @param _payee address of investor - * @param _dividend storage with previously issued dividends - * @param _dividendIndex Dividend to pay - */ - function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal { - (uint256 claim, uint256 withheld) = calculateDividend(_dividendIndex, _payee); - _dividend.claimed[_payee] = true; - uint256 claimAfterWithheld = claim.sub(withheld); - if (claimAfterWithheld > 0) { - if (_payee.send(claimAfterWithheld)) { - _dividend.claimedAmount = _dividend.claimedAmount.add(claim); - _dividend.dividendWithheld = _dividend.dividendWithheld.add(withheld); - investorWithheld[_payee] = investorWithheld[_payee].add(withheld); - emit EtherDividendClaimed(_payee, _dividendIndex, claim, withheld); - } else { - _dividend.claimed[_payee] = false; - emit EtherDividendClaimFailed(_payee, _dividendIndex, claim, withheld); - } - } - } - - /** - * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends - * @param _dividendIndex Dividend to reclaim - */ - function reclaimDividend(uint256 _dividendIndex) external onlyOwner { - require(_dividendIndex < dividends.length, "Incorrect dividend index"); - require(now >= dividends[_dividendIndex].expiry, "Dividend expiry is in the future"); - require(!dividends[_dividendIndex].reclaimed, "Dividend already claimed"); - Dividend storage dividend = dividends[_dividendIndex]; - dividend.reclaimed = true; - uint256 remainingAmount = dividend.amount.sub(dividend.claimedAmount); - msg.sender.transfer(remainingAmount); - emit EtherDividendReclaimed(msg.sender, _dividendIndex, remainingAmount); - } - - /** - * @notice Allows issuer to withdraw withheld tax - * @param _dividendIndex Dividend to withdraw from - */ - function withdrawWithholding(uint256 _dividendIndex) external onlyOwner { - require(_dividendIndex < dividends.length, "Incorrect dividend index"); - Dividend storage dividend = dividends[_dividendIndex]; - uint256 remainingWithheld = dividend.dividendWithheld.sub(dividend.dividendWithheldReclaimed); - dividend.dividendWithheldReclaimed = dividend.dividendWithheld; - msg.sender.transfer(remainingWithheld); - emit EtherDividendWithholdingWithdrawn(msg.sender, _dividendIndex, remainingWithheld); - } - -} +pragma solidity ^0.4.24; + +import "./DividendCheckpoint.sol"; + +/** + * @title Checkpoint module for issuing ether dividends + */ +contract EtherDividendCheckpoint is DividendCheckpoint { + using SafeMath for uint256; + + event EtherDividendDeposited(address indexed _depositor, uint256 _checkpointId, uint256 _created, uint256 _maturity, uint256 _expiry, uint256 _amount, uint256 _totalSupply, uint256 _dividendIndex, bytes32 indexed _name); + event EtherDividendClaimed(address indexed _payee, uint256 _dividendIndex, uint256 _amount, uint256 _withheld); + event EtherDividendReclaimed(address indexed _claimer, uint256 _dividendIndex, uint256 _claimedAmount); + event EtherDividendClaimFailed(address indexed _payee, uint256 _dividendIndex, uint256 _amount, uint256 _withheld); + event EtherDividendWithholdingWithdrawn(address indexed _claimer, uint256 _dividendIndex, uint256 _withheldAmount); + + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + */ + constructor (address _securityToken, address _polyAddress) public + Module(_securityToken, _polyAddress) + { + } + + /** + * @notice Creates a dividend and checkpoint for the dividend, using global list of excluded addresses + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _name name/title for identification + */ + function createDividend(uint256 _maturity, uint256 _expiry, bytes32 _name) payable external onlyOwner { + createDividendWithExclusions(_maturity, _expiry, excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint, using global list of excluded addresses + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _checkpointId Id of the checkpoint from which to issue dividend + * @param _name name/title for identification + */ + function createDividendWithCheckpoint(uint256 _maturity, uint256 _expiry, uint256 _checkpointId, bytes32 _name) payable external onlyOwner { + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _checkpointId, excluded, _name); + } + + /** + * @notice Creates a dividend and checkpoint for the dividend, specifying explicit excluded addresses + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _excluded List of addresses to exclude + * @param _name name/title for identification + */ + function createDividendWithExclusions(uint256 _maturity, uint256 _expiry, address[] _excluded, bytes32 _name) payable public onlyOwner { + uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint(); + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, checkpointId, _excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint, specifying explicit excluded addresses + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _checkpointId Id of the checkpoint from which to issue dividend + * @param _excluded List of addresses to exclude + * @param _name name/title for identification + */ + function createDividendWithCheckpointAndExclusions( + uint256 _maturity, + uint256 _expiry, + uint256 _checkpointId, + address[] _excluded, + bytes32 _name + ) + payable + public + onlyOwner + { + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _checkpointId, _excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint, specifying explicit excluded addresses + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _checkpointId Id of the checkpoint from which to issue dividend + * @param _excluded List of addresses to exclude + * @param _name name/title for identification + */ + function _createDividendWithCheckpointAndExclusions( + uint256 _maturity, + uint256 _expiry, + uint256 _checkpointId, + address[] _excluded, + bytes32 _name + ) + internal + { + require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many addresses excluded"); + require(_expiry > _maturity, "Expiry is before maturity"); + require(_expiry > now, "Expiry is in the past"); + require(msg.value > 0, "No dividend sent"); + require(_checkpointId <= ISecurityToken(securityToken).currentCheckpointId()); + require(_name[0] != 0); + uint256 dividendIndex = dividends.length; + uint256 currentSupply = ISecurityToken(securityToken).totalSupplyAt(_checkpointId); + uint256 excludedSupply = 0; + for (uint256 i = 0; i < _excluded.length; i++) { + excludedSupply = excludedSupply.add(ISecurityToken(securityToken).balanceOfAt(_excluded[i], _checkpointId)); + } + dividends.push( + Dividend( + _checkpointId, + now, + _maturity, + _expiry, + msg.value, + 0, + currentSupply.sub(excludedSupply), + false, + 0, + 0, + _name + ) + ); + for (uint256 j = 0; j < _excluded.length; j++) { + dividends[dividends.length - 1].dividendExcluded[_excluded[j]] = true; + } + emit EtherDividendDeposited(msg.sender, _checkpointId, now, _maturity, _expiry, msg.value, currentSupply, dividendIndex, _name); + } + + /** + * @notice Internal function for paying dividends + * @param _payee address of investor + * @param _dividend storage with previously issued dividends + * @param _dividendIndex Dividend to pay + */ + function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal { + (uint256 claim, uint256 withheld) = calculateDividend(_dividendIndex, _payee); + _dividend.claimed[_payee] = true; + uint256 claimAfterWithheld = claim.sub(withheld); + if (claimAfterWithheld > 0) { + if (_payee.send(claimAfterWithheld)) { + _dividend.claimedAmount = _dividend.claimedAmount.add(claim); + _dividend.dividendWithheld = _dividend.dividendWithheld.add(withheld); + investorWithheld[_payee] = investorWithheld[_payee].add(withheld); + emit EtherDividendClaimed(_payee, _dividendIndex, claim, withheld); + } else { + _dividend.claimed[_payee] = false; + emit EtherDividendClaimFailed(_payee, _dividendIndex, claim, withheld); + } + } + } + + /** + * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends + * @param _dividendIndex Dividend to reclaim + */ + function reclaimDividend(uint256 _dividendIndex) external onlyOwner { + require(_dividendIndex < dividends.length, "Incorrect dividend index"); + require(now >= dividends[_dividendIndex].expiry, "Dividend expiry is in the future"); + require(!dividends[_dividendIndex].reclaimed, "Dividend already claimed"); + Dividend storage dividend = dividends[_dividendIndex]; + dividend.reclaimed = true; + uint256 remainingAmount = dividend.amount.sub(dividend.claimedAmount); + msg.sender.transfer(remainingAmount); + emit EtherDividendReclaimed(msg.sender, _dividendIndex, remainingAmount); + } + + /** + * @notice Allows issuer to withdraw withheld tax + * @param _dividendIndex Dividend to withdraw from + */ + function withdrawWithholding(uint256 _dividendIndex) external onlyOwner { + require(_dividendIndex < dividends.length, "Incorrect dividend index"); + Dividend storage dividend = dividends[_dividendIndex]; + uint256 remainingWithheld = dividend.dividendWithheld.sub(dividend.dividendWithheldReclaimed); + dividend.dividendWithheldReclaimed = dividend.dividendWithheld; + msg.sender.transfer(remainingWithheld); + emit EtherDividendWithholdingWithdrawn(msg.sender, _dividendIndex, remainingWithheld); + } + +} diff --git a/contracts/modules/Checkpoint/ICheckpoint.sol b/contracts/modules/Checkpoint/ICheckpoint.sol index 214093131..3e567ba7b 100644 --- a/contracts/modules/Checkpoint/ICheckpoint.sol +++ b/contracts/modules/Checkpoint/ICheckpoint.sol @@ -1,8 +1,8 @@ -pragma solidity ^0.4.24; - -/** - * @title Interface to be implemented by all checkpoint modules - */ -interface ICheckpoint { - -} +pragma solidity ^0.4.24; + +/** + * @title Interface to be implemented by all checkpoint modules + */ +interface ICheckpoint { + +} diff --git a/contracts/oracles/MakerDAOOracle.sol b/contracts/oracles/MakerDAOOracle.sol index ab7795007..63d8b73cb 100644 --- a/contracts/oracles/MakerDAOOracle.sol +++ b/contracts/oracles/MakerDAOOracle.sol @@ -13,9 +13,9 @@ contract MakerDAOOracle is IOracle, Ownable { bool public manualOverride; uint256 public manualPrice; - event LogChangeMedianizer(address _newMedianizer, address _oldMedianizer, uint256 _now); - event LogSetManualPrice(uint256 _oldPrice, uint256 _newPrice, uint256 _time); - event LogSetManualOverride(bool _override, uint256 _time); + event ChangeMedianizer(address _newMedianizer, address _oldMedianizer, uint256 _now); + event SetManualPrice(uint256 _oldPrice, uint256 _newPrice, uint256 _time); + event SetManualOverride(bool _override, uint256 _time); /** * @notice Creates a new Maker based oracle @@ -35,7 +35,7 @@ contract MakerDAOOracle is IOracle, Ownable { */ function changeMedianier(address _medianizer) public onlyOwner { require(_medianizer != address(0), "0x not allowed"); - emit LogChangeMedianizer(_medianizer, medianizer, now); + emit ChangeMedianizer(_medianizer, medianizer, now); medianizer = _medianizer; } @@ -78,7 +78,7 @@ contract MakerDAOOracle is IOracle, Ownable { * @param _price Price to set */ function setManualPrice(uint256 _price) public onlyOwner { - emit LogSetManualPrice(manualPrice, _price, now); + emit SetManualPrice(manualPrice, _price, now); manualPrice = _price; } @@ -88,7 +88,7 @@ contract MakerDAOOracle is IOracle, Ownable { */ function setManualOverride(bool _override) public onlyOwner { manualOverride = _override; - emit LogSetManualOverride(_override, now); + emit SetManualOverride(_override, now); } } diff --git a/contracts/oracles/PolyOracle.sol b/contracts/oracles/PolyOracle.sol index e5328ea74..005d1677b 100644 --- a/contracts/oracles/PolyOracle.sol +++ b/contracts/oracles/PolyOracle.sol @@ -26,10 +26,10 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { bool public freezeOracle; - event LogPriceUpdated(uint256 _price, uint256 _oldPrice, bytes32 _queryId, uint256 _time); - event LogNewOraclizeQuery(uint256 _time, bytes32 _queryId, string _query); - event LogAdminSet(address _admin, bool _valid, uint256 _time); - event LogStalePriceUpdate(bytes32 _queryId, uint256 _time, string _result); + event PriceUpdated(uint256 _price, uint256 _oldPrice, bytes32 _queryId, uint256 _time); + event NewOraclizeQuery(uint256 _time, bytes32 _queryId, string _query); + event AdminSet(address _admin, bool _valid, uint256 _time); + event StalePriceUpdate(bytes32 _queryId, uint256 _time, string _result); modifier isAdminOrOwner { require(admin[msg.sender] || msg.sender == owner, "Address is not admin or owner"); @@ -55,7 +55,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { require(!ignoreRequestIds[_requestId], "Ignoring requestId"); if (requestIds[_requestId] < latestUpdate) { // Result is stale, probably because it was received out of order - emit LogStalePriceUpdate(_requestId, requestIds[_requestId], _result); + emit StalePriceUpdate(_requestId, requestIds[_requestId], _result); return; } require(requestIds[_requestId] >= latestUpdate, "Result is stale"); @@ -67,7 +67,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { require(newPOLYUSD >= POLYUSD.sub(bound), "Result is too small"); } latestUpdate = requestIds[_requestId]; - emit LogPriceUpdated(newPOLYUSD, POLYUSD, _requestId, latestUpdate); + emit PriceUpdated(newPOLYUSD, POLYUSD, _requestId, latestUpdate); POLYUSD = newPOLYUSD; } @@ -83,7 +83,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { requestId = oraclize_query(oracleQueryType, oracleURL, gasLimit); requestIds[requestId] = now; maximumScheduledUpdated = now; - emit LogNewOraclizeQuery(now, requestId, oracleURL); + emit NewOraclizeQuery(now, requestId, oracleURL); } else { require(oraclize_getPrice(oracleQueryType, gasLimit) * _times.length <= address(this).balance, "Insufficient Funds"); for (uint256 i = 0; i < _times.length; i++) { @@ -93,7 +93,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { if (maximumScheduledUpdated < requestIds[requestId]) { maximumScheduledUpdated = requestIds[requestId]; } - emit LogNewOraclizeQuery(_times[i], requestId, oracleURL); + emit NewOraclizeQuery(_times[i], requestId, oracleURL); } } if (latestScheduledUpdate < maximumScheduledUpdated) { @@ -117,7 +117,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { uint256 scheduledTime = _startTime + (i * _interval); requestId = oraclize_query(scheduledTime, oracleQueryType, oracleURL, gasLimit); requestIds[requestId] = scheduledTime; - emit LogNewOraclizeQuery(scheduledTime, requestId, oracleURL); + emit NewOraclizeQuery(scheduledTime, requestId, oracleURL); } if (latestScheduledUpdate < requestIds[requestId]) { latestScheduledUpdate = requestIds[requestId]; @@ -129,7 +129,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { * @param _price POLYUSD price */ function setPOLYUSD(uint256 _price) onlyOwner public { - emit LogPriceUpdated(_price, POLYUSD, 0, now); + emit PriceUpdated(_price, POLYUSD, 0, now); POLYUSD = _price; latestUpdate = now; } @@ -220,7 +220,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { */ function setAdmin(address _admin, bool _valid) onlyOwner public { admin[_admin] = _valid; - emit LogAdminSet(_admin, _valid, now); + emit AdminSet(_admin, _valid, now); } /** diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 2622d7fb5..c61d42b5c 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -149,7 +149,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr event ForceBurn(address indexed _controller, address indexed _from, uint256 _value, bool _verifyTransfer, bytes _data); event DisableController(uint256 _timestamp); - function isModule(address _module, uint8 _type) internal view returns (bool) { + function _isModule(address _module, uint8 _type) internal view returns (bool) { require(modulesToData[_module].module == _module, "Address mismatch"); require(modulesToData[_module].moduleType[_type], "Type mismatch"); require(!modulesToData[_module].isArchived, "Module archived"); @@ -158,7 +158,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // Require msg.sender to be the specified module type modifier onlyModule(uint8 _type) { - require(isModule(msg.sender, _type)); + require(_isModule(msg.sender, _type)); _; } @@ -167,7 +167,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr if (msg.sender == owner) { _; } else { - require(isModule(msg.sender, _type)); + require(_isModule(msg.sender, _type)); _; } } @@ -677,6 +677,29 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr return true; } + /** + * @notice Validate permissions with PermissionManager if it exists, If no Permission return false + * @dev Note that IModule withPerm will allow ST owner all permissions anyway + * @dev this allows individual modules to override this logic if needed (to not allow ST owner all permissions) + * @param _delegate address of delegate + * @param _module address of PermissionManager module + * @param _perm the permissions + * @return success + */ + function checkPermission(address _delegate, address _module, bytes32 _perm) public view returns(bool) { + if (modules[PERMISSIONMANAGER_KEY].length == 0) { + return false; + } + + for (uint8 i = 0; i < modules[PERMISSIONMANAGER_KEY].length; i++) { + if (IPermissionManager(modules[PERMISSIONMANAGER_KEY][i]).checkPermission(_delegate, _module, _perm)) { + return true; + } + } + + return false; + } + function _burn(address _from, uint256 _value) internal returns (bool) { require(_value <= balances[_from], "Value too high"); require(_updateTransfer(_from, address(0), _value), "Burn is not valid"); @@ -721,27 +744,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr return currentCheckpointId; } - /** - * @notice Validate permissions with PermissionManager if it exists, If no Permission return false - * @dev Note that IModule withPerm will allow ST owner all permissions anyway - * @dev this allows individual modules to override this logic if needed (to not allow ST owner all permissions) - * @param _delegate address of delegate - * @param _module address of PermissionManager module - * @param _perm the permissions - * @return success - */ - function checkPermission(address _delegate, address _module, bytes32 _perm) public view returns(bool) { - if (modules[PERMISSION_KEY].length == 0) { - return false; - } - - for (uint8 i = 0; i < modules[PERMISSION_KEY].length; i++) { - if (IPermissionManager(modules[PERMISSION_KEY][i]).checkPermission(_delegate, _module, _perm)) { - return true; - } - } - } - /** * @notice Gets list of times that checkpoints were created * @return List of checkpoint times diff --git a/scripts/test.sh b/scripts/test.sh index d6fb7a632..d24ce6b0f 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Global variable +# Global variable bridge_pid # Exit script as soon as a command fails. @@ -63,9 +63,9 @@ start_testrpc() { if ! [ -z "${TRAVIS_PULL_REQUEST+x}" ] && [ "$TRAVIS_PULL_REQUEST" != false ]; then node_modules/.bin/testrpc-sc --gasLimit 0xfffffffffff --port "$testrpc_port" "${accounts[@]}" > /dev/null & else - node_modules/.bin/ganache-cli --gasLimit 0xfffffffffff "${accounts[@]}" > /dev/null & + node_modules/.bin/ganache-cli --gasLimit 8000000 "${accounts[@]}" > /dev/null & fi - + testrpc_pid=$! } diff --git a/test/a_poly_oracle.js b/test/a_poly_oracle.js index 9eb6c9b56..f727b4014 100644 --- a/test/a_poly_oracle.js +++ b/test/a_poly_oracle.js @@ -84,9 +84,9 @@ let requestIds = new Array(); let tx = await I_PolyOracle.schedulePriceUpdatesFixed([],{from: owner, value:web3.utils.toWei("1")}); assert.isAtMost(tx.logs[0].args._time.toNumber(), latestTime()); // await increaseTime(50); - const logNewPriceWatcher = await promisifyLogWatch(I_PolyOracle.LogPriceUpdated({ fromBlock: blockNo }), 1); + const logNewPriceWatcher = await promisifyLogWatch(I_PolyOracle.PriceUpdated({ fromBlock: blockNo }), 1); // const log = await logNewPriceWatcher; - assert.equal(logNewPriceWatcher.event, 'LogPriceUpdated', 'LogPriceUpdated not emitted.') + assert.equal(logNewPriceWatcher.event, 'PriceUpdated', 'PriceUpdated not emitted.') assert.isNotNull(logNewPriceWatcher.args._price, 'Price returned was null.') assert.equal(logNewPriceWatcher.args._oldPrice.toNumber(), 0); console.log('Success! Current price is: ' + logNewPriceWatcher.args._price.dividedBy(new BigNumber(10).pow(18)).toNumber() + ' USD/POLY') @@ -107,9 +107,9 @@ let requestIds = new Array(); } // Wait for the callback to be invoked by oraclize and the event to be emitted - const logNewPriceWatcher = promisifyLogWatch(I_PolyOracle.LogPriceUpdated({ fromBlock: blockNo }), 2); + const logNewPriceWatcher = promisifyLogWatch(I_PolyOracle.PriceUpdated({ fromBlock: blockNo }), 2); const log = await logNewPriceWatcher; - assert.equal(log.event, 'LogPriceUpdated', 'LogPriceUpdated not emitted.') + assert.equal(log.event, 'PriceUpdated', 'PriceUpdated not emitted.') assert.isNotNull(log.args._price, 'Price returned was null.'); console.log('Success! Current price is: ' + log.args._price.dividedBy(new BigNumber(10).pow(18)).toNumber() + ' USD/POLY') }); @@ -137,9 +137,9 @@ let requestIds = new Array(); assert.isAtMost(time.toNumber(), latestTime() + ((i + 1) * 30)); } // Wait for the callback to be invoked by oraclize and the event to be emitted - const logNewPriceWatcher = promisifyLogWatch(I_PolyOracle.LogPriceUpdated({ fromBlock: blockNo }), 2); + const logNewPriceWatcher = promisifyLogWatch(I_PolyOracle.PriceUpdated({ fromBlock: blockNo }), 2); const log = await logNewPriceWatcher; - assert.equal(log.event, 'LogPriceUpdated', 'LogPriceUpdated not emitted.') + assert.equal(log.event, 'PriceUpdated', 'PriceUpdated not emitted.') assert.isNotNull(log.args._price, 'Price returned was null.') console.log('Success! Current price is: ' + log.args._price.dividedBy(new BigNumber(10).pow(18)).toNumber() + ' USD/POLY'); latestPrice = log.args._price; @@ -229,9 +229,9 @@ let requestIds = new Array(); assert.isAtMost(time.toNumber(), timeScheduling[i]); } - const logNewPriceWatcher = await promisifyLogWatch(I_PolyOracle.LogPriceUpdated({ fromBlock: blockNo }), 2); + const logNewPriceWatcher = await promisifyLogWatch(I_PolyOracle.PriceUpdated({ fromBlock: blockNo }), 2); - assert.equal(logNewPriceWatcher.event, 'LogPriceUpdated', 'LogPriceUpdated not emitted.') + assert.equal(logNewPriceWatcher.event, 'PriceUpdated', 'PriceUpdated not emitted.') assert.isNotNull(logNewPriceWatcher.args._price, 'Price returned was null.') console.log('Success! Current price is: ' + logNewPriceWatcher.args._price.dividedBy(new BigNumber(10).pow(18)).toNumber() + ' USD/POLY'); // assert.isTrue(false); @@ -319,8 +319,8 @@ let requestIds = new Array(); let blockNo = latestBlock(); let tx = await I_PolyOracle.schedulePriceUpdatesFixed([],{from: owner, value:web3.utils.toWei("1")}); assert.isAtMost(tx.logs[0].args._time.toNumber(), latestTime()); - const logNewPriceWatcher = await promisifyLogWatch(I_PolyOracle.LogPriceUpdated({ fromBlock: blockNo }), 1); - assert.equal(logNewPriceWatcher.event, 'LogPriceUpdated', 'LogPriceUpdated not emitted.') + const logNewPriceWatcher = await promisifyLogWatch(I_PolyOracle.PriceUpdated({ fromBlock: blockNo }), 1); + assert.equal(logNewPriceWatcher.event, 'PriceUpdated', 'PriceUpdated not emitted.') assert.isNotNull(logNewPriceWatcher.args._price, 'Price returned was null.') console.log('Success! Current price is: ' + logNewPriceWatcher.args._price.dividedBy(new BigNumber(10).pow(18)).toNumber() + ' USD/POLY'); // assert.isTrue(false); diff --git a/test/b_capped_sto.js b/test/b_capped_sto.js index 11a797933..ec216c637 100644 --- a/test/b_capped_sto.js +++ b/test/b_capped_sto.js @@ -258,7 +258,7 @@ contract('CappedSTO', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol, "SecurityToken doesn't get deployed"); @@ -298,7 +298,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, 0, [E_fundRaiseType], account_fundsReceiver]); let errorThrown = false; try { - const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); } catch(error) { console.log(` tx revert -> Rate is ${0}. Test Passed Successfully`.grey); errorThrown = true; @@ -315,7 +315,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, 0, [E_fundRaiseType], account_fundsReceiver]); let errorThrown = false; try { - const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); } catch(error) { console.log(`Tx Failed because of rate is ${0}. Test Passed Successfully`); errorThrown = true; @@ -328,7 +328,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [ Math.floor(Date.now()/1000 + 100000), Math.floor(Date.now()/1000 + 1000), cap, rate, [E_fundRaiseType], account_fundsReceiver]); let errorThrown = false; try { - const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); } catch(error) { errorThrown = true; console.log(` tx revert -> StartTime is greater than endTime. Test Passed Successfully`.grey); @@ -343,7 +343,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [ startTime, endTime, 0, rate, [E_fundRaiseType], account_fundsReceiver]); let errorThrown = false; try { - const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); } catch(error) { console.log(`Tx Failed because the Cap is equal to ${0}. Test Passed Successfully`); errorThrown = true; @@ -356,7 +356,7 @@ contract('CappedSTO', accounts => { startTime_ETH1 = latestTime() + duration.days(1); endTime_ETH1 = startTime_ETH1 + duration.days(30); let bytesSTO = encodeModuleCall(STOParameters, [startTime_ETH1, endTime_ETH1, cap, rate, [E_fundRaiseType], account_fundsReceiver]); - const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 45000000 }); + const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[3].args._name),"CappedSTO","CappedSTOFactory module was not added"); @@ -876,7 +876,7 @@ contract('CappedSTO', accounts => { it("POLY: Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(P_name, P_symbol, P_tokenDetails, false, { from: token_owner, gas:85000000 }); + let tx = await I_STRProxied.generateSecurityToken(P_name, P_symbol, P_tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, P_symbol, "SecurityToken doesn't get deployed"); @@ -904,7 +904,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime_POLY1, endTime_POLY1, P_cap, P_rate, [P_fundRaiseType], account_fundsReceiver]); - const tx = await I_SecurityToken_POLY.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken_POLY.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[3].args._name),"CappedSTO","CappedSTOFactory module was not added"); @@ -1262,7 +1262,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime_POLY2, endTime_POLY2, P_cap, P_rate, [P_fundRaiseType], account_fundsReceiver]); - const tx = await I_SecurityToken_POLY.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken_POLY.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[3].args._name),"CappedSTO","CappedSTOFactory module was not added"); diff --git a/test/c_checkpoints.js b/test/c_checkpoints.js index d40996a66..a9094c6c5 100644 --- a/test/c_checkpoints.js +++ b/test/c_checkpoints.js @@ -205,7 +205,7 @@ contract('Checkpoints', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner}); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/d_count_transfer_manager.js b/test/d_count_transfer_manager.js index 4b65e249a..75c938939 100644 --- a/test/d_count_transfer_manager.js +++ b/test/d_count_transfer_manager.js @@ -247,7 +247,7 @@ contract('CountTransferManager', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner}); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index 82125d688..cdd1fa98d 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -41,6 +41,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiryTime = toTime + duration.days(15); let message = "Transaction Should Fail!"; + let dividendName = "0x546573744469766964656e640000000000000000000000000000000000000000"; // Contract Instance Declaration let I_GeneralPermissionManagerFactory; @@ -239,7 +240,7 @@ contract('ERC20DividendCheckpoint', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner}); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); @@ -364,7 +365,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiry = latestTime() + duration.days(10); await I_PolyToken.getTokens(web3.utils.toWei('1.5', 'ether'), token_owner); try { - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because allowance = 0`.grey); ensureException(error); @@ -379,7 +380,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiry = latestTime() - duration.days(10); await I_PolyToken.approve(I_ERC20DividendCheckpoint.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); try { - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because maturity > expiry`.grey); ensureException(error); @@ -393,7 +394,7 @@ contract('ERC20DividendCheckpoint', accounts => { let maturity = latestTime() - duration.days(2); let expiry = latestTime() - duration.days(1); try { - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because now > expiry`.grey); ensureException(error); @@ -407,7 +408,7 @@ contract('ERC20DividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() + duration.days(10); try { - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, 0, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, 0, web3.utils.toWei('1.5', 'ether'), dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because token address is 0x`.grey); ensureException(error); @@ -421,7 +422,7 @@ contract('ERC20DividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() + duration.days(10); try { - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, 0, {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, 0, dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because amount < 0`.grey); ensureException(error); @@ -434,8 +435,9 @@ contract('ERC20DividendCheckpoint', accounts => { let maturity = latestTime() + duration.days(1); let expiry = latestTime() + duration.days(10); - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), dividendName, {from: token_owner}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 1, "Dividend should be created at checkpoint 1"); + assert.equal(tx.logs[0].args._name.toString(), dividendName, "Dividend name incorrect in event"); }); it("Investor 1 transfers his token balance to investor 2", async() => { @@ -519,12 +521,28 @@ contract('ERC20DividendCheckpoint', accounts => { ); }); - it("Create new dividend", async() => { + it("Should not allow to create dividend without name", async() => { let maturity = latestTime() + duration.days(1); let expiry = latestTime() + duration.days(10); await I_PolyToken.getTokens(web3.utils.toWei('1.5', 'ether'), token_owner); await I_PolyToken.approve(I_ERC20DividendCheckpoint.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let errorThrown = false; + try { + await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), '', {from: token_owner}); + } catch(error) { + console.log(` tx -> failed because dividend name is empty`.grey); + ensureException(error); + errorThrown = true; + } + assert.ok(errorThrown, message); + }); + + it("Create new dividend", async() => { + let maturity = latestTime() + duration.days(1); + let expiry = latestTime() + duration.days(10); + await I_PolyToken.getTokens(web3.utils.toWei('1.5', 'ether'), token_owner); + // approved in above test + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), dividendName, {from: token_owner}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 2, "Dividend should be created at checkpoint 1"); }); @@ -589,7 +607,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiry = latestTime() + duration.days(10); await I_PolyToken.getTokens(web3.utils.toWei('11', 'ether'), token_owner); await I_PolyToken.approve(I_ERC20DividendCheckpoint.address, web3.utils.toWei('11', 'ether'), {from: token_owner}); - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('10', 'ether'), {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('10', 'ether'), dividendName, {from: token_owner}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 3, "Dividend should be created at checkpoint 2"); }); @@ -676,7 +694,7 @@ contract('ERC20DividendCheckpoint', accounts => { console.log((await I_SecurityToken.currentCheckpointId()).toNumber()); await I_PolyToken.getTokens(web3.utils.toWei('20', 'ether'), token_owner); try { - tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 4, {from: token_owner}); + tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 4, dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because allowance is not provided`.grey); ensureException(error); @@ -693,7 +711,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiry = latestTime() - duration.days(10); await I_PolyToken.approve(I_ERC20DividendCheckpoint.address, web3.utils.toWei('20', 'ether'), {from: token_owner}); try { - tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 4, {from: token_owner}); + tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 4, dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because maturity > expiry`.grey); ensureException(error); @@ -709,7 +727,7 @@ contract('ERC20DividendCheckpoint', accounts => { let maturity = latestTime() - duration.days(5); let expiry = latestTime() - duration.days(2); try { - tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 4, {from: token_owner}); + tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 4, dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because now > expiry`.grey); ensureException(error); @@ -723,7 +741,7 @@ contract('ERC20DividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() + duration.days(2); try { - tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 5, {from: token_owner}); + tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 5, dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because checkpoint id > current checkpoint`.grey); ensureException(error); @@ -741,7 +759,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiry = latestTime() + duration.days(10); await I_PolyToken.getTokens(web3.utils.toWei('11', 'ether'), token_owner); await I_PolyToken.approve(I_ERC20DividendCheckpoint.address, web3.utils.toWei('11', 'ether'), {from: token_owner}); - let tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpointAndExclusions(maturity, expiry, I_PolyToken.address, web3.utils.toWei('10', 'ether'), 4, [account_investor1], {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpointAndExclusions(maturity, expiry, I_PolyToken.address, web3.utils.toWei('10', 'ether'), 4, [account_investor1], dividendName, {from: token_owner}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 4, "Dividend should be created at checkpoint 3"); }); diff --git a/test/f_ether_dividends.js b/test/f_ether_dividends.js index 0e7468075..dec4be72f 100644 --- a/test/f_ether_dividends.js +++ b/test/f_ether_dividends.js @@ -41,6 +41,7 @@ contract('EtherDividendCheckpoint', accounts => { let expiryTime = toTime + duration.days(15); let message = "Transaction Should Fail!"; + let dividendName = "0x546573744469766964656e640000000000000000000000000000000000000000"; // Contract Instance Declaration let I_GeneralPermissionManagerFactory; @@ -239,7 +240,7 @@ contract('EtherDividendCheckpoint', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner}); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); @@ -364,7 +365,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() + duration.days(10); try { - let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, {from: token_owner}); + let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because msg.value = 0`.grey); ensureException(error); @@ -378,7 +379,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() - duration.days(10); try { - let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); + let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, dividendName, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); } catch(error) { console.log(` tx -> failed because maturity > expiry`.grey); ensureException(error); @@ -392,7 +393,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime() - duration.days(2); let expiry = latestTime() - duration.days(1); try { - let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); + let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, dividendName, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); } catch(error) { console.log(` tx -> failed because now > expiry`.grey); ensureException(error); @@ -405,11 +406,26 @@ contract('EtherDividendCheckpoint', accounts => { await I_EtherDividendCheckpoint.setWithholdingFixed([account_investor2], BigNumber(20*10**16), {from: token_owner}); }); + it("Should fail in creating the dividend", async() => { + let errorThrown = false; + let maturity = latestTime() + duration.days(1); + let expiry = latestTime() + duration.days(10); + try { + await I_EtherDividendCheckpoint.createDividend(maturity, expiry, '', {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); + } catch(error) { + console.log(` tx -> failed because dividend name is empty`.grey); + ensureException(error); + errorThrown = true; + } + assert.ok(errorThrown, message); + }); + it("Create new dividend", async() => { let maturity = latestTime() + duration.days(1); let expiry = latestTime() + duration.days(10); - let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); + let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, dividendName, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 1, "Dividend should be created at checkpoint 1"); + assert.equal(tx.logs[0].args._name.toString(), dividendName, "Dividend name incorrect in event"); }); it("Investor 1 transfers his token balance to investor 2", async() => { @@ -510,7 +526,7 @@ contract('EtherDividendCheckpoint', accounts => { it("Create new dividend", async() => { let maturity = latestTime() + duration.days(1); let expiry = latestTime() + duration.days(10); - let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); + let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, dividendName, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 2, "Dividend should be created at checkpoint 2"); }); @@ -576,7 +592,7 @@ contract('EtherDividendCheckpoint', accounts => { it("Create another new dividend", async() => { let maturity = latestTime(); let expiry = latestTime() + duration.days(10); - let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); + let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, dividendName, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 3, "Dividend should be created at checkpoint 3"); }); @@ -662,7 +678,7 @@ contract('EtherDividendCheckpoint', accounts => { let expiry = latestTime() + duration.days(2); let tx = await I_SecurityToken.createCheckpoint({from: token_owner}); try { - tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 4, {from: token_owner, value: 0}); + tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 4, dividendName, {from: token_owner, value: 0}); } catch(error) { console.log(` tx -> failed because msg.value is 0`.grey); ensureException(error); @@ -676,7 +692,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() - duration.days(10); try { - tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 4, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); + tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 4, dividendName, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); } catch(error) { console.log(` tx -> failed because maturity > expiry`.grey); ensureException(error); @@ -690,7 +706,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime() - duration.days(5); let expiry = latestTime() - duration.days(2); try { - tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 4, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); + tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 4, dividendName, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); } catch(error) { console.log(` tx -> failed because now > expiry`.grey); ensureException(error); @@ -704,7 +720,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() + duration.days(2); try { - tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 5, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); + tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 5, dividendName, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); } catch(error) { console.log(` tx -> failed because checkpoint id > current checkpoint`.grey); ensureException(error); @@ -717,7 +733,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() + duration.days(10); let tx = await I_SecurityToken.createCheckpoint({from: token_owner}); - tx = await I_EtherDividendCheckpoint.createDividendWithCheckpointAndExclusions(maturity, expiry, 4, [account_investor1], {from: token_owner, value: web3.utils.toWei('10', 'ether')}); + tx = await I_EtherDividendCheckpoint.createDividendWithCheckpointAndExclusions(maturity, expiry, 4, [account_investor1], dividendName, {from: token_owner, value: web3.utils.toWei('10', 'ether')}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 4, "Dividend should be created at checkpoint 4"); }); @@ -890,7 +906,7 @@ contract('EtherDividendCheckpoint', accounts => { it("Create another new dividend", async() => { let maturity = latestTime(); let expiry = latestTime() + duration.days(10); - let tx = await I_EtherDividendCheckpoint.createDividendWithExclusions(maturity, expiry, [], {from: token_owner, value: web3.utils.toWei('12', 'ether')}); + let tx = await I_EtherDividendCheckpoint.createDividendWithExclusions(maturity, expiry, [], dividendName, {from: token_owner, value: web3.utils.toWei('12', 'ether')}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 6, "Dividend should be created at checkpoint 6"); }); diff --git a/test/g_general_permission_manager.js b/test/g_general_permission_manager.js index 6e483d203..3b7299ca2 100644 --- a/test/g_general_permission_manager.js +++ b/test/g_general_permission_manager.js @@ -254,7 +254,7 @@ contract('GeneralPermissionManager', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner}); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 190ab54ad..36eccdbb0 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -241,7 +241,7 @@ contract('GeneralTransferManager', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/j_manual_approval_transfer_manager.js b/test/j_manual_approval_transfer_manager.js index 78953fa24..9036435f8 100644 --- a/test/j_manual_approval_transfer_manager.js +++ b/test/j_manual_approval_transfer_manager.js @@ -255,7 +255,7 @@ contract('ManualApprovalTransferManager', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner}); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/k_module_registry.js b/test/k_module_registry.js index bc728259f..a7ed18719 100644 --- a/test/k_module_registry.js +++ b/test/k_module_registry.js @@ -384,7 +384,7 @@ contract('ModuleRegistry', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, fundRaiseType, account_fundsReceiver]); let errorThrown = false; try { - const tx = await I_SecurityToken.addModule(I_CappedSTOFactory1.address, bytesSTO, 0, 0, { from: token_owner, gas: 60000000 }); + const tx = await I_SecurityToken.addModule(I_CappedSTOFactory1.address, bytesSTO, 0, 0, { from: token_owner}); } catch(error) { errorThrown = true; console.log(` tx revert -> Module is un-verified`.grey); @@ -426,7 +426,7 @@ contract('ModuleRegistry', accounts => { endTime = startTime + duration.days(30); let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, fundRaiseType, account_fundsReceiver]); let tx = await I_MRProxied.registerModule(I_CappedSTOFactory2.address, { from: token_owner }); - tx = await I_SecurityToken.addModule(I_CappedSTOFactory2.address, bytesSTO, 0, 0, { from: token_owner, gas: 60000000 }); + tx = await I_SecurityToken.addModule(I_CappedSTOFactory2.address, bytesSTO, 0, 0, { from: token_owner}); assert.equal(tx.logs[2].args._type, stoKey, "CappedSTO doesn't get deployed"); assert.equal( diff --git a/test/l_percentage_transfer_manager.js b/test/l_percentage_transfer_manager.js index 92504c4c2..4e81888f4 100644 --- a/test/l_percentage_transfer_manager.js +++ b/test/l_percentage_transfer_manager.js @@ -249,7 +249,7 @@ contract('PercentageTransferManager', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/m_presale_sto.js b/test/m_presale_sto.js index acc04642d..862885bcf 100644 --- a/test/m_presale_sto.js +++ b/test/m_presale_sto.js @@ -229,7 +229,7 @@ contract('PreSaleSTO', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol, "SecurityToken doesn't get deployed"); @@ -256,7 +256,7 @@ contract('PreSaleSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [0]); let errorThrown = false; try { - const tx = await I_SecurityToken.addModule(I_PreSaleSTOFactory.address, bytesSTO, 0, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken.addModule(I_PreSaleSTOFactory.address, bytesSTO, 0, 0, { from: token_owner }); } catch(error) { console.log(` tx revert -> Rate is ${0}. Test Passed Successfully`.grey); errorThrown = true; @@ -269,7 +269,7 @@ contract('PreSaleSTO', accounts => { endTime = latestTime() + duration.days(30); // Start time will be 5000 seconds more than the latest time let bytesSTO = encodeModuleCall(STOParameters, [endTime]); - const tx = await I_SecurityToken.addModule(I_PreSaleSTOFactory.address, bytesSTO, 0, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken.addModule(I_PreSaleSTOFactory.address, bytesSTO, 0, 0, { from: token_owner }); assert.equal(tx.logs[2].args._type, stoKey, "PreSaleSTO doesn't get deployed"); assert.equal( @@ -333,7 +333,7 @@ contract('PreSaleSTO', accounts => { // Jump time await increaseTime(duration.days(1)); - await I_PreSaleSTO.allocateTokens(account_investor1, web3.utils.toWei('1', 'ether'), web3.utils.toWei('1', 'ether'), 0, {from: account_issuer, gas: 60000000}); + await I_PreSaleSTO.allocateTokens(account_investor1, web3.utils.toWei('1', 'ether'), web3.utils.toWei('1', 'ether'), 0, {from: account_issuer }); assert.equal( (await I_PreSaleSTO.getRaised.call(0)) @@ -350,7 +350,7 @@ contract('PreSaleSTO', accounts => { it("Should allocate the tokens -- failed due to msg.sender is not pre sale admin", async () => { let errorThrown = false; try { - await I_PreSaleSTO.allocateTokens(account_investor1, web3.utils.toWei('1', 'ether'), web3.utils.toWei('1', 'ether'), 0, {from: account_fundsReceiver, gas: 60000000}); + await I_PreSaleSTO.allocateTokens(account_investor1, web3.utils.toWei('1', 'ether'), web3.utils.toWei('1', 'ether'), 0, {from: account_fundsReceiver }); } catch(error) { console.log(` tx revert -> msg.sender is not pre sale admin`.grey); errorThrown = true; @@ -392,7 +392,7 @@ contract('PreSaleSTO', accounts => { assert.equal(tx2.logs[0].args._investor, account_investor3, "Failed in adding the investor in whitelist"); - await I_PreSaleSTO.allocateTokensMulti([account_investor2, account_investor3], [web3.utils.toWei('1', 'ether'), web3.utils.toWei('1', 'ether')], [0,0], [web3.utils.toWei('1000', 'ether'), web3.utils.toWei('1000', 'ether')], {from: account_issuer, gas: 60000000}); + await I_PreSaleSTO.allocateTokensMulti([account_investor2, account_investor3], [web3.utils.toWei('1', 'ether'), web3.utils.toWei('1', 'ether')], [0,0], [web3.utils.toWei('1000', 'ether'), web3.utils.toWei('1000', 'ether')], {from: account_issuer }); assert.equal( (await I_PreSaleSTO.getRaised.call(1)) diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index e51bea0bd..69d9623ad 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -485,7 +485,7 @@ contract('SecurityTokenRegistry', accounts => { let errorThrown = false; await I_PolyToken.approve(I_STRProxied.address, 0, { from: token_owner}); try { - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); } catch(error) { console.log(` tx revert -> POLY allowance not provided for registration fee`.grey); errorThrown = true; @@ -499,7 +499,7 @@ contract('SecurityTokenRegistry', accounts => { await I_STRProxied.pause({ from: account_polymath}); await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); try { - await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); } catch(error) { console.log(` tx revert -> Registration is paused`.grey); errorThrown = true; @@ -512,7 +512,7 @@ contract('SecurityTokenRegistry', accounts => { let errorThrown = false; await I_STRProxied.unpause({ from: account_polymath}); try { - await I_STRProxied.generateSecurityToken(name, "", tokenDetails, false, { from: token_owner, gas:60000000 }); + await I_STRProxied.generateSecurityToken(name, "", tokenDetails, false, { from: token_owner }); } catch(error) { console.log(` tx revert -> Zero ticker length is not allowed`.grey); errorThrown = true; @@ -524,7 +524,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should fail to generate the securityToken -- Because name length is 0", async() => { let errorThrown = false; try { - await I_STRProxied.generateSecurityToken("", symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + await I_STRProxied.generateSecurityToken("", symbol, tokenDetails, false, { from: token_owner }); } catch(error) { console.log(` tx revert -> 0 name length is not allowed`.grey); errorThrown = true; @@ -536,7 +536,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should fail to generate the securityToken -- Because msg.sender is not the rightful owner of the ticker", async() => { let errorThrown = false; try { - await I_STRProxied.generateSecurityToken("", symbol, tokenDetails, false, { from: account_temp, gas:60000000 }); + await I_STRProxied.generateSecurityToken("", symbol, tokenDetails, false, { from: account_temp }); } catch(error) { console.log(` tx revert -> Because msg.sender is not the rightful owner of the ticker`.grey); errorThrown = true; @@ -547,7 +547,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol, "SecurityToken doesn't get deployed"); @@ -568,7 +568,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should fail to generate the SecurityToken when token is already deployed with the same symbol", async() => { let errorThrown = false; try { - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); } catch(error) { console.log(` tx revert -> Because ticker is already in use`.grey); errorThrown = true; @@ -608,7 +608,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should generate the new security token with version 2", async() => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name2, symbol2, tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name2, symbol2, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol2, "SecurityToken doesn't get deployed"); @@ -739,9 +739,15 @@ contract('SecurityTokenRegistry', accounts => { // Register the new ticker -- Fulfiling the TickerStatus.ON condition await I_PolyToken.getTokens(web3.utils.toWei("1000"), account_temp); await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: account_temp}); + let tickersListArray = await I_STRProxied.getTickersByOwner.call(account_temp); + console.log(tickersListArray); await I_STRProxied.registerTicker(account_temp, "LOG", "LOGAN", { from : account_temp }); + tickersListArray = await I_STRProxied.getTickersByOwner.call(account_temp); + console.log(tickersListArray); // Generating the ST let tx = await I_STRProxied.modifySecurityToken("LOGAN", "LOG", account_temp, dummy_token, "I am custom ST", latestTime(), {from: account_polymath}); + tickersListArray = await I_STRProxied.getTickersByOwner.call(account_temp); + console.log(tickersListArray); assert.equal(tx.logs[1].args._ticker, "LOG", "Symbol should match with the registered symbol"); assert.equal(tx.logs[1].args._securityTokenAddress, dummy_token,`Address of the SecurityToken should be matched with the input value of addCustomSecurityToken`); let symbolDetails = await I_STRProxied.getTickerDetails("LOG"); @@ -751,6 +757,17 @@ contract('SecurityTokenRegistry', accounts => { it("Should successfully generate the custom token", async() => { // Fulfilling the TickerStatus.NN condition + // let errorThrown = false; + // try { + // await I_STRProxied.modifySecurityToken("LOGAN2", "LOG2", account_temp, dummy_token, "I am custom ST", latestTime(), {from: account_polymath}); + // } catch(error) { + // console.log(` tx revert -> because ticker not registered`.grey); + // errorThrown = true; + // ensureException(error); + // } + // assert.ok(errorThrown, message); + // await I_STRProxied.modifyTicker(account_temp, "LOG2", "LOGAN2", latestTime(), latestTime() + duration.days(10), false, {from: account_polymath}); + // await increaseTime(duration.days(1)); let tx = await I_STRProxied.modifySecurityToken("LOGAN2", "LOG2", account_temp, dummy_token, "I am custom ST", latestTime(), {from: account_polymath}); assert.equal(tx.logs[1].args._ticker, "LOG2", "Symbol should match with the registered symbol"); assert.equal(tx.logs[1].args._securityTokenAddress, dummy_token, `Address of the SecurityToken should be matched with the input value of addCustomSecurityToken`); @@ -833,8 +850,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should change the details of the existing ticker", async() => { let tx = await I_STRProxied.modifyTicker(token_owner, "ETH", "Ether", latestTime(), (latestTime() + duration.minutes(10)), false, {from: account_polymath}); - assert.equal(tx.logs[0].args._oldOwner, account_temp); - assert.equal(tx.logs[0].args._newOwner, token_owner); + assert.equal(tx.logs[0].args._owner, token_owner); }); }); @@ -1014,7 +1030,7 @@ contract('SecurityTokenRegistry', accounts => { let errorThrown = false; await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); try { - await I_STRProxied.generateSecurityToken("Polymath", "POLY", tokenDetails, false, { from: token_owner, gas:60000000 }); + await I_STRProxied.generateSecurityToken("Polymath", "POLY", tokenDetails, false, { from: token_owner }); } catch(error) { console.log(` tx revert -> failed because of old launch fee`.grey); errorThrown = true; @@ -1025,7 +1041,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should launch the the securityToken", async() => { await I_PolyToken.approve(I_STRProxied.address, web3.utils.toWei("500"), { from: token_owner}); - let tx = await I_STRProxied.generateSecurityToken("Polymath", "POLY", tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken("Polymath", "POLY", tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, "POLY", "SecurityToken doesn't get deployed"); @@ -1083,7 +1099,8 @@ contract('SecurityTokenRegistry', accounts => { let tickersList = await I_STRProxied.getTickersByOwner.call(token_owner); assert.equal(tickersList.length, 4); let tickersListArray = await I_STRProxied.getTickersByOwner.call(account_temp); - assert.equal(tickersListArray.length, 2); + console.log(tickersListArray); + assert.equal(tickersListArray.length, 3); }); }); @@ -1120,6 +1137,58 @@ contract('SecurityTokenRegistry', accounts => { }); }) + describe(" Test cases of the registerTicker", async() => { + + it("Should register the ticker 1", async () => { + await I_PolyToken.getTokens(web3.utils.toWei("1000"), account_temp); + await I_PolyToken.approve(I_STRProxied.address, web3.utils.toWei("1000"), { from: account_temp}); + let tx = await I_STRProxied.registerTicker(account_temp, "TOK1", "", { from: account_temp }); + assert.equal(tx.logs[0].args._owner, account_temp, `Owner should be the ${account_temp}`); + assert.equal(tx.logs[0].args._ticker, "TOK1", `Symbol should be TOK1`); + console.log((await I_STRProxied.getTickersByOwner.call(account_temp)).map(x => web3.utils.toAscii(x))); + }); + + it("Should register the ticker 2", async () => { + await I_PolyToken.getTokens(web3.utils.toWei("1000"), account_temp); + await I_PolyToken.approve(I_STRProxied.address, web3.utils.toWei("1000"), { from: account_temp}); + let tx = await I_STRProxied.registerTicker(account_temp, "TOK2", "", { from: account_temp }); + assert.equal(tx.logs[0].args._owner, account_temp, `Owner should be the ${account_temp}`); + assert.equal(tx.logs[0].args._ticker, "TOK2", `Symbol should be TOK2`); + console.log((await I_STRProxied.getTickersByOwner.call(account_temp)).map(x => web3.utils.toAscii(x))); + }); + + it("Should register the ticker 3", async () => { + await I_PolyToken.getTokens(web3.utils.toWei("1000"), account_temp); + await I_PolyToken.approve(I_STRProxied.address, web3.utils.toWei("1000"), { from: account_temp}); + let tx = await I_STRProxied.registerTicker(account_temp, "TOK3", "", { from: account_temp }); + assert.equal(tx.logs[0].args._owner, account_temp, `Owner should be the ${account_temp}`); + assert.equal(tx.logs[0].args._ticker, "TOK3", `Symbol should be TOK3`); + console.log((await I_STRProxied.getTickersByOwner.call(account_temp)).map(x => web3.utils.toAscii(x))); + }); + + it("Should successfully remove the ticker 2", async() => { + let tx = await I_STRProxied.removeTicker("TOK2", {from: account_polymath}); + assert.equal(tx.logs[0].args._ticker, "TOK2", "Ticker doesn't get deleted successfully"); + console.log((await I_STRProxied.getTickersByOwner.call(account_temp)).map(x => web3.utils.toAscii(x))); + }); + + it("Should modify ticker 1", async() => { + let tx = await I_STRProxied.modifyTicker(account_temp, "TOK1", "TOKEN 1", latestTime(), (latestTime() + duration.minutes(10)), false, {from: account_polymath}); + assert.equal(tx.logs[0].args._owner, account_temp, `Should be equal to the ${account_temp}`); + assert.equal(tx.logs[0].args._ticker, "TOK1", "Should be equal to TOK1"); + assert.equal(tx.logs[0].args._name, "TOKEN 1", "Should be equal to TOKEN 1"); + console.log((await I_STRProxied.getTickersByOwner.call(account_temp)).map(x => web3.utils.toAscii(x))); + }) + + it("Should modify ticker 3", async() => { + let tx = await I_STRProxied.modifyTicker(account_temp, "TOK3", "TOKEN 3", latestTime(), (latestTime() + duration.minutes(10)), false, {from: account_polymath}); + assert.equal(tx.logs[0].args._owner, account_temp, `Should be equal to the ${account_temp}`); + assert.equal(tx.logs[0].args._ticker, "TOK3", "Should be equal to TOK3"); + assert.equal(tx.logs[0].args._name, "TOKEN 3", "Should be equal to TOKEN 3"); + console.log((await I_STRProxied.getTickersByOwner.call(account_temp)).map(x => web3.utils.toAscii(x))); + }) + + }); describe("Test cases for IRegistry functionality", async() => { describe("Test cases for reclaiming funds", async() => { diff --git a/test/o_security_token.js b/test/o_security_token.js index caaade82c..1217c6c22 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -255,7 +255,7 @@ contract('SecurityToken', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol, "SecurityToken doesn't get deployed"); @@ -444,7 +444,7 @@ contract('SecurityToken', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, fundRaiseType, account_fundsReceiver]); let errorThrown = false; try { - let tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 60000000 }); + let tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); } catch (error) { console.log(` tx revert -> not enough poly in contract`); errorThrown = true; @@ -461,7 +461,7 @@ contract('SecurityToken', accounts => { await I_PolyToken.transfer(I_SecurityToken.address, cappedSTOSetupCost, { from: token_owner}); let errorThrown = false; try { - let tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, web3.utils.toWei("1000","ether"), 0, { from: token_owner, gas: 60000000 }); + let tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, web3.utils.toWei("1000","ether"), 0, { from: token_owner }); } catch (error) { console.log(` tx revert -> max cost too small`); errorThrown = true; @@ -478,7 +478,7 @@ contract('SecurityToken', accounts => { await I_PolyToken.getTokens(cappedSTOSetupCost, token_owner); await I_PolyToken.transfer(I_SecurityToken.address, cappedSTOSetupCost, { from: token_owner}); - const tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 60000000 }); + const tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.toUtf8(tx.logs[3].args._name), "CappedSTO", "CappedSTOFactory module was not added"); diff --git a/test/r_concurrent_STO.js b/test/r_concurrent_STO.js index c86d53a43..f01a36436 100644 --- a/test/r_concurrent_STO.js +++ b/test/r_concurrent_STO.js @@ -239,7 +239,7 @@ contract('Concurrent STO', accounts => { await I_PolyToken.getTokens(initRegFee, account_issuer); await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: account_issuer}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: account_issuer, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: account_issuer }); assert.equal(tx.logs[1].args._ticker, symbol, "SecurityToken doesn't get deployed"); I_SecurityToken = SecurityToken.at(tx.logs[1].args._securityTokenAddress); diff --git a/test/t_security_token_registry_proxy.js b/test/t_security_token_registry_proxy.js index 2dcafde5c..2666f7158 100644 --- a/test/t_security_token_registry_proxy.js +++ b/test/t_security_token_registry_proxy.js @@ -185,7 +185,7 @@ contract ("SecurityTokenRegistryProxy", accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol, "SecurityToken doesn't get deployed"); diff --git a/test/v_tracked_redemptions.js b/test/v_tracked_redemptions.js index fe03a8614..95f3303ae 100644 --- a/test/v_tracked_redemptions.js +++ b/test/v_tracked_redemptions.js @@ -227,7 +227,7 @@ contract('TrackedRedemption', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); From 59cb476826a433618fe999ca8800b24c1f150d6e Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Tue, 2 Oct 2018 22:16:50 +0100 Subject: [PATCH 04/28] Size too big... --- contracts/SecurityTokenRegistry.sol | 2 +- contracts/tokens/SecurityToken.sol | 6 +++--- test/b_capped_sto.js | 2 +- test/d_count_transfer_manager.js | 2 +- test/e_erc20_dividends.js | 2 +- test/f_ether_dividends.js | 2 +- test/g_general_permission_manager.js | 2 +- test/h_general_transfer_manager.js | 4 ++-- test/j_manual_approval_transfer_manager.js | 2 +- test/l_percentage_transfer_manager.js | 2 +- test/m_presale_sto.js | 2 +- test/p_usd_tiered_sto.js | 2 +- test/v_tracked_redemptions.js | 2 +- 13 files changed, 16 insertions(+), 16 deletions(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 438e2eef5..8f2229b59 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -278,7 +278,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { return true; } - function _tickerStatus(string _ticker) internal returns(bool) { + function _tickerStatus(string _ticker) internal view returns(bool) { return getBool(Encoder.getKey("registeredTickers_status", _ticker)); } diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index c61d42b5c..40b032f67 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -687,12 +687,12 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return success */ function checkPermission(address _delegate, address _module, bytes32 _perm) public view returns(bool) { - if (modules[PERMISSIONMANAGER_KEY].length == 0) { + if (modules[PERMISSION_KEY].length == 0) { return false; } - for (uint8 i = 0; i < modules[PERMISSIONMANAGER_KEY].length; i++) { - if (IPermissionManager(modules[PERMISSIONMANAGER_KEY][i]).checkPermission(_delegate, _module, _perm)) { + for (uint8 i = 0; i < modules[PERMISSION_KEY].length; i++) { + if (IPermissionManager(modules[PERMISSION_KEY][i]).checkPermission(_delegate, _module, _perm)) { return true; } } diff --git a/test/b_capped_sto.js b/test/b_capped_sto.js index ec216c637..a07d6b864 100644 --- a/test/b_capped_sto.js +++ b/test/b_capped_sto.js @@ -1102,7 +1102,7 @@ contract('CappedSTO', accounts => { describe("Test cases for the CappedSTOFactory", async() => { it("should get the exact details of the factory", async() => { assert.equal((await I_CappedSTOFactory.setupCost.call()).toNumber(), cappedSTOSetupCost); - assert.equal(await I_CappedSTOFactory.getType.call(),3); + assert.equal(await I_CappedSTOFactory.getTypes.call(0),3); assert.equal(web3.utils.hexToString(await I_CappedSTOFactory.getName.call()), "CappedSTO", "Wrong Module added"); diff --git a/test/d_count_transfer_manager.js b/test/d_count_transfer_manager.js index 75c938939..0e588a068 100644 --- a/test/d_count_transfer_manager.js +++ b/test/d_count_transfer_manager.js @@ -477,7 +477,7 @@ contract('CountTransferManager', accounts => { describe("Test cases for the factory", async() => { it("should get the exact details of the factory", async() => { assert.equal(await I_CountTransferManagerFactory.setupCost.call(),0); - assert.equal(await I_CountTransferManagerFactory.getType.call(),2); + assert.equal(await I_CountTransferManagerFactory.getTypes.call(0),2); assert.equal(web3.utils.toAscii(await I_CountTransferManagerFactory.getName.call()) .replace(/\u0000/g, ''), "CountTransferManager", diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index cdd1fa98d..b2d34f577 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -938,7 +938,7 @@ contract('ERC20DividendCheckpoint', accounts => { describe("Test cases for the ERC20DividendCheckpointFactory", async() => { it("should get the exact details of the factory", async() => { assert.equal((await I_ERC20DividendCheckpointFactory.setupCost.call()).toNumber(), 0); - assert.equal(await I_ERC20DividendCheckpointFactory.getType.call(), 4); + assert.equal(await I_ERC20DividendCheckpointFactory.getTypes.call(0), 4); assert.equal(web3.utils.toAscii(await I_ERC20DividendCheckpointFactory.getName.call()) .replace(/\u0000/g, ''), "ERC20DividendCheckpoint", diff --git a/test/f_ether_dividends.js b/test/f_ether_dividends.js index dec4be72f..c31197c0a 100644 --- a/test/f_ether_dividends.js +++ b/test/f_ether_dividends.js @@ -958,7 +958,7 @@ contract('EtherDividendCheckpoint', accounts => { describe("Test cases for the EtherDividendCheckpointFactory", async() => { it("should get the exact details of the factory", async() => { assert.equal((await I_EtherDividendCheckpointFactory.setupCost.call()).toNumber(), 0); - assert.equal(await I_EtherDividendCheckpointFactory.getType.call(), 4); + assert.equal(await I_EtherDividendCheckpointFactory.getTypes.call(0), 4); assert.equal(web3.utils.toAscii(await I_EtherDividendCheckpointFactory.getName.call()) .replace(/\u0000/g, ''), "EtherDividendCheckpoint", diff --git a/test/g_general_permission_manager.js b/test/g_general_permission_manager.js index 3b7299ca2..da5a8a3f1 100644 --- a/test/g_general_permission_manager.js +++ b/test/g_general_permission_manager.js @@ -398,7 +398,7 @@ contract('GeneralPermissionManager', accounts => { describe("General Permission Manager Factory test cases", async() => { it("should get the exact details of the factory", async() => { assert.equal(await I_GeneralPermissionManagerFactory.setupCost.call(),0); - assert.equal(await I_GeneralPermissionManagerFactory.getType.call(),1); + assert.equal(await I_GeneralPermissionManagerFactory.getTypes.call(0),1); assert.equal(web3.utils.toAscii(await I_GeneralPermissionManagerFactory.getName.call()) .replace(/\u0000/g, ''), "GeneralPermissionManager", diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 36eccdbb0..76b4be249 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -791,7 +791,7 @@ contract('GeneralTransferManager', accounts => { it("Should get the exact details of the factory", async() => { assert.equal(await I_GeneralTransferManagerFactory.setupCost.call(),0); - assert.equal(await I_GeneralTransferManagerFactory.getType.call(),2); + assert.equal(await I_GeneralTransferManagerFactory.getTypes.call(0),2); assert.equal(web3.utils.toAscii(await I_GeneralTransferManagerFactory.getName.call()) .replace(/\u0000/g, ''), "GeneralTransferManager", @@ -817,7 +817,7 @@ contract('GeneralTransferManager', accounts => { describe("Dummy STO Factory test cases", async() => { it("should get the exact details of the factory", async() => { assert.equal(await I_DummySTOFactory.setupCost.call(),0); - assert.equal(await I_DummySTOFactory.getType.call(),3); + assert.equal(await I_DummySTOFactory.getTypes.call(0),3); assert.equal(web3.utils.toAscii(await I_DummySTOFactory.getName.call()) .replace(/\u0000/g, ''), "DummySTO", diff --git a/test/j_manual_approval_transfer_manager.js b/test/j_manual_approval_transfer_manager.js index 9036435f8..4a1a6bd5c 100644 --- a/test/j_manual_approval_transfer_manager.js +++ b/test/j_manual_approval_transfer_manager.js @@ -691,7 +691,7 @@ contract('ManualApprovalTransferManager', accounts => { it("Should get the exact details of the factory", async() => { assert.equal(await I_ManualApprovalTransferManagerFactory.setupCost.call(),0); - assert.equal(await I_ManualApprovalTransferManagerFactory.getType.call(),2); + assert.equal(await I_ManualApprovalTransferManagerFactory.getTypes.call(0),2); let name = web3.utils.toUtf8(await I_ManualApprovalTransferManagerFactory.getName.call()); assert.equal(name,"ManualApprovalTransferManager","Wrong Module added"); let desc = await I_ManualApprovalTransferManagerFactory.getDescription.call(); diff --git a/test/l_percentage_transfer_manager.js b/test/l_percentage_transfer_manager.js index 4e81888f4..92e9e3a46 100644 --- a/test/l_percentage_transfer_manager.js +++ b/test/l_percentage_transfer_manager.js @@ -459,7 +459,7 @@ contract('PercentageTransferManager', accounts => { it("Should get the exact details of the factory", async() => { assert.equal(await I_PercentageTransferManagerFactory.setupCost.call(),0); - assert.equal(await I_PercentageTransferManagerFactory.getType.call(),2); + assert.equal(await I_PercentageTransferManagerFactory.getTypes.call(0),2); assert.equal(web3.utils.toAscii(await I_PercentageTransferManagerFactory.getName.call()) .replace(/\u0000/g, ''), "PercentageTransferManager", diff --git a/test/m_presale_sto.js b/test/m_presale_sto.js index 862885bcf..ad5482b35 100644 --- a/test/m_presale_sto.js +++ b/test/m_presale_sto.js @@ -455,7 +455,7 @@ contract('PreSaleSTO', accounts => { describe("Test cases for the PresaleSTOFactory", async() => { it("should get the exact details of the factory", async() => { assert.equal(await I_PreSaleSTOFactory.setupCost.call(),0); - assert.equal(await I_PreSaleSTOFactory.getType.call(),3); + assert.equal(await I_PreSaleSTOFactory.getTypes.call(0),3); assert.equal(web3.utils.toAscii(await I_PreSaleSTOFactory.getName.call()) .replace(/\u0000/g, ''), "PreSaleSTO", diff --git a/test/p_usd_tiered_sto.js b/test/p_usd_tiered_sto.js index 1acc0ef7d..79270063b 100644 --- a/test/p_usd_tiered_sto.js +++ b/test/p_usd_tiered_sto.js @@ -3493,7 +3493,7 @@ contract('USDTieredSTO', accounts => { describe("Test cases for the USDTieredSTOFactory", async() => { it("should get the exact details of the factory", async() => { assert.equal((await I_USDTieredSTOFactory.setupCost.call()).toNumber(), STOSetupCost); - assert.equal(await I_USDTieredSTOFactory.getType.call(),3); + assert.equal(await I_USDTieredSTOFactory.getTypes.call(0),3); assert.equal(web3.utils.hexToString(await I_USDTieredSTOFactory.getName.call()), "USDTieredSTO", "Wrong Module added"); diff --git a/test/v_tracked_redemptions.js b/test/v_tracked_redemptions.js index 95f3303ae..634eb31e2 100644 --- a/test/v_tracked_redemptions.js +++ b/test/v_tracked_redemptions.js @@ -354,7 +354,7 @@ contract('TrackedRedemption', accounts => { describe("Test cases for the TrackedRedemptionFactory", async() => { it("should get the exact details of the factory", async() => { assert.equal((await I_TrackedRedemptionFactory.setupCost.call()).toNumber(), 0); - assert.equal(await I_TrackedRedemptionFactory.getType.call(), 5); + assert.equal(await I_TrackedRedemptionFactory.getTypes.call(0), 5); assert.equal(web3.utils.toAscii(await I_TrackedRedemptionFactory.getName.call()) .replace(/\u0000/g, ''), "TrackedRedemption", From ce069842bf0e410f1467da93c998ca5fea8321cb Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 3 Oct 2018 12:17:10 +0100 Subject: [PATCH 05/28] WIP --- contracts/libraries/Encoder.sol | 25 ++++++------ contracts/libraries/Util.sol | 10 ++--- contracts/libraries/VersionUtils.sol | 38 +++++++++---------- .../GeneralTransferManagerFactory.sol | 3 +- contracts/tokens/SecurityToken.sol | 16 ++++++-- 5 files changed, 51 insertions(+), 41 deletions(-) diff --git a/contracts/libraries/Encoder.sol b/contracts/libraries/Encoder.sol index edd446ef0..6e227456f 100644 --- a/contracts/libraries/Encoder.sol +++ b/contracts/libraries/Encoder.sol @@ -1,30 +1,29 @@ pragma solidity ^0.4.24; - library Encoder { - - function getKey(string _key) internal pure returns (bytes32) { + + function getKey(string _key) public pure returns (bytes32) { return bytes32(keccak256(abi.encodePacked(_key))); } - function getKey(string _key1, address _key2) internal pure returns (bytes32) { + function getKey(string _key1, address _key2) public pure returns (bytes32) { return bytes32(keccak256(abi.encodePacked(_key1, _key2))); } - - function getKey(string _key1, string _key2) internal pure returns (bytes32) { + + function getKey(string _key1, string _key2) public pure returns (bytes32) { return bytes32(keccak256(abi.encodePacked(_key1, _key2))); } - - function getKey(string _key1, uint256 _key2) internal pure returns (bytes32) { + + function getKey(string _key1, uint256 _key2) public pure returns (bytes32) { return bytes32(keccak256(abi.encodePacked(_key1, _key2))); } - - function getKey(string _key1, bytes32 _key2) internal pure returns (bytes32) { + + function getKey(string _key1, bytes32 _key2) public pure returns (bytes32) { return bytes32(keccak256(abi.encodePacked(_key1, _key2))); } - - function getKey(string _key1, bool _key2) internal pure returns (bytes32) { + + function getKey(string _key1, bool _key2) public pure returns (bytes32) { return bytes32(keccak256(abi.encodePacked(_key1, _key2))); } -} \ No newline at end of file +} diff --git a/contracts/libraries/Util.sol b/contracts/libraries/Util.sol index 4e60c9c59..10df40218 100644 --- a/contracts/libraries/Util.sol +++ b/contracts/libraries/Util.sol @@ -9,7 +9,7 @@ library Util { * @notice changes a string to upper case * @param _base string to change */ - function upper(string _base) internal pure returns (string) { + function upper(string _base) public pure returns (string) { bytes memory _baseBytes = bytes(_base); for (uint i = 0; i < _baseBytes.length; i++) { bytes1 b1 = _baseBytes[i]; @@ -26,7 +26,7 @@ library Util { * @param _source String that need to convert into bytes32 */ /// Notice - Maximum length for _source will be 32 chars otherwise returned bytes32 value will have lossy value. - function stringToBytes32(string memory _source) internal pure returns (bytes32) { + function stringToBytes32(string memory _source) public pure returns (bytes32) { return bytesToBytes32(bytes(_source), 0); } @@ -36,7 +36,7 @@ library Util { * @param _offset Offset from which to begin conversion */ /// Notice - Maximum length for _source will be 32 chars otherwise returned bytes32 value will have lossy value. - function bytesToBytes32(bytes _b, uint _offset) internal pure returns (bytes32) { + function bytesToBytes32(bytes _b, uint _offset) public pure returns (bytes32) { bytes32 result; for (uint i = 0; i < _b.length; i++) { @@ -49,7 +49,7 @@ library Util { * @notice Changes the bytes32 into string * @param _source that need to convert into string */ - function bytes32ToString(bytes32 _source) internal pure returns (string result) { + function bytes32ToString(bytes32 _source) public pure returns (string result) { bytes memory bytesString = new bytes(32); uint charCount = 0; for (uint j = 0; j < 32; j++) { @@ -71,7 +71,7 @@ library Util { * @param _data passed data * @return bytes4 sig */ - function getSig(bytes _data) internal pure returns (bytes4 sig) { + function getSig(bytes _data) public pure returns (bytes4 sig) { uint len = _data.length < 4 ? _data.length : 4; for (uint i = 0; i < len; i++) { sig = bytes4(uint(sig) + uint(_data[i]) * (2 ** (8 * (len - 1 - i)))); diff --git a/contracts/libraries/VersionUtils.sol b/contracts/libraries/VersionUtils.sol index 9b5f4fcc4..a07674647 100644 --- a/contracts/libraries/VersionUtils.sol +++ b/contracts/libraries/VersionUtils.sol @@ -5,14 +5,14 @@ pragma solidity ^0.4.24; */ library VersionUtils { - + /** * @notice This function is used to validate the version submitted * @param _current Array holds the present version of ST * @param _new Array holds the latest version of the ST - * @return bool + * @return bool */ - function isValidVersion(uint8[] _current, uint8[] _new) internal pure returns(bool) { + function isValidVersion(uint8[] _current, uint8[] _new) public pure returns(bool) { bool[] memory _temp = new bool[](_current.length); uint8 counter = 0; for (uint8 i = 0; i < _current.length; i++) { @@ -21,16 +21,16 @@ library VersionUtils { else _temp[i] = false; } - + for (i = 0; i < _current.length; i++) { if (i == 0) { if (_current[i] <= _new[i]) - if(_temp[0]) { + if(_temp[0]) { counter = counter + 3; break; } else counter++; - else + else return false; } else { if (_temp[i-1]) @@ -49,9 +49,9 @@ library VersionUtils { * @notice This function use to compare the lower bound with the latest version * @param _version1 Array holds the lower bound of the version * @param _version2 Array holds the latest version of the ST - * @return bool + * @return bool */ - function compareLowerBound(uint8[] _version1, uint8[] _version2) internal pure returns(bool) { + function compareLowerBound(uint8[] _version1, uint8[] _version2) public pure returns(bool) { require(_version1.length == _version2.length); uint counter = 0; for (uint8 j = 0; j< _version1.length; j++) { @@ -71,18 +71,18 @@ library VersionUtils { if (counter == _version1.length - 1) return true; else - return false; + return false; } else - return true; + return true; } /** * @notice This function use to compare the upper bound with the latest version * @param _version1 Array holds the upper bound of the version * @param _version2 Array holds the latest version of the ST - * @return bool + * @return bool */ - function compareUpperBound(uint8[] _version1, uint8[] _version2) internal pure returns(bool) { + function compareUpperBound(uint8[] _version1, uint8[] _version2) public pure returns(bool) { require(_version1.length == _version2.length); uint counter = 0; for (uint8 j = 0; j< _version1.length; j++) { @@ -102,19 +102,19 @@ library VersionUtils { if (counter == _version1.length - 1) return true; else - return false; + return false; } else - return true; + return true; } - + /** * @notice Use to pack the uint8[] array data into uint24 value * @param _major Major version * @param _minor Minor version * @param _patch Patch version */ - function pack(uint8 _major, uint8 _minor, uint8 _patch) internal pure returns(uint24) { + function pack(uint8 _major, uint8 _minor, uint8 _patch) public pure returns(uint24) { return (uint24(_major) << 16) | (uint24(_minor) << 8) | uint24(_patch); } @@ -122,13 +122,13 @@ library VersionUtils { * @notice Use to convert packed data into uint8 array * @param _packedVersion Packed data */ - function unpack(uint24 _packedVersion) internal pure returns (uint8[]) { + function unpack(uint24 _packedVersion) public pure returns (uint8[]) { uint8[] memory _unpackVersion = new uint8[](3); _unpackVersion[0] = uint8(_packedVersion >> 16); _unpackVersion[1] = uint8(_packedVersion >> 8); _unpackVersion[2] = uint8(_packedVersion); return _unpackVersion; } - -} \ No newline at end of file + +} diff --git a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol index 60e85f8f4..8b8dd8790 100644 --- a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol @@ -41,8 +41,9 @@ contract GeneralTransferManagerFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - uint8[] memory res = new uint8[](1); + uint8[] memory res = new uint8[](2); res[0] = 2; + res[1] = 3; return res; } diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 40b032f67..d3e840261 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -68,6 +68,15 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // address whitelisted by issuer as controller address public controller; + event ModuleDataEvent( + bytes32 name, + address module, + address moduleFactory, + bool isArchived, + uint8[] moduleTypes, + uint256[] moduleIndexes, + uint256 nameIndex + ); // Struct for module data struct ModuleData { bytes32 name; @@ -269,18 +278,19 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr //Add to SecurityToken module map bytes32 moduleName = moduleFactory.getName(); uint256[] memory moduleIndexes = new uint256[](moduleTypes.length); - //TODO: Enforce uniqueness + //Enforce type uniqueness uint256 i; uint256 j; for (i = 0; i < moduleTypes.length; i++) { - for (j = i; j < moduleTypes.length; j++) { + for (j = 0; j < i; j++) { require(moduleTypes[i] != moduleTypes[j], "Bad types"); } } for (i = 0; i < moduleTypes.length; i++) { moduleIndexes[i] = modules[moduleTypes[i]].length; } - modulesToData[module] = ModuleData(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); + emit ModuleDataEvent(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); + /* modulesToData[module] = ModuleData(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); */ for (i = 0; i < moduleTypes.length; i++) { modules[moduleTypes[i]].push(module); } From ceed74e2bb883ba50ea1ad7179317a151600532f Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 3 Oct 2018 13:43:34 +0100 Subject: [PATCH 06/28] WIP --- contracts/libraries/Encoder.sol | 12 +- migrations/2_deploy_contracts.js | 458 +++++++++++++++++-------------- 2 files changed, 257 insertions(+), 213 deletions(-) diff --git a/contracts/libraries/Encoder.sol b/contracts/libraries/Encoder.sol index 6e227456f..27d9a4ddf 100644 --- a/contracts/libraries/Encoder.sol +++ b/contracts/libraries/Encoder.sol @@ -2,27 +2,27 @@ pragma solidity ^0.4.24; library Encoder { - function getKey(string _key) public pure returns (bytes32) { + function getKey(string _key) internal pure returns (bytes32) { return bytes32(keccak256(abi.encodePacked(_key))); } - function getKey(string _key1, address _key2) public pure returns (bytes32) { + function getKey(string _key1, address _key2) internal pure returns (bytes32) { return bytes32(keccak256(abi.encodePacked(_key1, _key2))); } - function getKey(string _key1, string _key2) public pure returns (bytes32) { + function getKey(string _key1, string _key2) internal pure returns (bytes32) { return bytes32(keccak256(abi.encodePacked(_key1, _key2))); } - function getKey(string _key1, uint256 _key2) public pure returns (bytes32) { + function getKey(string _key1, uint256 _key2) internal pure returns (bytes32) { return bytes32(keccak256(abi.encodePacked(_key1, _key2))); } - function getKey(string _key1, bytes32 _key2) public pure returns (bytes32) { + function getKey(string _key1, bytes32 _key2) internal pure returns (bytes32) { return bytes32(keccak256(abi.encodePacked(_key1, _key2))); } - function getKey(string _key1, bool _key2) public pure returns (bytes32) { + function getKey(string _key1, bool _key2) internal pure returns (bytes32) { return bytes32(keccak256(abi.encodePacked(_key1, _key2))); } diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index 97124b804..2a8804d49 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -17,6 +17,9 @@ 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') +const VersionUtils = artifacts.require('./VersionUtils.sol'); +const Util = artifacts.require('./Util.sol'); + let BigNumber = require('bignumber.js'); const cappedSTOSetupCost = new BigNumber(20000).times(new BigNumber(10).pow(18)); // 20K POLY fee const usdTieredSTOSetupCost = new BigNumber(100000).times(new BigNumber(10).pow(18)); // 100K POLY fee @@ -30,8 +33,9 @@ const Web3 = require('web3') module.exports = function (deployer, network, accounts) { // Ethereum account address hold by the Polymath (Act as the main account which have ownable permissions) - let PolymathAccount - let moduleRegistry + let PolymathAccount; + let moduleRegistry; + let polymathRegistry; let web3 if (network === 'development') { web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')) @@ -52,6 +56,7 @@ module.exports = function (deployer, network, accounts) { ETHOracle = mockedOracle.address; }); }); + } else if (network === 'kovan') { web3 = new Web3(new Web3.providers.HttpProvider('https://kovan.infura.io/g5xfoQ0jFSE9S5LwM1Ei')) PolymathAccount = accounts[0] @@ -101,220 +106,259 @@ module.exports = function (deployer, network, accounts) { },{ type: 'address', name: '_owner' - } -] -}; + }] + }; -const functionSignatureProxyMR = { - name: 'initialize', - type: 'function', - inputs: [{ - type:'address', - name: '_polymathRegistry' - },{ - type: 'address', - name: '_owner' - } -] -}; + const functionSignatureProxyMR = { + name: 'initialize', + type: 'function', + inputs: [{ + type:'address', + name: '_polymathRegistry' + },{ + type: 'address', + name: '_owner' + }] + }; // POLYMATH NETWORK Configuration :: DO THIS ONLY ONCE // A) Deploy the PolymathRegistry contract return deployer.deploy(PolymathRegistry, {from: PolymathAccount}).then(() => { - return PolymathRegistry.deployed().then((polymathRegistry) => { - - return polymathRegistry.changeAddress("PolyToken", PolyToken, {from: PolymathAccount}) - .then(() => { - // A) Deploy the ModuleRegistry Contract (It contains the list of verified ModuleFactory) - return deployer.deploy(ModuleRegistry, {from: PolymathAccount}); - }).then(() => { - return deployer.deploy(ModuleRegistryProxy, {from: PolymathAccount}); - }).then(() => { - let bytesProxyMR = web3.eth.abi.encodeFunctionCall(functionSignatureProxyMR, [polymathRegistry.address, PolymathAccount]); - ModuleRegistryProxy.at(ModuleRegistryProxy.address).upgradeToAndCall("1.0.0", ModuleRegistry.address, bytesProxyMR, {from: PolymathAccount}); - }).then(() => { - moduleRegistry = ModuleRegistry.at(ModuleRegistryProxy.address); - // Add module registry to polymath registry - return polymathRegistry.changeAddress("ModuleRegistry", ModuleRegistryProxy.address, {from: PolymathAccount}); - }).then(() => { - // B) Deploy the GeneralTransferManagerFactory Contract (Factory used to generate the GeneralTransferManager contract and this - // manager attach with the securityToken contract at the time of deployment) - return deployer.deploy(GeneralTransferManagerFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); - }).then(() => { - // C) Deploy the GeneralPermissionManagerFactory Contract (Factory used to generate the GeneralPermissionManager contract and - // this manager attach with the securityToken contract at the time of deployment) - return deployer.deploy(GeneralPermissionManagerFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); - }).then(() => { - // D) Deploy the CountTransferManagerFactory Contract (Factory used to generate the CountTransferManager contract use - // to track the counts of the investors of the security token) - return deployer.deploy(CountTransferManagerFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); - }).then(() => { - // D) Deploy the PercentageTransferManagerFactory Contract (Factory used to generate the PercentageTransferManager contract use - // to track the percentage of investment the investors could do for a particular security token) - return deployer.deploy(PercentageTransferManagerFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); - }).then(() => { - // D) Deploy the EtherDividendCheckpointFactory Contract (Factory used to generate the EtherDividendCheckpoint contract use - // to provide the functionality of the dividend in terms of ETH) - return deployer.deploy(EtherDividendCheckpointFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); - }).then(() => { - // D) Deploy the ERC20DividendCheckpointFactory Contract (Factory used to generate the ERC20DividendCheckpoint contract use - // to provide the functionality of the dividend in terms of ERC20 token) - return deployer.deploy(ERC20DividendCheckpointFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); - }).then(() => { - // D) Deploy the ManualApprovalTransferManagerFactory Contract (Factory used to generate the ManualApprovalTransferManager contract use - // to manual approve the transfer that will overcome the other transfer restrictions) - return deployer.deploy(ManualApprovalTransferManagerFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); - }).then(() => { - // H) Deploy the STVersionProxy001 Contract which contains the logic of deployment of securityToken. - return deployer.deploy(STFactory, GeneralTransferManagerFactory.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(() => { - // J) Deploy the SecurityTokenRegistry contract (Used to hold the deployed secuirtyToken details. It also act as the interface to deploy the SecurityToken) - return deployer.deploy(SecurityTokenRegistry, {from: PolymathAccount}) - }).then(()=> { - return deployer.deploy(SecurityTokenRegistryProxy, {from: PolymathAccount}); - }).then(() => { - let bytesProxy = web3.eth.abi.encodeFunctionCall(functionSignatureProxy, [PolymathRegistry.address, STFactory.address, initRegFee, initRegFee, PolyToken, PolymathAccount]); - SecurityTokenRegistryProxy.at(SecurityTokenRegistryProxy.address).upgradeToAndCall("1.0.0", SecurityTokenRegistry.address, bytesProxy, {from: PolymathAccount}); - }).then(() => { - // Assign the address into the SecurityTokenRegistry key - return polymathRegistry.changeAddress("SecurityTokenRegistry", SecurityTokenRegistryProxy.address, {from: PolymathAccount}); - }).then(() => { - // Update all addresses into the registry contract by calling the function updateFromregistry - return moduleRegistry.updateFromRegistry({from: PolymathAccount}); - }).then(() => { - // D) Register the PercentageTransferManagerFactory in the ModuleRegistry to make the factory available at the protocol level. - // So any securityToken can use that factory to generate the PercentageTransferManager contract. - return moduleRegistry.registerModule(PercentageTransferManagerFactory.address, {from: PolymathAccount}); - }).then(() => { - // D) Register the CountTransferManagerFactory in the ModuleRegistry to make the factory available at the protocol level. - // So any securityToken can use that factory to generate the CountTransferManager contract. - return moduleRegistry.registerModule(CountTransferManagerFactory.address, {from: PolymathAccount}); - }).then(() => { - // D) Register the GeneralTransferManagerFactory in the ModuleRegistry to make the factory available at the protocol level. - // So any securityToken can use that factory to generate the GeneralTransferManager contract. - return moduleRegistry.registerModule(GeneralTransferManagerFactory.address, {from: PolymathAccount}); - }).then(() => { - // E) Register the GeneralPermissionManagerFactory in the ModuleRegistry to make the factory available at the protocol level. - // So any securityToken can use that factory to generate the GeneralPermissionManager contract. - return moduleRegistry.registerModule(GeneralPermissionManagerFactory.address, {from: PolymathAccount}); - }).then(() => { - // E) Register the GeneralPermissionManagerFactory in the ModuleRegistry to make the factory available at the protocol level. - // So any securityToken can use that factory to generate the GeneralPermissionManager contract. - return moduleRegistry.registerModule(EtherDividendCheckpointFactory.address, {from: PolymathAccount}); - }).then(() => { - // D) Register the ManualApprovalTransferManagerFactory in the ModuleRegistry to make the factory available at the protocol level. - // So any securityToken can use that factory to generate the ManualApprovalTransferManager contract. - return moduleRegistry.registerModule(ManualApprovalTransferManagerFactory.address, {from: PolymathAccount}); - }).then(() => { - // E) Register the ERC20DividendCheckpointFactory in the ModuleRegistry to make the factory available at the protocol level. - // So any securityToken can use that factory to generate the ERC20DividendCheckpoint contract. - return moduleRegistry.registerModule(ERC20DividendCheckpointFactory.address, {from: PolymathAccount}); - }).then(() => { - // F) Once the GeneralTransferManagerFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken - // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. - // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. - return moduleRegistry.verifyModule(GeneralTransferManagerFactory.address, true, {from: PolymathAccount}); - }).then(() => { - // G) Once the CountTransferManagerFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken - // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. - // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. - return moduleRegistry.verifyModule(CountTransferManagerFactory.address, true, {from: PolymathAccount}); - }).then(() => { - // G) Once the PercentageTransferManagerFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken - // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. - // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. - return moduleRegistry.verifyModule(PercentageTransferManagerFactory.address, true, {from: PolymathAccount}); - }).then(() => { - // G) Once the GeneralPermissionManagerFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken - // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. - // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. - return moduleRegistry.verifyModule(GeneralPermissionManagerFactory.address, true, {from: PolymathAccount}) - }).then(() => { - // G) Once the EtherDividendCheckpointFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken - // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. - // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. - return moduleRegistry.verifyModule(EtherDividendCheckpointFactory.address, true, {from: PolymathAccount}); - }).then(() => { - // G) Once the ERC20DividendCheckpointFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken - // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. - // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. - return moduleRegistry.verifyModule(ERC20DividendCheckpointFactory.address, true, {from: PolymathAccount}); - }).then(() => { - // G) Once the ManualApprovalTransferManagerFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken - // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. - // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. - return moduleRegistry.verifyModule(ManualApprovalTransferManagerFactory.address, true, {from: PolymathAccount}); - }).then(() => { - // M) Deploy the CappedSTOFactory (Use to generate the CappedSTO contract which will used to collect the funds ). - return deployer.deploy(CappedSTOFactory, PolyToken, cappedSTOSetupCost, 0, 0, {from: PolymathAccount}) - }).then(() => { - // N) Register the CappedSTOFactory in the ModuleRegistry to make the factory available at the protocol level. - // So any securityToken can use that factory to generate the CappedSTOFactory contract. - return moduleRegistry.registerModule(CappedSTOFactory.address, {from: PolymathAccount}) - }).then(()=>{ - // G) Once the CappedSTOFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken - // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. - // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. - return moduleRegistry.verifyModule(CappedSTOFactory.address, true, {from: PolymathAccount}) - }).then(() => { - // Deploy the proxy factory - return deployer.deploy(USDTieredSTOProxyFactory, {from: PolymathAccount}); - }).then(() => { - // H) Deploy the USDTieredSTOFactory (Use to generate the USDTieredSTOFactory contract which will used to collect the funds ). - return deployer.deploy(USDTieredSTOFactory, PolyToken, usdTieredSTOSetupCost, 0, 0, USDTieredSTOProxyFactory.address, {from: PolymathAccount}) - }).then(() => { - // I) Register the USDTieredSTOFactory in the ModuleRegistry to make the factory available at the protocol level. - // So any securityToken can use that factory to generate the USDTieredSTOFactory contract. - return moduleRegistry.registerModule(USDTieredSTOFactory.address, {from: PolymathAccount}) - }).then(()=>{ - // J) Once the USDTieredSTOFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken - // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. - // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. - return moduleRegistry.verifyModule(USDTieredSTOFactory.address, true, {from: PolymathAccount}) - }).then(() => { - return polymathRegistry.changeAddress("PolyUsdOracle", POLYOracle, {from: PolymathAccount}); - }).then(() => { - return polymathRegistry.changeAddress("EthUsdOracle", ETHOracle, {from: PolymathAccount}); - }).then(() => { - console.log('\n'); - console.log(` - --------------------- Polymath Network Smart Contracts: --------------------- - PolymathRegistry: ${PolymathRegistry.address} - SecurityTokenRegistryProxy: ${SecurityTokenRegistryProxy.address} - SecurityTokenRegistry: ${SecurityTokenRegistry.address} - ModuleRegistry: ${ModuleRegistry.address} - ModuleRegistryProxy: ${ModuleRegistryProxy.address} - FeatureRegistry: ${FeatureRegistry.address} + return PolymathRegistry.deployed(); + }).then((_polymathRegistry) => { + polymathRegistry = _polymathRegistry; + return polymathRegistry.changeAddress("PolyToken", PolyToken, {from: PolymathAccount}); + }).then(() => { + // Deploy libraries + return deployer.deploy(VersionUtils, {from: PolymathAccount}); + }).then(() => { + return deployer.deploy(Util, {from: PolymathAccount}); + }).then(() => { + // Link libraries + return deployer.link(VersionUtils, ModuleRegistry); + }).then(() => { + return deployer.link(VersionUtils, SecurityTokenRegistry); + }).then(() => { + return deployer.link(VersionUtils, GeneralTransferManagerFactory); + }).then(() => { + return deployer.link(VersionUtils, GeneralPermissionManagerFactory); + }).then(() => { + return deployer.link(VersionUtils, PercentageTransferManagerFactory); + }).then(() => { + return deployer.link(VersionUtils, USDTieredSTOProxyFactory); + }).then(() => { + return deployer.link(VersionUtils, CountTransferManagerFactory); + }).then(() => { + return deployer.link(VersionUtils, EtherDividendCheckpointFactory); + }).then(() => { + return deployer.link(VersionUtils, ERC20DividendCheckpointFactory); + }).then(() => { + return deployer.link(VersionUtils, ManualApprovalTransferManagerFactory); + }).then(() => { + return deployer.link(VersionUtils, CappedSTOFactory); + }).then(() => { + return deployer.link(VersionUtils, USDTieredSTOFactory); + }).then(() => { + return deployer.link(Util, CappedSTOFactory); + }).then(() => { + return deployer.link(Util, USDTieredSTOFactory); + }).then(() => { + return deployer.link(Util, CountTransferManagerFactory); + }).then(() => { + return deployer.link(Util, PercentageTransferManagerFactory); + }).then(() => { + return deployer.link(Util, SecurityTokenRegistry); + }).then(() => { + return deployer.link(Util, STFactory); + }).then(() => { + // A) Deploy the ModuleRegistry Contract (It contains the list of verified ModuleFactory) + return deployer.deploy(ModuleRegistry, {from: PolymathAccount}); + }).then(() => { + return deployer.deploy(ModuleRegistryProxy, {from: PolymathAccount}); + }).then(() => { + let bytesProxyMR = web3.eth.abi.encodeFunctionCall(functionSignatureProxyMR, [polymathRegistry.address, PolymathAccount]); + ModuleRegistryProxy.at(ModuleRegistryProxy.address).upgradeToAndCall("1.0.0", ModuleRegistry.address, bytesProxyMR, {from: PolymathAccount}); + }).then(() => { + moduleRegistry = ModuleRegistry.at(ModuleRegistryProxy.address); + // Add module registry to polymath registry + return polymathRegistry.changeAddress("ModuleRegistry", ModuleRegistryProxy.address, {from: PolymathAccount}); + }).then(() => { + // B) Deploy the GeneralTransferManagerFactory Contract (Factory used to generate the GeneralTransferManager contract and this + // manager attach with the securityToken contract at the time of deployment) + return deployer.deploy(GeneralTransferManagerFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); + }).then(() => { + // C) Deploy the GeneralPermissionManagerFactory Contract (Factory used to generate the GeneralPermissionManager contract and + // this manager attach with the securityToken contract at the time of deployment) + return deployer.deploy(GeneralPermissionManagerFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); + }).then(() => { + // D) Deploy the CountTransferManagerFactory Contract (Factory used to generate the CountTransferManager contract use + // to track the counts of the investors of the security token) + return deployer.deploy(CountTransferManagerFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); + }).then(() => { + // D) Deploy the PercentageTransferManagerFactory Contract (Factory used to generate the PercentageTransferManager contract use + // to track the percentage of investment the investors could do for a particular security token) + return deployer.deploy(PercentageTransferManagerFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); + }).then(() => { + // D) Deploy the EtherDividendCheckpointFactory Contract (Factory used to generate the EtherDividendCheckpoint contract use + // to provide the functionality of the dividend in terms of ETH) + return deployer.deploy(EtherDividendCheckpointFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); + }).then(() => { + // D) Deploy the ERC20DividendCheckpointFactory Contract (Factory used to generate the ERC20DividendCheckpoint contract use + // to provide the functionality of the dividend in terms of ERC20 token) + return deployer.deploy(ERC20DividendCheckpointFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); + }).then(() => { + // D) Deploy the ManualApprovalTransferManagerFactory Contract (Factory used to generate the ManualApprovalTransferManager contract use + // to manual approve the transfer that will overcome the other transfer restrictions) + return deployer.deploy(ManualApprovalTransferManagerFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); + }).then(() => { + // H) Deploy the STVersionProxy001 Contract which contains the logic of deployment of securityToken. + return deployer.deploy(STFactory, GeneralTransferManagerFactory.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(() => { + // J) Deploy the SecurityTokenRegistry contract (Used to hold the deployed secuirtyToken details. It also act as the interface to deploy the SecurityToken) + return deployer.deploy(SecurityTokenRegistry, {from: PolymathAccount}) + }).then(()=> { + return deployer.deploy(SecurityTokenRegistryProxy, {from: PolymathAccount}); + }).then(() => { + let bytesProxy = web3.eth.abi.encodeFunctionCall(functionSignatureProxy, [PolymathRegistry.address, STFactory.address, initRegFee, initRegFee, PolyToken, PolymathAccount]); + SecurityTokenRegistryProxy.at(SecurityTokenRegistryProxy.address).upgradeToAndCall("1.0.0", SecurityTokenRegistry.address, bytesProxy, {from: PolymathAccount}); + }).then(() => { + // Assign the address into the SecurityTokenRegistry key + return polymathRegistry.changeAddress("SecurityTokenRegistry", SecurityTokenRegistryProxy.address, {from: PolymathAccount}); + }).then(() => { + // Update all addresses into the registry contract by calling the function updateFromregistry + return moduleRegistry.updateFromRegistry({from: PolymathAccount}); + }).then(() => { + // D) Register the PercentageTransferManagerFactory in the ModuleRegistry to make the factory available at the protocol level. + // So any securityToken can use that factory to generate the PercentageTransferManager contract. + return moduleRegistry.registerModule(PercentageTransferManagerFactory.address, {from: PolymathAccount}); + }).then(() => { + // D) Register the CountTransferManagerFactory in the ModuleRegistry to make the factory available at the protocol level. + // So any securityToken can use that factory to generate the CountTransferManager contract. + return moduleRegistry.registerModule(CountTransferManagerFactory.address, {from: PolymathAccount}); + }).then(() => { + // D) Register the GeneralTransferManagerFactory in the ModuleRegistry to make the factory available at the protocol level. + // So any securityToken can use that factory to generate the GeneralTransferManager contract. + return moduleRegistry.registerModule(GeneralTransferManagerFactory.address, {from: PolymathAccount}); + }).then(() => { + // E) Register the GeneralPermissionManagerFactory in the ModuleRegistry to make the factory available at the protocol level. + // So any securityToken can use that factory to generate the GeneralPermissionManager contract. + return moduleRegistry.registerModule(GeneralPermissionManagerFactory.address, {from: PolymathAccount}); + }).then(() => { + // E) Register the GeneralPermissionManagerFactory in the ModuleRegistry to make the factory available at the protocol level. + // So any securityToken can use that factory to generate the GeneralPermissionManager contract. + return moduleRegistry.registerModule(EtherDividendCheckpointFactory.address, {from: PolymathAccount}); + }).then(() => { + // D) Register the ManualApprovalTransferManagerFactory in the ModuleRegistry to make the factory available at the protocol level. + // So any securityToken can use that factory to generate the ManualApprovalTransferManager contract. + return moduleRegistry.registerModule(ManualApprovalTransferManagerFactory.address, {from: PolymathAccount}); + }).then(() => { + // E) Register the ERC20DividendCheckpointFactory in the ModuleRegistry to make the factory available at the protocol level. + // So any securityToken can use that factory to generate the ERC20DividendCheckpoint contract. + return moduleRegistry.registerModule(ERC20DividendCheckpointFactory.address, {from: PolymathAccount}); + }).then(() => { + // F) Once the GeneralTransferManagerFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken + // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. + // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. + return moduleRegistry.verifyModule(GeneralTransferManagerFactory.address, true, {from: PolymathAccount}); + }).then(() => { + // G) Once the CountTransferManagerFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken + // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. + // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. + return moduleRegistry.verifyModule(CountTransferManagerFactory.address, true, {from: PolymathAccount}); + }).then(() => { + // G) Once the PercentageTransferManagerFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken + // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. + // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. + return moduleRegistry.verifyModule(PercentageTransferManagerFactory.address, true, {from: PolymathAccount}); + }).then(() => { + // G) Once the GeneralPermissionManagerFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken + // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. + // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. + return moduleRegistry.verifyModule(GeneralPermissionManagerFactory.address, true, {from: PolymathAccount}) + }).then(() => { + // G) Once the EtherDividendCheckpointFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken + // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. + // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. + return moduleRegistry.verifyModule(EtherDividendCheckpointFactory.address, true, {from: PolymathAccount}); + }).then(() => { + // G) Once the ERC20DividendCheckpointFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken + // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. + // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. + return moduleRegistry.verifyModule(ERC20DividendCheckpointFactory.address, true, {from: PolymathAccount}); + }).then(() => { + // G) Once the ManualApprovalTransferManagerFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken + // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. + // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. + return moduleRegistry.verifyModule(ManualApprovalTransferManagerFactory.address, true, {from: PolymathAccount}); + }).then(() => { + // M) Deploy the CappedSTOFactory (Use to generate the CappedSTO contract which will used to collect the funds ). + return deployer.deploy(CappedSTOFactory, PolyToken, cappedSTOSetupCost, 0, 0, {from: PolymathAccount}) + }).then(() => { + // N) Register the CappedSTOFactory in the ModuleRegistry to make the factory available at the protocol level. + // So any securityToken can use that factory to generate the CappedSTOFactory contract. + return moduleRegistry.registerModule(CappedSTOFactory.address, {from: PolymathAccount}) + }).then(()=>{ + // G) Once the CappedSTOFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken + // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. + // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. + return moduleRegistry.verifyModule(CappedSTOFactory.address, true, {from: PolymathAccount}) + }).then(() => { + // Deploy the proxy factory + return deployer.deploy(USDTieredSTOProxyFactory, {from: PolymathAccount}); + }).then(() => { + // H) Deploy the USDTieredSTOFactory (Use to generate the USDTieredSTOFactory contract which will used to collect the funds ). + return deployer.deploy(USDTieredSTOFactory, PolyToken, usdTieredSTOSetupCost, 0, 0, USDTieredSTOProxyFactory.address, {from: PolymathAccount}) + }).then(() => { + // I) Register the USDTieredSTOFactory in the ModuleRegistry to make the factory available at the protocol level. + // So any securityToken can use that factory to generate the USDTieredSTOFactory contract. + return moduleRegistry.registerModule(USDTieredSTOFactory.address, {from: PolymathAccount}) + }).then(()=>{ + // J) Once the USDTieredSTOFactory registered with the ModuleRegistry contract then for making them accessble to the securityToken + // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. + // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. + return moduleRegistry.verifyModule(USDTieredSTOFactory.address, true, {from: PolymathAccount}) + }).then(() => { + return polymathRegistry.changeAddress("PolyUsdOracle", POLYOracle, {from: PolymathAccount}); + }).then(() => { + return polymathRegistry.changeAddress("EthUsdOracle", ETHOracle, {from: PolymathAccount}); + }).then(() => { + console.log('\n'); + console.log(` + --------------------- Polymath Network Smart Contracts: --------------------- + PolymathRegistry: ${PolymathRegistry.address} + SecurityTokenRegistryProxy: ${SecurityTokenRegistryProxy.address} + SecurityTokenRegistry: ${SecurityTokenRegistry.address} + ModuleRegistry: ${ModuleRegistry.address} + ModuleRegistryProxy: ${ModuleRegistryProxy.address} + FeatureRegistry: ${FeatureRegistry.address} - ETHOracle: ${ETHOracle} - POLYOracle: ${POLYOracle} + 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} - USDTieredSTOProxyFactory: ${USDTieredSTOProxyFactory.address} + CappedSTOFactory: ${CappedSTOFactory.address} + USDTieredSTOFactory: ${USDTieredSTOFactory.address} + USDTieredSTOProxyFactory: ${USDTieredSTOProxyFactory.address} - CountTransferManagerFactory: ${CountTransferManagerFactory.address} - PercentageTransferManagerFactory: ${PercentageTransferManagerFactory.address} - ManualApprovalTransferManagerFactory: - ${ManualApprovalTransferManagerFactory.address} + CountTransferManagerFactory: ${CountTransferManagerFactory.address} + PercentageTransferManagerFactory: ${PercentageTransferManagerFactory.address} + ManualApprovalTransferManagerFactory: + ${ManualApprovalTransferManagerFactory.address} - EtherDividendCheckpointFactory: ${EtherDividendCheckpointFactory.address} - ERC20DividendCheckpointFactory: ${ERC20DividendCheckpointFactory.address} - ----------------------------------------------------------------------------- - `); - console.log('\n'); - // -------- END OF POLYMATH NETWORK Configuration -------// - }); + EtherDividendCheckpointFactory: ${EtherDividendCheckpointFactory.address} + ERC20DividendCheckpointFactory: ${ERC20DividendCheckpointFactory.address} + ----------------------------------------------------------------------------- + `); + console.log('\n'); + // -------- END OF POLYMATH NETWORK Configuration -------// }); -}); } From e7caf0d1597adc1343b18836b27814dd0ace416d Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 3 Oct 2018 15:18:13 +0100 Subject: [PATCH 07/28] Go back to in-lined internals --- contracts/libraries/Util.sol | 10 ++-- contracts/libraries/VersionUtils.sol | 10 ++-- migrations/2_deploy_contracts.js | 84 ++++++++++++++-------------- 3 files changed, 52 insertions(+), 52 deletions(-) diff --git a/contracts/libraries/Util.sol b/contracts/libraries/Util.sol index 10df40218..4e60c9c59 100644 --- a/contracts/libraries/Util.sol +++ b/contracts/libraries/Util.sol @@ -9,7 +9,7 @@ library Util { * @notice changes a string to upper case * @param _base string to change */ - function upper(string _base) public pure returns (string) { + function upper(string _base) internal pure returns (string) { bytes memory _baseBytes = bytes(_base); for (uint i = 0; i < _baseBytes.length; i++) { bytes1 b1 = _baseBytes[i]; @@ -26,7 +26,7 @@ library Util { * @param _source String that need to convert into bytes32 */ /// Notice - Maximum length for _source will be 32 chars otherwise returned bytes32 value will have lossy value. - function stringToBytes32(string memory _source) public pure returns (bytes32) { + function stringToBytes32(string memory _source) internal pure returns (bytes32) { return bytesToBytes32(bytes(_source), 0); } @@ -36,7 +36,7 @@ library Util { * @param _offset Offset from which to begin conversion */ /// Notice - Maximum length for _source will be 32 chars otherwise returned bytes32 value will have lossy value. - function bytesToBytes32(bytes _b, uint _offset) public pure returns (bytes32) { + function bytesToBytes32(bytes _b, uint _offset) internal pure returns (bytes32) { bytes32 result; for (uint i = 0; i < _b.length; i++) { @@ -49,7 +49,7 @@ library Util { * @notice Changes the bytes32 into string * @param _source that need to convert into string */ - function bytes32ToString(bytes32 _source) public pure returns (string result) { + function bytes32ToString(bytes32 _source) internal pure returns (string result) { bytes memory bytesString = new bytes(32); uint charCount = 0; for (uint j = 0; j < 32; j++) { @@ -71,7 +71,7 @@ library Util { * @param _data passed data * @return bytes4 sig */ - function getSig(bytes _data) public pure returns (bytes4 sig) { + function getSig(bytes _data) internal pure returns (bytes4 sig) { uint len = _data.length < 4 ? _data.length : 4; for (uint i = 0; i < len; i++) { sig = bytes4(uint(sig) + uint(_data[i]) * (2 ** (8 * (len - 1 - i)))); diff --git a/contracts/libraries/VersionUtils.sol b/contracts/libraries/VersionUtils.sol index a07674647..41689713d 100644 --- a/contracts/libraries/VersionUtils.sol +++ b/contracts/libraries/VersionUtils.sol @@ -12,7 +12,7 @@ library VersionUtils { * @param _new Array holds the latest version of the ST * @return bool */ - function isValidVersion(uint8[] _current, uint8[] _new) public pure returns(bool) { + function isValidVersion(uint8[] _current, uint8[] _new) internal pure returns(bool) { bool[] memory _temp = new bool[](_current.length); uint8 counter = 0; for (uint8 i = 0; i < _current.length; i++) { @@ -51,7 +51,7 @@ library VersionUtils { * @param _version2 Array holds the latest version of the ST * @return bool */ - function compareLowerBound(uint8[] _version1, uint8[] _version2) public pure returns(bool) { + function compareLowerBound(uint8[] _version1, uint8[] _version2) internal pure returns(bool) { require(_version1.length == _version2.length); uint counter = 0; for (uint8 j = 0; j< _version1.length; j++) { @@ -82,7 +82,7 @@ library VersionUtils { * @param _version2 Array holds the latest version of the ST * @return bool */ - function compareUpperBound(uint8[] _version1, uint8[] _version2) public pure returns(bool) { + function compareUpperBound(uint8[] _version1, uint8[] _version2) internal pure returns(bool) { require(_version1.length == _version2.length); uint counter = 0; for (uint8 j = 0; j< _version1.length; j++) { @@ -114,7 +114,7 @@ library VersionUtils { * @param _minor Minor version * @param _patch Patch version */ - function pack(uint8 _major, uint8 _minor, uint8 _patch) public pure returns(uint24) { + function pack(uint8 _major, uint8 _minor, uint8 _patch) internal pure returns(uint24) { return (uint24(_major) << 16) | (uint24(_minor) << 8) | uint24(_patch); } @@ -122,7 +122,7 @@ library VersionUtils { * @notice Use to convert packed data into uint8 array * @param _packedVersion Packed data */ - function unpack(uint24 _packedVersion) public pure returns (uint8[]) { + function unpack(uint24 _packedVersion) internal pure returns (uint8[]) { uint8[] memory _unpackVersion = new uint8[](3); _unpackVersion[0] = uint8(_packedVersion >> 16); _unpackVersion[1] = uint8(_packedVersion >> 8); diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index 2a8804d49..4a78f3ec2 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -128,48 +128,48 @@ module.exports = function (deployer, network, accounts) { }).then((_polymathRegistry) => { polymathRegistry = _polymathRegistry; return polymathRegistry.changeAddress("PolyToken", PolyToken, {from: PolymathAccount}); - }).then(() => { - // Deploy libraries - return deployer.deploy(VersionUtils, {from: PolymathAccount}); - }).then(() => { - return deployer.deploy(Util, {from: PolymathAccount}); - }).then(() => { - // Link libraries - return deployer.link(VersionUtils, ModuleRegistry); - }).then(() => { - return deployer.link(VersionUtils, SecurityTokenRegistry); - }).then(() => { - return deployer.link(VersionUtils, GeneralTransferManagerFactory); - }).then(() => { - return deployer.link(VersionUtils, GeneralPermissionManagerFactory); - }).then(() => { - return deployer.link(VersionUtils, PercentageTransferManagerFactory); - }).then(() => { - return deployer.link(VersionUtils, USDTieredSTOProxyFactory); - }).then(() => { - return deployer.link(VersionUtils, CountTransferManagerFactory); - }).then(() => { - return deployer.link(VersionUtils, EtherDividendCheckpointFactory); - }).then(() => { - return deployer.link(VersionUtils, ERC20DividendCheckpointFactory); - }).then(() => { - return deployer.link(VersionUtils, ManualApprovalTransferManagerFactory); - }).then(() => { - return deployer.link(VersionUtils, CappedSTOFactory); - }).then(() => { - return deployer.link(VersionUtils, USDTieredSTOFactory); - }).then(() => { - return deployer.link(Util, CappedSTOFactory); - }).then(() => { - return deployer.link(Util, USDTieredSTOFactory); - }).then(() => { - return deployer.link(Util, CountTransferManagerFactory); - }).then(() => { - return deployer.link(Util, PercentageTransferManagerFactory); - }).then(() => { - return deployer.link(Util, SecurityTokenRegistry); - }).then(() => { - return deployer.link(Util, STFactory); + // }).then(() => { + // // Deploy libraries + // return deployer.deploy(VersionUtils, {from: PolymathAccount}); + // }).then(() => { + // return deployer.deploy(Util, {from: PolymathAccount}); + // }).then(() => { + // // Link libraries + // return deployer.link(VersionUtils, ModuleRegistry); + // }).then(() => { + // return deployer.link(VersionUtils, SecurityTokenRegistry); + // }).then(() => { + // return deployer.link(VersionUtils, GeneralTransferManagerFactory); + // }).then(() => { + // return deployer.link(VersionUtils, GeneralPermissionManagerFactory); + // }).then(() => { + // return deployer.link(VersionUtils, PercentageTransferManagerFactory); + // }).then(() => { + // return deployer.link(VersionUtils, USDTieredSTOProxyFactory); + // }).then(() => { + // return deployer.link(VersionUtils, CountTransferManagerFactory); + // }).then(() => { + // return deployer.link(VersionUtils, EtherDividendCheckpointFactory); + // }).then(() => { + // return deployer.link(VersionUtils, ERC20DividendCheckpointFactory); + // }).then(() => { + // return deployer.link(VersionUtils, ManualApprovalTransferManagerFactory); + // }).then(() => { + // return deployer.link(VersionUtils, CappedSTOFactory); + // }).then(() => { + // return deployer.link(VersionUtils, USDTieredSTOFactory); + // }).then(() => { + // return deployer.link(Util, CappedSTOFactory); + // }).then(() => { + // return deployer.link(Util, USDTieredSTOFactory); + // }).then(() => { + // return deployer.link(Util, CountTransferManagerFactory); + // }).then(() => { + // return deployer.link(Util, PercentageTransferManagerFactory); + // }).then(() => { + // return deployer.link(Util, SecurityTokenRegistry); + // }).then(() => { + // return deployer.link(Util, STFactory); }).then(() => { // A) Deploy the ModuleRegistry Contract (It contains the list of verified ModuleFactory) return deployer.deploy(ModuleRegistry, {from: PolymathAccount}); From 0a00f95bfd6a384e915d19aa09b9be8ed146b4d2 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 3 Oct 2018 15:21:47 +0100 Subject: [PATCH 08/28] Remove merge cruft --- contracts/SecurityTokenRegistry.sol | 4 ---- 1 file changed, 4 deletions(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index e70c19be0..8f2229b59 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -278,11 +278,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { return true; } -<<<<<<< HEAD function _tickerStatus(string _ticker) internal view returns(bool) { -======= - function _tickerStatus(string _ticker) internal returns(bool) { ->>>>>>> development-1.5.0 return getBool(Encoder.getKey("registeredTickers_status", _ticker)); } From 85a8ba6969c151e4f313bd8640c6f77c522c4349 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 3 Oct 2018 15:23:19 +0100 Subject: [PATCH 09/28] More merge cruft --- contracts/tokens/SecurityToken.sol | 9 --------- 1 file changed, 9 deletions(-) diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 5e14a08c1..d3e840261 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -697,21 +697,12 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return success */ function checkPermission(address _delegate, address _module, bytes32 _perm) public view returns(bool) { -<<<<<<< HEAD if (modules[PERMISSION_KEY].length == 0) { return false; } for (uint8 i = 0; i < modules[PERMISSION_KEY].length; i++) { if (IPermissionManager(modules[PERMISSION_KEY][i]).checkPermission(_delegate, _module, _perm)) { -======= - if (modules[PERMISSIONMANAGER_KEY].length == 0) { - return false; - } - - for (uint8 i = 0; i < modules[PERMISSIONMANAGER_KEY].length; i++) { - if (IPermissionManager(modules[PERMISSIONMANAGER_KEY][i]).checkPermission(_delegate, _module, _perm)) { ->>>>>>> development-1.5.0 return true; } } From f31a00146054a8593e39f0878882e9720ae77523 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 3 Oct 2018 18:23:17 +0100 Subject: [PATCH 10/28] WIP fixes --- contracts/interfaces/ISecurityToken.sol | 16 +- contracts/modules/Burn/TrackedRedemption.sol | 2 +- .../modules/Checkpoint/DividendCheckpoint.sol | 3 +- contracts/tokens/STFactory.sol | 22 +-- contracts/tokens/SecurityToken.sol | 148 ++++++++---------- test/o_security_token.js | 42 +++-- 6 files changed, 109 insertions(+), 124 deletions(-) diff --git a/contracts/interfaces/ISecurityToken.sol b/contracts/interfaces/ISecurityToken.sol index ced158b9c..a9c3b05a8 100644 --- a/contracts/interfaces/ISecurityToken.sol +++ b/contracts/interfaces/ISecurityToken.sol @@ -33,14 +33,14 @@ interface ISecurityToken { * @notice Burn function used to burn the securityToken * @param _value No. of tokens that get burned */ - function burn(uint256 _value) external returns (bool success); + function burn(uint256 _value) external; /** * @notice Burn function used to burn the securityToken on behalf of someone else * @param _from Address for whom to burn tokens * @param _value No. of token that get burned */ - function burnFrom(address _from, uint256 _value) external returns (bool success); + function burnFrom(address _from, uint256 _value) external; event Minted(address indexed _to, uint256 _value); event Burnt(address indexed _burner, uint256 _value); @@ -101,7 +101,7 @@ interface ISecurityToken { * NB - this length may differ from investorCount if the list has not been pruned of zero-balance investors * @return length */ - function getInvestorsLength() external view returns (uint256); + function getInvestors() external view returns (address[]); /** * @notice gets current checkpoint ID @@ -225,7 +225,15 @@ interface ISecurityToken { * @param _value amount of tokens to transfer * @param _data data attached to the transfer by controller to emit in event */ - function forceTransfer(address _from, address _to, uint256 _value, bytes _data) external returns(bool); + function forceTransfer(address _from, address _to, uint256 _value, bytes _data) external; + + /** + * @notice Use by a controller to execute a foced burn + * @param _from address from which to take tokens + * @param _value amount of tokens to transfer + * @param _data data attached to the transfer by controller to emit in event + */ + function forceBurn(address _from, uint256 _value, bytes _data) external; /** * @notice Use by the issuer to permanently disable controller functionality diff --git a/contracts/modules/Burn/TrackedRedemption.sol b/contracts/modules/Burn/TrackedRedemption.sol index f69d8a86a..44a0b1d0e 100644 --- a/contracts/modules/Burn/TrackedRedemption.sol +++ b/contracts/modules/Burn/TrackedRedemption.sol @@ -37,7 +37,7 @@ contract TrackedRedemption is IBurn, Module { * @param _value The number of tokens to redeem */ function redeemTokens(uint256 _value) public { - require(ISecurityToken(securityToken).burnFrom(msg.sender, _value), "Unable to redeem tokens"); + ISecurityToken(securityToken).burnFrom(msg.sender, _value); redeemedTokens[msg.sender] = redeemedTokens[msg.sender].add(_value); emit Redeemed(msg.sender, _value, now); } diff --git a/contracts/modules/Checkpoint/DividendCheckpoint.sol b/contracts/modules/Checkpoint/DividendCheckpoint.sol index fc70a9fde..425de3e90 100644 --- a/contracts/modules/Checkpoint/DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/DividendCheckpoint.sol @@ -131,7 +131,8 @@ contract DividendCheckpoint is ICheckpoint, Module { */ function pushDividendPayment(uint256 _dividendIndex, uint256 _start, uint256 _iterations) public withPerm(DISTRIBUTE) validDividendIndex(_dividendIndex) { Dividend storage dividend = dividends[_dividendIndex]; - uint256 numberInvestors = ISecurityToken(securityToken).getInvestorsLength(); + address[] memory investors = ISecurityToken(securityToken).getInvestors(); + uint256 numberInvestors = investors.length; for (uint256 i = _start; i < Math.min256(numberInvestors, _start.add(_iterations)); i++) { address payee = ISecurityToken(securityToken).investors(i); if ((!dividend.claimed[payee]) && (!dividend.dividendExcluded[payee])) { diff --git a/contracts/tokens/STFactory.sol b/contracts/tokens/STFactory.sol index 6273cc69c..4277a8f29 100644 --- a/contracts/tokens/STFactory.sol +++ b/contracts/tokens/STFactory.sol @@ -10,9 +10,6 @@ contract STFactory is ISTFactory { address public transferManagerFactory; - // Should be set to false when we have more TransferManager options - bool addTransferManager = true; - constructor (address _transferManagerFactory) public { transferManagerFactory = _transferManagerFactory; } @@ -24,20 +21,15 @@ contract STFactory is ISTFactory { function deployToken(string _name, string _symbol, uint8 _decimals, string _tokenDetails, address _issuer, bool _divisible, address _polymathRegistry) external returns (address) { address newSecurityTokenAddress = new SecurityToken( - _name, - _symbol, - _decimals, - _divisible ? 1 : uint256(10)**_decimals, - _tokenDetails, - _polymathRegistry + _name, + _symbol, + _decimals, + _divisible ? 1 : uint256(10)**_decimals, + _tokenDetails, + _polymathRegistry ); - - if (addTransferManager) { - SecurityToken(newSecurityTokenAddress).addModule(transferManagerFactory, "", 0, 0); - } - + SecurityToken(newSecurityTokenAddress).addModule(transferManagerFactory, "", 0, 0); SecurityToken(newSecurityTokenAddress).transferOwnership(_issuer); - return newSecurityTokenAddress; } } diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index d3e840261..7f2ef9f1b 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -34,16 +34,16 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr uint8 patch; } - SemanticVersion public securityTokenVersion; + SemanticVersion securityTokenVersion; // off-chain hash string public tokenDetails; - uint8 public constant PERMISSION_KEY = 1; - uint8 public constant TRANSFER_KEY = 2; - uint8 public constant MINT_KEY = 3; - uint8 public constant CHECKPOINT_KEY = 4; - uint8 public constant BURN_KEY = 5; + uint8 constant PERMISSION_KEY = 1; + uint8 constant TRANSFER_KEY = 2; + uint8 constant MINT_KEY = 3; + uint8 constant CHECKPOINT_KEY = 4; + uint8 constant BURN_KEY = 5; uint256 public granularity; @@ -54,7 +54,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr uint256 public investorCount; // List of token holders - address[] public investors; + address[] investors; // Use to temporarily halt all transactions bool public transfersFrozen; @@ -68,7 +68,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // address whitelisted by issuer as controller address public controller; - event ModuleDataEvent( + /* event ModuleDataEvent( bytes32 name, address module, address moduleFactory, @@ -76,7 +76,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr uint8[] moduleTypes, uint256[] moduleIndexes, uint256 nameIndex - ); + ); */ // Struct for module data struct ModuleData { bytes32 name; @@ -91,7 +91,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr } // Records added modules - module list should be order agnostic! - mapping (uint8 => address[]) public modules; + mapping (uint8 => address[]) modules; // Records information about the module mapping (address => ModuleData) modulesToData; @@ -106,20 +106,20 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr } // Map each investor to a series of checkpoints - mapping (address => Checkpoint[]) public checkpointBalances; + mapping (address => Checkpoint[]) checkpointBalances; // List of checkpoints that relate to total supply - Checkpoint[] public checkpointTotalSupply; + Checkpoint[] checkpointTotalSupply; // Times at which each checkpoint was created - uint256[] public checkpointTimes; + uint256[] checkpointTimes; // List of investors (may not be pruned to remove old investors with current zero balances) - mapping (address => bool) public investorListed; + mapping (address => bool) investorListed; // Emit at the time when module get added event ModuleAdded( - uint8[] indexed _types, + uint8[] _types, bytes32 _name, address _moduleFactory, address _module, @@ -133,13 +133,13 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // Emit when the granularity get changed event GranularityChanged(uint256 _oldGranularity, uint256 _newGranularity); // Emit when Module get removed from the securityToken - event ModuleRemoved(uint8[] indexed _types, address _module, uint256 _timestamp); + event ModuleRemoved(uint8[] _types, address _module, uint256 _timestamp); // Emit when Module get archived from the securityToken - event ModuleArchived(uint8[] indexed _types, address _module, uint256 _timestamp); + event ModuleArchived(uint8[] _types, address _module, uint256 _timestamp); // Emit when Module get unarchived from the securityToken - event ModuleUnarchived(uint8[] indexed _types, address _module, uint256 _timestamp); + event ModuleUnarchived(uint8[] _types, address _module, uint256 _timestamp); // Emit when the budget allocated to a module is changed - event ModuleBudgetChanged(uint8[] indexed _moduleTypes, address _module, uint256 _oldBudget, uint256 _budget); + event ModuleBudgetChanged(uint8[] _moduleTypes, address _module, uint256 _oldBudget, uint256 _budget); // Emit when transfers are frozen or unfrozen event FreezeTransfers(bool _status, uint256 _timestamp); // Emit when new checkpoint created @@ -187,7 +187,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr } modifier isMintingAllowed() { - require(!mintingFrozen, "Minting is frozen"); + require(!mintingFrozen, "Minting frozen"); _; } @@ -200,7 +200,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @notice Revert if called by account which is not a controller */ modifier onlyController() { - require(msg.sender == controller, "Caller not controller"); + require(msg.sender == controller, "Not controller"); require(!controllerDisabled, "Controller disabled"); _; } @@ -234,11 +234,15 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr } /** - * @notice Function used to attach the module in security token - * @param _moduleFactory Contract address of the module factory that needs to be attached - * @param _data Data used for the intialization of the module factory variables - * @param _maxCost Maximum cost of the Module factory - * @param _budget Budget of the Module factory + * @notice Function used to attach a module to the security token + * @dev E.G.: On deployment (through the STR) ST gets a TransferManager module attached to it + * @dev to control restrictions on transfers. + * @dev You are allowed to add a new moduleType if: + * @dev - there is no existing module of that type yet added + * @dev - the last member of the module list is replacable + * @param _moduleFactory is the address of the module factory to be added + * @param _data is data packed into bytes used to further configure the module (See STO usage) + * @param _maxCost max amount of POLY willing to pay to module. (WIP) */ function addModule( address _moduleFactory, @@ -246,35 +250,19 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr uint256 _maxCost, uint256 _budget ) external onlyOwner nonReentrant { - _addModule(_moduleFactory, _data, _maxCost, _budget); - } - - /** - * @notice _addModule handles the attachment (or replacement) of modules for the ST - * @dev E.G.: On deployment (through the STR) ST gets a TransferManager module attached to it - * @dev to control restrictions on transfers. - * @dev You are allowed to add a new moduleType if: - * @dev - there is no existing module of that type yet added - * @dev - the last member of the module list is replacable - * @param _moduleFactory is the address of the module factory to be added - * @param _data is data packed into bytes used to further configure the module (See STO usage) - * @param _maxCost max amount of POLY willing to pay to module. (WIP) - */ - function _addModule(address _moduleFactory, bytes _data, uint256 _maxCost, uint256 _budget) internal { //Check that module exists in registry - will throw otherwise IModuleRegistry(moduleRegistry).useModule(_moduleFactory); IModuleFactory moduleFactory = IModuleFactory(_moduleFactory); uint8[] memory moduleTypes = moduleFactory.getTypes(); - /* require(modules[moduleType].length < MAX_MODULES, "Limit of MAX MODULES is reached"); */ uint256 moduleCost = moduleFactory.getSetupCost(); - require(moduleCost <= _maxCost, "Module cost too high"); + require(moduleCost <= _maxCost, "Cost too high"); //Approve fee for module - require(ERC20(polyToken).approve(_moduleFactory, moduleCost), "Insufficient funds for cost"); + require(ERC20(polyToken).approve(_moduleFactory, moduleCost), "Insufficient funds"); //Creates instance of module from factory address module = moduleFactory.deploy(_data); - require(modulesToData[module].module == address(0), "Module already exists"); + require(modulesToData[module].module == address(0), "Module exists"); //Approve ongoing budget - require(ERC20(polyToken).approve(module, _budget), "Insufficient funds for budget"); + require(ERC20(polyToken).approve(module, _budget), "Insufficient funds"); //Add to SecurityToken module map bytes32 moduleName = moduleFactory.getName(); uint256[] memory moduleIndexes = new uint256[](moduleTypes.length); @@ -283,15 +271,16 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr uint256 j; for (i = 0; i < moduleTypes.length; i++) { for (j = 0; j < i; j++) { - require(moduleTypes[i] != moduleTypes[j], "Bad types"); + require(moduleTypes[i] != moduleTypes[j], "Type mismatch"); } } for (i = 0; i < moduleTypes.length; i++) { moduleIndexes[i] = modules[moduleTypes[i]].length; } - emit ModuleDataEvent(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); - /* modulesToData[module] = ModuleData(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); */ + /* emit ModuleDataEvent(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); */ + modulesToData[module] = ModuleData(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); for (i = 0; i < moduleTypes.length; i++) { + modulesToData[module].moduleType[moduleTypes[i]] = true; modules[moduleTypes[i]].push(module); } names[moduleName].push(module); @@ -304,7 +293,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _module address of module to archive */ function archiveModule(address _module) external onlyOwner { - require(!modulesToData[_module].isArchived, "Module already archived"); + require(!modulesToData[_module].isArchived, "Module archived"); require(modulesToData[_module].module != address(0), "Module missing"); emit ModuleArchived(modulesToData[_module].moduleTypes, _module, now); modulesToData[_module].isArchived = true; @@ -315,7 +304,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _module address of module to unarchive */ function unarchiveModule(address _module) external onlyOwner { - require(modulesToData[_module].isArchived, "Module already unarchived"); + require(modulesToData[_module].isArchived, "Module unarchived"); emit ModuleUnarchived(modulesToData[_module].moduleTypes, _module, now); modulesToData[_module].isArchived = false; } @@ -341,13 +330,14 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _module address of module to unarchive */ function removeModule(address _module) external onlyOwner { - require(modulesToData[_module].isArchived, "Module not archived"); + require(modulesToData[_module].isArchived, "Module archived"); require(modulesToData[_module].module != address(0), "Module missing"); emit ModuleRemoved(modulesToData[_module].moduleTypes, _module, now); // Remove from module type list uint8[] memory moduleTypes = modulesToData[_module].moduleTypes; for (uint256 i = 0; i < moduleTypes.length; i++) { _removeModuleWithIndex(moduleTypes[i], modulesToData[_module].moduleIndexes[i]); + modulesToData[_module].moduleType[moduleTypes[i]] = false; } // Remove from module names list uint256 index = modulesToData[_module].nameIndex; @@ -415,9 +405,9 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr require(modulesToData[_module].module != address(0), "Module missing"); uint256 _currentAllowance = IERC20(polyToken).allowance(address(this), _module); if (_budget < _currentAllowance) { - require(IERC20(polyToken).decreaseApproval(_module, _currentAllowance.sub(_budget)), "Insufficient balance to decreaseApproval"); + require(IERC20(polyToken).decreaseApproval(_module, _currentAllowance.sub(_budget)), "Insufficient balance"); } else { - require(IERC20(polyToken).increaseApproval(_module, _budget.sub(_currentAllowance)), "Insufficient balance to increaseApproval"); + require(IERC20(polyToken).increaseApproval(_module, _budget.sub(_currentAllowance)), "Insufficient balance"); } emit ModuleBudgetChanged(modulesToData[_module].moduleTypes, _module, _currentAllowance, _budget); } @@ -436,7 +426,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _granularity granularity level of the token */ function changeGranularity(uint256 _granularity) external onlyOwner { - require(_granularity != 0, "Granularity can not be 0"); + require(_granularity != 0, "Incorrect granularity"); emit GranularityChanged(granularity, _granularity); granularity = _granularity; } @@ -488,8 +478,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * NB - this length may differ from investorCount if list has not been pruned of zero balance investors * @return length */ - function getInvestorsLength() external view returns(uint256) { - return investors.length; + function getInvestors() external view returns(address[]) { + return investors; } /** @@ -565,7 +555,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return bool success */ function transfer(address _to, uint256 _value) public returns (bool success) { - require(_updateTransfer(msg.sender, _to, _value), "Transfer is not valid"); + require(_updateTransfer(msg.sender, _to, _value), "Transfer not valid"); require(super.transfer(_to, _value)); return true; } @@ -578,7 +568,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return bool success */ function transferFrom(address _from, address _to, uint256 _value) public returns(bool) { - require(_updateTransfer(_from, _to, _value), "Transfer is not valid"); + require(_updateTransfer(_from, _to, _value), "Transfer not valid"); require(super.transferFrom(_from, _to, _value)); return true; } @@ -660,9 +650,9 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return success */ function mint(address _investor, uint256 _value) public onlyModuleOrOwner(MINT_KEY) checkGranularity(_value) isMintingAllowed() returns (bool success) { - require(_investor != address(0), "Investor address should not be 0x"); + require(_investor != address(0), "Investor is 0"); _adjustInvestorCount(address(0), _investor, _value); - require(_verifyTransfer(address(0), _investor, _value, true), "Transfer is not valid"); + require(_verifyTransfer(address(0), _investor, _value, true), "Transfer not valid"); _adjustBalanceCheckpoints(_investor); _adjustTotalSupplyCheckpoints(); totalSupply_ = totalSupply_.add(_value); @@ -710,24 +700,22 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr return false; } - function _burn(address _from, uint256 _value) internal returns (bool) { + function _burn(address _from, uint256 _value) internal { require(_value <= balances[_from], "Value too high"); - require(_updateTransfer(_from, address(0), _value), "Burn is not valid"); + require(_updateTransfer(_from, address(0), _value), "Transfer not valid"); _adjustTotalSupplyCheckpoints(); balances[_from] = balances[_from].sub(_value); totalSupply_ = totalSupply_.sub(_value); emit Burnt(_from, _value); emit Transfer(_from, address(0), _value); - return true; } /** * @notice Burn function used to burn the securityToken * @param _value No. of tokens that get burned */ - function burn(uint256 _value) checkGranularity(_value) onlyModule(BURN_KEY) public returns (bool) { - require(_burn(msg.sender, _value), "Invalid burn"); - return true; + function burn(uint256 _value) checkGranularity(_value) onlyModule(BURN_KEY) public { + _burn(msg.sender, _value); } /** @@ -735,11 +723,10 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _from Address for whom to burn tokens * @param _value No. of tokens that get burned */ - function burnFrom(address _from, uint256 _value) checkGranularity(_value) onlyModule(BURN_KEY) public returns (bool) { + function burnFrom(address _from, uint256 _value) checkGranularity(_value) onlyModule(BURN_KEY) public { require(_value <= allowed[_from][msg.sender], "Value too high"); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); - require(_burn(_from, _value), "Invalid burn"); - return true; + _burn(_from, _value); } /** @@ -850,34 +837,33 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _value amount of tokens to transfer * @param _data data attached to the transfer by controller to emit in event */ - function forceTransfer(address _from, address _to, uint256 _value, bytes _data) public onlyController returns(bool) { + function forceTransfer(address _from, address _to, uint256 _value, bytes _data) public onlyController { require(_to != address(0)); - require(_value <= balances[_from]); - bool verified = _updateTransfer(_from, _to, _value); - balances[_from] = balances[_from].sub(_value); + bool verified = _transfer(_from, _to, _value); balances[_to] = balances[_to].add(_value); - emit ForceTransfer(msg.sender, _from, _to, _value, verified, _data); emit Transfer(_from, _to, _value); - return true; } + function _transfer(address _from, address _to, uint256 _value) internal returns(bool) { + require(_value <= balances[_from]); + bool verified = _updateTransfer(_from, _to, _value); + balances[_from] = balances[_from].sub(_value); + return verified; + } /** * @notice Use by a controller to execute a foced burn * @param _from address from which to take tokens * @param _value amount of tokens to transfer * @param _data data attached to the transfer by controller to emit in event */ - function forceBurn(address _from, uint256 _value, bytes _data) public onlyController returns(bool) { - require(_value <= balances[_from], "Value too high"); - bool verified = _updateTransfer(_from, address(0), _value); + function forceBurn(address _from, uint256 _value, bytes _data) public onlyController { + bool verified = _transfer(_from, address(0), _value); _adjustTotalSupplyCheckpoints(); - balances[_from] = balances[_from].sub(_value); totalSupply_ = totalSupply_.sub(_value); emit ForceBurn(msg.sender, _from, _value, verified, _data); emit Burnt(_from, _value); emit Transfer(_from, address(0), _value); - return true; } /** diff --git a/test/o_security_token.js b/test/o_security_token.js index 1217c6c22..cd096ac72 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -18,7 +18,6 @@ const GeneralTransferManagerFactory = artifacts.require('./GeneralTransferManage const GeneralTransferManager = artifacts.require('./GeneralTransferManager'); const GeneralPermissionManager = artifacts.require('./GeneralPermissionManager'); const PolyTokenFaucet = artifacts.require('./PolyTokenFaucet.sol'); -const TokenBurner = artifacts.require('./MockTokenBurner.sol'); const Web3 = require('web3'); const BigNumber = require('bignumber.js'); @@ -69,7 +68,6 @@ contract('SecurityToken', accounts => { let I_MRProxied; let I_CappedSTO; let I_PolyToken; - let I_TokenBurner; let I_PolymathRegistry; // SecurityToken Details (Launched ST on the behalf of the issuer) @@ -264,12 +262,13 @@ contract('SecurityToken', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), transferManagerKey); + console.log(log.args); + assert.equal(log.args._types[0].toNumber(), transferManagerKey); assert.equal(web3.utils.toUtf8(log.args._name),"GeneralTransferManager"); }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(transferManagerKey, 0); + let moduleData = (await I_SecurityToken.getModulesByType(transferManagerKey))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); assert.notEqual( @@ -480,7 +479,7 @@ contract('SecurityToken', accounts => { const tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); - assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); + assert.equal(tx.logs[3].args._types[0], stoKey, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.toUtf8(tx.logs[3].args._name), "CappedSTO", "CappedSTOFactory module was not added"); I_CappedSTO = CappedSTO.at(tx.logs[3].args._module); }); @@ -515,9 +514,7 @@ contract('SecurityToken', accounts => { assert.equal(moduleData[1], I_CappedSTO.address); assert.equal(moduleData[2], I_CappedSTOFactory.address); assert.equal(moduleData[3], false); - assert.equal(moduleData[4], 3); - assert.equal(moduleData[5], 0); - assert.equal(moduleData[6], 0); + assert.equal(moduleData[4][0], 3); }); it("Should get the modules of the securityToken by index (not added into the security token yet)", async () => { @@ -561,29 +558,29 @@ contract('SecurityToken', accounts => { assert.equal(log.logs[0].args._newDetails, "new token details"); }); - it("Should successfully remove the general transfer manager module from the securityToken -- fails msg.sender should be Owner", async() => { + it("Should fail to remove the module - module not archived", async() => { let errorThrown = false; try { - let tx = await I_SecurityToken.removeModule(I_GeneralTransferManager.address, { from : account_temp }); + let tx = await I_SecurityToken.removeModule(I_GeneralTransferManager.address, { from : token_owner }); } catch (error) { - console.log(`Test Case passed by restricting the unknown account to call removeModule of the securityToken`); + console.log(` tx -> Failed because address doesn't exist`); errorThrown = true; ensureException(error); } assert.ok(errorThrown, message); - }); + }) - it("Should fail to remove the module - module not archived", async() => { + it("Should successfully remove the general transfer manager module from the securityToken -- fails msg.sender should be Owner", async() => { let errorThrown = false; try { - let tx = await I_SecurityToken.removeModule(I_GeneralTransferManager.address, { from : token_owner }); + let tx = await I_SecurityToken.removeModule(I_GeneralTransferManager.address, { from : account_temp }); } catch (error) { - console.log(` tx -> Failed because address doesn't exist`); + console.log(`Test Case passed by restricting the unknown account to call removeModule of the securityToken`); errorThrown = true; ensureException(error); } assert.ok(errorThrown, message); - }) + }); it("Should fail to remove the module - incorrect address", async() => { let errorThrown = false; @@ -601,7 +598,7 @@ contract('SecurityToken', accounts => { let key = await takeSnapshot(); await I_SecurityToken.archiveModule(I_GeneralTransferManager.address, { from : token_owner }); let tx = await I_SecurityToken.removeModule(I_GeneralTransferManager.address, { from : token_owner }); - assert.equal(tx.logs[0].args._type, transferManagerKey); + assert.equal(tx.logs[0].args._types[0], transferManagerKey); assert.equal(tx.logs[0].args._module, I_GeneralTransferManager.address); await revertToSnapshot(key); }); @@ -615,7 +612,7 @@ contract('SecurityToken', accounts => { it("Should successfully archive the general transfer manager module from the securityToken", async() => { let tx = await I_SecurityToken.archiveModule(I_GeneralTransferManager.address, { from : token_owner }); - assert.equal(tx.logs[0].args._type, transferManagerKey); + assert.equal(tx.logs[0].args._types[0], transferManagerKey); assert.equal(tx.logs[0].args._module, I_GeneralTransferManager.address); let moduleData = await I_SecurityToken.getModule.call(I_GeneralTransferManager.address); assert.equal(web3.utils.toAscii(moduleData[0]).replace(/\u0000/g, ''), "GeneralTransferManager"); @@ -634,7 +631,7 @@ contract('SecurityToken', accounts => { it("Should successfully unarchive the general transfer manager module from the securityToken", async() => { let tx = await I_SecurityToken.unarchiveModule(I_GeneralTransferManager.address, { from : token_owner }); - assert.equal(tx.logs[0].args._type, transferManagerKey); + assert.equal(tx.logs[0].args._types[0], transferManagerKey); assert.equal(tx.logs[0].args._module, I_GeneralTransferManager.address); let moduleData = await I_SecurityToken.getModule.call(I_GeneralTransferManager.address); assert.equal(web3.utils.toAscii(moduleData[0]).replace(/\u0000/g, ''), "GeneralTransferManager"); @@ -671,7 +668,7 @@ contract('SecurityToken', accounts => { it("Should change the budget of the module", async() => { let tx = await I_SecurityToken.changeModuleBudget(I_CappedSTO.address, (100 * Math.pow(10, 18)),{ from : token_owner}); - assert.equal(tx.logs[1].args._moduleType, stoKey); + assert.equal(tx.logs[1].args._moduleTypes[0], stoKey); assert.equal(tx.logs[1].args._module, I_CappedSTO.address); assert.equal(tx.logs[1].args._budget.dividedBy(new BigNumber(10).pow(18)).toNumber(), 100); }); @@ -702,13 +699,14 @@ contract('SecurityToken', accounts => { // Jump time await increaseTime(5000); // Fallback transaction + console.log("BEFORE"); await web3.eth.sendTransaction({ from: account_investor1, to: I_CappedSTO.address, gas: 2100000, value: web3.utils.toWei('1', 'ether') }); - + console.log("AFTER"); assert.equal( (await I_CappedSTO.getRaised.call(0)) .dividedBy(new BigNumber(10).pow(18)) @@ -742,7 +740,7 @@ contract('SecurityToken', accounts => { let errorThrown = false; // Add permission to the deletgate (A regesteration process) await I_SecurityToken.addModule(I_GeneralPermissionManagerFactory.address, "", 0, 0, {from: token_owner}); - let moduleData = await I_SecurityToken.modules(permissionManagerKey, 0); + let moduleData = (await I_SecurityToken.getModulesByType(permissionManagerKey))[0]; I_GeneralPermissionManager = GeneralPermissionManager.at(moduleData); try { await I_GeneralPermissionManager.addPermission(account_delegate, delegateDetails, { from: account_temp }); From a37a7762f3394a114603f5e6ee7b33e052deab48 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 3 Oct 2018 21:29:28 +0100 Subject: [PATCH 11/28] Still too big --- contracts/ModuleRegistry.sol | 11 ++++++- .../ProxyFactory/USDTieredSTOProxyFactory.sol | 9 +++--- contracts/tokens/SecurityToken.sol | 30 +++++-------------- test/o_security_token.js | 24 +++++++-------- 4 files changed, 33 insertions(+), 41 deletions(-) diff --git a/contracts/ModuleRegistry.sol b/contracts/ModuleRegistry.sol index 60e5478a4..188745e98 100644 --- a/contracts/ModuleRegistry.sol +++ b/contracts/ModuleRegistry.sol @@ -155,7 +155,16 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { } require(getUint(Encoder.getKey('registry', _moduleFactory)) == 0, "Module factory should not be pre-registered"); IModuleFactory moduleFactory = IModuleFactory(_moduleFactory); - require(moduleFactory.getTypes().length != 0, "Factory must have type"); + //Enforce type uniqueness + uint256 i; + uint256 j; + uint8[] memory moduleTypes = moduleFactory.getTypes(); + for (i = 0; i < moduleTypes.length; i++) { + for (j = 0; j < i; j++) { + require(moduleTypes[i] != moduleTypes[j], "Type mismatch"); + } + } + require(moduleTypes.length != 0, "Factory must have type"); // NB - here we index by the first type of the module. uint8 moduleType = moduleFactory.getTypes()[0]; set(Encoder.getKey('registry', _moduleFactory), uint256(moduleType)); diff --git a/contracts/modules/STO/ProxyFactory/USDTieredSTOProxyFactory.sol b/contracts/modules/STO/ProxyFactory/USDTieredSTOProxyFactory.sol index dc4d6c628..1f241d8cc 100644 --- a/contracts/modules/STO/ProxyFactory/USDTieredSTOProxyFactory.sol +++ b/contracts/modules/STO/ProxyFactory/USDTieredSTOProxyFactory.sol @@ -5,17 +5,15 @@ import "../../../interfaces/IUSDTieredSTOProxy.sol"; contract USDTieredSTOProxyFactory is IUSDTieredSTOProxy { - - constructor() public { } - + /** * @notice deploys the STO. * @param _securityToken Contract address of the securityToken * @param _polyAddress Contract address of the PolyToken. - * @param _factoryAddress Contract address of the factory + * @param _factoryAddress Contract address of the factory * @return address Address of the deployed STO */ function deploySTO(address _securityToken, address _polyAddress, address _factoryAddress) external returns (address) { @@ -31,4 +29,5 @@ contract USDTieredSTOProxyFactory is IUSDTieredSTOProxy { function getInitFunction(address _contractAddress) external returns (bytes4) { return USDTieredSTO(_contractAddress).getInitFunction(); } -} \ No newline at end of file + +} diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 7f2ef9f1b..d9bdfebd5 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -68,15 +68,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // address whitelisted by issuer as controller address public controller; - /* event ModuleDataEvent( - bytes32 name, - address module, - address moduleFactory, - bool isArchived, - uint8[] moduleTypes, - uint256[] moduleIndexes, - uint256 nameIndex - ); */ // Struct for module data struct ModuleData { bytes32 name; @@ -86,7 +77,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr uint8[] moduleTypes; uint256[] moduleIndexes; uint256 nameIndex; - mapping (uint8 => bool) moduleType; mapping (uint8 => uint256) moduleIndex; } @@ -160,9 +150,13 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr function _isModule(address _module, uint8 _type) internal view returns (bool) { require(modulesToData[_module].module == _module, "Address mismatch"); - require(modulesToData[_module].moduleType[_type], "Type mismatch"); require(!modulesToData[_module].isArchived, "Module archived"); - return true; + for (uint256 i = 0; i < modulesToData[_module].moduleTypes.length; i++) { + if (modulesToData[_module].moduleTypes[i] == _type) { + return true; + } + } + return false; } // Require msg.sender to be the specified module type @@ -266,21 +260,13 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr //Add to SecurityToken module map bytes32 moduleName = moduleFactory.getName(); uint256[] memory moduleIndexes = new uint256[](moduleTypes.length); - //Enforce type uniqueness uint256 i; - uint256 j; - for (i = 0; i < moduleTypes.length; i++) { - for (j = 0; j < i; j++) { - require(moduleTypes[i] != moduleTypes[j], "Type mismatch"); - } - } for (i = 0; i < moduleTypes.length; i++) { moduleIndexes[i] = modules[moduleTypes[i]].length; } - /* emit ModuleDataEvent(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); */ modulesToData[module] = ModuleData(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); for (i = 0; i < moduleTypes.length; i++) { - modulesToData[module].moduleType[moduleTypes[i]] = true; + /* modulesToData[module].moduleType[moduleTypes[i]] = true; */ modules[moduleTypes[i]].push(module); } names[moduleName].push(module); @@ -337,7 +323,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr uint8[] memory moduleTypes = modulesToData[_module].moduleTypes; for (uint256 i = 0; i < moduleTypes.length; i++) { _removeModuleWithIndex(moduleTypes[i], modulesToData[_module].moduleIndexes[i]); - modulesToData[_module].moduleType[moduleTypes[i]] = false; + /* modulesToData[_module].moduleType[moduleTypes[i]] = false; */ } // Remove from module names list uint256 index = modulesToData[_module].nameIndex; diff --git a/test/o_security_token.js b/test/o_security_token.js index cd096ac72..68b3d6816 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -1106,15 +1106,14 @@ contract('SecurityToken', accounts => { it("Should check that the list of investors is correct", async ()=> { // Hardcode list of expected accounts based on transfers above - let investorsLength = await I_SecurityToken.getInvestorsLength(); - console.log(JSON.stringify(investorsLength)); + + let investors = await I_SecurityToken.getInvestors(); let expectedAccounts = [account_affiliate1, account_affiliate2, account_investor1, account_temp]; - assert.equal(investorsLength.toNumber(), 4); - console.log("Total Seen Investors: " + investorsLength.toNumber()); - for (let i = 0; i < investorsLength.toNumber(); i++) { - let investor = await I_SecurityToken.investors(i); - assert.equal(investor, expectedAccounts[i]); + for (let i = 0; i < expectedAccounts.length; i++) { + assert.equal(investors[i], expectedAccounts[i]); } + assert.equal(investors.length, 4); + console.log("Total Seen Investors: " + investors.length); }); it("Should fail to set controller status because msg.sender not owner", async() => { let errorThrown = false; @@ -1196,14 +1195,13 @@ contract('SecurityToken', accounts => { it("Should prune investor length", async ()=> { await I_SecurityToken.pruneInvestors(0, 10, {from: token_owner}); // Hardcode list of expected accounts based on transfers above - let investorsLength = (await I_SecurityToken.getInvestorsLength.call()).toNumber(); + + let investors = await I_SecurityToken.getInvestors.call(); let expectedAccounts = [account_affiliate1, account_affiliate2, account_investor1]; - assert.equal(investorsLength, 3); - console.log("Total Seen Investors: " + investorsLength); - for (let i = 0; i < investorsLength; i++) { - let investor = await I_SecurityToken.investors(i); - assert.equal(investor, expectedAccounts[i]); + for (let i = 0; i < expectedAccounts.length; i++) { + assert.equal(investors[i], expectedAccounts[i]); } + assert.equal(investors.length, 3); }); it("Should check the balance of investor at checkpoint", async() => { From 5c5dbd50df23daa42a8a034f2bbc60cedbef202e Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 3 Oct 2018 22:16:55 +0100 Subject: [PATCH 12/28] Working --- contracts/libraries/TokenLib.sol | 152 +++++++++++++++++++++++++++++ contracts/tokens/SecurityToken.sol | 107 +++++--------------- migrations/2_deploy_contracts.js | 17 ++-- 3 files changed, 186 insertions(+), 90 deletions(-) create mode 100644 contracts/libraries/TokenLib.sol diff --git a/contracts/libraries/TokenLib.sol b/contracts/libraries/TokenLib.sol new file mode 100644 index 000000000..76af88d5d --- /dev/null +++ b/contracts/libraries/TokenLib.sol @@ -0,0 +1,152 @@ +pragma solidity ^0.4.24; + +import "../modules/PermissionManager/IPermissionManager.sol"; + +library TokenLib { + + // Struct for module data + struct ModuleData { + bytes32 name; + address module; + address moduleFactory; + bool isArchived; + uint8[] moduleTypes; + uint256[] moduleIndexes; + uint256 nameIndex; + mapping (uint8 => uint256) moduleIndex; + } + + // Structures to maintain checkpoints of balances for governance / dividends + struct Checkpoint { + uint256 checkpointId; + uint256 value; + } + + // Emit when Module get archived from the securityToken + event ModuleArchived(uint8[] _types, address _module, uint256 _timestamp); + // Emit when Module get unarchived from the securityToken + event ModuleUnarchived(uint8[] _types, address _module, uint256 _timestamp); + + /** + * @notice Archives a module attached to the SecurityToken + * @param _moduleData storage data + * @param _module address of module to archive + */ + function archiveModule(ModuleData storage _moduleData, address _module) public { + require(!_moduleData.isArchived, "Module archived"); + require(_moduleData.module != address(0), "Module missing"); + emit ModuleArchived(_moduleData.moduleTypes, _module, now); + _moduleData.isArchived = true; + } + + /** + * @notice Unarchives a module attached to the SecurityToken + * @param _moduleData storage data + * @param _module address of module to unarchive + */ + function unarchiveModule(ModuleData storage _moduleData, address _module) public { + require(_moduleData.isArchived, "Module unarchived"); + emit ModuleUnarchived(_moduleData.moduleTypes, _module, now); + _moduleData.isArchived = false; + } + + /** + * @notice Validate permissions with PermissionManager if it exists, If no Permission return false + * @dev Note that IModule withPerm will allow ST owner all permissions anyway + * @dev this allows individual modules to override this logic if needed (to not allow ST owner all permissions) + * @param _modules storage data + * @param _delegate address of delegate + * @param _module address of PermissionManager module + * @param _perm the permissions + * @return success + */ + function checkPermission(address[] storage _modules, address _delegate, address _module, bytes32 _perm) public returns(bool) { + if (_modules.length == 0) { + return false; + } + + for (uint8 i = 0; i < _modules.length; i++) { + if (IPermissionManager(_modules[i]).checkPermission(_delegate, _module, _perm)) { + return true; + } + } + + return false; + } + + /** + * @notice Queries value at a defined checkpoint + * @param _checkpoints is array of Checkpoint objects + * @param _checkpointId Checkpoint ID to query + * @param _currentValue Current value of checkpoint + * @return uint256 + */ + function getValueAt(Checkpoint[] storage _checkpoints, uint256 _checkpointId, uint256 _currentValue) public returns(uint256) { + //Checkpoint id 0 is when the token is first created - everyone has a zero balance + if (_checkpointId == 0) { + return 0; + } + if (_checkpoints.length == 0) { + return _currentValue; + } + if (_checkpoints[0].checkpointId >= _checkpointId) { + return _checkpoints[0].value; + } + if (_checkpoints[_checkpoints.length - 1].checkpointId < _checkpointId) { + return _currentValue; + } + if (_checkpoints[_checkpoints.length - 1].checkpointId == _checkpointId) { + return _checkpoints[_checkpoints.length - 1].value; + } + uint256 min = 0; + uint256 max = _checkpoints.length - 1; + while (max > min) { + uint256 mid = (max + min) / 2; + if (_checkpoints[mid].checkpointId == _checkpointId) { + max = mid; + break; + } + if (_checkpoints[mid].checkpointId < _checkpointId) { + min = mid + 1; + } else { + max = mid; + } + } + return _checkpoints[max].value; + } + + /** + * @notice store the changes to the checkpoint objects + * @param _checkpoints the affected checkpoint object array + * @param _newValue the new value that needs to be stored + */ + function adjustCheckpoints(TokenLib.Checkpoint[] storage _checkpoints, uint256 _newValue, uint256 _currentCheckpointId) public { + //No checkpoints set yet + if (_currentCheckpointId == 0) { + return; + } + //No previous checkpoint data - add current balance against checkpoint + if (_checkpoints.length == 0) { + _checkpoints.push( + TokenLib.Checkpoint({ + checkpointId: _currentCheckpointId, + value: _newValue + }) + ); + return; + } + //No new checkpoints since last update + if (_checkpoints[_checkpoints.length - 1].checkpointId == _currentCheckpointId) { + return; + } + //New checkpoint, so record balance + _checkpoints.push( + TokenLib.Checkpoint({ + checkpointId: _currentCheckpointId, + value: _newValue + }) + ); + } + + +} diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index d9bdfebd5..d56a40404 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -7,12 +7,12 @@ import "../interfaces/IModuleFactory.sol"; import "../interfaces/IModuleRegistry.sol"; import "../interfaces/IFeatureRegistry.sol"; import "../modules/TransferManager/ITransferManager.sol"; -import "../modules/PermissionManager/IPermissionManager.sol"; import "../RegistryUpdater.sol"; import "../libraries/Util.sol"; import "openzeppelin-solidity/contracts/ReentrancyGuard.sol"; import "openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol"; import "openzeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol"; +import "../libraries/TokenLib.sol"; /** * @title Security Token contract @@ -68,38 +68,20 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // address whitelisted by issuer as controller address public controller; - // Struct for module data - struct ModuleData { - bytes32 name; - address module; - address moduleFactory; - bool isArchived; - uint8[] moduleTypes; - uint256[] moduleIndexes; - uint256 nameIndex; - mapping (uint8 => uint256) moduleIndex; - } - // Records added modules - module list should be order agnostic! mapping (uint8 => address[]) modules; // Records information about the module - mapping (address => ModuleData) modulesToData; + mapping (address => TokenLib.ModuleData) modulesToData; // Records added module names - module list should be order agnostic! mapping (bytes32 => address[]) names; - // Structures to maintain checkpoints of balances for governance / dividends - struct Checkpoint { - uint256 checkpointId; - uint256 value; - } - // Map each investor to a series of checkpoints - mapping (address => Checkpoint[]) checkpointBalances; + mapping (address => TokenLib.Checkpoint[]) checkpointBalances; // List of checkpoints that relate to total supply - Checkpoint[] checkpointTotalSupply; + TokenLib.Checkpoint[] checkpointTotalSupply; // Times at which each checkpoint was created uint256[] checkpointTimes; @@ -122,12 +104,12 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr event UpdateTokenDetails(string _oldDetails, string _newDetails); // Emit when the granularity get changed event GranularityChanged(uint256 _oldGranularity, uint256 _newGranularity); - // Emit when Module get removed from the securityToken - event ModuleRemoved(uint8[] _types, address _module, uint256 _timestamp); // Emit when Module get archived from the securityToken event ModuleArchived(uint8[] _types, address _module, uint256 _timestamp); // Emit when Module get unarchived from the securityToken event ModuleUnarchived(uint8[] _types, address _module, uint256 _timestamp); + // Emit when Module get removed from the securityToken + event ModuleRemoved(uint8[] _types, address _module, uint256 _timestamp); // Emit when the budget allocated to a module is changed event ModuleBudgetChanged(uint8[] _moduleTypes, address _module, uint256 _oldBudget, uint256 _budget); // Emit when transfers are frozen or unfrozen @@ -264,7 +246,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr for (i = 0; i < moduleTypes.length; i++) { moduleIndexes[i] = modules[moduleTypes[i]].length; } - modulesToData[module] = ModuleData(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); + modulesToData[module] = TokenLib.ModuleData(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); for (i = 0; i < moduleTypes.length; i++) { /* modulesToData[module].moduleType[moduleTypes[i]] = true; */ modules[moduleTypes[i]].push(module); @@ -279,10 +261,11 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _module address of module to archive */ function archiveModule(address _module) external onlyOwner { - require(!modulesToData[_module].isArchived, "Module archived"); + TokenLib.archiveModule(modulesToData[_module], _module); + /* require(!modulesToData[_module].isArchived, "Module archived"); require(modulesToData[_module].module != address(0), "Module missing"); emit ModuleArchived(modulesToData[_module].moduleTypes, _module, now); - modulesToData[_module].isArchived = true; + modulesToData[_module].isArchived = true; */ } /** @@ -290,9 +273,10 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _module address of module to unarchive */ function unarchiveModule(address _module) external onlyOwner { - require(modulesToData[_module].isArchived, "Module unarchived"); + TokenLib.unarchiveModule(modulesToData[_module], _module); + /* require(modulesToData[_module].isArchived, "Module unarchived"); emit ModuleUnarchived(modulesToData[_module].moduleTypes, _module, now); - modulesToData[_module].isArchived = false; + modulesToData[_module].isArchived = false; */ } function _removeModuleWithIndex(uint8 _type, uint256 _index) internal { @@ -490,7 +474,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @notice adjust totalsupply at checkpoint after minting or burning tokens */ function _adjustTotalSupplyCheckpoints() internal { - _adjustCheckpoints(checkpointTotalSupply, totalSupply()); + TokenLib.adjustCheckpoints(checkpointTotalSupply, totalSupply(), currentCheckpointId); + /* _adjustCheckpoints(checkpointTotalSupply, totalSupply()); */ } /** @@ -498,7 +483,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _investor address of the token holder affected */ function _adjustBalanceCheckpoints(address _investor) internal { - _adjustCheckpoints(checkpointBalances[_investor], balanceOf(_investor)); + TokenLib.adjustCheckpoints(checkpointBalances[_investor], balanceOf(_investor), currentCheckpointId); + /* _adjustCheckpoints(checkpointBalances[_investor], balanceOf(_investor)); */ } /** @@ -506,7 +492,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _checkpoints the affected checkpoint object array * @param _newValue the new value that needs to be stored */ - function _adjustCheckpoints(Checkpoint[] storage _checkpoints, uint256 _newValue) internal { + /* function _adjustCheckpoints(TokenLib.Checkpoint[] storage _checkpoints, uint256 _newValue) internal { //No checkpoints set yet if (currentCheckpointId == 0) { return; @@ -514,7 +500,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr //No previous checkpoint data - add current balance against checkpoint if (_checkpoints.length == 0) { _checkpoints.push( - Checkpoint({ + TokenLib.Checkpoint({ checkpointId: currentCheckpointId, value: _newValue }) @@ -527,12 +513,12 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr } //New checkpoint, so record balance _checkpoints.push( - Checkpoint({ + TokenLib.Checkpoint({ checkpointId: currentCheckpointId, value: _newValue }) ); - } + } */ /** * @notice Overloaded version of the transfer function @@ -673,7 +659,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return success */ function checkPermission(address _delegate, address _module, bytes32 _perm) public view returns(bool) { - if (modules[PERMISSION_KEY].length == 0) { + return TokenLib.checkPermission(modules[PERMISSION_KEY], _delegate, _module, _perm); + /* if (modules[PERMISSION_KEY].length == 0) { return false; } @@ -683,7 +670,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr } } - return false; + return false; */ } function _burn(address _from, uint256 _value) internal { @@ -741,49 +728,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return uint256 */ function totalSupplyAt(uint256 _checkpointId) external view returns(uint256) { - return _getValueAt(checkpointTotalSupply, _checkpointId, totalSupply()); - } - - /** - * @notice Queries value at a defined checkpoint - * @param checkpoints is array of Checkpoint objects - * @param _checkpointId Checkpoint ID to query - * @param _currentValue Current value of checkpoint - * @return uint256 - */ - function _getValueAt(Checkpoint[] storage checkpoints, uint256 _checkpointId, uint256 _currentValue) internal view returns(uint256) { require(_checkpointId <= currentCheckpointId); - //Checkpoint id 0 is when the token is first created - everyone has a zero balance - if (_checkpointId == 0) { - return 0; - } - if (checkpoints.length == 0) { - return _currentValue; - } - if (checkpoints[0].checkpointId >= _checkpointId) { - return checkpoints[0].value; - } - if (checkpoints[checkpoints.length - 1].checkpointId < _checkpointId) { - return _currentValue; - } - if (checkpoints[checkpoints.length - 1].checkpointId == _checkpointId) { - return checkpoints[checkpoints.length - 1].value; - } - uint256 min = 0; - uint256 max = checkpoints.length - 1; - while (max > min) { - uint256 mid = (max + min) / 2; - if (checkpoints[mid].checkpointId == _checkpointId) { - max = mid; - break; - } - if (checkpoints[mid].checkpointId < _checkpointId) { - min = mid + 1; - } else { - max = mid; - } - } - return checkpoints[max].value; + return TokenLib.getValueAt(checkpointTotalSupply, _checkpointId, totalSupply()); } /** @@ -792,7 +738,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _checkpointId Checkpoint ID to query as of */ function balanceOfAt(address _investor, uint256 _checkpointId) public view returns(uint256) { - return _getValueAt(checkpointBalances[_investor], _checkpointId, balanceOf(_investor)); + require(_checkpointId <= currentCheckpointId); + return TokenLib.getValueAt(checkpointBalances[_investor], _checkpointId, balanceOf(_investor)); } /** diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index 4a78f3ec2..fd2c27bb0 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -17,8 +17,7 @@ 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') -const VersionUtils = artifacts.require('./VersionUtils.sol'); -const Util = artifacts.require('./Util.sol'); +const TokenLib = artifacts.require('./TokenLib.sol'); let BigNumber = require('bignumber.js'); const cappedSTOSetupCost = new BigNumber(20000).times(new BigNumber(10).pow(18)); // 20K POLY fee @@ -128,14 +127,12 @@ module.exports = function (deployer, network, accounts) { }).then((_polymathRegistry) => { polymathRegistry = _polymathRegistry; return polymathRegistry.changeAddress("PolyToken", PolyToken, {from: PolymathAccount}); - // }).then(() => { - // // Deploy libraries - // return deployer.deploy(VersionUtils, {from: PolymathAccount}); - // }).then(() => { - // return deployer.deploy(Util, {from: PolymathAccount}); - // }).then(() => { - // // Link libraries - // return deployer.link(VersionUtils, ModuleRegistry); + }).then(() => { + // Deploy libraries + return deployer.deploy(TokenLib, {from: PolymathAccount}); + }).then(() => { + // Link libraries + return deployer.link(TokenLib, STFactory); // }).then(() => { // return deployer.link(VersionUtils, SecurityTokenRegistry); // }).then(() => { From 80bfbb1808034e879a626d948bee8571e8682928 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 3 Oct 2018 22:18:09 +0100 Subject: [PATCH 13/28] Remove commented lines --- contracts/tokens/SecurityToken.sol | 52 +----------------------------- 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index d56a40404..0ec644503 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -262,10 +262,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr */ function archiveModule(address _module) external onlyOwner { TokenLib.archiveModule(modulesToData[_module], _module); - /* require(!modulesToData[_module].isArchived, "Module archived"); - require(modulesToData[_module].module != address(0), "Module missing"); - emit ModuleArchived(modulesToData[_module].moduleTypes, _module, now); - modulesToData[_module].isArchived = true; */ } /** @@ -274,9 +270,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr */ function unarchiveModule(address _module) external onlyOwner { TokenLib.unarchiveModule(modulesToData[_module], _module); - /* require(modulesToData[_module].isArchived, "Module unarchived"); - emit ModuleUnarchived(modulesToData[_module].moduleTypes, _module, now); - modulesToData[_module].isArchived = false; */ } function _removeModuleWithIndex(uint8 _type, uint256 _index) internal { @@ -487,39 +480,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr /* _adjustCheckpoints(checkpointBalances[_investor], balanceOf(_investor)); */ } - /** - * @notice store the changes to the checkpoint objects - * @param _checkpoints the affected checkpoint object array - * @param _newValue the new value that needs to be stored - */ - /* function _adjustCheckpoints(TokenLib.Checkpoint[] storage _checkpoints, uint256 _newValue) internal { - //No checkpoints set yet - if (currentCheckpointId == 0) { - return; - } - //No previous checkpoint data - add current balance against checkpoint - if (_checkpoints.length == 0) { - _checkpoints.push( - TokenLib.Checkpoint({ - checkpointId: currentCheckpointId, - value: _newValue - }) - ); - return; - } - //No new checkpoints since last update - if (_checkpoints[_checkpoints.length - 1].checkpointId == currentCheckpointId) { - return; - } - //New checkpoint, so record balance - _checkpoints.push( - TokenLib.Checkpoint({ - checkpointId: currentCheckpointId, - value: _newValue - }) - ); - } */ - /** * @notice Overloaded version of the transfer function * @param _to receiver of transfer @@ -660,17 +620,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr */ function checkPermission(address _delegate, address _module, bytes32 _perm) public view returns(bool) { return TokenLib.checkPermission(modules[PERMISSION_KEY], _delegate, _module, _perm); - /* if (modules[PERMISSION_KEY].length == 0) { - return false; - } - - for (uint8 i = 0; i < modules[PERMISSION_KEY].length; i++) { - if (IPermissionManager(modules[PERMISSION_KEY][i]).checkPermission(_delegate, _module, _perm)) { - return true; - } - } - - return false; */ } function _burn(address _from, uint256 _value) internal { @@ -784,6 +733,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr balances[_from] = balances[_from].sub(_value); return verified; } + /** * @notice Use by a controller to execute a foced burn * @param _from address from which to take tokens From 5a7657b94c6a319cff8222175460ac9269075ecb Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 3 Oct 2018 22:29:28 +0100 Subject: [PATCH 14/28] Fix test cases --- contracts/libraries/TokenLib.sol | 4 ++-- test/b_capped_sto.js | 14 +++++++------- test/c_checkpoints.js | 4 ++-- test/d_count_transfer_manager.js | 8 ++++---- test/e_erc20_dividends.js | 8 ++++---- test/f_ether_dividends.js | 8 ++++---- test/g_general_permission_manager.js | 8 ++++---- test/h_general_transfer_manager.js | 8 ++++---- test/i_Issuance.js | 8 ++++---- test/j_manual_approval_transfer_manager.js | 10 +++++----- test/k_module_registry.js | 4 ++-- test/l_percentage_transfer_manager.js | 8 ++++---- test/m_presale_sto.js | 6 +++--- test/n_security_token_registry.js | 4 ++-- test/p_usd_tiered_sto.js | 12 ++++++------ test/q_usd_tiered_sto_sim.js | 6 +++--- test/r_concurrent_STO.js | 10 +++++----- test/s_v130_to_v140_upgrade.js | 6 +++--- test/t_security_token_registry_proxy.js | 2 +- test/v_tracked_redemptions.js | 6 +++--- 20 files changed, 72 insertions(+), 72 deletions(-) diff --git a/contracts/libraries/TokenLib.sol b/contracts/libraries/TokenLib.sol index 76af88d5d..8fa281d26 100644 --- a/contracts/libraries/TokenLib.sol +++ b/contracts/libraries/TokenLib.sol @@ -60,7 +60,7 @@ library TokenLib { * @param _perm the permissions * @return success */ - function checkPermission(address[] storage _modules, address _delegate, address _module, bytes32 _perm) public returns(bool) { + function checkPermission(address[] storage _modules, address _delegate, address _module, bytes32 _perm) public view returns(bool) { if (_modules.length == 0) { return false; } @@ -81,7 +81,7 @@ library TokenLib { * @param _currentValue Current value of checkpoint * @return uint256 */ - function getValueAt(Checkpoint[] storage _checkpoints, uint256 _checkpointId, uint256 _currentValue) public returns(uint256) { + function getValueAt(Checkpoint[] storage _checkpoints, uint256 _checkpointId, uint256 _currentValue) public view returns(uint256) { //Checkpoint id 0 is when the token is first created - everyone has a zero balance if (_checkpointId == 0) { return 0; diff --git a/test/b_capped_sto.js b/test/b_capped_sto.js index a07d6b864..795bfc843 100644 --- a/test/b_capped_sto.js +++ b/test/b_capped_sto.js @@ -269,7 +269,7 @@ contract('CappedSTO', accounts => { const log = await promisifyLogWatch(I_SecurityToken_ETH.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), transferManagerKey); + assert.equal(log.args._types[0].toNumber(), transferManagerKey); assert.equal(web3.utils.hexToString(log.args._name),"GeneralTransferManager"); }); @@ -358,7 +358,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime_ETH1, endTime_ETH1, cap, rate, [E_fundRaiseType], account_fundsReceiver]); const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); - assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); + assert.equal(tx.logs[3].args._types[0], stoKey, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[3].args._name),"CappedSTO","CappedSTOFactory module was not added"); I_CappedSTO_Array_ETH.push(CappedSTO.at(tx.logs[3].args._module)); }); @@ -729,7 +729,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime_ETH2, endTime_ETH2, cap, rate, [E_fundRaiseType], account_fundsReceiver]); const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); - assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); + assert.equal(tx.logs[3].args._types[0], stoKey, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[3].args._name),"CappedSTO","CappedSTOFactory module was not added"); I_CappedSTO_Array_ETH.push(CappedSTO.at(tx.logs[3].args._module)); }); @@ -839,7 +839,7 @@ contract('CappedSTO', accounts => { for (var STOIndex = 2; STOIndex < MAX_MODULES; STOIndex++) { const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); - assert.equal(tx.logs[3].args._type, stoKey, `Wrong module type added at index ${STOIndex}`); + assert.equal(tx.logs[3].args._types[0], stoKey, `Wrong module type added at index ${STOIndex}`); assert.equal(web3.utils.hexToString(tx.logs[3].args._name),"CappedSTO",`Wrong STO module added at index ${STOIndex}`); I_CappedSTO_Array_ETH.push(CappedSTO.at(tx.logs[3].args._module)); } @@ -886,7 +886,7 @@ contract('CappedSTO', accounts => { const log = await promisifyLogWatch(I_SecurityToken_POLY.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), transferManagerKey); + assert.equal(log.args._types[0].toNumber(), transferManagerKey); assert.equal(web3.utils.hexToString(log.args._name),"GeneralTransferManager"); }); @@ -906,7 +906,7 @@ contract('CappedSTO', accounts => { const tx = await I_SecurityToken_POLY.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); - assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); + assert.equal(tx.logs[3].args._types[0], stoKey, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[3].args._name),"CappedSTO","CappedSTOFactory module was not added"); I_CappedSTO_Array_POLY.push(CappedSTO.at(tx.logs[3].args._module)); }); @@ -1264,7 +1264,7 @@ contract('CappedSTO', accounts => { const tx = await I_SecurityToken_POLY.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); - assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); + assert.equal(tx.logs[3].args._types[0], stoKey, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[3].args._name),"CappedSTO","CappedSTOFactory module was not added"); I_CappedSTO_Array_POLY.push(CappedSTO.at(tx.logs[3].args._module)); }); diff --git a/test/c_checkpoints.js b/test/c_checkpoints.js index a9094c6c5..7f6a85960 100644 --- a/test/c_checkpoints.js +++ b/test/c_checkpoints.js @@ -215,7 +215,7 @@ contract('Checkpoints', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), 2); + assert.equal(log.args._types[0].toNumber(), 2); assert.equal( web3.utils.toAscii(log.args._name) .replace(/\u0000/g, ''), @@ -224,7 +224,7 @@ contract('Checkpoints', accounts => { }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(2, 0); + let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); diff --git a/test/d_count_transfer_manager.js b/test/d_count_transfer_manager.js index 0e588a068..c334e0d0d 100644 --- a/test/d_count_transfer_manager.js +++ b/test/d_count_transfer_manager.js @@ -256,7 +256,7 @@ contract('CountTransferManager', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), 2); + assert.equal(log.args._types[0].toNumber(), 2); assert.equal( web3.utils.toAscii(log.args._name) .replace(/\u0000/g, ''), @@ -265,7 +265,7 @@ contract('CountTransferManager', accounts => { }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(2, 0); + let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); @@ -287,7 +287,7 @@ contract('CountTransferManager', accounts => { let snapId = await takeSnapshot(); await I_PolyToken.transfer(I_SecurityToken.address, web3.utils.toWei("500", "ether"), {from: token_owner}); const tx = await I_SecurityToken.addModule(P_CountTransferManagerFactory.address, bytesSTO, web3.utils.toWei("500", "ether"), 0, { from: token_owner }); - assert.equal(tx.logs[3].args._type.toNumber(), transferManagerKey, "CountTransferManagerFactory doesn't get deployed"); + assert.equal(tx.logs[3].args._types[0].toNumber(), transferManagerKey, "CountTransferManagerFactory doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[3].args._name) .replace(/\u0000/g, ''), @@ -300,7 +300,7 @@ contract('CountTransferManager', accounts => { it("Should successfully attach the CountTransferManager with the security token", async () => { const tx = await I_SecurityToken.addModule(I_CountTransferManagerFactory.address, bytesSTO, 0, 0, { from: token_owner }); - assert.equal(tx.logs[2].args._type.toNumber(), transferManagerKey, "CountTransferManager doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0].toNumber(), transferManagerKey, "CountTransferManager doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[2].args._name) .replace(/\u0000/g, ''), diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index b2d34f577..e21073f06 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -249,7 +249,7 @@ contract('ERC20DividendCheckpoint', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), 2); + assert.equal(log.args._types[0].toNumber(), 2); assert.equal( web3.utils.toAscii(log.args._name) .replace(/\u0000/g, ''), @@ -258,7 +258,7 @@ contract('ERC20DividendCheckpoint', accounts => { }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(2, 0); + let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); @@ -280,7 +280,7 @@ contract('ERC20DividendCheckpoint', accounts => { await I_PolyToken.getTokens(web3.utils.toWei("500", "ether"), token_owner); await I_PolyToken.transfer(I_SecurityToken.address, web3.utils.toWei("500", "ether"), {from: token_owner}); const tx = await I_SecurityToken.addModule(P_ERC20DividendCheckpointFactory.address, "", web3.utils.toWei("500", "ether"), 0, { from: token_owner }); - assert.equal(tx.logs[3].args._type.toNumber(), checkpointKey, "ERC20DividendCheckpoint doesn't get deployed"); + assert.equal(tx.logs[3].args._types[0].toNumber(), checkpointKey, "ERC20DividendCheckpoint doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[3].args._name) .replace(/\u0000/g, ''), @@ -293,7 +293,7 @@ contract('ERC20DividendCheckpoint', accounts => { it("Should successfully attach the ERC20DividendCheckpoint with the security token", async () => { const tx = await I_SecurityToken.addModule(I_ERC20DividendCheckpointFactory.address, "", 0, 0, { from: token_owner }); - assert.equal(tx.logs[2].args._type.toNumber(), checkpointKey, "ERC20DividendCheckpoint doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0].toNumber(), checkpointKey, "ERC20DividendCheckpoint doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[2].args._name) .replace(/\u0000/g, ''), diff --git a/test/f_ether_dividends.js b/test/f_ether_dividends.js index c31197c0a..c02698e87 100644 --- a/test/f_ether_dividends.js +++ b/test/f_ether_dividends.js @@ -250,7 +250,7 @@ contract('EtherDividendCheckpoint', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), 2); + assert.equal(log.args._types[0].toNumber(), 2); assert.equal( web3.utils.toAscii(log.args._name) .replace(/\u0000/g, ''), @@ -259,7 +259,7 @@ contract('EtherDividendCheckpoint', accounts => { }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(2, 0); + let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); @@ -281,7 +281,7 @@ contract('EtherDividendCheckpoint', accounts => { let snapId = await takeSnapshot(); await I_PolyToken.transfer(I_SecurityToken.address, web3.utils.toWei("500", "ether"), {from: token_owner}); const tx = await I_SecurityToken.addModule(P_EtherDividendCheckpointFactory.address, "", web3.utils.toWei("500", "ether"), 0, { from: token_owner }); - assert.equal(tx.logs[3].args._type.toNumber(), checkpointKey, "EtherDividendCheckpoint doesn't get deployed"); + assert.equal(tx.logs[3].args._types[0].toNumber(), checkpointKey, "EtherDividendCheckpoint doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[3].args._name) .replace(/\u0000/g, ''), @@ -294,7 +294,7 @@ contract('EtherDividendCheckpoint', accounts => { it("Should successfully attach the EtherDividendCheckpoint with the security token", async () => { const tx = await I_SecurityToken.addModule(I_EtherDividendCheckpointFactory.address, "", 0, 0, { from: token_owner }); - assert.equal(tx.logs[2].args._type.toNumber(), checkpointKey, "EtherDividendCheckpoint doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0].toNumber(), checkpointKey, "EtherDividendCheckpoint doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[2].args._name) .replace(/\u0000/g, ''), diff --git a/test/g_general_permission_manager.js b/test/g_general_permission_manager.js index da5a8a3f1..b59ad25f1 100644 --- a/test/g_general_permission_manager.js +++ b/test/g_general_permission_manager.js @@ -264,7 +264,7 @@ contract('GeneralPermissionManager', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), 2); + assert.equal(log.args._types[0].toNumber(), 2); assert.equal( web3.utils.toAscii(log.args._name) .replace(/\u0000/g, ''), @@ -273,7 +273,7 @@ contract('GeneralPermissionManager', accounts => { }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(2, 0); + let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); @@ -294,7 +294,7 @@ contract('GeneralPermissionManager', accounts => { let snapId = await takeSnapshot(); await I_PolyToken.transfer(I_SecurityToken.address, web3.utils.toWei("500", "ether"), {from: token_owner}); const tx = await I_SecurityToken.addModule(P_GeneralPermissionManagerFactory.address, "0x", web3.utils.toWei("500", "ether"), 0, { from: token_owner }); - assert.equal(tx.logs[3].args._type.toNumber(), delegateManagerKey, "General Permission Manager doesn't get deployed"); + assert.equal(tx.logs[3].args._types[0].toNumber(), delegateManagerKey, "General Permission Manager doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[3].args._name) .replace(/\u0000/g, ''), @@ -307,7 +307,7 @@ contract('GeneralPermissionManager', accounts => { it("Should successfully attach the General permission manager factory with the security token", async () => { const tx = await I_SecurityToken.addModule(I_GeneralPermissionManagerFactory.address, "0x", 0, 0, { from: token_owner }); - assert.equal(tx.logs[2].args._type.toNumber(), delegateManagerKey, "General Permission Manager doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0].toNumber(), delegateManagerKey, "General Permission Manager doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[2].args._name) .replace(/\u0000/g, ''), diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 76b4be249..0c4deb6c8 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -251,7 +251,7 @@ contract('GeneralTransferManager', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), 2); + assert.equal(log.args._types[0].toNumber(), 2); assert.equal( web3.utils.toAscii(log.args._name) .replace(/\u0000/g, ''), @@ -260,7 +260,7 @@ contract('GeneralTransferManager', accounts => { }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(2, 0); + let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); @@ -289,7 +289,7 @@ contract('GeneralTransferManager', accounts => { it("Should successfully attach the STO factory with the security token", async () => { let bytesSTO = encodeModuleCall(STOParameters, [latestTime() + duration.seconds(1000), latestTime() + duration.days(40), cap, someString]); const tx = await I_SecurityToken.addModule(I_DummySTOFactory.address, bytesSTO, 0, 0, { from: token_owner }); - assert.equal(tx.logs[2].args._type.toNumber(), stoKey, "DummySTO doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0].toNumber(), stoKey, "DummySTO doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[2].args._name) .replace(/\u0000/g, ''), @@ -301,7 +301,7 @@ contract('GeneralTransferManager', accounts => { it("Should successfully attach the permission manager factory with the security token", async () => { const tx = await I_SecurityToken.addModule(I_GeneralPermissionManagerFactory.address, 0, 0, 0, { from: token_owner }); - assert.equal(tx.logs[2].args._type.toNumber(), delegateManagerKey, "GeneralPermissionManager doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0].toNumber(), delegateManagerKey, "GeneralPermissionManager doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[2].args._name) .replace(/\u0000/g, ''), diff --git a/test/i_Issuance.js b/test/i_Issuance.js index 4cfe448d3..a9c502252 100644 --- a/test/i_Issuance.js +++ b/test/i_Issuance.js @@ -250,7 +250,7 @@ contract('Issuance', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), transferManagerKey); + assert.equal(log.args._types[0].toNumber(), transferManagerKey); assert.equal( web3.utils.toAscii(log.args._name) .replace(/\u0000/g, ''), @@ -259,7 +259,7 @@ contract('Issuance', accounts => { }); it("POLYMATH: Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(transferManagerKey, 0); + let moduleData = (await I_SecurityToken.getModulesByType(transferManagerKey))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); @@ -287,7 +287,7 @@ contract('Issuance', accounts => { const tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: account_polymath }); - assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); + assert.equal(tx.logs[3].args._types[0], stoKey, "CappedSTO doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[3].args._name) .replace(/\u0000/g, ''), @@ -320,7 +320,7 @@ contract('Issuance', accounts => { it("Should add the delegate with permission", async() => { //First attach a permission manager to the token await I_SecurityToken.addModule(I_GeneralPermissionManagerFactory.address, "", 0, 0, {from: account_polymath}); - let moduleData = await I_SecurityToken.modules(permissionManagerKey, 0); + let moduleData = (await I_SecurityToken.getModulesByType(permissionManagerKey))[0]; I_GeneralPermissionManager = GeneralPermissionManager.at(moduleData); // Add permission to the deletgate (A regesteration process) await I_GeneralPermissionManager.addPermission(account_delegate, delegateDetails, { from: account_polymath}); diff --git a/test/j_manual_approval_transfer_manager.js b/test/j_manual_approval_transfer_manager.js index 4a1a6bd5c..08a69c318 100644 --- a/test/j_manual_approval_transfer_manager.js +++ b/test/j_manual_approval_transfer_manager.js @@ -265,12 +265,12 @@ contract('ManualApprovalTransferManager', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), 2); + assert.equal(log.args._types[0].toNumber(), 2); assert.equal(web3.utils.toUtf8(log.args._name), "GeneralTransferManager"); }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(2, 0); + let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); @@ -349,7 +349,7 @@ contract('ManualApprovalTransferManager', accounts => { let snapId = await takeSnapshot(); await I_PolyToken.transfer(I_SecurityToken.address, web3.utils.toWei("500", "ether"), {from: token_owner}); const tx = await I_SecurityToken.addModule(P_ManualApprovalTransferManagerFactory.address, "0x", web3.utils.toWei("500", "ether"), 0, { from: token_owner }); - assert.equal(tx.logs[3].args._type.toNumber(), transferManagerKey, "Manual Approval Transfer Manager doesn't get deployed"); + assert.equal(tx.logs[3].args._types[0].toNumber(), transferManagerKey, "Manual Approval Transfer Manager doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[3].args._name) .replace(/\u0000/g, ''), @@ -363,7 +363,7 @@ contract('ManualApprovalTransferManager', accounts => { it("Should successfully attach the ManualApprovalTransferManager with the security token", async () => { const tx = await I_SecurityToken.addModule(I_ManualApprovalTransferManagerFactory.address, "", 0, 0, { from: token_owner }); - assert.equal(tx.logs[2].args._type.toNumber(), transferManagerKey, "ManualApprovalTransferManager doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0].toNumber(), transferManagerKey, "ManualApprovalTransferManager doesn't get deployed"); assert.equal(web3.utils.toUtf8(tx.logs[2].args._name), "ManualApprovalTransferManager", "ManualApprovalTransferManager module was not added"); I_ManualApprovalTransferManager = ManualApprovalTransferManager.at(tx.logs[2].args._module); }); @@ -653,7 +653,7 @@ contract('ManualApprovalTransferManager', accounts => { }, [1]); const tx = await I_SecurityToken.addModule(I_CountTransferManagerFactory.address, bytesCountTM, 0, 0, { from: token_owner }); - assert.equal(tx.logs[2].args._type.toNumber(), transferManagerKey, "CountTransferManager doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0].toNumber(), transferManagerKey, "CountTransferManager doesn't get deployed"); let name = web3.utils.toUtf8(tx.logs[2].args._name); assert.equal(name, "CountTransferManager", "CountTransferManager module was not added"); I_CountTransferManager = CountTransferManager.at(tx.logs[2].args._module); diff --git a/test/k_module_registry.js b/test/k_module_registry.js index a7ed18719..ae5bfb434 100644 --- a/test/k_module_registry.js +++ b/test/k_module_registry.js @@ -428,7 +428,7 @@ contract('ModuleRegistry', accounts => { let tx = await I_MRProxied.registerModule(I_CappedSTOFactory2.address, { from: token_owner }); tx = await I_SecurityToken.addModule(I_CappedSTOFactory2.address, bytesSTO, 0, 0, { from: token_owner}); - assert.equal(tx.logs[2].args._type, stoKey, "CappedSTO doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0], stoKey, "CappedSTO doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[2].args._name) .replace(/\u0000/g, ''), @@ -444,7 +444,7 @@ contract('ModuleRegistry', accounts => { await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, {from: account_polymath}); await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, {from: account_polymath}); let tx = await I_SecurityToken.addModule(I_GeneralPermissionManagerFactory.address, "", 0, 0, { from: token_owner }); - assert.equal(tx.logs[2].args._type, permissionManagerKey, "module doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0], permissionManagerKey, "module doesn't get deployed"); }); it("Should failed in adding the TestSTOFactory module because not compatible with the current protocol version --lower", async() => { diff --git a/test/l_percentage_transfer_manager.js b/test/l_percentage_transfer_manager.js index 92e9e3a46..590e961a3 100644 --- a/test/l_percentage_transfer_manager.js +++ b/test/l_percentage_transfer_manager.js @@ -259,7 +259,7 @@ contract('PercentageTransferManager', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), 2); + assert.equal(log.args._types[0].toNumber(), 2); assert.equal( web3.utils.toAscii(log.args._name) .replace(/\u0000/g, ''), @@ -268,7 +268,7 @@ contract('PercentageTransferManager', accounts => { }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(2, 0); + let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); @@ -347,7 +347,7 @@ contract('PercentageTransferManager', accounts => { let snapId = await takeSnapshot(); await I_PolyToken.transfer(I_SecurityToken.address, web3.utils.toWei("500", "ether"), {from: token_owner}); const tx = await I_SecurityToken.addModule(P_PercentageTransferManagerFactory.address, bytesSTO, web3.utils.toWei("500", "ether"), 0, { from: token_owner }); - assert.equal(tx.logs[3].args._type.toNumber(), transferManagerKey, "PercentageTransferManagerFactory doesn't get deployed"); + assert.equal(tx.logs[3].args._types[0].toNumber(), transferManagerKey, "PercentageTransferManagerFactory doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[3].args._name) .replace(/\u0000/g, ''), @@ -360,7 +360,7 @@ contract('PercentageTransferManager', accounts => { it("Should successfully attach the PercentageTransferManager with the security token", async () => { const tx = await I_SecurityToken.addModule(I_PercentageTransferManagerFactory.address, bytesSTO, 0, 0, { from: token_owner }); - assert.equal(tx.logs[2].args._type.toNumber(), transferManagerKey, "PercentageTransferManager doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0].toNumber(), transferManagerKey, "PercentageTransferManager doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[2].args._name) .replace(/\u0000/g, ''), diff --git a/test/m_presale_sto.js b/test/m_presale_sto.js index ad5482b35..2f97f9747 100644 --- a/test/m_presale_sto.js +++ b/test/m_presale_sto.js @@ -239,7 +239,7 @@ contract('PreSaleSTO', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), transferManagerKey); + assert.equal(log.args._types[0].toNumber(), transferManagerKey); assert.equal( web3.utils.toAscii(log.args._name) .replace(/\u0000/g, ''), @@ -248,7 +248,7 @@ contract('PreSaleSTO', accounts => { }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(transferManagerKey, 0); + let moduleData = (await I_SecurityToken.getModulesByType(transferManagerKey))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); @@ -271,7 +271,7 @@ contract('PreSaleSTO', accounts => { const tx = await I_SecurityToken.addModule(I_PreSaleSTOFactory.address, bytesSTO, 0, 0, { from: token_owner }); - assert.equal(tx.logs[2].args._type, stoKey, "PreSaleSTO doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0], stoKey, "PreSaleSTO doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[2].args._name) .replace(/\u0000/g, ''), diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index 69d9623ad..7c47e12a9 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -557,7 +557,7 @@ contract('SecurityTokenRegistry', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTrasnferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), transferManagerKey, `Should be equal to the ${transferManagerKey}`); + assert.equal(log.args._types[0].toNumber(), transferManagerKey, `Should be equal to the ${transferManagerKey}`); assert.equal( web3.utils.toAscii(log.args._name) .replace(/\u0000/g, ''), @@ -620,7 +620,7 @@ contract('SecurityTokenRegistry', accounts => { const log = await promisifyLogWatch(I_SecurityToken002.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), transferManagerKey); + assert.equal(log.args._types[0].toNumber(), transferManagerKey); assert.equal( web3.utils.toAscii(log.args._name) .replace(/\u0000/g, ''), diff --git a/test/p_usd_tiered_sto.js b/test/p_usd_tiered_sto.js index 79270063b..e95f6897c 100644 --- a/test/p_usd_tiered_sto.js +++ b/test/p_usd_tiered_sto.js @@ -363,12 +363,12 @@ contract('USDTieredSTO', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), TMKEY); + assert.equal(log.args._types[0].toNumber(), TMKEY); assert.equal(web3.utils.hexToString(log.args._name),"GeneralTransferManager"); }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(TMKEY, 0); + let moduleData = (await I_SecurityToken.getModulesByType(TMKEY))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); @@ -401,7 +401,7 @@ contract('USDTieredSTO', accounts => { let bytesSTO = web3.eth.abi.encodeFunctionCall(functionSignature, config); let tx = await I_SecurityToken.addModule(I_USDTieredSTOFactory.address, bytesSTO, 0, 0, { from: ISSUER, gasPrice: GAS_PRICE }); console.log(" Gas addModule: ".grey+tx.receipt.gasUsed.toString().grey); - assert.equal(tx.logs[2].args._type, STOKEY, "USDTieredSTO doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0], STOKEY, "USDTieredSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[2].args._name),"USDTieredSTO","USDTieredSTOFactory module was not added"); I_USDTieredSTO_Array.push(USDTieredSTO.at(tx.logs[2].args._module)); @@ -447,7 +447,7 @@ contract('USDTieredSTO', accounts => { let bytesSTO = web3.eth.abi.encodeFunctionCall(functionSignature, config); let tx = await I_SecurityToken.addModule(I_USDTieredSTOFactory.address, bytesSTO, 0, 0, { from: ISSUER, gasPrice: GAS_PRICE }); console.log(" Gas addModule: ".grey+tx.receipt.gasUsed.toString().grey); - assert.equal(tx.logs[2].args._type, STOKEY, "USDTieredSTO doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0], STOKEY, "USDTieredSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[2].args._name),"USDTieredSTO","USDTieredSTOFactory module was not added"); I_USDTieredSTO_Array.push(USDTieredSTO.at(tx.logs[2].args._module)); @@ -493,7 +493,7 @@ contract('USDTieredSTO', accounts => { let bytesSTO = web3.eth.abi.encodeFunctionCall(functionSignature, config); let tx = await I_SecurityToken.addModule(I_USDTieredSTOFactory.address, bytesSTO, 0, 0, { from: ISSUER, gasPrice: GAS_PRICE }); console.log(" Gas addModule: ".grey+tx.receipt.gasUsed.toString().grey); - assert.equal(tx.logs[2].args._type, STOKEY, "USDTieredSTO doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0], STOKEY, "USDTieredSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[2].args._name),"USDTieredSTO","USDTieredSTOFactory module was not added"); I_USDTieredSTO_Array.push(USDTieredSTO.at(tx.logs[2].args._module)); }); @@ -523,7 +523,7 @@ contract('USDTieredSTO', accounts => { let bytesSTO = web3.eth.abi.encodeFunctionCall(functionSignature, config); let tx = await I_SecurityToken.addModule(I_USDTieredSTOFactory.address, bytesSTO, 0, 0, { from: ISSUER, gasPrice: GAS_PRICE }); console.log(" Gas addModule: ".grey+tx.receipt.gasUsed.toString().grey); - assert.equal(tx.logs[2].args._type, STOKEY, "USDTieredSTO doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0], STOKEY, "USDTieredSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[2].args._name),"USDTieredSTO","USDTieredSTOFactory module was not added"); I_USDTieredSTO_Array.push(USDTieredSTO.at(tx.logs[2].args._module)); }); diff --git a/test/q_usd_tiered_sto_sim.js b/test/q_usd_tiered_sto_sim.js index cd00ccb8d..96015926d 100644 --- a/test/q_usd_tiered_sto_sim.js +++ b/test/q_usd_tiered_sto_sim.js @@ -336,12 +336,12 @@ contract('USDTieredSTO Sim', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), TMKEY); + assert.equal(log.args._types[0].toNumber(), TMKEY); assert.equal(web3.utils.hexToString(log.args._name),"GeneralTransferManager"); }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(TMKEY, 0); + let moduleData = (await I_SecurityToken.getModulesByType(TMKEY))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); @@ -379,7 +379,7 @@ contract('USDTieredSTO Sim', accounts => { let bytesSTO = web3.eth.abi.encodeFunctionCall(functionSignature, config); let tx = await I_SecurityToken.addModule(I_USDTieredSTOFactory.address, bytesSTO, 0, 0, { from: ISSUER, gasPrice: GAS_PRICE }); console.log(" Gas addModule: ".grey+tx.receipt.gasUsed.toString().grey); - assert.equal(tx.logs[2].args._type, STOKEY, "USDTieredSTO doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0], STOKEY, "USDTieredSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[2].args._name),"USDTieredSTO","USDTieredSTOFactory module was not added"); I_USDTieredSTO_Array.push(USDTieredSTO.at(tx.logs[2].args._module)); diff --git a/test/r_concurrent_STO.js b/test/r_concurrent_STO.js index f01a36436..569534cad 100644 --- a/test/r_concurrent_STO.js +++ b/test/r_concurrent_STO.js @@ -247,12 +247,12 @@ contract('Concurrent STO', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), transferManagerKey); + assert.equal(log.args._types[0].toNumber(), transferManagerKey); assert.equal(web3.utils.hexToString(log.args._name),"GeneralTransferManager"); }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(transferManagerKey, 0); + let moduleData = (await I_SecurityToken.getModulesByType(transferManagerKey))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); @@ -300,21 +300,21 @@ contract('Concurrent STO', accounts => { case 0: // Capped STO let tx1 = await I_SecurityToken.addModule(I_CappedSTOFactory.address, cappedBytesSig, maxCost, budget, { from: account_issuer }); - assert.equal(tx1.logs[3].args._type, stoKey, `Wrong module type added at index ${STOIndex}`); + assert.equal(tx1.logs[3].args._types[0], stoKey, `Wrong module type added at index ${STOIndex}`); assert.equal(web3.utils.hexToString(tx1.logs[3].args._name),"CappedSTO",`Wrong STO module added at index ${STOIndex}`); I_STO_Array.push(CappedSTO.at(tx1.logs[3].args._module)); break; case 1: // Dummy STO let tx2 = await I_SecurityToken.addModule(I_DummySTOFactory.address, dummyBytesSig, maxCost, budget, { from: account_issuer }); - assert.equal(tx2.logs[3].args._type, stoKey, `Wrong module type added at index ${STOIndex}`); + assert.equal(tx2.logs[3].args._types[0], stoKey, `Wrong module type added at index ${STOIndex}`); assert.equal(web3.utils.hexToString(tx2.logs[3].args._name),"DummySTO",`Wrong STO module added at index ${STOIndex}`); I_STO_Array.push(DummySTO.at(tx2.logs[3].args._module)); break; case 2: // Pre Sale STO let tx3 = await I_SecurityToken.addModule(I_PreSaleSTOFactory.address, presaleBytesSig, maxCost, budget, { from: account_issuer }); - assert.equal(tx3.logs[3].args._type, stoKey, `Wrong module type added at index ${STOIndex}`); + assert.equal(tx3.logs[3].args._types[0], stoKey, `Wrong module type added at index ${STOIndex}`); assert.equal(web3.utils.hexToString(tx3.logs[3].args._name),"PreSaleSTO",`Wrong STO module added at index ${STOIndex}`); I_STO_Array.push(PreSaleSTO.at(tx3.logs[3].args._module)); break; diff --git a/test/s_v130_to_v140_upgrade.js b/test/s_v130_to_v140_upgrade.js index 4db50ca9f..f4dee4bf2 100644 --- a/test/s_v130_to_v140_upgrade.js +++ b/test/s_v130_to_v140_upgrade.js @@ -490,7 +490,7 @@ contract('Upgrade from v1.3.0 to v1.4.0', accounts => { let bytesSTO = web3.eth.abi.encodeFunctionCall(functionSignature, config); let tx = await I_SecurityToken1.addModule(I_USDTieredSTOFactory.address, bytesSTO, 0, 0, { from: ISSUER1 }); - assert.equal(tx.logs[2].args._type, STOKEY, "USDTieredSTO doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0], STOKEY, "USDTieredSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[2].args._name),"USDTieredSTO","USDTieredSTOFactory module was not added"); I_USDTieredSTO = USDTieredSTO.at(tx.logs[2].args._module); }); @@ -517,14 +517,14 @@ contract('Upgrade from v1.3.0 to v1.4.0', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, [fundRaiseType], fundsReceiver]); let tx = await I_SecurityToken2.addModule(I_UpgradedCappedSTOFactory.address, bytesSTO, 0, 0, { from: ISSUER2 }); - assert.equal(tx.logs[2].args._type, STOKEY, "CappedSTO doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0], STOKEY, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[2].args._name),"CappedSTO","CappedSTOFactory module was not added"); }); // Attach ManualApprovalTransferManager module for TOK2 it("Should successfully attach the ManualApprovalTransferManagerFactory with the second token", async () => { const tx = await I_SecurityToken2.addModule(I_ManualApprovalTransferManagerFactory.address, "", 0, 0, { from: ISSUER2 }); - assert.equal(tx.logs[2].args._type.toNumber(), TMKEY, "ManualApprovalTransferManagerFactory doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0].toNumber(), TMKEY, "ManualApprovalTransferManagerFactory doesn't get deployed"); assert.equal(web3.utils.toUtf8(tx.logs[2].args._name), "ManualApprovalTransferManager", "ManualApprovalTransferManagerFactory module was not added"); I_ManualApprovalTransferManagerFactory = ManualApprovalTransferManagerFactory.at(tx.logs[2].args._module); }); diff --git a/test/t_security_token_registry_proxy.js b/test/t_security_token_registry_proxy.js index 2666f7158..7032337f7 100644 --- a/test/t_security_token_registry_proxy.js +++ b/test/t_security_token_registry_proxy.js @@ -196,7 +196,7 @@ contract ("SecurityTokenRegistryProxy", accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), transferManagerKey); + assert.equal(log.args._types[0].toNumber(), transferManagerKey); assert.equal(web3.utils.hexToString(log.args._name),"GeneralTransferManager"); }); }) diff --git a/test/v_tracked_redemptions.js b/test/v_tracked_redemptions.js index 634eb31e2..082c49d28 100644 --- a/test/v_tracked_redemptions.js +++ b/test/v_tracked_redemptions.js @@ -237,7 +237,7 @@ contract('TrackedRedemption', accounts => { const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); // Verify that GeneralTransferManager module get added successfully or not - assert.equal(log.args._type.toNumber(), 2); + assert.equal(log.args._types[0].toNumber(), 2); assert.equal( web3.utils.toAscii(log.args._name) .replace(/\u0000/g, ''), @@ -246,14 +246,14 @@ contract('TrackedRedemption', accounts => { }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken.modules(2, 0); + let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); it("Should successfully attach the TrackedRedemption with the security token", async () => { const tx = await I_SecurityToken.addModule(I_TrackedRedemptionFactory.address, "", 0, 0, { from: token_owner }); - assert.equal(tx.logs[2].args._type.toNumber(), burnKey, "TrackedRedemption doesn't get deployed"); + assert.equal(tx.logs[2].args._types[0].toNumber(), burnKey, "TrackedRedemption doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[2].args._name) .replace(/\u0000/g, ''), From 527869613f1c15c565eb0cfb15c5a51c5df1ee98 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 3 Oct 2018 22:59:20 +0100 Subject: [PATCH 15/28] More fixes --- contracts/tokens/SecurityToken.sol | 8 ++------ test/b_capped_sto.js | 6 +++--- test/d_count_transfer_manager.js | 2 +- test/e_erc20_dividends.js | 2 +- test/f_ether_dividends.js | 2 +- test/g_general_permission_manager.js | 2 +- test/h_general_transfer_manager.js | 4 ++-- test/j_manual_approval_transfer_manager.js | 2 +- test/l_percentage_transfer_manager.js | 2 +- test/m_presale_sto.js | 2 +- test/p_usd_tiered_sto.js | 2 +- test/v_tracked_redemptions.js | 2 +- 12 files changed, 16 insertions(+), 20 deletions(-) diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 0ec644503..e0a0cdb18 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -468,7 +468,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr */ function _adjustTotalSupplyCheckpoints() internal { TokenLib.adjustCheckpoints(checkpointTotalSupply, totalSupply(), currentCheckpointId); - /* _adjustCheckpoints(checkpointTotalSupply, totalSupply()); */ } /** @@ -477,7 +476,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr */ function _adjustBalanceCheckpoints(address _investor) internal { TokenLib.adjustCheckpoints(checkpointBalances[_investor], balanceOf(_investor), currentCheckpointId); - /* _adjustCheckpoints(checkpointBalances[_investor], balanceOf(_investor)); */ } /** @@ -583,9 +581,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr */ function mint(address _investor, uint256 _value) public onlyModuleOrOwner(MINT_KEY) checkGranularity(_value) isMintingAllowed() returns (bool success) { require(_investor != address(0), "Investor is 0"); - _adjustInvestorCount(address(0), _investor, _value); - require(_verifyTransfer(address(0), _investor, _value, true), "Transfer not valid"); - _adjustBalanceCheckpoints(_investor); + require(_updateTransfer(address(0), _investor, _value), "Transfer not valid"); _adjustTotalSupplyCheckpoints(); totalSupply_ = totalSupply_.add(_value); balances[_investor] = balances[_investor].add(_value); @@ -733,7 +729,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr balances[_from] = balances[_from].sub(_value); return verified; } - + /** * @notice Use by a controller to execute a foced burn * @param _from address from which to take tokens diff --git a/test/b_capped_sto.js b/test/b_capped_sto.js index 795bfc843..c753d22db 100644 --- a/test/b_capped_sto.js +++ b/test/b_capped_sto.js @@ -274,7 +274,7 @@ contract('CappedSTO', accounts => { }); it("Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken_ETH.modules(transferManagerKey, 0); + let moduleData = (await I_SecurityToken_ETH.getModulesByType(transferManagerKey))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); @@ -891,7 +891,7 @@ contract('CappedSTO', accounts => { }); it("POLY: Should intialize the auto attached modules", async () => { - let moduleData = await I_SecurityToken_POLY.modules(transferManagerKey, 0); + let moduleData = (await I_SecurityToken_POLY.getModulesByType(transferManagerKey))[0]; I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); @@ -1102,7 +1102,7 @@ contract('CappedSTO', accounts => { describe("Test cases for the CappedSTOFactory", async() => { it("should get the exact details of the factory", async() => { assert.equal((await I_CappedSTOFactory.setupCost.call()).toNumber(), cappedSTOSetupCost); - assert.equal(await I_CappedSTOFactory.getTypes.call(0),3); + assert.equal((await I_CappedSTOFactory.getTypes.call())[0],3); assert.equal(web3.utils.hexToString(await I_CappedSTOFactory.getName.call()), "CappedSTO", "Wrong Module added"); diff --git a/test/d_count_transfer_manager.js b/test/d_count_transfer_manager.js index c334e0d0d..164538f50 100644 --- a/test/d_count_transfer_manager.js +++ b/test/d_count_transfer_manager.js @@ -477,7 +477,7 @@ contract('CountTransferManager', accounts => { describe("Test cases for the factory", async() => { it("should get the exact details of the factory", async() => { assert.equal(await I_CountTransferManagerFactory.setupCost.call(),0); - assert.equal(await I_CountTransferManagerFactory.getTypes.call(0),2); + assert.equal((await I_CountTransferManagerFactory.getTypes.call())[0],2); assert.equal(web3.utils.toAscii(await I_CountTransferManagerFactory.getName.call()) .replace(/\u0000/g, ''), "CountTransferManager", diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index e21073f06..9f8f71984 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -938,7 +938,7 @@ contract('ERC20DividendCheckpoint', accounts => { describe("Test cases for the ERC20DividendCheckpointFactory", async() => { it("should get the exact details of the factory", async() => { assert.equal((await I_ERC20DividendCheckpointFactory.setupCost.call()).toNumber(), 0); - assert.equal(await I_ERC20DividendCheckpointFactory.getTypes.call(0), 4); + assert.equal((await I_ERC20DividendCheckpointFactory.getTypes.call())[0], 4); assert.equal(web3.utils.toAscii(await I_ERC20DividendCheckpointFactory.getName.call()) .replace(/\u0000/g, ''), "ERC20DividendCheckpoint", diff --git a/test/f_ether_dividends.js b/test/f_ether_dividends.js index c02698e87..b65a8f7c1 100644 --- a/test/f_ether_dividends.js +++ b/test/f_ether_dividends.js @@ -958,7 +958,7 @@ contract('EtherDividendCheckpoint', accounts => { describe("Test cases for the EtherDividendCheckpointFactory", async() => { it("should get the exact details of the factory", async() => { assert.equal((await I_EtherDividendCheckpointFactory.setupCost.call()).toNumber(), 0); - assert.equal(await I_EtherDividendCheckpointFactory.getTypes.call(0), 4); + assert.equal((await I_EtherDividendCheckpointFactory.getTypes.call())[0], 4); assert.equal(web3.utils.toAscii(await I_EtherDividendCheckpointFactory.getName.call()) .replace(/\u0000/g, ''), "EtherDividendCheckpoint", diff --git a/test/g_general_permission_manager.js b/test/g_general_permission_manager.js index b59ad25f1..32b501565 100644 --- a/test/g_general_permission_manager.js +++ b/test/g_general_permission_manager.js @@ -398,7 +398,7 @@ contract('GeneralPermissionManager', accounts => { describe("General Permission Manager Factory test cases", async() => { it("should get the exact details of the factory", async() => { assert.equal(await I_GeneralPermissionManagerFactory.setupCost.call(),0); - assert.equal(await I_GeneralPermissionManagerFactory.getTypes.call(0),1); + assert.equal((await I_GeneralPermissionManagerFactory.getTypes.call())[0],1); assert.equal(web3.utils.toAscii(await I_GeneralPermissionManagerFactory.getName.call()) .replace(/\u0000/g, ''), "GeneralPermissionManager", diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 0c4deb6c8..232f7c1d2 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -791,7 +791,7 @@ contract('GeneralTransferManager', accounts => { it("Should get the exact details of the factory", async() => { assert.equal(await I_GeneralTransferManagerFactory.setupCost.call(),0); - assert.equal(await I_GeneralTransferManagerFactory.getTypes.call(0),2); + assert.equal((await I_GeneralTransferManagerFactory.getTypes.call())[0],2); assert.equal(web3.utils.toAscii(await I_GeneralTransferManagerFactory.getName.call()) .replace(/\u0000/g, ''), "GeneralTransferManager", @@ -817,7 +817,7 @@ contract('GeneralTransferManager', accounts => { describe("Dummy STO Factory test cases", async() => { it("should get the exact details of the factory", async() => { assert.equal(await I_DummySTOFactory.setupCost.call(),0); - assert.equal(await I_DummySTOFactory.getTypes.call(0),3); + assert.equal((await I_DummySTOFactory.getTypes.call())[0],3); assert.equal(web3.utils.toAscii(await I_DummySTOFactory.getName.call()) .replace(/\u0000/g, ''), "DummySTO", diff --git a/test/j_manual_approval_transfer_manager.js b/test/j_manual_approval_transfer_manager.js index 08a69c318..cc6471e8a 100644 --- a/test/j_manual_approval_transfer_manager.js +++ b/test/j_manual_approval_transfer_manager.js @@ -691,7 +691,7 @@ contract('ManualApprovalTransferManager', accounts => { it("Should get the exact details of the factory", async() => { assert.equal(await I_ManualApprovalTransferManagerFactory.setupCost.call(),0); - assert.equal(await I_ManualApprovalTransferManagerFactory.getTypes.call(0),2); + assert.equal((await I_ManualApprovalTransferManagerFactory.getTypes.call())[0],2); let name = web3.utils.toUtf8(await I_ManualApprovalTransferManagerFactory.getName.call()); assert.equal(name,"ManualApprovalTransferManager","Wrong Module added"); let desc = await I_ManualApprovalTransferManagerFactory.getDescription.call(); diff --git a/test/l_percentage_transfer_manager.js b/test/l_percentage_transfer_manager.js index 590e961a3..a3af87a97 100644 --- a/test/l_percentage_transfer_manager.js +++ b/test/l_percentage_transfer_manager.js @@ -459,7 +459,7 @@ contract('PercentageTransferManager', accounts => { it("Should get the exact details of the factory", async() => { assert.equal(await I_PercentageTransferManagerFactory.setupCost.call(),0); - assert.equal(await I_PercentageTransferManagerFactory.getTypes.call(0),2); + assert.equal((await I_PercentageTransferManagerFactory.getTypes.call())[0],2); assert.equal(web3.utils.toAscii(await I_PercentageTransferManagerFactory.getName.call()) .replace(/\u0000/g, ''), "PercentageTransferManager", diff --git a/test/m_presale_sto.js b/test/m_presale_sto.js index 2f97f9747..81ed48fd7 100644 --- a/test/m_presale_sto.js +++ b/test/m_presale_sto.js @@ -455,7 +455,7 @@ contract('PreSaleSTO', accounts => { describe("Test cases for the PresaleSTOFactory", async() => { it("should get the exact details of the factory", async() => { assert.equal(await I_PreSaleSTOFactory.setupCost.call(),0); - assert.equal(await I_PreSaleSTOFactory.getTypes.call(0),3); + assert.equal((await I_PreSaleSTOFactory.getTypes.call())[0],3); assert.equal(web3.utils.toAscii(await I_PreSaleSTOFactory.getName.call()) .replace(/\u0000/g, ''), "PreSaleSTO", diff --git a/test/p_usd_tiered_sto.js b/test/p_usd_tiered_sto.js index e95f6897c..20656b0bc 100644 --- a/test/p_usd_tiered_sto.js +++ b/test/p_usd_tiered_sto.js @@ -3493,7 +3493,7 @@ contract('USDTieredSTO', accounts => { describe("Test cases for the USDTieredSTOFactory", async() => { it("should get the exact details of the factory", async() => { assert.equal((await I_USDTieredSTOFactory.setupCost.call()).toNumber(), STOSetupCost); - assert.equal(await I_USDTieredSTOFactory.getTypes.call(0),3); + assert.equal((await I_USDTieredSTOFactory.getTypes.call())[0],3); assert.equal(web3.utils.hexToString(await I_USDTieredSTOFactory.getName.call()), "USDTieredSTO", "Wrong Module added"); diff --git a/test/v_tracked_redemptions.js b/test/v_tracked_redemptions.js index 082c49d28..4330616ea 100644 --- a/test/v_tracked_redemptions.js +++ b/test/v_tracked_redemptions.js @@ -354,7 +354,7 @@ contract('TrackedRedemption', accounts => { describe("Test cases for the TrackedRedemptionFactory", async() => { it("should get the exact details of the factory", async() => { assert.equal((await I_TrackedRedemptionFactory.setupCost.call()).toNumber(), 0); - assert.equal(await I_TrackedRedemptionFactory.getTypes.call(0), 5); + assert.equal((await I_TrackedRedemptionFactory.getTypes.call())[0], 5); assert.equal(web3.utils.toAscii(await I_TrackedRedemptionFactory.getName.call()) .replace(/\u0000/g, ''), "TrackedRedemption", From 3b0f0be4b71d3288b22cabd172fb9ed211672759 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 3 Oct 2018 23:18:40 +0100 Subject: [PATCH 16/28] Remove kludge --- .../modules/TransferManager/GeneralTransferManagerFactory.sol | 3 +-- contracts/tokens/SecurityToken.sol | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol index 8b8dd8790..60e85f8f4 100644 --- a/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol +++ b/contracts/modules/TransferManager/GeneralTransferManagerFactory.sol @@ -41,9 +41,8 @@ contract GeneralTransferManagerFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - uint8[] memory res = new uint8[](2); + uint8[] memory res = new uint8[](1); res[0] = 2; - res[1] = 3; return res; } diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index e0a0cdb18..9f232463b 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -547,8 +547,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr } // If no unarchived modules, return true by default return unarchived ? (isForceValid ? true : (isInvalid ? false : isValid)) : true; - } - return false; + } + return false; } /** From b91c14ef5693b3d871800ebd9290836ea6c6d743 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 3 Oct 2018 23:32:15 +0100 Subject: [PATCH 17/28] Fix some more tests --- contracts/mocks/MockFactory.sol | 3 +-- contracts/modules/Checkpoint/DividendCheckpoint.sol | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/contracts/mocks/MockFactory.sol b/contracts/mocks/MockFactory.sol index ba1f38083..144db6b15 100644 --- a/contracts/mocks/MockFactory.sol +++ b/contracts/mocks/MockFactory.sol @@ -41,8 +41,7 @@ contract MockFactory is ModuleFactory { * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - uint8[] memory res = new uint8[](1); - res[0] = 0; + uint8[] memory res = new uint8[](0); return res; } diff --git a/contracts/modules/Checkpoint/DividendCheckpoint.sol b/contracts/modules/Checkpoint/DividendCheckpoint.sol index 425de3e90..006ec1bde 100644 --- a/contracts/modules/Checkpoint/DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/DividendCheckpoint.sol @@ -134,7 +134,7 @@ contract DividendCheckpoint is ICheckpoint, Module { address[] memory investors = ISecurityToken(securityToken).getInvestors(); uint256 numberInvestors = investors.length; for (uint256 i = _start; i < Math.min256(numberInvestors, _start.add(_iterations)); i++) { - address payee = ISecurityToken(securityToken).investors(i); + address payee = investors[i]; if ((!dividend.claimed[payee]) && (!dividend.dividendExcluded[payee])) { _payDividend(payee, dividend, _dividendIndex); } From b37b6052df8190070c4f318c7d452d24ac5712fc Mon Sep 17 00:00:00 2001 From: satyam Date: Thu, 4 Oct 2018 11:30:07 +0530 Subject: [PATCH 18/28] move investors data and logic into the library --- contracts/libraries/TokenLib.sol | 51 ++++++++++++++++++++++++++++++ contracts/tokens/SecurityToken.sol | 43 +++++++------------------ migrations/2_deploy_contracts.js | 34 -------------------- test/o_security_token.js | 12 +++---- 4 files changed, 68 insertions(+), 72 deletions(-) diff --git a/contracts/libraries/TokenLib.sol b/contracts/libraries/TokenLib.sol index 8fa281d26..24c09f81c 100644 --- a/contracts/libraries/TokenLib.sol +++ b/contracts/libraries/TokenLib.sol @@ -1,9 +1,12 @@ pragma solidity ^0.4.24; import "../modules/PermissionManager/IPermissionManager.sol"; +import "./KindMath.sol"; library TokenLib { + using KindMath for uint256; + // Struct for module data struct ModuleData { bytes32 name; @@ -22,6 +25,15 @@ library TokenLib { uint256 value; } + struct InvestorDataStorage { + // List of investors (may not be pruned to remove old investors with current zero balances) + mapping (address => bool) investorListed; + // List of token holders + address[] investors; + // Total number of non-zero token holders + uint256 investorCount; + } + // Emit when Module get archived from the securityToken event ModuleArchived(uint8[] _types, address _module, uint256 _timestamp); // Emit when Module get unarchived from the securityToken @@ -148,5 +160,44 @@ library TokenLib { ); } + /** + * @notice keeps track of the number of non-zero token holders + * @param _from sender of transfer + * @param _to receiver of transfer + * @param _value value of transfer + */ + function adjustInvestorCount(InvestorDataStorage storage _investors, address _from, address _to, uint256 _value, uint256 _balanceTo, uint256 _balanceFrom) public { + if ((_value == 0) || (_from == _to)) { + return; + } + // Check whether receiver is a new token holder + if ((_balanceTo == 0) && (_to != address(0))) { + _investors.investorCount = (_investors.investorCount).add(1); + } + // Check whether sender is moving all of their tokens + if (_value == _balanceFrom) { + _investors.investorCount = (_investors.investorCount).sub(1); + } + //Also adjust investor list + if (!_investors.investorListed[_to] && (_to != address(0))) { + _investors.investors.push(_to); + _investors.investorListed[_to] = true; + } + + } + + /** + * @notice removes addresses with zero balances from the investors list + * @param _index Index in investor list at which to start removing zero balances + * NB - pruning this list will mean you may not be able to iterate over investors on-chain as of a historical checkpoint + */ + function pruneInvestors(InvestorDataStorage storage _investorData, uint256 _index) public { + _investorData.investorListed[_investorData.investors[_index]] = false; + _investorData.investors[_index] = _investorData.investors[_investorData.investors.length - 1]; + _investorData.investors.length--; + } + + + } diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 9f232463b..27564e0e7 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -27,6 +27,8 @@ import "../libraries/TokenLib.sol"; contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, RegistryUpdater { using SafeMath for uint256; + TokenLib.InvestorDataStorage investorData; + // Use to hold the version struct SemanticVersion { uint8 major; @@ -50,12 +52,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // Value of current checkpoint uint256 public currentCheckpointId; - // Total number of non-zero token holders - uint256 public investorCount; - - // List of token holders - address[] investors; - // Use to temporarily halt all transactions bool public transfersFrozen; @@ -86,9 +82,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // Times at which each checkpoint was created uint256[] checkpointTimes; - // List of investors (may not be pruned to remove old investors with current zero balances) - mapping (address => bool) investorListed; - // Emit at the time when module get added event ModuleAdded( uint8[] _types, @@ -401,23 +394,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _value value of transfer */ function _adjustInvestorCount(address _from, address _to, uint256 _value) internal { - if ((_value == 0) || (_from == _to)) { - return; - } - // Check whether receiver is a new token holder - if ((balanceOf(_to) == 0) && (_to != address(0))) { - investorCount = investorCount.add(1); - } - // Check whether sender is moving all of their tokens - if (_value == balanceOf(_from)) { - investorCount = investorCount.sub(1); - } - //Also adjust investor list - if (!investorListed[_to] && (_to != address(0))) { - investors.push(_to); - investorListed[_to] = true; - } - + TokenLib.adjustInvestorCount(investorData, _from, _to, _value, balanceOf(_to), balanceOf(_from)); } /** @@ -427,11 +404,9 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * NB - pruning this list will mean you may not be able to iterate over investors on-chain as of a historical checkpoint */ function pruneInvestors(uint256 _start, uint256 _iters) external onlyOwner { - for (uint256 i = _start; i < Math.min256(_start.add(_iters), investors.length); i++) { - if ((i < investors.length) && (balanceOf(investors[i]) == 0)) { - investorListed[investors[i]] = false; - investors[i] = investors[investors.length - 1]; - investors.length--; + for (uint256 i = _start; i < Math.min256(_start.add(_iters), investorData.investors.length); i++) { + if ((i < investorData.investors.length) && (balanceOf(investorData.investors[i]) == 0)) { + TokenLib.pruneInvestors(investorData, i); } } } @@ -442,7 +417,11 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return length */ function getInvestors() external view returns(address[]) { - return investors; + return investorData.investors; + } + + function getInvestorCount() external view returns(uint256) { + return investorData.investorCount; } /** diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index fd2c27bb0..7b1feeece 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -133,40 +133,6 @@ module.exports = function (deployer, network, accounts) { }).then(() => { // Link libraries return deployer.link(TokenLib, STFactory); - // }).then(() => { - // return deployer.link(VersionUtils, SecurityTokenRegistry); - // }).then(() => { - // return deployer.link(VersionUtils, GeneralTransferManagerFactory); - // }).then(() => { - // return deployer.link(VersionUtils, GeneralPermissionManagerFactory); - // }).then(() => { - // return deployer.link(VersionUtils, PercentageTransferManagerFactory); - // }).then(() => { - // return deployer.link(VersionUtils, USDTieredSTOProxyFactory); - // }).then(() => { - // return deployer.link(VersionUtils, CountTransferManagerFactory); - // }).then(() => { - // return deployer.link(VersionUtils, EtherDividendCheckpointFactory); - // }).then(() => { - // return deployer.link(VersionUtils, ERC20DividendCheckpointFactory); - // }).then(() => { - // return deployer.link(VersionUtils, ManualApprovalTransferManagerFactory); - // }).then(() => { - // return deployer.link(VersionUtils, CappedSTOFactory); - // }).then(() => { - // return deployer.link(VersionUtils, USDTieredSTOFactory); - // }).then(() => { - // return deployer.link(Util, CappedSTOFactory); - // }).then(() => { - // return deployer.link(Util, USDTieredSTOFactory); - // }).then(() => { - // return deployer.link(Util, CountTransferManagerFactory); - // }).then(() => { - // return deployer.link(Util, PercentageTransferManagerFactory); - // }).then(() => { - // return deployer.link(Util, SecurityTokenRegistry); - // }).then(() => { - // return deployer.link(Util, STFactory); }).then(() => { // A) Deploy the ModuleRegistry Contract (It contains the list of verified ModuleFactory) return deployer.deploy(ModuleRegistry, {from: PolymathAccount}); diff --git a/test/o_security_token.js b/test/o_security_token.js index 68b3d6816..b6abc9b20 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -1154,7 +1154,7 @@ contract('SecurityToken', accounts => { it("Should force burn the tokens - value too high", async ()=> { let errorThrown = false; await I_GeneralTransferManager.changeAllowAllBurnTransfers(true, {from : token_owner}); - let currentInvestorCount = await I_SecurityToken.investorCount(); + let currentInvestorCount = await I_SecurityToken.getInvestorCount.call(); let currentBalance = await I_SecurityToken.balanceOf(account_temp); try { let tx = await I_SecurityToken.forceBurn(account_temp, currentBalance + web3.utils.toWei("500", "ether"), "", { from: account_controller }); @@ -1168,7 +1168,7 @@ contract('SecurityToken', accounts => { it("Should force burn the tokens - wrong caller", async ()=> { let errorThrown = false; await I_GeneralTransferManager.changeAllowAllBurnTransfers(true, {from : token_owner}); - let currentInvestorCount = await I_SecurityToken.investorCount(); + let currentInvestorCount = await I_SecurityToken.getInvestorCount.call(); let currentBalance = await I_SecurityToken.balanceOf(account_temp); try { let tx = await I_SecurityToken.forceBurn(account_temp, currentBalance, "", { from: token_owner }); @@ -1181,13 +1181,13 @@ contract('SecurityToken', accounts => { }); it("Should burn the tokens", async ()=> { - let currentInvestorCount = await I_SecurityToken.investorCount(); + let currentInvestorCount = await I_SecurityToken.getInvestorCount.call(); let currentBalance = await I_SecurityToken.balanceOf(account_temp); // console.log(currentInvestorCount.toString(), currentBalance.toString()); let tx = await I_SecurityToken.forceBurn(account_temp, currentBalance, "", { from: account_controller }); // console.log(tx.logs[0].args._value.toNumber(), currentBalance.toNumber()); assert.equal(tx.logs[0].args._value.toNumber(), currentBalance.toNumber()); - let newInvestorCount = await I_SecurityToken.investorCount(); + let newInvestorCount = await I_SecurityToken.getInvestorCount.call(); // console.log(newInvestorCount.toString()); assert.equal(newInvestorCount.toNumber() + 1, currentInvestorCount.toNumber(), "Investor count drops by one"); }); @@ -1298,13 +1298,13 @@ contract('SecurityToken', accounts => { let sender = account_investor1; let receiver = account_investor2; - let start_investorCount = await I_SecurityToken.investorCount.call(); + let start_investorCount = await I_SecurityToken.getInvestorCount.call(); let start_balInv1 = await I_SecurityToken.balanceOf.call(account_investor1); let start_balInv2 = await I_SecurityToken.balanceOf.call(account_investor2); let tx = await I_SecurityToken.forceTransfer(account_investor1, account_investor2, web3.utils.toWei("10", "ether"), "reason", {from: account_controller}); - let end_investorCount = await I_SecurityToken.investorCount.call(); + let end_investorCount = await I_SecurityToken.getInvestorCount.call(); let end_balInv1 = await I_SecurityToken.balanceOf.call(account_investor1); let end_balInv2 = await I_SecurityToken.balanceOf.call(account_investor2); From 11f6e60f28b4e2f10f21c4c2ebf18c4b5ec4142d Mon Sep 17 00:00:00 2001 From: satyam Date: Thu, 4 Oct 2018 11:33:19 +0530 Subject: [PATCH 19/28] minor naming fix --- contracts/libraries/TokenLib.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/libraries/TokenLib.sol b/contracts/libraries/TokenLib.sol index 24c09f81c..691b71068 100644 --- a/contracts/libraries/TokenLib.sol +++ b/contracts/libraries/TokenLib.sol @@ -166,22 +166,22 @@ library TokenLib { * @param _to receiver of transfer * @param _value value of transfer */ - function adjustInvestorCount(InvestorDataStorage storage _investors, address _from, address _to, uint256 _value, uint256 _balanceTo, uint256 _balanceFrom) public { + function adjustInvestorCount(InvestorDataStorage storage _investorData, address _from, address _to, uint256 _value, uint256 _balanceTo, uint256 _balanceFrom) public { if ((_value == 0) || (_from == _to)) { return; } // Check whether receiver is a new token holder if ((_balanceTo == 0) && (_to != address(0))) { - _investors.investorCount = (_investors.investorCount).add(1); + _investorData.investorCount = (_investorData.investorCount).add(1); } // Check whether sender is moving all of their tokens if (_value == _balanceFrom) { - _investors.investorCount = (_investors.investorCount).sub(1); + _investorData.investorCount = (_investorData.investorCount).sub(1); } //Also adjust investor list - if (!_investors.investorListed[_to] && (_to != address(0))) { - _investors.investors.push(_to); - _investors.investorListed[_to] = true; + if (!_investorData.investorListed[_to] && (_to != address(0))) { + _investorData.investors.push(_to); + _investorData.investorListed[_to] = true; } } From e7a290dfd03f17ae89599b510d1e760c269eb6c0 Mon Sep 17 00:00:00 2001 From: satyam Date: Thu, 4 Oct 2018 12:08:57 +0530 Subject: [PATCH 20/28] cleanup --- contracts/tokens/SecurityToken.sol | 32 ++++++++++++++-------------- migrations/2_deploy_contracts.js | 34 ------------------------------ 2 files changed, 16 insertions(+), 50 deletions(-) diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 9f232463b..f19d392e9 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -272,22 +272,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr TokenLib.unarchiveModule(modulesToData[_module], _module); } - function _removeModuleWithIndex(uint8 _type, uint256 _index) internal { - uint256 length = modules[_type].length; - modules[_type][_index] = modules[_type][length - 1]; - modules[_type].length = length - 1; - - if ((length - 1) != _index) { - //Need to find index of _type in moduleTypes of module we are moving - uint8[] memory newTypes = modulesToData[modules[_type][_index]].moduleTypes; - for (uint256 i = 0; i < newTypes.length; i++) { - if (newTypes[i] == _type) { - modulesToData[modules[_type][_index]].moduleIndexes[i] = _index; - } - } - } - } - /** * @notice Removes a module attached to the SecurityToken * @param _module address of module to unarchive @@ -315,6 +299,22 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr delete modulesToData[_module]; } + function _removeModuleWithIndex(uint8 _type, uint256 _index) internal { + uint256 length = modules[_type].length; + modules[_type][_index] = modules[_type][length - 1]; + modules[_type].length = length - 1; + + if ((length - 1) != _index) { + //Need to find index of _type in moduleTypes of module we are moving + uint8[] memory newTypes = modulesToData[modules[_type][_index]].moduleTypes; + for (uint256 i = 0; i < newTypes.length; i++) { + if (newTypes[i] == _type) { + modulesToData[modules[_type][_index]].moduleIndexes[i] = _index; + } + } + } + } + /** * @notice Returns module list for a module type * @param _module address of the module diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index fd2c27bb0..7b1feeece 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -133,40 +133,6 @@ module.exports = function (deployer, network, accounts) { }).then(() => { // Link libraries return deployer.link(TokenLib, STFactory); - // }).then(() => { - // return deployer.link(VersionUtils, SecurityTokenRegistry); - // }).then(() => { - // return deployer.link(VersionUtils, GeneralTransferManagerFactory); - // }).then(() => { - // return deployer.link(VersionUtils, GeneralPermissionManagerFactory); - // }).then(() => { - // return deployer.link(VersionUtils, PercentageTransferManagerFactory); - // }).then(() => { - // return deployer.link(VersionUtils, USDTieredSTOProxyFactory); - // }).then(() => { - // return deployer.link(VersionUtils, CountTransferManagerFactory); - // }).then(() => { - // return deployer.link(VersionUtils, EtherDividendCheckpointFactory); - // }).then(() => { - // return deployer.link(VersionUtils, ERC20DividendCheckpointFactory); - // }).then(() => { - // return deployer.link(VersionUtils, ManualApprovalTransferManagerFactory); - // }).then(() => { - // return deployer.link(VersionUtils, CappedSTOFactory); - // }).then(() => { - // return deployer.link(VersionUtils, USDTieredSTOFactory); - // }).then(() => { - // return deployer.link(Util, CappedSTOFactory); - // }).then(() => { - // return deployer.link(Util, USDTieredSTOFactory); - // }).then(() => { - // return deployer.link(Util, CountTransferManagerFactory); - // }).then(() => { - // return deployer.link(Util, PercentageTransferManagerFactory); - // }).then(() => { - // return deployer.link(Util, SecurityTokenRegistry); - // }).then(() => { - // return deployer.link(Util, STFactory); }).then(() => { // A) Deploy the ModuleRegistry Contract (It contains the list of verified ModuleFactory) return deployer.deploy(ModuleRegistry, {from: PolymathAccount}); From 2b50c164d39ef27546a15a712d418e0d2f7861be Mon Sep 17 00:00:00 2001 From: satyam Date: Thu, 4 Oct 2018 12:33:37 +0530 Subject: [PATCH 21/28] add some improvements --- contracts/interfaces/ISecurityToken.sol | 5 +++++ contracts/libraries/TokenLib.sol | 6 +++++- contracts/tokens/SecurityToken.sol | 3 +++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/contracts/interfaces/ISecurityToken.sol b/contracts/interfaces/ISecurityToken.sol index a9c3b05a8..4cf950308 100644 --- a/contracts/interfaces/ISecurityToken.sol +++ b/contracts/interfaces/ISecurityToken.sol @@ -245,4 +245,9 @@ interface ISecurityToken { * @notice Use to get the version of the securityToken */ function getVersion() external view returns(uint8[]); + + /** + * @notice gets the investor count + */ + function getInvestorCount() external view returns(uint256) } diff --git a/contracts/libraries/TokenLib.sol b/contracts/libraries/TokenLib.sol index 691b71068..7aaa2e7f8 100644 --- a/contracts/libraries/TokenLib.sol +++ b/contracts/libraries/TokenLib.sol @@ -162,9 +162,12 @@ library TokenLib { /** * @notice keeps track of the number of non-zero token holders + * @param _investorData Date releated to investor metrics * @param _from sender of transfer * @param _to receiver of transfer * @param _value value of transfer + * @param _balanceTo balance of the _to address + * @param _balanceFrom balance of the _from address */ function adjustInvestorCount(InvestorDataStorage storage _investorData, address _from, address _to, uint256 _value, uint256 _balanceTo, uint256 _balanceFrom) public { if ((_value == 0) || (_from == _to)) { @@ -188,7 +191,8 @@ library TokenLib { /** * @notice removes addresses with zero balances from the investors list - * @param _index Index in investor list at which to start removing zero balances + * @param _investorData Date releated to investor metrics + * @param _index Index in investor list * NB - pruning this list will mean you may not be able to iterate over investors on-chain as of a historical checkpoint */ function pruneInvestors(InvestorDataStorage storage _investorData, uint256 _index) public { diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 895075941..65256a914 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -420,6 +420,9 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr return investorData.investors; } + /** + * @notice gets the investor count + */ function getInvestorCount() external view returns(uint256) { return investorData.investorCount; } From d5e0a7f03fd094d1cc42169da3182b3f406d4cf2 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Thu, 4 Oct 2018 13:03:16 +0530 Subject: [PATCH 22/28] added a missing semi-colon --- contracts/interfaces/ISecurityToken.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/interfaces/ISecurityToken.sol b/contracts/interfaces/ISecurityToken.sol index 4cf950308..09ffd2bb9 100644 --- a/contracts/interfaces/ISecurityToken.sol +++ b/contracts/interfaces/ISecurityToken.sol @@ -249,5 +249,5 @@ interface ISecurityToken { /** * @notice gets the investor count */ - function getInvestorCount() external view returns(uint256) + function getInvestorCount() external view returns(uint256); } From f4869dd6d47c0816181401530cf677f6deef9281 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Thu, 4 Oct 2018 11:48:33 +0100 Subject: [PATCH 23/28] Fixes based on comments --- contracts/ModuleRegistry.sol | 2 +- contracts/libraries/TokenLib.sol | 14 +--------- .../modules/Checkpoint/DividendCheckpoint.sol | 4 +-- .../modules/Scheduled/CheckpointScheduler.sol | 0 contracts/tokens/SecurityToken.sol | 26 +++++++------------ 5 files changed, 13 insertions(+), 33 deletions(-) create mode 100644 contracts/modules/Scheduled/CheckpointScheduler.sol diff --git a/contracts/ModuleRegistry.sol b/contracts/ModuleRegistry.sol index 188745e98..c1269c331 100644 --- a/contracts/ModuleRegistry.sol +++ b/contracts/ModuleRegistry.sol @@ -159,7 +159,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { uint256 i; uint256 j; uint8[] memory moduleTypes = moduleFactory.getTypes(); - for (i = 0; i < moduleTypes.length; i++) { + for (i = 1; i < moduleTypes.length; i++) { for (j = 0; j < i; j++) { require(moduleTypes[i] != moduleTypes[j], "Type mismatch"); } diff --git a/contracts/libraries/TokenLib.sol b/contracts/libraries/TokenLib.sol index 8fa281d26..d09c17862 100644 --- a/contracts/libraries/TokenLib.sol +++ b/contracts/libraries/TokenLib.sol @@ -13,7 +13,6 @@ library TokenLib { uint8[] moduleTypes; uint256[] moduleIndexes; uint256 nameIndex; - mapping (uint8 => uint256) moduleIndex; } // Structures to maintain checkpoints of balances for governance / dividends @@ -125,18 +124,8 @@ library TokenLib { if (_currentCheckpointId == 0) { return; } - //No previous checkpoint data - add current balance against checkpoint - if (_checkpoints.length == 0) { - _checkpoints.push( - TokenLib.Checkpoint({ - checkpointId: _currentCheckpointId, - value: _newValue - }) - ); - return; - } //No new checkpoints since last update - if (_checkpoints[_checkpoints.length - 1].checkpointId == _currentCheckpointId) { + if ((_checkpoints.length > 0) && (_checkpoints[_checkpoints.length - 1].checkpointId == _currentCheckpointId)) { return; } //New checkpoint, so record balance @@ -148,5 +137,4 @@ library TokenLib { ); } - } diff --git a/contracts/modules/Checkpoint/DividendCheckpoint.sol b/contracts/modules/Checkpoint/DividendCheckpoint.sol index 006ec1bde..1385637bc 100644 --- a/contracts/modules/Checkpoint/DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/DividendCheckpoint.sol @@ -132,8 +132,8 @@ contract DividendCheckpoint is ICheckpoint, Module { function pushDividendPayment(uint256 _dividendIndex, uint256 _start, uint256 _iterations) public withPerm(DISTRIBUTE) validDividendIndex(_dividendIndex) { Dividend storage dividend = dividends[_dividendIndex]; address[] memory investors = ISecurityToken(securityToken).getInvestors(); - uint256 numberInvestors = investors.length; - for (uint256 i = _start; i < Math.min256(numberInvestors, _start.add(_iterations)); i++) { + uint256 numberInvestors = Math.min256(investors.length, _start.add(_iterations)); + for (uint256 i = _start; i < numberInvestors; i++) { address payee = investors[i]; if ((!dividend.claimed[payee]) && (!dividend.dividendExcluded[payee])) { _payDividend(payee, dividend, _dividendIndex); diff --git a/contracts/modules/Scheduled/CheckpointScheduler.sol b/contracts/modules/Scheduled/CheckpointScheduler.sol new file mode 100644 index 000000000..e69de29bb diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index f19d392e9..7d466d1e5 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -618,14 +618,15 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr return TokenLib.checkPermission(modules[PERMISSION_KEY], _delegate, _module, _perm); } - function _burn(address _from, uint256 _value) internal { + function _burn(address _from, uint256 _value) internal returns(bool) { require(_value <= balances[_from], "Value too high"); - require(_updateTransfer(_from, address(0), _value), "Transfer not valid"); + bool verified = _updateTransfer(_from, address(0), _value); _adjustTotalSupplyCheckpoints(); balances[_from] = balances[_from].sub(_value); totalSupply_ = totalSupply_.sub(_value); emit Burnt(_from, _value); emit Transfer(_from, address(0), _value); + return verified; } /** @@ -633,7 +634,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _value No. of tokens that get burned */ function burn(uint256 _value) checkGranularity(_value) onlyModule(BURN_KEY) public { - _burn(msg.sender, _value); + require(_burn(msg.sender, _value), "Burn not valid"); } /** @@ -644,7 +645,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr function burnFrom(address _from, uint256 _value) checkGranularity(_value) onlyModule(BURN_KEY) public { require(_value <= allowed[_from][msg.sender], "Value too high"); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); - _burn(_from, _value); + require(_burn(_from, _value), "Burn not valid"); } /** @@ -717,17 +718,12 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr */ function forceTransfer(address _from, address _to, uint256 _value, bytes _data) public onlyController { require(_to != address(0)); - bool verified = _transfer(_from, _to, _value); - balances[_to] = balances[_to].add(_value); - emit ForceTransfer(msg.sender, _from, _to, _value, verified, _data); - emit Transfer(_from, _to, _value); - } - - function _transfer(address _from, address _to, uint256 _value) internal returns(bool) { require(_value <= balances[_from]); bool verified = _updateTransfer(_from, _to, _value); balances[_from] = balances[_from].sub(_value); - return verified; + balances[_to] = balances[_to].add(_value); + emit ForceTransfer(msg.sender, _from, _to, _value, verified, _data); + emit Transfer(_from, _to, _value); } /** @@ -737,12 +733,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _data data attached to the transfer by controller to emit in event */ function forceBurn(address _from, uint256 _value, bytes _data) public onlyController { - bool verified = _transfer(_from, address(0), _value); - _adjustTotalSupplyCheckpoints(); - totalSupply_ = totalSupply_.sub(_value); + bool verified = _burn(_from, _value); emit ForceBurn(msg.sender, _from, _value, verified, _data); - emit Burnt(_from, _value); - emit Transfer(_from, address(0), _value); } /** From a810f915c8d7879a6539f20f6f3a027c751f6096 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Thu, 4 Oct 2018 11:49:12 +0100 Subject: [PATCH 24/28] Remove empty module --- contracts/modules/Scheduled/CheckpointScheduler.sol | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 contracts/modules/Scheduled/CheckpointScheduler.sol diff --git a/contracts/modules/Scheduled/CheckpointScheduler.sol b/contracts/modules/Scheduled/CheckpointScheduler.sol deleted file mode 100644 index e69de29bb..000000000 From 2952dc42024f8d21aaf467f7707d0a43629df02d Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Thu, 4 Oct 2018 12:06:40 +0100 Subject: [PATCH 25/28] Add forceBurn to fuzz testing for checkpoints --- test/c_checkpoints.js | 54 +++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/test/c_checkpoints.js b/test/c_checkpoints.js index 7f6a85960..d094a2dfc 100644 --- a/test/c_checkpoints.js +++ b/test/c_checkpoints.js @@ -223,9 +223,13 @@ contract('Checkpoints', accounts => { ); }); + it("Should set controller to token owner", async () => { + await I_SecurityToken.setController(token_owner, {from: token_owner}); + }); + it("Should intialize the auto attached modules", async () => { - let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; - I_GeneralTransferManager = GeneralTransferManager.at(moduleData); + let moduleData = (await I_SecurityToken.getModulesByType(2))[0]; + I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); }); @@ -353,19 +357,39 @@ contract('Checkpoints', accounts => { await I_SecurityToken.transfer(receiver, amount, { from: sender }); } if (Math.random() > 0.5) { - let n = BigNumber(Math.random().toFixed(10)).mul(10**17).toFixed(0); - let p = Math.random() * 3; - let r = Math.random() * 3; - let minter; - if (r < 1) { - minter = account_investor1; - } else if (r < 2) { - minter = account_investor2; - } else { - minter = account_investor3; - } - console.log("Minting: " + n.toString() + " to: " + minter); - await I_SecurityToken.mint(minter, n, { from: token_owner }); + let n = BigNumber(Math.random().toFixed(10)).mul(10**17).toFixed(0); + let p = Math.random() * 3; + let r = Math.random() * 3; + let minter; + if (r < 1) { + minter = account_investor1; + } else if (r < 2) { + minter = account_investor2; + } else { + minter = account_investor3; + } + console.log("Minting: " + n.toString() + " to: " + minter); + await I_SecurityToken.mint(minter, n, { from: token_owner }); + } + if (Math.random() > 0.5) { + let n = BigNumber(Math.random().toFixed(10)).mul(10**17); + let p = Math.random() * 3; + let r = Math.random() * 3; + let burner; + if (r < 1) { + burner = account_investor1; + } else if (r < 2) { + burner = account_investor2; + } else { + burner = account_investor3; + } + let burnerBalance = BigNumber(await I_SecurityToken.balanceOf(burner)); + if (n.gt(burnerBalance.div(2))) { + n = burnerBalance.div(2); + } + n = n.toFixed(0); + console.log("Burning: " + n.toString() + " from: " + burner); + await I_SecurityToken.forceBurn(burner, n, "", { from: token_owner }); } console.log("Checking Interim..."); for (let k = 0; k < cps.length; k++) { From 7e2859be63aac7dfeefe235baed97677a37281a9 Mon Sep 17 00:00:00 2001 From: satyam Date: Thu, 4 Oct 2018 17:24:06 +0530 Subject: [PATCH 26/28] minor fix --- contracts/modules/TransferManager/CountTransferManager.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/modules/TransferManager/CountTransferManager.sol b/contracts/modules/TransferManager/CountTransferManager.sol index 274dae2d8..565a03033 100644 --- a/contracts/modules/TransferManager/CountTransferManager.sol +++ b/contracts/modules/TransferManager/CountTransferManager.sol @@ -28,7 +28,7 @@ contract CountTransferManager is ITransferManager { /// @notice Used to verify the transfer transaction according to the rule implemented in the trnasfer managers function verifyTransfer(address /* _from */, address _to, uint256 /* _amount */, bool /* _isTransfer */) public returns(Result) { if (!paused) { - if (maxHolderCount < ISecurityToken(securityToken).investorCount()) { + if (maxHolderCount < ISecurityToken(securityToken).getInvestorCount()) { // Allow transfers to existing maxHolders if (ISecurityToken(securityToken).balanceOf(_to) != 0) { return Result.NA; From 6d8bcee90d038d96bc0f344b6735b21e2b2ce95d Mon Sep 17 00:00:00 2001 From: satyam Date: Thu, 4 Oct 2018 18:29:42 +0530 Subject: [PATCH 27/28] remove investorCount --- contracts/interfaces/ISecurityToken.sol | 6 ------ 1 file changed, 6 deletions(-) diff --git a/contracts/interfaces/ISecurityToken.sol b/contracts/interfaces/ISecurityToken.sol index 09ffd2bb9..b0cbd22b1 100644 --- a/contracts/interfaces/ISecurityToken.sol +++ b/contracts/interfaces/ISecurityToken.sol @@ -116,12 +116,6 @@ interface ISecurityToken { */ function investors(uint256 _index) external view returns (address); - /** - * @notice gets the number of investors - * @return count of investors - */ - function investorCount() external view returns (uint256); - /** * @notice allows the owner to withdraw unspent POLY stored by them on the ST. * @dev Owner can transfer POLY to the ST which will be used to pay for modules that require a POLY fee. From 1b4a5497f0a580f3a166980cb7b96570a32123ac Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Thu, 4 Oct 2018 15:19:25 +0100 Subject: [PATCH 28/28] Small update --- contracts/modules/TransferManager/ITransferManager.sol | 1 + contracts/tokens/SecurityToken.sol | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/contracts/modules/TransferManager/ITransferManager.sol b/contracts/modules/TransferManager/ITransferManager.sol index 5d23a37fd..8279e68c5 100644 --- a/contracts/modules/TransferManager/ITransferManager.sol +++ b/contracts/modules/TransferManager/ITransferManager.sol @@ -5,6 +5,7 @@ import "../Module.sol"; /** * @title Interface to be implemented by all Transfer Manager modules + * @dev abstract contract */ contract ITransferManager is Module, Pausable { diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index ac8edd049..83724284e 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -238,12 +238,9 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr uint256 i; for (i = 0; i < moduleTypes.length; i++) { moduleIndexes[i] = modules[moduleTypes[i]].length; - } - modulesToData[module] = TokenLib.ModuleData(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); - for (i = 0; i < moduleTypes.length; i++) { - /* modulesToData[module].moduleType[moduleTypes[i]] = true; */ modules[moduleTypes[i]].push(module); } + modulesToData[module] = TokenLib.ModuleData(moduleName, module, _moduleFactory, false, moduleTypes, moduleIndexes, names[moduleName].length); names[moduleName].push(module); //Emit log event emit ModuleAdded(moduleTypes, moduleName, _moduleFactory, module, moduleCost, _budget, now);