diff --git a/.solcover.js b/.solcover.js index c7a6ed7d1..ffd077e28 100644 --- a/.solcover.js +++ b/.solcover.js @@ -4,6 +4,6 @@ module.exports = { copyPackages: ['openzeppelin-solidity'], testCommand: 'node ../node_modules/.bin/truffle test `find test/*.js ! -name a_poly_oracle.js -and ! -name s_v130_to_v140_upgrade.js` --network coverage', deepSkip: true, - skipFiles: ['external', 'flat', 'helpers', 'mocks', 'oracles'], + skipFiles: ['external', 'flat', 'helpers', 'mocks', 'oracles', 'libraries/KindMath.sol', 'storage'], forceParse: ['mocks', 'oracles'] }; diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a4896b14..c4b8fdb42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,11 +26,12 @@ All notable changes to this project will be documented in this file. * Add `getReputationOfFactory()` & `getModuleListOfType()` functions to get the array type data from the ModuleRegistry contract. * Add `_setupCost` in `LogGenerateModuleFromFactory` event. * Add new function `getAllModulesByName()`, To get the list of modules having the same name. #198. -* Add new function `modifyTickerDetails()`, To modify the details of undeployed ticker. #230 +* Add new function `modifyTickerDetails()`, To modify the details of undeployed ticker. #230 ## Fixed * Generalize the STO varaible names and added them in `ISTO.sol` to use the common standard in all STOs. -* Generalize the event when any new token get registered with the polymath ecosystem. `LogNewSecurityToken` should emit _ticker, _name, _securityTokenAddress, _owner, _addedAt, _registrant respectively. #230 +* Generalize the event when any new token get registered with the polymath ecosystem. `LogNewSecurityToken` should emit _ticker, _name, _securityTokenAddress, _owner, _addedAt, _registrant respectively. #230 +* Change the function name of `withdraPoly` to `withdrawERC20` and make the function generalize to extract tokens from the ST contract. parmeters are contract address and the value need to extract from the securityToken. ## Removed * Remove `swarmHash` from the `registerTicker(), addCustomTicker(), generateSecurityToken(), addCustomSecurityToken()` functions of TickerRegistry.sol and SecurityTokenRegistry.sol. #230 diff --git a/contracts/ModuleRegistry.sol b/contracts/ModuleRegistry.sol index b7b85c2b5..03c5f3016 100644 --- a/contracts/ModuleRegistry.sol +++ b/contracts/ModuleRegistry.sol @@ -126,7 +126,6 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { 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"); pushArray(Encoder.getKey("reputation", _moduleFactory), msg.sender); emit ModuleUsed(_moduleFactory, msg.sender); } diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 9286a1a7f..29ed14a8a 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -669,6 +669,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _patch Patch version of the proxy */ function setProtocolVersion(address _STFactoryAddress, uint8 _major, uint8 _minor, uint8 _patch) external onlyOwner { + require(_STFactoryAddress != address(0), "0x address is not allowed"); _setProtocolVersion(_STFactoryAddress, _major, _minor, _patch); } diff --git a/contracts/interfaces/ISecurityToken.sol b/contracts/interfaces/ISecurityToken.sol index e099006bc..c845cc30d 100644 --- a/contracts/interfaces/ISecurityToken.sol +++ b/contracts/interfaces/ISecurityToken.sol @@ -127,12 +127,13 @@ interface ISecurityToken { */ function investors(uint256 _index) external view returns (address); - /** - * @notice allows the owner to withdraw unspent POLY stored by them on the ST. + /** + * @notice allows the owner to withdraw unspent POLY stored by them on the ST or any ERC20 token. * @dev Owner can transfer POLY to the ST which will be used to pay for modules that require a POLY fee. + * @param _tokenContract Address of the ERC20Basic compliance token * @param _value amount of POLY to withdraw */ - function withdrawPoly(uint256 _value) external; + function withdrawERC20(address _tokenContract, uint256 _value) external; /** * @notice allows owner to approve more POLY to one of the modules diff --git a/contracts/mocks/MockBurnFactory.sol b/contracts/mocks/MockBurnFactory.sol new file mode 100644 index 000000000..c21b474f1 --- /dev/null +++ b/contracts/mocks/MockBurnFactory.sol @@ -0,0 +1,34 @@ +pragma solidity ^0.4.24; + +import "./MockRedemptionManager.sol"; +import "../modules/Burn/TrackedRedemptionFactory.sol"; + +/** + * @title Mock Contract Not fit for production environment + */ + +contract MockBurnFactory is TrackedRedemptionFactory { + + /** + * @notice Constructor + * @param _polyAddress Address of the polytoken + */ + constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public + TrackedRedemptionFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) + { + } + + /** + * @notice used to launch the Module with the help of factory + * @return address Contract address of the Module + */ + function deploy(bytes /*_data*/) external returns(address) { + if(setupCost > 0) + require(polyToken.transferFrom(msg.sender, owner, setupCost), "Unable to pay setup cost"); + //Check valid bytes - can only call module init function + MockRedemptionManager mockRedemptionManager = new MockRedemptionManager(msg.sender, address(polyToken)); + emit GenerateModuleFromFactory(address(mockRedemptionManager), getName(), address(this), msg.sender, setupCost, now); + return address(mockRedemptionManager); + } + +} diff --git a/contracts/mocks/MockFactory.sol b/contracts/mocks/MockFactory.sol index 5f2469cde..627efb71c 100644 --- a/contracts/mocks/MockFactory.sol +++ b/contracts/mocks/MockFactory.sol @@ -1,99 +1,42 @@ pragma solidity ^0.4.24; -import "../modules/STO/DummySTO.sol"; -import "../modules/ModuleFactory.sol"; -import "../libraries/Util.sol"; +import "../modules/STO/DummySTOFactory.sol"; -contract MockFactory is ModuleFactory { +/** + * @title Mock Contract Not fit for production environment + */ +contract MockFactory is DummySTOFactory { + + bool public switchTypes = false; /** * @notice Constructor * @param _polyAddress Address of the polytoken */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public - ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) + DummySTOFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { - version = "1.0.0"; - name = "Mock"; - title = "Mock Manager"; - description = "MockManager"; - compatibleSTVersionRange["lowerBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); - compatibleSTVersionRange["upperBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); - } - /** - * @notice used to launch the Module with the help of factory - * @param _data Data used for the intialization of the module factory variables - * @return address Contract address of the Module - */ - function deploy(bytes _data) external returns(address) { - if(setupCost > 0) - require(polyToken.transferFrom(msg.sender, owner, setupCost), "Unable to pay setup cost"); - //Check valid bytes - can only call module init function - DummySTO dummySTO = new DummySTO(msg.sender, address(polyToken)); - //Checks that _data is valid (not calling anything it shouldn't) - require(Util.getSig(_data) == dummySTO.getInitFunction(), "Invalid initialisation"); - require(address(dummySTO).call(_data), "Unsuccessfull initialisation"); - return address(dummySTO); } /** * @notice Type of the Module factory */ function getTypes() external view returns(uint8[]) { - uint8[] memory res = new uint8[](0); - return res; - } - - /** - * @notice Get the name of the Module - */ - function getName() public view returns(bytes32) { - return name; - } - - /** - * @notice Get the description of the Module - */ - function getDescription() external view returns(string) { - return description; - } - - /** - * @notice Get the title of the Module - */ - function getTitle() external view returns(string) { - return title; - } - - /** - * @notice Get the version of the Module - */ - function getVersion() external view returns(string) { - return version; - } - - /** - * @notice Get the setup cost of the module - */ - function getSetupCost() external view returns (uint256) { - return setupCost; - } - - /** - * @notice Returns the instructions associated with the module - */ - 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() external view returns(bytes32[]) { - bytes32[] memory availableTags = new bytes32[](4); - availableTags[0] = "Mock"; - return availableTags; + if (!switchTypes) { + uint8[] memory types = new uint8[](0); + return types; + } else { + uint8[] memory res = new uint8[](2); + res[0] = 1; + res[1] = 1; + return res; + } + + } + + function changeTypes() external onlyOwner { + switchTypes = !switchTypes; } } diff --git a/contracts/mocks/MockRedemptionManager.sol b/contracts/mocks/MockRedemptionManager.sol new file mode 100644 index 000000000..a2a0a6f7c --- /dev/null +++ b/contracts/mocks/MockRedemptionManager.sol @@ -0,0 +1,45 @@ +pragma solidity ^0.4.24; + +import "../modules/Burn/TrackedRedemption.sol"; + +/** + * @title Burn module for burning tokens and keeping track of burnt amounts + */ +contract MockRedemptionManager is TrackedRedemption { + + mapping (address => uint256) tokenToRedeem; + + event RedeemedTokenByOwner(address _investor, address _byWhoom, uint256 _value, uint256 _timestamp); + + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + */ + constructor (address _securityToken, address _polyAddress) public + TrackedRedemption(_securityToken, _polyAddress) + { + } + + /** + * @notice Transfer tokens to Module to burn + * @param _value The number of tokens to redeem + */ + function transferToRedeem(uint256 _value) public { + require(ISecurityToken(securityToken).transferFrom(msg.sender, address(this), _value), "Insufficient funds"); + tokenToRedeem[msg.sender] = _value; + } + + /** + * @notice use to redeem tokens by the module + * @param _value The number of tokens to redeem + */ + function redeemTokenByOwner(uint256 _value) public { + require(tokenToRedeem[msg.sender] >= _value); + tokenToRedeem[msg.sender] = tokenToRedeem[msg.sender].sub(_value); + redeemedTokens[msg.sender] = redeemedTokens[msg.sender].add(_value); + ISecurityToken(securityToken).burnWithData(_value, ""); + emit RedeemedTokenByOwner(msg.sender, address(this), _value, now); + } + +} diff --git a/contracts/mocks/MockWrongTypeFactory.sol b/contracts/mocks/MockWrongTypeFactory.sol new file mode 100644 index 000000000..f04a3a2de --- /dev/null +++ b/contracts/mocks/MockWrongTypeFactory.sol @@ -0,0 +1,31 @@ +pragma solidity ^0.4.24; + +import "./MockBurnFactory.sol"; +import "../modules/ModuleFactory.sol"; +import "../libraries/Util.sol"; + +/** + * @title Mock Contract Not fit for production environment + */ + +contract MockWrongTypeFactory is MockBurnFactory { + + /** + * @notice Constructor + * @param _polyAddress Address of the polytoken + */ + constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public + MockBurnFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) + { + } + + /** + * @notice Type of the Module factory + */ + function getTypes() external view returns(uint8[]) { + uint8[] memory types = new uint8[](1); + types[0] = 4; + return types; + } + +} diff --git a/contracts/mocks/TestSTOFactory.sol b/contracts/mocks/TestSTOFactory.sol index 85c32f2f9..eb26bd922 100644 --- a/contracts/mocks/TestSTOFactory.sol +++ b/contracts/mocks/TestSTOFactory.sol @@ -1,17 +1,15 @@ pragma solidity ^0.4.24; -import "../modules/STO/DummySTO.sol"; -import "../modules/ModuleFactory.sol"; -import "../libraries/Util.sol"; +import "../modules/STO/DummySTOFactory.sol"; -contract TestSTOFactory is ModuleFactory { +contract TestSTOFactory is DummySTOFactory { /** * @notice Constructor * @param _polyAddress Address of the polytoken */ constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public - ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) + DummySTOFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) { version = "1.0.0"; name = "TestSTO"; @@ -21,66 +19,6 @@ contract TestSTOFactory is ModuleFactory { compatibleSTVersionRange["upperBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); } - /** - * @notice used to launch the Module with the help of factory - * @param _data Data used for the intialization of the module factory variables - * @return address Contract address of the Module - */ - function deploy(bytes _data) external returns(address) { - if(setupCost > 0) - require(polyToken.transferFrom(msg.sender, owner, setupCost), "Failed transferFrom because of sufficent Allowance is not provided"); - //Check valid bytes - can only call module init function - DummySTO dummySTO = new DummySTO(msg.sender, address(polyToken)); - //Checks that _data is valid (not calling anything it shouldn't) - require(Util.getSig(_data) == dummySTO.getInitFunction(), "Provided data is not valid"); - require(address(dummySTO).call(_data), "Un-successfull call"); - return address(dummySTO); - } - - /** - * @notice Type of the Module factory - */ - function getTypes() external view returns(uint8[]) { - uint8[] memory res = new uint8[](1); - res[0] = 3; - return res; - } - - /** - * @notice Get the name of the Module - */ - function getName() external view returns(bytes32) { - return name; - } - - /** - * @notice Get the description of the Module - */ - function getDescription() external view returns(string) { - return description; - } - - /** - * @notice Get the title of the Module - */ - function getTitle() external view returns(string) { - return title; - } - - /** - * @notice Get the version of the Module - */ - function getVersion() external view returns(string) { - return version; - } - - /** - * @notice Get the setup cost of the module - */ - function getSetupCost() external view returns (uint256) { - return setupCost; - } - /** * @notice Returns the instructions associated with the module */ diff --git a/contracts/modules/Burn/TrackedRedemption.sol b/contracts/modules/Burn/TrackedRedemption.sol index f6211a140..60745f778 100644 --- a/contracts/modules/Burn/TrackedRedemption.sol +++ b/contracts/modules/Burn/TrackedRedemption.sol @@ -41,7 +41,7 @@ contract TrackedRedemption is IBurn, Module { redeemedTokens[msg.sender] = redeemedTokens[msg.sender].add(_value); emit Redeemed(msg.sender, _value, now); } - + /** * @notice Return the permissions flag that are associated with CountTransferManager */ diff --git a/contracts/modules/TransferManager/ManualApprovalTransferManager.sol b/contracts/modules/TransferManager/ManualApprovalTransferManager.sol index aa3810747..1dcc9f4cd 100644 --- a/contracts/modules/TransferManager/ManualApprovalTransferManager.sol +++ b/contracts/modules/TransferManager/ManualApprovalTransferManager.sol @@ -129,7 +129,7 @@ contract ManualApprovalTransferManager is ITransferManager { require(_from != address(0), "Invalid from address"); require(_to != address(0), "Invalid to address"); require(_expiryTime > now, "Invalid expiry time"); - require(manualApprovals[_from][_to].expiryTime == 0, "Blocking already exists"); + require(manualBlockings[_from][_to].expiryTime == 0, "Blocking already exists"); manualBlockings[_from][_to] = ManualBlocking(_expiryTime); emit AddManualBlocking(_from, _to, _expiryTime, msg.sender); } diff --git a/contracts/proxy/OwnedUpgradeabilityProxy.sol b/contracts/proxy/OwnedUpgradeabilityProxy.sol index e1890a243..81a634ec8 100644 --- a/contracts/proxy/OwnedUpgradeabilityProxy.sol +++ b/contracts/proxy/OwnedUpgradeabilityProxy.sol @@ -80,7 +80,7 @@ contract OwnedUpgradeabilityProxy is UpgradeabilityProxy { * @return address of the current implementation */ function implementation() external ifOwner returns (address) { - _implementation(); + return _implementation(); } /** diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index dde865fa8..1d2b165f5 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -341,13 +341,16 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr return modules[_type]; } - /** - * @notice allows the owner to withdraw unspent POLY stored by them on the ST. + /** + * @notice allows the owner to withdraw unspent POLY stored by them on the ST or any ERC20 token. * @dev Owner can transfer POLY to the ST which will be used to pay for modules that require a POLY fee. + * @param _tokenContract Address of the ERC20Basic compliance token * @param _value amount of POLY to withdraw */ - function withdrawPoly(uint256 _value) external onlyOwner { - require(ERC20(polyToken).transfer(owner, _value), "Insufficient balance"); + function withdrawERC20(address _tokenContract, uint256 _value) external onlyOwner { + require(_tokenContract != address(0)); + IERC20 token = IERC20(_tokenContract); + require(token.transfer(owner, _value)); } /** @@ -429,7 +432,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @notice freezes transfers */ function freezeTransfers() external onlyOwner { - require(!transfersFrozen, "transfers already frozen"); + require(!transfersFrozen, "Already frozen"); transfersFrozen = true; emit FreezeTransfers(true, now); } @@ -438,7 +441,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @notice unfreeze transfers */ function unfreezeTransfers() external onlyOwner { - require(transfersFrozen, "transfer are not fronzen"); + require(transfersFrozen, "Not frozen"); transfersFrozen = false; emit FreezeTransfers(false, now); } @@ -730,7 +733,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _controller address of the controller */ function setController(address _controller) public onlyOwner { - require(!controllerDisabled,"Controller functions are disabled"); + require(!controllerDisabled,"Controller disabled"); emit SetController(controller, _controller); controller = _controller; } @@ -740,7 +743,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @dev enabled via feature switch "disableControllerAllowed" */ function disableController() external isEnabled("disableControllerAllowed") onlyOwner { - require(!controllerDisabled,"Controller functions are disabled"); + require(!controllerDisabled,"Controller disabled"); controllerDisabled = true; delete controller; emit DisableController(now); diff --git a/test/b_capped_sto.js b/test/b_capped_sto.js index 33fc5f6a6..ff80f1025 100644 --- a/test/b_capped_sto.js +++ b/test/b_capped_sto.js @@ -88,6 +88,7 @@ contract("CappedSTO", accounts => { const cap = web3.utils.toWei("10000"); const rate = 1000; const E_fundRaiseType = 0; + const address_zero = "0x0000000000000000000000000000000000000000"; let startTime_POLY1; let endTime_POLY1; @@ -136,7 +137,7 @@ contract("CappedSTO", accounts => { assert.notEqual( I_CappedSTOFactory.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "CappedSTOFactory contract was not deployed" ); @@ -197,7 +198,7 @@ contract("CappedSTO", accounts => { it("Should mint the tokens before attaching the STO", async () => { await catchRevert( - I_SecurityToken_ETH.mint("0x0000000000000000000000000000000000000000", web3.utils.toWei("1"), { from: token_owner }) + I_SecurityToken_ETH.mint(address_zero, web3.utils.toWei("1"), { from: token_owner }) ); }); @@ -221,6 +222,24 @@ contract("CappedSTO", accounts => { await catchRevert(I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner })); }); + it("Should fail to launch the STO due funds reciever account 0x", async () => { + let startTime = latestTime() + duration.days(1); + let endTime = startTime + duration.days(30); + + let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, [E_fundRaiseType], address_zero]); + + await catchRevert(I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner })); + }); + + it("Should fail to launch the STO due to raise type of 0 length", async () => { + let startTime = latestTime() + duration.days(1); + let endTime = startTime + duration.days(30); + + let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, [], account_fundsReceiver]); + + await catchRevert(I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner })); + }); + it("Should fail to launch the STO due to startTime > endTime", async () => { let bytesSTO = encodeModuleCall(STOParameters, [ Math.floor(Date.now() / 1000 + 100000), @@ -242,6 +261,13 @@ contract("CappedSTO", accounts => { await catchRevert(I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner })); }); + it("Should fail to launch the STO due to different value incompare to getInitFunction", async() => { + let startTime = latestTime() + duration.days(1); + let endTime = startTime + duration.days(30); + let bytesSTO = encodeModuleCall(['uint256', 'uint256', 'uint256'], [startTime, endTime, 0, ]); + await catchRevert(I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner })); + }); + it("Should successfully attach the STO module to the security token", async () => { startTime_ETH1 = latestTime() + duration.days(1); endTime_ETH1 = startTime_ETH1 + duration.days(30); @@ -259,6 +285,12 @@ contract("CappedSTO", accounts => { 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)); }); + + it("Should call the configure function -- fail because of the bad owner", async()=> { + await catchRevert( + I_CappedSTO_Array_ETH[0].configure(startTime_ETH1, endTime_ETH1, cap, rate, [E_fundRaiseType], account_fundsReceiver, {from: account_polymath }) + ); + }) }); describe("verify the data of STO", async () => { @@ -329,8 +361,7 @@ contract("CappedSTO", accounts => { // Add the Investor in to the whitelist let tx = await I_GeneralTransferManager.modifyWhitelist(account_investor1, fromTime, toTime, expiryTime, true, { - from: account_issuer, - gas: 500000 + from: account_issuer }); assert.equal(tx.logs[0].args._investor, account_investor1, "Failed in adding the investor in whitelist"); @@ -346,10 +377,9 @@ contract("CappedSTO", accounts => { }); assert.equal((await I_CappedSTO_Array_ETH[0].getRaised.call(ETH)).dividedBy(new BigNumber(10).pow(18)).toNumber(), 1); - assert.equal(await I_CappedSTO_Array_ETH[0].investorCount.call(), 1); - assert.equal((await I_SecurityToken_ETH.balanceOf(account_investor1)).dividedBy(new BigNumber(10).pow(18)).toNumber(), 1000); + assert.equal((await I_CappedSTO_Array_ETH[0].getTokensSold.call()).dividedBy(new BigNumber(10).pow(18)).toNumber(), 1000); }); it("Verification of the event Token Purchase", async () => { @@ -359,6 +389,14 @@ contract("CappedSTO", accounts => { assert.equal(log.args.amount.dividedBy(new BigNumber(10).pow(18)).toNumber(), 1000, "Wrong No. token get dilivered"); }); + it("Should fail to buy the tokens -- Because fundRaiseType is ETH not POLY", async ()=> { + await I_PolyToken.getTokens(web3.utils.toWei("500"), account_investor1); + await I_PolyToken.approve(I_CappedSTO_Array_ETH[0].address, web3.utils.toWei("500"), {from: account_investor1}); + await catchRevert( + I_CappedSTO_Array_ETH[0].buyTokensWithPoly(web3.utils.toWei("500"), {from: account_investor1}) + ); + }) + it("Should pause the STO -- Failed due to wrong msg.sender", async () => { await catchRevert(I_CappedSTO_Array_ETH[0].pause({ from: account_investor1 })); }); @@ -407,8 +445,7 @@ contract("CappedSTO", accounts => { expiryTime, true, { - from: account_issuer, - gas: 500000 + from: account_issuer } ); @@ -427,7 +464,7 @@ contract("CappedSTO", accounts => { assert.equal(await I_CappedSTO_Array_ETH[0].investorCount.call(), 2); assert.equal((await I_SecurityToken_ETH.balanceOf(account_investor2)).dividedBy(new BigNumber(10).pow(18)).toNumber(), 9000); - await catchRevert(I_CappedSTO_Array_ETH[0].buyTokens(account_investor2, { value: web3.utils.toWei("100") })); + await catchRevert(I_CappedSTO_Array_ETH[0].buyTokens(account_investor2, { value: web3.utils.toWei("81") })); }); it("Should fundRaised value equal to the raised value in the funds receiver wallet", async () => { @@ -458,7 +495,7 @@ contract("CappedSTO", accounts => { await I_PolyToken.getTokens(value, account_investor1); await I_PolyToken.transfer(I_CappedSTO_Array_ETH[0].address, value, { from: account_investor1 }); - await catchRevert(I_CappedSTO_Array_ETH[0].reclaimERC20("0x0000000000000000000000000000000000000000", { from: token_owner })); + await catchRevert(I_CappedSTO_Array_ETH[0].reclaimERC20(address_zero, { from: token_owner })); }); it("Should successfully reclaim POLY", async () => { @@ -471,7 +508,7 @@ contract("CappedSTO", accounts => { await I_PolyToken.transfer(I_CappedSTO_Array_ETH[0].address, value, { from: account_investor1 }); await I_CappedSTO_Array_ETH[0].reclaimERC20(I_PolyToken.address, { from: token_owner }); assert.equal( - (await I_PolyToken.balanceOf(account_investor3)).toNumber(), + (await I_PolyToken.balanceOf(account_investor1)).toNumber(), initInvestorBalance.toNumber(), "tokens are not transfered out from investor account" ); @@ -553,6 +590,12 @@ contract("CappedSTO", accounts => { assert.equal(allow, true, "allowBeneficialInvestments should be true"); }); + it("Should allow non-matching beneficiary -- failed because it is already active", async () => { + await catchRevert( + I_CappedSTO_Array_ETH[1].changeAllowBeneficialInvestments(true, { from: account_issuer }) + ); + }); + it("Should invest in second STO", async () => { await I_CappedSTO_Array_ETH[1].buyTokens(account_investor3, { from: account_issuer, value: web3.utils.toWei("1", "ether") }); @@ -686,7 +729,7 @@ contract("CappedSTO", accounts => { blockNo = latestBlock(); assert.equal( (await I_PolyToken.balanceOf(account_investor1)).dividedBy(new BigNumber(10).pow(18)).toNumber(), - 10000, + 10500, "Tokens are not transfered properly" ); @@ -704,8 +747,7 @@ contract("CappedSTO", accounts => { // buyTokensWithPoly transaction await I_CappedSTO_Array_POLY[0].buyTokensWithPoly(1000 * Math.pow(10, 18), { - from: account_investor1, - gas: 6000000 + from: account_investor1 }); assert.equal((await I_CappedSTO_Array_POLY[0].getRaised.call(POLY)).dividedBy(new BigNumber(10).pow(18)).toNumber(), 1000); @@ -725,6 +767,33 @@ contract("CappedSTO", accounts => { assert.equal(log.args.amount.dividedBy(new BigNumber(10).pow(18)).toNumber(), 5000, "Wrong No. token get dilivered"); }); + it("Should failed to buy tokens -- because fundraisetype is POLY not ETH", async() => { + await catchRevert( + // Fallback transaction + web3.eth.sendTransaction({ + from: account_investor1, + to: I_CappedSTO_Array_POLY[0].address, + gas: 2100000, + value: web3.utils.toWei("2", "ether") + }) + ); + }); + + it("Should fail in buying tokens because buying is paused", async() => { + await I_CappedSTO_Array_POLY[0].pause({ from: account_issuer }); + await I_PolyToken.approve(I_CappedSTO_Array_POLY[0].address, 1000 * Math.pow(10, 18), { from: account_investor1 }); + + // buyTokensWithPoly transaction + await catchRevert( + I_CappedSTO_Array_POLY[0].buyTokensWithPoly(1000 * Math.pow(10, 18), { + from: account_investor1, + gas: 6000000 + }) + ); + await I_CappedSTO_Array_POLY[0].unpause({ from: account_issuer }); + }); + + it("Should restrict to buy tokens after hiting the cap in second tx first tx pass", async () => { let tx = await I_GeneralTransferManager.modifyWhitelist( account_investor2, @@ -745,7 +814,7 @@ contract("CappedSTO", accounts => { await I_PolyToken.approve(I_CappedSTO_Array_POLY[0].address, 9000 * Math.pow(10, 18), { from: account_investor2 }); // buyTokensWithPoly transaction - await I_CappedSTO_Array_POLY[0].buyTokensWithPoly(9000 * Math.pow(10, 18), { from: account_investor2, gas: 6000000 }); + await I_CappedSTO_Array_POLY[0].buyTokensWithPoly(9000 * Math.pow(10, 18), { from: account_investor2 }); assert.equal((await I_CappedSTO_Array_POLY[0].getRaised.call(POLY)).dividedBy(new BigNumber(10).pow(18)).toNumber(), 10000); @@ -757,7 +826,7 @@ contract("CappedSTO", accounts => { ); await I_PolyToken.approve(I_CappedSTO_Array_POLY[0].address, 1000 * Math.pow(10, 18), { from: account_investor1 }); await catchRevert( - I_CappedSTO_Array_POLY[0].buyTokensWithPoly(1000 * Math.pow(10, 18), { from: account_investor1, gas: 6000000 }) + I_CappedSTO_Array_POLY[0].buyTokensWithPoly(1000 * Math.pow(10, 18), { from: account_investor1 }) ); }); @@ -797,6 +866,7 @@ contract("CappedSTO", accounts => { ); let tags = await I_CappedSTOFactory.getTags.call(); assert.equal(web3.utils.hexToString(tags[0]), "Capped"); + assert.equal(await I_CappedSTOFactory.getVersion.call(), "1.0.0"); }); it("Should fail to change the title -- bad owner", async () => { diff --git a/test/d_count_transfer_manager.js b/test/d_count_transfer_manager.js index 3bf785a5d..6db725c74 100644 --- a/test/d_count_transfer_manager.js +++ b/test/d_count_transfer_manager.js @@ -249,7 +249,33 @@ contract("CountTransferManager", accounts => { assert.equal((await I_SecurityToken.balanceOf(account_investor2)).toNumber(), web3.utils.toWei("2", "ether")); }); + it("Should able to buy some more tokens (more than 2 hoders) -- because CountTransferManager is paused", async() => { + await I_CountTransferManager.pause({from: account_issuer }); + let snapId = await takeSnapshot(); + let tx = await I_GeneralTransferManager.modifyWhitelist( + account_investor3, + latestTime(), + latestTime(), + latestTime() + duration.days(10), + true, + { + from: account_issuer, + gas: 500000 + } + ); + + assert.equal( + tx.logs[0].args._investor.toLowerCase(), + account_investor3.toLowerCase(), + "Failed in adding the investor in whitelist" + ); + + await I_SecurityToken.mint(account_investor3, web3.utils.toWei("3", "ether"), { from: token_owner }) + await revertToSnapshot(snapId); + }) + it("Should fail to buy some more tokens (more than 2 holders)", async () => { + await I_CountTransferManager.unpause({from: account_issuer }); // Add the Investor in to the whitelist let tx = await I_GeneralTransferManager.modifyWhitelist( account_investor3, @@ -349,5 +375,79 @@ contract("CountTransferManager", accounts => { assert.equal(web3.utils.toAscii(tags[0]).replace(/\u0000/g, ""), "Count"); }); }); + + describe("Test cases for the ModuleFactory", async() => { + it("Should successfully change the SetupCost -- fail beacuse of bad owner", async() => { + await catchRevert( + I_CountTransferManagerFactory.changeFactorySetupFee(web3.utils.toWei("500"), {from: account_investor3}) + ); + }); + + it("Should successfully change the setupCost", async() => { + await I_CountTransferManagerFactory.changeFactorySetupFee(web3.utils.toWei("800"), { from: account_polymath }); + assert.equal(await I_CountTransferManagerFactory.getSetupCost.call(), web3.utils.toWei("800")); + }) + + it("Should successfully change the usage fee -- fail beacuse of bad owner", async() => { + await catchRevert( + I_CountTransferManagerFactory.changeFactoryUsageFee(web3.utils.toWei("500"), {from: account_investor3}) + ); + }); + + it("Should successfully change the usage fee", async() => { + await I_CountTransferManagerFactory.changeFactoryUsageFee(web3.utils.toWei("800"), { from: account_polymath }); + assert.equal(await I_CountTransferManagerFactory.usageCost.call(), web3.utils.toWei("800")); + }); + + it("Should successfully change the subscription fee -- fail beacuse of bad owner", async() => { + await catchRevert( + I_CountTransferManagerFactory.changeFactorySubscriptionFee(web3.utils.toWei("500"), {from: account_investor3}) + ); + }); + + it("Should successfully change the subscription fee", async() => { + await I_CountTransferManagerFactory.changeFactorySubscriptionFee(web3.utils.toWei("800"), { from: account_polymath }); + assert.equal(await I_CountTransferManagerFactory.monthlySubscriptionCost.call(), web3.utils.toWei("800")); + }); + + it("Should successfully change the version of the factory -- failed because of bad owner", async() => { + await catchRevert( + I_CountTransferManagerFactory.changeVersion("5.0.0", {from: account_investor3}) + ); + }); + + it("Should successfully change the version of the fatory -- failed because of the 0 string", async() => { + await catchRevert( + I_CountTransferManagerFactory.changeVersion("", {from: account_polymath}) + ); + }); + + it("Should successfully change the version of the fatory", async() => { + await I_CountTransferManagerFactory.changeVersion("5.0.0", {from: account_polymath}); + assert.equal(await I_CountTransferManagerFactory.getVersion.call(), "5.0.0"); + }); + }) + + describe("Test case for the changeSTVersionBounds", async() => { + it("Should successfully change the version bounds -- failed because of the non permitted bound type", async() => { + await catchRevert( + I_CountTransferManagerFactory.changeSTVersionBounds("middleType", [1,2,3], {from: account_polymath}) + ); + }) + + it("Should successfully change the version bound --failed because the new version length < 3", async()=> { + await catchRevert( + I_CountTransferManagerFactory.changeSTVersionBounds("lowerBound", [1,2], {from: account_polymath}) + ); + }) + + it("Should successfully change the version bound", async()=> { + await I_CountTransferManagerFactory.changeSTVersionBounds("lowerBound", [1,2,1], {from: account_polymath}); + await I_CountTransferManagerFactory.changeSTVersionBounds("lowerBound", [1,4,9], {from: account_polymath}); + await catchRevert( + I_CountTransferManagerFactory.changeSTVersionBounds("lowerBound", [1,0,0], {from: account_polymath}) + ); + }) + }) }); }); diff --git a/test/g_general_permission_manager.js b/test/g_general_permission_manager.js index 0cf090030..eb22406c8 100644 --- a/test/g_general_permission_manager.js +++ b/test/g_general_permission_manager.js @@ -1,22 +1,21 @@ -import latestTime from "./helpers/latestTime"; -import { signData } from "./helpers/signData"; -import { pk } from "./helpers/testprivateKey"; -import { duration, ensureException, promisifyLogWatch, latestBlock } from "./helpers/utils"; -import takeSnapshot, { increaseTime, revertToSnapshot } from "./helpers/time"; -import { encodeProxyCall, encodeModuleCall } from "./helpers/encodeCall"; +import latestTime from './helpers/latestTime'; +import {signData} from './helpers/signData'; +import { pk } from './helpers/testprivateKey'; +import { duration, promisifyLogWatch, latestBlock } from './helpers/utils'; +import { takeSnapshot, increaseTime, revertToSnapshot } from './helpers/time'; import { catchRevert } from "./helpers/exceptions"; -import { setUpPolymathNetwork, deployGPMAndVerifyed, deployDummySTOAndVerifyed } from "./helpers/createInstances"; +import { setUpPolymathNetwork, deployGPMAndVerifyed } from "./helpers/createInstances"; -const DummySTO = artifacts.require("./DummySTO.sol"); -const SecurityToken = artifacts.require("./SecurityToken.sol"); -const GeneralTransferManager = artifacts.require("./GeneralTransferManager"); -const GeneralPermissionManager = artifacts.require("./GeneralPermissionManager"); +const SecurityToken = artifacts.require('./SecurityToken.sol'); +const GeneralTransferManager = artifacts.require('./GeneralTransferManager'); +const GeneralPermissionManager = artifacts.require('./GeneralPermissionManager'); -const Web3 = require("web3"); -const BigNumber = require("bignumber.js"); -const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); // Hardcoded development port +const Web3 = require('web3'); +const BigNumber = require('bignumber.js'); +const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")) // Hardcoded development port + +contract('GeneralPermissionManager', accounts => { -contract("GeneralPermissionManager", accounts => { // Accounts Variable declaration let account_polymath; let account_issuer; @@ -53,7 +52,6 @@ contract("GeneralPermissionManager", accounts => { let I_SecurityToken; let I_MRProxied; let I_STRProxied; - let I_DummySTO; let I_PolyToken; let I_PolymathRegistry; @@ -73,16 +71,7 @@ contract("GeneralPermissionManager", accounts => { // Initial fee for ticker registry and security token registry const initRegFee = web3.utils.toWei("250"); - // Dummy STO details - const startTime = latestTime() + duration.seconds(5000); // Start time will be 5000 seconds more than the latest time - const endTime = startTime + duration.days(80); // Add 80 days more - const cap = web3.utils.toWei("10", "ether"); - const someString = "A string which is not used"; - const STOParameters = ["uint256", "uint256", "uint256", "string"]; - - let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, someString]); - - before(async () => { + before(async() => { // Accounts setup account_polymath = accounts[0]; account_issuer = accounts[1]; @@ -112,14 +101,11 @@ contract("GeneralPermissionManager", accounts => { I_SecurityTokenRegistryProxy, I_STRProxied ] = instances; - // STEP 5: Deploy the GeneralDelegateManagerFactory [I_GeneralPermissionManagerFactory] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); // STEP 6: Deploy the GeneralDelegateManagerFactory - [P_GeneralPermissionManagerFactory] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, web3.utils.toWei("500", "ether")); - // STEP 7: Deploy the DummySTOFactory - [I_DummySTOFactory] = await deployDummySTOAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); + [P_GeneralPermissionManagerFactory] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, web3.utils.toWei("500")); // Printing all the contract addresses console.log(` @@ -134,8 +120,6 @@ contract("GeneralPermissionManager", accounts => { STFactory: ${I_STFactory.address} GeneralTransferManagerFactory: ${I_GeneralTransferManagerFactory.address} GeneralPermissionManagerFactory: ${I_GeneralPermissionManagerFactory.address} - - DummySTOFactory: ${I_DummySTOFactory.address} ----------------------------------------------------------------------------- `); }); @@ -170,12 +154,11 @@ contract("GeneralPermissionManager", accounts => { I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); - it("Should successfully attach the General permission manager factory with the security token", async () => { + it("Should successfully attach the General permission manager factory with the security token -- failed because Token is not paid", async () => { + let errorThrown = false; await I_PolyToken.getTokens(web3.utils.toWei("500", "ether"), token_owner); await catchRevert( - I_SecurityToken.addModule(P_GeneralPermissionManagerFactory.address, "0x", web3.utils.toWei("500", "ether"), 0, { - from: token_owner - }) + I_SecurityToken.addModule(P_GeneralPermissionManagerFactory.address, "0x", web3.utils.toWei("500", "ether"), 0, { from: token_owner }) ); }); @@ -218,27 +201,22 @@ contract("GeneralPermissionManager", accounts => { assert.equal(web3.utils.toAscii(tx).replace(/\u0000/g, ""), 0); }); - it("Should fail in adding the permission to the delegate --msg.sender doesn't have permission", async () => { - await catchRevert(I_GeneralPermissionManager.addDelegate(account_delegate, delegateDetails, { from: account_investor1 })); - }); - - it("Should fail to provide the permission-- because delegate is not yet added", async () => { - await catchRevert( - I_GeneralPermissionManager.changePermission(account_delegate, I_GeneralTransferManager.address, "WHITELIST", true, { - from: token_owner - }) - ); - }); - it("Should fail in adding the delegate -- msg.sender doesn't have permission", async() => { + let errorThrown = false; await catchRevert( I_GeneralPermissionManager.addDelegate(account_delegate, delegateDetails, { from: account_investor1}) ); }); it("Should fail in adding the delegate -- no delegate details provided", async() => { + catchRevert( + I_GeneralPermissionManager.addDelegate(account_delegate, '', { from: token_owner }) + ); + }); + + it("Should fail to provide the permission -- because delegate is not yet added", async() => { await catchRevert( - I_GeneralPermissionManager.addDelegate(account_delegate, '', { from: account_investor1}) + I_GeneralPermissionManager.changePermission(account_delegate, I_GeneralTransferManager.address, "WHITELIST", true, {from: token_owner}) ); }); @@ -247,12 +225,16 @@ contract("GeneralPermissionManager", accounts => { assert.equal(tx.logs[0].args._delegate, account_delegate); }); - it("Should fail to provide the permission", async () => { + it("Should successfully add the delegate -- failed because trying to add the already present delegate", async() => { await catchRevert( - I_GeneralPermissionManager.changePermission(account_delegate, I_GeneralTransferManager.address, "WHITELIST", true, { - from: account_investor1 - }) + I_GeneralPermissionManager.addDelegate(account_delegate, delegateDetails, { from: token_owner}) ); + }) + + it("Should fail to provide the permission -- because msg.sender doesn't have permission", async() => { + await catchRevert( + I_GeneralPermissionManager.changePermission(account_delegate, I_GeneralTransferManager.address, "WHITELIST", true, {from: account_investor1}) + ); }); it("Should check the permission", async () => { @@ -293,12 +275,17 @@ contract("GeneralPermissionManager", accounts => { it("Should return all delegates", async() => { await I_GeneralPermissionManager.addDelegate(account_delegate2, delegateDetails, { from: token_owner}); let tx = await I_GeneralPermissionManager.getAllDelegates.call(); - console.log(tx); assert.equal(tx.length, 2); assert.equal(tx[0], account_delegate); assert.equal(tx[1], account_delegate2); }); + it("Should check is delegate for 0x address - failed 0x address is not allowed", async() => { + await catchRevert( + I_GeneralPermissionManager.checkDelegate.call("0x0000000000000000000000000000000000000000000000000") + ); + }); + it("Should return false when check is delegate - because user is not a delegate", async() => { assert.equal(await I_GeneralPermissionManager.checkDelegate.call(account_investor1), false); }); @@ -308,9 +295,32 @@ contract("GeneralPermissionManager", accounts => { }); - it("Should provide the permission in bulk", async() => { + it("Should successfully provide the permissions in batch -- failed because of array length is 0", async() => { await I_GeneralPermissionManager.addDelegate(account_delegate3, delegateDetails, { from: token_owner}); + await catchRevert( + I_GeneralPermissionManager.changePermissionMulti(account_delegate3, [], ["WHITELIST","CHANGE_PERMISSION"], [true, true], {from: token_owner}) + ); + }); + + it("Should successfully provide the permissions in batch -- failed because of perm array length is 0", async() => { + await catchRevert( + I_GeneralPermissionManager.changePermissionMulti(account_delegate3, [I_GeneralTransferManager.address, I_GeneralPermissionManager.address], [], [true, true], {from: token_owner}) + ); + }); + + it("Should successfully provide the permissions in batch -- failed because mismatch in arrays length", async() => { + await catchRevert( + I_GeneralPermissionManager.changePermissionMulti(account_delegate3, [I_GeneralTransferManager.address], ["WHITELIST","CHANGE_PERMISSION"], [true, true], {from: token_owner}) + ); + }); + + it("Should successfully provide the permissions in batch -- failed because mismatch in arrays length", async() => { + await catchRevert( + I_GeneralPermissionManager.changePermissionMulti(account_delegate3, [I_GeneralTransferManager.address, I_GeneralPermissionManager.address], ["WHITELIST","CHANGE_PERMISSION"], [true], {from: token_owner}) + ); + }); + it("Should successfully provide the permissions in batch", async() => { let tx = await I_GeneralPermissionManager.changePermissionMulti(account_delegate3, [I_GeneralTransferManager.address, I_GeneralPermissionManager.address], ["WHITELIST","CHANGE_PERMISSION"], [true, true], {from: token_owner}); assert.equal(tx.logs[0].args._delegate, account_delegate3); @@ -318,27 +328,26 @@ contract("GeneralPermissionManager", accounts => { assert.isTrue(await I_GeneralPermissionManager.checkPermission.call(account_delegate3, I_GeneralPermissionManager.address, "CHANGE_PERMISSION")); }); - it("Should provide all delegates with specified permission", async() => { - await I_GeneralPermissionManager.changePermission(account_delegate2, I_GeneralTransferManager.address, "WHITELIST", true, {from: token_owner}); - let tx = await I_GeneralPermissionManager.getAllDelegatesWithPerm.call(I_GeneralTransferManager.address, "WHITELIST"); - // console.log(tx); assert.equal(tx.length, 3); assert.equal(tx[0], account_delegate); assert.equal(tx[1], account_delegate2); }); + it("Should get all delegates for the permission manager", async() => { + let tx = await I_GeneralPermissionManager.getAllDelegatesWithPerm.call(I_GeneralPermissionManager.address, "CHANGE_PERMISSION"); + assert.equal(tx.length, 1); + assert.equal(tx[0], account_delegate3); + }) + it("Should return all modules and all permission", async() => { - let tx = await I_GeneralPermissionManager.getAllModulesAndPermsFromTypes.call(account_delegate3, [2,1], I_SecurityToken.address); - console.log (tx); assert.equal(tx[0][0], I_GeneralTransferManager.address); assert.equal(tx[1][0], "0x57484954454c4953540000000000000000000000000000000000000000000000"); assert.equal(tx[0][1], I_GeneralPermissionManager.address); assert.equal(tx[1][1], "0x4348414e47455f5045524d495353494f4e000000000000000000000000000000"); - }); }); @@ -370,5 +379,10 @@ contract("GeneralPermissionManager", accounts => { let tags = await I_GeneralPermissionManagerFactory.getTags.call(); assert.equal(tags.length, 0); }); + + it("Should ge the version of the factory", async() => { + let version = await I_GeneralPermissionManagerFactory.getVersion.call(); + assert.equal(version, "1.0.0"); + }) }); }); diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 6f1272ded..c40809d8b 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -5,7 +5,7 @@ import { signData } from "./helpers/signData"; import { pk } from "./helpers/testprivateKey"; import { encodeProxyCall, encodeModuleCall } from "./helpers/encodeCall"; import { catchRevert } from "./helpers/exceptions"; -import { setUpPolymathNetwork, deployGPMAndVerifyed, deployDummySTOAndVerifyed } from "./helpers/createInstances"; +import { setUpPolymathNetwork, deployGPMAndVerifyed, deployDummySTOAndVerifyed, deployGTMAndVerifyed } from "./helpers/createInstances"; const DummySTO = artifacts.require("./DummySTO.sol"); @@ -49,6 +49,7 @@ contract("GeneralTransferManager", accounts => { let I_FeatureRegistry; let I_SecurityTokenRegistry; let I_DummySTOFactory; + let P_DummySTOFactory; let I_STFactory; let I_SecurityToken; let I_STRProxied; @@ -56,6 +57,7 @@ contract("GeneralTransferManager", accounts => { let I_DummySTO; let I_PolyToken; let I_PolymathRegistry; + let P_GeneralTransferManagerFactory; // SecurityToken Details const name = "Team"; @@ -113,7 +115,9 @@ contract("GeneralTransferManager", accounts => { ] = instances; [I_GeneralPermissionManagerFactory] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); + [P_GeneralTransferManagerFactory] = await deployGTMAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, web3.utils.toWei("500")); [I_DummySTOFactory] = await deployDummySTOAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); + [P_DummySTOFactory] = await deployDummySTOAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, web3.utils.toWei("500")); // Printing all the contract addresses console.log(` @@ -164,6 +168,19 @@ contract("GeneralTransferManager", accounts => { I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); + it("Should attach the paid GTM -- failed because of no tokens", async() => { + await catchRevert( + I_SecurityToken.addModule(P_GeneralTransferManagerFactory.address, "", web3.utils.toWei("500"), 0, {from: account_issuer}) + ); + }) + + it("Should attach the paid GTM", async() => { + let snap_id = await takeSnapshot(); + await I_PolyToken.getTokens(web3.utils.toWei("500"), I_SecurityToken.address); + await I_SecurityToken.addModule(P_GeneralTransferManagerFactory.address, "", web3.utils.toWei("500"), 0, {from: account_issuer}); + await revertToSnapshot(snap_id); + }) + it("Should whitelist the affiliates before the STO attached", async () => { let tx = await I_GeneralTransferManager.modifyWhitelistMulti( [account_affiliates1, account_affiliates2], @@ -189,6 +206,49 @@ contract("GeneralTransferManager", accounts => { assert.equal((await I_SecurityToken.balanceOf.call(account_affiliates2)).dividedBy(new BigNumber(10).pow(18)).toNumber(), 100); }); + + it("Should successfully attach the STO factory with the security token -- failed because of no tokens", async () => { + let bytesSTO = encodeModuleCall(STOParameters, [ + latestTime() + duration.seconds(1000), + latestTime() + duration.days(40), + cap, + someString + ]); + await catchRevert( + I_SecurityToken.addModule(P_DummySTOFactory.address, bytesSTO, web3.utils.toWei("500"), 0, { from: token_owner }) + ); + }); + + it("Should successfully attach the STO factory with the security token", async () => { + let snap_id = await takeSnapshot(); + let bytesSTO = encodeModuleCall(STOParameters, [ + latestTime() + duration.seconds(1000), + latestTime() + duration.days(40), + cap, + someString + ]); + await I_PolyToken.getTokens(web3.utils.toWei("500"), I_SecurityToken.address); + const tx = await I_SecurityToken.addModule(P_DummySTOFactory.address, bytesSTO, web3.utils.toWei("500"), 0, { from: token_owner }); + assert.equal(tx.logs[3].args._types[0].toNumber(), stoKey, "DummySTO doesn't get deployed"); + assert.equal( + web3.utils.toAscii(tx.logs[3].args._name).replace(/\u0000/g, ""), + "DummySTO", + "DummySTOFactory module was not added" + ); + I_DummySTO = DummySTO.at(tx.logs[3].args._module); + await revertToSnapshot(snap_id); + }); + + it("Should successfully attach the STO factory with the security token - invalid data", async () => { + let bytesSTO = encodeModuleCall(['uint256', 'string'], [ + latestTime() + duration.seconds(1000), + someString + ]); + await catchRevert( + I_SecurityToken.addModule(P_DummySTOFactory.address, bytesSTO, 0, 0, { from: token_owner }) + ); + }); + it("Should successfully attach the STO factory with the security token", async () => { let bytesSTO = encodeModuleCall(STOParameters, [ latestTime() + duration.seconds(1000), @@ -257,6 +317,24 @@ contract("GeneralTransferManager", accounts => { await catchRevert(I_DummySTO.generateTokens(account_affiliates1, web3.utils.toWei("1", "ether"), { from: token_owner })); }); + it("Should fail in buying the tokens from the STO -- because amount is 0", async() => { + await catchRevert( + I_DummySTO.generateTokens(account_investor1, 0, { from: token_owner }) + ); + }); + + it("Should fail in buying the tokens from the STO -- because STO is paused", async() => { + await I_DummySTO.pause({from: account_issuer }); + await catchRevert(I_DummySTO.generateTokens(account_investor1, web3.utils.toWei("1", "ether"), { from: token_owner })); + // Reverting the changes releated to pause + await I_DummySTO.unpause({from: account_issuer }); + }); + + it("Should buy more tokens from the STO to investor1", async() => { + await I_DummySTO.generateTokens(account_investor1, web3.utils.toWei("1", "ether"), { from: token_owner }); + assert.equal((await I_SecurityToken.balanceOf(account_investor1)).toNumber(), web3.utils.toWei("2", "ether")); + }); + it("Should fail in investing the money in STO -- expiry limit reached", async () => { await increaseTime(duration.days(10)); @@ -478,7 +556,7 @@ contract("GeneralTransferManager", accounts => { it("Should set a budget for the GeneralTransferManager", async () => { await I_SecurityToken.changeModuleBudget(I_GeneralTransferManager.address, 10 * Math.pow(10, 18), { from: token_owner }); - await catchRevert(I_GeneralTransferManager.takeFee(web3.utils.toWei("1", "ether"), { from: account_polymath })); + await catchRevert(I_GeneralTransferManager.takeFee(web3.utils.toWei("1", "ether"), { from: token_owner })); await I_PolyToken.getTokens(10 * Math.pow(10, 18), token_owner); await I_PolyToken.transfer(I_SecurityToken.address, 10 * Math.pow(10, 18), { from: token_owner }); }); @@ -646,6 +724,7 @@ contract("GeneralTransferManager", accounts => { "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.", "Wrong Module added" ); + assert.equal(await I_GeneralPermissionManagerFactory.getVersion.call(), "1.0.0"); }); it("Should get the tags of the factory", async () => { @@ -672,6 +751,11 @@ contract("GeneralTransferManager", accounts => { let tags = await I_DummySTOFactory.getTags.call(); assert.equal(web3.utils.toAscii(tags[0]).replace(/\u0000/g, ""), "Dummy"); }); + + it("Should get the version of factory", async() => { + let version = await I_DummySTOFactory.getVersion.call(); + assert.equal(version, "1.0.0"); + }); }); describe("Test cases for the get functions of the dummy sto", async () => { @@ -684,12 +768,16 @@ contract("GeneralTransferManager", accounts => { }); it("Should get the investors", async () => { - assert.equal((await I_DummySTO.investorCount.call()).toNumber(), 2); + assert.equal((await I_DummySTO.getNumberInvestors.call()).toNumber(), 2); }); it("Should get the listed permissions", async () => { let tx = await I_DummySTO.getPermissions.call(); assert.equal(web3.utils.toAscii(tx[0]).replace(/\u0000/g, ""), "ADMIN"); }); + + it("Should get the amount of tokens sold", async() => { + assert.equal(await I_DummySTO.getTokensSold.call(), 0); + }) }); }); diff --git a/test/helpers/createInstances.js b/test/helpers/createInstances.js index 82a77e42a..f72ab54e3 100644 --- a/test/helpers/createInstances.js +++ b/test/helpers/createInstances.js @@ -27,6 +27,8 @@ const PreSaleSTOFactory = artifacts.require("./PreSaleSTOFactory.sol"); const PolyToken = artifacts.require("./PolyToken.sol"); const PolyTokenFaucet = artifacts.require("./PolyTokenFaucet.sol"); const DummySTOFactory = artifacts.require("./DummySTOFactory.sol"); +const MockBurnFactory = artifacts.require("./MockBurnFactory.sol"); +const MockWrongTypeFactory = artifacts.require("./MockWrongTypeFactory.sol"); const Web3 = require("web3"); const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); // Hardcoded development port @@ -35,6 +37,8 @@ const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); let I_USDTieredSTOProxyFactory; let I_USDTieredSTOFactory; let I_TrackedRedemptionFactory; +let I_MockBurnFactory; +let I_MockWrongTypeBurnFactory; let I_SingleTradeVolumeRestrictionManagerFactory; let I_ManualApprovalTransferManagerFactory; let I_VolumeRestrictionTransferManagerFactory; @@ -378,7 +382,31 @@ export async function deployRedemptionAndVerifyed(accountPolymath, MRProxyInstan } +export async function deployMockRedemptionAndVerifyed(accountPolymath, MRProxyInstance, polyToken, setupCost) { + I_MockBurnFactory = await MockBurnFactory.new(polyToken, setupCost, 0, 0, { from: accountPolymath }); + assert.notEqual( + I_MockBurnFactory.address.valueOf(), + "0x0000000000000000000000000000000000000000", + "MockBurnfactory contract was not deployed" + ); + + await registerAndVerifyByMR(I_MockBurnFactory.address, accountPolymath, MRProxyInstance); + return new Array(I_MockBurnFactory); +} + +export async function deployMockWrongTypeRedemptionAndVerifyed(accountPolymath, MRProxyInstance, polyToken, setupCost) { + I_MockWrongTypeBurnFactory = await MockWrongTypeFactory.new(polyToken, setupCost, 0, 0, { from: accountPolymath }); + + assert.notEqual( + I_MockWrongTypeBurnFactory.address.valueOf(), + "0x0000000000000000000000000000000000000000", + "MockWrongTypeBurnFactory contract was not deployed" + ); + + await registerAndVerifyByMR(I_MockWrongTypeBurnFactory.address, accountPolymath, MRProxyInstance); + return new Array(I_MockWrongTypeBurnFactory); +} diff --git a/test/i_Issuance.js b/test/i_Issuance.js index 2087e2bbe..ac1fcdd37 100644 --- a/test/i_Issuance.js +++ b/test/i_Issuance.js @@ -63,6 +63,7 @@ contract("Issuance", accounts => { const transferManagerKey = 2; const stoKey = 3; const budget = 0; + const address_zero = "0x0000000000000000000000000000000000000000"; // Initial fee for ticker registry and security token registry const initRegFee = web3.utils.toWei("250"); @@ -171,7 +172,7 @@ contract("Issuance", accounts => { assert.notEqual( I_CappedSTOFactory.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "CappedSTOFactory contract was not deployed" ); diff --git a/test/j_manual_approval_transfer_manager.js b/test/j_manual_approval_transfer_manager.js index 61472e4ff..0a1346f31 100644 --- a/test/j_manual_approval_transfer_manager.js +++ b/test/j_manual_approval_transfer_manager.js @@ -302,12 +302,15 @@ contract("ManualApprovalTransferManager", accounts => { account_investor3.toLowerCase(), "Failed in adding the investor in whitelist" ); - + // Pause at the transferManager level + await I_ManualApprovalTransferManager.pause({from: token_owner}); // Add the Investor in to the whitelist // Mint some tokens await I_SecurityToken.mint(account_investor3, web3.utils.toWei("1", "ether"), { from: token_owner }); assert.equal((await I_SecurityToken.balanceOf(account_investor3)).toNumber(), web3.utils.toWei("1", "ether")); + // Unpause at the transferManager level + await I_ManualApprovalTransferManager.unpause({from: token_owner}); }); it("Should still be able to transfer between existing token holders", async () => { @@ -364,6 +367,18 @@ contract("ManualApprovalTransferManager", accounts => { ); }); + it("Should fail to add a manual approval because allowance is laready exists", async () => { + await catchRevert( + I_ManualApprovalTransferManager.addManualApproval( + account_investor1, + account_investor4, + web3.utils.toWei("2", "ether"), + latestTime() + duration.days(5), + { from: token_owner } + ) + ); + }); + it("Should fail to revoke manual approval because invalid _from address", async () => { await catchRevert(I_ManualApprovalTransferManager.revokeManualApproval("", account_investor4, { from: token_owner })); }); @@ -452,6 +467,12 @@ contract("ManualApprovalTransferManager", accounts => { }); }); + it("Should fail to add a manual block because blocking already exist", async () => { + await catchRevert( + I_ManualApprovalTransferManager.addManualBlocking(account_investor1, account_investor2, latestTime() + duration.days(5), { from: token_owner }) + ); + }); + it("Check manual block causes failure", async () => { await catchRevert(I_SecurityToken.transfer(account_investor2, web3.utils.toWei("1", "ether"), { from: account_investor1 })); }); @@ -507,21 +528,6 @@ contract("ManualApprovalTransferManager", accounts => { assert.equal(perm.length, 1); }); - // it("Check manual approval has a higher priority than an INVALID result from another TM", async() => { - // //Should fail initial transfer - // - // try { - // await I_SecurityToken.transfer(account_investor5, web3.utils.toWei('1', 'ether'), { from: account_investor2 }); - // } catch(error) { - // console.log(`Failed due to to count block`); - // ensureException(error); - // errorThrown = true; - // } - // //Add a manual approval - transfer should now work - // await I_ManualApprovalTransferManager.addManualApproval(account_investor2, account_investor5, web3.utils.toWei('1', 'ether'), latestTime() + duration.days(1), { from: token_owner }); - // await I_SecurityToken.transfer(account_investor5, web3.utils.toWei('1', 'ether'), { from: account_investor2 }); - // }); - it("Should get the init function", async () => { let byte = await I_ManualApprovalTransferManager.getInitFunction.call(); assert.equal(web3.utils.toAscii(byte).replace(/\u0000/g, ""), 0); @@ -544,6 +550,7 @@ contract("ManualApprovalTransferManager", accounts => { "Allows an issuer to set manual approvals or blocks for specific pairs of addresses and amounts. Init function takes no parameters.", "Wrong Module added" ); + assert.equal(await I_ManualApprovalTransferManagerFactory.getVersion.call(), "1.0.0"); }); it("Should get the tags of the factory", async () => { diff --git a/test/k_module_registry.js b/test/k_module_registry.js index 00da52285..193c53bad 100644 --- a/test/k_module_registry.js +++ b/test/k_module_registry.js @@ -8,10 +8,13 @@ import { setUpPolymathNetwork } from "./helpers/createInstances"; const CappedSTOFactory = artifacts.require("./CappedSTOFactory.sol"); const DummySTOFactory = artifacts.require("./DummySTOFactory.sol"); const SecurityToken = artifacts.require("./SecurityToken.sol"); +const ModuleRegistryProxy = artifacts.require("./ModuleRegistryProxy.sol"); +const ModuleRegistry = artifacts.require("./ModuleRegistry.sol"); const GeneralPermissionManagerFactory = artifacts.require("./GeneralPermissionManagerFactory.sol"); const GeneralTransferManagerFactory = artifacts.require("./GeneralTransferManagerFactory.sol"); const MockFactory = artifacts.require("./MockFactory.sol"); const TestSTOFactory = artifacts.require("./TestSTOFactory.sol"); +const ReclaimTokens = artifacts.require("./ReclaimTokens.sol"); const Web3 = require("web3"); const BigNumber = require("bignumber.js"); @@ -47,9 +50,11 @@ contract("ModuleRegistry", accounts => { let I_SecurityTokenRegistry; let I_CappedSTOFactory1; let I_CappedSTOFactory2; + let I_CappedSTOFactory3; let I_STFactory; let I_MRProxied; let I_SecurityToken; + let I_ReclaimERC20; let I_STRProxied; let I_CappedSTO; let I_PolyToken; @@ -70,6 +75,7 @@ contract("ModuleRegistry", accounts => { const transferManagerKey = 2; const stoKey = 3; const budget = 0; + const address_zero = "0x0000000000000000000000000000000000000000"; // Initial fee for ticker registry and security token registry const initRegFee = web3.utils.toWei("250"); @@ -115,7 +121,7 @@ contract("ModuleRegistry", accounts => { I_STRProxied ] = instances; - I_GeneralTransferManagerFactory = await GeneralTransferManagerFactory.new(I_PolyToken.address, 0, 0, 0, { from: account_polymath }); + I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from: account_polymath}); // Printing all the contract addresses console.log(` @@ -133,6 +139,57 @@ contract("ModuleRegistry", accounts => { `); }); + describe("Test the initialize the function", async () => { + it("Should successfully update the implementation address -- fail because polymathRegistry address is 0x", async () => { + let bytesProxy = encodeProxyCall(MRProxyParameters, [ + address_zero, + account_polymath + ]); + catchRevert( + I_ModuleRegistryProxy.upgradeToAndCall("1.0.0", I_ModuleRegistry.address, bytesProxy, { + from: account_polymath + }), + "tx-> revert because polymathRegistry address is 0x" + ); + }); + + it("Should successfully update the implementation address -- fail because owner address is 0x", async () => { + let bytesProxy = encodeProxyCall(MRProxyParameters, [ + I_PolymathRegistry.address, + address_zero + ]); + catchRevert( + I_ModuleRegistryProxy.upgradeToAndCall("1.0.0", I_ModuleRegistry.address, bytesProxy, { + from: account_polymath + }), + "tx-> revert because owner address is 0x" + ); + }); + + it("Should successfully update the implementation address -- fail because all params are 0x", async () => { + let bytesProxy = encodeProxyCall(MRProxyParameters, [ + address_zero, + address_zero + ]); + catchRevert( + I_ModuleRegistryProxy.upgradeToAndCall("1.0.0", I_ModuleRegistry.address, bytesProxy, { + from: account_polymath + }), + "tx-> revert because all params are 0x" + ); + }); + + it("Should successfully update the implementation address", async() => { + let bytesProxy = encodeProxyCall(MRProxyParameters, [ + I_PolymathRegistry.address, + account_polymath + ]); + await I_ModuleRegistryProxy.upgradeToAndCall("1.0.0", I_ModuleRegistry.address, bytesProxy, { from: account_polymath }); + I_MRProxied = await ModuleRegistry.at(I_ModuleRegistryProxy.address); + await I_PolymathRegistry.changeAddress("ModuleRegistry", I_ModuleRegistryProxy.address, { from: account_polymath }); + }) + }); + describe("Test cases for the ModuleRegistry", async () => { describe("Test case for the upgradeFromregistry", async () => { it("Should successfully update the registry contract address -- failed because of bad owner", async () => { @@ -191,8 +248,8 @@ contract("ModuleRegistry", accounts => { assert.equal(tx.logs[0].args._owner, account_polymath, "Should be the right owner"); let _list = await I_MRProxied.getModulesByType(transferManagerKey); - assert.equal(_list.length, 2, "Length should be 2"); - assert.equal(_list[1], I_GeneralTransferManagerFactory.address); + assert.equal(_list.length, 1, "Length should be 1"); + assert.equal(_list[0], I_GeneralTransferManagerFactory.address); let _reputation = await I_MRProxied.getReputationByFactory(I_GeneralTransferManagerFactory.address); assert.equal(_reputation.length, 0); @@ -205,8 +262,22 @@ contract("ModuleRegistry", accounts => { it("Should fail in registering the module-- type = 0", async () => { I_MockFactory = await MockFactory.new(I_PolyToken.address, 0, 0, 0, { from: account_polymath }); - await catchRevert(I_MRProxied.registerModule(I_MockFactory.address, { from: account_polymath })); + catchRevert(I_MRProxied.registerModule(I_MockFactory.address, { from: account_polymath })); + }); + + it("Should fail to register the new module because msg.sender is not the owner of the module", async() => { + I_CappedSTOFactory3 = await CappedSTOFactory.new(I_PolyToken.address, 0, 0, 0, { from: account_temp }); + catchRevert( + I_MRProxied.registerModule(I_CappedSTOFactory3.address, { from: token_owner }) + ); }); + + it("Should successfully register the module -- fail because no module type uniqueness", async() => { + await I_MockFactory.changeTypes({from: account_polymath }); + catchRevert( + I_MRProxied.registerModule(I_MockFactory.address, { from: account_polymath }) + ); + }) }); describe("Test case for verifyModule", async () => { @@ -256,7 +327,7 @@ contract("ModuleRegistry", accounts => { assert.notEqual( I_CappedSTOFactory2.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "CappedSTOFactory contract was not deployed" ); @@ -294,6 +365,16 @@ contract("ModuleRegistry", accounts => { assert.equal(_reputation.length, 1); }); + it("Should successfully add module when custom modules switched on -- fail because factory owner is different", async() => { + await I_MRProxied.registerModule(I_CappedSTOFactory3.address, { from: account_temp }) + startTime = latestTime() + duration.seconds(5000); + endTime = startTime + duration.days(30); + let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, fundRaiseType, account_fundsReceiver]); + catchRevert( + I_SecurityToken.addModule(I_CappedSTOFactory3.address, bytesSTO, 0, 0, { from: token_owner }) + ); + }) + it("Should successfully add verified module", async () => { I_GeneralPermissionManagerFactory = await GeneralPermissionManagerFactory.new(I_PolyToken.address, 0, 0, 0, { from: account_polymath @@ -398,25 +479,27 @@ contract("ModuleRegistry", accounts => { let sto1 = (await I_MRProxied.getModulesByType.call(3))[0]; let sto2 = (await I_MRProxied.getModulesByType.call(3))[1]; + let sto3 = (await I_MRProxied.getModulesByType.call(3))[2]; + let sto4 = (await I_MRProxied.getModulesByType.call(3))[3]; assert.equal(sto1, I_CappedSTOFactory1.address); assert.equal(sto2, I_CappedSTOFactory2.address); - assert.equal((await I_MRProxied.getModulesByType.call(3)).length, 3); + assert.equal((await I_MRProxied.getModulesByType.call(3)).length, 4); - let tx = await I_MRProxied.removeModule(sto1, { from: account_polymath }); + let tx = await I_MRProxied.removeModule(sto4, { from: account_polymath }); - assert.equal(tx.logs[0].args._moduleFactory, sto1, "Event is not properly emitted for _moduleFactory"); + assert.equal(tx.logs[0].args._moduleFactory, sto4, "Event is not properly emitted for _moduleFactory"); assert.equal(tx.logs[0].args._decisionMaker, account_polymath, "Event is not properly emitted for _decisionMaker"); - let sto2_end = (await I_MRProxied.getModulesByType.call(3))[1]; + let sto3_end = (await I_MRProxied.getModulesByType.call(3))[2]; // re-ordering - assert.equal(sto2_end, sto2); + assert.equal(sto3_end, sto3); // delete related data - assert.equal(await I_MRProxied.getUintValues.call(web3.utils.soliditySha3("registry", sto1)), 0); - assert.equal(await I_MRProxied.getReputationByFactory.call(sto1), 0); - assert.equal((await I_MRProxied.getModulesByType.call(3)).length, 2); - assert.equal(await I_MRProxied.getBoolValues.call(web3.utils.soliditySha3("verified", sto1)), false); + assert.equal(await I_MRProxied.getUintValues.call(web3.utils.soliditySha3("registry", sto4)), 0); + assert.equal(await I_MRProxied.getReputationByFactory.call(sto4), 0); + assert.equal((await I_MRProxied.getModulesByType.call(3)).length, 3); + assert.equal(await I_MRProxied.getBoolValues.call(web3.utils.soliditySha3("verified", sto4)), false); await revertToSnapshot(snap); }); @@ -427,7 +510,7 @@ contract("ModuleRegistry", accounts => { assert.equal(sto1, I_CappedSTOFactory1.address); assert.equal(sto2, I_CappedSTOFactory2.address); - assert.equal((await I_MRProxied.getModulesByType.call(3)).length, 3); + assert.equal((await I_MRProxied.getModulesByType.call(3)).length, 4); let tx = await I_MRProxied.removeModule(sto2, { from: token_owner }); @@ -441,7 +524,7 @@ contract("ModuleRegistry", accounts => { // delete related data assert.equal(await I_MRProxied.getUintValues.call(web3.utils.soliditySha3("registry", sto2)), 0); assert.equal(await I_MRProxied.getReputationByFactory.call(sto2), 0); - assert.equal((await I_MRProxied.getModulesByType.call(3)).length, 2); + assert.equal((await I_MRProxied.getModulesByType.call(3)).length, 3); assert.equal(await I_MRProxied.getBoolValues.call(web3.utils.soliditySha3("verified", sto2)), false); }); @@ -452,6 +535,20 @@ contract("ModuleRegistry", accounts => { describe("Test cases for IRegistry functionality", async () => { describe("Test cases for reclaiming funds", async () => { + + it("Should successfully reclaim POLY tokens -- fail because token address will be 0x", async() => { + await I_PolyToken.transfer(I_MRProxied.address, web3.utils.toWei("1"), { from: token_owner }); + catchRevert( + I_MRProxied.reclaimERC20("0x000000000000000000000000000000000000000", { from: account_polymath }) + ); + }); + + it("Should successfully reclaim POLY tokens -- not authorised", async() => { + catchRevert( + I_MRProxied.reclaimERC20(I_PolyToken.address, { from: account_temp }) + ); + }); + it("Should successfully reclaim POLY tokens", async () => { await I_PolyToken.getTokens(web3.utils.toWei("1"), I_MRProxied.address); let bal1 = await I_PolyToken.balanceOf.call(account_polymath); @@ -485,6 +582,48 @@ contract("ModuleRegistry", accounts => { assert.isNotOk(status); }); }); + + describe("Test cases for the ReclaimTokens contract", async() => { + + it("Should successfully reclaim POLY tokens -- fail because token address will be 0x", async() => { + I_ReclaimERC20 = await ReclaimTokens.at(I_FeatureRegistry.address); + await I_PolyToken.transfer(I_ReclaimERC20.address, web3.utils.toWei("1"), { from: token_owner }); + catchRevert( + I_ReclaimERC20.reclaimERC20("0x000000000000000000000000000000000000000", { from: account_polymath }) + ); + }); + + it("Should successfully reclaim POLY tokens -- not authorised", async() => { + catchRevert( + I_ReclaimERC20.reclaimERC20(I_PolyToken.address, { from: account_temp }) + ); + }); + + it("Should successfully reclaim POLY tokens", async () => { + await I_PolyToken.getTokens(web3.utils.toWei("1"), I_ReclaimERC20.address); + let bal1 = await I_PolyToken.balanceOf.call(account_polymath); + await I_ReclaimERC20.reclaimERC20(I_PolyToken.address); + let bal2 = await I_PolyToken.balanceOf.call(account_polymath); + assert.isAtLeast( + bal2.dividedBy(new BigNumber(10).pow(18)).toNumber(), + bal2.dividedBy(new BigNumber(10).pow(18)).toNumber() + ); + }); + }) + + describe("Test case for the PolymathRegistry", async() => { + + it("Should successfully get the address -- fail because key is not exist", async() => { + catchRevert( + I_PolymathRegistry.getAddress("PolyOracle") + ); + }); + + it("Should successfully get the address", async() => { + let _moduleR = await I_PolymathRegistry.getAddress("ModuleRegistry"); + assert.equal(_moduleR, I_ModuleRegistryProxy.address); + }) + }) }); }); }); diff --git a/test/l_percentage_transfer_manager.js b/test/l_percentage_transfer_manager.js index c9e03ecfb..3a62463ac 100644 --- a/test/l_percentage_transfer_manager.js +++ b/test/l_percentage_transfer_manager.js @@ -320,6 +320,10 @@ contract("PercentageTransferManager", accounts => { let snapId = await takeSnapshot(); await I_PercentageTransferManager.setAllowPrimaryIssuance(true, { from: token_owner }); await I_SecurityToken.mint(account_investor3, web3.utils.toWei('100', 'ether'), { from: token_owner }); + // trying to call it again with the same value. should fail + await catchRevert( + I_PercentageTransferManager.setAllowPrimaryIssuance(true, { from: token_owner }) + ) await revertToSnapshot(snapId); }); @@ -342,6 +346,18 @@ contract("PercentageTransferManager", accounts => { await I_SecurityToken.transfer(account_investor3, web3.utils.toWei("2", "ether"), { from: account_investor1 }); }); + it("Should whitelist in batch --failed because of mismatch in array lengths", async() => { + await catchRevert( + I_PercentageTransferManager.modifyWhitelistMulti([account_investor3, account_investor4], [false], { from: token_owner }) + ); + }) + + it("Should whitelist in batch", async() => { + let snapId = await takeSnapshot(); + await I_PercentageTransferManager.modifyWhitelistMulti([account_investor3, account_investor4], [false, true], { from: token_owner }); + await revertToSnapshot(snapId); + }) + it("Should be able to whitelist address and then transfer regardless of holders", async () => { await I_PercentageTransferManager.changeHolderPercentage(30 * 10 ** 16, { from: token_owner }); await I_PercentageTransferManager.modifyWhitelist(account_investor1, true, { from: token_owner }); @@ -374,6 +390,7 @@ contract("PercentageTransferManager", accounts => { "Allows an issuer to restrict the total number of non-zero token holders", "Wrong Module added" ); + assert.equal(await I_PercentageTransferManagerFactory.getVersion.call(), "1.0.0"); }); it("Should get the tags of the factory", async () => { diff --git a/test/m_presale_sto.js b/test/m_presale_sto.js index df605d86e..4e2e80327 100644 --- a/test/m_presale_sto.js +++ b/test/m_presale_sto.js @@ -41,6 +41,7 @@ contract("PreSaleSTO", accounts => { let I_FeatureRegistry; let I_SecurityTokenRegistry; let I_PreSaleSTOFactory; + let P_PreSaleSTOFactory; let I_STFactory; let I_SecurityToken; let I_MRProxied; @@ -69,6 +70,7 @@ contract("PreSaleSTO", accounts => { // Initial fee for ticker registry and security token registry const initRegFee = web3.utils.toWei("250"); let endTime; + const address_zero = "0x0000000000000000000000000000000000000000"; const STOParameters = ["uint256"]; before(async () => { @@ -99,6 +101,8 @@ contract("PreSaleSTO", accounts => { // STEP 4: Deploy the PreSaleSTOFactory [I_PreSaleSTOFactory] = await deployPresaleSTOAndVerified(account_polymath, I_MRProxied, I_PolyToken.address, 0); + // STEP 5: Deploy the paid PresaleSTOFactory + [P_PreSaleSTOFactory] = await deployPresaleSTOAndVerified(account_polymath, I_MRProxied, I_PolyToken.address, 0); // Printing all the contract addresses console.log(` @@ -154,6 +158,46 @@ contract("PreSaleSTO", accounts => { await catchRevert(I_SecurityToken.addModule(I_PreSaleSTOFactory.address, bytesSTO, 0, 0, { from: token_owner })); }); + it("Should successfully attach the Paid STO factory with the security token", async () => { + let snap_id = await takeSnapshot(); + endTime = latestTime() + duration.days(30); // Start time will be 5000 seconds more than the latest time + let bytesSTO = encodeModuleCall(STOParameters, [endTime]); + await I_PolyToken.getTokens(web3.utils.toWei("500"), I_SecurityToken.address); + const tx = await I_SecurityToken.addModule(P_PreSaleSTOFactory.address, bytesSTO, web3.utils.toWei("500"), 0, { from: token_owner }); + + 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, ""), + "PreSaleSTO", + "PreSaleSTOFactory module was not added" + ); + I_PreSaleSTO = PreSaleSTO.at(tx.logs[2].args._module); + await revertToSnapshot(snap_id); + }); + + it("Should successfully attach the STO factory with the security token -- fail because signature is different", async () => { + endTime = latestTime() + duration.days(30); // Start time will be 5000 seconds more than the latest time + let bytesSTO = encodeModuleCall(["string"], ["hey"]); + await catchRevert( + I_SecurityToken.addModule(I_PreSaleSTOFactory.address, bytesSTO, 0, 0, { from: token_owner }) + ); + }); + + it("Should successfully attach the STO factory with the security token", async () => { + 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 }); + + 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, ""), + "PreSaleSTO", + "PreSaleSTOFactory module was not added" + ); + I_PreSaleSTO = PreSaleSTO.at(tx.logs[2].args._module); + }); + it("Should successfully attach the STO factory with the security token", async () => { endTime = latestTime() + duration.days(30); // Start time will be 5000 seconds more than the latest time let bytesSTO = encodeModuleCall(STOParameters, [endTime]); @@ -211,6 +255,14 @@ contract("PreSaleSTO", accounts => { // assert.isTrue(false); }); + it("Should allocate the tokens --failed because of amount is 0", async() => { + await catchRevert( + I_PreSaleSTO.allocateTokens(account_investor1, 0, web3.utils.toWei("1", "ether"), 0, { + from: account_issuer + }) + ); + }) + it("Should allocate the tokens -- failed due to msg.sender is not pre sale admin", async () => { await catchRevert( I_PreSaleSTO.allocateTokens(account_investor1, web3.utils.toWei("1", "ether"), web3.utils.toWei("1", "ether"), 0, { @@ -252,6 +304,54 @@ contract("PreSaleSTO", accounts => { assert.equal((await I_PreSaleSTO.getNumberInvestors.call()).toNumber(), 3); }); + it("Should successfully mint multiple tokens -- failed because array mismatch", async() => { + await catchRevert( + I_PreSaleSTO.allocateTokensMulti( + [account_investor2], + [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 } + ) + ); + }) + + it("Should successfully mint multiple tokens -- failed because array mismatch", async() => { + await catchRevert( + I_PreSaleSTO.allocateTokensMulti( + [account_investor2, account_investor3], + [web3.utils.toWei("1", "ether"), web3.utils.toWei("1", "ether")], + [0], + [web3.utils.toWei("1000", "ether"), web3.utils.toWei("1000", "ether")], + { from: account_issuer } + ) + ); + }); + + it("Should successfully mint multiple tokens -- failed because array mismatch", async() => { + await catchRevert( + I_PreSaleSTO.allocateTokensMulti( + [account_investor2, account_investor3], + [web3.utils.toWei("1", "ether"), web3.utils.toWei("1", "ether")], + [0,0], + [web3.utils.toWei("1000", "ether")], + { from: account_issuer } + ) + ); + }); + + it("Should successfully mint multiple tokens -- failed because array mismatch", async() => { + await catchRevert( + I_PreSaleSTO.allocateTokensMulti( + [account_investor2, account_investor3], + [web3.utils.toWei("1", "ether"), web3.utils.toWei("1", "ether")], + [0], + [web3.utils.toWei("1000", "ether"), web3.utils.toWei("1000", "ether")], + { from: account_issuer } + ) + ); + }); + it("Should failed at the time of buying the tokens -- Because STO has started", async () => { await increaseTime(duration.days(100)); // increased beyond the end time of the STO @@ -267,7 +367,7 @@ contract("PreSaleSTO", accounts => { await I_PolyToken.getTokens(value, account_investor1); await I_PolyToken.transfer(I_PreSaleSTO.address, value, { from: account_investor1 }); - await catchRevert(I_PreSaleSTO.reclaimERC20("0x0000000000000000000000000000000000000000", { from: token_owner })); + await catchRevert(I_PreSaleSTO.reclaimERC20(address_zero, { from: token_owner })); }); it("Should successfully reclaim POLY", async () => { @@ -298,6 +398,11 @@ contract("PreSaleSTO", accounts => { "tokens are not trandfered out from STO contract" ); }); + + it("Should get the the tokens sold", async() => { + let _tokensSold = await I_PreSaleSTO.getTokensSold.call(); + console.log(_tokensSold); + }) }); describe("Test cases for the PresaleSTOFactory", async () => { diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index dc5fc80d5..9000b87ed 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -70,6 +70,7 @@ contract("SecurityTokenRegistry", accounts => { const name2 = "Demo2 Token"; const symbol2 = "DET2"; const tokenDetails2 = "This is equity type of issuance"; + const address_zero = "0x0000000000000000000000000000000000000000"; // Module key const permissionManagerKey = 1; @@ -125,7 +126,7 @@ contract("SecurityTokenRegistry", accounts => { assert.notEqual( I_SecurityTokenRegistry.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "SecurityTokenRegistry contract was not deployed" ); @@ -155,7 +156,7 @@ contract("SecurityTokenRegistry", accounts => { describe("Test the initialize the function", async () => { it("Should successfully update the implementation address -- fail because polymathRegistry address is 0x", async () => { let bytesProxy = encodeProxyCall(STRProxyParameters, [ - "0x0000000000000000000000000000000000000000", + address_zero, I_STFactory.address, initRegFee, initRegFee, @@ -173,7 +174,7 @@ contract("SecurityTokenRegistry", accounts => { it("Should successfully update the implementation address -- fail because STFactory address is 0x", async () => { let bytesProxy = encodeProxyCall(STRProxyParameters, [ I_PolymathRegistry.address, - "0x0000000000000000000000000000000000000000", + address_zero, initRegFee, initRegFee, I_PolyToken.address, @@ -227,7 +228,7 @@ contract("SecurityTokenRegistry", accounts => { I_STFactory.address, initRegFee, initRegFee, - "0x0000000000000000000000000000000000000000", + address_zero, account_polymath ]); catchRevert( @@ -245,7 +246,24 @@ contract("SecurityTokenRegistry", accounts => { initRegFee, initRegFee, I_PolyToken.address, - "0x0000000000000000000000000000000000000000" + address_zero + ]); + catchRevert( + I_SecurityTokenRegistryProxy.upgradeToAndCall("1.0.0", I_SecurityTokenRegistry.address, bytesProxy, { + from: account_polymath + }), + "tx-> revert because owner address is 0x" + ); + }); + + it("Should successfully update the implementation address -- fail because all params get 0", async () => { + let bytesProxy = encodeProxyCall(STRProxyParameters, [ + address_zero, + address_zero, + 0, + 0, + address_zero, + address_zero ]); catchRevert( I_SecurityTokenRegistryProxy.upgradeToAndCall("1.0.0", I_SecurityTokenRegistry.address, bytesProxy, { @@ -321,7 +339,7 @@ contract("SecurityTokenRegistry", accounts => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: account_temp }); catchRevert( - I_STRProxied.registerTicker("0x0000000000000000000000000000000000000000", symbol, name, { from: account_temp }), + I_STRProxied.registerTicker(address_zero, symbol, name, { from: account_temp }), "tx revert -> owner should not be 0x" ); }); @@ -343,6 +361,15 @@ contract("SecurityTokenRegistry", accounts => { assert.equal(tx.logs[0].args._ticker, symbol, `Symbol should be ${symbol}`); }); + it("Should register the ticker when the tickerRegFee is 0", async() => { + let snap_Id = await takeSnapshot(); + await I_STRProxied.changeTickerRegistrationFee(0, { from: account_polymath }); + let tx = await I_STRProxied.registerTicker(account_temp, "ZERO", name, { 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, "ZERO", `Symbol should be ZERO`); + await revertToSnapshot(snap_Id); + }) + it("Should fail to register same symbol again", async () => { // Give POLY to token issuer await I_PolyToken.getTokens(initRegFee, token_owner); @@ -421,7 +448,7 @@ contract("SecurityTokenRegistry", accounts => { it("Should get the details of unregistered token", async () => { let tx = await I_STRProxied.getTickerDetails.call("TORO"); - assert.equal(tx[0], "0x0000000000000000000000000000000000000000", "Should be 0x as ticker is not exists in the registry"); + assert.equal(tx[0], address_zero, "Should be 0x as ticker is not exists in the registry"); assert.equal(tx[3], "", "Should be an empty string"); assert.equal(tx[4], false, "Status if the symbol should be undeployed -- false"); }); @@ -435,7 +462,7 @@ contract("SecurityTokenRegistry", accounts => { assert.equal(data[4], false, "Token is not launched yet so it should return False"); data = await I_SecurityTokenRegistry.getTickerDetails(symbol, { from: token_owner }); console.log("This is the data from the original securityTokenRegistry contract"); - assert.equal(data[0], "0x0000000000000000000000000000000000000000", "Token owner should be 0x"); + assert.equal(data[0], address_zero, "Token owner should be 0x"); }); it("Should fail to generate new security token if fee not provided", async () => { @@ -475,7 +502,7 @@ contract("SecurityTokenRegistry", accounts => { it("Should fail to generate the securityToken -- Because msg.sender is not the rightful owner of the ticker", async () => { catchRevert( - I_STRProxied.generateSecurityToken("", symbol, tokenDetails, false, { from: account_temp }), + I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: account_temp }), "tx revert -> Because msg.sender is not the rightful owner of the ticker" ); }); @@ -502,6 +529,27 @@ contract("SecurityTokenRegistry", accounts => { "tx revert -> Because ticker is already in use" ); }); + + it("Should fail to generate the SecurityToken because ticker gets expired", async() => { + let snap_Id = await takeSnapshot(); + await I_PolyToken.approve(I_STRProxied.address, web3.utils.toWei("500"), { from: token_owner }); + let tx = await I_STRProxied.registerTicker(token_owner, "CCC", name, { from: token_owner }); + await increaseTime(duration.days(65)); + catchRevert( + I_STRProxied.generateSecurityToken(name, "CCC", tokenDetails, false, { from: token_owner }), + "tx revert -> Because ticker is expired" + ); + await revertToSnapshot(snap_Id); + }); + + it("Should generate the SecurityToken when launch fee is 0", async() => { + let snap_Id = await takeSnapshot(); + await I_STRProxied.changeSecurityLaunchFee(0, { from: account_polymath }); + await I_PolyToken.approve(I_STRProxied.address, web3.utils.toWei("500"), { from: token_owner }); + let tx = await I_STRProxied.registerTicker(token_owner, "CCC", name, { from: token_owner }); + await I_STRProxied.generateSecurityToken(name, "CCC", tokenDetails, false, { from: token_owner }), + await revertToSnapshot(snap_Id); + }); }); describe("Generate SecurityToken v2", async () => { @@ -512,7 +560,7 @@ contract("SecurityTokenRegistry", accounts => { assert.notEqual( I_STFactory002.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "STFactory002 contract was not deployed" ); await I_STRProxied.setProtocolVersion(I_STFactory002.address, 0, 2, 0, { from: account_polymath }); @@ -554,7 +602,7 @@ contract("SecurityTokenRegistry", accounts => { I_SecurityTokenRegistryV2 = await SecurityTokenRegistryMock.new({ from: account_polymath }); assert.notEqual( I_SecurityTokenRegistryV2.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "SecurityTokenRegistry contract was not deployed" ); }); @@ -597,6 +645,15 @@ contract("SecurityTokenRegistry", accounts => { ); }); + it("Should fail to genrate the custom security token -- ticker length is greater than 10 chars", async() => { + catchRevert( + I_STRProxied.modifySecurityToken("LOGAN", "LOGLOGLOGLOG", account_temp, dummy_token, "I am custom ST", latestTime(), { + from: account_polymath + }), + "tx revert -> msg.sender is not polymath account" + ); + }) + it("Should fail to generate the custom security token -- name should not be 0 length ", async () => { catchRevert( I_STRProxied.modifySecurityToken("", "LOG", account_temp, dummy_token, "I am custom ST", latestTime(), { @@ -678,6 +735,12 @@ contract("SecurityTokenRegistry", accounts => { assert.equal(symbolDetails[0], account_temp, `Owner of the symbol should be ${account_temp}`); assert.equal(symbolDetails[3], "LOGAN2", `Name of the symbol should be LOGAN`); }); + + it("Should successfully modify the ticker", async() => { + let snap_Id = await takeSnapshot(); + let tx = await I_STRProxied.modifyTicker(account_temp, "LOG2", "LOGAN2", latestTime(), latestTime() + duration.days(60), false, {from: account_polymath}); + await revertToSnapshot(snap_Id); + }) }); describe("Test case for modifyTicker", async () => { @@ -1026,10 +1089,23 @@ contract("SecurityTokenRegistry", accounts => { }); describe("Test cases for IRegistry functionality", async () => { describe("Test cases for reclaiming funds", async () => { - it("Should successfully reclaim POLY tokens", async () => { + + it("Should successfully reclaim POLY tokens -- fail because token address will be 0x", async() => { I_PolyToken.transfer(I_STRProxied.address, web3.utils.toWei("1"), { from: token_owner }); + catchRevert( + I_STRProxied.reclaimERC20("0x000000000000000000000000000000000000000", { from: account_polymath }) + ); + }); + + it("Should successfully reclaim POLY tokens -- not authorised", async() => { + catchRevert( + I_STRProxied.reclaimERC20(I_PolyToken.address, { from: account_temp }) + ); + }); + + it("Should successfully reclaim POLY tokens", async () => { let bal1 = await I_PolyToken.balanceOf.call(account_polymath); - await I_STRProxied.reclaimERC20(I_PolyToken.address); + await I_STRProxied.reclaimERC20(I_PolyToken.address, { from: account_polymath }); let bal2 = await I_PolyToken.balanceOf.call(account_polymath); assert.isAtLeast( bal2.dividedBy(new BigNumber(10).pow(18)).toNumber(), @@ -1059,5 +1135,57 @@ contract("SecurityTokenRegistry", accounts => { assert.isNotOk(status); }); }); + + describe("Test cases for the setProtocolVersion", async() => { + + it("Should successfully change the protocolVersion -- failed because of bad owner", async() => { + catchRevert( + I_STRProxied.setProtocolVersion(accounts[8], 5, 6, 7, { from: account_temp }) + ); + }); + + it("Should successfully change the protocolVersion -- failed because factory address is 0x", async() => { + catchRevert( + I_STRProxied.setProtocolVersion("0x000000000000000000000000000000000000000", 5, 6, 7, { from: account_polymath }) + ); + }); + + it("Should successfully change the protocolVersion -- not a valid vesrion", async() => { + catchRevert( + I_STRProxied.setProtocolVersion(accounts[8], 0, 0, 0, { from: account_polymath }) + ); + }); + + it("Should successfully change the protocolVersion -- fail in second attempt because of invalid version", async() => { + let snap_Id = await takeSnapshot(); + await I_STRProxied.setProtocolVersion(accounts[8], 1, 2, 1, {from: account_polymath }); + await catchRevert( + I_STRProxied.setProtocolVersion(accounts[8], 0, 2, 1, {from: account_polymath }) + ); + await revertToSnapshot(snap_Id); + }); + + }); + + describe("Test cases for the transferOwnership", async() => { + + it("Should fail to transfer the ownership -- not authorised", async() => { + catchRevert( + I_STRProxied.transferOwnership(account_temp, { from: account_issuer}) + ); + }); + + it("Should fail to transfer the ownership -- 0x address is not allowed", async() => { + catchRevert( + I_STRProxied.transferOwnership("0x000000000000000000000000000000000000000", { from: account_polymath}) + ); + }); + + it("Should successfully transfer the ownership of the STR", async() => { + let tx = await I_STRProxied.transferOwnership(account_temp, { from: account_polymath }); + assert.equal(tx.logs[0].args.previousOwner, account_polymath); + assert.equal(tx.logs[0].args.newOwner, account_temp); + }); + }) }); }); diff --git a/test/o_security_token.js b/test/o_security_token.js index b5ca2dbdf..619b80035 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -3,13 +3,20 @@ import { duration, ensureException, promisifyLogWatch, latestBlock } from "./hel import takeSnapshot, { increaseTime, revertToSnapshot } from "./helpers/time"; import { encodeProxyCall, encodeModuleCall } from "./helpers/encodeCall"; import { catchRevert } from "./helpers/exceptions"; -import { setUpPolymathNetwork, deployGPMAndVerifyed, deployCappedSTOAndVerifyed } from "./helpers/createInstances"; +import { + setUpPolymathNetwork, + deployGPMAndVerifyed, + deployCappedSTOAndVerifyed, + deployMockRedemptionAndVerifyed, + deployMockWrongTypeRedemptionAndVerifyed + } from "./helpers/createInstances"; const CappedSTOFactory = artifacts.require("./CappedSTOFactory.sol"); const CappedSTO = artifacts.require("./CappedSTO.sol"); const SecurityToken = artifacts.require("./SecurityToken.sol"); const GeneralTransferManager = artifacts.require("./GeneralTransferManager"); const GeneralPermissionManager = artifacts.require("./GeneralPermissionManager"); +const MockRedemptionManager = artifacts.require("./MockRedemptionManager.sol"); const Web3 = require("web3"); const BigNumber = require("bignumber.js"); @@ -58,6 +65,9 @@ contract("SecurityToken", accounts => { let I_CappedSTO; let I_PolyToken; let I_PolymathRegistry; + let I_MockRedemptionManagerFactory; + let I_MockRedemptionManager; + // SecurityToken Details (Launched ST on the behalf of the issuer) const name = "Demo Token"; @@ -69,6 +79,7 @@ contract("SecurityToken", accounts => { const permissionManagerKey = 1; const transferManagerKey = 2; const stoKey = 3; + const burnKey = 5; const budget = 0; // Initial fee for ticker registry and security token registry @@ -377,6 +388,43 @@ contract("SecurityToken", accounts => { let tx = await I_SecurityToken.removeModule(I_GeneralTransferManager.address, { from: token_owner }); assert.equal(tx.logs[0].args._types[0], transferManagerKey); assert.equal(tx.logs[0].args._module, I_GeneralTransferManager.address); + await I_SecurityToken.mint(account_investor1, web3.utils.toWei("500"), {from: token_owner}); + await I_SecurityToken.transfer(account_investor2, web3.utils.toWei("200"), {from: account_investor1 }); + assert.equal((await I_SecurityToken.balanceOf(account_investor2)).dividedBy(new BigNumber(10).pow(18)).toNumber(), 200); + await revertToSnapshot(key); + }); + + it("Should successfully remove the module from the middle of the names mapping", async() => { + let snap_Id = await takeSnapshot(); + let D_GPM, D_GPM_1, D_GPM_2; + let FactoryInstances; + let GPMAddress = new Array(); + + [D_GPM] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); + [D_GPM_1] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); + [D_GPM_2] = await deployGPMAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); + FactoryInstances = [D_GPM, D_GPM_1, D_GPM_2]; + // Adding module in the ST + for (let i = 0; i < FactoryInstances.length; i++) { + let tx = await I_SecurityToken.addModule(FactoryInstances[i].address, "", 0, 0, {from: token_owner }); + assert.equal(tx.logs[2].args._types[0], permissionManagerKey, "fail in adding the GPM") + GPMAddress.push(tx.logs[2].args._module); + } + // Archive the one of the module + await I_SecurityToken.archiveModule(GPMAddress[0], {from: token_owner}); + // Remove the module + let tx = await I_SecurityToken.removeModule(GPMAddress[0], {from: token_owner}); + assert.equal(tx.logs[0].args._types[0], permissionManagerKey); + assert.equal(tx.logs[0].args._module, GPMAddress[0]); + await revertToSnapshot(snap_Id); + }); + + it("Should successfully archive the module first and fail during achiving the module again", async() => { + let key = await takeSnapshot(); + await I_SecurityToken.archiveModule(I_GeneralTransferManager.address, { from: token_owner }); + await catchRevert( + I_SecurityToken.archiveModule(I_GeneralTransferManager.address, { from: token_owner }) + ); await revertToSnapshot(key); }); @@ -416,6 +464,18 @@ contract("SecurityToken", accounts => { assert.equal(moduleData[3], false); }); + it("Should successfully unarchive the general transfer manager module from the securityToken -- fail because module is already unarchived", async () => { + await catchRevert( + I_SecurityToken.unarchiveModule(I_GeneralTransferManager.address, { from: token_owner }) + ); + }); + + it("Should successfully archive the module -- fail because module is not existed", async() => { + await catchRevert( + I_SecurityToken.archiveModule(I_GeneralPermissionManagerFactory.address, { from: token_owner }) + ); + }) + it("Should fail to mint tokens while GTM unarchived", async () => { await catchRevert(I_SecurityToken.mint(1, 100 * Math.pow(10, 18), { from: token_owner, gas: 500000 })); }); @@ -430,6 +490,19 @@ contract("SecurityToken", accounts => { 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); }); + + it("Should change the budget of the module (decrease it)", async() => { + let tx = await I_SecurityToken.changeModuleBudget(I_CappedSTO.address, 50 * Math.pow(10, 18), { from: token_owner }); + 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(), 50); + }); + + it("Should fail to get the total supply -- because checkpoint id is greater than present", async() => { + await catchRevert( + I_SecurityToken.totalSupplyAt.call(50) + ); + }) }); describe("General Transfer manager Related test cases", async () => { @@ -803,14 +876,94 @@ contract("SecurityToken", accounts => { }); }); + describe("Test cases for the Mock TrackedRedeemption", async() => { + + it("Should add the tracked redeemption module successfully", async() => { + [I_MockRedemptionManagerFactory] = await deployMockRedemptionAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); + let tx = await I_SecurityToken.addModule(I_MockRedemptionManagerFactory.address, "", 0, 0, {from: token_owner }); + assert.equal(tx.logs[2].args._types[0], burnKey, "fail in adding the burn manager"); + I_MockRedemptionManager = MockRedemptionManager.at(tx.logs[2].args._module); + // adding the burn module into the GTM + tx = await I_GeneralTransferManager.modifyWhitelist( + I_MockRedemptionManager.address, + latestTime(), + latestTime() + duration.seconds(2), + latestTime() + duration.days(50), + true, + { + from: account_delegate, + gas: 6000000 + } + ); + assert.equal(tx.logs[0].args._investor, I_MockRedemptionManager.address, "Failed in adding the investor in whitelist"); + }); + + it("Should successfully burn tokens", async() => { + await I_GeneralTransferManager.changeAllowAllWhitelistTransfers(false, {from: token_owner}); + // Minting some tokens + await I_SecurityToken.mint(account_investor1, web3.utils.toWei("1000"), {from: token_owner}); + // Provide approval to trnafer the tokens to Module + await I_SecurityToken.approve(I_MockRedemptionManager.address, web3.utils.toWei("500"), {from: account_investor1}); + // Allow all whitelist transfer + await I_GeneralTransferManager.changeAllowAllWhitelistTransfers(true, {from: token_owner}); + // Transfer the tokens to module (Burn) + await I_MockRedemptionManager.transferToRedeem(web3.utils.toWei("500"), { from: account_investor1}); + // Redeem tokens + let tx = await I_MockRedemptionManager.redeemTokenByOwner(web3.utils.toWei("250"), {from: account_investor1}); + assert.equal(tx.logs[0].args._investor, account_investor1, "Burn tokens of wrong owner"); + assert.equal((tx.logs[0].args._value).dividedBy(new BigNumber(10).pow(18)).toNumber(), 250); + }); + + it("Should fail to burn the tokens because module get archived", async() => { + await I_SecurityToken.archiveModule(I_MockRedemptionManager.address, {from: token_owner}); + await catchRevert( + I_MockRedemptionManager.redeemTokenByOwner(web3.utils.toWei("250"), {from: account_investor1}) + ); + }) + + it("Should successfully fail in calling the burn functions", async() => { + [I_MockRedemptionManagerFactory] = await deployMockWrongTypeRedemptionAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); + let tx = await I_SecurityToken.addModule(I_MockRedemptionManagerFactory.address, "", 0, 0, {from: token_owner }); + I_MockRedemptionManager = MockRedemptionManager.at(tx.logs[2].args._module); + + // adding the burn module into the GTM + tx = await I_GeneralTransferManager.modifyWhitelist( + I_MockRedemptionManager.address, + latestTime(), + latestTime() + duration.seconds(2), + latestTime() + duration.days(50), + true, + { + from: account_delegate, + gas: 6000000 + } + ); + assert.equal(tx.logs[0].args._investor, I_MockRedemptionManager.address, "Failed in adding the investor in whitelist"); + // Provide approval to trnafer the tokens to Module + await I_SecurityToken.approve(I_MockRedemptionManager.address, web3.utils.toWei("500"), {from: account_investor1}); + // Transfer the tokens to module (Burn) + await I_MockRedemptionManager.transferToRedeem(web3.utils.toWei("500"), { from: account_investor1}); + + await catchRevert( + // Redeem tokens + I_MockRedemptionManager.redeemTokenByOwner(web3.utils.toWei("250"), {from: account_investor1}) + ); + }); + + }) + describe("Withdraw Poly", async () => { + it("Should successfully withdraw the poly -- failed because of zero address of token", async() => { + await catchRevert(I_SecurityToken.withdrawERC20("0x00000000000000000000000000000000000000000", web3.utils.toWei("20000", "ether"), { from: account_temp })); + }) + it("Should successfully withdraw the poly", async () => { - await catchRevert(I_SecurityToken.withdrawPoly(web3.utils.toWei("20000", "ether"), { from: account_temp })); + await catchRevert(I_SecurityToken.withdrawERC20(I_PolyToken.address, web3.utils.toWei("20000", "ether"), { from: account_temp })); }); it("Should successfully withdraw the poly", async () => { let balanceBefore = await I_PolyToken.balanceOf(token_owner); - await I_SecurityToken.withdrawPoly(web3.utils.toWei("20000", "ether"), { from: token_owner }); + await I_SecurityToken.withdrawERC20(I_PolyToken.address, web3.utils.toWei("20000", "ether"), { from: token_owner }); let balanceAfter = await I_PolyToken.balanceOf(token_owner); assert.equal( BigNumber(balanceAfter) @@ -821,7 +974,7 @@ contract("SecurityToken", accounts => { }); it("Should successfully withdraw the poly", async () => { - await catchRevert(I_SecurityToken.withdrawPoly(web3.utils.toWei("10", "ether"), { from: token_owner })); + await catchRevert(I_SecurityToken.withdrawERC20(I_PolyToken.address, web3.utils.toWei("10", "ether"), { from: token_owner })); }); }); diff --git a/test/p_usd_tiered_sto.js b/test/p_usd_tiered_sto.js index 73856e2cf..62cd4cc05 100644 --- a/test/p_usd_tiered_sto.js +++ b/test/p_usd_tiered_sto.js @@ -58,6 +58,7 @@ contract("USDTieredSTO", accounts => { let I_PolyToken; let I_DaiToken; let I_PolymathRegistry; + let P_USDTieredSTOFactory; // SecurityToken Details for funds raise Type ETH const NAME = "Team"; @@ -68,6 +69,8 @@ contract("USDTieredSTO", accounts => { // Module key const TMKEY = 2; const STOKEY = 3; + let snapId; + const address_zero = "0x0000000000000000000000000000000000000000"; // Initial fee for ticker registry and security token registry const REGFEE = web3.utils.toWei("250"); @@ -226,7 +229,7 @@ contract("USDTieredSTO", accounts => { // STEP 5: Deploy the USDTieredSTOFactory [I_USDTieredSTOFactory] = await deployUSDTieredSTOAndVerified(POLYMATH, I_MRProxied, I_PolyToken.address, STOSetupCost); - + [P_USDTieredSTOFactory] = await deployUSDTieredSTOAndVerified(POLYMATH, I_MRProxied, I_PolyToken.address, web3.utils.toWei("500")); // Step 12: Deploy & Register Mock Oracles I_USDOracle = await MockOracle.new(0, "ETH", "USD", USDETH, { from: POLYMATH }); // 500 dollars per POLY I_POLYOracle = await MockOracle.new(I_PolyToken.address, "POLY", "USD", USDPOLY, { from: POLYMATH }); // 25 cents per POLY @@ -371,6 +374,83 @@ contract("USDTieredSTO", accounts => { assert.equal((await I_USDTieredSTO_Array[stoId].getPermissions()).length, 0, "Incorrect number of permissions"); }); + it("Should attach the paid STO factory -- failed because of no tokens", async() => { + let stoId = 0; // No discount + let config = [ + _startTime[stoId], + _endTime[stoId], + _ratePerTier[stoId], + _ratePerTierDiscountPoly[stoId], + _tokensPerTierTotal[stoId], + _tokensPerTierDiscountPoly[stoId], + _nonAccreditedLimitUSD[stoId], + _minimumInvestmentUSD[stoId], + _fundRaiseTypes[stoId], + _wallet[stoId], + _reserveWallet[stoId], + _usdToken[stoId] + ]; + + let bytesSTO = web3.eth.abi.encodeFunctionCall(functionSignature, config); + await catchRevert( + I_SecurityToken.addModule(P_USDTieredSTOFactory.address, bytesSTO, web3.utils.toWei("500"), 0, { from: ISSUER, gasPrice: GAS_PRICE }) + ); + }); + + it("Should attach the paid STO factory", async() => { + let snapId = await takeSnapshot(); + let stoId = 0; // No discount + let config = [ + _startTime[stoId], + _endTime[stoId], + _ratePerTier[stoId], + _ratePerTierDiscountPoly[stoId], + _tokensPerTierTotal[stoId], + _tokensPerTierDiscountPoly[stoId], + _nonAccreditedLimitUSD[stoId], + _minimumInvestmentUSD[stoId], + _fundRaiseTypes[stoId], + _wallet[stoId], + _reserveWallet[stoId], + _usdToken[stoId] + ]; + + let bytesSTO = web3.eth.abi.encodeFunctionCall(functionSignature, config); + await I_PolyToken.getTokens(web3.utils.toWei("500"), I_SecurityToken.address); + let tx = await I_SecurityToken.addModule(P_USDTieredSTOFactory.address, bytesSTO, web3.utils.toWei("500"), 0, { from: ISSUER, gasPrice: GAS_PRICE }); + await revertToSnapshot(snapId); + }); + + it("Should allow non-matching beneficiary", async () => { + snapId = await takeSnapshot(); + await I_USDTieredSTO_Array[0].changeAllowBeneficialInvestments(true, { from: ISSUER }); + let allow = await I_USDTieredSTO_Array[0].allowBeneficialInvestments(); + assert.equal(allow, true, "allowBeneficialInvestments should be true"); + }); + + it("Should allow non-matching beneficiary -- failed because it is already active", async () => { + await catchRevert( + I_USDTieredSTO_Array[0].changeAllowBeneficialInvestments(true, { from: ISSUER }) + ); + await revertToSnapshot(snapId); + }); + + it("Should successfully call the modifyTimes before starting the STO -- fail because of bad owner", async() => { + await catchRevert( + I_USDTieredSTO_Array[0].modifyTimes(latestTime() + duration.days(15), latestTime() + duration.days(55), { from: POLYMATH }) + ); + }) + + it("Should successfully call the modifyTimes before starting the STO", async() => { + let snapId = await takeSnapshot(); + let _startTime = latestTime() + duration.days(15); + let _endTime = latestTime() + duration.days(55) + await I_USDTieredSTO_Array[0].modifyTimes(_startTime, _endTime, { from: ISSUER }); + assert.equal(await I_USDTieredSTO_Array[0].startTime.call(), _startTime, "Incorrect _startTime in config"); + assert.equal(await I_USDTieredSTO_Array[0].endTime.call(), _endTime, "Incorrect _endTime in config"); + await revertToSnapshot(snapId); + }); + it("Should successfully attach the second STO module to the security token", async () => { let stoId = 1; // No discount @@ -655,7 +735,7 @@ contract("USDTieredSTO", accounts => { it("Should fail because Zero address is not permitted for wallet", async () => { let stoId = 0; - let wallet = "0x0000000000000000000000000000000000000000"; + let wallet = address_zero; let config = [ _startTime[stoId], _endTime[stoId], @@ -678,7 +758,7 @@ contract("USDTieredSTO", accounts => { it("Should fail because Zero address is not permitted for reserveWallet", async () => { let stoId = 0; - let reserveWallet = "0x0000000000000000000000000000000000000000"; + let reserveWallet = address_zero; let config = [ _startTime[stoId], _endTime[stoId], @@ -815,7 +895,7 @@ contract("USDTieredSTO", accounts => { await I_USDTieredSTO_Array[stoId].modifyAddresses( "0x0000000000000000000000000400000000000000", "0x0000000000000000000003000000000000000000", - "0x0000000000000000000000000000000000000000", + address_zero, { from: ISSUER } ); assert.equal( @@ -830,7 +910,7 @@ contract("USDTieredSTO", accounts => { ); assert.equal( await I_USDTieredSTO_Array[stoId].usdToken.call(), - "0x0000000000000000000000000000000000000000", + address_zero, "STO Configuration doesn't set as expected" ); }); @@ -4229,6 +4309,7 @@ contract("USDTieredSTO", accounts => { assert.equal(await I_USDTieredSTOFactory.getDescription.call(), "USD Tiered STO", "Wrong Module added"); assert.equal(await I_USDTieredSTOFactory.getTitle.call(), "USD Tiered STO", "Wrong Module added"); assert.equal(await I_USDTieredSTOFactory.getInstructions.call(), "Initialises a USD tiered STO.", "Wrong Module added"); + assert.equal(await I_USDTieredSTOFactory.getVersion.call(), "1.0.0"); let tags = await I_USDTieredSTOFactory.getTags.call(); assert.equal(web3.utils.hexToString(tags[0]), "USD"); assert.equal(web3.utils.hexToString(tags[1]), "Tiered"); diff --git a/test/s_v130_to_v140_upgrade.js b/test/s_v130_to_v140_upgrade.js index 8422dc6ee..3fb3092aa 100644 --- a/test/s_v130_to_v140_upgrade.js +++ b/test/s_v130_to_v140_upgrade.js @@ -33,6 +33,7 @@ contract("Upgrade from v1.3.0 to v1.4.0", accounts => { // Initial fee for ticker registry and security token registry const REGFEE = web3.utils.toWei("250"); const STOSetupCost = 0; + const address_zero = "0x0000000000000000000000000000000000000000"; // Module key const STOKEY = 3; @@ -187,7 +188,7 @@ contract("Upgrade from v1.3.0 to v1.4.0", accounts => { console.log(I_POLYOracle.address); assert.notEqual( I_POLYOracle.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "POLYOracle contract was not deployed" ); tx = await I_PolymathRegistry.changeAddress("PolyUsdOracle", I_POLYOracle.address, { from: POLYMATH }); @@ -198,13 +199,13 @@ contract("Upgrade from v1.3.0 to v1.4.0", accounts => { it("Should successfully deploy ETH Oracle and register on PolymathRegistry", async () => { I_USDOracle = await ETHOracle.new( "0x216d678c14be600cb88338e763bb57755ca2b1cf", - "0x0000000000000000000000000000000000000000", + address_zero, "ETH", { from: POLYMATH } ); assert.notEqual( I_USDOracle.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "USDOracle contract was not deployed" ); tx = await I_PolymathRegistry.changeAddress("EthUsdOracle", I_USDOracle.address, { from: POLYMATH }); @@ -227,7 +228,7 @@ contract("Upgrade from v1.3.0 to v1.4.0", accounts => { ); assert.notEqual( I_USDTieredSTOFactory.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "USDTieredSTOFactory contract was not deployed" ); let setupCost = await I_USDTieredSTOFactory.setupCost({ from: POLYMATH }); @@ -249,7 +250,7 @@ contract("Upgrade from v1.3.0 to v1.4.0", accounts => { I_UpgradedCappedSTOFactory = await CappedSTOFactory.new(I_PolyToken.address, STOSetupCost, 0, 0, { from: POLYMATH }); assert.notEqual( I_UpgradedCappedSTOFactory.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "CappedSTOFactory contract was not deployed" ); let setupCost = await I_UpgradedCappedSTOFactory.setupCost({ from: POLYMATH }); @@ -281,7 +282,7 @@ contract("Upgrade from v1.3.0 to v1.4.0", accounts => { }); assert.notEqual( I_ManualApprovalTransferManagerFactory.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "ManualApprovalTransferManagerFactory contract was not deployed" ); }); diff --git a/test/t_security_token_registry_proxy.js b/test/t_security_token_registry_proxy.js index 2d426d656..40b1cced8 100644 --- a/test/t_security_token_registry_proxy.js +++ b/test/t_security_token_registry_proxy.js @@ -257,5 +257,13 @@ contract("SecurityTokenRegistryProxy", accounts => { assert.equal(await readStorage(c.address, 12), I_SecurityTokenRegistry.address, "Implemnted address is not matched"); I_STRProxied = await SecurityTokenRegistry.at(I_SecurityTokenRegistryProxy.address); }); + + it("Should get the version", async() => { + assert.equal(await I_SecurityTokenRegistryProxy.version.call({ from: account_polymath_new }), "1.2.0"); + }); + + it("Should get the implementation address", async() => { + assert.equal(await I_SecurityTokenRegistryProxy.implementation.call({ from: account_polymath_new }), I_SecurityTokenRegistry.address); + }) }); }); diff --git a/test/u_module_registry_proxy.js b/test/u_module_registry_proxy.js index 4ba4d12c6..6d00b8fe2 100644 --- a/test/u_module_registry_proxy.js +++ b/test/u_module_registry_proxy.js @@ -41,7 +41,7 @@ contract("ModuleRegistryProxy", accounts => { const initRegFee = web3.utils.toWei("250"); const version = "1.0.0"; const message = "Transaction Should Fail!"; - + const address_zero = "0x0000000000000000000000000000000000000000"; // SecurityToken Details for funds raise Type ETH const name = "Team"; const symbol = "SAP"; @@ -128,7 +128,7 @@ contract("ModuleRegistryProxy", accounts => { assert.notEqual( I_GeneralTransferManagerFactory.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "GeneralTransferManagerFactory contract was not deployed" ); @@ -143,7 +143,7 @@ contract("ModuleRegistryProxy", accounts => { assert.notEqual( I_STFactory.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "STFactory contract was not deployed" ); }); @@ -166,7 +166,7 @@ contract("ModuleRegistryProxy", accounts => { assert.notEqual( I_GeneralPermissionManagerfactory.address.valueOf(), - "0x0000000000000000000000000000000000000000", + address_zero, "GeneralPermissionManagerFactory contract was not deployed" ); diff --git a/test/v_tracked_redemptions.js b/test/v_tracked_redemptions.js index b1af22535..a8a11f66d 100644 --- a/test/v_tracked_redemptions.js +++ b/test/v_tracked_redemptions.js @@ -51,6 +51,7 @@ contract("TrackedRedemption", accounts => { let I_PolyToken; let I_MRProxied; let I_PolymathRegistry; + let P_TrackedRedemptionFactory; // SecurityToken Details const name = "Team"; @@ -104,6 +105,7 @@ contract("TrackedRedemption", accounts => { // STEP 4: Deploy the TrackedRedemption [I_TrackedRedemptionFactory] = await deployRedemptionAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, 0); + [P_TrackedRedemptionFactory] = await deployRedemptionAndVerifyed(account_polymath, I_MRProxied, I_PolyToken.address, web3.utils.toWei("500")); // Printing all the contract addresses console.log(` @@ -153,6 +155,20 @@ contract("TrackedRedemption", accounts => { I_GeneralTransferManager = GeneralTransferManager.at(moduleData); }); + it("Should successfully attach the paid TrackedRedemption with the security token", async () => { + let snapId = await takeSnapshot(); + await I_PolyToken.getTokens(web3.utils.toWei("500"), I_SecurityToken.address); + const tx = await I_SecurityToken.addModule(P_TrackedRedemptionFactory.address, "", web3.utils.toWei("500"), 0, { from: token_owner }); + assert.equal(tx.logs[3].args._types[0].toNumber(), burnKey, "TrackedRedemption doesn't get deployed"); + assert.equal( + web3.utils.toAscii(tx.logs[3].args._name).replace(/\u0000/g, ""), + "TrackedRedemption", + "TrackedRedemption module was not added" + ); + I_TrackedRedemption = TrackedRedemption.at(tx.logs[3].args._module); + await revertToSnapshot(snapId); + }); + 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._types[0].toNumber(), burnKey, "TrackedRedemption doesn't get deployed"); diff --git a/test/w_lockup_volume_restriction_transfer_manager.js b/test/w_lockup_volume_restriction_transfer_manager.js index 1caea7374..fda65be4f 100644 --- a/test/w_lockup_volume_restriction_transfer_manager.js +++ b/test/w_lockup_volume_restriction_transfer_manager.js @@ -359,7 +359,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { it("Should prevent the transfer of tokens in a lockup", async() => { let balance = await I_SecurityToken.balanceOf(account_investor2) - + console.log("balance", balance.dividedBy(new BigNumber(1).times(new BigNumber(10).pow(18))).toNumber()); // create a lockup for their entire balance // over 12 seconds total, with 3 periods of 4 seconds each. await I_VolumeRestrictionTransferManager.addLockUp(account_investor2, 12, 4, 0, balance, { from: token_owner }); @@ -377,7 +377,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { it("Should allow the transfer of tokens in a lockup if a period has passed", async() => { // wait 4 seconds - await new Promise(resolve => setTimeout(resolve, 4000)); + await increaseTime(duration.seconds(4)); await I_SecurityToken.transfer(account_investor1, web3.utils.toWei('3', 'ether'), { from: account_investor2 }); }); @@ -392,7 +392,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { it("Should allow the transfer of more tokens in a lockup if another period has passed", async() => { // wait 4 more seconds - await new Promise(resolve => setTimeout(resolve, 4000)); + await increaseTime(4000); await I_SecurityToken.transfer(account_investor1, web3.utils.toWei('3', 'ether'), { from: account_investor2 }); }); @@ -402,7 +402,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { let balance = await I_SecurityToken.balanceOf(account_investor2) // wait 4 more seconds - await new Promise(resolve => setTimeout(resolve, 4000)); + await increaseTime(4000); await I_SecurityToken.transfer(account_investor1, balance, { from: account_investor2 }); }); @@ -453,6 +453,20 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { }); + it("Should succesfully modify the lockup - fail because array index out of bound", async() => { + // balance here should be 12000000000000000000 (12e18 or 12 eth) + let balance = await I_SecurityToken.balanceOf(account_investor1); + await catchRevert( + I_VolumeRestrictionTransferManager.modifyLockUp(account_investor1, 8, 8, 4, 0, balance, { from: token_owner }) + ); + }) + + it("Should succesfully get the lockup - fail because array index out of bound", async() => { + await catchRevert( + I_VolumeRestrictionTransferManager.getLockUp(account_investor1, 9) + ); + }) + it("Should be possible to remove a lockup -- couldn't transfer because of lock up", async() => { let acct1Balance = await I_SecurityToken.balanceOf(account_investor1) @@ -478,6 +492,12 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { assert.equal(acct2BalanceAfter.sub(acct2BalanceBefore).toString(), acct1Balance.toString()) }); + it("Should try to remove the lockup --failed because of index is out of bounds", async() => { + await catchRevert( + I_VolumeRestrictionTransferManager.removeLockUp(account_investor2, 7, { from: token_owner }) + ); + }) + it("Should be possible to create multiple lockups at once", async() => { let balancesBefore = {} @@ -536,7 +556,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { assert.equal(lockUpCountsAfter[account_investor3], 1); // wait 4 seconds - await new Promise(resolve => setTimeout(resolve, 4000)); + await increaseTime(4000); // try transfers again await I_SecurityToken.transfer(account_investor1, web3.utils.toWei('2', 'ether'), { from: account_investor2 }); @@ -576,34 +596,27 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { lockUpsLength = await I_VolumeRestrictionTransferManager.getLockUpsLength(account_investor2); assert.equal(lockUpsLength, 0); - let now = (await web3.eth.getBlock('latest')).timestamp + let now = latestTime(); // balance here should be 10000000000000000000 let balance = await I_SecurityToken.balanceOf(account_investor2) - await I_VolumeRestrictionTransferManager.addLockUp(account_investor2, 100, 10, now + 4, balance, { from: token_owner }); - - // try a transfer. it should fail because the lockup hasn't started yet. - await catchRevert( - I_SecurityToken.transfer(account_investor1, web3.utils.toWei('1', 'ether'), { from: account_investor2 }) - ); - now = (await web3.eth.getBlock('latest')).timestamp + await I_VolumeRestrictionTransferManager.addLockUp(account_investor2, 100, 10, now + duration.seconds(4), balance, { from: token_owner }); // wait 4 seconds for the lockup to begin - await new Promise(resolve => setTimeout(resolve, 4000)); + await increaseTime(duration.seconds(4)); // try another transfer. it should also fail because the lockup has just begun await catchRevert( I_SecurityToken.transfer(account_investor1, web3.utils.toWei('1', 'ether'), { from: account_investor2 }) ); - now = (await web3.eth.getBlock('latest')).timestamp }); it("Should be possible to edit a lockup with a specific start time in the future", async() => { // edit the lockup - let now = (await web3.eth.getBlock('latest')).timestamp + let now = latestTime(); // should be 10000000000000000000 let balance = await I_SecurityToken.balanceOf(account_investor2) @@ -621,7 +634,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { assert.equal(lockUp[3].toString(), balance.toString()); // edit the lockup - await I_VolumeRestrictionTransferManager.modifyLockUp(account_investor2, 0, 8, 4, now + 4, balance, { from: token_owner }); + await I_VolumeRestrictionTransferManager.modifyLockUp(account_investor2, 0, 8, 4, now + duration.seconds(4), balance, { from: token_owner }); // check and get the lockup again lockUpCount = await I_VolumeRestrictionTransferManager.getLockUpsLength(account_investor2); @@ -641,7 +654,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { ); // wait 4 seconds for the lockup to begin - await new Promise(resolve => setTimeout(resolve, 4000)); + await increaseTime(duration.seconds(4)); // try another transfer. it should fail because the lockup has just begun await catchRevert( @@ -649,7 +662,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { ); // wait 4 seconds for the lockup's first period to elapse - await new Promise(resolve => setTimeout(resolve, 4000)); + await increaseTime(duration.seconds(4)); // try another transfer. it should pass await I_SecurityToken.transfer(account_investor1, web3.utils.toWei('5', 'ether'), { from: account_investor2 }); @@ -661,7 +674,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { ); // wait 4 seconds for the lockup's first period to elapse - await new Promise(resolve => setTimeout(resolve, 4000)); + await increaseTime(duration.seconds(4)); let lockUpBeforeVerify = await I_VolumeRestrictionTransferManager.getLockUp(account_investor2, 0); // check if transfer will pass in read-only operation @@ -676,7 +689,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { await I_SecurityToken.transfer(account_investor1, web3.utils.toWei('5', 'ether'), { from: account_investor2 }); // wait 4 seconds for the lockup's first period to elapse. but, we are all out of periods. - await new Promise(resolve => setTimeout(resolve, 4000)); + await increaseTime(duration.seconds(4)); // try one final transfer. this should fail because the user has already withdrawn their entire balance await catchRevert( @@ -702,8 +715,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { I_SecurityToken.transfer(account_investor2, web3.utils.toWei('1', 'ether'), { from: account_investor1 }) ); // wait 4 seconds for the lockup's first period to elapse. - await new Promise(resolve => setTimeout(resolve, 4000)); - + await increaseTime(duration.seconds(4)); // should succeed await I_SecurityToken.transfer(account_investor2, web3.utils.toWei('2', 'ether'), { from: account_investor1 }); @@ -720,7 +732,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { ); // wait 4 seconds for the 1st lockup's second period to elapse, and the 2nd lockup's first period to elapse - await new Promise(resolve => setTimeout(resolve, 4000)); + await increaseTime(duration.seconds(4)); // should now be able to transfer 4, because of 2 allowed from the 1st lockup and 2 from the 2nd await I_SecurityToken.transfer(account_investor2, web3.utils.toWei('4', 'ether'), { from: account_investor1 }); @@ -731,14 +743,12 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { ); // wait 4 seconds for the 1st lockup's final period to elapse, and the 2nd lockup's second period to elapse - await new Promise(resolve => setTimeout(resolve, 4000)); - + await increaseTime(duration.seconds(4)); // should now be able to transfer 4, because of 2 allowed from the 1st lockup and 2 from the 2nd await I_SecurityToken.transfer(account_investor2, web3.utils.toWei('4', 'ether'), { from: account_investor1 }); // wait 8 seconds for 2nd lockup's third and fourth periods to elapse - await new Promise(resolve => setTimeout(resolve, 8000)); - + await increaseTime(duration.seconds(8)); // should now be able to transfer 4, because there are 2 allowed per period in the 2nd lockup, and 2 periods have elapsed await I_SecurityToken.transfer(account_investor2, web3.utils.toWei('4', 'ether'), { from: account_investor1 }); @@ -786,7 +796,7 @@ contract('LockupVolumeRestrictionTransferManager', accounts => { assert.equal(await I_VolumeRestrictionTransferManagerFactory.getInstructions.call(), "Allows an issuer to set lockup periods for user addresses, with funds distributed over time. Init function takes no parameters.", "Wrong Module added"); - + assert.equal(await I_VolumeRestrictionTransferManagerFactory.getVersion.call(), "1.0.0"); }); it("Should get the tags of the factory", async() => { diff --git a/test/x_single_trade_volume_restriction.js b/test/x_single_trade_volume_restriction.js index f4bf8180a..a0e1fb3f0 100644 --- a/test/x_single_trade_volume_restriction.js +++ b/test/x_single_trade_volume_restriction.js @@ -277,6 +277,15 @@ contract('SingleTradeVolumeRestrictionManager', accounts => { ); }); + it("Should allow the primary issuance", async() => { + let snapId = await takeSnapshot(); + await I_SingleTradeVolumeRestrictionManager.setAllowPrimaryIssuance(true, {from: token_owner}); + await catchRevert( + I_SingleTradeVolumeRestrictionManager.setAllowPrimaryIssuance(true, {from: token_owner}) + ) + await revertToSnapshot(snapId); + }) + it("add exempt wallet -- Not authorised ", async () => { await catchRevert ( I_SingleTradeVolumeRestrictionManager.addExemptWallet(accounts[5])